From 960bbcb3ce4a82cf4f031d1c6682ce4c1a04474d Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 30 Dec 2007 11:35:44 -0800 Subject: [PATCH 0001/1492] initial import --- README | 0 Rakefile | 10 ++++ lib/sql_algebra.rb | 24 ++++++++ lib/sql_algebra/extensions/range.rb | 0 lib/sql_algebra/relations/attribute.rb | 35 +++++++++++ lib/sql_algebra/relations/join_operation.rb | 16 +++++ lib/sql_algebra/relations/join_relation.rb | 13 ++++ .../relations/predicates/binary_predicate.rb | 12 ++++ .../predicates/equality_predicate.rb | 7 +++ .../greater_than_or_equal_to_predicate.rb | 2 + .../predicates/greater_than_predicate.rb | 2 + .../less_than_or_equal_to_predicate.rb | 2 + .../predicates/less_than_predicate.rb | 2 + .../relations/predicates/match_predicate.rb | 7 +++ .../relations/predicates/predicate.rb | 5 ++ .../predicates/range_inclusion_predicate.rb | 0 .../relation_inclusion_predicate.rb | 11 ++++ lib/sql_algebra/relations/relation.rb | 13 ++++ lib/sql_algebra/relations/table_relation.rb | 11 ++++ lib/sql_algebra/sql/select.rb | 23 +++++++ spec/extensions/range_spec.rb | 1 + spec/predicates/binary_predicate_spec.rb | 27 +++++++++ spec/predicates/equality_predicate_spec.rb | 25 ++++++++ .../relation_inclusion_predicate_spec.rb | 16 +++++ spec/relations/attribute_spec.rb | 60 +++++++++++++++++++ spec/relations/join_operation_spec.rb | 29 +++++++++ spec/relations/join_relation_spec.rb | 20 +++++++ spec/relations/relation_spec.rb | 52 ++++++++++++++++ spec/relations/table_relation_spec.rb | 7 +++ spec/spec_helper.rb | 3 + spec/sql/select_spec.rb | 19 ++++++ 31 files changed, 454 insertions(+) create mode 100644 README create mode 100644 Rakefile create mode 100644 lib/sql_algebra.rb create mode 100644 lib/sql_algebra/extensions/range.rb create mode 100644 lib/sql_algebra/relations/attribute.rb create mode 100644 lib/sql_algebra/relations/join_operation.rb create mode 100644 lib/sql_algebra/relations/join_relation.rb create mode 100644 lib/sql_algebra/relations/predicates/binary_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/equality_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/greater_than_or_equal_to_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/greater_than_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/less_than_or_equal_to_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/less_than_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/match_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/range_inclusion_predicate.rb create mode 100644 lib/sql_algebra/relations/predicates/relation_inclusion_predicate.rb create mode 100644 lib/sql_algebra/relations/relation.rb create mode 100644 lib/sql_algebra/relations/table_relation.rb create mode 100644 lib/sql_algebra/sql/select.rb create mode 100644 spec/extensions/range_spec.rb create mode 100644 spec/predicates/binary_predicate_spec.rb create mode 100644 spec/predicates/equality_predicate_spec.rb create mode 100644 spec/predicates/relation_inclusion_predicate_spec.rb create mode 100644 spec/relations/attribute_spec.rb create mode 100644 spec/relations/join_operation_spec.rb create mode 100644 spec/relations/join_relation_spec.rb create mode 100644 spec/relations/relation_spec.rb create mode 100644 spec/relations/table_relation_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/sql/select_spec.rb diff --git a/README b/README new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000000..2557babbc03cc --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require 'rubygems' +require 'spec' +require 'spec/rake/spectask' + +Spec::Rake::SpecTask.new do |t| + t.spec_files = FileList['spec/**/*_spec.rb'] +end + +desc "Default task is to run specs" +task :default => :spec \ No newline at end of file diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb new file mode 100644 index 0000000000000..b1816844e47ab --- /dev/null +++ b/lib/sql_algebra.rb @@ -0,0 +1,24 @@ +$LOAD_PATH.unshift(File.dirname(__FILE__)) +require 'rubygems' +require 'active_support' + +require 'sql_algebra/relations/relation' +require 'sql_algebra/relations/table_relation' +require 'sql_algebra/relations/join_operation' +require 'sql_algebra/relations/join_relation' +require 'sql_algebra/relations/attribute' + +require 'sql_algebra/relations/predicates/predicate' +require 'sql_algebra/relations/predicates/binary_predicate' +require 'sql_algebra/relations/predicates/equality_predicate' +require 'sql_algebra/relations/predicates/less_than_predicate' +require 'sql_algebra/relations/predicates/less_than_or_equal_to_predicate' +require 'sql_algebra/relations/predicates/greater_than_predicate' +require 'sql_algebra/relations/predicates/greater_than_or_equal_to_predicate' +require 'sql_algebra/relations/predicates/range_inclusion_predicate' +require 'sql_algebra/relations/predicates/relation_inclusion_predicate' +require 'sql_algebra/relations/predicates/match_predicate' + +require 'sql_algebra/extensions/range' + +require 'sql_algebra/sql/select' \ No newline at end of file diff --git a/lib/sql_algebra/extensions/range.rb b/lib/sql_algebra/extensions/range.rb new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb new file mode 100644 index 0000000000000..c0b8df3083c2b --- /dev/null +++ b/lib/sql_algebra/relations/attribute.rb @@ -0,0 +1,35 @@ +class Attribute + attr_reader :relation, :attribute_name + + def initialize(relation, attribute_name) + @relation, @attribute_name = relation, attribute_name + end + + def eql?(other) + relation == other.relation and attribute_name == other.attribute_name + end + + def ==(other) + EqualityPredicate.new(self, other) + end + + def <(other) + LessThanPredicate.new(self, other) + end + + def <=(other) + LessThanOrEqualToPredicate.new(self, other) + end + + def >(other) + GreaterThanPredicate.new(self, other) + end + + def >=(other) + GreaterThanOrEqualToPredicate.new(self, other) + end + + def =~(regexp) + MatchPredicate.new(self, regexp) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join_operation.rb b/lib/sql_algebra/relations/join_operation.rb new file mode 100644 index 0000000000000..dab8e9e6bd7f3 --- /dev/null +++ b/lib/sql_algebra/relations/join_operation.rb @@ -0,0 +1,16 @@ +class JoinOperation + attr_reader :relation1, :relation2 + + def initialize(relation1, relation2) + @relation1, @relation2 = relation1, relation2 + end + + def on(*predicates) + JoinRelation.new(relation1, relation2, *predicates) + end + + def ==(other) + (relation1 == other.relation1 and relation2 == other.relation2) or + (relation1 == other.relation2 and relation2 == other.relation1) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb new file mode 100644 index 0000000000000..64db8e0e68062 --- /dev/null +++ b/lib/sql_algebra/relations/join_relation.rb @@ -0,0 +1,13 @@ +class JoinRelation < Relation + attr_reader :relation1, :relation2, :predicates + + def initialize(relation1, relation2, *predicates) + @relation1, @relation2, @predicates = relation1, relation2, predicates + end + + def ==(other) + predicates == other.predicates and + ((relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2)) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/binary_predicate.rb b/lib/sql_algebra/relations/predicates/binary_predicate.rb new file mode 100644 index 0000000000000..d7f4cb20e7132 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/binary_predicate.rb @@ -0,0 +1,12 @@ +class BinaryPredicate < Predicate + attr_reader :attribute1, :attribute2 + + def initialize(attribute1, attribute2) + @attribute1, @attribute2 = attribute1, attribute2 + end + + def ==(other) + super and + (attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/equality_predicate.rb b/lib/sql_algebra/relations/predicates/equality_predicate.rb new file mode 100644 index 0000000000000..2d206e6c120ad --- /dev/null +++ b/lib/sql_algebra/relations/predicates/equality_predicate.rb @@ -0,0 +1,7 @@ +class EqualityPredicate < BinaryPredicate + def ==(other) + self.class == other.class and + ((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or + (attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1))) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/greater_than_or_equal_to_predicate.rb b/lib/sql_algebra/relations/predicates/greater_than_or_equal_to_predicate.rb new file mode 100644 index 0000000000000..49127c312c041 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/greater_than_or_equal_to_predicate.rb @@ -0,0 +1,2 @@ +class GreaterThanOrEqualToPredicate < BinaryPredicate +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/greater_than_predicate.rb b/lib/sql_algebra/relations/predicates/greater_than_predicate.rb new file mode 100644 index 0000000000000..03aecaed62601 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/greater_than_predicate.rb @@ -0,0 +1,2 @@ +class GreaterThanPredicate < BinaryPredicate +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/less_than_or_equal_to_predicate.rb b/lib/sql_algebra/relations/predicates/less_than_or_equal_to_predicate.rb new file mode 100644 index 0000000000000..fee6ea7f35627 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/less_than_or_equal_to_predicate.rb @@ -0,0 +1,2 @@ +class LessThanOrEqualToPredicate < BinaryPredicate +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/less_than_predicate.rb b/lib/sql_algebra/relations/predicates/less_than_predicate.rb new file mode 100644 index 0000000000000..03cbdcf0002e4 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/less_than_predicate.rb @@ -0,0 +1,2 @@ +class LessThanPredicate < BinaryPredicate +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/match_predicate.rb b/lib/sql_algebra/relations/predicates/match_predicate.rb new file mode 100644 index 0000000000000..90a13090d43e7 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/match_predicate.rb @@ -0,0 +1,7 @@ +class MatchPredicate < Predicate + attr_reader :attribute, :regexp + + def initialize(attribute, regexp) + @attribute, @regexp = attribute, regexp + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/predicate.rb b/lib/sql_algebra/relations/predicates/predicate.rb new file mode 100644 index 0000000000000..4c395a3fdc2b3 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/predicate.rb @@ -0,0 +1,5 @@ +class Predicate + def ==(other) + self.class == other.class + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/predicates/range_inclusion_predicate.rb b/lib/sql_algebra/relations/predicates/range_inclusion_predicate.rb new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/lib/sql_algebra/relations/predicates/relation_inclusion_predicate.rb b/lib/sql_algebra/relations/predicates/relation_inclusion_predicate.rb new file mode 100644 index 0000000000000..5881a85d997b4 --- /dev/null +++ b/lib/sql_algebra/relations/predicates/relation_inclusion_predicate.rb @@ -0,0 +1,11 @@ +class RelationInclusionPredicate < Predicate + attr_reader :attribute, :relation + + def initialize(attribute, relation) + @attribute, @relation = attribute, relation + end + + def ==(other) + super and attribute == other.attribute and relation == other.relation + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb new file mode 100644 index 0000000000000..f1f8fc5884d9f --- /dev/null +++ b/lib/sql_algebra/relations/relation.rb @@ -0,0 +1,13 @@ +class Relation + def *(other) + JoinOperation.new(self, other) + end + + def [](attribute_name) + Attribute.new(self, attribute_name) + end + + def include?(attribute) + RelationInclusionPredicate.new(attribute, self) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb new file mode 100644 index 0000000000000..dd4987c3e181a --- /dev/null +++ b/lib/sql_algebra/relations/table_relation.rb @@ -0,0 +1,11 @@ +class TableRelation < Relation + attr_reader :table + + def initialize(table) + @table = table + end + + def to_sql + Select.new(:*).from(table) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql/select.rb b/lib/sql_algebra/sql/select.rb new file mode 100644 index 0000000000000..da92ad3a5213f --- /dev/null +++ b/lib/sql_algebra/sql/select.rb @@ -0,0 +1,23 @@ +class Select + attr_reader :attributes, :tables, :predicates + + def initialize(*attributes) + @attributes = attributes + end + + def from(*tables) + returning self do |select| + @tables = tables + end + end + + def where(*predicates) + returning self do |select| + @predicates = predicates + end + end + + def ==(other) + attributes == other.attributes and tables == other.tables and predicates == other.predicates + end +end \ No newline at end of file diff --git a/spec/extensions/range_spec.rb b/spec/extensions/range_spec.rb new file mode 100644 index 0000000000000..26ca8978ca260 --- /dev/null +++ b/spec/extensions/range_spec.rb @@ -0,0 +1 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb new file mode 100644 index 0000000000000..1be7dd067df08 --- /dev/null +++ b/spec/predicates/binary_predicate_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe BinaryPredicate do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @attribute1 = Attribute.new(@relation1, :attribute_name) + @attribute2 = Attribute.new(@relation2, :attribute_name) + end + + describe BinaryPredicate, '==' do + before do + class ConcreteBinaryPredicate < BinaryPredicate + end + end + + it "obtains if attribute1 and attribute2 are identical" do + BinaryPredicate.new(@attribute1, @attribute2).should == BinaryPredicate.new(@attribute1, @attribute2) + BinaryPredicate.new(@attribute1, @attribute2).should_not == BinaryPredicate.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the BinaryPredicates are identical" do + ConcreteBinaryPredicate.new(@attribute1, @attribute2).should == ConcreteBinaryPredicate.new(@attribute1, @attribute2) + BinaryPredicate.new(@attribute1, @attribute2).should_not == ConcreteBinaryPredicate.new(@attribute1, @attribute2) + end + end +end \ No newline at end of file diff --git a/spec/predicates/equality_predicate_spec.rb b/spec/predicates/equality_predicate_spec.rb new file mode 100644 index 0000000000000..18d33991934fa --- /dev/null +++ b/spec/predicates/equality_predicate_spec.rb @@ -0,0 +1,25 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe EqualityPredicate do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @attribute1 = Attribute.new(@relation1, :attribute_name) + @attribute2 = Attribute.new(@relation2, :attribute_name) + end + + describe EqualityPredicate, '==' do + it "obtains if attribute1 and attribute2 are identical" do + EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2) + EqualityPredicate.new(@attribute1, @attribute2).should_not == EqualityPredicate.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + EqualityPredicate.new(@attribute1, @attribute2).should_not == BinaryPredicate.new(@attribute1, @attribute2) + end + + it "is commutative on the attributes" do + EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute2, @attribute1) + end + end +end \ No newline at end of file diff --git a/spec/predicates/relation_inclusion_predicate_spec.rb b/spec/predicates/relation_inclusion_predicate_spec.rb new file mode 100644 index 0000000000000..6cd37fafa8dd3 --- /dev/null +++ b/spec/predicates/relation_inclusion_predicate_spec.rb @@ -0,0 +1,16 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe RelationInclusionPredicate do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @attribute = @relation1[:baz] + end + + describe RelationInclusionPredicate, '==' do + it "obtains if attribute1 and attribute2 are identical" do + RelationInclusionPredicate.new(@attribute, @relation1).should == RelationInclusionPredicate.new(@attribute, @relation1) + RelationInclusionPredicate.new(@attribute, @relation1).should_not == RelationInclusionPredicate.new(@attribute, @relation2) + end + end +end \ No newline at end of file diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb new file mode 100644 index 0000000000000..5f2d70ec48ad4 --- /dev/null +++ b/spec/relations/attribute_spec.rb @@ -0,0 +1,60 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe Attribute do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + end + + describe Attribute, '#eql?' do + it "obtains if the relation and attribute name are identical" do + Attribute.new(@relation1, :attribute_name).should be_eql(Attribute.new(@relation1, :attribute_name)) + Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation1, :another_attribute_name)) + Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation2, :attribute_name)) + end + end + + describe Attribute, 'predications' do + before do + @attribute1 = Attribute.new(@relation1, :attribute_name) + @attribute2 = Attribute.new(@relation2, :attribute_name) + end + + describe Attribute, '==' do + it "manufactures an equality predicate" do + (@attribute1 == @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2) + end + end + + describe Attribute, '<' do + it "manufactures a less-than predicate" do + (@attribute1 < @attribute2).should == LessThanPredicate.new(@attribute1, @attribute2) + end + end + + describe Attribute, '<=' do + it "manufactures a less-than or equal-to predicate" do + (@attribute1 <= @attribute2).should == LessThanOrEqualToPredicate.new(@attribute1, @attribute2) + end + end + + describe Attribute, '>' do + it "manufactures a greater-than predicate" do + (@attribute1 > @attribute2).should == GreaterThanPredicate.new(@attribute1, @attribute2) + end + end + + describe Attribute, '>=' do + it "manufactures a greater-than or equal to predicate" do + (@attribute1 >= @attribute2).should == GreaterThanOrEqualToPredicate.new(@attribute1, @attribute2) + end + end + + describe Attribute, '=~' do + it "manufactures a match predicate" do + (@attribute1 =~ /.*/).should == MatchPredicate.new(@attribute1, @attribute2) + end + end + + end +end diff --git a/spec/relations/join_operation_spec.rb b/spec/relations/join_operation_spec.rb new file mode 100644 index 0000000000000..13e50e057e0a8 --- /dev/null +++ b/spec/relations/join_operation_spec.rb @@ -0,0 +1,29 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe JoinOperation, 'between two relations' do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + end + + describe JoinOperation, '==' do + it "obtains if the relations of both joins are identical" do + JoinOperation.new(@relation1, @relation2).should == JoinOperation.new(@relation1, @relation2) + JoinOperation.new(@relation1, @relation2).should_not == JoinOperation.new(@relation1, @relation1) + end + + it "is commutative on the relations" do + JoinOperation.new(@relation1, @relation2).should == JoinOperation.new(@relation2, @relation1) + end + end + + describe JoinOperation, 'on' do + before do + @predicate = Predicate.new + end + + it "manufactures a JoinRelation" do + JoinOperation.new(@relation1, @relation2).on(@predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) + end + end +end \ No newline at end of file diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb new file mode 100644 index 0000000000000..7309563cd5a63 --- /dev/null +++ b/spec/relations/join_relation_spec.rb @@ -0,0 +1,20 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe JoinRelation, 'between two relations' do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @predicate = Predicate.new + end + + describe JoinRelation, '==' do + it "obtains if the two relations and the predicate are identical" do + JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) + JoinRelation.new(@relation1, @relation2, @predicate).should_not == JoinRelation.new(@relation1, @relation1, @predicate) + end + + it "is commutative on the relations" do + JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation2, @relation1, @predicate) + end + end +end \ No newline at end of file diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb new file mode 100644 index 0000000000000..c482eb4a01910 --- /dev/null +++ b/spec/relations/relation_spec.rb @@ -0,0 +1,52 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe Relation do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + end + + describe Relation, '*' do + it "manufactures a JoinOperation between those two relations" do + (@relation1 * @relation2).should == JoinOperation.new(@relation1, @relation2) + end + end + + describe Relation, 'attributes' do + end + + describe Relation, '[]' do + it "manufactures a attribute" do + @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) + end + + it "raises an error if the named attribute is not part of the relation" do + end + end + + describe Relation, 'include?' do + before do + @attribute = Attribute.new(@relation1, :id) + end + + it "manufactures an inclusion predicate" do + @relation1.include?(@attribute).should == RelationInclusionPredicate.new(@attribute, @relation1) + end + end + + describe Relation, 'project' do + before do + @attribute1 = Attribute.new(@relation1, :id) + @attribute2 = Attribute.new(@relation1, :name) + end + + it "only allows projecting attributes in the relation" do + end + + it "collapses identical projections" do + end + end + + describe Relation, 'select' do + end +end \ No newline at end of file diff --git a/spec/relations/table_relation_spec.rb b/spec/relations/table_relation_spec.rb new file mode 100644 index 0000000000000..dd86f83294e2d --- /dev/null +++ b/spec/relations/table_relation_spec.rb @@ -0,0 +1,7 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe TableRelation, '#to_sql' do + it "returns a simple SELECT query" do + TableRelation.new(:users).to_sql.should == Select.new(:*).from(:users) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000000000..30c1f65f570c3 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,3 @@ +require 'rubygems' +require 'spec' +require File.join(File.dirname(__FILE__), '..', 'lib', 'sql_algebra') \ No newline at end of file diff --git a/spec/sql/select_spec.rb b/spec/sql/select_spec.rb new file mode 100644 index 0000000000000..7d40a20a5b203 --- /dev/null +++ b/spec/sql/select_spec.rb @@ -0,0 +1,19 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe Select, '==' do + it "obtains for queries with identical attributes" do + Select.new(:foo).should == Select.new(:foo) + Select.new(:bar).should_not == Select.new(:foo) + end + + it "obtains for queries with identical tables" do + Select.new(:foo).from(:bar).should == Select.new(:foo).from(:bar) + Select.new(:foo).from(:bar).should_not == Select.new(:foo).from(:foo) + end + + it "obtains for queries with identical predicates" do + Select.new(:foo).from(:bar).where(:baz).should == Select.new(:foo).from(:bar).where(:baz) + Select.new(:foo).from(:bar).where(:baz).should_not == Select.new(:foo).from(:bar).where(:foo) + end + +end \ No newline at end of file From f9cc8bba39b1deb6b3f70cecb96beaf988054915 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 30 Dec 2007 13:22:31 -0800 Subject: [PATCH 0002/1492] various --- lib/sql_algebra.rb | 24 +++++++++------- .../predicates/binary_predicate.rb | 0 .../predicates/equality_predicate.rb | 0 .../greater_than_or_equal_to_predicate.rb | 0 .../predicates/greater_than_predicate.rb | 0 .../less_than_or_equal_to_predicate.rb | 0 .../predicates/less_than_predicate.rb | 0 .../predicates/match_predicate.rb | 0 .../{relations => }/predicates/predicate.rb | 0 .../predicates/range_inclusion_predicate.rb | 0 .../relation_inclusion_predicate.rb | 0 lib/sql_algebra/relations/order_relation.rb | 11 ++++++++ .../relations/projection_relation.rb | 11 ++++++++ lib/sql_algebra/relations/range_relation.rb | 11 ++++++++ .../relations/selection_relation.rb | 12 ++++++++ spec/predicates/binary_predicate_spec.rb | 6 ++++ spec/relations/order_relation_spec.rb | 18 ++++++++++++ spec/relations/projection_relation_spec.rb | 18 ++++++++++++ spec/relations/range_relation_spec.rb | 18 ++++++++++++ spec/relations/relation_spec.rb | 23 +++++++++++---- spec/relations/selection_relation_spec.rb | 28 +++++++++++++++++++ 21 files changed, 164 insertions(+), 16 deletions(-) rename lib/sql_algebra/{relations => }/predicates/binary_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/equality_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/greater_than_or_equal_to_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/greater_than_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/less_than_or_equal_to_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/less_than_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/match_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/range_inclusion_predicate.rb (100%) rename lib/sql_algebra/{relations => }/predicates/relation_inclusion_predicate.rb (100%) create mode 100644 lib/sql_algebra/relations/order_relation.rb create mode 100644 lib/sql_algebra/relations/projection_relation.rb create mode 100644 lib/sql_algebra/relations/range_relation.rb create mode 100644 lib/sql_algebra/relations/selection_relation.rb create mode 100644 spec/relations/order_relation_spec.rb create mode 100644 spec/relations/projection_relation_spec.rb create mode 100644 spec/relations/range_relation_spec.rb create mode 100644 spec/relations/selection_relation_spec.rb diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index b1816844e47ab..7407dc264bc3d 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -7,17 +7,21 @@ require 'sql_algebra/relations/join_operation' require 'sql_algebra/relations/join_relation' require 'sql_algebra/relations/attribute' +require 'sql_algebra/relations/projection_relation' +require 'sql_algebra/relations/selection_relation' +require 'sql_algebra/relations/order_relation' +require 'sql_algebra/relations/range_relation' -require 'sql_algebra/relations/predicates/predicate' -require 'sql_algebra/relations/predicates/binary_predicate' -require 'sql_algebra/relations/predicates/equality_predicate' -require 'sql_algebra/relations/predicates/less_than_predicate' -require 'sql_algebra/relations/predicates/less_than_or_equal_to_predicate' -require 'sql_algebra/relations/predicates/greater_than_predicate' -require 'sql_algebra/relations/predicates/greater_than_or_equal_to_predicate' -require 'sql_algebra/relations/predicates/range_inclusion_predicate' -require 'sql_algebra/relations/predicates/relation_inclusion_predicate' -require 'sql_algebra/relations/predicates/match_predicate' +require 'sql_algebra/predicates/predicate' +require 'sql_algebra/predicates/binary_predicate' +require 'sql_algebra/predicates/equality_predicate' +require 'sql_algebra/predicates/less_than_predicate' +require 'sql_algebra/predicates/less_than_or_equal_to_predicate' +require 'sql_algebra/predicates/greater_than_predicate' +require 'sql_algebra/predicates/greater_than_or_equal_to_predicate' +require 'sql_algebra/predicates/range_inclusion_predicate' +require 'sql_algebra/predicates/relation_inclusion_predicate' +require 'sql_algebra/predicates/match_predicate' require 'sql_algebra/extensions/range' diff --git a/lib/sql_algebra/relations/predicates/binary_predicate.rb b/lib/sql_algebra/predicates/binary_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/binary_predicate.rb rename to lib/sql_algebra/predicates/binary_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/equality_predicate.rb b/lib/sql_algebra/predicates/equality_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/equality_predicate.rb rename to lib/sql_algebra/predicates/equality_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/greater_than_or_equal_to_predicate.rb b/lib/sql_algebra/predicates/greater_than_or_equal_to_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/greater_than_or_equal_to_predicate.rb rename to lib/sql_algebra/predicates/greater_than_or_equal_to_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/greater_than_predicate.rb b/lib/sql_algebra/predicates/greater_than_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/greater_than_predicate.rb rename to lib/sql_algebra/predicates/greater_than_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/less_than_or_equal_to_predicate.rb b/lib/sql_algebra/predicates/less_than_or_equal_to_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/less_than_or_equal_to_predicate.rb rename to lib/sql_algebra/predicates/less_than_or_equal_to_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/less_than_predicate.rb b/lib/sql_algebra/predicates/less_than_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/less_than_predicate.rb rename to lib/sql_algebra/predicates/less_than_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/match_predicate.rb b/lib/sql_algebra/predicates/match_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/match_predicate.rb rename to lib/sql_algebra/predicates/match_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/predicate.rb b/lib/sql_algebra/predicates/predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/predicate.rb rename to lib/sql_algebra/predicates/predicate.rb diff --git a/lib/sql_algebra/relations/predicates/range_inclusion_predicate.rb b/lib/sql_algebra/predicates/range_inclusion_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/range_inclusion_predicate.rb rename to lib/sql_algebra/predicates/range_inclusion_predicate.rb diff --git a/lib/sql_algebra/relations/predicates/relation_inclusion_predicate.rb b/lib/sql_algebra/predicates/relation_inclusion_predicate.rb similarity index 100% rename from lib/sql_algebra/relations/predicates/relation_inclusion_predicate.rb rename to lib/sql_algebra/predicates/relation_inclusion_predicate.rb diff --git a/lib/sql_algebra/relations/order_relation.rb b/lib/sql_algebra/relations/order_relation.rb new file mode 100644 index 0000000000000..8d07c58d64927 --- /dev/null +++ b/lib/sql_algebra/relations/order_relation.rb @@ -0,0 +1,11 @@ +class OrderRelation < Relation + attr_reader :relation, :attributes + + def initialize(relation, *attributes) + @relation, @attributes = relation, attributes + end + + def ==(other) + relation == other.relation and attributes.eql?(other.attributes) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/projection_relation.rb b/lib/sql_algebra/relations/projection_relation.rb new file mode 100644 index 0000000000000..caebfc1b62c9e --- /dev/null +++ b/lib/sql_algebra/relations/projection_relation.rb @@ -0,0 +1,11 @@ +class ProjectionRelation < Relation + attr_reader :relation, :attributes + + def initialize(relation, *attributes) + @relation, @attributes = relation, attributes + end + + def ==(other) + relation == other.relation and attributes.eql?(other.attributes) + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/range_relation.rb b/lib/sql_algebra/relations/range_relation.rb new file mode 100644 index 0000000000000..fd7e2898fad0d --- /dev/null +++ b/lib/sql_algebra/relations/range_relation.rb @@ -0,0 +1,11 @@ +class RangeRelation < Relation + attr_reader :relation, :range + + def initialize(relation, range) + @relation, @range = relation, range + end + + def ==(other) + relation == other.relation and range == other.range + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/sql_algebra/relations/selection_relation.rb new file mode 100644 index 0000000000000..5654d8de31c9e --- /dev/null +++ b/lib/sql_algebra/relations/selection_relation.rb @@ -0,0 +1,12 @@ +class SelectionRelation < Relation + attr_reader :relation, :predicate + + def initialize(relation, *predicates) + @predicate = predicates.shift + @relation = predicates.empty?? relation : SelectionRelation.new(relation, *predicates) + end + + def ==(other) + relation == other.relation and predicate == other.predicate + end +end \ No newline at end of file diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb index 1be7dd067df08..58e395b08de43 100644 --- a/spec/predicates/binary_predicate_spec.rb +++ b/spec/predicates/binary_predicate_spec.rb @@ -8,6 +8,12 @@ @attribute2 = Attribute.new(@relation2, :attribute_name) end + describe BinaryPredicate, '#initialize' do + it "requires that both columns come from the same relation" do + pending + end + end + describe BinaryPredicate, '==' do before do class ConcreteBinaryPredicate < BinaryPredicate diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb new file mode 100644 index 0000000000000..362544d0d137c --- /dev/null +++ b/spec/relations/order_relation_spec.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe OrderRelation do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @attribute1 = @relation1[:foo] + @attribute2 = @relation2[:bar] + end + + describe OrderRelation, '==' do + it "obtains if the relation and attributes are identical" do + OrderRelation.new(@relation1, @attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) + OrderRelation.new(@relation1, @attribute1).should_not == OrderRelation.new(@relation2, @attribute1) + OrderRelation.new(@relation1, @attribute1, @attribute2).should_not == OrderRelation.new(@relation1, @attribute2, @attribute1) + end + end +end \ No newline at end of file diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb new file mode 100644 index 0000000000000..f802a2e293b92 --- /dev/null +++ b/spec/relations/projection_relation_spec.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe ProjectionRelation do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @attribute1 = @relation1[:foo] + @attribute2 = @relation2[:bar] + end + + describe ProjectionRelation, '==' do + it "obtains if the relations and attributes are identical" do + ProjectionRelation.new(@relation1, @attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) + ProjectionRelation.new(@relation1, @attribute1).should_not == ProjectionRelation.new(@relation2, @attribute1) + ProjectionRelation.new(@relation1, @attribute1).should_not == ProjectionRelation.new(@relation1, @attribute2) + end + end +end \ No newline at end of file diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb new file mode 100644 index 0000000000000..2a1cd1d070a2a --- /dev/null +++ b/spec/relations/range_relation_spec.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe RangeRelation do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @range1 = 1..2 + @range2 = Time.now..2.days.from_now + end + + describe RangeRelation, '==' do + it "obtains if the relation and range are identical" do + RangeRelation.new(@relation1, @range1).should == RangeRelation.new(@relation1, @range1) + RangeRelation.new(@relation1, @range1).should_not == RangeRelation.new(@relation2, @range1) + RangeRelation.new(@relation1, @range1).should_not == RangeRelation.new(@relation1, @range2) + end + end +end \ No newline at end of file diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index c482eb4a01910..7434bd563b135 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -12,19 +12,17 @@ end end - describe Relation, 'attributes' do - end - describe Relation, '[]' do it "manufactures a attribute" do @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) end it "raises an error if the named attribute is not part of the relation" do + pending end end - describe Relation, 'include?' do + describe Relation, '#include?' do before do @attribute = Attribute.new(@relation1, :id) end @@ -34,19 +32,32 @@ end end - describe Relation, 'project' do + describe Relation, '#project' do before do @attribute1 = Attribute.new(@relation1, :id) @attribute2 = Attribute.new(@relation1, :name) end it "only allows projecting attributes in the relation" do + pending end it "collapses identical projections" do + pending + end + + it "manufactures a projected relation" do + @relation1.project(@attribute1, @attribute2).should == ProjectedRelation(@relation1, @attribute1, @attribute2) end end - describe Relation, 'select' do + describe Relation, '#select' do + before do + @predicate = EqualityPredicate.new() + end + + it "manufactures a selected relation" do + @relation1.select(@attribute1, @attribute2).should == SelectedRelation(@relation1, @attribute1, @attribute2) + end end end \ No newline at end of file diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb new file mode 100644 index 0000000000000..0cfd55449c185 --- /dev/null +++ b/spec/relations/selection_relation_spec.rb @@ -0,0 +1,28 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe SelectionRelation do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @predicate1 = EqualityPredicate.new(@relation1[:id], @relation2[:foo_id]) + @predicate2 = LessThanPredicate.new(@relation1[:age], 2) + end + + describe SelectionRelation, '==' do + it "obtains if both the predicate and the relation are identical" do + SelectionRelation.new(@relation1, @predicate1). \ + should == SelectionRelation.new(@relation1, @predicate1) + SelectionRelation.new(@relation1, @predicate1). \ + should_not == SelectionRelation.new(@relation2, @predicate1) + SelectionRelation.new(@relation1, @predicate1). \ + should_not == SelectionRelation.new(@relation1, @predicate2) + end + end + + describe SelectionRelation, '#initialize' do + it "manufactures nested selection relations if multiple predicates are provided" do + SelectionRelation.new(@relation1, @predicate1, @predicate2). \ + should == SelectionRelation.new(SelectionRelation.new(@relation1, @predicate2), @predicate1) + end + end +end \ No newline at end of file From 63b9c6a41f7ab92a16362a50b60bcea7e20cb427 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 30 Dec 2007 13:48:13 -0800 Subject: [PATCH 0003/1492] joins --- lib/sql_algebra.rb | 4 ++ lib/sql_algebra/relations/join_operation.rb | 2 +- lib/sql_algebra/relations/relation.rb | 29 ++++++++++-- spec/relations/join_operation_spec.rb | 10 +++- spec/relations/relation_spec.rb | 51 +++++++++++++-------- 5 files changed, 69 insertions(+), 27 deletions(-) diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 7407dc264bc3d..8adbed150d768 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -5,7 +5,11 @@ require 'sql_algebra/relations/relation' require 'sql_algebra/relations/table_relation' require 'sql_algebra/relations/join_operation' +require 'sql_algebra/relations/inner_join_operation' +require 'sql_algebra/relations/left_outer_join_operation' require 'sql_algebra/relations/join_relation' +require 'sql_algebra/relations/inner_join_relation' +require 'sql_algebra/relations/left_outer_join_relation' require 'sql_algebra/relations/attribute' require 'sql_algebra/relations/projection_relation' require 'sql_algebra/relations/selection_relation' diff --git a/lib/sql_algebra/relations/join_operation.rb b/lib/sql_algebra/relations/join_operation.rb index dab8e9e6bd7f3..2b4548a041af3 100644 --- a/lib/sql_algebra/relations/join_operation.rb +++ b/lib/sql_algebra/relations/join_operation.rb @@ -6,7 +6,7 @@ def initialize(relation1, relation2) end def on(*predicates) - JoinRelation.new(relation1, relation2, *predicates) + relation_class.new(relation1, relation2, *predicates) end def ==(other) diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb index f1f8fc5884d9f..bd812b368d2e1 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/sql_algebra/relations/relation.rb @@ -1,13 +1,34 @@ class Relation - def *(other) - JoinOperation.new(self, other) + def <=>(other) + InnerJoinOperation.new(self, other) end - def [](attribute_name) - Attribute.new(self, attribute_name) + def <<(other) + LeftOuterJoinOperation.new(self, other) + end + + def [](index) + case index + when Symbol + Attribute.new(self, index) + when Range + RangeRelation.new(self, index) + end end def include?(attribute) RelationInclusionPredicate.new(attribute, self) end + + def select(*predicates) + SelectionRelation.new(self, *predicates) + end + + def project(*attributes) + ProjectionRelation.new(self, *attributes) + end + + def order(*attributes) + OrderRelation.new(self, *attributes) + end end \ No newline at end of file diff --git a/spec/relations/join_operation_spec.rb b/spec/relations/join_operation_spec.rb index 13e50e057e0a8..d75d2d5c93f68 100644 --- a/spec/relations/join_operation_spec.rb +++ b/spec/relations/join_operation_spec.rb @@ -20,10 +20,16 @@ describe JoinOperation, 'on' do before do @predicate = Predicate.new + @join_operation = JoinOperation.new(@relation1, @relation2) + class << @join_operation + def relation_class + JoinRelation + end + end end - it "manufactures a JoinRelation" do - JoinOperation.new(@relation1, @relation2).on(@predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) + it "manufactures a join relation of the appropriate type" do + @join_operation.on(@predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) end end end \ No newline at end of file diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index 7434bd563b135..6c2c2b86112ba 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -4,40 +4,45 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) + @attribute1 = Attribute.new(@relation1, :id) + @attribute2 = Attribute.new(@relation1, :name) end - describe Relation, '*' do - it "manufactures a JoinOperation between those two relations" do - (@relation1 * @relation2).should == JoinOperation.new(@relation1, @relation2) + describe Relation, 'joins' do + describe Relation, '<=>' do + it "manufactures an inner join operation between those two relations" do + (@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2) + end + end + + describe Relation, '<<' do + it "manufactures a left outer join operation between those two relations" do + (@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2) + end end end describe Relation, '[]' do - it "manufactures a attribute" do + it "manufactures an attribute when given a symbol" do @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) end + it "manufactures a range relation when given a range" do + @relation1[1..2].should == RangeRelation.new(@relation1, 1..2) + end + it "raises an error if the named attribute is not part of the relation" do pending end end describe Relation, '#include?' do - before do - @attribute = Attribute.new(@relation1, :id) - end - it "manufactures an inclusion predicate" do - @relation1.include?(@attribute).should == RelationInclusionPredicate.new(@attribute, @relation1) + @relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1) end end describe Relation, '#project' do - before do - @attribute1 = Attribute.new(@relation1, :id) - @attribute2 = Attribute.new(@relation1, :name) - end - it "only allows projecting attributes in the relation" do pending end @@ -46,18 +51,24 @@ pending end - it "manufactures a projected relation" do - @relation1.project(@attribute1, @attribute2).should == ProjectedRelation(@relation1, @attribute1, @attribute2) + it "manufactures a projection relation" do + @relation1.project(@attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) end end describe Relation, '#select' do before do - @predicate = EqualityPredicate.new() + @predicate = EqualityPredicate.new(@attribute1, @attribute2) end - it "manufactures a selected relation" do - @relation1.select(@attribute1, @attribute2).should == SelectedRelation(@relation1, @attribute1, @attribute2) + it "manufactures a selection relation" do + @relation1.select(@attribute1, @attribute2).should == SelectionRelation.new(@relation1, @attribute1, @attribute2) end - end + end + + describe Relation, 'order' do + it "manufactures an order relation" do + @relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) + end + end end \ No newline at end of file From 1a59c8cbc90d37fa571c12049d0e43aa44d46388 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 30 Dec 2007 17:35:23 -0800 Subject: [PATCH 0004/1492] sql builder --- lib/sql_algebra.rb | 3 ++- lib/sql_algebra/relations/table_relation.rb | 5 ++++- lib/sql_algebra/sql/select.rb | 23 --------------------- spec/relations/table_relation_spec.rb | 5 ++++- spec/spec_helper.rb | 7 ++++++- spec/sql/select_spec.rb | 19 ----------------- 6 files changed, 16 insertions(+), 46 deletions(-) delete mode 100644 lib/sql_algebra/sql/select.rb delete mode 100644 spec/sql/select_spec.rb diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 8adbed150d768..79bdc8a449f40 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -29,4 +29,5 @@ require 'sql_algebra/extensions/range' -require 'sql_algebra/sql/select' \ No newline at end of file +require 'sql_algebra/sql_builder/sql_builder' +require 'sql_algebra/sql_builder/select_builder' \ No newline at end of file diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb index dd4987c3e181a..17cdbab61a0ee 100644 --- a/lib/sql_algebra/relations/table_relation.rb +++ b/lib/sql_algebra/relations/table_relation.rb @@ -6,6 +6,9 @@ def initialize(table) end def to_sql - Select.new(:*).from(table) + SelectBuilder.new do + select :* + from table + end end end \ No newline at end of file diff --git a/lib/sql_algebra/sql/select.rb b/lib/sql_algebra/sql/select.rb deleted file mode 100644 index da92ad3a5213f..0000000000000 --- a/lib/sql_algebra/sql/select.rb +++ /dev/null @@ -1,23 +0,0 @@ -class Select - attr_reader :attributes, :tables, :predicates - - def initialize(*attributes) - @attributes = attributes - end - - def from(*tables) - returning self do |select| - @tables = tables - end - end - - def where(*predicates) - returning self do |select| - @predicates = predicates - end - end - - def ==(other) - attributes == other.attributes and tables == other.tables and predicates == other.predicates - end -end \ No newline at end of file diff --git a/spec/relations/table_relation_spec.rb b/spec/relations/table_relation_spec.rb index dd86f83294e2d..a0647aa541c65 100644 --- a/spec/relations/table_relation_spec.rb +++ b/spec/relations/table_relation_spec.rb @@ -2,6 +2,9 @@ describe TableRelation, '#to_sql' do it "returns a simple SELECT query" do - TableRelation.new(:users).to_sql.should == Select.new(:*).from(:users) + TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s| + select :* + from :users + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 30c1f65f570c3..a764fff03ef8a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,8 @@ require 'rubygems' require 'spec' -require File.join(File.dirname(__FILE__), '..', 'lib', 'sql_algebra') \ No newline at end of file +require File.join(File.dirname(__FILE__), '..', 'lib', 'sql_algebra') +require File.join(File.dirname(__FILE__), 'spec_helpers', 'be_like') + +Spec::Runner.configure do |config| + config.include(BeLikeMatcher) +end \ No newline at end of file diff --git a/spec/sql/select_spec.rb b/spec/sql/select_spec.rb deleted file mode 100644 index 7d40a20a5b203..0000000000000 --- a/spec/sql/select_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') - -describe Select, '==' do - it "obtains for queries with identical attributes" do - Select.new(:foo).should == Select.new(:foo) - Select.new(:bar).should_not == Select.new(:foo) - end - - it "obtains for queries with identical tables" do - Select.new(:foo).from(:bar).should == Select.new(:foo).from(:bar) - Select.new(:foo).from(:bar).should_not == Select.new(:foo).from(:foo) - end - - it "obtains for queries with identical predicates" do - Select.new(:foo).from(:bar).where(:baz).should == Select.new(:foo).from(:bar).where(:baz) - Select.new(:foo).from(:bar).where(:baz).should_not == Select.new(:foo).from(:bar).where(:foo) - end - -end \ No newline at end of file From 1c1c878e2d2ea6d437f8e1011492c78f1916196e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 30 Dec 2007 17:43:34 -0800 Subject: [PATCH 0005/1492] nk - broken out into multiple files --- lib/sql_algebra.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 79bdc8a449f40..8cd44386ad033 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -30,4 +30,10 @@ require 'sql_algebra/extensions/range' require 'sql_algebra/sql_builder/sql_builder' -require 'sql_algebra/sql_builder/select_builder' \ No newline at end of file +require 'sql_algebra/sql_builder/select_builder' +require 'sql_algebra/sql_builder/where_builder' +require 'sql_algebra/sql_builder/joins_builder' +require 'sql_algebra/sql_builder/join_builder' +require 'sql_algebra/sql_builder/inner_join_builder' +require 'sql_algebra/sql_builder/left_outer_join_builder' +require 'sql_algebra/sql_builder/equals_condition_builder' From bd5a4d6d22321f10eb716024f01a1f84f1b80d3f Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 30 Dec 2007 23:59:29 -0800 Subject: [PATCH 0006/1492] before doing crazy --- lib/sql_algebra.rb | 3 ++ .../predicates/binary_predicate.rb | 6 ++++ .../predicates/equality_predicate.rb | 5 +++ lib/sql_algebra/relations/attribute.rb | 4 +++ lib/sql_algebra/relations/join_relation.rb | 36 +++++++++++++++++++ .../relations/selection_relation.rb | 8 +++++ lib/sql_algebra/relations/table_relation.rb | 4 +-- spec/predicates/binary_predicate_spec.rb | 26 +++++++++----- spec/relations/attribute_spec.rb | 23 +++++++----- spec/relations/join_operation_spec.rb | 6 ++-- spec/relations/join_relation_spec.rb | 35 +++++++++++++++--- spec/relations/selection_relation_spec.rb | 16 +++++++-- 12 files changed, 142 insertions(+), 30 deletions(-) diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 8cd44386ad033..e8955ae18bc0b 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -37,3 +37,6 @@ require 'sql_algebra/sql_builder/inner_join_builder' require 'sql_algebra/sql_builder/left_outer_join_builder' require 'sql_algebra/sql_builder/equals_condition_builder' +require 'sql_algebra/sql_builder/column_builder' +require 'sql_algebra/sql_builder/conditions_builder' + diff --git a/lib/sql_algebra/predicates/binary_predicate.rb b/lib/sql_algebra/predicates/binary_predicate.rb index d7f4cb20e7132..3e5b9ce1930fc 100644 --- a/lib/sql_algebra/predicates/binary_predicate.rb +++ b/lib/sql_algebra/predicates/binary_predicate.rb @@ -9,4 +9,10 @@ def ==(other) super and (attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) end + + def to_sql(builder = ConditionsBuilder.new) + builder.call do + send(predicate_name, attribute1.to_sql(self), attribute2.to_sql(self)) + end + end end \ No newline at end of file diff --git a/lib/sql_algebra/predicates/equality_predicate.rb b/lib/sql_algebra/predicates/equality_predicate.rb index 2d206e6c120ad..2061d0f6446ad 100644 --- a/lib/sql_algebra/predicates/equality_predicate.rb +++ b/lib/sql_algebra/predicates/equality_predicate.rb @@ -4,4 +4,9 @@ def ==(other) ((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or (attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1))) end + + protected + def predicate_name + :equals + end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb index c0b8df3083c2b..7a4a0d72c5e21 100644 --- a/lib/sql_algebra/relations/attribute.rb +++ b/lib/sql_algebra/relations/attribute.rb @@ -32,4 +32,8 @@ def >=(other) def =~(regexp) MatchPredicate.new(self, regexp) end + + def to_sql(ignore_builder_because_i_can_only_exist_atomically) + ColumnBuilder.new(relation.table, attribute_name) + end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb index 64db8e0e68062..4052798d511f3 100644 --- a/lib/sql_algebra/relations/join_relation.rb +++ b/lib/sql_algebra/relations/join_relation.rb @@ -10,4 +10,40 @@ def ==(other) ((relation1 == other.relation1 and relation2 == other.relation2) or (relation2 == other.relation1 and relation1 == other.relation2)) end + + def to_sql(builder = SelectBuilder.new) + enclosed_join_name, enclosed_predicates = join_name, predicates + relation2.to_sql(Adapter.new(relation1.to_sql(builder)) do + define_method :from do |table| + send(enclosed_join_name, table) do + enclosed_predicates.each do |predicate| + predicate.to_sql(self) + end + end + end + end) + end + + class Adapter + instance_methods.each { |m| undef_method m unless m =~ /^__|^instance_eval/ } + + def initialize(adaptee, &block) + @adaptee = adaptee + (class << self; self end).class_eval do + (adaptee.methods - instance_methods).each { |m| delegate m, :to => :@adaptee } + end + (class << self; self end).class_eval(&block) + end + + def call(&block) + @caller = eval("self", block.binding) + returning self do |adapter| + instance_eval(&block) + end + end + + def method_missing(method, *args, &block) + @caller.send(method, *args, &block) + end + end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/sql_algebra/relations/selection_relation.rb index 5654d8de31c9e..cce93917c4fc0 100644 --- a/lib/sql_algebra/relations/selection_relation.rb +++ b/lib/sql_algebra/relations/selection_relation.rb @@ -9,4 +9,12 @@ def initialize(relation, *predicates) def ==(other) relation == other.relation and predicate == other.predicate end + + def to_sql(builder = SelectBuilder.new) + relation.to_sql(builder).call do + where do + predicate.to_sql(self) + end + end + end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb index 17cdbab61a0ee..eee24e5d68cd1 100644 --- a/lib/sql_algebra/relations/table_relation.rb +++ b/lib/sql_algebra/relations/table_relation.rb @@ -5,8 +5,8 @@ def initialize(table) @table = table end - def to_sql - SelectBuilder.new do + def to_sql(builder = SelectBuilder.new) + builder.call do select :* from table end diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb index 58e395b08de43..3d9a9b3b94b6b 100644 --- a/spec/predicates/binary_predicate_spec.rb +++ b/spec/predicates/binary_predicate_spec.rb @@ -4,22 +4,22 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :attribute_name) - @attribute2 = Attribute.new(@relation2, :attribute_name) + @attribute1 = Attribute.new(@relation1, :attribute_name1) + @attribute2 = Attribute.new(@relation2, :attribute_name2) + class ConcreteBinaryPredicate < BinaryPredicate + def predicate_name + :equals + end + end end - describe BinaryPredicate, '#initialize' do + describe '#initialize' do it "requires that both columns come from the same relation" do pending end end - describe BinaryPredicate, '==' do - before do - class ConcreteBinaryPredicate < BinaryPredicate - end - end - + describe '==' do it "obtains if attribute1 and attribute2 are identical" do BinaryPredicate.new(@attribute1, @attribute2).should == BinaryPredicate.new(@attribute1, @attribute2) BinaryPredicate.new(@attribute1, @attribute2).should_not == BinaryPredicate.new(@attribute1, @attribute1) @@ -30,4 +30,12 @@ class ConcreteBinaryPredicate < BinaryPredicate BinaryPredicate.new(@attribute1, @attribute2).should_not == ConcreteBinaryPredicate.new(@attribute1, @attribute2) end end + + describe '#to_sql' do + it '' do + ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do + equals 'foo.attribute_name1', 'bar.attribute_name2' + end + end + end end \ No newline at end of file diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb index 5f2d70ec48ad4..78d602abf90f7 100644 --- a/spec/relations/attribute_spec.rb +++ b/spec/relations/attribute_spec.rb @@ -6,7 +6,7 @@ @relation2 = TableRelation.new(:bar) end - describe Attribute, '#eql?' do + describe '#eql?' do it "obtains if the relation and attribute name are identical" do Attribute.new(@relation1, :attribute_name).should be_eql(Attribute.new(@relation1, :attribute_name)) Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation1, :another_attribute_name)) @@ -14,47 +14,52 @@ end end - describe Attribute, 'predications' do + describe 'predications' do before do @attribute1 = Attribute.new(@relation1, :attribute_name) @attribute2 = Attribute.new(@relation2, :attribute_name) end - describe Attribute, '==' do + describe '==' do it "manufactures an equality predicate" do (@attribute1 == @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2) end end - describe Attribute, '<' do + describe '<' do it "manufactures a less-than predicate" do (@attribute1 < @attribute2).should == LessThanPredicate.new(@attribute1, @attribute2) end end - describe Attribute, '<=' do + describe '<=' do it "manufactures a less-than or equal-to predicate" do (@attribute1 <= @attribute2).should == LessThanOrEqualToPredicate.new(@attribute1, @attribute2) end end - describe Attribute, '>' do + describe '>' do it "manufactures a greater-than predicate" do (@attribute1 > @attribute2).should == GreaterThanPredicate.new(@attribute1, @attribute2) end end - describe Attribute, '>=' do + describe '>=' do it "manufactures a greater-than or equal to predicate" do (@attribute1 >= @attribute2).should == GreaterThanOrEqualToPredicate.new(@attribute1, @attribute2) end end - describe Attribute, '=~' do + describe '=~' do it "manufactures a match predicate" do (@attribute1 =~ /.*/).should == MatchPredicate.new(@attribute1, @attribute2) end end - + end + + describe '#to_sql' do + it "manufactures a column" do + Attribute.new(@relation1, :attribute_name).to_sql.should == ColumnBuilder.new(@relation1.table, :attribute_name) + end end end diff --git a/spec/relations/join_operation_spec.rb b/spec/relations/join_operation_spec.rb index d75d2d5c93f68..db30198f6ec3b 100644 --- a/spec/relations/join_operation_spec.rb +++ b/spec/relations/join_operation_spec.rb @@ -1,12 +1,12 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper') -describe JoinOperation, 'between two relations' do +describe 'between two relations' do before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) end - describe JoinOperation, '==' do + describe '==' do it "obtains if the relations of both joins are identical" do JoinOperation.new(@relation1, @relation2).should == JoinOperation.new(@relation1, @relation2) JoinOperation.new(@relation1, @relation2).should_not == JoinOperation.new(@relation1, @relation1) @@ -17,7 +17,7 @@ end end - describe JoinOperation, 'on' do + describe 'on' do before do @predicate = Predicate.new @join_operation = JoinOperation.new(@relation1, @relation2) diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb index 7309563cd5a63..c6fae90ff3d33 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/relations/join_relation_spec.rb @@ -1,20 +1,45 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper') -describe JoinRelation, 'between two relations' do +describe 'between two relations' do before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @predicate = Predicate.new + @predicate = EqualityPredicate.new(@relation1[:a], @relation2[:b]) end - describe JoinRelation, '==' do - it "obtains if the two relations and the predicate are identical" do + describe '==' do + it 'obtains if the two relations and the predicate are identical' do JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) JoinRelation.new(@relation1, @relation2, @predicate).should_not == JoinRelation.new(@relation1, @relation1, @predicate) end - it "is commutative on the relations" do + it 'is commutative on the relations' do JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation2, @relation1, @predicate) end end + + describe '#to_sql' do + before do + @relation1 = @relation1.select(@relation1[:c] == @relation2[:d]) + class ConcreteJoinRelation < JoinRelation + def join_name + :inner_join + end + end + end + + it 'manufactures sql joining the two tables on the predicate, merging the selects' do + ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_sql.to_s.should == SelectBuilder.new do + select :* + from :foo do + inner_join :bar do + equals 'foo.a', 'bar.b' + end + end + where do + equals 'foo.c', 'bar.d' + end + end.to_s + end + end end \ No newline at end of file diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb index 0cfd55449c185..1f8b760272770 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/relations/selection_relation_spec.rb @@ -8,7 +8,7 @@ @predicate2 = LessThanPredicate.new(@relation1[:age], 2) end - describe SelectionRelation, '==' do + describe '==' do it "obtains if both the predicate and the relation are identical" do SelectionRelation.new(@relation1, @predicate1). \ should == SelectionRelation.new(@relation1, @predicate1) @@ -19,10 +19,22 @@ end end - describe SelectionRelation, '#initialize' do + describe '#initialize' do it "manufactures nested selection relations if multiple predicates are provided" do SelectionRelation.new(@relation1, @predicate1, @predicate2). \ should == SelectionRelation.new(SelectionRelation.new(@relation1, @predicate2), @predicate1) end end + + describe '#to_sql' do + it "manufactures sql with where clause conditions" do + SelectionRelation.new(@relation1, @predicate1).to_sql.should == SelectBuilder.new do + select :* + from :foo + where do + equals 'foo.id', 'bar.foo_id' + end + end + end + end end \ No newline at end of file From 9a976c1bbcbdcf253d90253f2a10068316aa663b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 31 Dec 2007 12:38:20 -0800 Subject: [PATCH 0007/1492] cleanest implementation of adapter i could manage --- lib/sql_algebra.rb | 2 +- lib/sql_algebra/relations/attribute.rb | 2 +- lib/sql_algebra/relations/join_relation.rb | 41 +++++++--------------- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index e8955ae18bc0b..8389250755495 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -29,9 +29,9 @@ require 'sql_algebra/extensions/range' +require 'sql_algebra/sql_builder/sql_builder_adapter' require 'sql_algebra/sql_builder/sql_builder' require 'sql_algebra/sql_builder/select_builder' -require 'sql_algebra/sql_builder/where_builder' require 'sql_algebra/sql_builder/joins_builder' require 'sql_algebra/sql_builder/join_builder' require 'sql_algebra/sql_builder/inner_join_builder' diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb index 7a4a0d72c5e21..af448286f1365 100644 --- a/lib/sql_algebra/relations/attribute.rb +++ b/lib/sql_algebra/relations/attribute.rb @@ -33,7 +33,7 @@ def =~(regexp) MatchPredicate.new(self, regexp) end - def to_sql(ignore_builder_because_i_can_only_exist_atomically) + def to_sql(ignore_builder_because_i_can_only_exist_atomically = nil) ColumnBuilder.new(relation.table, attribute_name) end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb index 4052798d511f3..b96cd175de785 100644 --- a/lib/sql_algebra/relations/join_relation.rb +++ b/lib/sql_algebra/relations/join_relation.rb @@ -12,38 +12,23 @@ def ==(other) end def to_sql(builder = SelectBuilder.new) - enclosed_join_name, enclosed_predicates = join_name, predicates - relation2.to_sql(Adapter.new(relation1.to_sql(builder)) do + relation2.to_sql(translate_from_to_inner_join_on_predicates(relation1.to_sql(builder))) + end + + private + # translate 'from' to 'inner join on ' + def translate_from_to_inner_join_on_predicates(builder) + schmoin_name, schmredicates = join_name, predicates + SqlBuilderAdapter.new(builder) do |builder| define_method :from do |table| - send(enclosed_join_name, table) do - enclosed_predicates.each do |predicate| - predicate.to_sql(self) + builder.call do + send(schmoin_name, table) do + schmredicates.each do |predicate| + predicate.to_sql(self) + end end end end - end) - end - - class Adapter - instance_methods.each { |m| undef_method m unless m =~ /^__|^instance_eval/ } - - def initialize(adaptee, &block) - @adaptee = adaptee - (class << self; self end).class_eval do - (adaptee.methods - instance_methods).each { |m| delegate m, :to => :@adaptee } - end - (class << self; self end).class_eval(&block) - end - - def call(&block) - @caller = eval("self", block.binding) - returning self do |adapter| - instance_eval(&block) - end - end - - def method_missing(method, *args, &block) - @caller.send(method, *args, &block) end end end \ No newline at end of file From 0496a59e1fe0caf2d295defb588a00460cf15efb Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 31 Dec 2007 13:25:32 -0800 Subject: [PATCH 0008/1492] more to_sql --- lib/sql_algebra/relations/order_relation.rb | 8 ++++++++ .../relations/projection_relation.rb | 6 ++++++ lib/sql_algebra/relations/range_relation.rb | 7 +++++++ spec/relations/order_relation_spec.rb | 13 ++++++++++++- spec/relations/projection_relation_spec.rb | 11 ++++++++++- spec/relations/range_relation_spec.rb | 18 ++++++++++++++++-- 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/sql_algebra/relations/order_relation.rb b/lib/sql_algebra/relations/order_relation.rb index 8d07c58d64927..e3c29dcc27ae7 100644 --- a/lib/sql_algebra/relations/order_relation.rb +++ b/lib/sql_algebra/relations/order_relation.rb @@ -8,4 +8,12 @@ def initialize(relation, *attributes) def ==(other) relation == other.relation and attributes.eql?(other.attributes) end + + def to_sql(builder = SelectBuilder.new) + relation.to_sql(builder).call do + attributes.each do |attribute| + order_by attribute.to_sql(self) + end + end + end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/projection_relation.rb b/lib/sql_algebra/relations/projection_relation.rb index caebfc1b62c9e..ca5f0bfca4beb 100644 --- a/lib/sql_algebra/relations/projection_relation.rb +++ b/lib/sql_algebra/relations/projection_relation.rb @@ -8,4 +8,10 @@ def initialize(relation, *attributes) def ==(other) relation == other.relation and attributes.eql?(other.attributes) end + + def to_sql(builder = SelectBuilder.new) + relation.to_sql(builder).call do + select attributes.collect { |a| a.to_sql(self) } + end + end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/range_relation.rb b/lib/sql_algebra/relations/range_relation.rb index fd7e2898fad0d..9225d5615b0fa 100644 --- a/lib/sql_algebra/relations/range_relation.rb +++ b/lib/sql_algebra/relations/range_relation.rb @@ -8,4 +8,11 @@ def initialize(relation, range) def ==(other) relation == other.relation and range == other.range end + + def to_sql(builder = SelectBuilder.new) + relation.to_sql(builder).call do + limit range.last - range.first + 1 + offset range.first + end + end end \ No newline at end of file diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb index 362544d0d137c..4f7a18fc8e512 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/relations/order_relation_spec.rb @@ -8,11 +8,22 @@ @attribute2 = @relation2[:bar] end - describe OrderRelation, '==' do + describe '==' do it "obtains if the relation and attributes are identical" do OrderRelation.new(@relation1, @attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) OrderRelation.new(@relation1, @attribute1).should_not == OrderRelation.new(@relation2, @attribute1) OrderRelation.new(@relation1, @attribute1, @attribute2).should_not == OrderRelation.new(@relation1, @attribute2, @attribute1) end end + + describe '#to_s' do + it "manufactures sql with an order clause" do + OrderRelation.new(@relation1, @attribute1).to_sql.should == SelectBuilder.new do + select :* + from :foo + order_by 'foo.foo' + end + end + end + end \ No newline at end of file diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb index f802a2e293b92..ba5620dcdeb0b 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/relations/projection_relation_spec.rb @@ -8,11 +8,20 @@ @attribute2 = @relation2[:bar] end - describe ProjectionRelation, '==' do + describe '==' do it "obtains if the relations and attributes are identical" do ProjectionRelation.new(@relation1, @attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) ProjectionRelation.new(@relation1, @attribute1).should_not == ProjectionRelation.new(@relation2, @attribute1) ProjectionRelation.new(@relation1, @attribute1).should_not == ProjectionRelation.new(@relation1, @attribute2) end end + + describe '#to_sql' do + it "manufactures sql with a limited select clause" do + ProjectionRelation.new(@relation1, @attribute1).to_sql.should == SelectBuilder.new do + select 'foo.foo' + from :foo + end + end + end end \ No newline at end of file diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb index 2a1cd1d070a2a..fc7094c873098 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/relations/range_relation_spec.rb @@ -5,14 +5,28 @@ @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) @range1 = 1..2 - @range2 = Time.now..2.days.from_now + @range2 = 4..9 end - describe RangeRelation, '==' do + describe '==' do it "obtains if the relation and range are identical" do RangeRelation.new(@relation1, @range1).should == RangeRelation.new(@relation1, @range1) RangeRelation.new(@relation1, @range1).should_not == RangeRelation.new(@relation2, @range1) RangeRelation.new(@relation1, @range1).should_not == RangeRelation.new(@relation1, @range2) end end + + describe '#to_sql' do + it "manufactures sql with limit and offset" do + range_size = @range2.last - @range2.first + 1 + range_start = @range2.first + RangeRelation.new(@relation1, @range2).to_sql.to_s.should == SelectBuilder.new do + select :* + from :foo + limit range_size + offset range_start + end.to_s + end + end + end \ No newline at end of file From 6c89e3818d85e3169a7fb8de27b25357c2259881 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 1 Jan 2008 16:44:33 -0800 Subject: [PATCH 0009/1492] integration test --- lib/sql_algebra.rb | 5 +- .../predicates/binary_predicate.rb | 5 +- lib/sql_algebra/relations/attribute.rb | 12 +- .../relations/inner_join_operation.rb | 6 + .../relations/inner_join_relation.rb | 5 + .../relations/left_outer_join_operation.rb | 6 + .../relations/left_outer_join_relation.rb | 5 + lib/sql_algebra/relations/order_relation.rb | 4 +- .../relations/projection_relation.rb | 4 +- .../relations/selection_relation.rb | 2 + lib/sql_algebra/relations/table_relation.rb | 2 +- .../sql_builder/conditions_builder.rb | 16 ++ .../sql_builder/equals_condition_builder.rb | 18 ++ .../sql_builder/inner_join_builder.rb | 5 + lib/sql_algebra/sql_builder/join_builder.rb | 13 ++ lib/sql_algebra/sql_builder/joins_builder.rb | 18 ++ .../sql_builder/left_outer_join_builder.rb | 5 + lib/sql_algebra/sql_builder/select_builder.rb | 63 +++++++ lib/sql_algebra/sql_builder/sql_builder.rb | 28 +++ .../sql_builder/sql_builder_adapter.rb | 22 +++ spec/integration/scratch_spec.rb | 37 ++++ spec/predicates/binary_predicate_spec.rb | 7 +- spec/relations/attribute_spec.rb | 4 +- spec/relations/join_relation_spec.rb | 12 +- spec/relations/order_relation_spec.rb | 8 +- spec/relations/projection_relation_spec.rb | 4 +- spec/relations/range_relation_spec.rb | 2 +- spec/relations/selection_relation_spec.rb | 7 +- spec/relations/table_relation_spec.rb | 2 +- spec/spec_helpers/be_like.rb | 24 +++ spec/sql_builder/conditions_spec.rb | 18 ++ spec/sql_builder/select_builder_spec.rb | 170 ++++++++++++++++++ 32 files changed, 514 insertions(+), 25 deletions(-) create mode 100644 lib/sql_algebra/relations/inner_join_operation.rb create mode 100644 lib/sql_algebra/relations/inner_join_relation.rb create mode 100644 lib/sql_algebra/relations/left_outer_join_operation.rb create mode 100644 lib/sql_algebra/relations/left_outer_join_relation.rb create mode 100644 lib/sql_algebra/sql_builder/conditions_builder.rb create mode 100644 lib/sql_algebra/sql_builder/equals_condition_builder.rb create mode 100644 lib/sql_algebra/sql_builder/inner_join_builder.rb create mode 100644 lib/sql_algebra/sql_builder/join_builder.rb create mode 100644 lib/sql_algebra/sql_builder/joins_builder.rb create mode 100644 lib/sql_algebra/sql_builder/left_outer_join_builder.rb create mode 100644 lib/sql_algebra/sql_builder/select_builder.rb create mode 100644 lib/sql_algebra/sql_builder/sql_builder.rb create mode 100644 lib/sql_algebra/sql_builder/sql_builder_adapter.rb create mode 100644 spec/integration/scratch_spec.rb create mode 100644 spec/spec_helpers/be_like.rb create mode 100644 spec/sql_builder/conditions_spec.rb create mode 100644 spec/sql_builder/select_builder_spec.rb diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 8389250755495..5753a48d2f2e3 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -28,6 +28,7 @@ require 'sql_algebra/predicates/match_predicate' require 'sql_algebra/extensions/range' +require 'sql_algebra/extensions/object' require 'sql_algebra/sql_builder/sql_builder_adapter' require 'sql_algebra/sql_builder/sql_builder' @@ -37,6 +38,6 @@ require 'sql_algebra/sql_builder/inner_join_builder' require 'sql_algebra/sql_builder/left_outer_join_builder' require 'sql_algebra/sql_builder/equals_condition_builder' -require 'sql_algebra/sql_builder/column_builder' require 'sql_algebra/sql_builder/conditions_builder' - +require 'sql_algebra/sql_builder/order_builder' +require 'sql_algebra/sql_builder/selects_builder' \ No newline at end of file diff --git a/lib/sql_algebra/predicates/binary_predicate.rb b/lib/sql_algebra/predicates/binary_predicate.rb index 3e5b9ce1930fc..9463f162c55d4 100644 --- a/lib/sql_algebra/predicates/binary_predicate.rb +++ b/lib/sql_algebra/predicates/binary_predicate.rb @@ -12,7 +12,10 @@ def ==(other) def to_sql(builder = ConditionsBuilder.new) builder.call do - send(predicate_name, attribute1.to_sql(self), attribute2.to_sql(self)) + send(predicate_name) do + attribute1.to_sql(self) + attribute2.to_sql(self) + end end end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb index af448286f1365..85d40dfb124d4 100644 --- a/lib/sql_algebra/relations/attribute.rb +++ b/lib/sql_algebra/relations/attribute.rb @@ -1,8 +1,8 @@ class Attribute - attr_reader :relation, :attribute_name + attr_reader :relation, :attribute_name, :aliaz - def initialize(relation, attribute_name) - @relation, @attribute_name = relation, attribute_name + def initialize(relation, attribute_name, aliaz = nil) + @relation, @attribute_name, @aliaz = relation, attribute_name, aliaz end def eql?(other) @@ -33,7 +33,9 @@ def =~(regexp) MatchPredicate.new(self, regexp) end - def to_sql(ignore_builder_because_i_can_only_exist_atomically = nil) - ColumnBuilder.new(relation.table, attribute_name) + def to_sql(builder = SelectsBuilder.new) + builder.call do + column relation.table, attribute_name, aliaz + end end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/inner_join_operation.rb b/lib/sql_algebra/relations/inner_join_operation.rb new file mode 100644 index 0000000000000..6b5c5ce8d0bb3 --- /dev/null +++ b/lib/sql_algebra/relations/inner_join_operation.rb @@ -0,0 +1,6 @@ +class InnerJoinOperation < JoinOperation + protected + def relation_class + InnerJoinRelation + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/inner_join_relation.rb b/lib/sql_algebra/relations/inner_join_relation.rb new file mode 100644 index 0000000000000..1ef965a6f55ff --- /dev/null +++ b/lib/sql_algebra/relations/inner_join_relation.rb @@ -0,0 +1,5 @@ +class InnerJoinRelation < JoinRelation + def join_name + :inner_join + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/left_outer_join_operation.rb b/lib/sql_algebra/relations/left_outer_join_operation.rb new file mode 100644 index 0000000000000..fbb2a4e2ed482 --- /dev/null +++ b/lib/sql_algebra/relations/left_outer_join_operation.rb @@ -0,0 +1,6 @@ +class LeftOuterJoinOperation < JoinOperation + protected + def relation_class + LeftOuterJoinRelation + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/left_outer_join_relation.rb b/lib/sql_algebra/relations/left_outer_join_relation.rb new file mode 100644 index 0000000000000..c7722c394dee2 --- /dev/null +++ b/lib/sql_algebra/relations/left_outer_join_relation.rb @@ -0,0 +1,5 @@ +class LeftOuterJoinRelation < JoinRelation + def join_name + :left_outer_join + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/order_relation.rb b/lib/sql_algebra/relations/order_relation.rb index e3c29dcc27ae7..384a007bc23d0 100644 --- a/lib/sql_algebra/relations/order_relation.rb +++ b/lib/sql_algebra/relations/order_relation.rb @@ -12,7 +12,9 @@ def ==(other) def to_sql(builder = SelectBuilder.new) relation.to_sql(builder).call do attributes.each do |attribute| - order_by attribute.to_sql(self) + order_by do + attribute.to_sql(self) + end end end end diff --git a/lib/sql_algebra/relations/projection_relation.rb b/lib/sql_algebra/relations/projection_relation.rb index ca5f0bfca4beb..0b5d645d79a8a 100644 --- a/lib/sql_algebra/relations/projection_relation.rb +++ b/lib/sql_algebra/relations/projection_relation.rb @@ -11,7 +11,9 @@ def ==(other) def to_sql(builder = SelectBuilder.new) relation.to_sql(builder).call do - select attributes.collect { |a| a.to_sql(self) } + select do + attributes.collect { |a| a.to_sql(self) } + end end end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/sql_algebra/relations/selection_relation.rb index cce93917c4fc0..51461de7d242c 100644 --- a/lib/sql_algebra/relations/selection_relation.rb +++ b/lib/sql_algebra/relations/selection_relation.rb @@ -17,4 +17,6 @@ def to_sql(builder = SelectBuilder.new) end end end + + delegate :[], :to => :relation end \ No newline at end of file diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb index eee24e5d68cd1..60bdfda8ee84b 100644 --- a/lib/sql_algebra/relations/table_relation.rb +++ b/lib/sql_algebra/relations/table_relation.rb @@ -7,7 +7,7 @@ def initialize(table) def to_sql(builder = SelectBuilder.new) builder.call do - select :* + select { all } from table end end diff --git a/lib/sql_algebra/sql_builder/conditions_builder.rb b/lib/sql_algebra/sql_builder/conditions_builder.rb new file mode 100644 index 0000000000000..5d42a36cecc76 --- /dev/null +++ b/lib/sql_algebra/sql_builder/conditions_builder.rb @@ -0,0 +1,16 @@ +class ConditionsBuilder < SqlBuilder + def initialize(&block) + @conditions = [] + super(&block) + end + + def equals(&block) + @conditions << EqualsConditionBuilder.new(&block) + end + + def to_s + @conditions.join(' AND ') + end + + delegate :blank?, :to => :@conditions +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/equals_condition_builder.rb b/lib/sql_algebra/sql_builder/equals_condition_builder.rb new file mode 100644 index 0000000000000..016395556aed9 --- /dev/null +++ b/lib/sql_algebra/sql_builder/equals_condition_builder.rb @@ -0,0 +1,18 @@ +class EqualsConditionBuilder < SqlBuilder + def initialize(&block) + @operands = [] + super(&block) + end + + def column(table, column, aliaz = nil) + @operands << (aliaz ? aliaz : "#{table}.#{column}") + end + + def value(value) + @operands << value + end + + def to_s + "#{@operands[0]} = #{@operands[1]}" + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/inner_join_builder.rb b/lib/sql_algebra/sql_builder/inner_join_builder.rb new file mode 100644 index 0000000000000..6aec703325707 --- /dev/null +++ b/lib/sql_algebra/sql_builder/inner_join_builder.rb @@ -0,0 +1,5 @@ +class InnerJoinBuilder < JoinBuilder + def join_type + "INNER JOIN" + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/join_builder.rb b/lib/sql_algebra/sql_builder/join_builder.rb new file mode 100644 index 0000000000000..28f4437decd4b --- /dev/null +++ b/lib/sql_algebra/sql_builder/join_builder.rb @@ -0,0 +1,13 @@ +class JoinBuilder < SqlBuilder + def initialize(table, &block) + @table = table + @conditions = ConditionsBuilder.new + super(&block) + end + + delegate :call, :to => :@conditions + + def to_s + "#{join_type} #{@table} ON #{@conditions}" + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/joins_builder.rb b/lib/sql_algebra/sql_builder/joins_builder.rb new file mode 100644 index 0000000000000..36a92e9922cd5 --- /dev/null +++ b/lib/sql_algebra/sql_builder/joins_builder.rb @@ -0,0 +1,18 @@ +class JoinsBuilder < SqlBuilder + def initialize(&block) + @joins = [] + super(&block) + end + + def inner_join(table, &block) + @joins << InnerJoinBuilder.new(table, &block) + end + + def left_outer_join(table, &block) + @joins << LeftOuterJoinBuilder.new(table, &block) + end + + def to_s + @joins.join(' ') + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/left_outer_join_builder.rb b/lib/sql_algebra/sql_builder/left_outer_join_builder.rb new file mode 100644 index 0000000000000..dad3f85810cda --- /dev/null +++ b/lib/sql_algebra/sql_builder/left_outer_join_builder.rb @@ -0,0 +1,5 @@ +class LeftOuterJoinBuilder < JoinBuilder + def join_type + "LEFT OUTER JOIN" + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/select_builder.rb b/lib/sql_algebra/sql_builder/select_builder.rb new file mode 100644 index 0000000000000..d4eb4feb56659 --- /dev/null +++ b/lib/sql_algebra/sql_builder/select_builder.rb @@ -0,0 +1,63 @@ +class SelectBuilder < SqlBuilder + def select(&block) + @selects = SelectsBuilder.new(&block) + end + + def from(table, &block) + @table = table + @joins = JoinsBuilder.new(&block) + end + delegate :inner_join, :left_outer_join, :to => :@joins + + def where(&block) + @conditions ||= ConditionsBuilder.new + @conditions.call(&block) + end + + def order_by(&block) + @orders = OrderBuilder.new(&block) + end + + def limit(i, offset = nil) + @limit = i + offset(offset) if offset + end + + def offset(i) + @offset = i + end + + def to_s + [select_clause, + from_clause, + where_clause, + order_by_clause, + limit_clause, + offset_clause].compact.join("\n") + end + + private + def select_clause + "SELECT #{@selects}" unless @selects.blank? + end + + def from_clause + "FROM #{@table} #{@joins}" unless @table.blank? + end + + def where_clause + "WHERE #{@conditions}" unless @conditions.blank? + end + + def order_by_clause + "ORDER BY #{@orders}" unless @orders.blank? + end + + def limit_clause + "LIMIT #{@limit}" unless @limit.blank? + end + + def offset_clause + "OFFSET #{@offset}" unless @offset.blank? + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/sql_builder.rb b/lib/sql_algebra/sql_builder/sql_builder.rb new file mode 100644 index 0000000000000..5cfbe578d5e7d --- /dev/null +++ b/lib/sql_algebra/sql_builder/sql_builder.rb @@ -0,0 +1,28 @@ +class SqlBuilder + def initialize(&block) + @callers = [] + call(&block) if block + end + + def method_missing(method, *args) + @callers.last.send(method, *args) + end + + def ==(other) + to_s == other.to_s + end + + def to_s + end + + def call(&block) + returning self do |builder| + @callers << eval("self", block.binding) + begin + instance_eval &block + ensure + @callers.pop + end + end + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/sql_builder_adapter.rb b/lib/sql_algebra/sql_builder/sql_builder_adapter.rb new file mode 100644 index 0000000000000..9bb5271f3380c --- /dev/null +++ b/lib/sql_algebra/sql_builder/sql_builder_adapter.rb @@ -0,0 +1,22 @@ +class SqlBuilderAdapter + instance_methods.each { |m| undef_method m unless m =~ /^__|^instance_eval|class/ } + + def initialize(adaptee, &block) + @adaptee = adaptee + (class << self; self end).class_eval do + (adaptee.methods - instance_methods).each { |m| delegate m, :to => :@adaptee } + end + (class << self; self end).instance_exec(@adaptee, &block) + end + + def call(&block) + @caller = eval("self", block.binding) + returning self do |adapter| + instance_eval(&block) + end + end + + def method_missing(method, *args, &block) + @caller.send(method, *args, &block) + end +end \ No newline at end of file diff --git a/spec/integration/scratch_spec.rb b/spec/integration/scratch_spec.rb new file mode 100644 index 0000000000000..6426d2478de41 --- /dev/null +++ b/spec/integration/scratch_spec.rb @@ -0,0 +1,37 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe 'Relational Algebra' do + before do + User = TableRelation.new(:users) + Photo = TableRelation.new(:photos) + Camera = TableRelation.new(:cameras) + user = User.select(User[:id] == 1) + @user_photos = (user << Photo).on(user[:id] == Photo[:user_id]) + end + + it 'simulates User.has_many :photos' do + @user_photos.to_sql.should == SelectBuilder.new do + select { all } + from :users do + left_outer_join :photos do + equals { column :users, :id; column :photos, :user_id } + end + end + where do + equals { column :users, :id; value 1 } + end + end + @user_photos.to_sql.to_s.should be_like(""" + SELECT * + FROM users + LEFT OUTER JOIN photos + ON users.id = photos.user_id + WHERE + users.id = 1 + """) + end + + it 'simulating a User.has_many :cameras :through => :photos' do + user_cameras = (@user_photos << Camera).on(@user_photos[:camera_id] == Camera[:id]) + end +end \ No newline at end of file diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb index 3d9a9b3b94b6b..a044e43a84a9e 100644 --- a/spec/predicates/binary_predicate_spec.rb +++ b/spec/predicates/binary_predicate_spec.rb @@ -32,9 +32,12 @@ def predicate_name end describe '#to_sql' do - it '' do + it 'manufactures correct sql' do ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do - equals 'foo.attribute_name1', 'bar.attribute_name2' + equals do + column :foo, :attribute_name1 + column :bar, :attribute_name2 + end end end end diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb index 78d602abf90f7..5ddbaa96b528a 100644 --- a/spec/relations/attribute_spec.rb +++ b/spec/relations/attribute_spec.rb @@ -59,7 +59,9 @@ describe '#to_sql' do it "manufactures a column" do - Attribute.new(@relation1, :attribute_name).to_sql.should == ColumnBuilder.new(@relation1.table, :attribute_name) + Attribute.new(@relation1, :attribute_name, :alias).to_sql.should == SelectsBuilder.new do + column :foo, :attribute_name, :alias + end end end end diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb index c6fae90ff3d33..a7c15fd76a38d 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/relations/join_relation_spec.rb @@ -30,14 +30,20 @@ def join_name it 'manufactures sql joining the two tables on the predicate, merging the selects' do ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_sql.to_s.should == SelectBuilder.new do - select :* + select { all } from :foo do inner_join :bar do - equals 'foo.a', 'bar.b' + equals do + column :foo, :a + column :bar, :b + end end end where do - equals 'foo.c', 'bar.d' + equals do + column :foo, :c + column :bar, :d + end end end.to_s end diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb index 4f7a18fc8e512..8050aa981ca94 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/relations/order_relation_spec.rb @@ -16,12 +16,14 @@ end end - describe '#to_s' do + describe '#to_sql' do it "manufactures sql with an order clause" do OrderRelation.new(@relation1, @attribute1).to_sql.should == SelectBuilder.new do - select :* + select { all } from :foo - order_by 'foo.foo' + order_by do + column :foo, :foo + end end end end diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb index ba5620dcdeb0b..f17f57df7bee7 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/relations/projection_relation_spec.rb @@ -19,7 +19,9 @@ describe '#to_sql' do it "manufactures sql with a limited select clause" do ProjectionRelation.new(@relation1, @attribute1).to_sql.should == SelectBuilder.new do - select 'foo.foo' + select do + column :foo, :foo + end from :foo end end diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb index fc7094c873098..e6caa32e80c58 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/relations/range_relation_spec.rb @@ -21,7 +21,7 @@ range_size = @range2.last - @range2.first + 1 range_start = @range2.first RangeRelation.new(@relation1, @range2).to_sql.to_s.should == SelectBuilder.new do - select :* + select { all } from :foo limit range_size offset range_start diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb index 1f8b760272770..ceb771b46dedf 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/relations/selection_relation_spec.rb @@ -29,10 +29,13 @@ describe '#to_sql' do it "manufactures sql with where clause conditions" do SelectionRelation.new(@relation1, @predicate1).to_sql.should == SelectBuilder.new do - select :* + select { all } from :foo where do - equals 'foo.id', 'bar.foo_id' + equals do + column :foo, :id + column :bar, :foo_id + end end end end diff --git a/spec/relations/table_relation_spec.rb b/spec/relations/table_relation_spec.rb index a0647aa541c65..7a820782dfd29 100644 --- a/spec/relations/table_relation_spec.rb +++ b/spec/relations/table_relation_spec.rb @@ -3,7 +3,7 @@ describe TableRelation, '#to_sql' do it "returns a simple SELECT query" do TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s| - select :* + select { all } from :users end end diff --git a/spec/spec_helpers/be_like.rb b/spec/spec_helpers/be_like.rb new file mode 100644 index 0000000000000..cea3f3027b9f6 --- /dev/null +++ b/spec/spec_helpers/be_like.rb @@ -0,0 +1,24 @@ +module BeLikeMatcher + class BeLike + def initialize(expected) + @expected = expected + end + + def matches?(target) + @target = target + @expected.gsub(/\s+/, ' ').strip == @target.gsub(/\s+/, ' ').strip + end + + def failure_message + "expected #{@target} to be like #{@expected}" + end + + def negative_failure_message + "expected #{@target} to be unlike #{@expected}" + end + end + + def be_like(expected) + BeLike.new(expected) + end +end \ No newline at end of file diff --git a/spec/sql_builder/conditions_spec.rb b/spec/sql_builder/conditions_spec.rb new file mode 100644 index 0000000000000..78590e2631d73 --- /dev/null +++ b/spec/sql_builder/conditions_spec.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe ConditionsBuilder do + describe '#to_s' do + describe 'with aliased columns' do + it 'manufactures correct sql' do + ConditionsBuilder.new do + equals do + column(:a, :b) + column(:c, :d, :e) + end + end.to_s.should be_like(""" + a.b = e + """) + end + end + end +end \ No newline at end of file diff --git a/spec/sql_builder/select_builder_spec.rb b/spec/sql_builder/select_builder_spec.rb new file mode 100644 index 0000000000000..39597b0392d2e --- /dev/null +++ b/spec/sql_builder/select_builder_spec.rb @@ -0,0 +1,170 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe SelectBuilder do + describe '#to_s' do + describe 'with select and from clauses' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users + end.to_s.should be_like(""" + SELECT * + FROM users + """) + end + end + + describe 'with specified columns and column aliases' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + column(:a, :b, :c) + column(:e, :f) + end + from :users + end.to_s.should be_like(""" + SELECT a.b AS c, e.f + FROM users + """) + end + end + + describe 'with where clause' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users + where do + equals do + value :a + column :b, :c + end + end + end.to_s.should be_like(""" + SELECT * + FROM users + WHERE a = b.c + """) + end + end + + describe 'with inner join' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users do + inner_join(:friendships) do + equals do + value :id + value :user_id + end + end + end + end.to_s.should be_like(""" + SELECT * + FROM users INNER JOIN friendships ON id = user_id + """) + end + end + + describe 'with order' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users + order_by do + column :users, :id + column :users, :created_at, :alias + end + end.to_s.should be_like(""" + SELECT * + FROM users + ORDER BY users.id, alias + """) + end + end + + describe 'with limit and/or offset' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users + limit 10 + offset 10 + end.to_s.should be_like(""" + SELECT * + FROM users + LIMIT 10 + OFFSET 10 + """) + end + end + + describe 'repeated clauses' do + describe 'with repeating joins' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users do + inner_join(:friendships) do + equals do + value :id + value :user_id + end + end + end + inner_join(:pictures) do + equals do + value :id + value :user_id + end + end + end.to_s.should be_like(""" + SELECT * + FROM users INNER JOIN friendships ON id = user_id INNER JOIN pictures ON id = user_id + """) + end + end + + describe 'with repeating wheres' do + it 'manufactures correct sql' do + SelectBuilder.new do + select do + all + end + from :users + where do + equals do + value :a + value :b + end + end + where do + equals do + value :b + value :c + end + end + end.to_s.should be_like(""" + SELECT * + FROM users + WHERE a = b + AND b = c + """) + end + end + end + end +end \ No newline at end of file From a5d62729799ed58ce344dba0621e951dbc92ab3f Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 3 Jan 2008 23:41:43 -0800 Subject: [PATCH 0010/1492] new usage of builder ` --- eager include.txt | 49 + lib/sql_algebra.rb | 6 +- lib/sql_algebra/extensions/base.rb | 15 + lib/sql_algebra/extensions/object.rb | 8 + .../relations/inner_join_relation.rb | 2 +- lib/sql_algebra/relations/join_relation.rb | 32 +- .../relations/left_outer_join_relation.rb | 2 +- lib/sql_algebra/relations/relation.rb | 75 +- .../relations/selection_relation.rb | 12 +- lib/sql_algebra/relations/table_relation.rb | 17 +- lib/sql_algebra/sql_builder/order_builder.rb | 16 + .../sql_builder/selects_builder.rb | 20 + .../sql_builder/sql_builder_adapter.rb | 22 - spec/debug.log | 1 + spec/integration/debug.log | 1581 +++++++++++++++++ spec/integration/scratch_spec.rb | 39 +- spec/relations/attribute_spec.rb | 1 + spec/relations/join_relation_spec.rb | 22 +- spec/relations/order_relation_spec.rb | 15 +- spec/relations/projection_relation_spec.rb | 10 +- spec/relations/range_relation_spec.rb | 5 +- spec/relations/relation_spec.rb | 8 - spec/relations/selection_relation_spec.rb | 9 +- spec/relations/table_relation_spec.rb | 5 +- spec/spec_helper.rb | 11 + 25 files changed, 1853 insertions(+), 130 deletions(-) create mode 100644 eager include.txt create mode 100644 lib/sql_algebra/extensions/base.rb create mode 100644 lib/sql_algebra/extensions/object.rb create mode 100644 lib/sql_algebra/sql_builder/order_builder.rb create mode 100644 lib/sql_algebra/sql_builder/selects_builder.rb delete mode 100644 lib/sql_algebra/sql_builder/sql_builder_adapter.rb create mode 100644 spec/debug.log create mode 100644 spec/integration/debug.log diff --git a/eager include.txt b/eager include.txt new file mode 100644 index 0000000000000..0c56323b40f5b --- /dev/null +++ b/eager include.txt @@ -0,0 +1,49 @@ +User.find( :all, :include => { :photos => :camera } ) + +User.reflection[:photos].klass.reflection[:camera] + +users_photos_camera = User.relation << User.reflections[:photos].relation << Photo.reflections[:camera].relation + +users_photos_camera.each do |record| + User.bring_forth(record, :photos => :camera) +end + +def User.bring_forth(record, included = { :photos => :camera }) + user = @cache[ record % 'users.id' ] || User.instantiate(record % User.attributes) + user.photos.bring_forth(record, :camera) +end + +def User.photos.bring_forth(record, included = :camera) + photo = @cache[ record % 'photos.id' ] || Photo.instantiate(record % Photo.attributes) + photo.camera.bring_forth(record) +end + +def User.photos.camera.bring_forth(record, included = nil) + camera = @cache [ record % 'cameras.id' ] || Camera.instantiate(record % Camera.attributes) +end + +########################### + +# first, rename the attributes to remove ambiguity (analogous to c0_t0 stuff) +eager_loaded_user_cameras = @user_cameras.rename( + @user.attributes => @user.attributes.prefixed, + @photos.attributes => ..., + @cameras.attributes => ..., +) + +# second, bring forth!! +class Repository + def bring_forth(record, includes = []) + object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) } + includes.each do |include| + case include + when Symbol + object.send(association = include).bring_forth(record) + when Hash + include.each do |association, nested_associations| + object.send(association).bring_forth(record, nested_associations) + end + end + end + end +end \ No newline at end of file diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 5753a48d2f2e3..b3e3c8d17660a 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -1,8 +1,10 @@ $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'rubygems' -require 'active_support' +require 'activesupport' +require 'activerecord' require 'sql_algebra/relations/relation' +require 'sql_algebra/relations/compound_relation' require 'sql_algebra/relations/table_relation' require 'sql_algebra/relations/join_operation' require 'sql_algebra/relations/inner_join_operation' @@ -15,6 +17,7 @@ require 'sql_algebra/relations/selection_relation' require 'sql_algebra/relations/order_relation' require 'sql_algebra/relations/range_relation' +require 'sql_algebra/relations/join' require 'sql_algebra/predicates/predicate' require 'sql_algebra/predicates/binary_predicate' @@ -30,7 +33,6 @@ require 'sql_algebra/extensions/range' require 'sql_algebra/extensions/object' -require 'sql_algebra/sql_builder/sql_builder_adapter' require 'sql_algebra/sql_builder/sql_builder' require 'sql_algebra/sql_builder/select_builder' require 'sql_algebra/sql_builder/joins_builder' diff --git a/lib/sql_algebra/extensions/base.rb b/lib/sql_algebra/extensions/base.rb new file mode 100644 index 0000000000000..79f2ce75d1dea --- /dev/null +++ b/lib/sql_algebra/extensions/base.rb @@ -0,0 +1,15 @@ +class ActiveRecord::Base + def self.bring_forth(record, includes = []) + object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) } + includes.each do |include| + case include + when Symbol + object.send(association = include).bring_forth(record) + when Hash + include.each do |association, nested_associations| + object.send(association).bring_forth(record, nested_associations) + end + end + end + end +end \ No newline at end of file diff --git a/lib/sql_algebra/extensions/object.rb b/lib/sql_algebra/extensions/object.rb new file mode 100644 index 0000000000000..639e810a97ccf --- /dev/null +++ b/lib/sql_algebra/extensions/object.rb @@ -0,0 +1,8 @@ +class Object + def to_sql(builder = EqualsConditionBuilder.new) + me = self + builder.call do + value me + end + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/inner_join_relation.rb b/lib/sql_algebra/relations/inner_join_relation.rb index 1ef965a6f55ff..6b932e3b21a76 100644 --- a/lib/sql_algebra/relations/inner_join_relation.rb +++ b/lib/sql_algebra/relations/inner_join_relation.rb @@ -1,5 +1,5 @@ class InnerJoinRelation < JoinRelation - def join_name + def join_type :inner_join end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb index b96cd175de785..dc57e24c96c53 100644 --- a/lib/sql_algebra/relations/join_relation.rb +++ b/lib/sql_algebra/relations/join_relation.rb @@ -11,24 +11,22 @@ def ==(other) (relation2 == other.relation1 and relation1 == other.relation2)) end - def to_sql(builder = SelectBuilder.new) - relation2.to_sql(translate_from_to_inner_join_on_predicates(relation1.to_sql(builder))) + def joins + relation1.joins + relation2.joins + [Join.new(relation1, relation2, predicates, join_type)] end - private - # translate 'from' to 'inner join on ' - def translate_from_to_inner_join_on_predicates(builder) - schmoin_name, schmredicates = join_name, predicates - SqlBuilderAdapter.new(builder) do |builder| - define_method :from do |table| - builder.call do - send(schmoin_name, table) do - schmredicates.each do |predicate| - predicate.to_sql(self) - end - end - end - end - end + def selects + relation1.selects + relation2.selects end + + def attributes + relation1.attributes + relation2.attributes + end + + def attribute(name) + relation1[name] || relation2[name] + end + + protected + delegate :table, :to => :relation1 end \ No newline at end of file diff --git a/lib/sql_algebra/relations/left_outer_join_relation.rb b/lib/sql_algebra/relations/left_outer_join_relation.rb index c7722c394dee2..f4ece438617a2 100644 --- a/lib/sql_algebra/relations/left_outer_join_relation.rb +++ b/lib/sql_algebra/relations/left_outer_join_relation.rb @@ -1,5 +1,5 @@ class LeftOuterJoinRelation < JoinRelation - def join_name + def join_type :left_outer_join end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb index bd812b368d2e1..8c21927d01c76 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/sql_algebra/relations/relation.rb @@ -1,34 +1,65 @@ class Relation - def <=>(other) - InnerJoinOperation.new(self, other) - end + module Operations + def <=>(other) + InnerJoinOperation.new(self, other) + end - def <<(other) - LeftOuterJoinOperation.new(self, other) - end + def <<(other) + LeftOuterJoinOperation.new(self, other) + end - def [](index) - case index - when Symbol - Attribute.new(self, index) - when Range - RangeRelation.new(self, index) + def [](index) + case index + when Symbol + attribute(index) + when Range + RangeRelation.new(self, index) + end end - end - def include?(attribute) - RelationInclusionPredicate.new(attribute, self) - end + def include?(attribute) + RelationInclusionPredicate.new(attribute, self) + end - def select(*predicates) - SelectionRelation.new(self, *predicates) + def select(*predicates) + SelectionRelation.new(self, *predicates) + end + + def project(*attributes) + ProjectionRelation.new(self, *attributes) + end + + def order(*attributes) + OrderRelation.new(self, *attributes) + end end + include Operations - def project(*attributes) - ProjectionRelation.new(self, *attributes) + def connection + ActiveRecord::Base.connection end - def order(*attributes) - OrderRelation.new(self, *attributes) + def to_sql(builder = SelectBuilder.new) + builder.call do + select do + attributes.each { |a| a.to_sql(self) } + end + from table do + joins.each { |j| j.to_sql(self) } + end + where do + selects.each { |s| s.to_sql(self) } + end + order_by do + orders.each { |o| o.to_sql(self) } + end + end end + + protected + def attributes; [] end + def joins; [] end + def selects; [] end + def orders; [] end + end \ No newline at end of file diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/sql_algebra/relations/selection_relation.rb index 51461de7d242c..72911aa65af5b 100644 --- a/lib/sql_algebra/relations/selection_relation.rb +++ b/lib/sql_algebra/relations/selection_relation.rb @@ -1,4 +1,4 @@ -class SelectionRelation < Relation +class SelectionRelation < CompoundRelation attr_reader :relation, :predicate def initialize(relation, *predicates) @@ -10,13 +10,7 @@ def ==(other) relation == other.relation and predicate == other.predicate end - def to_sql(builder = SelectBuilder.new) - relation.to_sql(builder).call do - where do - predicate.to_sql(self) - end - end + def selects + [predicate] end - - delegate :[], :to => :relation end \ No newline at end of file diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb index 60bdfda8ee84b..1915b42565271 100644 --- a/lib/sql_algebra/relations/table_relation.rb +++ b/lib/sql_algebra/relations/table_relation.rb @@ -5,10 +5,19 @@ def initialize(table) @table = table end - def to_sql(builder = SelectBuilder.new) - builder.call do - select { all } - from table + def attributes + attributes_by_name.values + end + + protected + def attribute(name) + attributes_by_name[name.to_s] + end + + private + def attributes_by_name + @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| + attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym)) end end end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/order_builder.rb b/lib/sql_algebra/sql_builder/order_builder.rb new file mode 100644 index 0000000000000..4eea40fa3668d --- /dev/null +++ b/lib/sql_algebra/sql_builder/order_builder.rb @@ -0,0 +1,16 @@ +class OrderBuilder < SqlBuilder + def initialize(&block) + @orders = [] + super(&block) + end + + def column(table, column, aliaz = nil) + @orders << (aliaz ? aliaz : "#{table}.#{column}") + end + + def to_s + @orders.join(', ') + end + + delegate :blank?, :to => :@orders +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/selects_builder.rb b/lib/sql_algebra/sql_builder/selects_builder.rb new file mode 100644 index 0000000000000..72f6f52397058 --- /dev/null +++ b/lib/sql_algebra/sql_builder/selects_builder.rb @@ -0,0 +1,20 @@ +class SelectsBuilder < SqlBuilder + def initialize(&block) + @selects = [] + super(&block) + end + + def to_s + @selects.join(', ') + end + + def all + @selects << :* + end + + def column(table, column, aliaz = nil) + @selects << "#{table}.#{column}" + (aliaz ? " AS #{aliaz}" : '') + end + + delegate :blank?, :to => :@selects +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/sql_builder_adapter.rb b/lib/sql_algebra/sql_builder/sql_builder_adapter.rb deleted file mode 100644 index 9bb5271f3380c..0000000000000 --- a/lib/sql_algebra/sql_builder/sql_builder_adapter.rb +++ /dev/null @@ -1,22 +0,0 @@ -class SqlBuilderAdapter - instance_methods.each { |m| undef_method m unless m =~ /^__|^instance_eval|class/ } - - def initialize(adaptee, &block) - @adaptee = adaptee - (class << self; self end).class_eval do - (adaptee.methods - instance_methods).each { |m| delegate m, :to => :@adaptee } - end - (class << self; self end).instance_exec(@adaptee, &block) - end - - def call(&block) - @caller = eval("self", block.binding) - returning self do |adapter| - instance_eval(&block) - end - end - - def method_missing(method, *args, &block) - @caller.send(method, *args, &block) - end -end \ No newline at end of file diff --git a/spec/debug.log b/spec/debug.log new file mode 100644 index 0000000000000..d38ed11d82f66 --- /dev/null +++ b/spec/debug.log @@ -0,0 +1 @@ +# Logfile created on Tue Jan 01 17:49:28 -0800 2008 by logger.rb/1.5.2.9 diff --git a/spec/integration/debug.log b/spec/integration/debug.log new file mode 100644 index 0000000000000..9b5b08cc20be7 --- /dev/null +++ b/spec/integration/debug.log @@ -0,0 +1,1581 @@ +# Logfile created on Tue Jan 01 18:37:24 -0800 2008 by logger.rb/1.5.2.9 + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010719) SHOW FIELDS FROM `users` + SQL (0.002219) SHOW FIELDS FROM `photos` + SQL (0.001538) SHOW FIELDS FROM `users` + SQL (0.002551) SHOW FIELDS FROM `photos` + SQL (0.001835) SHOW FIELDS FROM `cameras` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010748) SHOW FIELDS FROM `users` + SQL (0.002223) SHOW FIELDS FROM `photos` + SQL (0.002938) SHOW FIELDS FROM `users` + SQL (0.002466) SHOW FIELDS FROM `photos` + SQL (0.001493) SHOW FIELDS FROM `cameras` + SQL (0.000116) SET SQL_AUTO_IS_NULL=0 + SQL (0.010722) SHOW FIELDS FROM `users` + SQL (0.002196) SHOW FIELDS FROM `photos` + SQL (0.001528) SHOW FIELDS FROM `users` + SQL (0.001373) SHOW FIELDS FROM `photos` + SQL (0.001372) SHOW FIELDS FROM `cameras` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.001599) SHOW FIELDS FROM `users` + SQL (0.012868) SHOW FIELDS FROM `photos` + SQL (0.001681) SHOW FIELDS FROM `users` + SQL (0.002253) SHOW FIELDS FROM `photos` + SQL (0.002186) SHOW FIELDS FROM `cameras` + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010737) SHOW FIELDS FROM `users` + SQL (0.002277) SHOW FIELDS FROM `photos` + SQL (0.001517) SHOW FIELDS FROM `users` + SQL (0.001368) SHOW FIELDS FROM `photos` + SQL (0.001481) SHOW FIELDS FROM `cameras` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010719) SHOW FIELDS FROM `users` + SQL (0.002651) SHOW FIELDS FROM `photos` + SQL (0.001464) SHOW FIELDS FROM `users` + SQL (0.001504) SHOW FIELDS FROM `photos` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010820) SHOW FIELDS FROM `users` + SQL (0.002194) SHOW FIELDS FROM `photos` + SQL (0.001565) SHOW FIELDS FROM `users` + SQL (0.001282) SHOW FIELDS FROM `photos` + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010719) SHOW FIELDS FROM `users` + SQL (0.002103) SHOW FIELDS FROM `photos` + SQL (0.001468) SHOW FIELDS FROM `users` + SQL (0.001526) SHOW FIELDS FROM `photos` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010648) SHOW FIELDS FROM `users` + SQL (0.002458) SHOW FIELDS FROM `photos` + SQL (0.001525) SHOW FIELDS FROM `users` + SQL (0.001571) SHOW FIELDS FROM `photos` + SQL (0.001274) SHOW FIELDS FROM `users` + SQL (0.001527) SHOW FIELDS FROM `photos` + SQL (0.000130) SET SQL_AUTO_IS_NULL=0 + SQL (0.010705) SHOW FIELDS FROM `users` + SQL (0.002444) SHOW FIELDS FROM `photos` + SQL (0.001608) SHOW FIELDS FROM `users` + SQL (0.001488) SHOW FIELDS FROM `photos` + SQL (0.001462) SHOW FIELDS FROM `users` + SQL (0.001492) SHOW FIELDS FROM `photos` + SQL (0.015956) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.001676) SHOW TABLES + User Columns (0.001593) SHOW FIELDS FROM `users` + SQL (0.000144) SET SQL_AUTO_IS_NULL=0 + SQL (0.010771) SHOW FIELDS FROM `users` + SQL (0.002480) SHOW FIELDS FROM `photos` + SQL (0.001474) SHOW FIELDS FROM `users` + SQL (0.001357) SHOW FIELDS FROM `photos` + SQL (0.011769) SHOW FIELDS FROM `users` + SQL (0.001586) SHOW FIELDS FROM `photos` + SQL (0.000232) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000120) SET SQL_AUTO_IS_NULL=0 + SQL (0.010804) SHOW FIELDS FROM `users` + SQL (0.002188) SHOW FIELDS FROM `photos` + SQL (0.001478) SHOW FIELDS FROM `users` + SQL (0.001550) SHOW FIELDS FROM `photos` + SQL (0.001413) SHOW FIELDS FROM `users` + SQL (0.001515) SHOW FIELDS FROM `photos` + SQL (0.000251) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010826) SHOW FIELDS FROM `users` + SQL (0.002353) SHOW FIELDS FROM `photos` + SQL (0.001500) SHOW FIELDS FROM `users` + SQL (0.001522) SHOW FIELDS FROM `photos` + SQL (0.001438) SHOW FIELDS FROM `users` + SQL (0.001436) SHOW FIELDS FROM `photos` + SQL (0.000266) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001396) SHOW FIELDS FROM `users` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010772) SHOW FIELDS FROM `users` + SQL (0.002268) SHOW FIELDS FROM `photos` + SQL (0.001566) SHOW FIELDS FROM `users` + SQL (0.001390) SHOW FIELDS FROM `photos` + SQL (0.001466) SHOW FIELDS FROM `users` + SQL (0.001600) SHOW FIELDS FROM `photos` + SQL (0.000247) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010742) SHOW FIELDS FROM `users` + SQL (0.002382) SHOW FIELDS FROM `photos` + SQL (0.001490) SHOW FIELDS FROM `users` + SQL (0.001505) SHOW FIELDS FROM `photos` + SQL (0.001846) SHOW FIELDS FROM `users` + SQL (0.001491) SHOW FIELDS FROM `photos` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010798) SHOW FIELDS FROM `users` + SQL (0.002447) SHOW FIELDS FROM `photos` + SQL (0.001557) SHOW FIELDS FROM `users` + SQL (0.001387) SHOW FIELDS FROM `photos` + SQL (0.001469) SHOW FIELDS FROM `users` + SQL (0.001394) SHOW FIELDS FROM `photos` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010727) SHOW FIELDS FROM `users` + SQL (0.002213) SHOW FIELDS FROM `photos` + SQL (0.001491) SHOW FIELDS FROM `users` + SQL (0.001407) SHOW FIELDS FROM `photos` + SQL (0.001457) SHOW FIELDS FROM `users` + SQL (0.001529) SHOW FIELDS FROM `photos` + SQL (0.000247) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000320) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000135) SET SQL_AUTO_IS_NULL=0 + SQL (0.010663) SHOW FIELDS FROM `users` + SQL (0.002319) SHOW FIELDS FROM `photos` + SQL (0.001467) SHOW FIELDS FROM `users` + SQL (0.001319) SHOW FIELDS FROM `photos` + SQL (0.010583) SHOW FIELDS FROM `users` + SQL (0.001805) SHOW FIELDS FROM `photos` + SQL (0.000290) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000271) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010733) SHOW FIELDS FROM `users` + SQL (0.002277) SHOW FIELDS FROM `photos` + SQL (0.001500) SHOW FIELDS FROM `users` + SQL (0.001387) SHOW FIELDS FROM `photos` + SQL (0.001421) SHOW FIELDS FROM `users` + SQL (0.001726) SHOW FIELDS FROM `photos` + SQL (0.000261) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000261) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001432) SHOW FIELDS FROM `photos` + SQL (0.000134) SET SQL_AUTO_IS_NULL=0 + SQL (0.010759) SHOW FIELDS FROM `users` + SQL (0.002287) SHOW FIELDS FROM `photos` + SQL (0.001424) SHOW FIELDS FROM `users` + SQL (0.001550) SHOW FIELDS FROM `photos` + SQL (0.001342) SHOW FIELDS FROM `cameras` + SQL (0.001545) SHOW FIELDS FROM `users` + SQL (0.001488) SHOW FIELDS FROM `photos` + SQL (0.000249) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000290) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000139) SET SQL_AUTO_IS_NULL=0 + SQL (0.010766) SHOW FIELDS FROM `users` + SQL (0.002183) SHOW FIELDS FROM `photos` + SQL (0.001465) SHOW FIELDS FROM `users` + SQL (0.001492) SHOW FIELDS FROM `photos` + SQL (0.012690) SHOW FIELDS FROM `cameras` + SQL (0.001591) SHOW FIELDS FROM `users` + SQL (0.001740) SHOW FIELDS FROM `photos` + SQL (0.000261) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000262) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000110) SET SQL_AUTO_IS_NULL=0 + SQL (0.010751) SHOW FIELDS FROM `users` + SQL (0.002343) SHOW FIELDS FROM `photos` + SQL (0.001476) SHOW FIELDS FROM `users` + SQL (0.001513) SHOW FIELDS FROM `photos` + SQL (0.001495) SHOW FIELDS FROM `cameras` + SQL (0.001569) SHOW FIELDS FROM `users` + SQL (0.001497) SHOW FIELDS FROM `photos` + SQL (0.000249) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.028671) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010774) SHOW FIELDS FROM `users` + SQL (0.002229) SHOW FIELDS FROM `photos` + SQL (0.001532) SHOW FIELDS FROM `users` + SQL (0.001526) SHOW FIELDS FROM `photos` + SQL (0.001463) SHOW FIELDS FROM `cameras` + SQL (0.001558) SHOW FIELDS FROM `users` + SQL (0.001479) SHOW FIELDS FROM `photos` + SQL (0.000253) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000248) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000141) SET SQL_AUTO_IS_NULL=0 + SQL (0.010731) SHOW FIELDS FROM `users` + SQL (0.002167) SHOW FIELDS FROM `photos` + SQL (0.001370) SHOW FIELDS FROM `users` + SQL (0.001523) SHOW FIELDS FROM `photos` + SQL (0.001275) SHOW FIELDS FROM `cameras` + SQL (0.001480) SHOW FIELDS FROM `users` + SQL (0.001193) SHOW FIELDS FROM `photos` + SQL (0.000228) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000228) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.011242) SHOW FIELDS FROM `users` + SQL (0.001695) SHOW FIELDS FROM `photos` + SQL (0.001744) SHOW FIELDS FROM `users` + SQL (0.001452) SHOW FIELDS FROM `photos` + SQL (0.001419) SHOW FIELDS FROM `cameras` + SQL (0.001378) SHOW FIELDS FROM `users` + SQL (0.002561) SHOW FIELDS FROM `photos` + SQL (0.000923) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000275) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000157) SET SQL_AUTO_IS_NULL=0 + SQL (0.010515) SHOW FIELDS FROM `users` + SQL (0.002311) SHOW FIELDS FROM `photos` + SQL (0.002045) SHOW FIELDS FROM `users` + SQL (0.001878) SHOW FIELDS FROM `photos` + SQL (0.001586) SHOW FIELDS FROM `cameras` + SQL (0.001397) SHOW FIELDS FROM `users` + SQL (0.001944) SHOW FIELDS FROM `photos` + SQL (0.000453) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000283) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010759) SHOW FIELDS FROM `users` + SQL (0.002066) SHOW FIELDS FROM `photos` + SQL (0.001582) SHOW FIELDS FROM `users` + SQL (0.001459) SHOW FIELDS FROM `photos` + SQL (0.001418) SHOW FIELDS FROM `cameras` + SQL (0.001367) SHOW FIELDS FROM `users` + SQL (0.001849) SHOW FIELDS FROM `photos` + SQL (0.001231) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000357) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010706) SHOW FIELDS FROM `users` + SQL (0.002375) SHOW FIELDS FROM `photos` + SQL (0.001616) SHOW FIELDS FROM `users` + SQL (0.001826) SHOW FIELDS FROM `photos` + SQL (0.001508) SHOW FIELDS FROM `cameras` + SQL (0.001638) SHOW FIELDS FROM `users` + SQL (0.001719) SHOW FIELDS FROM `photos` + SQL (0.001674) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000337) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000114) SET SQL_AUTO_IS_NULL=0 + SQL (0.010717) SHOW FIELDS FROM `users` + SQL (0.002698) SHOW FIELDS FROM `photos` + SQL (0.001432) SHOW FIELDS FROM `users` + SQL (0.001686) SHOW FIELDS FROM `photos` + SQL (0.001403) SHOW FIELDS FROM `cameras` + SQL (0.001809) SHOW FIELDS FROM `users` + SQL (0.001590) SHOW FIELDS FROM `photos` + SQL (0.000540) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000341) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010746) SHOW FIELDS FROM `users` + SQL (0.002455) SHOW FIELDS FROM `photos` + SQL (0.001483) SHOW FIELDS FROM `users` + SQL (0.001588) SHOW FIELDS FROM `photos` + SQL (0.001513) SHOW FIELDS FROM `cameras` + SQL (0.001247) SHOW FIELDS FROM `users` + SQL (0.001527) SHOW FIELDS FROM `photos` + SQL (0.000227) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000252) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000142) SET SQL_AUTO_IS_NULL=0 + SQL (0.010735) SHOW FIELDS FROM `users` + SQL (0.002400) SHOW FIELDS FROM `photos` + SQL (0.001299) SHOW FIELDS FROM `users` + SQL (0.001451) SHOW FIELDS FROM `photos` + SQL (0.001173) SHOW FIELDS FROM `cameras` + SQL (0.001530) SHOW FIELDS FROM `users` + SQL (0.001793) SHOW FIELDS FROM `photos` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010758) SHOW FIELDS FROM `users` + SQL (0.002271) SHOW FIELDS FROM `photos` + SQL (0.001485) SHOW FIELDS FROM `users` + SQL (0.001578) SHOW FIELDS FROM `photos` + SQL (0.001492) SHOW FIELDS FROM `cameras` + SQL (0.001389) SHOW FIELDS FROM `users` + SQL (0.001391) SHOW FIELDS FROM `photos` + SQL (0.000249) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000170) SET SQL_AUTO_IS_NULL=0 + SQL (0.010733) SHOW FIELDS FROM `users` + SQL (0.002313) SHOW FIELDS FROM `photos` + SQL (0.001469) SHOW FIELDS FROM `users` + SQL (0.001593) SHOW FIELDS FROM `photos` + SQL (0.001511) SHOW FIELDS FROM `cameras` + SQL (0.001484) SHOW FIELDS FROM `users` + SQL (0.001478) SHOW FIELDS FROM `photos` + SQL (0.000232) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010796) SHOW FIELDS FROM `users` + SQL (0.001970) SHOW FIELDS FROM `photos` + SQL (0.001558) SHOW FIELDS FROM `users` + SQL (0.001440) SHOW FIELDS FROM `photos` + SQL (0.001354) SHOW FIELDS FROM `cameras` + SQL (0.001544) SHOW FIELDS FROM `users` + SQL (0.001405) SHOW FIELDS FROM `photos` + SQL (0.000239) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000111) SET SQL_AUTO_IS_NULL=0 + SQL (0.010751) SHOW FIELDS FROM `users` + SQL (0.002354) SHOW FIELDS FROM `photos` + SQL (0.001463) SHOW FIELDS FROM `users` + SQL (0.001588) SHOW FIELDS FROM `photos` + SQL (0.001505) SHOW FIELDS FROM `cameras` + SQL (0.001464) SHOW FIELDS FROM `users` + SQL (0.001509) SHOW FIELDS FROM `photos` + SQL (0.000235) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000133) SET SQL_AUTO_IS_NULL=0 + SQL (0.010651) SHOW FIELDS FROM `users` + SQL (0.002468) SHOW FIELDS FROM `photos` + SQL (0.001364) SHOW FIELDS FROM `users` + SQL (0.001503) SHOW FIELDS FROM `photos` + SQL (0.001543) SHOW FIELDS FROM `cameras` + SQL (0.001452) SHOW FIELDS FROM `users` + SQL (0.001445) SHOW FIELDS FROM `photos` + SQL (0.000228) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.330787) SHOW FIELDS FROM `users` + SQL (0.002584) SHOW FIELDS FROM `photos` + SQL (0.001456) SHOW FIELDS FROM `users` + SQL (0.001621) SHOW FIELDS FROM `photos` + SQL (0.001475) SHOW FIELDS FROM `cameras` + SQL (0.001481) SHOW FIELDS FROM `users` + SQL (0.001552) SHOW FIELDS FROM `photos` + SQL (0.000226) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000144) SET SQL_AUTO_IS_NULL=0 + SQL (0.010706) SHOW FIELDS FROM `users` + SQL (0.002394) SHOW FIELDS FROM `photos` + SQL (0.001322) SHOW FIELDS FROM `users` + SQL (0.001656) SHOW FIELDS FROM `photos` + SQL (0.001495) SHOW FIELDS FROM `cameras` + SQL (0.001498) SHOW FIELDS FROM `users` + SQL (0.001510) SHOW FIELDS FROM `photos` + SQL (0.000222) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010785) SHOW FIELDS FROM `users` + SQL (0.002249) SHOW FIELDS FROM `photos` + SQL (0.001469) SHOW FIELDS FROM `users` + SQL (0.001410) SHOW FIELDS FROM `photos` + SQL (0.001666) SHOW FIELDS FROM `cameras` + SQL (0.001627) SHOW FIELDS FROM `users` + SQL (0.002215) SHOW FIELDS FROM `photos` + SQL (0.000942) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000149) SET SQL_AUTO_IS_NULL=0 + SQL (0.010774) SHOW FIELDS FROM `users` + SQL (0.001649) SHOW FIELDS FROM `photos` + SQL (0.001497) SHOW FIELDS FROM `users` + SQL (0.001457) SHOW FIELDS FROM `photos` + SQL (0.001345) SHOW FIELDS FROM `cameras` + SQL (0.001298) SHOW FIELDS FROM `users` + SQL (0.001849) SHOW FIELDS FROM `photos` + SQL (0.000967) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000143) SET SQL_AUTO_IS_NULL=0 + SQL (0.010724) SHOW FIELDS FROM `users` + SQL (0.002360) SHOW FIELDS FROM `photos` + SQL (0.001570) SHOW FIELDS FROM `users` + SQL (0.001733) SHOW FIELDS FROM `photos` + SQL (0.001487) SHOW FIELDS FROM `cameras` + SQL (0.001624) SHOW FIELDS FROM `users` + SQL (0.001840) SHOW FIELDS FROM `photos` + SQL (0.001080) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010885) SHOW FIELDS FROM `users` + SQL (0.002106) SHOW FIELDS FROM `photos` + SQL (0.001603) SHOW FIELDS FROM `users` + SQL (0.001575) SHOW FIELDS FROM `photos` + SQL (0.001529) SHOW FIELDS FROM `cameras` + SQL (0.001517) SHOW FIELDS FROM `users` + SQL (0.001556) SHOW FIELDS FROM `photos` + SQL (0.000260) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010689) SHOW FIELDS FROM `users` + SQL (0.002034) SHOW FIELDS FROM `photos` + SQL (0.001430) SHOW FIELDS FROM `users` + SQL (0.001590) SHOW FIELDS FROM `photos` + SQL (0.001434) SHOW FIELDS FROM `cameras` + SQL (0.001543) SHOW FIELDS FROM `users` + SQL (0.001597) SHOW FIELDS FROM `photos` + SQL (0.001103) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000143) SET SQL_AUTO_IS_NULL=0 + SQL (0.010735) SHOW FIELDS FROM `users` + SQL (0.002171) SHOW FIELDS FROM `photos` + SQL (0.001553) SHOW FIELDS FROM `users` + SQL (0.001586) SHOW FIELDS FROM `photos` + SQL (0.001520) SHOW FIELDS FROM `cameras` + SQL (0.001441) SHOW FIELDS FROM `users` + SQL (0.001560) SHOW FIELDS FROM `photos` + SQL (0.001796) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010772) SHOW FIELDS FROM `users` + SQL (0.002291) SHOW FIELDS FROM `photos` + SQL (0.001505) SHOW FIELDS FROM `users` + SQL (0.001466) SHOW FIELDS FROM `photos` + SQL (0.002032) SHOW FIELDS FROM `cameras` + SQL (0.001543) SHOW FIELDS FROM `users` + SQL (0.001434) SHOW FIELDS FROM `photos` + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010845) SHOW FIELDS FROM `users` + SQL (0.002185) SHOW FIELDS FROM `photos` + SQL (0.001479) SHOW FIELDS FROM `users` + SQL (0.001551) SHOW FIELDS FROM `photos` + SQL (0.001459) SHOW FIELDS FROM `cameras` + SQL (0.001521) SHOW FIELDS FROM `users` + SQL (0.001392) SHOW FIELDS FROM `photos` + SQL (0.000222) SELECT photos.user_id, photos.camera_id, photos.id +FROM photos  + SQL (0.000246) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000136) SET SQL_AUTO_IS_NULL=0 + SQL (0.010662) SHOW FIELDS FROM `users` + SQL (0.002267) SHOW FIELDS FROM `photos` + SQL (0.001467) SHOW FIELDS FROM `users` + SQL (0.001437) SHOW FIELDS FROM `photos` + SQL (0.001355) SHOW FIELDS FROM `cameras` + SQL (0.001506) SHOW FIELDS FROM `users` + SQL (0.012944) SHOW FIELDS FROM `photos` + SQL (0.000256) SELECT * +FROM photos  + SQL (0.000271) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010682) SHOW FIELDS FROM `users` + SQL (0.002485) SHOW FIELDS FROM `photos` + SQL (0.001454) SHOW FIELDS FROM `users` + SQL (0.001588) SHOW FIELDS FROM `photos` + SQL (0.001480) SHOW FIELDS FROM `cameras` + SQL (0.001539) SHOW FIELDS FROM `users` + SQL (0.001735) SHOW FIELDS FROM `photos` + SQL (0.000111) SET SQL_AUTO_IS_NULL=0 + SQL (0.010744) SHOW FIELDS FROM `users` + SQL (0.002250) SHOW FIELDS FROM `photos` + SQL (0.001491) SHOW FIELDS FROM `users` + SQL (0.001534) SHOW FIELDS FROM `photos` + SQL (0.001499) SHOW FIELDS FROM `cameras` + SQL (0.001482) SHOW FIELDS FROM `users` + SQL (0.001496) SHOW FIELDS FROM `photos` + SQL (0.000165) SET SQL_AUTO_IS_NULL=0 + SQL (0.010840) SHOW FIELDS FROM `users` + SQL (0.002301) SHOW FIELDS FROM `photos` + SQL (0.001598) SHOW FIELDS FROM `users` + SQL (0.001456) SHOW FIELDS FROM `photos` + SQL (0.001241) SHOW FIELDS FROM `cameras` + SQL (0.001479) SHOW FIELDS FROM `users` + SQL (0.000887) SHOW FIELDS FROM `photos` + SQL (0.000137) SET SQL_AUTO_IS_NULL=0 + SQL (0.010721) SHOW FIELDS FROM `users` + SQL (0.002243) SHOW FIELDS FROM `photos` + SQL (0.001485) SHOW FIELDS FROM `users` + SQL (0.001592) SHOW FIELDS FROM `photos` + SQL (0.001519) SHOW FIELDS FROM `cameras` + SQL (0.001480) SHOW FIELDS FROM `users` + SQL (0.001534) SHOW FIELDS FROM `photos` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010748) SHOW FIELDS FROM `users` + SQL (0.002303) SHOW FIELDS FROM `photos` + SQL (0.001459) SHOW FIELDS FROM `users` + SQL (0.001580) SHOW FIELDS FROM `photos` + SQL (0.001584) SHOW FIELDS FROM `cameras` + SQL (0.001507) SHOW FIELDS FROM `users` + SQL (0.001526) SHOW FIELDS FROM `photos` + SQL (0.000139) SET SQL_AUTO_IS_NULL=0 + SQL (0.001564) SHOW FIELDS FROM `users` + SQL (0.001517) SHOW FIELDS FROM `photos` + SQL (0.001405) SHOW FIELDS FROM `users` + SQL (0.001516) SHOW FIELDS FROM `photos` + SQL (0.001704) SHOW FIELDS FROM `cameras` + SQL (0.001583) SHOW FIELDS FROM `users` + SQL (0.001579) SHOW FIELDS FROM `photos` + SQL (0.000135) SET SQL_AUTO_IS_NULL=0 + SQL (0.010720) SHOW FIELDS FROM `users` + SQL (0.002156) SHOW FIELDS FROM `photos` + SQL (0.001639) SHOW FIELDS FROM `users` + SQL (0.001434) SHOW FIELDS FROM `photos` + SQL (0.001357) SHOW FIELDS FROM `cameras` + SQL (0.001513) SHOW FIELDS FROM `users` + SQL (0.001474) SHOW FIELDS FROM `photos` + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010719) SHOW FIELDS FROM `users` + SQL (0.002256) SHOW FIELDS FROM `photos` + SQL (0.001531) SHOW FIELDS FROM `users` + SQL (0.001453) SHOW FIELDS FROM `photos` + SQL (0.001388) SHOW FIELDS FROM `cameras` + SQL (0.001494) SHOW FIELDS FROM `users` + SQL (0.001101) SHOW FIELDS FROM `photos` + SQL (0.000219) SELECT users.id +FROM users +WHERE users.id = 1 + SQL (0.000157) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.011477) SHOW FIELDS FROM `users` + SQL (0.002257) SHOW FIELDS FROM `photos` + SQL (0.001520) SHOW FIELDS FROM `users` + SQL (0.001410) SHOW FIELDS FROM `photos` + SQL (0.001383) SHOW FIELDS FROM `cameras` + SQL (0.001505) SHOW FIELDS FROM `users` + SQL (0.001462) SHOW FIELDS FROM `photos` + SQL (0.000222) SELECT users.id +FROM users +WHERE users.id = 1 + SQL (0.000197) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010701) SHOW FIELDS FROM `users` + SQL (0.002382) SHOW FIELDS FROM `photos` + SQL (0.001523) SHOW FIELDS FROM `users` + SQL (0.001558) SHOW FIELDS FROM `photos` + SQL (0.001494) SHOW FIELDS FROM `cameras` + SQL (0.001467) SHOW FIELDS FROM `users` + SQL (0.001516) SHOW FIELDS FROM `photos` + SQL (0.000129) SET SQL_AUTO_IS_NULL=0 + SQL (0.010711) SHOW FIELDS FROM `users` + SQL (0.002382) SHOW FIELDS FROM `photos` + SQL (0.001495) SHOW FIELDS FROM `users` + SQL (0.001445) SHOW FIELDS FROM `photos` + SQL (0.001363) SHOW FIELDS FROM `cameras` + SQL (0.001557) SHOW FIELDS FROM `users` + SQL (0.001433) SHOW FIELDS FROM `photos` + SQL (0.000000) Mysql::Error: Unknown column 'photos.id' in 'field list': SELECT photos.id +FROM users +WHERE users.id = 1 + SQL (0.000132) SET SQL_AUTO_IS_NULL=0 + SQL (0.010902) SHOW FIELDS FROM `users` + SQL (0.002079) SHOW FIELDS FROM `photos` + SQL (0.001455) SHOW FIELDS FROM `users` + SQL (0.001626) SHOW FIELDS FROM `photos` + SQL (0.012539) SHOW FIELDS FROM `cameras` + SQL (0.001557) SHOW FIELDS FROM `users` + SQL (0.001437) SHOW FIELDS FROM `photos` + SQL (0.000255) SELECT users.id +FROM users +WHERE users.id = 1 + SQL (0.000225) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010766) SHOW FIELDS FROM `users` + SQL (0.002370) SHOW FIELDS FROM `photos` + SQL (0.001453) SHOW FIELDS FROM `users` + SQL (0.001556) SHOW FIELDS FROM `photos` + SQL (0.001492) SHOW FIELDS FROM `cameras` + SQL (0.001243) SHOW FIELDS FROM `users` + SQL (0.001527) SHOW FIELDS FROM `photos` + SQL (0.000151) SET SQL_AUTO_IS_NULL=0 + SQL (0.010730) SHOW FIELDS FROM `users` + SQL (0.002308) SHOW FIELDS FROM `photos` + SQL (0.001489) SHOW FIELDS FROM `users` + SQL (0.001571) SHOW FIELDS FROM `photos` + SQL (0.001345) SHOW FIELDS FROM `cameras` + SQL (0.001456) SHOW FIELDS FROM `users` + SQL (0.001161) SHOW FIELDS FROM `photos` + SQL (0.000215) SELECT users.id +FROM users +WHERE users.id = 1 + SQL (0.000261) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000139) SET SQL_AUTO_IS_NULL=0 + SQL (0.010683) SHOW FIELDS FROM `users` + SQL (0.002298) SHOW FIELDS FROM `photos` + SQL (0.001478) SHOW FIELDS FROM `users` + SQL (0.001413) SHOW FIELDS FROM `photos` + SQL (0.001521) SHOW FIELDS FROM `cameras` + SQL (0.001462) SHOW FIELDS FROM `users` + SQL (0.001509) SHOW FIELDS FROM `photos` + SQL (0.001637) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000136) SET SQL_AUTO_IS_NULL=0 + SQL (0.010714) SHOW FIELDS FROM `users` + SQL (0.002255) SHOW FIELDS FROM `photos` + SQL (0.001471) SHOW FIELDS FROM `users` + SQL (0.001491) SHOW FIELDS FROM `photos` + SQL (0.001494) SHOW FIELDS FROM `cameras` + SQL (0.001537) SHOW FIELDS FROM `users` + SQL (0.001500) SHOW FIELDS FROM `photos` + SQL (0.000144) SET SQL_AUTO_IS_NULL=0 + SQL (0.010658) SHOW FIELDS FROM `users` + SQL (0.002047) SHOW FIELDS FROM `photos` + SQL (0.001307) SHOW FIELDS FROM `users` + SQL (0.001529) SHOW FIELDS FROM `photos` + SQL (0.001380) SHOW FIELDS FROM `cameras` + SQL (0.001558) SHOW FIELDS FROM `users` + SQL (0.000851) SHOW FIELDS FROM `photos` + SQL (0.000135) SET SQL_AUTO_IS_NULL=0 + SQL (0.010643) SHOW FIELDS FROM `users` + SQL (0.002531) SHOW FIELDS FROM `photos` + SQL (0.001449) SHOW FIELDS FROM `users` + SQL (0.001423) SHOW FIELDS FROM `photos` + SQL (0.001522) SHOW FIELDS FROM `cameras` + SQL (0.001515) SHOW FIELDS FROM `users` + SQL (0.001581) SHOW FIELDS FROM `photos` + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010786) SHOW FIELDS FROM `users` + SQL (0.002348) SHOW FIELDS FROM `photos` + SQL (0.001476) SHOW FIELDS FROM `users` + SQL (0.001604) SHOW FIELDS FROM `photos` + SQL (0.001380) SHOW FIELDS FROM `cameras` + SQL (0.001484) SHOW FIELDS FROM `users` + SQL (0.001383) SHOW FIELDS FROM `photos` + SQL (0.000117) SET SQL_AUTO_IS_NULL=0 + SQL (0.010702) SHOW FIELDS FROM `users` + SQL (0.002339) SHOW FIELDS FROM `photos` + SQL (0.001304) SHOW FIELDS FROM `users` + SQL (0.001578) SHOW FIELDS FROM `photos` + SQL (0.001470) SHOW FIELDS FROM `cameras` + SQL (0.001524) SHOW FIELDS FROM `users` + SQL (0.001554) SHOW FIELDS FROM `photos` + SQL (0.000144) SET SQL_AUTO_IS_NULL=0 + SQL (0.010746) SHOW FIELDS FROM `users` + SQL (0.002433) SHOW FIELDS FROM `photos` + SQL (0.001489) SHOW FIELDS FROM `users` + SQL (0.001530) SHOW FIELDS FROM `photos` + SQL (0.001540) SHOW FIELDS FROM `cameras` + SQL (0.001528) SHOW FIELDS FROM `users` + SQL (0.001524) SHOW FIELDS FROM `photos` + SQL (0.000393) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000149) SET SQL_AUTO_IS_NULL=0 + SQL (0.010676) SHOW FIELDS FROM `users` + SQL (0.002224) SHOW FIELDS FROM `photos` + SQL (0.001456) SHOW FIELDS FROM `users` + SQL (0.001773) SHOW FIELDS FROM `photos` + SQL (0.001509) SHOW FIELDS FROM `cameras` + SQL (0.001473) SHOW FIELDS FROM `users` + SQL (0.001511) SHOW FIELDS FROM `photos` + SQL (0.000274) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010825) SHOW FIELDS FROM `users` + SQL (0.002358) SHOW FIELDS FROM `photos` + SQL (0.001492) SHOW FIELDS FROM `users` + SQL (0.001578) SHOW FIELDS FROM `photos` + SQL (0.001702) SHOW FIELDS FROM `cameras` + SQL (0.001495) SHOW FIELDS FROM `users` + SQL (0.001778) SHOW FIELDS FROM `photos` + SQL (0.000348) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000113) SET SQL_AUTO_IS_NULL=0 + SQL (0.010701) SHOW FIELDS FROM `users` + SQL (0.002380) SHOW FIELDS FROM `photos` + SQL (0.001329) SHOW FIELDS FROM `users` + SQL (0.001403) SHOW FIELDS FROM `photos` + SQL (0.001409) SHOW FIELDS FROM `cameras` + SQL (0.001458) SHOW FIELDS FROM `users` + SQL (0.001486) SHOW FIELDS FROM `photos` + SQL (0.000562) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000134) SET SQL_AUTO_IS_NULL=0 + SQL (0.010761) SHOW FIELDS FROM `users` + SQL (0.002300) SHOW FIELDS FROM `photos` + SQL (0.001565) SHOW FIELDS FROM `users` + SQL (0.001514) SHOW FIELDS FROM `photos` + SQL (0.001377) SHOW FIELDS FROM `cameras` + SQL (0.001553) SHOW FIELDS FROM `users` + SQL (0.001454) SHOW FIELDS FROM `photos` + SQL (0.000319) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000156) SET SQL_AUTO_IS_NULL=0 + SQL (0.010664) SHOW FIELDS FROM `users` + SQL (0.002495) SHOW FIELDS FROM `photos` + SQL (0.001454) SHOW FIELDS FROM `users` + SQL (0.001569) SHOW FIELDS FROM `photos` + SQL (0.001277) SHOW FIELDS FROM `cameras` + SQL (0.001250) SHOW FIELDS FROM `users` + SQL (0.001543) SHOW FIELDS FROM `photos` + SQL (0.000263) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000143) SET SQL_AUTO_IS_NULL=0 + SQL (0.010756) SHOW FIELDS FROM `users` + SQL (0.002397) SHOW FIELDS FROM `photos` + SQL (0.001731) SHOW FIELDS FROM `users` + SQL (0.001443) SHOW FIELDS FROM `photos` + SQL (0.001366) SHOW FIELDS FROM `cameras` + SQL (0.001472) SHOW FIELDS FROM `users` + SQL (0.001420) SHOW FIELDS FROM `photos` + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010705) SHOW FIELDS FROM `users` + SQL (0.002368) SHOW FIELDS FROM `photos` + SQL (0.001556) SHOW FIELDS FROM `users` + SQL (0.001472) SHOW FIELDS FROM `photos` + SQL (0.001455) SHOW FIELDS FROM `cameras` + SQL (0.001475) SHOW FIELDS FROM `users` + SQL (0.002127) SHOW FIELDS FROM `photos` + SQL (0.001414) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010742) SHOW FIELDS FROM `users` + SQL (0.002380) SHOW FIELDS FROM `photos` + SQL (0.001634) SHOW FIELDS FROM `users` + SQL (0.001587) SHOW FIELDS FROM `photos` + SQL (0.001452) SHOW FIELDS FROM `cameras` + SQL (0.001454) SHOW FIELDS FROM `users` + SQL (0.001514) SHOW FIELDS FROM `photos` + SQL (0.000135) SET SQL_AUTO_IS_NULL=0 + SQL (0.010668) SHOW FIELDS FROM `users` + SQL (0.002191) SHOW FIELDS FROM `photos` + SQL (0.001521) SHOW FIELDS FROM `users` + SQL (0.001418) SHOW FIELDS FROM `photos` + SQL (0.001330) SHOW FIELDS FROM `cameras` + SQL (0.001474) SHOW FIELDS FROM `users` + SQL (0.001406) SHOW FIELDS FROM `photos` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010693) SHOW FIELDS FROM `users` + SQL (0.002296) SHOW FIELDS FROM `photos` + SQL (0.001485) SHOW FIELDS FROM `users` + SQL (0.001604) SHOW FIELDS FROM `photos` + SQL (0.001479) SHOW FIELDS FROM `cameras` + SQL (0.001660) SHOW FIELDS FROM `users` + SQL (0.001632) SHOW FIELDS FROM `photos` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010678) SHOW FIELDS FROM `users` + SQL (0.002302) SHOW FIELDS FROM `photos` + SQL (0.001501) SHOW FIELDS FROM `users` + SQL (0.001360) SHOW FIELDS FROM `photos` + SQL (0.001353) SHOW FIELDS FROM `cameras` + SQL (0.001562) SHOW FIELDS FROM `users` + SQL (0.001542) SHOW FIELDS FROM `photos` + SQL (0.000147) SET SQL_AUTO_IS_NULL=0 + SQL (0.010704) SHOW FIELDS FROM `users` + SQL (0.002335) SHOW FIELDS FROM `photos` + SQL (0.001425) SHOW FIELDS FROM `users` + SQL (0.001468) SHOW FIELDS FROM `photos` + SQL (0.001469) SHOW FIELDS FROM `cameras` + SQL (0.001573) SHOW FIELDS FROM `users` + SQL (0.001489) SHOW FIELDS FROM `photos` + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010787) SHOW FIELDS FROM `users` + SQL (0.002303) SHOW FIELDS FROM `photos` + SQL (0.001529) SHOW FIELDS FROM `users` + SQL (0.001689) SHOW FIELDS FROM `photos` + SQL (0.001503) SHOW FIELDS FROM `cameras` + SQL (0.001463) SHOW FIELDS FROM `users` + SQL (0.001487) SHOW FIELDS FROM `photos` + SQL (0.000149) SET SQL_AUTO_IS_NULL=0 + SQL (0.010737) SHOW FIELDS FROM `users` + SQL (0.002412) SHOW FIELDS FROM `photos` + SQL (0.001487) SHOW FIELDS FROM `users` + SQL (0.001547) SHOW FIELDS FROM `photos` + SQL (0.001571) SHOW FIELDS FROM `cameras` + SQL (0.001482) SHOW FIELDS FROM `users` + SQL (0.001395) SHOW FIELDS FROM `photos` + SQL (0.000481) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010918) SHOW FIELDS FROM `users` + SQL (0.001957) SHOW FIELDS FROM `photos` + SQL (0.001485) SHOW FIELDS FROM `users` + SQL (0.001498) SHOW FIELDS FROM `photos` + SQL (0.001374) SHOW FIELDS FROM `cameras` + SQL (0.001461) SHOW FIELDS FROM `users` + SQL (0.001923) SHOW FIELDS FROM `photos` + SQL (0.000233) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000232) SELECT photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.011208) SHOW FIELDS FROM `users` + SQL (0.002172) SHOW FIELDS FROM `photos` + SQL (0.001453) SHOW FIELDS FROM `users` + SQL (0.001526) SHOW FIELDS FROM `photos` + SQL (0.001666) SHOW FIELDS FROM `cameras` + SQL (0.001273) SHOW FIELDS FROM `users` + SQL (0.001845) SHOW FIELDS FROM `photos` + SQL (0.000270) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000133) SET SQL_AUTO_IS_NULL=0 + SQL (0.010785) SHOW FIELDS FROM `users` + SQL (0.002207) SHOW FIELDS FROM `photos` + SQL (0.001480) SHOW FIELDS FROM `users` + SQL (0.001563) SHOW FIELDS FROM `photos` + SQL (0.001459) SHOW FIELDS FROM `cameras` + SQL (0.001206) SHOW FIELDS FROM `users` + SQL (0.001250) SHOW FIELDS FROM `photos` + SQL (0.000224) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000227) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000192) SET SQL_AUTO_IS_NULL=0 + SQL (0.010546) SHOW FIELDS FROM `users` + SQL (0.002397) SHOW FIELDS FROM `photos` + SQL (0.002065) SHOW FIELDS FROM `users` + SQL (0.001381) SHOW FIELDS FROM `photos` + SQL (0.000979) SHOW FIELDS FROM `cameras` + SQL (0.001410) SHOW FIELDS FROM `users` + SQL (0.001516) SHOW FIELDS FROM `photos` + SQL (0.000216) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000240) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010781) SHOW FIELDS FROM `users` + SQL (0.002045) SHOW FIELDS FROM `photos` + SQL (0.001462) SHOW FIELDS FROM `users` + SQL (0.001712) SHOW FIELDS FROM `photos` + SQL (0.001383) SHOW FIELDS FROM `cameras` + SQL (0.001934) SHOW FIELDS FROM `users` + SQL (0.001974) SHOW FIELDS FROM `photos` + SQL (0.000277) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000266) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010789) SHOW FIELDS FROM `users` + SQL (0.002174) SHOW FIELDS FROM `photos` + SQL (0.001549) SHOW FIELDS FROM `users` + SQL (0.001406) SHOW FIELDS FROM `photos` + SQL (0.001380) SHOW FIELDS FROM `cameras` + SQL (0.001590) SHOW FIELDS FROM `users` + SQL (0.001465) SHOW FIELDS FROM `photos` + SQL (0.000236) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000260) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000148) SET SQL_AUTO_IS_NULL=0 + SQL (0.010729) SHOW FIELDS FROM `users` + SQL (0.002288) SHOW FIELDS FROM `photos` + SQL (0.001373) SHOW FIELDS FROM `users` + SQL (0.001594) SHOW FIELDS FROM `photos` + SQL (0.001516) SHOW FIELDS FROM `cameras` + SQL (0.001470) SHOW FIELDS FROM `users` + SQL (0.001653) SHOW FIELDS FROM `photos` + SQL (0.000249) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000324) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010695) SHOW FIELDS FROM `users` + SQL (0.002188) SHOW FIELDS FROM `photos` + SQL (0.001450) SHOW FIELDS FROM `users` + SQL (0.001569) SHOW FIELDS FROM `photos` + SQL (0.001437) SHOW FIELDS FROM `cameras` + SQL (0.001780) SHOW FIELDS FROM `users` + SQL (0.002270) SHOW FIELDS FROM `photos` + SQL (0.001585) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000325) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000151) SET SQL_AUTO_IS_NULL=0 + SQL (0.010721) SHOW FIELDS FROM `users` + SQL (0.002947) SHOW FIELDS FROM `photos` + SQL (0.001515) SHOW FIELDS FROM `users` + SQL (0.001270) SHOW FIELDS FROM `photos` + SQL (0.001479) SHOW FIELDS FROM `cameras` + SQL (0.001428) SHOW FIELDS FROM `users` + SQL (0.001953) SHOW FIELDS FROM `photos` + SQL (0.000253) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000279) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010670) SHOW FIELDS FROM `users` + SQL (0.002111) SHOW FIELDS FROM `photos` + SQL (0.001460) SHOW FIELDS FROM `users` + SQL (0.001578) SHOW FIELDS FROM `photos` + SQL (0.001576) SHOW FIELDS FROM `cameras` + SQL (0.001497) SHOW FIELDS FROM `users` + SQL (0.001326) SHOW FIELDS FROM `photos` + SQL (0.000235) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000250) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.001613) SHOW FIELDS FROM `users` + SQL (0.001535) SHOW FIELDS FROM `photos` + SQL (0.001418) SHOW FIELDS FROM `users` + SQL (0.001545) SHOW FIELDS FROM `photos` + SQL (0.001536) SHOW FIELDS FROM `cameras` + SQL (0.001527) SHOW FIELDS FROM `users` + SQL (0.001497) SHOW FIELDS FROM `photos` + SQL (0.000230) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000227) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000134) SET SQL_AUTO_IS_NULL=0 + SQL (0.011304) SHOW FIELDS FROM `users` + SQL (0.002381) SHOW FIELDS FROM `photos` + SQL (0.001508) SHOW FIELDS FROM `users` + SQL (0.001665) SHOW FIELDS FROM `photos` + SQL (0.001498) SHOW FIELDS FROM `cameras` + SQL (0.001503) SHOW FIELDS FROM `users` + SQL (0.001514) SHOW FIELDS FROM `photos` + SQL (0.000225) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000231) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000134) SET SQL_AUTO_IS_NULL=0 + SQL (0.010747) SHOW FIELDS FROM `users` + SQL (0.002111) SHOW FIELDS FROM `photos` + SQL (0.001510) SHOW FIELDS FROM `users` + SQL (0.001581) SHOW FIELDS FROM `photos` + SQL (0.001428) SHOW FIELDS FROM `cameras` + SQL (0.001507) SHOW FIELDS FROM `users` + SQL (0.001808) SHOW FIELDS FROM `photos` + SQL (0.000247) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000237) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010702) SHOW FIELDS FROM `users` + SQL (0.002320) SHOW FIELDS FROM `photos` + SQL (0.001504) SHOW FIELDS FROM `users` + SQL (0.001589) SHOW FIELDS FROM `photos` + SQL (0.001555) SHOW FIELDS FROM `cameras` + SQL (0.002636) SHOW FIELDS FROM `users` + SQL (0.001766) SHOW FIELDS FROM `photos` + SQL (0.000239) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000281) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000115) SET SQL_AUTO_IS_NULL=0 + SQL (0.011377) SHOW FIELDS FROM `users` + SQL (0.002266) SHOW FIELDS FROM `photos` + SQL (0.001512) SHOW FIELDS FROM `users` + SQL (0.001553) SHOW FIELDS FROM `photos` + SQL (0.001686) SHOW FIELDS FROM `cameras` + SQL (0.001487) SHOW FIELDS FROM `users` + SQL (0.001520) SHOW FIELDS FROM `photos` + SQL (0.000223) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000233) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000133) SET SQL_AUTO_IS_NULL=0 + SQL (0.011494) SHOW FIELDS FROM `users` + SQL (0.002092) SHOW FIELDS FROM `photos` + SQL (0.001556) SHOW FIELDS FROM `cameras` + SQL (0.001490) SHOW FIELDS FROM `users` + SQL (0.001594) SHOW FIELDS FROM `photos` + SQL (0.001273) SHOW FIELDS FROM `cameras` + SQL (0.001512) SHOW FIELDS FROM `users` + SQL (0.001362) SHOW FIELDS FROM `photos` + SQL (0.001476) SHOW FIELDS FROM `cameras` + SQL (0.000227) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000335) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.001514) SHOW FIELDS FROM `users` + SQL (0.001589) SHOW FIELDS FROM `photos` + SQL (0.001412) SHOW FIELDS FROM `cameras` + SQL (0.000110) SET SQL_AUTO_IS_NULL=0 + SQL (0.010696) SHOW FIELDS FROM `users` + SQL (0.002449) SHOW FIELDS FROM `photos` + SQL (0.001558) SHOW FIELDS FROM `cameras` + SQL (0.001720) SHOW FIELDS FROM `users` + SQL (0.001577) SHOW FIELDS FROM `photos` + SQL (0.001420) SHOW FIELDS FROM `cameras` + SQL (0.009109) SHOW FIELDS FROM `users` + SQL (0.001770) SHOW FIELDS FROM `photos` + SQL (0.001409) SHOW FIELDS FROM `cameras` + SQL (0.000247) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000305) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001429) SHOW FIELDS FROM `users` + SQL (0.001503) SHOW FIELDS FROM `users` + SQL (0.001595) SHOW FIELDS FROM `photos` + SQL (0.001775) SHOW FIELDS FROM `cameras` + SQL (0.000137) SET SQL_AUTO_IS_NULL=0 + SQL (0.010741) SHOW FIELDS FROM `users` + SQL (0.002217) SHOW FIELDS FROM `photos` + SQL (0.001614) SHOW FIELDS FROM `cameras` + SQL (0.001277) SHOW FIELDS FROM `users` + SQL (0.001394) SHOW FIELDS FROM `photos` + SQL (0.001412) SHOW FIELDS FROM `cameras` + SQL (0.001534) SHOW FIELDS FROM `users` + SQL (0.001595) SHOW FIELDS FROM `photos` + SQL (0.001771) SHOW FIELDS FROM `cameras` + SQL (0.000246) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000287) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.001537) SHOW FIELDS FROM `users` + SQL (0.001578) SHOW FIELDS FROM `photos` + SQL (0.001351) SHOW FIELDS FROM `cameras` + SQL (0.000124) SET SQL_AUTO_IS_NULL=0 + SQL (0.010755) SHOW FIELDS FROM `users` + SQL (0.002276) SHOW FIELDS FROM `photos` + SQL (0.001312) SHOW FIELDS FROM `cameras` + SQL (0.002071) SHOW FIELDS FROM `users` + SQL (0.001613) SHOW FIELDS FROM `photos` + SQL (0.001271) SHOW FIELDS FROM `cameras` + SQL (0.001665) SHOW FIELDS FROM `users` + SQL (0.001605) SHOW FIELDS FROM `photos` + SQL (0.001360) SHOW FIELDS FROM `cameras` + SQL (0.000247) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000303) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001449) SHOW FIELDS FROM `users` + SQL (0.001510) SHOW FIELDS FROM `users` + SQL (0.001413) SHOW FIELDS FROM `photos` + SQL (0.001546) SHOW FIELDS FROM `cameras` + SQL (0.000115) SET SQL_AUTO_IS_NULL=0 + SQL (0.001542) SHOW FIELDS FROM `users` + SQL (0.001224) SHOW FIELDS FROM `photos` + SQL (0.001201) SHOW FIELDS FROM `cameras` + SQL (0.001325) SHOW FIELDS FROM `users` + SQL (0.001269) SHOW FIELDS FROM `photos` + SQL (0.001364) SHOW FIELDS FROM `cameras` + SQL (0.001517) SHOW FIELDS FROM `users` + SQL (0.001422) SHOW FIELDS FROM `photos` + SQL (0.001674) SHOW FIELDS FROM `cameras` + SQL (0.000270) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000269) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.008183) SHOW FIELDS FROM `users` + Photo Columns (0.001576) SHOW FIELDS FROM `photos` + SQL (0.001595) SHOW FIELDS FROM `users` + SQL (0.001461) SHOW FIELDS FROM `photos` + SQL (0.001327) SHOW FIELDS FROM `cameras` + SQL (0.000129) SET SQL_AUTO_IS_NULL=0 + SQL (0.001503) SHOW FIELDS FROM `users` + SQL (0.001544) SHOW FIELDS FROM `photos` + SQL (0.001444) SHOW FIELDS FROM `cameras` + SQL (0.001509) SHOW FIELDS FROM `users` + SQL (0.001593) SHOW FIELDS FROM `photos` + SQL (0.001422) SHOW FIELDS FROM `cameras` + SQL (0.001487) SHOW FIELDS FROM `users` + SQL (0.001996) SHOW FIELDS FROM `photos` + SQL (0.001380) SHOW FIELDS FROM `cameras` + SQL (0.000275) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000279) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001516) SHOW FIELDS FROM `users` + SQL (0.001449) SHOW FIELDS FROM `users` + SQL (0.001558) SHOW FIELDS FROM `photos` + SQL (0.001347) SHOW FIELDS FROM `cameras` + SQL (0.000133) SET SQL_AUTO_IS_NULL=0 + SQL (0.010735) SHOW FIELDS FROM `users` + SQL (0.002173) SHOW FIELDS FROM `photos` + SQL (0.001449) SHOW FIELDS FROM `cameras` + SQL (0.001510) SHOW FIELDS FROM `users` + SQL (0.001410) SHOW FIELDS FROM `photos` + SQL (0.001592) SHOW FIELDS FROM `cameras` + SQL (0.001570) SHOW FIELDS FROM `users` + SQL (0.001423) SHOW FIELDS FROM `photos` + SQL (0.001301) SHOW FIELDS FROM `cameras` + SQL (0.000287) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000301) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001475) SHOW FIELDS FROM `users` + Photo Columns (0.001465) SHOW FIELDS FROM `photos` + SQL (0.001633) SHOW FIELDS FROM `users` + SQL (0.001467) SHOW FIELDS FROM `photos` + SQL (0.001332) SHOW FIELDS FROM `cameras` + SQL (0.000132) SET SQL_AUTO_IS_NULL=0 + SQL (0.010888) SHOW FIELDS FROM `users` + SQL (0.002202) SHOW FIELDS FROM `photos` + SQL (0.001500) SHOW FIELDS FROM `cameras` + SQL (0.001457) SHOW FIELDS FROM `users` + SQL (0.001593) SHOW FIELDS FROM `photos` + SQL (0.001424) SHOW FIELDS FROM `cameras` + SQL (0.001492) SHOW FIELDS FROM `users` + SQL (0.001520) SHOW FIELDS FROM `photos` + SQL (0.001480) SHOW FIELDS FROM `cameras` + SQL (0.000290) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000263) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + SQL (0.000320) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001896) SHOW FIELDS FROM `users` + SQL (0.001262) SHOW FIELDS FROM `users` + SQL (0.001675) SHOW FIELDS FROM `photos` + SQL (0.001409) SHOW FIELDS FROM `cameras` + SQL (0.000130) SET SQL_AUTO_IS_NULL=0 + SQL (0.010691) SHOW FIELDS FROM `users` + SQL (0.002363) SHOW FIELDS FROM `photos` + SQL (0.001590) SHOW FIELDS FROM `cameras` + SQL (0.001560) SHOW FIELDS FROM `users` + SQL (0.013103) SHOW FIELDS FROM `photos` + SQL (0.001597) SHOW FIELDS FROM `cameras` + SQL (0.001491) SHOW FIELDS FROM `users` + SQL (0.001553) SHOW FIELDS FROM `photos` + SQL (0.001368) SHOW FIELDS FROM `cameras` + SQL (0.000300) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.001508) SHOW FIELDS FROM `users` + SQL (0.001583) SHOW FIELDS FROM `photos` + SQL (0.001442) SHOW FIELDS FROM `cameras` + SQL (0.000132) SET SQL_AUTO_IS_NULL=0 + SQL (0.010756) SHOW FIELDS FROM `users` + SQL (0.002320) SHOW FIELDS FROM `photos` + SQL (0.001416) SHOW FIELDS FROM `cameras` + SQL (0.001507) SHOW FIELDS FROM `users` + SQL (0.012716) SHOW FIELDS FROM `photos` + SQL (0.001406) SHOW FIELDS FROM `cameras` + SQL (0.001353) SHOW FIELDS FROM `users` + SQL (0.001440) SHOW FIELDS FROM `photos` + SQL (0.001263) SHOW FIELDS FROM `cameras` + SQL (0.000233) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000259) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001394) SHOW FIELDS FROM `users` + SQL (0.001487) SHOW FIELDS FROM `users` + SQL (0.001837) SHOW FIELDS FROM `photos` + SQL (0.001501) SHOW FIELDS FROM `cameras` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.001575) SHOW FIELDS FROM `users` + SQL (0.001415) SHOW FIELDS FROM `photos` + SQL (0.001483) SHOW FIELDS FROM `cameras` + SQL (0.000820) SHOW FIELDS FROM `users` + SQL (0.001526) SHOW FIELDS FROM `photos` + SQL (0.001093) SHOW FIELDS FROM `cameras` + SQL (0.001526) SHOW FIELDS FROM `users` + SQL (0.001631) SHOW FIELDS FROM `photos` + SQL (0.001346) SHOW FIELDS FROM `cameras` + SQL (0.000282) SELECT * +FROM users +WHERE users.id = 1 + SQL (0.000281) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + User Columns (0.001235) SHOW FIELDS FROM `users` + Photo Columns (0.001422) SHOW FIELDS FROM `photos` + SQL (0.001607) SHOW FIELDS FROM `users` + SQL (0.001685) SHOW FIELDS FROM `photos` + SQL (0.001318) SHOW FIELDS FROM `cameras` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010894) SHOW FIELDS FROM `users` + SQL (0.002240) SHOW FIELDS FROM `photos` + SQL (0.001487) SHOW FIELDS FROM `cameras` + SQL (0.001578) SHOW FIELDS FROM `users` + SQL (0.001582) SHOW FIELDS FROM `photos` + SQL (0.001418) SHOW FIELDS FROM `cameras` + SQL (0.001528) SHOW FIELDS FROM `users` + SQL (0.001577) SHOW FIELDS FROM `photos` + SQL (0.001215) SHOW FIELDS FROM `cameras` + SQL (0.000251) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001387) SHOW FIELDS FROM `users` + SQL (0.000296) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001457) SHOW FIELDS FROM `photos` + SQL (0.001421) SHOW FIELDS FROM `users` + SQL (0.001431) SHOW FIELDS FROM `photos` + SQL (0.001485) SHOW FIELDS FROM `cameras` + SQL (0.000145) SET SQL_AUTO_IS_NULL=0 + SQL (0.010759) SHOW FIELDS FROM `users` + SQL (0.002325) SHOW FIELDS FROM `photos` + SQL (0.001391) SHOW FIELDS FROM `cameras` + SQL (0.001545) SHOW FIELDS FROM `users` + SQL (0.001442) SHOW FIELDS FROM `photos` + SQL (0.001285) SHOW FIELDS FROM `cameras` + SQL (0.001287) SHOW FIELDS FROM `users` + SQL (0.001565) SHOW FIELDS FROM `photos` + SQL (0.001098) SHOW FIELDS FROM `cameras` + SQL (0.000215) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001362) SHOW FIELDS FROM `users` + SQL (0.000283) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001459) SHOW FIELDS FROM `photos` + SQL (0.001404) SHOW FIELDS FROM `users` + SQL (0.001554) SHOW FIELDS FROM `photos` + SQL (0.001531) SHOW FIELDS FROM `cameras` + SQL (0.000146) SET SQL_AUTO_IS_NULL=0 + SQL (0.010611) SHOW FIELDS FROM `users` + SQL (0.002560) SHOW FIELDS FROM `photos` + SQL (0.001457) SHOW FIELDS FROM `cameras` + SQL (0.001439) SHOW FIELDS FROM `users` + SQL (0.001575) SHOW FIELDS FROM `photos` + SQL (0.001422) SHOW FIELDS FROM `cameras` + SQL (0.001475) SHOW FIELDS FROM `users` + SQL (0.001563) SHOW FIELDS FROM `photos` + SQL (0.001389) SHOW FIELDS FROM `cameras` + SQL (0.000213) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001375) SHOW FIELDS FROM `users` + SQL (0.000251) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001417) SHOW FIELDS FROM `photos` + SQL (0.001395) SHOW FIELDS FROM `users` + SQL (0.001539) SHOW FIELDS FROM `photos` + SQL (0.001552) SHOW FIELDS FROM `cameras` + SQL (0.000113) SET SQL_AUTO_IS_NULL=0 + SQL (0.010659) SHOW FIELDS FROM `users` + SQL (0.002496) SHOW FIELDS FROM `photos` + SQL (0.001466) SHOW FIELDS FROM `cameras` + SQL (0.001519) SHOW FIELDS FROM `users` + SQL (0.001591) SHOW FIELDS FROM `photos` + SQL (0.001455) SHOW FIELDS FROM `cameras` + SQL (0.001502) SHOW FIELDS FROM `users` + SQL (0.001543) SHOW FIELDS FROM `photos` + SQL (0.001432) SHOW FIELDS FROM `cameras` + SQL (0.000225) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001376) SHOW FIELDS FROM `users` + SQL (0.000266) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001440) SHOW FIELDS FROM `photos` + SQL (0.001105) SHOW FIELDS FROM `users` + SQL (0.001152) SHOW FIELDS FROM `photos` + SQL (0.001384) SHOW FIELDS FROM `cameras` + SQL (0.000127) SET SQL_AUTO_IS_NULL=0 + SQL (0.010753) SHOW FIELDS FROM `users` + SQL (0.002275) SHOW FIELDS FROM `photos` + SQL (0.001708) SHOW FIELDS FROM `cameras` + SQL (0.001413) SHOW FIELDS FROM `users` + SQL (0.001552) SHOW FIELDS FROM `photos` + SQL (0.001604) SHOW FIELDS FROM `cameras` + SQL (0.001482) SHOW FIELDS FROM `users` + SQL (0.001500) SHOW FIELDS FROM `photos` + SQL (0.001349) SHOW FIELDS FROM `cameras` + SQL (0.000227) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001386) SHOW FIELDS FROM `users` + SQL (0.000269) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001425) SHOW FIELDS FROM `photos` + SQL (0.001065) SHOW FIELDS FROM `users` + SQL (0.001438) SHOW FIELDS FROM `photos` + SQL (0.001376) SHOW FIELDS FROM `cameras` + SQL (0.000107) SET SQL_AUTO_IS_NULL=0 + SQL (0.010766) SHOW FIELDS FROM `users` + SQL (0.002300) SHOW FIELDS FROM `photos` + SQL (0.001306) SHOW FIELDS FROM `cameras` + SQL (0.001562) SHOW FIELDS FROM `users` + SQL (0.001725) SHOW FIELDS FROM `photos` + SQL (0.001356) SHOW FIELDS FROM `cameras` + SQL (0.001539) SHOW FIELDS FROM `users` + SQL (0.001465) SHOW FIELDS FROM `photos` + SQL (0.001345) SHOW FIELDS FROM `cameras` + SQL (0.000303) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001553) SHOW FIELDS FROM `users` + SQL (0.000299) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001329) SHOW FIELDS FROM `photos` + SQL (0.001422) SHOW FIELDS FROM `users` + SQL (0.001414) SHOW FIELDS FROM `photos` + SQL (0.001429) SHOW FIELDS FROM `cameras` + SQL (0.000349) SELECT * +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id LEFT OUTER JOIN cameras ON photos.camera_id = cameras.id +WHERE users.id = 1 + SQL (0.000109) SET SQL_AUTO_IS_NULL=0 + SQL (0.010688) SHOW FIELDS FROM `users` + SQL (0.002247) SHOW FIELDS FROM `photos` + SQL (0.001542) SHOW FIELDS FROM `cameras` + SQL (0.001432) SHOW FIELDS FROM `users` + SQL (0.001390) SHOW FIELDS FROM `photos` + SQL (0.001428) SHOW FIELDS FROM `cameras` + SQL (0.001641) SHOW FIELDS FROM `users` + SQL (0.001602) SHOW FIELDS FROM `photos` + SQL (0.001426) SHOW FIELDS FROM `cameras` + SQL (0.000253) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001398) SHOW FIELDS FROM `users` + SQL (0.000304) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001457) SHOW FIELDS FROM `photos` + SQL (0.001298) SHOW FIELDS FROM `users` + SQL (0.001539) SHOW FIELDS FROM `photos` + SQL (0.001487) SHOW FIELDS FROM `cameras` + SQL (0.000139) SET SQL_AUTO_IS_NULL=0 + SQL (0.001575) SHOW FIELDS FROM `users` + SQL (0.001596) SHOW FIELDS FROM `photos` + SQL (0.001406) SHOW FIELDS FROM `cameras` + SQL (0.001432) SHOW FIELDS FROM `users` + SQL (0.001640) SHOW FIELDS FROM `photos` + SQL (0.001465) SHOW FIELDS FROM `cameras` + SQL (0.001463) SHOW FIELDS FROM `users` + SQL (0.001577) SHOW FIELDS FROM `photos` + SQL (0.001434) SHOW FIELDS FROM `cameras` + SQL (0.000258) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001417) SHOW FIELDS FROM `users` + SQL (0.000338) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001542) SHOW FIELDS FROM `photos` + SQL (0.001474) SHOW FIELDS FROM `users` + SQL (0.001582) SHOW FIELDS FROM `photos` + SQL (0.001524) SHOW FIELDS FROM `cameras` + SQL (0.000112) SET SQL_AUTO_IS_NULL=0 + SQL (0.016053) SHOW FIELDS FROM `users` + SQL (0.001843) SHOW FIELDS FROM `photos` + SQL (0.001493) SHOW FIELDS FROM `cameras` + SQL (0.001376) SHOW FIELDS FROM `users` + SQL (0.001547) SHOW FIELDS FROM `photos` + SQL (0.001670) SHOW FIELDS FROM `cameras` + SQL (0.001504) SHOW FIELDS FROM `users` + SQL (0.001756) SHOW FIELDS FROM `photos` + SQL (0.001567) SHOW FIELDS FROM `cameras` + SQL (0.001476) SHOW FIELDS FROM `users` + SQL (0.001574) SHOW FIELDS FROM `photos` + SQL (0.001402) SHOW FIELDS FROM `cameras` + SQL (0.001565) SHOW FIELDS FROM `users` + SQL (0.001346) SHOW FIELDS FROM `photos` + SQL (0.001424) SHOW FIELDS FROM `cameras` + SQL (0.001447) SHOW FIELDS FROM `users` + SQL (0.001570) SHOW FIELDS FROM `photos` + SQL (0.001502) SHOW FIELDS FROM `cameras` + SQL (0.000244) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001413) SHOW FIELDS FROM `users` + SQL (0.000304) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001471) SHOW FIELDS FROM `photos` + SQL (0.034694) SHOW FIELDS FROM `users` + SQL (0.001709) SHOW FIELDS FROM `photos` + SQL (0.001407) SHOW FIELDS FROM `cameras` + SQL (0.000109) SET SQL_AUTO_IS_NULL=0 + SQL (0.010677) SHOW FIELDS FROM `users` + SQL (0.002292) SHOW FIELDS FROM `photos` + SQL (0.001455) SHOW FIELDS FROM `cameras` + SQL (0.001467) SHOW FIELDS FROM `users` + SQL (0.001537) SHOW FIELDS FROM `photos` + SQL (0.001429) SHOW FIELDS FROM `cameras` + SQL (0.001476) SHOW FIELDS FROM `users` + SQL (0.001679) SHOW FIELDS FROM `photos` + SQL (0.001440) SHOW FIELDS FROM `cameras` + SQL (0.001147) SHOW FIELDS FROM `users` + SQL (0.001687) SHOW FIELDS FROM `photos` + SQL (0.001424) SHOW FIELDS FROM `cameras` + SQL (0.001509) SHOW FIELDS FROM `users` + SQL (0.001622) SHOW FIELDS FROM `photos` + SQL (0.001417) SHOW FIELDS FROM `cameras` + SQL (0.001430) SHOW FIELDS FROM `users` + SQL (0.001540) SHOW FIELDS FROM `photos` + SQL (0.001420) SHOW FIELDS FROM `cameras` + SQL (0.000244) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001374) SHOW FIELDS FROM `users` + SQL (0.000288) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001449) SHOW FIELDS FROM `photos` + SQL (0.034463) SHOW FIELDS FROM `users` + SQL (0.001751) SHOW FIELDS FROM `photos` + SQL (0.002051) SHOW FIELDS FROM `cameras` + SQL (0.000108) SET SQL_AUTO_IS_NULL=0 + SQL (0.010738) SHOW FIELDS FROM `users` + SQL (0.002251) SHOW FIELDS FROM `photos` + SQL (0.001306) SHOW FIELDS FROM `cameras` + SQL (0.001717) SHOW FIELDS FROM `users` + SQL (0.001554) SHOW FIELDS FROM `photos` + SQL (0.001364) SHOW FIELDS FROM `cameras` + SQL (0.001622) SHOW FIELDS FROM `users` + SQL (0.001490) SHOW FIELDS FROM `photos` + SQL (0.001310) SHOW FIELDS FROM `cameras` + SQL (0.001666) SHOW FIELDS FROM `users` + SQL (0.002175) SHOW FIELDS FROM `photos` + SQL (0.001601) SHOW FIELDS FROM `cameras` + SQL (0.001647) SHOW FIELDS FROM `users` + SQL (0.002284) SHOW FIELDS FROM `photos` + SQL (0.001156) SHOW FIELDS FROM `cameras` + SQL (0.001447) SHOW FIELDS FROM `users` + SQL (0.001549) SHOW FIELDS FROM `photos` + SQL (0.001431) SHOW FIELDS FROM `cameras` + SQL (0.000391) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001439) SHOW FIELDS FROM `users` + SQL (0.000284) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001431) SHOW FIELDS FROM `photos` + SQL (0.036129) SHOW FIELDS FROM `users` + SQL (0.001678) SHOW FIELDS FROM `photos` + SQL (0.001446) SHOW FIELDS FROM `cameras` + SQL (0.000111) SET SQL_AUTO_IS_NULL=0 + SQL (0.010686) SHOW FIELDS FROM `users` + SQL (0.002498) SHOW FIELDS FROM `photos` + SQL (0.001549) SHOW FIELDS FROM `cameras` + SQL (0.001496) SHOW FIELDS FROM `users` + SQL (0.001586) SHOW FIELDS FROM `photos` + SQL (0.001451) SHOW FIELDS FROM `cameras` + SQL (0.001455) SHOW FIELDS FROM `users` + SQL (0.001648) SHOW FIELDS FROM `photos` + SQL (0.001364) SHOW FIELDS FROM `cameras` + SQL (0.001406) SHOW FIELDS FROM `users` + SQL (0.001501) SHOW FIELDS FROM `photos` + SQL (0.001399) SHOW FIELDS FROM `cameras` + SQL (0.001388) SHOW FIELDS FROM `users` + SQL (0.001888) SHOW FIELDS FROM `photos` + SQL (0.001454) SHOW FIELDS FROM `cameras` + SQL (0.001570) SHOW FIELDS FROM `users` + SQL (0.002665) SHOW FIELDS FROM `photos` + SQL (0.001922) SHOW FIELDS FROM `cameras` + SQL (0.001160) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001117) SHOW FIELDS FROM `users` + SQL (0.001219) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001255) SHOW FIELDS FROM `photos` + SQL (0.034678) SHOW FIELDS FROM `users` + SQL (0.001684) SHOW FIELDS FROM `photos` + SQL (0.001242) SHOW FIELDS FROM `cameras` + SQL (0.000110) SET SQL_AUTO_IS_NULL=0 + SQL (0.010673) SHOW FIELDS FROM `users` + SQL (0.002380) SHOW FIELDS FROM `photos` + SQL (0.001444) SHOW FIELDS FROM `cameras` + SQL (0.001580) SHOW FIELDS FROM `users` + SQL (0.001158) SHOW FIELDS FROM `photos` + SQL (0.001358) SHOW FIELDS FROM `cameras` + SQL (0.002625) SHOW FIELDS FROM `users` + SQL (0.002378) SHOW FIELDS FROM `photos` + SQL (0.001774) SHOW FIELDS FROM `cameras` + SQL (0.002249) SHOW FIELDS FROM `users` + SQL (0.001218) SHOW FIELDS FROM `photos` + SQL (0.002117) SHOW FIELDS FROM `cameras` + SQL (0.001795) SHOW FIELDS FROM `users` + SQL (0.002656) SHOW FIELDS FROM `photos` + SQL (0.001412) SHOW FIELDS FROM `cameras` + SQL (0.001415) SHOW FIELDS FROM `users` + SQL (0.001519) SHOW FIELDS FROM `photos` + SQL (0.001043) SHOW FIELDS FROM `cameras` + SQL (0.000346) SELECT * +FROM users +WHERE users.id = 1 + User Columns (0.001560) SHOW FIELDS FROM `users` + SQL (0.000297) SELECT photos.user_id, photos.camera_id, photos.id +FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +WHERE users.id = 1 + Photo Columns (0.001471) SHOW FIELDS FROM `photos` + SQL (0.001420) SHOW FIELDS FROM `users` + SQL (0.001463) SHOW FIELDS FROM `photos` + SQL (0.001395) SHOW FIELDS FROM `cameras` diff --git a/spec/integration/scratch_spec.rb b/spec/integration/scratch_spec.rb index 6426d2478de41..12832c1162a28 100644 --- a/spec/integration/scratch_spec.rb +++ b/spec/integration/scratch_spec.rb @@ -2,27 +2,17 @@ describe 'Relational Algebra' do before do - User = TableRelation.new(:users) - Photo = TableRelation.new(:photos) - Camera = TableRelation.new(:cameras) - user = User.select(User[:id] == 1) - @user_photos = (user << Photo).on(user[:id] == Photo[:user_id]) + @users = TableRelation.new(:users) + @photos = TableRelation.new(:photos) + @cameras = TableRelation.new(:cameras) + @user = @users.select(@users[:id] == 1) + @user_photos = (@user << @photos).on(@user[:id] == @photos[:user_id]) + @user_cameras = (@user_photos << @cameras).on(@user_photos[:camera_id] == @cameras[:id]) end it 'simulates User.has_many :photos' do - @user_photos.to_sql.should == SelectBuilder.new do - select { all } - from :users do - left_outer_join :photos do - equals { column :users, :id; column :photos, :user_id } - end - end - where do - equals { column :users, :id; value 1 } - end - end - @user_photos.to_sql.to_s.should be_like(""" - SELECT * + @user_photos.project(*@photos.attributes).to_sql.to_s.should be_like(""" + SELECT photos.id, photos.user_id, photos.camera_id FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id @@ -31,7 +21,16 @@ """) end - it 'simulating a User.has_many :cameras :through => :photos' do - user_cameras = (@user_photos << Camera).on(@user_photos[:camera_id] == Camera[:id]) + it 'simulates a User.has_many :cameras :through => :photos' do + @user_cameras.project(*@cameras.attributes).to_sql.to_s.should be_like(""" + SELECT cameras.id + FROM users + LEFT OUTER JOIN photos + ON users.id = photos.user_id + LEFT OUTER JOIN cameras + ON photos.camera_id = cameras.id + WHERE + users.id = 1 + """) end end \ No newline at end of file diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb index 5ddbaa96b528a..d8a007f918183 100644 --- a/spec/relations/attribute_spec.rb +++ b/spec/relations/attribute_spec.rb @@ -57,6 +57,7 @@ end end + describe '#to_sql' do it "manufactures a column" do Attribute.new(@relation1, :attribute_name, :alias).to_sql.should == SelectsBuilder.new do diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb index a7c15fd76a38d..bae294440e46a 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/relations/join_relation_spec.rb @@ -4,7 +4,7 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @predicate = EqualityPredicate.new(@relation1[:a], @relation2[:b]) + @predicate = EqualityPredicate.new(@relation1[:id], @relation2[:id]) end describe '==' do @@ -20,9 +20,9 @@ describe '#to_sql' do before do - @relation1 = @relation1.select(@relation1[:c] == @relation2[:d]) + @relation1 = @relation1.select(@relation1[:id] == @relation2[:foo_id]) class ConcreteJoinRelation < JoinRelation - def join_name + def join_type :inner_join end end @@ -30,19 +30,25 @@ def join_name it 'manufactures sql joining the two tables on the predicate, merging the selects' do ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_sql.to_s.should == SelectBuilder.new do - select { all } + select do + column :foo, :name + column :foo, :id + column :bar, :name + column :bar, :foo_id + column :bar, :id + end from :foo do inner_join :bar do equals do - column :foo, :a - column :bar, :b + column :foo, :id + column :bar, :id end end end where do equals do - column :foo, :c - column :bar, :d + column :foo, :id + column :bar, :foo_id end end end.to_s diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb index 8050aa981ca94..d0654bd8da038 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/relations/order_relation_spec.rb @@ -4,8 +4,8 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @attribute1 = @relation1[:foo] - @attribute2 = @relation2[:bar] + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] end describe '==' do @@ -18,13 +18,16 @@ describe '#to_sql' do it "manufactures sql with an order clause" do - OrderRelation.new(@relation1, @attribute1).to_sql.should == SelectBuilder.new do - select { all } + OrderRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do + select do + column :foo, :name + column :foo, :id + end from :foo order_by do - column :foo, :foo + column :foo, :id end - end + end.to_s end end diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb index f17f57df7bee7..47386f966d18b 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/relations/projection_relation_spec.rb @@ -4,8 +4,8 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @attribute1 = @relation1[:foo] - @attribute2 = @relation2[:bar] + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] end describe '==' do @@ -18,12 +18,12 @@ describe '#to_sql' do it "manufactures sql with a limited select clause" do - ProjectionRelation.new(@relation1, @attribute1).to_sql.should == SelectBuilder.new do + ProjectionRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do select do - column :foo, :foo + column :foo, :id end from :foo - end + end.to_s end end end \ No newline at end of file diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb index e6caa32e80c58..ea3901e3fdc41 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/relations/range_relation_spec.rb @@ -21,7 +21,10 @@ range_size = @range2.last - @range2.first + 1 range_start = @range2.first RangeRelation.new(@relation1, @range2).to_sql.to_s.should == SelectBuilder.new do - select { all } + select do + column :foo, :name + column :foo, :id + end from :foo limit range_size offset range_start diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index 6c2c2b86112ba..db4b6b87753ca 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -30,10 +30,6 @@ it "manufactures a range relation when given a range" do @relation1[1..2].should == RangeRelation.new(@relation1, 1..2) end - - it "raises an error if the named attribute is not part of the relation" do - pending - end end describe Relation, '#include?' do @@ -43,10 +39,6 @@ end describe Relation, '#project' do - it "only allows projecting attributes in the relation" do - pending - end - it "collapses identical projections" do pending end diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb index ceb771b46dedf..1a7f9e6659608 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/relations/selection_relation_spec.rb @@ -28,8 +28,11 @@ describe '#to_sql' do it "manufactures sql with where clause conditions" do - SelectionRelation.new(@relation1, @predicate1).to_sql.should == SelectBuilder.new do - select { all } + SelectionRelation.new(@relation1, @predicate1).to_sql.to_s.should == SelectBuilder.new do + select do + column :foo, :name + column :foo, :id + end from :foo where do equals do @@ -37,7 +40,7 @@ column :bar, :foo_id end end - end + end.to_s end end end \ No newline at end of file diff --git a/spec/relations/table_relation_spec.rb b/spec/relations/table_relation_spec.rb index 7a820782dfd29..8cd31a9ac829c 100644 --- a/spec/relations/table_relation_spec.rb +++ b/spec/relations/table_relation_spec.rb @@ -3,7 +3,10 @@ describe TableRelation, '#to_sql' do it "returns a simple SELECT query" do TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s| - select { all } + select do + column :users, :name + column :users, :id + end from :users end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a764fff03ef8a..c53277b8e31d1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,6 +3,17 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'sql_algebra') require File.join(File.dirname(__FILE__), 'spec_helpers', 'be_like') +ActiveRecord::Base.configurations = { + 'sql_algebra_test' => { + :adapter => 'mysql', + :username => 'root', + :password => 'password', + :encoding => 'utf8', + :database => 'sql_algebra_test', + }, +} +ActiveRecord::Base.establish_connection 'sql_algebra_test' + Spec::Runner.configure do |config| config.include(BeLikeMatcher) end \ No newline at end of file From 3117a5a6605fcb7c033b3ea5e074e5f087615fcf Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 3 Jan 2008 23:41:54 -0800 Subject: [PATCH 0011/1492] missing files --- lib/sql_algebra/relations/compound_relation.rb | 3 +++ lib/sql_algebra/relations/join.rb | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 lib/sql_algebra/relations/compound_relation.rb create mode 100644 lib/sql_algebra/relations/join.rb diff --git a/lib/sql_algebra/relations/compound_relation.rb b/lib/sql_algebra/relations/compound_relation.rb new file mode 100644 index 0000000000000..a8e9a41b5e35f --- /dev/null +++ b/lib/sql_algebra/relations/compound_relation.rb @@ -0,0 +1,3 @@ +class CompoundRelation < Relation + delegate :attributes, :attribute, :joins, :select, :orders, :table, :to => :relation +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join.rb b/lib/sql_algebra/relations/join.rb new file mode 100644 index 0000000000000..9a6196deacf51 --- /dev/null +++ b/lib/sql_algebra/relations/join.rb @@ -0,0 +1,15 @@ +class Join + attr_reader :relation1, :relation2, :predicates, :join_type + + def initialize(relation1, relation2, predicates, join_type) + @relation1, @relation2, @predicates, @join_type = relation1, relation2, predicates, join_type + end + + def to_sql(builder = JoinsBuilder.new) + builder.call do + send(join_type, relation2.table) do + predicates.each { |p| p.to_sql(self) } + end + end + end +end \ No newline at end of file From 4366f8658e75ead57070427c09b0c57abe683df9 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 3 Jan 2008 23:42:51 -0800 Subject: [PATCH 0012/1492] removed overly flexible sql builder funcitonality --- lib/sql_algebra/sql_builder/select_builder.rb | 1 - spec/sql_builder/select_builder_spec.rb | 57 ------------------- 2 files changed, 58 deletions(-) diff --git a/lib/sql_algebra/sql_builder/select_builder.rb b/lib/sql_algebra/sql_builder/select_builder.rb index d4eb4feb56659..68df68db93fbd 100644 --- a/lib/sql_algebra/sql_builder/select_builder.rb +++ b/lib/sql_algebra/sql_builder/select_builder.rb @@ -7,7 +7,6 @@ def from(table, &block) @table = table @joins = JoinsBuilder.new(&block) end - delegate :inner_join, :left_outer_join, :to => :@joins def where(&block) @conditions ||= ConditionsBuilder.new diff --git a/spec/sql_builder/select_builder_spec.rb b/spec/sql_builder/select_builder_spec.rb index 39597b0392d2e..7b059bd6bd7d8 100644 --- a/spec/sql_builder/select_builder_spec.rb +++ b/spec/sql_builder/select_builder_spec.rb @@ -109,62 +109,5 @@ """) end end - - describe 'repeated clauses' do - describe 'with repeating joins' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users do - inner_join(:friendships) do - equals do - value :id - value :user_id - end - end - end - inner_join(:pictures) do - equals do - value :id - value :user_id - end - end - end.to_s.should be_like(""" - SELECT * - FROM users INNER JOIN friendships ON id = user_id INNER JOIN pictures ON id = user_id - """) - end - end - - describe 'with repeating wheres' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users - where do - equals do - value :a - value :b - end - end - where do - equals do - value :b - value :c - end - end - end.to_s.should be_like(""" - SELECT * - FROM users - WHERE a = b - AND b = c - """) - end - end - end end end \ No newline at end of file From 346d9c6bde5ae0a0c918b4e0b25d79aa2760234a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 5 Jan 2008 13:00:39 -0800 Subject: [PATCH 0013/1492] basic rename functionality --- lib/sql_algebra.rb | 1 + lib/sql_algebra/relations/attribute.rb | 4 ++++ lib/sql_algebra/relations/relation.rb | 4 ++++ spec/relations/attribute_spec.rb | 6 ++++++ spec/relations/relation_spec.rb | 6 ++++++ spec/relations/table_relation_spec.rb | 24 ++++++++++++++++-------- 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index b3e3c8d17660a..61625ff270aaf 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -17,6 +17,7 @@ require 'sql_algebra/relations/selection_relation' require 'sql_algebra/relations/order_relation' require 'sql_algebra/relations/range_relation' +require 'sql_algebra/relations/rename_relation' require 'sql_algebra/relations/join' require 'sql_algebra/predicates/predicate' diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb index 85d40dfb124d4..89ac495245722 100644 --- a/lib/sql_algebra/relations/attribute.rb +++ b/lib/sql_algebra/relations/attribute.rb @@ -5,6 +5,10 @@ def initialize(relation, attribute_name, aliaz = nil) @relation, @attribute_name, @aliaz = relation, attribute_name, aliaz end + def aliazz(aliaz) + Attribute.new(relation, attribute_name, aliaz) + end + def eql?(other) relation == other.relation and attribute_name == other.attribute_name end diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb index 8c21927d01c76..02723ae0ccf07 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/sql_algebra/relations/relation.rb @@ -32,6 +32,10 @@ def project(*attributes) def order(*attributes) OrderRelation.new(self, *attributes) end + + def rename(attribute, aliaz) + RenameRelation.new(self, attribute, aliaz) + end end include Operations diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb index d8a007f918183..7015fd2542855 100644 --- a/spec/relations/attribute_spec.rb +++ b/spec/relations/attribute_spec.rb @@ -6,6 +6,12 @@ @relation2 = TableRelation.new(:bar) end + describe 'aliaz' do + it "manufactures an aliased attributed" do + pending + end + end + describe '#eql?' do it "obtains if the relation and attribute name are identical" do Attribute.new(@relation1, :attribute_name).should be_eql(Attribute.new(@relation1, :attribute_name)) diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index db4b6b87753ca..5cef7d7b3dde6 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -48,6 +48,12 @@ end end + describe Relation, '#rename' do + it "manufactures a rename relation" do + @relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1, :foo) + end + end + describe Relation, '#select' do before do @predicate = EqualityPredicate.new(@attribute1, @attribute2) diff --git a/spec/relations/table_relation_spec.rb b/spec/relations/table_relation_spec.rb index 8cd31a9ac829c..dec8bba6b1c61 100644 --- a/spec/relations/table_relation_spec.rb +++ b/spec/relations/table_relation_spec.rb @@ -1,13 +1,21 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper') -describe TableRelation, '#to_sql' do - it "returns a simple SELECT query" do - TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s| - select do - column :users, :name - column :users, :id +describe TableRelation do + describe '#to_sql' do + it "returns a simple SELECT query" do + TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s| + select do + column :users, :name + column :users, :id + end + from :users end - from :users end end -end + + describe '#attributes' do + it 'manufactures attributes corresponding to columns in the table' do + pending + end + end +end \ No newline at end of file From d7b89d957dbceb4eeceb0b1d381474a4de70a14d Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 5 Jan 2008 15:24:46 -0800 Subject: [PATCH 0014/1492] qualified naming --- lib/sql_algebra.rb | 1 + lib/sql_algebra/extensions/array.rb | 5 ++ lib/sql_algebra/extensions/base.rb | 12 ++-- lib/sql_algebra/extensions/object.rb | 4 ++ .../predicates/binary_predicate.rb | 4 ++ .../predicates/equality_predicate.rb | 2 +- lib/sql_algebra/relations/attribute.rb | 57 +++++++++------- lib/sql_algebra/relations/join_relation.rb | 2 +- lib/sql_algebra/relations/order_relation.rb | 6 +- .../relations/projection_relation.rb | 4 ++ lib/sql_algebra/relations/relation.rb | 2 +- lib/sql_algebra/relations/rename_relation.rb | 34 ++++++++++ .../relations/selection_relation.rb | 5 ++ lib/sql_algebra/relations/table_relation.rb | 8 +++ spec/integration/scratch_spec.rb | 5 ++ spec/predicates/binary_predicate_spec.rb | 15 ++-- spec/predicates/equality_predicate_spec.rb | 6 +- spec/relations/attribute_spec.rb | 34 +++++++--- spec/relations/order_relation_spec.rb | 7 ++ spec/relations/projection_relation_spec.rb | 7 ++ spec/relations/range_relation_spec.rb | 6 ++ spec/relations/relation_spec.rb | 20 +++--- spec/relations/rename_relation_spec.rb | 68 +++++++++++++++++++ spec/relations/selection_relation_spec.rb | 7 ++ spec/relations/table_relation_spec.rb | 14 +++- spec/spec_helper.rb | 8 +++ 26 files changed, 283 insertions(+), 60 deletions(-) create mode 100644 lib/sql_algebra/extensions/array.rb create mode 100644 lib/sql_algebra/relations/rename_relation.rb create mode 100644 spec/relations/rename_relation_spec.rb diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 61625ff270aaf..475bb231383ec 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -33,6 +33,7 @@ require 'sql_algebra/extensions/range' require 'sql_algebra/extensions/object' +require 'sql_algebra/extensions/array' require 'sql_algebra/sql_builder/sql_builder' require 'sql_algebra/sql_builder/select_builder' diff --git a/lib/sql_algebra/extensions/array.rb b/lib/sql_algebra/extensions/array.rb new file mode 100644 index 0000000000000..5b6d6d6abd537 --- /dev/null +++ b/lib/sql_algebra/extensions/array.rb @@ -0,0 +1,5 @@ +class Array + def to_hash + Hash[*flatten] + end +end \ No newline at end of file diff --git a/lib/sql_algebra/extensions/base.rb b/lib/sql_algebra/extensions/base.rb index 79f2ce75d1dea..0143caf23d9c1 100644 --- a/lib/sql_algebra/extensions/base.rb +++ b/lib/sql_algebra/extensions/base.rb @@ -3,12 +3,12 @@ def self.bring_forth(record, includes = []) object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) } includes.each do |include| case include - when Symbol - object.send(association = include).bring_forth(record) - when Hash - include.each do |association, nested_associations| - object.send(association).bring_forth(record, nested_associations) - end + when Symbol + object.send(association = include).bring_forth(record) + when Hash + include.each do |association, nested_associations| + object.send(association).bring_forth(record, nested_associations) + end end end end diff --git a/lib/sql_algebra/extensions/object.rb b/lib/sql_algebra/extensions/object.rb index 639e810a97ccf..6ea66d74840c9 100644 --- a/lib/sql_algebra/extensions/object.rb +++ b/lib/sql_algebra/extensions/object.rb @@ -1,4 +1,8 @@ class Object + def qualify + self + end + def to_sql(builder = EqualsConditionBuilder.new) me = self builder.call do diff --git a/lib/sql_algebra/predicates/binary_predicate.rb b/lib/sql_algebra/predicates/binary_predicate.rb index 9463f162c55d4..f5c420c83312b 100644 --- a/lib/sql_algebra/predicates/binary_predicate.rb +++ b/lib/sql_algebra/predicates/binary_predicate.rb @@ -10,6 +10,10 @@ def ==(other) (attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) end + def qualify + self.class.new(attribute1.qualify, attribute2.qualify) + end + def to_sql(builder = ConditionsBuilder.new) builder.call do send(predicate_name) do diff --git a/lib/sql_algebra/predicates/equality_predicate.rb b/lib/sql_algebra/predicates/equality_predicate.rb index 2061d0f6446ad..7040c45f6704d 100644 --- a/lib/sql_algebra/predicates/equality_predicate.rb +++ b/lib/sql_algebra/predicates/equality_predicate.rb @@ -4,7 +4,7 @@ def ==(other) ((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or (attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1))) end - + protected def predicate_name :equals diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/sql_algebra/relations/attribute.rb index 89ac495245722..7583553b8001c 100644 --- a/lib/sql_algebra/relations/attribute.rb +++ b/lib/sql_algebra/relations/attribute.rb @@ -1,45 +1,56 @@ class Attribute - attr_reader :relation, :attribute_name, :aliaz + attr_reader :relation, :name, :aliaz - def initialize(relation, attribute_name, aliaz = nil) - @relation, @attribute_name, @aliaz = relation, attribute_name, aliaz + def initialize(relation, name, aliaz = nil) + @relation, @name, @aliaz = relation, name, aliaz end def aliazz(aliaz) - Attribute.new(relation, attribute_name, aliaz) + Attribute.new(relation, name, aliaz) end - def eql?(other) - relation == other.relation and attribute_name == other.attribute_name + def qualified_name + "#{relation.table}.#{name}" end - def ==(other) - EqualityPredicate.new(self, other) + def qualify + aliazz(qualified_name) end + + module Predications + def eql?(other) + relation == other.relation and name == other.name and aliaz == other.aliaz + end - def <(other) - LessThanPredicate.new(self, other) - end + def ==(other) + EqualityPredicate.new(self, other) + end - def <=(other) - LessThanOrEqualToPredicate.new(self, other) - end + def <(other) + LessThanPredicate.new(self, other) + end - def >(other) - GreaterThanPredicate.new(self, other) - end + def <=(other) + LessThanOrEqualToPredicate.new(self, other) + end - def >=(other) - GreaterThanOrEqualToPredicate.new(self, other) - end + def >(other) + GreaterThanPredicate.new(self, other) + end - def =~(regexp) - MatchPredicate.new(self, regexp) + def >=(other) + GreaterThanOrEqualToPredicate.new(self, other) + end + + def =~(regexp) + MatchPredicate.new(self, regexp) + end end + include Predications def to_sql(builder = SelectsBuilder.new) builder.call do - column relation.table, attribute_name, aliaz + column relation.table, name, aliaz end end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb index dc57e24c96c53..c65b07225ffa3 100644 --- a/lib/sql_algebra/relations/join_relation.rb +++ b/lib/sql_algebra/relations/join_relation.rb @@ -16,7 +16,7 @@ def joins end def selects - relation1.selects + relation2.selects + relation1.send(:selects) + relation2.send(:selects) end def attributes diff --git a/lib/sql_algebra/relations/order_relation.rb b/lib/sql_algebra/relations/order_relation.rb index 384a007bc23d0..b39dc45c3f72f 100644 --- a/lib/sql_algebra/relations/order_relation.rb +++ b/lib/sql_algebra/relations/order_relation.rb @@ -1,4 +1,4 @@ -class OrderRelation < Relation +class OrderRelation < CompoundRelation attr_reader :relation, :attributes def initialize(relation, *attributes) @@ -9,6 +9,10 @@ def ==(other) relation == other.relation and attributes.eql?(other.attributes) end + def qualify + OrderRelation.new(relation.qualify, *attributes.collect { |a| a.qualify }) + end + def to_sql(builder = SelectBuilder.new) relation.to_sql(builder).call do attributes.each do |attribute| diff --git a/lib/sql_algebra/relations/projection_relation.rb b/lib/sql_algebra/relations/projection_relation.rb index 0b5d645d79a8a..1a0e8dbfe40b0 100644 --- a/lib/sql_algebra/relations/projection_relation.rb +++ b/lib/sql_algebra/relations/projection_relation.rb @@ -9,6 +9,10 @@ def ==(other) relation == other.relation and attributes.eql?(other.attributes) end + def qualify + ProjectionRelation.new(relation.qualify, *attributes.collect(&:qualify)) + end + def to_sql(builder = SelectBuilder.new) relation.to_sql(builder).call do select do diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb index 02723ae0ccf07..82266fd7e8bf1 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/sql_algebra/relations/relation.rb @@ -34,7 +34,7 @@ def order(*attributes) end def rename(attribute, aliaz) - RenameRelation.new(self, attribute, aliaz) + RenameRelation.new(self, attribute => aliaz) end end include Operations diff --git a/lib/sql_algebra/relations/rename_relation.rb b/lib/sql_algebra/relations/rename_relation.rb new file mode 100644 index 0000000000000..8acf5091b26c5 --- /dev/null +++ b/lib/sql_algebra/relations/rename_relation.rb @@ -0,0 +1,34 @@ +class RenameRelation < CompoundRelation + attr_reader :relation, :schmattribute, :aliaz + + def initialize(relation, renames) + @schmattribute, @aliaz = renames.shift + @relation = renames.empty?? relation : RenameRelation.new(relation, renames) + end + + def ==(other) + relation == other.relation and schmattribute.eql?(other.schmattribute) and aliaz == other.aliaz + end + + def attributes + relation.attributes.collect { |a| substitute(a) } + end + + def qualify + RenameRelation.new(relation.qualify, schmattribute.qualify => aliaz) + end + + protected + def attribute(name) + case + when name == aliaz then schmattribute.aliazz(aliaz) + when relation[name].eql?(schmattribute) then nil + else relation[name] + end + end + + private + def substitute(a) + a.eql?(schmattribute) ? a.aliazz(aliaz) : a + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/sql_algebra/relations/selection_relation.rb index 72911aa65af5b..dcf5f4745fb8b 100644 --- a/lib/sql_algebra/relations/selection_relation.rb +++ b/lib/sql_algebra/relations/selection_relation.rb @@ -10,6 +10,11 @@ def ==(other) relation == other.relation and predicate == other.predicate end + def qualify + SelectionRelation.new(relation.qualify, predicate.qualify) + end + + protected def selects [predicate] end diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/sql_algebra/relations/table_relation.rb index 1915b42565271..5a47ae7a3426c 100644 --- a/lib/sql_algebra/relations/table_relation.rb +++ b/lib/sql_algebra/relations/table_relation.rb @@ -8,6 +8,10 @@ def initialize(table) def attributes attributes_by_name.values end + + def qualify + RenameRelation.new self, qualifications + end protected def attribute(name) @@ -20,4 +24,8 @@ def attributes_by_name attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym)) end end + + def qualifications + attributes.zip(attributes.collect(&:qualified_name)).to_hash + end end \ No newline at end of file diff --git a/spec/integration/scratch_spec.rb b/spec/integration/scratch_spec.rb index 12832c1162a28..b19f1a52341b6 100644 --- a/spec/integration/scratch_spec.rb +++ b/spec/integration/scratch_spec.rb @@ -33,4 +33,9 @@ users.id = 1 """) end + + it '' do + # + # @users.rename() + end end \ No newline at end of file diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb index a044e43a84a9e..25cffde2c5dae 100644 --- a/spec/predicates/binary_predicate_spec.rb +++ b/spec/predicates/binary_predicate_spec.rb @@ -4,8 +4,8 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :attribute_name1) - @attribute2 = Attribute.new(@relation2, :attribute_name2) + @attribute1 = Attribute.new(@relation1, :name1) + @attribute2 = Attribute.new(@relation2, :name2) class ConcreteBinaryPredicate < BinaryPredicate def predicate_name :equals @@ -31,12 +31,19 @@ def predicate_name end end + describe '#qualify' do + it "manufactures an equality predicate with qualified attributes" do + ConcreteBinaryPredicate.new(@attribute1, @attribute2).qualify. \ + should == ConcreteBinaryPredicate.new(@attribute1.qualify, @attribute2.qualify) + end + end + describe '#to_sql' do it 'manufactures correct sql' do ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do equals do - column :foo, :attribute_name1 - column :bar, :attribute_name2 + column :foo, :name1 + column :bar, :name2 end end end diff --git a/spec/predicates/equality_predicate_spec.rb b/spec/predicates/equality_predicate_spec.rb index 18d33991934fa..75b495b6f7f1e 100644 --- a/spec/predicates/equality_predicate_spec.rb +++ b/spec/predicates/equality_predicate_spec.rb @@ -4,11 +4,11 @@ before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :attribute_name) - @attribute2 = Attribute.new(@relation2, :attribute_name) + @attribute1 = Attribute.new(@relation1, :name) + @attribute2 = Attribute.new(@relation2, :name) end - describe EqualityPredicate, '==' do + describe '==' do it "obtains if attribute1 and attribute2 are identical" do EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2) EqualityPredicate.new(@attribute1, @attribute2).should_not == EqualityPredicate.new(@attribute1, @attribute1) diff --git a/spec/relations/attribute_spec.rb b/spec/relations/attribute_spec.rb index 7015fd2542855..4887be38d2ccd 100644 --- a/spec/relations/attribute_spec.rb +++ b/spec/relations/attribute_spec.rb @@ -6,24 +6,41 @@ @relation2 = TableRelation.new(:bar) end - describe 'aliaz' do + describe '#aliazz' do it "manufactures an aliased attributed" do pending end + + it "should be renamed to #alias!" do + pending + @relation1.alias + end + end + + describe '#qualified_name' do + it "manufactures an attribute name prefixed with the relation's name" do + @relation1[:id].qualified_name.should == 'foo.id' + end + end + + describe '#qualify' do + it "manufactures an attribute aliased with that attributes qualified name" do + @relation1[:id].qualify == @relation1[:id].qualify + end end describe '#eql?' do it "obtains if the relation and attribute name are identical" do - Attribute.new(@relation1, :attribute_name).should be_eql(Attribute.new(@relation1, :attribute_name)) - Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation1, :another_attribute_name)) - Attribute.new(@relation1, :attribute_name).should_not be_eql(Attribute.new(@relation2, :attribute_name)) + Attribute.new(@relation1, :name).should be_eql(Attribute.new(@relation1, :name)) + Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation1, :another_name)) + Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation2, :name)) end end describe 'predications' do before do - @attribute1 = Attribute.new(@relation1, :attribute_name) - @attribute2 = Attribute.new(@relation2, :attribute_name) + @attribute1 = Attribute.new(@relation1, :name) + @attribute2 = Attribute.new(@relation2, :name) end describe '==' do @@ -63,11 +80,10 @@ end end - describe '#to_sql' do it "manufactures a column" do - Attribute.new(@relation1, :attribute_name, :alias).to_sql.should == SelectsBuilder.new do - column :foo, :attribute_name, :alias + Attribute.new(@relation1, :name, :alias).to_sql.should == SelectsBuilder.new do + column :foo, :name, :alias end end end diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb index d0654bd8da038..62275ff0ac4e0 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/relations/order_relation_spec.rb @@ -16,6 +16,13 @@ end end + describe '#qualify' do + it "manufactures an order relation with qualified attributes and qualified relation" do + OrderRelation.new(@relation1, @attribute1).qualify. \ + should == OrderRelation.new(@relation1.qualify, @attribute1.qualify) + end + end + describe '#to_sql' do it "manufactures sql with an order clause" do OrderRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb index 47386f966d18b..eb74b5cedf0b8 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/relations/projection_relation_spec.rb @@ -16,6 +16,13 @@ end end + describe '#qualify' do + it "manufactures a projection relation with qualified attributes and qualified relation" do + ProjectionRelation.new(@relation1, @attribute1).qualify. \ + should == ProjectionRelation.new(@relation1.qualify, @attribute1.qualify) + end + end + describe '#to_sql' do it "manufactures sql with a limited select clause" do ProjectionRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb index ea3901e3fdc41..261afcaf8ee70 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/relations/range_relation_spec.rb @@ -16,6 +16,12 @@ end end + describe '#qualify' do + it "manufactures a range relation with a qualified relation and a qualified range" do + pending + end + end + describe '#to_sql' do it "manufactures sql with limit and offset" do range_size = @range2.last - @range2.first + 1 diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index 5cef7d7b3dde6..d029827f216fd 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -8,21 +8,21 @@ @attribute2 = Attribute.new(@relation1, :name) end - describe Relation, 'joins' do - describe Relation, '<=>' do + describe 'joins' do + describe '<=>' do it "manufactures an inner join operation between those two relations" do (@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2) end end - describe Relation, '<<' do + describe '<<' do it "manufactures a left outer join operation between those two relations" do (@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2) end end end - describe Relation, '[]' do + describe '[]' do it "manufactures an attribute when given a symbol" do @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) end @@ -32,13 +32,13 @@ end end - describe Relation, '#include?' do + describe '#include?' do it "manufactures an inclusion predicate" do @relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1) end end - describe Relation, '#project' do + describe '#project' do it "collapses identical projections" do pending end @@ -48,13 +48,13 @@ end end - describe Relation, '#rename' do + describe '#rename' do it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1, :foo) + @relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1 => :foo) end end - describe Relation, '#select' do + describe '#select' do before do @predicate = EqualityPredicate.new(@attribute1, @attribute2) end @@ -64,7 +64,7 @@ end end - describe Relation, 'order' do + describe 'order' do it "manufactures an order relation" do @relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) end diff --git a/spec/relations/rename_relation_spec.rb b/spec/relations/rename_relation_spec.rb new file mode 100644 index 0000000000000..e7792d146af50 --- /dev/null +++ b/spec/relations/rename_relation_spec.rb @@ -0,0 +1,68 @@ +require File.join(File.dirname(__FILE__), '..', 'spec_helper') + +describe RenameRelation do + before do + @relation = TableRelation.new(:foo) + @renamed_relation = RenameRelation.new(@relation, @relation[:id] => :schmid) + end + + describe '#initialize' do + it "manufactures nested rename relations if multiple renames are provided" do + RenameRelation.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ + should == RenameRelation.new(RenameRelation.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) + end + + it "make this test less brittle wrt/ hash order" do + pending + end + + it "raises an exception if the alias provided is already used" do + pending + end + end + + describe '==' do + it "obtains if the relation, attribute, and alias are identical" do + pending + end + end + + describe '#attributes' do + it "manufactures a list of attributes with the renamed attribute aliased" do + RenameRelation.new(@relation, @relation[:id] => :schmid).attributes.should == + (@relation.attributes - [@relation[:id]]) + [@relation[:id].aliazz(:schmid)] + end + end + + describe '[]' do + it 'indexes attributes by alias' do + @renamed_relation[:id].should be_nil + @renamed_relation[:schmid].should == @relation[:id] + end + end + + describe '#schmattribute' do + it "should be renamed" do + pending + end + end + + describe '#qualify' do + it "manufactures a rename relation with an identical attribute and alias, but with a qualified relation" do + RenameRelation.new(@relation, @relation[:id] => :schmid).qualify. \ + should == RenameRelation.new(@relation.qualify, @relation[:id].qualify => :schmid) + end + end + + describe '#to_sql' do + it 'manufactures sql aliasing the attribute' do + @renamed_relation.to_sql.to_s.should == SelectBuilder.new do + select do + column :foo, :name + column :foo, :id, :schmid + end + from :foo + end.to_s + end + end +end \ No newline at end of file diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb index 1a7f9e6659608..395a3f76931a1 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/relations/selection_relation_spec.rb @@ -26,6 +26,13 @@ end end + describe '#qualify' do + it "manufactures a selection relation with qualified predicates and qualified relation" do + SelectionRelation.new(@relation1, @predicate1).qualify. \ + should == SelectionRelation.new(@relation1.qualify, @predicate1.qualify) + end + end + describe '#to_sql' do it "manufactures sql with where clause conditions" do SelectionRelation.new(@relation1, @predicate1).to_sql.to_s.should == SelectBuilder.new do diff --git a/spec/relations/table_relation_spec.rb b/spec/relations/table_relation_spec.rb index dec8bba6b1c61..038037234415e 100644 --- a/spec/relations/table_relation_spec.rb +++ b/spec/relations/table_relation_spec.rb @@ -1,9 +1,13 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper') describe TableRelation do + before do + @relation = TableRelation.new(:users) + end + describe '#to_sql' do it "returns a simple SELECT query" do - TableRelation.new(:users).to_sql.should == SelectBuilder.new do |s| + @relation.to_sql.should == SelectBuilder.new do |s| select do column :users, :name column :users, :id @@ -18,4 +22,12 @@ pending end end + + describe '#qualify' do + it 'manufactures a rename relation with all attribute names qualified' do + @relation.qualify.should == RenameRelation.new( + RenameRelation.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' + ) + end + end end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c53277b8e31d1..edace54f589b9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,6 +14,14 @@ } ActiveRecord::Base.establish_connection 'sql_algebra_test' +class Hash + def shift + returning to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash }.shift do |key, value| + delete(key) + end + end +end + Spec::Runner.configure do |config| config.include(BeLikeMatcher) end \ No newline at end of file From d1e5265a1db424e7361878772d32ae4ec39babe2 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 5 Jan 2008 15:32:22 -0800 Subject: [PATCH 0015/1492] join relation qualification --- lib/sql_algebra/relations/join_relation.rb | 6 +++++- spec/predicates/binary_predicate_spec.rb | 2 +- spec/relations/join_relation_spec.rb | 9 ++++++++- spec/relations/order_relation_spec.rb | 2 +- spec/relations/projection_relation_spec.rb | 2 +- spec/relations/range_relation_spec.rb | 2 +- spec/relations/rename_relation_spec.rb | 6 +----- spec/relations/selection_relation_spec.rb | 2 +- 8 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb index c65b07225ffa3..6dd63ad117455 100644 --- a/lib/sql_algebra/relations/join_relation.rb +++ b/lib/sql_algebra/relations/join_relation.rb @@ -10,7 +10,12 @@ def ==(other) ((relation1 == other.relation1 and relation2 == other.relation2) or (relation2 == other.relation1 and relation1 == other.relation2)) end + + def qualify + JoinRelation.new(relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + end + protected def joins relation1.joins + relation2.joins + [Join.new(relation1, relation2, predicates, join_type)] end @@ -27,6 +32,5 @@ def attribute(name) relation1[name] || relation2[name] end - protected delegate :table, :to => :relation1 end \ No newline at end of file diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/predicates/binary_predicate_spec.rb index 25cffde2c5dae..ede44e517518a 100644 --- a/spec/predicates/binary_predicate_spec.rb +++ b/spec/predicates/binary_predicate_spec.rb @@ -32,7 +32,7 @@ def predicate_name end describe '#qualify' do - it "manufactures an equality predicate with qualified attributes" do + it "distributes over the predicates and attributes" do ConcreteBinaryPredicate.new(@attribute1, @attribute2).qualify. \ should == ConcreteBinaryPredicate.new(@attribute1.qualify, @attribute2.qualify) end diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb index bae294440e46a..b7357b02e88d9 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/relations/join_relation_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper') -describe 'between two relations' do +describe JoinRelation do before do @relation1 = TableRelation.new(:foo) @relation2 = TableRelation.new(:bar) @@ -18,6 +18,13 @@ end end + describe '#qualify' do + it 'distributes over the relations and predicates' do + JoinRelation.new(@relation1, @relation2, @predicate).qualify. \ + should == JoinRelation.new(@relation1.qualify, @relation2.qualify, @predicate.qualify) + end + end + describe '#to_sql' do before do @relation1 = @relation1.select(@relation1[:id] == @relation2[:foo_id]) diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb index 62275ff0ac4e0..8792683eecb3a 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/relations/order_relation_spec.rb @@ -17,7 +17,7 @@ end describe '#qualify' do - it "manufactures an order relation with qualified attributes and qualified relation" do + it "distributes over the relation and attributes" do OrderRelation.new(@relation1, @attribute1).qualify. \ should == OrderRelation.new(@relation1.qualify, @attribute1.qualify) end diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb index eb74b5cedf0b8..149669c5b2f82 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/relations/projection_relation_spec.rb @@ -17,7 +17,7 @@ end describe '#qualify' do - it "manufactures a projection relation with qualified attributes and qualified relation" do + it "distributes over teh relation and attributes" do ProjectionRelation.new(@relation1, @attribute1).qualify. \ should == ProjectionRelation.new(@relation1.qualify, @attribute1.qualify) end diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb index 261afcaf8ee70..947bf351204f0 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/relations/range_relation_spec.rb @@ -17,7 +17,7 @@ end describe '#qualify' do - it "manufactures a range relation with a qualified relation and a qualified range" do + it "distributes over the relation and attributes" do pending end end diff --git a/spec/relations/rename_relation_spec.rb b/spec/relations/rename_relation_spec.rb index e7792d146af50..7db329ad7ab03 100644 --- a/spec/relations/rename_relation_spec.rb +++ b/spec/relations/rename_relation_spec.rb @@ -12,10 +12,6 @@ should == RenameRelation.new(RenameRelation.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) end - it "make this test less brittle wrt/ hash order" do - pending - end - it "raises an exception if the alias provided is already used" do pending end @@ -48,7 +44,7 @@ end describe '#qualify' do - it "manufactures a rename relation with an identical attribute and alias, but with a qualified relation" do + it "distributes over the relation and renames" do RenameRelation.new(@relation, @relation[:id] => :schmid).qualify. \ should == RenameRelation.new(@relation.qualify, @relation[:id].qualify => :schmid) end diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb index 395a3f76931a1..7ffb3b3676fe9 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/relations/selection_relation_spec.rb @@ -27,7 +27,7 @@ end describe '#qualify' do - it "manufactures a selection relation with qualified predicates and qualified relation" do + it "distributes over the relation and predicates" do SelectionRelation.new(@relation1, @predicate1).qualify. \ should == SelectionRelation.new(@relation1.qualify, @predicate1.qualify) end From 648209d11f16243a9f073b177e6b32ce8c094408 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 5 Jan 2008 15:38:03 -0800 Subject: [PATCH 0016/1492] minor cleanup --- lib/sql_algebra/relations/relation.rb | 1 + spec/integration/scratch_spec.rb | 5 +++-- spec/relations/join_relation_spec.rb | 2 +- spec/relations/order_relation_spec.rb | 2 +- spec/relations/projection_relation_spec.rb | 2 +- spec/relations/range_relation_spec.rb | 2 +- spec/relations/rename_relation_spec.rb | 2 +- spec/relations/selection_relation_spec.rb | 2 +- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb index 82266fd7e8bf1..13742cb5703fc 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/sql_algebra/relations/relation.rb @@ -59,6 +59,7 @@ def to_sql(builder = SelectBuilder.new) end end end + delegate :to_s, :to => :to_sql protected def attributes; [] end diff --git a/spec/integration/scratch_spec.rb b/spec/integration/scratch_spec.rb index b19f1a52341b6..725ac755c0736 100644 --- a/spec/integration/scratch_spec.rb +++ b/spec/integration/scratch_spec.rb @@ -11,7 +11,7 @@ end it 'simulates User.has_many :photos' do - @user_photos.project(*@photos.attributes).to_sql.to_s.should be_like(""" + @user_photos.project(*@photos.attributes).to_s.should be_like(""" SELECT photos.id, photos.user_id, photos.camera_id FROM users LEFT OUTER JOIN photos @@ -22,7 +22,7 @@ end it 'simulates a User.has_many :cameras :through => :photos' do - @user_cameras.project(*@cameras.attributes).to_sql.to_s.should be_like(""" + @user_cameras.project(*@cameras.attributes).to_s.should be_like(""" SELECT cameras.id FROM users LEFT OUTER JOIN photos @@ -35,6 +35,7 @@ end it '' do + # @user_cameras.qualify.to_s # # @users.rename() end diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb index b7357b02e88d9..b70bf553b16ec 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/relations/join_relation_spec.rb @@ -36,7 +36,7 @@ def join_type end it 'manufactures sql joining the two tables on the predicate, merging the selects' do - ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_sql.to_s.should == SelectBuilder.new do + ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_s.should == SelectBuilder.new do select do column :foo, :name column :foo, :id diff --git a/spec/relations/order_relation_spec.rb b/spec/relations/order_relation_spec.rb index 8792683eecb3a..a78ac148e2f8c 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/relations/order_relation_spec.rb @@ -25,7 +25,7 @@ describe '#to_sql' do it "manufactures sql with an order clause" do - OrderRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do + OrderRelation.new(@relation1, @attribute1).to_s.should == SelectBuilder.new do select do column :foo, :name column :foo, :id diff --git a/spec/relations/projection_relation_spec.rb b/spec/relations/projection_relation_spec.rb index 149669c5b2f82..5a33b16bd555d 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/relations/projection_relation_spec.rb @@ -25,7 +25,7 @@ describe '#to_sql' do it "manufactures sql with a limited select clause" do - ProjectionRelation.new(@relation1, @attribute1).to_sql.to_s.should == SelectBuilder.new do + ProjectionRelation.new(@relation1, @attribute1).to_s.should == SelectBuilder.new do select do column :foo, :id end diff --git a/spec/relations/range_relation_spec.rb b/spec/relations/range_relation_spec.rb index 947bf351204f0..926cc0929f3ef 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/relations/range_relation_spec.rb @@ -26,7 +26,7 @@ it "manufactures sql with limit and offset" do range_size = @range2.last - @range2.first + 1 range_start = @range2.first - RangeRelation.new(@relation1, @range2).to_sql.to_s.should == SelectBuilder.new do + RangeRelation.new(@relation1, @range2).to_s.should == SelectBuilder.new do select do column :foo, :name column :foo, :id diff --git a/spec/relations/rename_relation_spec.rb b/spec/relations/rename_relation_spec.rb index 7db329ad7ab03..301ee6db9eae2 100644 --- a/spec/relations/rename_relation_spec.rb +++ b/spec/relations/rename_relation_spec.rb @@ -52,7 +52,7 @@ describe '#to_sql' do it 'manufactures sql aliasing the attribute' do - @renamed_relation.to_sql.to_s.should == SelectBuilder.new do + @renamed_relation.to_s.should == SelectBuilder.new do select do column :foo, :name column :foo, :id, :schmid diff --git a/spec/relations/selection_relation_spec.rb b/spec/relations/selection_relation_spec.rb index 7ffb3b3676fe9..656a386fd68bb 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/relations/selection_relation_spec.rb @@ -35,7 +35,7 @@ describe '#to_sql' do it "manufactures sql with where clause conditions" do - SelectionRelation.new(@relation1, @predicate1).to_sql.to_s.should == SelectBuilder.new do + SelectionRelation.new(@relation1, @predicate1).to_s.should == SelectBuilder.new do select do column :foo, :name column :foo, :id From b8a4dabab94bfaa73ec031337ce9ef9abd798383 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 5 Jan 2008 16:04:41 -0800 Subject: [PATCH 0017/1492] quoting --- lib/sql_algebra/extensions/object.rb | 2 +- .../relations/inner_join_relation.rb | 1 + lib/sql_algebra/relations/join_relation.rb | 2 +- .../relations/left_outer_join_relation.rb | 1 + .../sql_builder/equals_condition_builder.rb | 2 +- lib/sql_algebra/sql_builder/join_builder.rb | 2 +- lib/sql_algebra/sql_builder/order_builder.rb | 2 +- lib/sql_algebra/sql_builder/select_builder.rb | 2 +- .../sql_builder/selects_builder.rb | 2 +- lib/sql_algebra/sql_builder/sql_builder.rb | 7 +++++ spec/integration/scratch_spec.rb | 26 ++++++++-------- spec/relations/join_relation_spec.rb | 11 ++----- spec/sql_builder/conditions_spec.rb | 4 +-- spec/sql_builder/select_builder_spec.rb | 30 +++++++++---------- 14 files changed, 49 insertions(+), 45 deletions(-) diff --git a/lib/sql_algebra/extensions/object.rb b/lib/sql_algebra/extensions/object.rb index 6ea66d74840c9..c241581f861df 100644 --- a/lib/sql_algebra/extensions/object.rb +++ b/lib/sql_algebra/extensions/object.rb @@ -6,7 +6,7 @@ def qualify def to_sql(builder = EqualsConditionBuilder.new) me = self builder.call do - value me + value me.to_s end end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/inner_join_relation.rb b/lib/sql_algebra/relations/inner_join_relation.rb index 6b932e3b21a76..5e58f241f8f92 100644 --- a/lib/sql_algebra/relations/inner_join_relation.rb +++ b/lib/sql_algebra/relations/inner_join_relation.rb @@ -1,4 +1,5 @@ class InnerJoinRelation < JoinRelation + protected def join_type :inner_join end diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/sql_algebra/relations/join_relation.rb index 6dd63ad117455..79c8a915b89ec 100644 --- a/lib/sql_algebra/relations/join_relation.rb +++ b/lib/sql_algebra/relations/join_relation.rb @@ -12,7 +12,7 @@ def ==(other) end def qualify - JoinRelation.new(relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + self.class.new(relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) end protected diff --git a/lib/sql_algebra/relations/left_outer_join_relation.rb b/lib/sql_algebra/relations/left_outer_join_relation.rb index f4ece438617a2..6d13d8da07d8a 100644 --- a/lib/sql_algebra/relations/left_outer_join_relation.rb +++ b/lib/sql_algebra/relations/left_outer_join_relation.rb @@ -1,4 +1,5 @@ class LeftOuterJoinRelation < JoinRelation + protected def join_type :left_outer_join end diff --git a/lib/sql_algebra/sql_builder/equals_condition_builder.rb b/lib/sql_algebra/sql_builder/equals_condition_builder.rb index 016395556aed9..70067c20ca8b4 100644 --- a/lib/sql_algebra/sql_builder/equals_condition_builder.rb +++ b/lib/sql_algebra/sql_builder/equals_condition_builder.rb @@ -5,7 +5,7 @@ def initialize(&block) end def column(table, column, aliaz = nil) - @operands << (aliaz ? aliaz : "#{table}.#{column}") + @operands << (aliaz ? quote(aliaz) : "#{quote_table_name(table)}.#{quote_column_name(column)}") end def value(value) diff --git a/lib/sql_algebra/sql_builder/join_builder.rb b/lib/sql_algebra/sql_builder/join_builder.rb index 28f4437decd4b..ef63d1fcb16e2 100644 --- a/lib/sql_algebra/sql_builder/join_builder.rb +++ b/lib/sql_algebra/sql_builder/join_builder.rb @@ -8,6 +8,6 @@ def initialize(table, &block) delegate :call, :to => :@conditions def to_s - "#{join_type} #{@table} ON #{@conditions}" + "#{join_type} #{quote_table_name(@table)} ON #{@conditions}" end end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/order_builder.rb b/lib/sql_algebra/sql_builder/order_builder.rb index 4eea40fa3668d..43f705faf006f 100644 --- a/lib/sql_algebra/sql_builder/order_builder.rb +++ b/lib/sql_algebra/sql_builder/order_builder.rb @@ -5,7 +5,7 @@ def initialize(&block) end def column(table, column, aliaz = nil) - @orders << (aliaz ? aliaz : "#{table}.#{column}") + @orders << (aliaz ? quote(aliaz) : "#{quote_table_name(table)}.#{quote_column_name(column)}") end def to_s diff --git a/lib/sql_algebra/sql_builder/select_builder.rb b/lib/sql_algebra/sql_builder/select_builder.rb index 68df68db93fbd..9a85ad7eec705 100644 --- a/lib/sql_algebra/sql_builder/select_builder.rb +++ b/lib/sql_algebra/sql_builder/select_builder.rb @@ -41,7 +41,7 @@ def select_clause end def from_clause - "FROM #{@table} #{@joins}" unless @table.blank? + "FROM #{quote_table_name(@table)} #{@joins}" unless @table.blank? end def where_clause diff --git a/lib/sql_algebra/sql_builder/selects_builder.rb b/lib/sql_algebra/sql_builder/selects_builder.rb index 72f6f52397058..ce6ee1eb678bb 100644 --- a/lib/sql_algebra/sql_builder/selects_builder.rb +++ b/lib/sql_algebra/sql_builder/selects_builder.rb @@ -13,7 +13,7 @@ def all end def column(table, column, aliaz = nil) - @selects << "#{table}.#{column}" + (aliaz ? " AS #{aliaz}" : '') + @selects << "#{quote_table_name(table)}.#{quote_column_name(column)}" + (aliaz ? " AS #{quote(aliaz)}" : '') end delegate :blank?, :to => :@selects diff --git a/lib/sql_algebra/sql_builder/sql_builder.rb b/lib/sql_algebra/sql_builder/sql_builder.rb index 5cfbe578d5e7d..c984444e41bd1 100644 --- a/lib/sql_algebra/sql_builder/sql_builder.rb +++ b/lib/sql_algebra/sql_builder/sql_builder.rb @@ -25,4 +25,11 @@ def call(&block) end end end + + private + delegate :quote_table_name, :quote_column_name, :quote, :to => :connection + + def connection + ActiveRecord::Base.connection + end end \ No newline at end of file diff --git a/spec/integration/scratch_spec.rb b/spec/integration/scratch_spec.rb index 725ac755c0736..32ee98d361938 100644 --- a/spec/integration/scratch_spec.rb +++ b/spec/integration/scratch_spec.rb @@ -12,30 +12,30 @@ it 'simulates User.has_many :photos' do @user_photos.project(*@photos.attributes).to_s.should be_like(""" - SELECT photos.id, photos.user_id, photos.camera_id - FROM users - LEFT OUTER JOIN photos - ON users.id = photos.user_id + SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + LEFT OUTER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` WHERE - users.id = 1 + `users`.`id` = 1 """) end it 'simulates a User.has_many :cameras :through => :photos' do @user_cameras.project(*@cameras.attributes).to_s.should be_like(""" - SELECT cameras.id - FROM users - LEFT OUTER JOIN photos - ON users.id = photos.user_id - LEFT OUTER JOIN cameras - ON photos.camera_id = cameras.id + SELECT `cameras`.`id` + FROM `users` + LEFT OUTER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + LEFT OUTER JOIN `cameras` + ON `photos`.`camera_id` = `cameras`.`id` WHERE - users.id = 1 + `users`.`id` = 1 """) end it '' do - # @user_cameras.qualify.to_s + # p @user_cameras.qualify.to_s # # @users.rename() end diff --git a/spec/relations/join_relation_spec.rb b/spec/relations/join_relation_spec.rb index b70bf553b16ec..ece7e61cc166c 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/relations/join_relation_spec.rb @@ -20,23 +20,18 @@ describe '#qualify' do it 'distributes over the relations and predicates' do - JoinRelation.new(@relation1, @relation2, @predicate).qualify. \ - should == JoinRelation.new(@relation1.qualify, @relation2.qualify, @predicate.qualify) + InnerJoinRelation.new(@relation1, @relation2, @predicate).qualify. \ + should == InnerJoinRelation.new(@relation1.qualify, @relation2.qualify, @predicate.qualify) end end describe '#to_sql' do before do @relation1 = @relation1.select(@relation1[:id] == @relation2[:foo_id]) - class ConcreteJoinRelation < JoinRelation - def join_type - :inner_join - end - end end it 'manufactures sql joining the two tables on the predicate, merging the selects' do - ConcreteJoinRelation.new(@relation1, @relation2, @predicate).to_s.should == SelectBuilder.new do + InnerJoinRelation.new(@relation1, @relation2, @predicate).to_s.should == SelectBuilder.new do select do column :foo, :name column :foo, :id diff --git a/spec/sql_builder/conditions_spec.rb b/spec/sql_builder/conditions_spec.rb index 78590e2631d73..c1cae902c1a1d 100644 --- a/spec/sql_builder/conditions_spec.rb +++ b/spec/sql_builder/conditions_spec.rb @@ -7,10 +7,10 @@ ConditionsBuilder.new do equals do column(:a, :b) - column(:c, :d, :e) + column(:c, :d, 'e') end end.to_s.should be_like(""" - a.b = e + `a`.`b` = 'e' """) end end diff --git a/spec/sql_builder/select_builder_spec.rb b/spec/sql_builder/select_builder_spec.rb index 7b059bd6bd7d8..060c642c1b2dc 100644 --- a/spec/sql_builder/select_builder_spec.rb +++ b/spec/sql_builder/select_builder_spec.rb @@ -11,7 +11,7 @@ from :users end.to_s.should be_like(""" SELECT * - FROM users + FROM `users` """) end end @@ -20,13 +20,13 @@ it 'manufactures correct sql' do SelectBuilder.new do select do - column(:a, :b, :c) - column(:e, :f) + column :a, :b, 'c' + column :e, :f end from :users end.to_s.should be_like(""" - SELECT a.b AS c, e.f - FROM users + SELECT `a`.`b` AS 'c', `e`.`f` + FROM `users` """) end end @@ -40,14 +40,14 @@ from :users where do equals do - value :a + value 1 column :b, :c end end end.to_s.should be_like(""" SELECT * - FROM users - WHERE a = b.c + FROM `users` + WHERE 1 = `b`.`c` """) end end @@ -61,14 +61,14 @@ from :users do inner_join(:friendships) do equals do - value :id - value :user_id + column :users, :id + column :friendships, :user_id end end end end.to_s.should be_like(""" SELECT * - FROM users INNER JOIN friendships ON id = user_id + FROM `users` INNER JOIN `friendships` ON `users`.`id` = `friendships`.`user_id` """) end end @@ -82,12 +82,12 @@ from :users order_by do column :users, :id - column :users, :created_at, :alias + column :users, :created_at, 'alias' end end.to_s.should be_like(""" SELECT * - FROM users - ORDER BY users.id, alias + FROM `users` + ORDER BY `users`.`id`, 'alias' """) end end @@ -103,7 +103,7 @@ offset 10 end.to_s.should be_like(""" SELECT * - FROM users + FROM `users` LIMIT 10 OFFSET 10 """) From d43a4e9fc1316fc9eb8ff087c52c7ca7a475c041 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 6 Jan 2008 00:32:17 -0800 Subject: [PATCH 0018/1492] integration spec is persuasive, hopefully --- lib/sql_algebra.rb | 2 + lib/sql_algebra/extensions/base.rb | 54 +- lib/sql_algebra/extensions/hash.rb | 7 + lib/sql_algebra/relations/relation.rb | 15 +- .../sql_builder/equals_condition_builder.rb | 2 +- lib/sql_algebra/sql_builder/order_builder.rb | 2 +- spec/integration/debug.log | 1581 ----------------- spec/integration/scratch_spec.rb | 246 ++- spec/spec_helper.rb | 2 + spec/sql_builder/conditions_spec.rb | 2 +- spec/sql_builder/select_builder_spec.rb | 2 +- 11 files changed, 287 insertions(+), 1628 deletions(-) create mode 100644 lib/sql_algebra/extensions/hash.rb diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb index 475bb231383ec..fbd053541cae7 100644 --- a/lib/sql_algebra.rb +++ b/lib/sql_algebra.rb @@ -34,6 +34,8 @@ require 'sql_algebra/extensions/range' require 'sql_algebra/extensions/object' require 'sql_algebra/extensions/array' +require 'sql_algebra/extensions/base' +require 'sql_algebra/extensions/hash' require 'sql_algebra/sql_builder/sql_builder' require 'sql_algebra/sql_builder/select_builder' diff --git a/lib/sql_algebra/extensions/base.rb b/lib/sql_algebra/extensions/base.rb index 0143caf23d9c1..0dbdef703ff7a 100644 --- a/lib/sql_algebra/extensions/base.rb +++ b/lib/sql_algebra/extensions/base.rb @@ -1,15 +1,47 @@ class ActiveRecord::Base - def self.bring_forth(record, includes = []) - object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) } - includes.each do |include| - case include - when Symbol - object.send(association = include).bring_forth(record) - when Hash - include.each do |association, nested_associations| - object.send(association).bring_forth(record, nested_associations) - end - end + class << self + def cache + @identity_map ||= IdentityMap.new end + + def relation + @relation ||= TableRelation.new(table_name) + end + end + + class IdentityMap + def initialize + @map = {} + end + + def get(record, &block) + @map[record] ||= yield + end + end +end + +class ActiveRecord::Associations::BelongsToAssociation + def instantiate(record, joins = []) + @target = proxy_reflection.klass.instantiate(record, joins) + loaded + end + + # this basically disables belongs_to from loading themselves + def reload + @target = 'hack' + end +end + +class ActiveRecord::Associations::AssociationCollection + def instantiate(record, joins = []) + @target << proxy_reflection.klass.instantiate(record, joins) + loaded # technically, this isn't true. doesn't matter though + end +end + +class ActiveRecord::Associations::HasManyThroughAssociation + def instantiate(record, joins = []) + @target << proxy_reflection.klass.instantiate(record, joins) + loaded # again, not really true. end end \ No newline at end of file diff --git a/lib/sql_algebra/extensions/hash.rb b/lib/sql_algebra/extensions/hash.rb new file mode 100644 index 0000000000000..c83ee0d04f26f --- /dev/null +++ b/lib/sql_algebra/extensions/hash.rb @@ -0,0 +1,7 @@ +class Hash + def alias(&block) + inject({}) do |aliased, (key, value)| + aliased.merge(yield(key) => value) + end + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/relation.rb b/lib/sql_algebra/relations/relation.rb index 13742cb5703fc..8efe0c7d9f5be 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/sql_algebra/relations/relation.rb @@ -1,4 +1,17 @@ class Relation + module Iteration + include Enumerable + + def each(&block) + connection.select_all(to_s).each(&block) + end + + def first + connection.select_one(to_s) + end + end + include Iteration + module Operations def <=>(other) InnerJoinOperation.new(self, other) @@ -60,7 +73,7 @@ def to_sql(builder = SelectBuilder.new) end end delegate :to_s, :to => :to_sql - + protected def attributes; [] end def joins; [] end diff --git a/lib/sql_algebra/sql_builder/equals_condition_builder.rb b/lib/sql_algebra/sql_builder/equals_condition_builder.rb index 70067c20ca8b4..cfa919c34c9f8 100644 --- a/lib/sql_algebra/sql_builder/equals_condition_builder.rb +++ b/lib/sql_algebra/sql_builder/equals_condition_builder.rb @@ -5,7 +5,7 @@ def initialize(&block) end def column(table, column, aliaz = nil) - @operands << (aliaz ? quote(aliaz) : "#{quote_table_name(table)}.#{quote_column_name(column)}") + @operands << "#{quote_table_name(table)}.#{quote_column_name(column)}" end def value(value) diff --git a/lib/sql_algebra/sql_builder/order_builder.rb b/lib/sql_algebra/sql_builder/order_builder.rb index 43f705faf006f..66a8cfdba95ab 100644 --- a/lib/sql_algebra/sql_builder/order_builder.rb +++ b/lib/sql_algebra/sql_builder/order_builder.rb @@ -5,7 +5,7 @@ def initialize(&block) end def column(table, column, aliaz = nil) - @orders << (aliaz ? quote(aliaz) : "#{quote_table_name(table)}.#{quote_column_name(column)}") + @orders << "#{quote_table_name(table)}.#{quote_column_name(column)}" end def to_s diff --git a/spec/integration/debug.log b/spec/integration/debug.log index 9b5b08cc20be7..e69de29bb2d1d 100644 --- a/spec/integration/debug.log +++ b/spec/integration/debug.log @@ -1,1581 +0,0 @@ -# Logfile created on Tue Jan 01 18:37:24 -0800 2008 by logger.rb/1.5.2.9 - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010719) SHOW FIELDS FROM `users` - SQL (0.002219) SHOW FIELDS FROM `photos` - SQL (0.001538) SHOW FIELDS FROM `users` - SQL (0.002551) SHOW FIELDS FROM `photos` - SQL (0.001835) SHOW FIELDS FROM `cameras` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010748) SHOW FIELDS FROM `users` - SQL (0.002223) SHOW FIELDS FROM `photos` - SQL (0.002938) SHOW FIELDS FROM `users` - SQL (0.002466) SHOW FIELDS FROM `photos` - SQL (0.001493) SHOW FIELDS FROM `cameras` - SQL (0.000116) SET SQL_AUTO_IS_NULL=0 - SQL (0.010722) SHOW FIELDS FROM `users` - SQL (0.002196) SHOW FIELDS FROM `photos` - SQL (0.001528) SHOW FIELDS FROM `users` - SQL (0.001373) SHOW FIELDS FROM `photos` - SQL (0.001372) SHOW FIELDS FROM `cameras` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.001599) SHOW FIELDS FROM `users` - SQL (0.012868) SHOW FIELDS FROM `photos` - SQL (0.001681) SHOW FIELDS FROM `users` - SQL (0.002253) SHOW FIELDS FROM `photos` - SQL (0.002186) SHOW FIELDS FROM `cameras` - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010737) SHOW FIELDS FROM `users` - SQL (0.002277) SHOW FIELDS FROM `photos` - SQL (0.001517) SHOW FIELDS FROM `users` - SQL (0.001368) SHOW FIELDS FROM `photos` - SQL (0.001481) SHOW FIELDS FROM `cameras` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010719) SHOW FIELDS FROM `users` - SQL (0.002651) SHOW FIELDS FROM `photos` - SQL (0.001464) SHOW FIELDS FROM `users` - SQL (0.001504) SHOW FIELDS FROM `photos` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010820) SHOW FIELDS FROM `users` - SQL (0.002194) SHOW FIELDS FROM `photos` - SQL (0.001565) SHOW FIELDS FROM `users` - SQL (0.001282) SHOW FIELDS FROM `photos` - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010719) SHOW FIELDS FROM `users` - SQL (0.002103) SHOW FIELDS FROM `photos` - SQL (0.001468) SHOW FIELDS FROM `users` - SQL (0.001526) SHOW FIELDS FROM `photos` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010648) SHOW FIELDS FROM `users` - SQL (0.002458) SHOW FIELDS FROM `photos` - SQL (0.001525) SHOW FIELDS FROM `users` - SQL (0.001571) SHOW FIELDS FROM `photos` - SQL (0.001274) SHOW FIELDS FROM `users` - SQL (0.001527) SHOW FIELDS FROM `photos` - SQL (0.000130) SET SQL_AUTO_IS_NULL=0 - SQL (0.010705) SHOW FIELDS FROM `users` - SQL (0.002444) SHOW FIELDS FROM `photos` - SQL (0.001608) SHOW FIELDS FROM `users` - SQL (0.001488) SHOW FIELDS FROM `photos` - SQL (0.001462) SHOW FIELDS FROM `users` - SQL (0.001492) SHOW FIELDS FROM `photos` - SQL (0.015956) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.001676) SHOW TABLES - User Columns (0.001593) SHOW FIELDS FROM `users` - SQL (0.000144) SET SQL_AUTO_IS_NULL=0 - SQL (0.010771) SHOW FIELDS FROM `users` - SQL (0.002480) SHOW FIELDS FROM `photos` - SQL (0.001474) SHOW FIELDS FROM `users` - SQL (0.001357) SHOW FIELDS FROM `photos` - SQL (0.011769) SHOW FIELDS FROM `users` - SQL (0.001586) SHOW FIELDS FROM `photos` - SQL (0.000232) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000120) SET SQL_AUTO_IS_NULL=0 - SQL (0.010804) SHOW FIELDS FROM `users` - SQL (0.002188) SHOW FIELDS FROM `photos` - SQL (0.001478) SHOW FIELDS FROM `users` - SQL (0.001550) SHOW FIELDS FROM `photos` - SQL (0.001413) SHOW FIELDS FROM `users` - SQL (0.001515) SHOW FIELDS FROM `photos` - SQL (0.000251) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010826) SHOW FIELDS FROM `users` - SQL (0.002353) SHOW FIELDS FROM `photos` - SQL (0.001500) SHOW FIELDS FROM `users` - SQL (0.001522) SHOW FIELDS FROM `photos` - SQL (0.001438) SHOW FIELDS FROM `users` - SQL (0.001436) SHOW FIELDS FROM `photos` - SQL (0.000266) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001396) SHOW FIELDS FROM `users` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010772) SHOW FIELDS FROM `users` - SQL (0.002268) SHOW FIELDS FROM `photos` - SQL (0.001566) SHOW FIELDS FROM `users` - SQL (0.001390) SHOW FIELDS FROM `photos` - SQL (0.001466) SHOW FIELDS FROM `users` - SQL (0.001600) SHOW FIELDS FROM `photos` - SQL (0.000247) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010742) SHOW FIELDS FROM `users` - SQL (0.002382) SHOW FIELDS FROM `photos` - SQL (0.001490) SHOW FIELDS FROM `users` - SQL (0.001505) SHOW FIELDS FROM `photos` - SQL (0.001846) SHOW FIELDS FROM `users` - SQL (0.001491) SHOW FIELDS FROM `photos` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010798) SHOW FIELDS FROM `users` - SQL (0.002447) SHOW FIELDS FROM `photos` - SQL (0.001557) SHOW FIELDS FROM `users` - SQL (0.001387) SHOW FIELDS FROM `photos` - SQL (0.001469) SHOW FIELDS FROM `users` - SQL (0.001394) SHOW FIELDS FROM `photos` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010727) SHOW FIELDS FROM `users` - SQL (0.002213) SHOW FIELDS FROM `photos` - SQL (0.001491) SHOW FIELDS FROM `users` - SQL (0.001407) SHOW FIELDS FROM `photos` - SQL (0.001457) SHOW FIELDS FROM `users` - SQL (0.001529) SHOW FIELDS FROM `photos` - SQL (0.000247) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000320) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000135) SET SQL_AUTO_IS_NULL=0 - SQL (0.010663) SHOW FIELDS FROM `users` - SQL (0.002319) SHOW FIELDS FROM `photos` - SQL (0.001467) SHOW FIELDS FROM `users` - SQL (0.001319) SHOW FIELDS FROM `photos` - SQL (0.010583) SHOW FIELDS FROM `users` - SQL (0.001805) SHOW FIELDS FROM `photos` - SQL (0.000290) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000271) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010733) SHOW FIELDS FROM `users` - SQL (0.002277) SHOW FIELDS FROM `photos` - SQL (0.001500) SHOW FIELDS FROM `users` - SQL (0.001387) SHOW FIELDS FROM `photos` - SQL (0.001421) SHOW FIELDS FROM `users` - SQL (0.001726) SHOW FIELDS FROM `photos` - SQL (0.000261) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000261) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001432) SHOW FIELDS FROM `photos` - SQL (0.000134) SET SQL_AUTO_IS_NULL=0 - SQL (0.010759) SHOW FIELDS FROM `users` - SQL (0.002287) SHOW FIELDS FROM `photos` - SQL (0.001424) SHOW FIELDS FROM `users` - SQL (0.001550) SHOW FIELDS FROM `photos` - SQL (0.001342) SHOW FIELDS FROM `cameras` - SQL (0.001545) SHOW FIELDS FROM `users` - SQL (0.001488) SHOW FIELDS FROM `photos` - SQL (0.000249) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000290) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000139) SET SQL_AUTO_IS_NULL=0 - SQL (0.010766) SHOW FIELDS FROM `users` - SQL (0.002183) SHOW FIELDS FROM `photos` - SQL (0.001465) SHOW FIELDS FROM `users` - SQL (0.001492) SHOW FIELDS FROM `photos` - SQL (0.012690) SHOW FIELDS FROM `cameras` - SQL (0.001591) SHOW FIELDS FROM `users` - SQL (0.001740) SHOW FIELDS FROM `photos` - SQL (0.000261) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000262) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000110) SET SQL_AUTO_IS_NULL=0 - SQL (0.010751) SHOW FIELDS FROM `users` - SQL (0.002343) SHOW FIELDS FROM `photos` - SQL (0.001476) SHOW FIELDS FROM `users` - SQL (0.001513) SHOW FIELDS FROM `photos` - SQL (0.001495) SHOW FIELDS FROM `cameras` - SQL (0.001569) SHOW FIELDS FROM `users` - SQL (0.001497) SHOW FIELDS FROM `photos` - SQL (0.000249) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.028671) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010774) SHOW FIELDS FROM `users` - SQL (0.002229) SHOW FIELDS FROM `photos` - SQL (0.001532) SHOW FIELDS FROM `users` - SQL (0.001526) SHOW FIELDS FROM `photos` - SQL (0.001463) SHOW FIELDS FROM `cameras` - SQL (0.001558) SHOW FIELDS FROM `users` - SQL (0.001479) SHOW FIELDS FROM `photos` - SQL (0.000253) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000248) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000141) SET SQL_AUTO_IS_NULL=0 - SQL (0.010731) SHOW FIELDS FROM `users` - SQL (0.002167) SHOW FIELDS FROM `photos` - SQL (0.001370) SHOW FIELDS FROM `users` - SQL (0.001523) SHOW FIELDS FROM `photos` - SQL (0.001275) SHOW FIELDS FROM `cameras` - SQL (0.001480) SHOW FIELDS FROM `users` - SQL (0.001193) SHOW FIELDS FROM `photos` - SQL (0.000228) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000228) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.011242) SHOW FIELDS FROM `users` - SQL (0.001695) SHOW FIELDS FROM `photos` - SQL (0.001744) SHOW FIELDS FROM `users` - SQL (0.001452) SHOW FIELDS FROM `photos` - SQL (0.001419) SHOW FIELDS FROM `cameras` - SQL (0.001378) SHOW FIELDS FROM `users` - SQL (0.002561) SHOW FIELDS FROM `photos` - SQL (0.000923) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000275) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000157) SET SQL_AUTO_IS_NULL=0 - SQL (0.010515) SHOW FIELDS FROM `users` - SQL (0.002311) SHOW FIELDS FROM `photos` - SQL (0.002045) SHOW FIELDS FROM `users` - SQL (0.001878) SHOW FIELDS FROM `photos` - SQL (0.001586) SHOW FIELDS FROM `cameras` - SQL (0.001397) SHOW FIELDS FROM `users` - SQL (0.001944) SHOW FIELDS FROM `photos` - SQL (0.000453) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000283) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010759) SHOW FIELDS FROM `users` - SQL (0.002066) SHOW FIELDS FROM `photos` - SQL (0.001582) SHOW FIELDS FROM `users` - SQL (0.001459) SHOW FIELDS FROM `photos` - SQL (0.001418) SHOW FIELDS FROM `cameras` - SQL (0.001367) SHOW FIELDS FROM `users` - SQL (0.001849) SHOW FIELDS FROM `photos` - SQL (0.001231) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000357) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010706) SHOW FIELDS FROM `users` - SQL (0.002375) SHOW FIELDS FROM `photos` - SQL (0.001616) SHOW FIELDS FROM `users` - SQL (0.001826) SHOW FIELDS FROM `photos` - SQL (0.001508) SHOW FIELDS FROM `cameras` - SQL (0.001638) SHOW FIELDS FROM `users` - SQL (0.001719) SHOW FIELDS FROM `photos` - SQL (0.001674) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000337) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000114) SET SQL_AUTO_IS_NULL=0 - SQL (0.010717) SHOW FIELDS FROM `users` - SQL (0.002698) SHOW FIELDS FROM `photos` - SQL (0.001432) SHOW FIELDS FROM `users` - SQL (0.001686) SHOW FIELDS FROM `photos` - SQL (0.001403) SHOW FIELDS FROM `cameras` - SQL (0.001809) SHOW FIELDS FROM `users` - SQL (0.001590) SHOW FIELDS FROM `photos` - SQL (0.000540) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000341) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010746) SHOW FIELDS FROM `users` - SQL (0.002455) SHOW FIELDS FROM `photos` - SQL (0.001483) SHOW FIELDS FROM `users` - SQL (0.001588) SHOW FIELDS FROM `photos` - SQL (0.001513) SHOW FIELDS FROM `cameras` - SQL (0.001247) SHOW FIELDS FROM `users` - SQL (0.001527) SHOW FIELDS FROM `photos` - SQL (0.000227) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000252) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000142) SET SQL_AUTO_IS_NULL=0 - SQL (0.010735) SHOW FIELDS FROM `users` - SQL (0.002400) SHOW FIELDS FROM `photos` - SQL (0.001299) SHOW FIELDS FROM `users` - SQL (0.001451) SHOW FIELDS FROM `photos` - SQL (0.001173) SHOW FIELDS FROM `cameras` - SQL (0.001530) SHOW FIELDS FROM `users` - SQL (0.001793) SHOW FIELDS FROM `photos` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010758) SHOW FIELDS FROM `users` - SQL (0.002271) SHOW FIELDS FROM `photos` - SQL (0.001485) SHOW FIELDS FROM `users` - SQL (0.001578) SHOW FIELDS FROM `photos` - SQL (0.001492) SHOW FIELDS FROM `cameras` - SQL (0.001389) SHOW FIELDS FROM `users` - SQL (0.001391) SHOW FIELDS FROM `photos` - SQL (0.000249) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000170) SET SQL_AUTO_IS_NULL=0 - SQL (0.010733) SHOW FIELDS FROM `users` - SQL (0.002313) SHOW FIELDS FROM `photos` - SQL (0.001469) SHOW FIELDS FROM `users` - SQL (0.001593) SHOW FIELDS FROM `photos` - SQL (0.001511) SHOW FIELDS FROM `cameras` - SQL (0.001484) SHOW FIELDS FROM `users` - SQL (0.001478) SHOW FIELDS FROM `photos` - SQL (0.000232) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010796) SHOW FIELDS FROM `users` - SQL (0.001970) SHOW FIELDS FROM `photos` - SQL (0.001558) SHOW FIELDS FROM `users` - SQL (0.001440) SHOW FIELDS FROM `photos` - SQL (0.001354) SHOW FIELDS FROM `cameras` - SQL (0.001544) SHOW FIELDS FROM `users` - SQL (0.001405) SHOW FIELDS FROM `photos` - SQL (0.000239) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000111) SET SQL_AUTO_IS_NULL=0 - SQL (0.010751) SHOW FIELDS FROM `users` - SQL (0.002354) SHOW FIELDS FROM `photos` - SQL (0.001463) SHOW FIELDS FROM `users` - SQL (0.001588) SHOW FIELDS FROM `photos` - SQL (0.001505) SHOW FIELDS FROM `cameras` - SQL (0.001464) SHOW FIELDS FROM `users` - SQL (0.001509) SHOW FIELDS FROM `photos` - SQL (0.000235) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000133) SET SQL_AUTO_IS_NULL=0 - SQL (0.010651) SHOW FIELDS FROM `users` - SQL (0.002468) SHOW FIELDS FROM `photos` - SQL (0.001364) SHOW FIELDS FROM `users` - SQL (0.001503) SHOW FIELDS FROM `photos` - SQL (0.001543) SHOW FIELDS FROM `cameras` - SQL (0.001452) SHOW FIELDS FROM `users` - SQL (0.001445) SHOW FIELDS FROM `photos` - SQL (0.000228) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.330787) SHOW FIELDS FROM `users` - SQL (0.002584) SHOW FIELDS FROM `photos` - SQL (0.001456) SHOW FIELDS FROM `users` - SQL (0.001621) SHOW FIELDS FROM `photos` - SQL (0.001475) SHOW FIELDS FROM `cameras` - SQL (0.001481) SHOW FIELDS FROM `users` - SQL (0.001552) SHOW FIELDS FROM `photos` - SQL (0.000226) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000144) SET SQL_AUTO_IS_NULL=0 - SQL (0.010706) SHOW FIELDS FROM `users` - SQL (0.002394) SHOW FIELDS FROM `photos` - SQL (0.001322) SHOW FIELDS FROM `users` - SQL (0.001656) SHOW FIELDS FROM `photos` - SQL (0.001495) SHOW FIELDS FROM `cameras` - SQL (0.001498) SHOW FIELDS FROM `users` - SQL (0.001510) SHOW FIELDS FROM `photos` - SQL (0.000222) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010785) SHOW FIELDS FROM `users` - SQL (0.002249) SHOW FIELDS FROM `photos` - SQL (0.001469) SHOW FIELDS FROM `users` - SQL (0.001410) SHOW FIELDS FROM `photos` - SQL (0.001666) SHOW FIELDS FROM `cameras` - SQL (0.001627) SHOW FIELDS FROM `users` - SQL (0.002215) SHOW FIELDS FROM `photos` - SQL (0.000942) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000149) SET SQL_AUTO_IS_NULL=0 - SQL (0.010774) SHOW FIELDS FROM `users` - SQL (0.001649) SHOW FIELDS FROM `photos` - SQL (0.001497) SHOW FIELDS FROM `users` - SQL (0.001457) SHOW FIELDS FROM `photos` - SQL (0.001345) SHOW FIELDS FROM `cameras` - SQL (0.001298) SHOW FIELDS FROM `users` - SQL (0.001849) SHOW FIELDS FROM `photos` - SQL (0.000967) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000143) SET SQL_AUTO_IS_NULL=0 - SQL (0.010724) SHOW FIELDS FROM `users` - SQL (0.002360) SHOW FIELDS FROM `photos` - SQL (0.001570) SHOW FIELDS FROM `users` - SQL (0.001733) SHOW FIELDS FROM `photos` - SQL (0.001487) SHOW FIELDS FROM `cameras` - SQL (0.001624) SHOW FIELDS FROM `users` - SQL (0.001840) SHOW FIELDS FROM `photos` - SQL (0.001080) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010885) SHOW FIELDS FROM `users` - SQL (0.002106) SHOW FIELDS FROM `photos` - SQL (0.001603) SHOW FIELDS FROM `users` - SQL (0.001575) SHOW FIELDS FROM `photos` - SQL (0.001529) SHOW FIELDS FROM `cameras` - SQL (0.001517) SHOW FIELDS FROM `users` - SQL (0.001556) SHOW FIELDS FROM `photos` - SQL (0.000260) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010689) SHOW FIELDS FROM `users` - SQL (0.002034) SHOW FIELDS FROM `photos` - SQL (0.001430) SHOW FIELDS FROM `users` - SQL (0.001590) SHOW FIELDS FROM `photos` - SQL (0.001434) SHOW FIELDS FROM `cameras` - SQL (0.001543) SHOW FIELDS FROM `users` - SQL (0.001597) SHOW FIELDS FROM `photos` - SQL (0.001103) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000143) SET SQL_AUTO_IS_NULL=0 - SQL (0.010735) SHOW FIELDS FROM `users` - SQL (0.002171) SHOW FIELDS FROM `photos` - SQL (0.001553) SHOW FIELDS FROM `users` - SQL (0.001586) SHOW FIELDS FROM `photos` - SQL (0.001520) SHOW FIELDS FROM `cameras` - SQL (0.001441) SHOW FIELDS FROM `users` - SQL (0.001560) SHOW FIELDS FROM `photos` - SQL (0.001796) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010772) SHOW FIELDS FROM `users` - SQL (0.002291) SHOW FIELDS FROM `photos` - SQL (0.001505) SHOW FIELDS FROM `users` - SQL (0.001466) SHOW FIELDS FROM `photos` - SQL (0.002032) SHOW FIELDS FROM `cameras` - SQL (0.001543) SHOW FIELDS FROM `users` - SQL (0.001434) SHOW FIELDS FROM `photos` - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010845) SHOW FIELDS FROM `users` - SQL (0.002185) SHOW FIELDS FROM `photos` - SQL (0.001479) SHOW FIELDS FROM `users` - SQL (0.001551) SHOW FIELDS FROM `photos` - SQL (0.001459) SHOW FIELDS FROM `cameras` - SQL (0.001521) SHOW FIELDS FROM `users` - SQL (0.001392) SHOW FIELDS FROM `photos` - SQL (0.000222) SELECT photos.user_id, photos.camera_id, photos.id -FROM photos  - SQL (0.000246) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000136) SET SQL_AUTO_IS_NULL=0 - SQL (0.010662) SHOW FIELDS FROM `users` - SQL (0.002267) SHOW FIELDS FROM `photos` - SQL (0.001467) SHOW FIELDS FROM `users` - SQL (0.001437) SHOW FIELDS FROM `photos` - SQL (0.001355) SHOW FIELDS FROM `cameras` - SQL (0.001506) SHOW FIELDS FROM `users` - SQL (0.012944) SHOW FIELDS FROM `photos` - SQL (0.000256) SELECT * -FROM photos  - SQL (0.000271) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010682) SHOW FIELDS FROM `users` - SQL (0.002485) SHOW FIELDS FROM `photos` - SQL (0.001454) SHOW FIELDS FROM `users` - SQL (0.001588) SHOW FIELDS FROM `photos` - SQL (0.001480) SHOW FIELDS FROM `cameras` - SQL (0.001539) SHOW FIELDS FROM `users` - SQL (0.001735) SHOW FIELDS FROM `photos` - SQL (0.000111) SET SQL_AUTO_IS_NULL=0 - SQL (0.010744) SHOW FIELDS FROM `users` - SQL (0.002250) SHOW FIELDS FROM `photos` - SQL (0.001491) SHOW FIELDS FROM `users` - SQL (0.001534) SHOW FIELDS FROM `photos` - SQL (0.001499) SHOW FIELDS FROM `cameras` - SQL (0.001482) SHOW FIELDS FROM `users` - SQL (0.001496) SHOW FIELDS FROM `photos` - SQL (0.000165) SET SQL_AUTO_IS_NULL=0 - SQL (0.010840) SHOW FIELDS FROM `users` - SQL (0.002301) SHOW FIELDS FROM `photos` - SQL (0.001598) SHOW FIELDS FROM `users` - SQL (0.001456) SHOW FIELDS FROM `photos` - SQL (0.001241) SHOW FIELDS FROM `cameras` - SQL (0.001479) SHOW FIELDS FROM `users` - SQL (0.000887) SHOW FIELDS FROM `photos` - SQL (0.000137) SET SQL_AUTO_IS_NULL=0 - SQL (0.010721) SHOW FIELDS FROM `users` - SQL (0.002243) SHOW FIELDS FROM `photos` - SQL (0.001485) SHOW FIELDS FROM `users` - SQL (0.001592) SHOW FIELDS FROM `photos` - SQL (0.001519) SHOW FIELDS FROM `cameras` - SQL (0.001480) SHOW FIELDS FROM `users` - SQL (0.001534) SHOW FIELDS FROM `photos` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010748) SHOW FIELDS FROM `users` - SQL (0.002303) SHOW FIELDS FROM `photos` - SQL (0.001459) SHOW FIELDS FROM `users` - SQL (0.001580) SHOW FIELDS FROM `photos` - SQL (0.001584) SHOW FIELDS FROM `cameras` - SQL (0.001507) SHOW FIELDS FROM `users` - SQL (0.001526) SHOW FIELDS FROM `photos` - SQL (0.000139) SET SQL_AUTO_IS_NULL=0 - SQL (0.001564) SHOW FIELDS FROM `users` - SQL (0.001517) SHOW FIELDS FROM `photos` - SQL (0.001405) SHOW FIELDS FROM `users` - SQL (0.001516) SHOW FIELDS FROM `photos` - SQL (0.001704) SHOW FIELDS FROM `cameras` - SQL (0.001583) SHOW FIELDS FROM `users` - SQL (0.001579) SHOW FIELDS FROM `photos` - SQL (0.000135) SET SQL_AUTO_IS_NULL=0 - SQL (0.010720) SHOW FIELDS FROM `users` - SQL (0.002156) SHOW FIELDS FROM `photos` - SQL (0.001639) SHOW FIELDS FROM `users` - SQL (0.001434) SHOW FIELDS FROM `photos` - SQL (0.001357) SHOW FIELDS FROM `cameras` - SQL (0.001513) SHOW FIELDS FROM `users` - SQL (0.001474) SHOW FIELDS FROM `photos` - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010719) SHOW FIELDS FROM `users` - SQL (0.002256) SHOW FIELDS FROM `photos` - SQL (0.001531) SHOW FIELDS FROM `users` - SQL (0.001453) SHOW FIELDS FROM `photos` - SQL (0.001388) SHOW FIELDS FROM `cameras` - SQL (0.001494) SHOW FIELDS FROM `users` - SQL (0.001101) SHOW FIELDS FROM `photos` - SQL (0.000219) SELECT users.id -FROM users -WHERE users.id = 1 - SQL (0.000157) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.011477) SHOW FIELDS FROM `users` - SQL (0.002257) SHOW FIELDS FROM `photos` - SQL (0.001520) SHOW FIELDS FROM `users` - SQL (0.001410) SHOW FIELDS FROM `photos` - SQL (0.001383) SHOW FIELDS FROM `cameras` - SQL (0.001505) SHOW FIELDS FROM `users` - SQL (0.001462) SHOW FIELDS FROM `photos` - SQL (0.000222) SELECT users.id -FROM users -WHERE users.id = 1 - SQL (0.000197) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010701) SHOW FIELDS FROM `users` - SQL (0.002382) SHOW FIELDS FROM `photos` - SQL (0.001523) SHOW FIELDS FROM `users` - SQL (0.001558) SHOW FIELDS FROM `photos` - SQL (0.001494) SHOW FIELDS FROM `cameras` - SQL (0.001467) SHOW FIELDS FROM `users` - SQL (0.001516) SHOW FIELDS FROM `photos` - SQL (0.000129) SET SQL_AUTO_IS_NULL=0 - SQL (0.010711) SHOW FIELDS FROM `users` - SQL (0.002382) SHOW FIELDS FROM `photos` - SQL (0.001495) SHOW FIELDS FROM `users` - SQL (0.001445) SHOW FIELDS FROM `photos` - SQL (0.001363) SHOW FIELDS FROM `cameras` - SQL (0.001557) SHOW FIELDS FROM `users` - SQL (0.001433) SHOW FIELDS FROM `photos` - SQL (0.000000) Mysql::Error: Unknown column 'photos.id' in 'field list': SELECT photos.id -FROM users -WHERE users.id = 1 - SQL (0.000132) SET SQL_AUTO_IS_NULL=0 - SQL (0.010902) SHOW FIELDS FROM `users` - SQL (0.002079) SHOW FIELDS FROM `photos` - SQL (0.001455) SHOW FIELDS FROM `users` - SQL (0.001626) SHOW FIELDS FROM `photos` - SQL (0.012539) SHOW FIELDS FROM `cameras` - SQL (0.001557) SHOW FIELDS FROM `users` - SQL (0.001437) SHOW FIELDS FROM `photos` - SQL (0.000255) SELECT users.id -FROM users -WHERE users.id = 1 - SQL (0.000225) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010766) SHOW FIELDS FROM `users` - SQL (0.002370) SHOW FIELDS FROM `photos` - SQL (0.001453) SHOW FIELDS FROM `users` - SQL (0.001556) SHOW FIELDS FROM `photos` - SQL (0.001492) SHOW FIELDS FROM `cameras` - SQL (0.001243) SHOW FIELDS FROM `users` - SQL (0.001527) SHOW FIELDS FROM `photos` - SQL (0.000151) SET SQL_AUTO_IS_NULL=0 - SQL (0.010730) SHOW FIELDS FROM `users` - SQL (0.002308) SHOW FIELDS FROM `photos` - SQL (0.001489) SHOW FIELDS FROM `users` - SQL (0.001571) SHOW FIELDS FROM `photos` - SQL (0.001345) SHOW FIELDS FROM `cameras` - SQL (0.001456) SHOW FIELDS FROM `users` - SQL (0.001161) SHOW FIELDS FROM `photos` - SQL (0.000215) SELECT users.id -FROM users -WHERE users.id = 1 - SQL (0.000261) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000139) SET SQL_AUTO_IS_NULL=0 - SQL (0.010683) SHOW FIELDS FROM `users` - SQL (0.002298) SHOW FIELDS FROM `photos` - SQL (0.001478) SHOW FIELDS FROM `users` - SQL (0.001413) SHOW FIELDS FROM `photos` - SQL (0.001521) SHOW FIELDS FROM `cameras` - SQL (0.001462) SHOW FIELDS FROM `users` - SQL (0.001509) SHOW FIELDS FROM `photos` - SQL (0.001637) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000136) SET SQL_AUTO_IS_NULL=0 - SQL (0.010714) SHOW FIELDS FROM `users` - SQL (0.002255) SHOW FIELDS FROM `photos` - SQL (0.001471) SHOW FIELDS FROM `users` - SQL (0.001491) SHOW FIELDS FROM `photos` - SQL (0.001494) SHOW FIELDS FROM `cameras` - SQL (0.001537) SHOW FIELDS FROM `users` - SQL (0.001500) SHOW FIELDS FROM `photos` - SQL (0.000144) SET SQL_AUTO_IS_NULL=0 - SQL (0.010658) SHOW FIELDS FROM `users` - SQL (0.002047) SHOW FIELDS FROM `photos` - SQL (0.001307) SHOW FIELDS FROM `users` - SQL (0.001529) SHOW FIELDS FROM `photos` - SQL (0.001380) SHOW FIELDS FROM `cameras` - SQL (0.001558) SHOW FIELDS FROM `users` - SQL (0.000851) SHOW FIELDS FROM `photos` - SQL (0.000135) SET SQL_AUTO_IS_NULL=0 - SQL (0.010643) SHOW FIELDS FROM `users` - SQL (0.002531) SHOW FIELDS FROM `photos` - SQL (0.001449) SHOW FIELDS FROM `users` - SQL (0.001423) SHOW FIELDS FROM `photos` - SQL (0.001522) SHOW FIELDS FROM `cameras` - SQL (0.001515) SHOW FIELDS FROM `users` - SQL (0.001581) SHOW FIELDS FROM `photos` - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010786) SHOW FIELDS FROM `users` - SQL (0.002348) SHOW FIELDS FROM `photos` - SQL (0.001476) SHOW FIELDS FROM `users` - SQL (0.001604) SHOW FIELDS FROM `photos` - SQL (0.001380) SHOW FIELDS FROM `cameras` - SQL (0.001484) SHOW FIELDS FROM `users` - SQL (0.001383) SHOW FIELDS FROM `photos` - SQL (0.000117) SET SQL_AUTO_IS_NULL=0 - SQL (0.010702) SHOW FIELDS FROM `users` - SQL (0.002339) SHOW FIELDS FROM `photos` - SQL (0.001304) SHOW FIELDS FROM `users` - SQL (0.001578) SHOW FIELDS FROM `photos` - SQL (0.001470) SHOW FIELDS FROM `cameras` - SQL (0.001524) SHOW FIELDS FROM `users` - SQL (0.001554) SHOW FIELDS FROM `photos` - SQL (0.000144) SET SQL_AUTO_IS_NULL=0 - SQL (0.010746) SHOW FIELDS FROM `users` - SQL (0.002433) SHOW FIELDS FROM `photos` - SQL (0.001489) SHOW FIELDS FROM `users` - SQL (0.001530) SHOW FIELDS FROM `photos` - SQL (0.001540) SHOW FIELDS FROM `cameras` - SQL (0.001528) SHOW FIELDS FROM `users` - SQL (0.001524) SHOW FIELDS FROM `photos` - SQL (0.000393) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000149) SET SQL_AUTO_IS_NULL=0 - SQL (0.010676) SHOW FIELDS FROM `users` - SQL (0.002224) SHOW FIELDS FROM `photos` - SQL (0.001456) SHOW FIELDS FROM `users` - SQL (0.001773) SHOW FIELDS FROM `photos` - SQL (0.001509) SHOW FIELDS FROM `cameras` - SQL (0.001473) SHOW FIELDS FROM `users` - SQL (0.001511) SHOW FIELDS FROM `photos` - SQL (0.000274) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010825) SHOW FIELDS FROM `users` - SQL (0.002358) SHOW FIELDS FROM `photos` - SQL (0.001492) SHOW FIELDS FROM `users` - SQL (0.001578) SHOW FIELDS FROM `photos` - SQL (0.001702) SHOW FIELDS FROM `cameras` - SQL (0.001495) SHOW FIELDS FROM `users` - SQL (0.001778) SHOW FIELDS FROM `photos` - SQL (0.000348) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000113) SET SQL_AUTO_IS_NULL=0 - SQL (0.010701) SHOW FIELDS FROM `users` - SQL (0.002380) SHOW FIELDS FROM `photos` - SQL (0.001329) SHOW FIELDS FROM `users` - SQL (0.001403) SHOW FIELDS FROM `photos` - SQL (0.001409) SHOW FIELDS FROM `cameras` - SQL (0.001458) SHOW FIELDS FROM `users` - SQL (0.001486) SHOW FIELDS FROM `photos` - SQL (0.000562) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000134) SET SQL_AUTO_IS_NULL=0 - SQL (0.010761) SHOW FIELDS FROM `users` - SQL (0.002300) SHOW FIELDS FROM `photos` - SQL (0.001565) SHOW FIELDS FROM `users` - SQL (0.001514) SHOW FIELDS FROM `photos` - SQL (0.001377) SHOW FIELDS FROM `cameras` - SQL (0.001553) SHOW FIELDS FROM `users` - SQL (0.001454) SHOW FIELDS FROM `photos` - SQL (0.000319) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000156) SET SQL_AUTO_IS_NULL=0 - SQL (0.010664) SHOW FIELDS FROM `users` - SQL (0.002495) SHOW FIELDS FROM `photos` - SQL (0.001454) SHOW FIELDS FROM `users` - SQL (0.001569) SHOW FIELDS FROM `photos` - SQL (0.001277) SHOW FIELDS FROM `cameras` - SQL (0.001250) SHOW FIELDS FROM `users` - SQL (0.001543) SHOW FIELDS FROM `photos` - SQL (0.000263) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000143) SET SQL_AUTO_IS_NULL=0 - SQL (0.010756) SHOW FIELDS FROM `users` - SQL (0.002397) SHOW FIELDS FROM `photos` - SQL (0.001731) SHOW FIELDS FROM `users` - SQL (0.001443) SHOW FIELDS FROM `photos` - SQL (0.001366) SHOW FIELDS FROM `cameras` - SQL (0.001472) SHOW FIELDS FROM `users` - SQL (0.001420) SHOW FIELDS FROM `photos` - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010705) SHOW FIELDS FROM `users` - SQL (0.002368) SHOW FIELDS FROM `photos` - SQL (0.001556) SHOW FIELDS FROM `users` - SQL (0.001472) SHOW FIELDS FROM `photos` - SQL (0.001455) SHOW FIELDS FROM `cameras` - SQL (0.001475) SHOW FIELDS FROM `users` - SQL (0.002127) SHOW FIELDS FROM `photos` - SQL (0.001414) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010742) SHOW FIELDS FROM `users` - SQL (0.002380) SHOW FIELDS FROM `photos` - SQL (0.001634) SHOW FIELDS FROM `users` - SQL (0.001587) SHOW FIELDS FROM `photos` - SQL (0.001452) SHOW FIELDS FROM `cameras` - SQL (0.001454) SHOW FIELDS FROM `users` - SQL (0.001514) SHOW FIELDS FROM `photos` - SQL (0.000135) SET SQL_AUTO_IS_NULL=0 - SQL (0.010668) SHOW FIELDS FROM `users` - SQL (0.002191) SHOW FIELDS FROM `photos` - SQL (0.001521) SHOW FIELDS FROM `users` - SQL (0.001418) SHOW FIELDS FROM `photos` - SQL (0.001330) SHOW FIELDS FROM `cameras` - SQL (0.001474) SHOW FIELDS FROM `users` - SQL (0.001406) SHOW FIELDS FROM `photos` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010693) SHOW FIELDS FROM `users` - SQL (0.002296) SHOW FIELDS FROM `photos` - SQL (0.001485) SHOW FIELDS FROM `users` - SQL (0.001604) SHOW FIELDS FROM `photos` - SQL (0.001479) SHOW FIELDS FROM `cameras` - SQL (0.001660) SHOW FIELDS FROM `users` - SQL (0.001632) SHOW FIELDS FROM `photos` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010678) SHOW FIELDS FROM `users` - SQL (0.002302) SHOW FIELDS FROM `photos` - SQL (0.001501) SHOW FIELDS FROM `users` - SQL (0.001360) SHOW FIELDS FROM `photos` - SQL (0.001353) SHOW FIELDS FROM `cameras` - SQL (0.001562) SHOW FIELDS FROM `users` - SQL (0.001542) SHOW FIELDS FROM `photos` - SQL (0.000147) SET SQL_AUTO_IS_NULL=0 - SQL (0.010704) SHOW FIELDS FROM `users` - SQL (0.002335) SHOW FIELDS FROM `photos` - SQL (0.001425) SHOW FIELDS FROM `users` - SQL (0.001468) SHOW FIELDS FROM `photos` - SQL (0.001469) SHOW FIELDS FROM `cameras` - SQL (0.001573) SHOW FIELDS FROM `users` - SQL (0.001489) SHOW FIELDS FROM `photos` - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010787) SHOW FIELDS FROM `users` - SQL (0.002303) SHOW FIELDS FROM `photos` - SQL (0.001529) SHOW FIELDS FROM `users` - SQL (0.001689) SHOW FIELDS FROM `photos` - SQL (0.001503) SHOW FIELDS FROM `cameras` - SQL (0.001463) SHOW FIELDS FROM `users` - SQL (0.001487) SHOW FIELDS FROM `photos` - SQL (0.000149) SET SQL_AUTO_IS_NULL=0 - SQL (0.010737) SHOW FIELDS FROM `users` - SQL (0.002412) SHOW FIELDS FROM `photos` - SQL (0.001487) SHOW FIELDS FROM `users` - SQL (0.001547) SHOW FIELDS FROM `photos` - SQL (0.001571) SHOW FIELDS FROM `cameras` - SQL (0.001482) SHOW FIELDS FROM `users` - SQL (0.001395) SHOW FIELDS FROM `photos` - SQL (0.000481) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010918) SHOW FIELDS FROM `users` - SQL (0.001957) SHOW FIELDS FROM `photos` - SQL (0.001485) SHOW FIELDS FROM `users` - SQL (0.001498) SHOW FIELDS FROM `photos` - SQL (0.001374) SHOW FIELDS FROM `cameras` - SQL (0.001461) SHOW FIELDS FROM `users` - SQL (0.001923) SHOW FIELDS FROM `photos` - SQL (0.000233) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000232) SELECT photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.011208) SHOW FIELDS FROM `users` - SQL (0.002172) SHOW FIELDS FROM `photos` - SQL (0.001453) SHOW FIELDS FROM `users` - SQL (0.001526) SHOW FIELDS FROM `photos` - SQL (0.001666) SHOW FIELDS FROM `cameras` - SQL (0.001273) SHOW FIELDS FROM `users` - SQL (0.001845) SHOW FIELDS FROM `photos` - SQL (0.000270) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000133) SET SQL_AUTO_IS_NULL=0 - SQL (0.010785) SHOW FIELDS FROM `users` - SQL (0.002207) SHOW FIELDS FROM `photos` - SQL (0.001480) SHOW FIELDS FROM `users` - SQL (0.001563) SHOW FIELDS FROM `photos` - SQL (0.001459) SHOW FIELDS FROM `cameras` - SQL (0.001206) SHOW FIELDS FROM `users` - SQL (0.001250) SHOW FIELDS FROM `photos` - SQL (0.000224) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000227) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000192) SET SQL_AUTO_IS_NULL=0 - SQL (0.010546) SHOW FIELDS FROM `users` - SQL (0.002397) SHOW FIELDS FROM `photos` - SQL (0.002065) SHOW FIELDS FROM `users` - SQL (0.001381) SHOW FIELDS FROM `photos` - SQL (0.000979) SHOW FIELDS FROM `cameras` - SQL (0.001410) SHOW FIELDS FROM `users` - SQL (0.001516) SHOW FIELDS FROM `photos` - SQL (0.000216) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000240) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010781) SHOW FIELDS FROM `users` - SQL (0.002045) SHOW FIELDS FROM `photos` - SQL (0.001462) SHOW FIELDS FROM `users` - SQL (0.001712) SHOW FIELDS FROM `photos` - SQL (0.001383) SHOW FIELDS FROM `cameras` - SQL (0.001934) SHOW FIELDS FROM `users` - SQL (0.001974) SHOW FIELDS FROM `photos` - SQL (0.000277) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000266) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010789) SHOW FIELDS FROM `users` - SQL (0.002174) SHOW FIELDS FROM `photos` - SQL (0.001549) SHOW FIELDS FROM `users` - SQL (0.001406) SHOW FIELDS FROM `photos` - SQL (0.001380) SHOW FIELDS FROM `cameras` - SQL (0.001590) SHOW FIELDS FROM `users` - SQL (0.001465) SHOW FIELDS FROM `photos` - SQL (0.000236) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000260) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000148) SET SQL_AUTO_IS_NULL=0 - SQL (0.010729) SHOW FIELDS FROM `users` - SQL (0.002288) SHOW FIELDS FROM `photos` - SQL (0.001373) SHOW FIELDS FROM `users` - SQL (0.001594) SHOW FIELDS FROM `photos` - SQL (0.001516) SHOW FIELDS FROM `cameras` - SQL (0.001470) SHOW FIELDS FROM `users` - SQL (0.001653) SHOW FIELDS FROM `photos` - SQL (0.000249) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000324) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010695) SHOW FIELDS FROM `users` - SQL (0.002188) SHOW FIELDS FROM `photos` - SQL (0.001450) SHOW FIELDS FROM `users` - SQL (0.001569) SHOW FIELDS FROM `photos` - SQL (0.001437) SHOW FIELDS FROM `cameras` - SQL (0.001780) SHOW FIELDS FROM `users` - SQL (0.002270) SHOW FIELDS FROM `photos` - SQL (0.001585) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000325) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000151) SET SQL_AUTO_IS_NULL=0 - SQL (0.010721) SHOW FIELDS FROM `users` - SQL (0.002947) SHOW FIELDS FROM `photos` - SQL (0.001515) SHOW FIELDS FROM `users` - SQL (0.001270) SHOW FIELDS FROM `photos` - SQL (0.001479) SHOW FIELDS FROM `cameras` - SQL (0.001428) SHOW FIELDS FROM `users` - SQL (0.001953) SHOW FIELDS FROM `photos` - SQL (0.000253) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000279) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010670) SHOW FIELDS FROM `users` - SQL (0.002111) SHOW FIELDS FROM `photos` - SQL (0.001460) SHOW FIELDS FROM `users` - SQL (0.001578) SHOW FIELDS FROM `photos` - SQL (0.001576) SHOW FIELDS FROM `cameras` - SQL (0.001497) SHOW FIELDS FROM `users` - SQL (0.001326) SHOW FIELDS FROM `photos` - SQL (0.000235) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000250) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.001613) SHOW FIELDS FROM `users` - SQL (0.001535) SHOW FIELDS FROM `photos` - SQL (0.001418) SHOW FIELDS FROM `users` - SQL (0.001545) SHOW FIELDS FROM `photos` - SQL (0.001536) SHOW FIELDS FROM `cameras` - SQL (0.001527) SHOW FIELDS FROM `users` - SQL (0.001497) SHOW FIELDS FROM `photos` - SQL (0.000230) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000227) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000134) SET SQL_AUTO_IS_NULL=0 - SQL (0.011304) SHOW FIELDS FROM `users` - SQL (0.002381) SHOW FIELDS FROM `photos` - SQL (0.001508) SHOW FIELDS FROM `users` - SQL (0.001665) SHOW FIELDS FROM `photos` - SQL (0.001498) SHOW FIELDS FROM `cameras` - SQL (0.001503) SHOW FIELDS FROM `users` - SQL (0.001514) SHOW FIELDS FROM `photos` - SQL (0.000225) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000231) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000134) SET SQL_AUTO_IS_NULL=0 - SQL (0.010747) SHOW FIELDS FROM `users` - SQL (0.002111) SHOW FIELDS FROM `photos` - SQL (0.001510) SHOW FIELDS FROM `users` - SQL (0.001581) SHOW FIELDS FROM `photos` - SQL (0.001428) SHOW FIELDS FROM `cameras` - SQL (0.001507) SHOW FIELDS FROM `users` - SQL (0.001808) SHOW FIELDS FROM `photos` - SQL (0.000247) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000237) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010702) SHOW FIELDS FROM `users` - SQL (0.002320) SHOW FIELDS FROM `photos` - SQL (0.001504) SHOW FIELDS FROM `users` - SQL (0.001589) SHOW FIELDS FROM `photos` - SQL (0.001555) SHOW FIELDS FROM `cameras` - SQL (0.002636) SHOW FIELDS FROM `users` - SQL (0.001766) SHOW FIELDS FROM `photos` - SQL (0.000239) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000281) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000115) SET SQL_AUTO_IS_NULL=0 - SQL (0.011377) SHOW FIELDS FROM `users` - SQL (0.002266) SHOW FIELDS FROM `photos` - SQL (0.001512) SHOW FIELDS FROM `users` - SQL (0.001553) SHOW FIELDS FROM `photos` - SQL (0.001686) SHOW FIELDS FROM `cameras` - SQL (0.001487) SHOW FIELDS FROM `users` - SQL (0.001520) SHOW FIELDS FROM `photos` - SQL (0.000223) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000233) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000133) SET SQL_AUTO_IS_NULL=0 - SQL (0.011494) SHOW FIELDS FROM `users` - SQL (0.002092) SHOW FIELDS FROM `photos` - SQL (0.001556) SHOW FIELDS FROM `cameras` - SQL (0.001490) SHOW FIELDS FROM `users` - SQL (0.001594) SHOW FIELDS FROM `photos` - SQL (0.001273) SHOW FIELDS FROM `cameras` - SQL (0.001512) SHOW FIELDS FROM `users` - SQL (0.001362) SHOW FIELDS FROM `photos` - SQL (0.001476) SHOW FIELDS FROM `cameras` - SQL (0.000227) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000335) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.001514) SHOW FIELDS FROM `users` - SQL (0.001589) SHOW FIELDS FROM `photos` - SQL (0.001412) SHOW FIELDS FROM `cameras` - SQL (0.000110) SET SQL_AUTO_IS_NULL=0 - SQL (0.010696) SHOW FIELDS FROM `users` - SQL (0.002449) SHOW FIELDS FROM `photos` - SQL (0.001558) SHOW FIELDS FROM `cameras` - SQL (0.001720) SHOW FIELDS FROM `users` - SQL (0.001577) SHOW FIELDS FROM `photos` - SQL (0.001420) SHOW FIELDS FROM `cameras` - SQL (0.009109) SHOW FIELDS FROM `users` - SQL (0.001770) SHOW FIELDS FROM `photos` - SQL (0.001409) SHOW FIELDS FROM `cameras` - SQL (0.000247) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000305) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001429) SHOW FIELDS FROM `users` - SQL (0.001503) SHOW FIELDS FROM `users` - SQL (0.001595) SHOW FIELDS FROM `photos` - SQL (0.001775) SHOW FIELDS FROM `cameras` - SQL (0.000137) SET SQL_AUTO_IS_NULL=0 - SQL (0.010741) SHOW FIELDS FROM `users` - SQL (0.002217) SHOW FIELDS FROM `photos` - SQL (0.001614) SHOW FIELDS FROM `cameras` - SQL (0.001277) SHOW FIELDS FROM `users` - SQL (0.001394) SHOW FIELDS FROM `photos` - SQL (0.001412) SHOW FIELDS FROM `cameras` - SQL (0.001534) SHOW FIELDS FROM `users` - SQL (0.001595) SHOW FIELDS FROM `photos` - SQL (0.001771) SHOW FIELDS FROM `cameras` - SQL (0.000246) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000287) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.001537) SHOW FIELDS FROM `users` - SQL (0.001578) SHOW FIELDS FROM `photos` - SQL (0.001351) SHOW FIELDS FROM `cameras` - SQL (0.000124) SET SQL_AUTO_IS_NULL=0 - SQL (0.010755) SHOW FIELDS FROM `users` - SQL (0.002276) SHOW FIELDS FROM `photos` - SQL (0.001312) SHOW FIELDS FROM `cameras` - SQL (0.002071) SHOW FIELDS FROM `users` - SQL (0.001613) SHOW FIELDS FROM `photos` - SQL (0.001271) SHOW FIELDS FROM `cameras` - SQL (0.001665) SHOW FIELDS FROM `users` - SQL (0.001605) SHOW FIELDS FROM `photos` - SQL (0.001360) SHOW FIELDS FROM `cameras` - SQL (0.000247) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000303) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001449) SHOW FIELDS FROM `users` - SQL (0.001510) SHOW FIELDS FROM `users` - SQL (0.001413) SHOW FIELDS FROM `photos` - SQL (0.001546) SHOW FIELDS FROM `cameras` - SQL (0.000115) SET SQL_AUTO_IS_NULL=0 - SQL (0.001542) SHOW FIELDS FROM `users` - SQL (0.001224) SHOW FIELDS FROM `photos` - SQL (0.001201) SHOW FIELDS FROM `cameras` - SQL (0.001325) SHOW FIELDS FROM `users` - SQL (0.001269) SHOW FIELDS FROM `photos` - SQL (0.001364) SHOW FIELDS FROM `cameras` - SQL (0.001517) SHOW FIELDS FROM `users` - SQL (0.001422) SHOW FIELDS FROM `photos` - SQL (0.001674) SHOW FIELDS FROM `cameras` - SQL (0.000270) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000269) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.008183) SHOW FIELDS FROM `users` - Photo Columns (0.001576) SHOW FIELDS FROM `photos` - SQL (0.001595) SHOW FIELDS FROM `users` - SQL (0.001461) SHOW FIELDS FROM `photos` - SQL (0.001327) SHOW FIELDS FROM `cameras` - SQL (0.000129) SET SQL_AUTO_IS_NULL=0 - SQL (0.001503) SHOW FIELDS FROM `users` - SQL (0.001544) SHOW FIELDS FROM `photos` - SQL (0.001444) SHOW FIELDS FROM `cameras` - SQL (0.001509) SHOW FIELDS FROM `users` - SQL (0.001593) SHOW FIELDS FROM `photos` - SQL (0.001422) SHOW FIELDS FROM `cameras` - SQL (0.001487) SHOW FIELDS FROM `users` - SQL (0.001996) SHOW FIELDS FROM `photos` - SQL (0.001380) SHOW FIELDS FROM `cameras` - SQL (0.000275) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000279) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001516) SHOW FIELDS FROM `users` - SQL (0.001449) SHOW FIELDS FROM `users` - SQL (0.001558) SHOW FIELDS FROM `photos` - SQL (0.001347) SHOW FIELDS FROM `cameras` - SQL (0.000133) SET SQL_AUTO_IS_NULL=0 - SQL (0.010735) SHOW FIELDS FROM `users` - SQL (0.002173) SHOW FIELDS FROM `photos` - SQL (0.001449) SHOW FIELDS FROM `cameras` - SQL (0.001510) SHOW FIELDS FROM `users` - SQL (0.001410) SHOW FIELDS FROM `photos` - SQL (0.001592) SHOW FIELDS FROM `cameras` - SQL (0.001570) SHOW FIELDS FROM `users` - SQL (0.001423) SHOW FIELDS FROM `photos` - SQL (0.001301) SHOW FIELDS FROM `cameras` - SQL (0.000287) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000301) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001475) SHOW FIELDS FROM `users` - Photo Columns (0.001465) SHOW FIELDS FROM `photos` - SQL (0.001633) SHOW FIELDS FROM `users` - SQL (0.001467) SHOW FIELDS FROM `photos` - SQL (0.001332) SHOW FIELDS FROM `cameras` - SQL (0.000132) SET SQL_AUTO_IS_NULL=0 - SQL (0.010888) SHOW FIELDS FROM `users` - SQL (0.002202) SHOW FIELDS FROM `photos` - SQL (0.001500) SHOW FIELDS FROM `cameras` - SQL (0.001457) SHOW FIELDS FROM `users` - SQL (0.001593) SHOW FIELDS FROM `photos` - SQL (0.001424) SHOW FIELDS FROM `cameras` - SQL (0.001492) SHOW FIELDS FROM `users` - SQL (0.001520) SHOW FIELDS FROM `photos` - SQL (0.001480) SHOW FIELDS FROM `cameras` - SQL (0.000290) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000263) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - SQL (0.000320) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001896) SHOW FIELDS FROM `users` - SQL (0.001262) SHOW FIELDS FROM `users` - SQL (0.001675) SHOW FIELDS FROM `photos` - SQL (0.001409) SHOW FIELDS FROM `cameras` - SQL (0.000130) SET SQL_AUTO_IS_NULL=0 - SQL (0.010691) SHOW FIELDS FROM `users` - SQL (0.002363) SHOW FIELDS FROM `photos` - SQL (0.001590) SHOW FIELDS FROM `cameras` - SQL (0.001560) SHOW FIELDS FROM `users` - SQL (0.013103) SHOW FIELDS FROM `photos` - SQL (0.001597) SHOW FIELDS FROM `cameras` - SQL (0.001491) SHOW FIELDS FROM `users` - SQL (0.001553) SHOW FIELDS FROM `photos` - SQL (0.001368) SHOW FIELDS FROM `cameras` - SQL (0.000300) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.001508) SHOW FIELDS FROM `users` - SQL (0.001583) SHOW FIELDS FROM `photos` - SQL (0.001442) SHOW FIELDS FROM `cameras` - SQL (0.000132) SET SQL_AUTO_IS_NULL=0 - SQL (0.010756) SHOW FIELDS FROM `users` - SQL (0.002320) SHOW FIELDS FROM `photos` - SQL (0.001416) SHOW FIELDS FROM `cameras` - SQL (0.001507) SHOW FIELDS FROM `users` - SQL (0.012716) SHOW FIELDS FROM `photos` - SQL (0.001406) SHOW FIELDS FROM `cameras` - SQL (0.001353) SHOW FIELDS FROM `users` - SQL (0.001440) SHOW FIELDS FROM `photos` - SQL (0.001263) SHOW FIELDS FROM `cameras` - SQL (0.000233) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000259) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001394) SHOW FIELDS FROM `users` - SQL (0.001487) SHOW FIELDS FROM `users` - SQL (0.001837) SHOW FIELDS FROM `photos` - SQL (0.001501) SHOW FIELDS FROM `cameras` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.001575) SHOW FIELDS FROM `users` - SQL (0.001415) SHOW FIELDS FROM `photos` - SQL (0.001483) SHOW FIELDS FROM `cameras` - SQL (0.000820) SHOW FIELDS FROM `users` - SQL (0.001526) SHOW FIELDS FROM `photos` - SQL (0.001093) SHOW FIELDS FROM `cameras` - SQL (0.001526) SHOW FIELDS FROM `users` - SQL (0.001631) SHOW FIELDS FROM `photos` - SQL (0.001346) SHOW FIELDS FROM `cameras` - SQL (0.000282) SELECT * -FROM users -WHERE users.id = 1 - SQL (0.000281) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - User Columns (0.001235) SHOW FIELDS FROM `users` - Photo Columns (0.001422) SHOW FIELDS FROM `photos` - SQL (0.001607) SHOW FIELDS FROM `users` - SQL (0.001685) SHOW FIELDS FROM `photos` - SQL (0.001318) SHOW FIELDS FROM `cameras` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010894) SHOW FIELDS FROM `users` - SQL (0.002240) SHOW FIELDS FROM `photos` - SQL (0.001487) SHOW FIELDS FROM `cameras` - SQL (0.001578) SHOW FIELDS FROM `users` - SQL (0.001582) SHOW FIELDS FROM `photos` - SQL (0.001418) SHOW FIELDS FROM `cameras` - SQL (0.001528) SHOW FIELDS FROM `users` - SQL (0.001577) SHOW FIELDS FROM `photos` - SQL (0.001215) SHOW FIELDS FROM `cameras` - SQL (0.000251) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001387) SHOW FIELDS FROM `users` - SQL (0.000296) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001457) SHOW FIELDS FROM `photos` - SQL (0.001421) SHOW FIELDS FROM `users` - SQL (0.001431) SHOW FIELDS FROM `photos` - SQL (0.001485) SHOW FIELDS FROM `cameras` - SQL (0.000145) SET SQL_AUTO_IS_NULL=0 - SQL (0.010759) SHOW FIELDS FROM `users` - SQL (0.002325) SHOW FIELDS FROM `photos` - SQL (0.001391) SHOW FIELDS FROM `cameras` - SQL (0.001545) SHOW FIELDS FROM `users` - SQL (0.001442) SHOW FIELDS FROM `photos` - SQL (0.001285) SHOW FIELDS FROM `cameras` - SQL (0.001287) SHOW FIELDS FROM `users` - SQL (0.001565) SHOW FIELDS FROM `photos` - SQL (0.001098) SHOW FIELDS FROM `cameras` - SQL (0.000215) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001362) SHOW FIELDS FROM `users` - SQL (0.000283) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001459) SHOW FIELDS FROM `photos` - SQL (0.001404) SHOW FIELDS FROM `users` - SQL (0.001554) SHOW FIELDS FROM `photos` - SQL (0.001531) SHOW FIELDS FROM `cameras` - SQL (0.000146) SET SQL_AUTO_IS_NULL=0 - SQL (0.010611) SHOW FIELDS FROM `users` - SQL (0.002560) SHOW FIELDS FROM `photos` - SQL (0.001457) SHOW FIELDS FROM `cameras` - SQL (0.001439) SHOW FIELDS FROM `users` - SQL (0.001575) SHOW FIELDS FROM `photos` - SQL (0.001422) SHOW FIELDS FROM `cameras` - SQL (0.001475) SHOW FIELDS FROM `users` - SQL (0.001563) SHOW FIELDS FROM `photos` - SQL (0.001389) SHOW FIELDS FROM `cameras` - SQL (0.000213) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001375) SHOW FIELDS FROM `users` - SQL (0.000251) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001417) SHOW FIELDS FROM `photos` - SQL (0.001395) SHOW FIELDS FROM `users` - SQL (0.001539) SHOW FIELDS FROM `photos` - SQL (0.001552) SHOW FIELDS FROM `cameras` - SQL (0.000113) SET SQL_AUTO_IS_NULL=0 - SQL (0.010659) SHOW FIELDS FROM `users` - SQL (0.002496) SHOW FIELDS FROM `photos` - SQL (0.001466) SHOW FIELDS FROM `cameras` - SQL (0.001519) SHOW FIELDS FROM `users` - SQL (0.001591) SHOW FIELDS FROM `photos` - SQL (0.001455) SHOW FIELDS FROM `cameras` - SQL (0.001502) SHOW FIELDS FROM `users` - SQL (0.001543) SHOW FIELDS FROM `photos` - SQL (0.001432) SHOW FIELDS FROM `cameras` - SQL (0.000225) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001376) SHOW FIELDS FROM `users` - SQL (0.000266) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001440) SHOW FIELDS FROM `photos` - SQL (0.001105) SHOW FIELDS FROM `users` - SQL (0.001152) SHOW FIELDS FROM `photos` - SQL (0.001384) SHOW FIELDS FROM `cameras` - SQL (0.000127) SET SQL_AUTO_IS_NULL=0 - SQL (0.010753) SHOW FIELDS FROM `users` - SQL (0.002275) SHOW FIELDS FROM `photos` - SQL (0.001708) SHOW FIELDS FROM `cameras` - SQL (0.001413) SHOW FIELDS FROM `users` - SQL (0.001552) SHOW FIELDS FROM `photos` - SQL (0.001604) SHOW FIELDS FROM `cameras` - SQL (0.001482) SHOW FIELDS FROM `users` - SQL (0.001500) SHOW FIELDS FROM `photos` - SQL (0.001349) SHOW FIELDS FROM `cameras` - SQL (0.000227) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001386) SHOW FIELDS FROM `users` - SQL (0.000269) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001425) SHOW FIELDS FROM `photos` - SQL (0.001065) SHOW FIELDS FROM `users` - SQL (0.001438) SHOW FIELDS FROM `photos` - SQL (0.001376) SHOW FIELDS FROM `cameras` - SQL (0.000107) SET SQL_AUTO_IS_NULL=0 - SQL (0.010766) SHOW FIELDS FROM `users` - SQL (0.002300) SHOW FIELDS FROM `photos` - SQL (0.001306) SHOW FIELDS FROM `cameras` - SQL (0.001562) SHOW FIELDS FROM `users` - SQL (0.001725) SHOW FIELDS FROM `photos` - SQL (0.001356) SHOW FIELDS FROM `cameras` - SQL (0.001539) SHOW FIELDS FROM `users` - SQL (0.001465) SHOW FIELDS FROM `photos` - SQL (0.001345) SHOW FIELDS FROM `cameras` - SQL (0.000303) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001553) SHOW FIELDS FROM `users` - SQL (0.000299) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001329) SHOW FIELDS FROM `photos` - SQL (0.001422) SHOW FIELDS FROM `users` - SQL (0.001414) SHOW FIELDS FROM `photos` - SQL (0.001429) SHOW FIELDS FROM `cameras` - SQL (0.000349) SELECT * -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id LEFT OUTER JOIN cameras ON photos.camera_id = cameras.id -WHERE users.id = 1 - SQL (0.000109) SET SQL_AUTO_IS_NULL=0 - SQL (0.010688) SHOW FIELDS FROM `users` - SQL (0.002247) SHOW FIELDS FROM `photos` - SQL (0.001542) SHOW FIELDS FROM `cameras` - SQL (0.001432) SHOW FIELDS FROM `users` - SQL (0.001390) SHOW FIELDS FROM `photos` - SQL (0.001428) SHOW FIELDS FROM `cameras` - SQL (0.001641) SHOW FIELDS FROM `users` - SQL (0.001602) SHOW FIELDS FROM `photos` - SQL (0.001426) SHOW FIELDS FROM `cameras` - SQL (0.000253) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001398) SHOW FIELDS FROM `users` - SQL (0.000304) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001457) SHOW FIELDS FROM `photos` - SQL (0.001298) SHOW FIELDS FROM `users` - SQL (0.001539) SHOW FIELDS FROM `photos` - SQL (0.001487) SHOW FIELDS FROM `cameras` - SQL (0.000139) SET SQL_AUTO_IS_NULL=0 - SQL (0.001575) SHOW FIELDS FROM `users` - SQL (0.001596) SHOW FIELDS FROM `photos` - SQL (0.001406) SHOW FIELDS FROM `cameras` - SQL (0.001432) SHOW FIELDS FROM `users` - SQL (0.001640) SHOW FIELDS FROM `photos` - SQL (0.001465) SHOW FIELDS FROM `cameras` - SQL (0.001463) SHOW FIELDS FROM `users` - SQL (0.001577) SHOW FIELDS FROM `photos` - SQL (0.001434) SHOW FIELDS FROM `cameras` - SQL (0.000258) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001417) SHOW FIELDS FROM `users` - SQL (0.000338) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001542) SHOW FIELDS FROM `photos` - SQL (0.001474) SHOW FIELDS FROM `users` - SQL (0.001582) SHOW FIELDS FROM `photos` - SQL (0.001524) SHOW FIELDS FROM `cameras` - SQL (0.000112) SET SQL_AUTO_IS_NULL=0 - SQL (0.016053) SHOW FIELDS FROM `users` - SQL (0.001843) SHOW FIELDS FROM `photos` - SQL (0.001493) SHOW FIELDS FROM `cameras` - SQL (0.001376) SHOW FIELDS FROM `users` - SQL (0.001547) SHOW FIELDS FROM `photos` - SQL (0.001670) SHOW FIELDS FROM `cameras` - SQL (0.001504) SHOW FIELDS FROM `users` - SQL (0.001756) SHOW FIELDS FROM `photos` - SQL (0.001567) SHOW FIELDS FROM `cameras` - SQL (0.001476) SHOW FIELDS FROM `users` - SQL (0.001574) SHOW FIELDS FROM `photos` - SQL (0.001402) SHOW FIELDS FROM `cameras` - SQL (0.001565) SHOW FIELDS FROM `users` - SQL (0.001346) SHOW FIELDS FROM `photos` - SQL (0.001424) SHOW FIELDS FROM `cameras` - SQL (0.001447) SHOW FIELDS FROM `users` - SQL (0.001570) SHOW FIELDS FROM `photos` - SQL (0.001502) SHOW FIELDS FROM `cameras` - SQL (0.000244) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001413) SHOW FIELDS FROM `users` - SQL (0.000304) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001471) SHOW FIELDS FROM `photos` - SQL (0.034694) SHOW FIELDS FROM `users` - SQL (0.001709) SHOW FIELDS FROM `photos` - SQL (0.001407) SHOW FIELDS FROM `cameras` - SQL (0.000109) SET SQL_AUTO_IS_NULL=0 - SQL (0.010677) SHOW FIELDS FROM `users` - SQL (0.002292) SHOW FIELDS FROM `photos` - SQL (0.001455) SHOW FIELDS FROM `cameras` - SQL (0.001467) SHOW FIELDS FROM `users` - SQL (0.001537) SHOW FIELDS FROM `photos` - SQL (0.001429) SHOW FIELDS FROM `cameras` - SQL (0.001476) SHOW FIELDS FROM `users` - SQL (0.001679) SHOW FIELDS FROM `photos` - SQL (0.001440) SHOW FIELDS FROM `cameras` - SQL (0.001147) SHOW FIELDS FROM `users` - SQL (0.001687) SHOW FIELDS FROM `photos` - SQL (0.001424) SHOW FIELDS FROM `cameras` - SQL (0.001509) SHOW FIELDS FROM `users` - SQL (0.001622) SHOW FIELDS FROM `photos` - SQL (0.001417) SHOW FIELDS FROM `cameras` - SQL (0.001430) SHOW FIELDS FROM `users` - SQL (0.001540) SHOW FIELDS FROM `photos` - SQL (0.001420) SHOW FIELDS FROM `cameras` - SQL (0.000244) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001374) SHOW FIELDS FROM `users` - SQL (0.000288) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001449) SHOW FIELDS FROM `photos` - SQL (0.034463) SHOW FIELDS FROM `users` - SQL (0.001751) SHOW FIELDS FROM `photos` - SQL (0.002051) SHOW FIELDS FROM `cameras` - SQL (0.000108) SET SQL_AUTO_IS_NULL=0 - SQL (0.010738) SHOW FIELDS FROM `users` - SQL (0.002251) SHOW FIELDS FROM `photos` - SQL (0.001306) SHOW FIELDS FROM `cameras` - SQL (0.001717) SHOW FIELDS FROM `users` - SQL (0.001554) SHOW FIELDS FROM `photos` - SQL (0.001364) SHOW FIELDS FROM `cameras` - SQL (0.001622) SHOW FIELDS FROM `users` - SQL (0.001490) SHOW FIELDS FROM `photos` - SQL (0.001310) SHOW FIELDS FROM `cameras` - SQL (0.001666) SHOW FIELDS FROM `users` - SQL (0.002175) SHOW FIELDS FROM `photos` - SQL (0.001601) SHOW FIELDS FROM `cameras` - SQL (0.001647) SHOW FIELDS FROM `users` - SQL (0.002284) SHOW FIELDS FROM `photos` - SQL (0.001156) SHOW FIELDS FROM `cameras` - SQL (0.001447) SHOW FIELDS FROM `users` - SQL (0.001549) SHOW FIELDS FROM `photos` - SQL (0.001431) SHOW FIELDS FROM `cameras` - SQL (0.000391) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001439) SHOW FIELDS FROM `users` - SQL (0.000284) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001431) SHOW FIELDS FROM `photos` - SQL (0.036129) SHOW FIELDS FROM `users` - SQL (0.001678) SHOW FIELDS FROM `photos` - SQL (0.001446) SHOW FIELDS FROM `cameras` - SQL (0.000111) SET SQL_AUTO_IS_NULL=0 - SQL (0.010686) SHOW FIELDS FROM `users` - SQL (0.002498) SHOW FIELDS FROM `photos` - SQL (0.001549) SHOW FIELDS FROM `cameras` - SQL (0.001496) SHOW FIELDS FROM `users` - SQL (0.001586) SHOW FIELDS FROM `photos` - SQL (0.001451) SHOW FIELDS FROM `cameras` - SQL (0.001455) SHOW FIELDS FROM `users` - SQL (0.001648) SHOW FIELDS FROM `photos` - SQL (0.001364) SHOW FIELDS FROM `cameras` - SQL (0.001406) SHOW FIELDS FROM `users` - SQL (0.001501) SHOW FIELDS FROM `photos` - SQL (0.001399) SHOW FIELDS FROM `cameras` - SQL (0.001388) SHOW FIELDS FROM `users` - SQL (0.001888) SHOW FIELDS FROM `photos` - SQL (0.001454) SHOW FIELDS FROM `cameras` - SQL (0.001570) SHOW FIELDS FROM `users` - SQL (0.002665) SHOW FIELDS FROM `photos` - SQL (0.001922) SHOW FIELDS FROM `cameras` - SQL (0.001160) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001117) SHOW FIELDS FROM `users` - SQL (0.001219) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001255) SHOW FIELDS FROM `photos` - SQL (0.034678) SHOW FIELDS FROM `users` - SQL (0.001684) SHOW FIELDS FROM `photos` - SQL (0.001242) SHOW FIELDS FROM `cameras` - SQL (0.000110) SET SQL_AUTO_IS_NULL=0 - SQL (0.010673) SHOW FIELDS FROM `users` - SQL (0.002380) SHOW FIELDS FROM `photos` - SQL (0.001444) SHOW FIELDS FROM `cameras` - SQL (0.001580) SHOW FIELDS FROM `users` - SQL (0.001158) SHOW FIELDS FROM `photos` - SQL (0.001358) SHOW FIELDS FROM `cameras` - SQL (0.002625) SHOW FIELDS FROM `users` - SQL (0.002378) SHOW FIELDS FROM `photos` - SQL (0.001774) SHOW FIELDS FROM `cameras` - SQL (0.002249) SHOW FIELDS FROM `users` - SQL (0.001218) SHOW FIELDS FROM `photos` - SQL (0.002117) SHOW FIELDS FROM `cameras` - SQL (0.001795) SHOW FIELDS FROM `users` - SQL (0.002656) SHOW FIELDS FROM `photos` - SQL (0.001412) SHOW FIELDS FROM `cameras` - SQL (0.001415) SHOW FIELDS FROM `users` - SQL (0.001519) SHOW FIELDS FROM `photos` - SQL (0.001043) SHOW FIELDS FROM `cameras` - SQL (0.000346) SELECT * -FROM users -WHERE users.id = 1 - User Columns (0.001560) SHOW FIELDS FROM `users` - SQL (0.000297) SELECT photos.user_id, photos.camera_id, photos.id -FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id -WHERE users.id = 1 - Photo Columns (0.001471) SHOW FIELDS FROM `photos` - SQL (0.001420) SHOW FIELDS FROM `users` - SQL (0.001463) SHOW FIELDS FROM `photos` - SQL (0.001395) SHOW FIELDS FROM `cameras` diff --git a/spec/integration/scratch_spec.rb b/spec/integration/scratch_spec.rb index 32ee98d361938..b5d27f1dc2522 100644 --- a/spec/integration/scratch_spec.rb +++ b/spec/integration/scratch_spec.rb @@ -1,42 +1,226 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper') -describe 'Relational Algebra' do +describe 'ActiveRelation', 'Proposed refactoring to ActiveRecord, introducing both a SQL + builder and a Relational Algebra to mediate connections + between ActiveRecord and the database. The goal of the + refactoring is to remove code duplication concerning AR + associations; remove complexity surrounding eager loading; + comprehensively solve quoting issues; remove the with_scope + merging logic; minimize the need for with_scope in general; + simplify the implementation of plugins like HasFinder and + ActsAsParanoid; introduce an identity map; and allow for + query optimization. All this while effectively not changing + the public interface of ActiveRecord. + The Relational Algebra makes these ambitious goals + possible. There\'s no need to be scared by the math, it\'s + actually quite simple. Relational Algebras have some nice + advantages over flexible SQL builders like Sequel and and + SqlAlchemy (a beautiful Python library). Principally, a + relation is writable as well as readable. This obviates the + :create with_scope, and perhaps also + #set_belongs_to_association_for. + With so much complexity removed from ActiveRecord, I + propose a mild reconsideration of the architecture of Base, + AssocationProxy, AssociationCollection, and so forth. These + should all be understood as \'Repositories\': a factory that + given a relation can manufacture objects, and given an object + can manipulate a relation. This may sound trivial, but I + think it has the potential to make the code much smaller and + more consistent.' do before do - @users = TableRelation.new(:users) - @photos = TableRelation.new(:photos) - @cameras = TableRelation.new(:cameras) - @user = @users.select(@users[:id] == 1) - @user_photos = (@user << @photos).on(@user[:id] == @photos[:user_id]) - @user_cameras = (@user_photos << @cameras).on(@user_photos[:camera_id] == @cameras[:id]) + class User < ActiveRecord::Base; has_many :photos end + class Photo < ActiveRecord::Base; belongs_to :camera end + class Camera < ActiveRecord::Base; end end - it 'simulates User.has_many :photos' do - @user_photos.project(*@photos.attributes).to_s.should be_like(""" - SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - LEFT OUTER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - WHERE - `users`.`id` = 1 - """) + before do + # Rather than being associated with a table, an ActiveRecord is now associated with + # a relation. + @users = User.relation + @photos = Photo.relation + @cameras = Camera.relation + # A first taste of a Relational Algebra: User.find(1) + # == is overridden on attributes to return a predicate, not true or false + @user = @users.select(@users[:id] == 1) + end + + # In a Relational Algebra, the various ActiveRecord associations become a simple + # mapping from one relation to another. The Reflection object parameterizes the + # mapping. + def user_has_many_photos(user_relation) + primary_key = User.reflections[:photos].klass.primary_key.to_sym + foreign_key = User.reflections[:photos].primary_key_name.to_sym + + # << is the left outer join operator + (user_relation << @photos).on(user_relation[primary_key] == @photos[foreign_key]) + end + + def photo_belongs_to_camera(photo_relation) + primary_key = Photo.reflections[:camera].klass.primary_key.to_sym + foreign_key = Photo.reflections[:camera].primary_key_name.to_sym + + (photo_relation << @cameras).on(photo_relation[foreign_key] == @cameras[primary_key]) end + + describe 'Relational Algebra', 'a relational algebra allows the implementation of + associations like has_many to be specified once, + regardless of eager-joins, has_many :through, and so + forth' do + it 'generates the query for User.has_many :photos' do + user_photos = user_has_many_photos(@user) + # the 'project' operator limits the columns that come back from the query. + # Note how all the operators are compositional: 'project' is applied to a query + # that previously had been joined and selected. + user_photos.project(*@photos.attributes).to_s.should be_like(""" + SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + LEFT OUTER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + WHERE + `users`.`id` = 1 + """) + # Also note the correctly quoted columns and tables. In this instance the + # MysqlAdapter from ActiveRecord is used to do the escaping. + end - it 'simulates a User.has_many :cameras :through => :photos' do - @user_cameras.project(*@cameras.attributes).to_s.should be_like(""" - SELECT `cameras`.`id` - FROM `users` - LEFT OUTER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - LEFT OUTER JOIN `cameras` - ON `photos`.`camera_id` = `cameras`.`id` - WHERE - `users`.`id` = 1 - """) + it 'generates the query for User.has_many :cameras :through => :photos' do + # note, again, the compositionality of the operators: + user_cameras = photo_belongs_to_camera(user_has_many_photos(@user)) + user_cameras.project(*@cameras.attributes).to_s.should be_like(""" + SELECT `cameras`.`id` + FROM `users` + LEFT OUTER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + LEFT OUTER JOIN `cameras` + ON `photos`.`camera_id` = `cameras`.`id` + WHERE + `users`.`id` = 1 + """) + end + + it 'generates the query for an eager join for a collection using the same logic as + for an association on an individual row' do + users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)) + users_cameras.to_s.should be_like(""" + SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`, `cameras`.`id` + FROM `users` + LEFT OUTER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + LEFT OUTER JOIN `cameras` + ON `photos`.`camera_id` = `cameras`.`id` + """) + end + + it 'is trivial to disambiguate columns' do + users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify + users_cameras.to_s.should be_like(""" + SELECT `users`.`name` AS 'users.name', `users`.`id` AS 'users.id', `photos`.`id` AS 'photos.id', `photos`.`user_id` AS 'photos.user_id', `photos`.`camera_id` AS 'photos.camera_id', `cameras`.`id` AS 'cameras.id' + FROM `users` + LEFT OUTER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + LEFT OUTER JOIN `cameras` + ON `photos`.`camera_id` = `cameras`.`id` + """) + end + + it 'obviates the need for with_scope merging logic since, e.g., + `with_scope :conditions => ...` is just a #select operation on the relation' do + end + + it 'may eliminate the need for with_scope altogether since the associations no longer + need it: the relation underlying the association fully encapsulates the scope' do + end end + + describe 'Repository', 'ActiveRecord::Base, HasManyAssociation, and so forth are + all repositories: given a relation, they manufacture objects' do + before do + class << ActiveRecord::Base; public :instantiate end + end - it '' do - # p @user_cameras.qualify.to_s - # - # @users.rename() + it 'manufactures objects' do + User.instantiate(@users.first).attributes.should == {"name" => "hai", "id" => 1} + end + + it 'frees ActiveRecords from being tied to tables' do + pending # pending, but trivial to implement: + + class User < ActiveRecord::Base + # acts_as_paranoid without alias_method_chain: + set_relation @users.select(@users[:deleted_at] != nil) + end + + class Person < ActiveRecord::Base + set_relation @accounts.join(@profiles).on(@accounts[:id] == @profiles[:account_id]) + end + # I know this sounds crazy, but even writes are possible in the last example. + # calling #save on a person can write to two tables! + end + + describe 'the n+1 problem' do + describe 'the eager join algorithm is vastly simpler' do + it 'three active records are loaded with only one query' do + # using 'rr' mocking framework: the real #select_all is called, but we assert + # that it only happens once: + mock.proxy(ActiveRecord::Base.connection).select_all.with_any_args.once + users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify + user = User.instantiate(users_cameras.first, [:photos => [:camera]]) + user.photos.first.camera.attributes.should == {"id" => 1} + end + + before do + class << ActiveRecord::Base + # An identity map makes this algorithm efficient. + def instantiate_with_cache(record) + cache.get(record) { instantiate_without_cache(record) } + end + alias_method_chain :instantiate, :cache + + # for each row in the result set, which may contain data from n tables, + # - instantiate that slice of the data corresponding to the current class + # - recusively walk the dependency chain and repeat. + def instantiate_with_joins(data, joins = []) + record = unqualify(data) + returning instantiate_without_joins(record) do |object| + joins.each do |join| + case join + when Symbol + object.send(association = join).instantiate(data) + when Hash + join.each do |association, nested_associations| + object.send(association).instantiate(data, nested_associations) + end + end + end + end + end + alias_method_chain :instantiate, :joins + + private + # Sometimes, attributes are qualified to remove ambiguity. Here, bring back + # ambiguity by translating 'users.id' to 'id' so we can call #attributes=. + # This code should work correctly if the attributes are qualified or not. + def unqualify(qualified_attributes) + qualified_attributes_for_this_class = qualified_attributes. \ + slice(*relation.attributes.collect(&:qualified_name)) + qualified_attributes_for_this_class.alias do |qualified_name| + qualified_name.split('.')[1] || qualified_name # the latter means it must not really be qualified + end + end + end + end + + it "is possible to be smarter about eager loading. DataMapper is smart enough + to notice when you do users.each { |u| u.photos } and make this two queries + rather than n+1: the first invocation of #photos is lazy but it preloads + photos for all subsequent users. This is substantially easier with the + Algebra since we can do @user.join(@photos).on(...) and transform that to + @users.join(@photos).on(...), relying on the IdentityMap to eliminate + the n+1 problem. This is somewhat similar to ActiveRecordContext but it + works with every association type, not just belongs_to." do + pending + end + end + end end end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index edace54f589b9..8d90e0dd51808 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,6 @@ require 'rubygems' require 'spec' +require 'rr' require File.join(File.dirname(__FILE__), '..', 'lib', 'sql_algebra') require File.join(File.dirname(__FILE__), 'spec_helpers', 'be_like') @@ -24,4 +25,5 @@ def shift Spec::Runner.configure do |config| config.include(BeLikeMatcher) + config.mock_with :rr end \ No newline at end of file diff --git a/spec/sql_builder/conditions_spec.rb b/spec/sql_builder/conditions_spec.rb index c1cae902c1a1d..dc44cedc85acd 100644 --- a/spec/sql_builder/conditions_spec.rb +++ b/spec/sql_builder/conditions_spec.rb @@ -10,7 +10,7 @@ column(:c, :d, 'e') end end.to_s.should be_like(""" - `a`.`b` = 'e' + `a`.`b` = `c`.`d` """) end end diff --git a/spec/sql_builder/select_builder_spec.rb b/spec/sql_builder/select_builder_spec.rb index 060c642c1b2dc..122539967e51a 100644 --- a/spec/sql_builder/select_builder_spec.rb +++ b/spec/sql_builder/select_builder_spec.rb @@ -87,7 +87,7 @@ end.to_s.should be_like(""" SELECT * FROM `users` - ORDER BY `users`.`id`, 'alias' + ORDER BY `users`.`id`, `users`.`created_at` """) end end From 311f5f8eb588d4cde051762ace87a61425300bec Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 7 Jan 2008 18:37:20 -0800 Subject: [PATCH 0019/1492] minor --- eager include.txt | 49 ---------- lib/active_relation.rb | 56 +++++++++++ .../extensions/array.rb | 0 .../extensions/base.rb | 0 .../extensions/hash.rb | 6 ++ .../extensions/object.rb | 0 .../extensions/range.rb | 0 .../predicates/binary_predicate.rb | 0 .../predicates/equality_predicate.rb | 0 .../greater_than_or_equal_to_predicate.rb | 0 .../predicates/greater_than_predicate.rb | 0 .../less_than_or_equal_to_predicate.rb | 0 .../predicates/less_than_predicate.rb | 0 .../predicates/match_predicate.rb | 0 .../predicates/predicate.rb | 0 .../predicates/range_inclusion_predicate.rb | 0 .../relation_inclusion_predicate.rb | 0 .../relations/attribute.rb | 0 .../relations/compound_relation.rb | 3 + .../relations/deletion_relation.rb | 22 +++++ .../relations/inner_join_operation.rb | 0 .../relations/inner_join_relation.rb | 0 .../relations/insertion_relation.rb | 29 ++++++ .../relations/join.rb | 0 .../relations/join_operation.rb | 0 .../relations/join_relation.rb | 0 .../relations/left_outer_join_operation.rb | 0 .../relations/left_outer_join_relation.rb | 0 .../relations/order_relation.rb | 0 .../relations/projection_relation.rb | 0 .../relations/range_relation.rb | 0 .../relations/relation.rb | 10 +- .../relations/rename_relation.rb | 0 .../relations/selection_relation.rb | 2 +- .../relations/table_relation.rb | 0 .../sql_builder/columns_builder.rb | 16 ++++ .../sql_builder/conditions_builder.rb | 4 + .../sql_builder/delete_builder.rb | 32 +++++++ .../sql_builder/equals_condition_builder.rb | 0 .../sql_builder/inner_join_builder.rb | 0 .../sql_builder/insert_builder.rb | 41 +++++++++ .../sql_builder/join_builder.rb | 0 .../sql_builder/joins_builder.rb | 0 .../sql_builder/left_outer_join_builder.rb | 0 .../sql_builder/order_builder.rb | 0 .../sql_builder/select_builder.rb | 3 +- .../sql_builder/selects_builder.rb | 9 ++ .../sql_builder/sql_builder.rb | 0 .../sql_builder/values_builder.rb | 16 ++++ lib/sql_algebra.rb | 49 ---------- .../relations/compound_relation.rb | 3 - .../sql_builder/selects_builder.rb | 20 ---- .../integration/scratch_spec.rb | 87 +++++++++++++----- .../predicates/binary_predicate_spec.rb | 2 +- .../predicates/equality_predicate_spec.rb | 2 +- .../relation_inclusion_predicate_spec.rb | 2 +- .../relations/attribute_spec.rb | 2 +- .../relations/deletion_relation_spec.rb | 22 +++++ .../relations/insertion_relation_spec.rb | 37 ++++++++ .../relations/join_operation_spec.rb | 6 +- .../relations/join_relation_spec.rb | 2 +- .../relations/order_relation_spec.rb | 2 +- .../relations/projection_relation_spec.rb | 2 +- .../relations/range_relation_spec.rb | 2 +- .../relations/relation_spec.rb | 92 +++++++++++++++++++ .../relations/rename_relation_spec.rb | 2 +- .../relations/selection_relation_spec.rb | 2 +- .../relations/table_relation_spec.rb | 2 +- .../sql_builder/conditions_spec.rb | 2 +- .../sql_builder/delete_builder_spec.rb | 22 +++++ .../sql_builder/insert_builder_spec.rb | 24 +++++ .../sql_builder/select_builder_spec.rb | 39 +++++++- spec/debug.log | 1 - spec/extensions/range_spec.rb | 1 - spec/integration/debug.log | 0 spec/{spec_helpers => matchers}/be_like.rb | 0 spec/relations/relation_spec.rb | 72 --------------- spec/spec_helper.rb | 7 +- 78 files changed, 566 insertions(+), 238 deletions(-) delete mode 100644 eager include.txt create mode 100644 lib/active_relation.rb rename lib/{sql_algebra => active_relation}/extensions/array.rb (100%) rename lib/{sql_algebra => active_relation}/extensions/base.rb (100%) rename lib/{sql_algebra => active_relation}/extensions/hash.rb (56%) rename lib/{sql_algebra => active_relation}/extensions/object.rb (100%) rename lib/{sql_algebra => active_relation}/extensions/range.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/binary_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/equality_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/greater_than_or_equal_to_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/greater_than_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/less_than_or_equal_to_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/less_than_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/match_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/range_inclusion_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/predicates/relation_inclusion_predicate.rb (100%) rename lib/{sql_algebra => active_relation}/relations/attribute.rb (100%) create mode 100644 lib/active_relation/relations/compound_relation.rb create mode 100644 lib/active_relation/relations/deletion_relation.rb rename lib/{sql_algebra => active_relation}/relations/inner_join_operation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/inner_join_relation.rb (100%) create mode 100644 lib/active_relation/relations/insertion_relation.rb rename lib/{sql_algebra => active_relation}/relations/join.rb (100%) rename lib/{sql_algebra => active_relation}/relations/join_operation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/join_relation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/left_outer_join_operation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/left_outer_join_relation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/order_relation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/projection_relation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/range_relation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/relation.rb (90%) rename lib/{sql_algebra => active_relation}/relations/rename_relation.rb (100%) rename lib/{sql_algebra => active_relation}/relations/selection_relation.rb (91%) rename lib/{sql_algebra => active_relation}/relations/table_relation.rb (100%) create mode 100644 lib/active_relation/sql_builder/columns_builder.rb rename lib/{sql_algebra => active_relation}/sql_builder/conditions_builder.rb (83%) create mode 100644 lib/active_relation/sql_builder/delete_builder.rb rename lib/{sql_algebra => active_relation}/sql_builder/equals_condition_builder.rb (100%) rename lib/{sql_algebra => active_relation}/sql_builder/inner_join_builder.rb (100%) create mode 100644 lib/active_relation/sql_builder/insert_builder.rb rename lib/{sql_algebra => active_relation}/sql_builder/join_builder.rb (100%) rename lib/{sql_algebra => active_relation}/sql_builder/joins_builder.rb (100%) rename lib/{sql_algebra => active_relation}/sql_builder/left_outer_join_builder.rb (100%) rename lib/{sql_algebra => active_relation}/sql_builder/order_builder.rb (100%) rename lib/{sql_algebra => active_relation}/sql_builder/select_builder.rb (93%) create mode 100644 lib/active_relation/sql_builder/selects_builder.rb rename lib/{sql_algebra => active_relation}/sql_builder/sql_builder.rb (100%) create mode 100644 lib/active_relation/sql_builder/values_builder.rb delete mode 100644 lib/sql_algebra.rb delete mode 100644 lib/sql_algebra/relations/compound_relation.rb delete mode 100644 lib/sql_algebra/sql_builder/selects_builder.rb rename spec/{ => active_relation}/integration/scratch_spec.rb (75%) rename spec/{ => active_relation}/predicates/binary_predicate_spec.rb (95%) rename spec/{ => active_relation}/predicates/equality_predicate_spec.rb (92%) rename spec/{ => active_relation}/predicates/relation_inclusion_predicate_spec.rb (88%) rename spec/{ => active_relation}/relations/attribute_spec.rb (97%) create mode 100644 spec/active_relation/relations/deletion_relation_spec.rb create mode 100644 spec/active_relation/relations/insertion_relation_spec.rb rename spec/{ => active_relation}/relations/join_operation_spec.rb (82%) rename spec/{ => active_relation}/relations/join_relation_spec.rb (96%) rename spec/{ => active_relation}/relations/order_relation_spec.rb (94%) rename spec/{ => active_relation}/relations/projection_relation_spec.rb (94%) rename spec/{ => active_relation}/relations/range_relation_spec.rb (93%) create mode 100644 spec/active_relation/relations/relation_spec.rb rename spec/{ => active_relation}/relations/rename_relation_spec.rb (96%) rename spec/{ => active_relation}/relations/selection_relation_spec.rb (96%) rename spec/{ => active_relation}/relations/table_relation_spec.rb (91%) rename spec/{ => active_relation}/sql_builder/conditions_spec.rb (83%) create mode 100644 spec/active_relation/sql_builder/delete_builder_spec.rb create mode 100644 spec/active_relation/sql_builder/insert_builder_spec.rb rename spec/{ => active_relation}/sql_builder/select_builder_spec.rb (72%) delete mode 100644 spec/debug.log delete mode 100644 spec/extensions/range_spec.rb delete mode 100644 spec/integration/debug.log rename spec/{spec_helpers => matchers}/be_like.rb (100%) delete mode 100644 spec/relations/relation_spec.rb diff --git a/eager include.txt b/eager include.txt deleted file mode 100644 index 0c56323b40f5b..0000000000000 --- a/eager include.txt +++ /dev/null @@ -1,49 +0,0 @@ -User.find( :all, :include => { :photos => :camera } ) - -User.reflection[:photos].klass.reflection[:camera] - -users_photos_camera = User.relation << User.reflections[:photos].relation << Photo.reflections[:camera].relation - -users_photos_camera.each do |record| - User.bring_forth(record, :photos => :camera) -end - -def User.bring_forth(record, included = { :photos => :camera }) - user = @cache[ record % 'users.id' ] || User.instantiate(record % User.attributes) - user.photos.bring_forth(record, :camera) -end - -def User.photos.bring_forth(record, included = :camera) - photo = @cache[ record % 'photos.id' ] || Photo.instantiate(record % Photo.attributes) - photo.camera.bring_forth(record) -end - -def User.photos.camera.bring_forth(record, included = nil) - camera = @cache [ record % 'cameras.id' ] || Camera.instantiate(record % Camera.attributes) -end - -########################### - -# first, rename the attributes to remove ambiguity (analogous to c0_t0 stuff) -eager_loaded_user_cameras = @user_cameras.rename( - @user.attributes => @user.attributes.prefixed, - @photos.attributes => ..., - @cameras.attributes => ..., -) - -# second, bring forth!! -class Repository - def bring_forth(record, includes = []) - object = cache.get(record % klass.primary_key) { Klass.instantiate(record % Klass.attributes) } - includes.each do |include| - case include - when Symbol - object.send(association = include).bring_forth(record) - when Hash - include.each do |association, nested_associations| - object.send(association).bring_forth(record, nested_associations) - end - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation.rb b/lib/active_relation.rb new file mode 100644 index 0000000000000..0d7af7bfb8fdf --- /dev/null +++ b/lib/active_relation.rb @@ -0,0 +1,56 @@ +$LOAD_PATH.unshift(File.dirname(__FILE__)) + +require 'rubygems' +require 'activesupport' +require 'activerecord' + +require 'active_relation/relations/relation' +require 'active_relation/relations/compound_relation' +require 'active_relation/relations/table_relation' +require 'active_relation/relations/join_operation' +require 'active_relation/relations/inner_join_operation' +require 'active_relation/relations/left_outer_join_operation' +require 'active_relation/relations/join_relation' +require 'active_relation/relations/inner_join_relation' +require 'active_relation/relations/left_outer_join_relation' +require 'active_relation/relations/attribute' +require 'active_relation/relations/projection_relation' +require 'active_relation/relations/selection_relation' +require 'active_relation/relations/order_relation' +require 'active_relation/relations/range_relation' +require 'active_relation/relations/rename_relation' +require 'active_relation/relations/join' +require 'active_relation/relations/deletion_relation' +require 'active_relation/relations/insertion_relation' + +require 'active_relation/predicates/predicate' +require 'active_relation/predicates/binary_predicate' +require 'active_relation/predicates/equality_predicate' +require 'active_relation/predicates/less_than_predicate' +require 'active_relation/predicates/less_than_or_equal_to_predicate' +require 'active_relation/predicates/greater_than_predicate' +require 'active_relation/predicates/greater_than_or_equal_to_predicate' +require 'active_relation/predicates/range_inclusion_predicate' +require 'active_relation/predicates/relation_inclusion_predicate' +require 'active_relation/predicates/match_predicate' + +require 'active_relation/extensions/range' +require 'active_relation/extensions/object' +require 'active_relation/extensions/array' +require 'active_relation/extensions/base' +require 'active_relation/extensions/hash' + +require 'active_relation/sql_builder/sql_builder' +require 'active_relation/sql_builder/select_builder' +require 'active_relation/sql_builder/delete_builder' +require 'active_relation/sql_builder/insert_builder' +require 'active_relation/sql_builder/joins_builder' +require 'active_relation/sql_builder/join_builder' +require 'active_relation/sql_builder/inner_join_builder' +require 'active_relation/sql_builder/left_outer_join_builder' +require 'active_relation/sql_builder/equals_condition_builder' +require 'active_relation/sql_builder/conditions_builder' +require 'active_relation/sql_builder/order_builder' +require 'active_relation/sql_builder/columns_builder' +require 'active_relation/sql_builder/selects_builder' +require 'active_relation/sql_builder/values_builder' \ No newline at end of file diff --git a/lib/sql_algebra/extensions/array.rb b/lib/active_relation/extensions/array.rb similarity index 100% rename from lib/sql_algebra/extensions/array.rb rename to lib/active_relation/extensions/array.rb diff --git a/lib/sql_algebra/extensions/base.rb b/lib/active_relation/extensions/base.rb similarity index 100% rename from lib/sql_algebra/extensions/base.rb rename to lib/active_relation/extensions/base.rb diff --git a/lib/sql_algebra/extensions/hash.rb b/lib/active_relation/extensions/hash.rb similarity index 56% rename from lib/sql_algebra/extensions/hash.rb rename to lib/active_relation/extensions/hash.rb index c83ee0d04f26f..f643ac17ab3e2 100644 --- a/lib/sql_algebra/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -4,4 +4,10 @@ def alias(&block) aliased.merge(yield(key) => value) end end + + def to_sql(builder = ValuesBuilder.new) + builder.call do + row *values + end + end end \ No newline at end of file diff --git a/lib/sql_algebra/extensions/object.rb b/lib/active_relation/extensions/object.rb similarity index 100% rename from lib/sql_algebra/extensions/object.rb rename to lib/active_relation/extensions/object.rb diff --git a/lib/sql_algebra/extensions/range.rb b/lib/active_relation/extensions/range.rb similarity index 100% rename from lib/sql_algebra/extensions/range.rb rename to lib/active_relation/extensions/range.rb diff --git a/lib/sql_algebra/predicates/binary_predicate.rb b/lib/active_relation/predicates/binary_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/binary_predicate.rb rename to lib/active_relation/predicates/binary_predicate.rb diff --git a/lib/sql_algebra/predicates/equality_predicate.rb b/lib/active_relation/predicates/equality_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/equality_predicate.rb rename to lib/active_relation/predicates/equality_predicate.rb diff --git a/lib/sql_algebra/predicates/greater_than_or_equal_to_predicate.rb b/lib/active_relation/predicates/greater_than_or_equal_to_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/greater_than_or_equal_to_predicate.rb rename to lib/active_relation/predicates/greater_than_or_equal_to_predicate.rb diff --git a/lib/sql_algebra/predicates/greater_than_predicate.rb b/lib/active_relation/predicates/greater_than_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/greater_than_predicate.rb rename to lib/active_relation/predicates/greater_than_predicate.rb diff --git a/lib/sql_algebra/predicates/less_than_or_equal_to_predicate.rb b/lib/active_relation/predicates/less_than_or_equal_to_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/less_than_or_equal_to_predicate.rb rename to lib/active_relation/predicates/less_than_or_equal_to_predicate.rb diff --git a/lib/sql_algebra/predicates/less_than_predicate.rb b/lib/active_relation/predicates/less_than_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/less_than_predicate.rb rename to lib/active_relation/predicates/less_than_predicate.rb diff --git a/lib/sql_algebra/predicates/match_predicate.rb b/lib/active_relation/predicates/match_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/match_predicate.rb rename to lib/active_relation/predicates/match_predicate.rb diff --git a/lib/sql_algebra/predicates/predicate.rb b/lib/active_relation/predicates/predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/predicate.rb rename to lib/active_relation/predicates/predicate.rb diff --git a/lib/sql_algebra/predicates/range_inclusion_predicate.rb b/lib/active_relation/predicates/range_inclusion_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/range_inclusion_predicate.rb rename to lib/active_relation/predicates/range_inclusion_predicate.rb diff --git a/lib/sql_algebra/predicates/relation_inclusion_predicate.rb b/lib/active_relation/predicates/relation_inclusion_predicate.rb similarity index 100% rename from lib/sql_algebra/predicates/relation_inclusion_predicate.rb rename to lib/active_relation/predicates/relation_inclusion_predicate.rb diff --git a/lib/sql_algebra/relations/attribute.rb b/lib/active_relation/relations/attribute.rb similarity index 100% rename from lib/sql_algebra/relations/attribute.rb rename to lib/active_relation/relations/attribute.rb diff --git a/lib/active_relation/relations/compound_relation.rb b/lib/active_relation/relations/compound_relation.rb new file mode 100644 index 0000000000000..fe92905d922b9 --- /dev/null +++ b/lib/active_relation/relations/compound_relation.rb @@ -0,0 +1,3 @@ +class CompoundRelation < Relation + delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :to => :relation +end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion_relation.rb b/lib/active_relation/relations/deletion_relation.rb new file mode 100644 index 0000000000000..e060efd5f90e8 --- /dev/null +++ b/lib/active_relation/relations/deletion_relation.rb @@ -0,0 +1,22 @@ +class DeletionRelation < CompoundRelation + attr_reader :relation + + def ==(other) + relation == other.relation + end + + def initialize(relation) + @relation = relation + end + + def to_sql(builder = DeleteBuilder.new) + builder.call do + delete + from table + where do + selects.each { |s| s.to_sql(self) } + end + end + end + +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/inner_join_operation.rb b/lib/active_relation/relations/inner_join_operation.rb similarity index 100% rename from lib/sql_algebra/relations/inner_join_operation.rb rename to lib/active_relation/relations/inner_join_operation.rb diff --git a/lib/sql_algebra/relations/inner_join_relation.rb b/lib/active_relation/relations/inner_join_relation.rb similarity index 100% rename from lib/sql_algebra/relations/inner_join_relation.rb rename to lib/active_relation/relations/inner_join_relation.rb diff --git a/lib/active_relation/relations/insertion_relation.rb b/lib/active_relation/relations/insertion_relation.rb new file mode 100644 index 0000000000000..84752d13f936b --- /dev/null +++ b/lib/active_relation/relations/insertion_relation.rb @@ -0,0 +1,29 @@ +class InsertionRelation < CompoundRelation + attr_reader :relation, :tuple + + def initialize(relation, tuple) + @relation, @tuple = relation, tuple + end + + def to_sql(builder = InsertBuilder.new) + builder.call do + insert + into table + columns do + tuple.keys.each { |attribute| attribute.to_sql(self) } + end + values do + inserts.each { |insert| insert.to_sql(self) } + end + end + end + + def ==(other) + relation == other.relation and tuple == other.tuple + end + + protected + def inserts + relation.inserts + [tuple] + end +end \ No newline at end of file diff --git a/lib/sql_algebra/relations/join.rb b/lib/active_relation/relations/join.rb similarity index 100% rename from lib/sql_algebra/relations/join.rb rename to lib/active_relation/relations/join.rb diff --git a/lib/sql_algebra/relations/join_operation.rb b/lib/active_relation/relations/join_operation.rb similarity index 100% rename from lib/sql_algebra/relations/join_operation.rb rename to lib/active_relation/relations/join_operation.rb diff --git a/lib/sql_algebra/relations/join_relation.rb b/lib/active_relation/relations/join_relation.rb similarity index 100% rename from lib/sql_algebra/relations/join_relation.rb rename to lib/active_relation/relations/join_relation.rb diff --git a/lib/sql_algebra/relations/left_outer_join_operation.rb b/lib/active_relation/relations/left_outer_join_operation.rb similarity index 100% rename from lib/sql_algebra/relations/left_outer_join_operation.rb rename to lib/active_relation/relations/left_outer_join_operation.rb diff --git a/lib/sql_algebra/relations/left_outer_join_relation.rb b/lib/active_relation/relations/left_outer_join_relation.rb similarity index 100% rename from lib/sql_algebra/relations/left_outer_join_relation.rb rename to lib/active_relation/relations/left_outer_join_relation.rb diff --git a/lib/sql_algebra/relations/order_relation.rb b/lib/active_relation/relations/order_relation.rb similarity index 100% rename from lib/sql_algebra/relations/order_relation.rb rename to lib/active_relation/relations/order_relation.rb diff --git a/lib/sql_algebra/relations/projection_relation.rb b/lib/active_relation/relations/projection_relation.rb similarity index 100% rename from lib/sql_algebra/relations/projection_relation.rb rename to lib/active_relation/relations/projection_relation.rb diff --git a/lib/sql_algebra/relations/range_relation.rb b/lib/active_relation/relations/range_relation.rb similarity index 100% rename from lib/sql_algebra/relations/range_relation.rb rename to lib/active_relation/relations/range_relation.rb diff --git a/lib/sql_algebra/relations/relation.rb b/lib/active_relation/relations/relation.rb similarity index 90% rename from lib/sql_algebra/relations/relation.rb rename to lib/active_relation/relations/relation.rb index 8efe0c7d9f5be..be6ee760a5e0e 100644 --- a/lib/sql_algebra/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -49,6 +49,14 @@ def order(*attributes) def rename(attribute, aliaz) RenameRelation.new(self, attribute => aliaz) end + + def insert(tuple) + InsertionRelation.new(self, tuple) + end + + def delete + DeletionRelation.new(self) + end end include Operations @@ -79,5 +87,5 @@ def attributes; [] end def joins; [] end def selects; [] end def orders; [] end - + def inserts; [] end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/rename_relation.rb b/lib/active_relation/relations/rename_relation.rb similarity index 100% rename from lib/sql_algebra/relations/rename_relation.rb rename to lib/active_relation/relations/rename_relation.rb diff --git a/lib/sql_algebra/relations/selection_relation.rb b/lib/active_relation/relations/selection_relation.rb similarity index 91% rename from lib/sql_algebra/relations/selection_relation.rb rename to lib/active_relation/relations/selection_relation.rb index dcf5f4745fb8b..77864efb285f3 100644 --- a/lib/sql_algebra/relations/selection_relation.rb +++ b/lib/active_relation/relations/selection_relation.rb @@ -16,6 +16,6 @@ def qualify protected def selects - [predicate] + relation.send(:selects) + [predicate] end end \ No newline at end of file diff --git a/lib/sql_algebra/relations/table_relation.rb b/lib/active_relation/relations/table_relation.rb similarity index 100% rename from lib/sql_algebra/relations/table_relation.rb rename to lib/active_relation/relations/table_relation.rb diff --git a/lib/active_relation/sql_builder/columns_builder.rb b/lib/active_relation/sql_builder/columns_builder.rb new file mode 100644 index 0000000000000..a8a5d0e4ca4a7 --- /dev/null +++ b/lib/active_relation/sql_builder/columns_builder.rb @@ -0,0 +1,16 @@ +class ColumnsBuilder < SqlBuilder + def initialize(&block) + @columns = [] + super(&block) + end + + def to_s + @columns.join(', ') + end + + def column(table, column, aliaz = nil) + @columns << "#{quote_table_name(table)}.#{quote_column_name(column)}" + end + + delegate :blank?, :to => :@columns +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/conditions_builder.rb b/lib/active_relation/sql_builder/conditions_builder.rb similarity index 83% rename from lib/sql_algebra/sql_builder/conditions_builder.rb rename to lib/active_relation/sql_builder/conditions_builder.rb index 5d42a36cecc76..60430f65d8a37 100644 --- a/lib/sql_algebra/sql_builder/conditions_builder.rb +++ b/lib/active_relation/sql_builder/conditions_builder.rb @@ -7,6 +7,10 @@ def initialize(&block) def equals(&block) @conditions << EqualsConditionBuilder.new(&block) end + + def value(value) + @conditions << value + end def to_s @conditions.join(' AND ') diff --git a/lib/active_relation/sql_builder/delete_builder.rb b/lib/active_relation/sql_builder/delete_builder.rb new file mode 100644 index 0000000000000..2e8be94dfe0fa --- /dev/null +++ b/lib/active_relation/sql_builder/delete_builder.rb @@ -0,0 +1,32 @@ +class DeleteBuilder < SqlBuilder + def delete + end + + def from(table) + @table = table + end + + def where(&block) + @conditions = ConditionsBuilder.new(&block) + end + + def to_s + [delete_clause, + from_clause, + where_clause + ].compact.join("\n") + end + + private + def delete_clause + "DELETE" + end + + def from_clause + "FROM #{quote_table_name(@table)}" + end + + def where_clause + "WHERE #{@conditions}" unless @conditions.blank? + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/equals_condition_builder.rb b/lib/active_relation/sql_builder/equals_condition_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/equals_condition_builder.rb rename to lib/active_relation/sql_builder/equals_condition_builder.rb diff --git a/lib/sql_algebra/sql_builder/inner_join_builder.rb b/lib/active_relation/sql_builder/inner_join_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/inner_join_builder.rb rename to lib/active_relation/sql_builder/inner_join_builder.rb diff --git a/lib/active_relation/sql_builder/insert_builder.rb b/lib/active_relation/sql_builder/insert_builder.rb new file mode 100644 index 0000000000000..09deefad1057b --- /dev/null +++ b/lib/active_relation/sql_builder/insert_builder.rb @@ -0,0 +1,41 @@ +class InsertBuilder < SqlBuilder + def insert + end + + def into(table) + @table = table + end + + def columns(&block) + @columns = ColumnsBuilder.new(&block) + end + + def values(&block) + @values = ValuesBuilder.new(&block) + end + + def to_s + [insert_clause, + into_clause, + columns_clause, + values_clause + ].compact.join("\n") + end + + private + def insert_clause + "INSERT" + end + + def into_clause + "INTO #{quote_table_name(@table)}" + end + + def values_clause + "VALUES #{@values}" unless @values.blank? + end + + def columns_clause + "(#{@columns})" unless @columns.blank? + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/join_builder.rb b/lib/active_relation/sql_builder/join_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/join_builder.rb rename to lib/active_relation/sql_builder/join_builder.rb diff --git a/lib/sql_algebra/sql_builder/joins_builder.rb b/lib/active_relation/sql_builder/joins_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/joins_builder.rb rename to lib/active_relation/sql_builder/joins_builder.rb diff --git a/lib/sql_algebra/sql_builder/left_outer_join_builder.rb b/lib/active_relation/sql_builder/left_outer_join_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/left_outer_join_builder.rb rename to lib/active_relation/sql_builder/left_outer_join_builder.rb diff --git a/lib/sql_algebra/sql_builder/order_builder.rb b/lib/active_relation/sql_builder/order_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/order_builder.rb rename to lib/active_relation/sql_builder/order_builder.rb diff --git a/lib/sql_algebra/sql_builder/select_builder.rb b/lib/active_relation/sql_builder/select_builder.rb similarity index 93% rename from lib/sql_algebra/sql_builder/select_builder.rb rename to lib/active_relation/sql_builder/select_builder.rb index 9a85ad7eec705..57116cb64b52d 100644 --- a/lib/sql_algebra/sql_builder/select_builder.rb +++ b/lib/active_relation/sql_builder/select_builder.rb @@ -9,8 +9,7 @@ def from(table, &block) end def where(&block) - @conditions ||= ConditionsBuilder.new - @conditions.call(&block) + @conditions = ConditionsBuilder.new(&block) end def order_by(&block) diff --git a/lib/active_relation/sql_builder/selects_builder.rb b/lib/active_relation/sql_builder/selects_builder.rb new file mode 100644 index 0000000000000..6ad06d0ae4e2b --- /dev/null +++ b/lib/active_relation/sql_builder/selects_builder.rb @@ -0,0 +1,9 @@ +class SelectsBuilder < ColumnsBuilder + def all + @columns << :* + end + + def column(table, column, aliaz = nil) + @columns << "#{quote_table_name(table)}.#{quote_column_name(column)}" + (aliaz ? " AS #{quote(aliaz)}" : '') + end +end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/sql_builder.rb b/lib/active_relation/sql_builder/sql_builder.rb similarity index 100% rename from lib/sql_algebra/sql_builder/sql_builder.rb rename to lib/active_relation/sql_builder/sql_builder.rb diff --git a/lib/active_relation/sql_builder/values_builder.rb b/lib/active_relation/sql_builder/values_builder.rb new file mode 100644 index 0000000000000..f22b1e507ed8b --- /dev/null +++ b/lib/active_relation/sql_builder/values_builder.rb @@ -0,0 +1,16 @@ +class ValuesBuilder < SqlBuilder + def initialize(&block) + @values = [] + super(&block) + end + + def row(*values) + @values << "(#{values.collect { |v| quote(v) }.join(', ')})" + end + + def to_s + @values.join(', ') + end + + delegate :blank?, :to => :@values +end \ No newline at end of file diff --git a/lib/sql_algebra.rb b/lib/sql_algebra.rb deleted file mode 100644 index fbd053541cae7..0000000000000 --- a/lib/sql_algebra.rb +++ /dev/null @@ -1,49 +0,0 @@ -$LOAD_PATH.unshift(File.dirname(__FILE__)) -require 'rubygems' -require 'activesupport' -require 'activerecord' - -require 'sql_algebra/relations/relation' -require 'sql_algebra/relations/compound_relation' -require 'sql_algebra/relations/table_relation' -require 'sql_algebra/relations/join_operation' -require 'sql_algebra/relations/inner_join_operation' -require 'sql_algebra/relations/left_outer_join_operation' -require 'sql_algebra/relations/join_relation' -require 'sql_algebra/relations/inner_join_relation' -require 'sql_algebra/relations/left_outer_join_relation' -require 'sql_algebra/relations/attribute' -require 'sql_algebra/relations/projection_relation' -require 'sql_algebra/relations/selection_relation' -require 'sql_algebra/relations/order_relation' -require 'sql_algebra/relations/range_relation' -require 'sql_algebra/relations/rename_relation' -require 'sql_algebra/relations/join' - -require 'sql_algebra/predicates/predicate' -require 'sql_algebra/predicates/binary_predicate' -require 'sql_algebra/predicates/equality_predicate' -require 'sql_algebra/predicates/less_than_predicate' -require 'sql_algebra/predicates/less_than_or_equal_to_predicate' -require 'sql_algebra/predicates/greater_than_predicate' -require 'sql_algebra/predicates/greater_than_or_equal_to_predicate' -require 'sql_algebra/predicates/range_inclusion_predicate' -require 'sql_algebra/predicates/relation_inclusion_predicate' -require 'sql_algebra/predicates/match_predicate' - -require 'sql_algebra/extensions/range' -require 'sql_algebra/extensions/object' -require 'sql_algebra/extensions/array' -require 'sql_algebra/extensions/base' -require 'sql_algebra/extensions/hash' - -require 'sql_algebra/sql_builder/sql_builder' -require 'sql_algebra/sql_builder/select_builder' -require 'sql_algebra/sql_builder/joins_builder' -require 'sql_algebra/sql_builder/join_builder' -require 'sql_algebra/sql_builder/inner_join_builder' -require 'sql_algebra/sql_builder/left_outer_join_builder' -require 'sql_algebra/sql_builder/equals_condition_builder' -require 'sql_algebra/sql_builder/conditions_builder' -require 'sql_algebra/sql_builder/order_builder' -require 'sql_algebra/sql_builder/selects_builder' \ No newline at end of file diff --git a/lib/sql_algebra/relations/compound_relation.rb b/lib/sql_algebra/relations/compound_relation.rb deleted file mode 100644 index a8e9a41b5e35f..0000000000000 --- a/lib/sql_algebra/relations/compound_relation.rb +++ /dev/null @@ -1,3 +0,0 @@ -class CompoundRelation < Relation - delegate :attributes, :attribute, :joins, :select, :orders, :table, :to => :relation -end \ No newline at end of file diff --git a/lib/sql_algebra/sql_builder/selects_builder.rb b/lib/sql_algebra/sql_builder/selects_builder.rb deleted file mode 100644 index ce6ee1eb678bb..0000000000000 --- a/lib/sql_algebra/sql_builder/selects_builder.rb +++ /dev/null @@ -1,20 +0,0 @@ -class SelectsBuilder < SqlBuilder - def initialize(&block) - @selects = [] - super(&block) - end - - def to_s - @selects.join(', ') - end - - def all - @selects << :* - end - - def column(table, column, aliaz = nil) - @selects << "#{quote_table_name(table)}.#{quote_column_name(column)}" + (aliaz ? " AS #{quote(aliaz)}" : '') - end - - delegate :blank?, :to => :@selects -end \ No newline at end of file diff --git a/spec/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb similarity index 75% rename from spec/integration/scratch_spec.rb rename to spec/active_relation/integration/scratch_spec.rb index b5d27f1dc2522..fba587e4ba177 100644 --- a/spec/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -1,16 +1,16 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe 'ActiveRelation', 'Proposed refactoring to ActiveRecord, introducing both a SQL - builder and a Relational Algebra to mediate connections - between ActiveRecord and the database. The goal of the - refactoring is to remove code duplication concerning AR - associations; remove complexity surrounding eager loading; - comprehensively solve quoting issues; remove the with_scope - merging logic; minimize the need for with_scope in general; - simplify the implementation of plugins like HasFinder and - ActsAsParanoid; introduce an identity map; and allow for - query optimization. All this while effectively not changing - the public interface of ActiveRecord. +describe 'ActiveRelation', 'A proposed refactoring to ActiveRecord, introducing both a SQL + Builder and a Relational Algebra to mediate between + ActiveRecord and the database. The goal of the refactoring is + to remove code duplication concerning AR associations; remove + complexity surrounding eager loading; comprehensively solve + quoting issues; remove the with_scope merging logic; minimize + the need for with_scope in general; simplify the + implementation of plugins like HasFinder and ActsAsParanoid; + introduce an identity map; and allow for query optimization. + All this while remaining backwards-compatible with the + existing ActiveRecord interface. The Relational Algebra makes these ambitious goals possible. There\'s no need to be scared by the math, it\'s actually quite simple. Relational Algebras have some nice @@ -25,7 +25,7 @@ should all be understood as \'Repositories\': a factory that given a relation can manufacture objects, and given an object can manipulate a relation. This may sound trivial, but I - think it has the potential to make the code much smaller and + think it has the potential to make the code smaller and more consistent.' do before do class User < ActiveRecord::Base; has_many :photos end @@ -40,8 +40,8 @@ class Camera < ActiveRecord::Base; end @photos = Photo.relation @cameras = Camera.relation # A first taste of a Relational Algebra: User.find(1) - # == is overridden on attributes to return a predicate, not true or false @user = @users.select(@users[:id] == 1) + # == is overridden on attributes to return a predicate, not true or false end # In a Relational Algebra, the various ActiveRecord associations become a simple @@ -122,13 +122,47 @@ def photo_belongs_to_camera(photo_relation) ON `photos`.`camera_id` = `cameras`.`id` """) end + + it 'allows arbitrary sql to be passed through' do + (@users << @photos).on("asdf").to_s.should be_like(""" + SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + LEFT OUTER JOIN `photos` + ON asdf + """) + @users.select("asdf").to_s.should be_like(""" + SELECT `users`.`name`, `users`.`id` + FROM `users` + WHERE asdf + """) + end + + describe 'write operations' do + it 'generates the query for user.destroy' do + @user.delete.to_s.should be_like(""" + DELETE + FROM `users` + WHERE `users`.`id` = 1 + """) + end - it 'obviates the need for with_scope merging logic since, e.g., - `with_scope :conditions => ...` is just a #select operation on the relation' do + it 'generates an efficient query for two User.creates -- UnitOfWork is within reach!' do + @users.insert(@users[:name] => "humpty").insert(@users[:name] => "dumpty").to_s.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('humpty'), ('dumpty') + """) + end end + + describe 'with_scope' do + it 'obviates the need for with_scope merging logic since, e.g., + `with_scope :conditions => ...` is just a #select operation on the relation' do + end - it 'may eliminate the need for with_scope altogether since the associations no longer - need it: the relation underlying the association fully encapsulates the scope' do + it 'may eliminate the need for with_scope altogether since the associations no longer + need it: the relation underlying the association fully encapsulates the scope' do + end end end @@ -159,10 +193,11 @@ class Person < ActiveRecord::Base describe 'the n+1 problem' do describe 'the eager join algorithm is vastly simpler' do - it 'three active records are loaded with only one query' do + it 'loads three active records with only one query' do # using 'rr' mocking framework: the real #select_all is called, but we assert # that it only happens once: mock.proxy(ActiveRecord::Base.connection).select_all.with_any_args.once + users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify user = User.instantiate(users_cameras.first, [:photos => [:camera]]) user.photos.first.camera.attributes.should == {"id" => 1} @@ -216,11 +251,21 @@ def unqualify(qualified_attributes) photos for all subsequent users. This is substantially easier with the Algebra since we can do @user.join(@photos).on(...) and transform that to @users.join(@photos).on(...), relying on the IdentityMap to eliminate - the n+1 problem. This is somewhat similar to ActiveRecordContext but it - works with every association type, not just belongs_to." do + the n+1 problem." do pending end end end end + + describe 'The Architecture', 'I propose to produce a new gem, ActiveRelation, which encaplulates + the existing ActiveRecord Connection Adapter, the new SQL Builder, + and the Relational Algebra. ActiveRecord, then, should no longer + interact with the connection object directly.' do + end + + describe 'Miscellaneous Ideas' do + it 'may be easy to write a SQL parser that can take arbitrary SQL and produce a relation. + This has the advantage of permitting e.g., pagination with custom finder_sql' + end end \ No newline at end of file diff --git a/spec/predicates/binary_predicate_spec.rb b/spec/active_relation/predicates/binary_predicate_spec.rb similarity index 95% rename from spec/predicates/binary_predicate_spec.rb rename to spec/active_relation/predicates/binary_predicate_spec.rb index ede44e517518a..5de559df41231 100644 --- a/spec/predicates/binary_predicate_spec.rb +++ b/spec/active_relation/predicates/binary_predicate_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe BinaryPredicate do before do diff --git a/spec/predicates/equality_predicate_spec.rb b/spec/active_relation/predicates/equality_predicate_spec.rb similarity index 92% rename from spec/predicates/equality_predicate_spec.rb rename to spec/active_relation/predicates/equality_predicate_spec.rb index 75b495b6f7f1e..af43b754e093f 100644 --- a/spec/predicates/equality_predicate_spec.rb +++ b/spec/active_relation/predicates/equality_predicate_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe EqualityPredicate do before do diff --git a/spec/predicates/relation_inclusion_predicate_spec.rb b/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb similarity index 88% rename from spec/predicates/relation_inclusion_predicate_spec.rb rename to spec/active_relation/predicates/relation_inclusion_predicate_spec.rb index 6cd37fafa8dd3..f8c911429b351 100644 --- a/spec/predicates/relation_inclusion_predicate_spec.rb +++ b/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe RelationInclusionPredicate do before do diff --git a/spec/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb similarity index 97% rename from spec/relations/attribute_spec.rb rename to spec/active_relation/relations/attribute_spec.rb index 4887be38d2ccd..ddfc22fe280fa 100644 --- a/spec/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe Attribute do before do diff --git a/spec/active_relation/relations/deletion_relation_spec.rb b/spec/active_relation/relations/deletion_relation_spec.rb new file mode 100644 index 0000000000000..4f75a261f4835 --- /dev/null +++ b/spec/active_relation/relations/deletion_relation_spec.rb @@ -0,0 +1,22 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe DeletionRelation do + before do + @relation = TableRelation.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql deleting the relation' do + DeletionRelation.new(@relation.select(@relation[:id] == 1)).to_sql.to_s.should == DeleteBuilder.new do + delete + from :users + where do + equals do + column :users, :id + value 1 + end + end + end.to_s + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/insertion_relation_spec.rb b/spec/active_relation/relations/insertion_relation_spec.rb new file mode 100644 index 0000000000000..6bafabb473738 --- /dev/null +++ b/spec/active_relation/relations/insertion_relation_spec.rb @@ -0,0 +1,37 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe InsertionRelation do + before do + @relation = TableRelation.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql inserting the data for one item' do + InsertionRelation.new(@relation, @relation[:name] => "nick").to_sql.should == InsertBuilder.new do + insert + into :users + columns do + column :users, :name + end + values do + row "nick" + end + end + end + + it 'manufactures sql inserting the data for multiple items' do + nested_insertion = InsertionRelation.new(@relation, @relation[:name] => "cobra") + InsertionRelation.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.to_s.should == InsertBuilder.new do + insert + into :users + columns do + column :users, :name + end + values do + row "cobra" + row "commander" + end + end.to_s + end + end +end \ No newline at end of file diff --git a/spec/relations/join_operation_spec.rb b/spec/active_relation/relations/join_operation_spec.rb similarity index 82% rename from spec/relations/join_operation_spec.rb rename to spec/active_relation/relations/join_operation_spec.rb index db30198f6ec3b..a8ab85123b01e 100644 --- a/spec/relations/join_operation_spec.rb +++ b/spec/active_relation/relations/join_operation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe 'between two relations' do before do @@ -31,5 +31,9 @@ def relation_class it "manufactures a join relation of the appropriate type" do @join_operation.on(@predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) end + + it "accepts arbitrary strings" do + @join_operation.on("arbitrary").should == JoinRelation.new(@relation1, @relation2, "arbitrary") + end end end \ No newline at end of file diff --git a/spec/relations/join_relation_spec.rb b/spec/active_relation/relations/join_relation_spec.rb similarity index 96% rename from spec/relations/join_relation_spec.rb rename to spec/active_relation/relations/join_relation_spec.rb index ece7e61cc166c..d0be2708378c8 100644 --- a/spec/relations/join_relation_spec.rb +++ b/spec/active_relation/relations/join_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe JoinRelation do before do diff --git a/spec/relations/order_relation_spec.rb b/spec/active_relation/relations/order_relation_spec.rb similarity index 94% rename from spec/relations/order_relation_spec.rb rename to spec/active_relation/relations/order_relation_spec.rb index a78ac148e2f8c..17f730b564fd5 100644 --- a/spec/relations/order_relation_spec.rb +++ b/spec/active_relation/relations/order_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe OrderRelation do before do diff --git a/spec/relations/projection_relation_spec.rb b/spec/active_relation/relations/projection_relation_spec.rb similarity index 94% rename from spec/relations/projection_relation_spec.rb rename to spec/active_relation/relations/projection_relation_spec.rb index 5a33b16bd555d..164c4857610a6 100644 --- a/spec/relations/projection_relation_spec.rb +++ b/spec/active_relation/relations/projection_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe ProjectionRelation do before do diff --git a/spec/relations/range_relation_spec.rb b/spec/active_relation/relations/range_relation_spec.rb similarity index 93% rename from spec/relations/range_relation_spec.rb rename to spec/active_relation/relations/range_relation_spec.rb index 926cc0929f3ef..ac9f887d9b497 100644 --- a/spec/relations/range_relation_spec.rb +++ b/spec/active_relation/relations/range_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe RangeRelation do before do diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb new file mode 100644 index 0000000000000..9ed42a98cbd00 --- /dev/null +++ b/spec/active_relation/relations/relation_spec.rb @@ -0,0 +1,92 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe Relation do + before do + @relation1 = TableRelation.new(:foo) + @relation2 = TableRelation.new(:bar) + @attribute1 = Attribute.new(@relation1, :id) + @attribute2 = Attribute.new(@relation1, :name) + end + + describe '[]' do + it "manufactures an attribute when given a symbol" do + @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) + end + + it "manufactures a range relation when given a range" do + @relation1[1..2].should == RangeRelation.new(@relation1, 1..2) + end + end + + describe '#include?' do + it "manufactures an inclusion predicate" do + @relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1) + end + end + + describe 'read operations' do + describe 'joins' do + describe '<=>' do + it "manufactures an inner join operation between those two relations" do + (@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2) + end + end + + describe '<<' do + it "manufactures a left outer join operation between those two relations" do + (@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2) + end + end + end + + describe '#project' do + it "collapses identical projections" do + pending + end + + it "manufactures a projection relation" do + @relation1.project(@attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) + end + end + + describe '#rename' do + it "manufactures a rename relation" do + @relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1 => :foo) + end + end + + describe '#select' do + before do + @predicate = EqualityPredicate.new(@attribute1, @attribute2) + end + + it "manufactures a selection relation" do + @relation1.select(@predicate).should == SelectionRelation.new(@relation1, @predicate) + end + + it "accepts arbitrary strings" do + @relation1.select("arbitrary").should == SelectionRelation.new(@relation1, "arbitrary") + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) + end + end + end + + describe 'write operations' do + describe '#delete' do + it 'manufactures a deletion relation' do + @relation1.delete.should == DeletionRelation.new(@relation1) + end + end + + describe '#insert' do + it 'manufactures an insertion relation' do + @relation1.insert(tuple = {:id => 1}).should == InsertionRelation.new(@relation1, tuple) + end + end + end +end \ No newline at end of file diff --git a/spec/relations/rename_relation_spec.rb b/spec/active_relation/relations/rename_relation_spec.rb similarity index 96% rename from spec/relations/rename_relation_spec.rb rename to spec/active_relation/relations/rename_relation_spec.rb index 301ee6db9eae2..9b1d2d5cc8926 100644 --- a/spec/relations/rename_relation_spec.rb +++ b/spec/active_relation/relations/rename_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe RenameRelation do before do diff --git a/spec/relations/selection_relation_spec.rb b/spec/active_relation/relations/selection_relation_spec.rb similarity index 96% rename from spec/relations/selection_relation_spec.rb rename to spec/active_relation/relations/selection_relation_spec.rb index 656a386fd68bb..c4aadc807ba3e 100644 --- a/spec/relations/selection_relation_spec.rb +++ b/spec/active_relation/relations/selection_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe SelectionRelation do before do diff --git a/spec/relations/table_relation_spec.rb b/spec/active_relation/relations/table_relation_spec.rb similarity index 91% rename from spec/relations/table_relation_spec.rb rename to spec/active_relation/relations/table_relation_spec.rb index 038037234415e..c943fe6c9201d 100644 --- a/spec/relations/table_relation_spec.rb +++ b/spec/active_relation/relations/table_relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe TableRelation do before do diff --git a/spec/sql_builder/conditions_spec.rb b/spec/active_relation/sql_builder/conditions_spec.rb similarity index 83% rename from spec/sql_builder/conditions_spec.rb rename to spec/active_relation/sql_builder/conditions_spec.rb index dc44cedc85acd..dc2d10a2f6924 100644 --- a/spec/sql_builder/conditions_spec.rb +++ b/spec/active_relation/sql_builder/conditions_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe ConditionsBuilder do describe '#to_s' do diff --git a/spec/active_relation/sql_builder/delete_builder_spec.rb b/spec/active_relation/sql_builder/delete_builder_spec.rb new file mode 100644 index 0000000000000..fd62fde155354 --- /dev/null +++ b/spec/active_relation/sql_builder/delete_builder_spec.rb @@ -0,0 +1,22 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe DeleteBuilder do + describe '#to_s' do + it 'manufactures correct sql' do + DeleteBuilder.new do + delete + from :users + where do + equals do + column :users, :id + value 1 + end + end + end.to_s.should be_like(""" + DELETE + FROM `users` + WHERE `users`.`id` = 1 + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/sql_builder/insert_builder_spec.rb b/spec/active_relation/sql_builder/insert_builder_spec.rb new file mode 100644 index 0000000000000..dddc971986fb1 --- /dev/null +++ b/spec/active_relation/sql_builder/insert_builder_spec.rb @@ -0,0 +1,24 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe InsertBuilder do + describe '#to_s' do + it 'manufactures correct sql' do + InsertBuilder.new do + insert + into :users + columns do + column :users, :id + column :users, :name + end + values do + row 1, 'bob' + row 2, 'moe' + end + end.to_s.should be_like(""" + INSERT + INTO `users` + (`users`.`id`, `users`.`name`) VALUES (1, 'bob'), (2, 'moe') + """) + end + end +end \ No newline at end of file diff --git a/spec/sql_builder/select_builder_spec.rb b/spec/active_relation/sql_builder/select_builder_spec.rb similarity index 72% rename from spec/sql_builder/select_builder_spec.rb rename to spec/active_relation/sql_builder/select_builder_spec.rb index 122539967e51a..6539afe0c4425 100644 --- a/spec/sql_builder/select_builder_spec.rb +++ b/spec/active_relation/sql_builder/select_builder_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe SelectBuilder do describe '#to_s' do @@ -50,6 +50,22 @@ WHERE 1 = `b`.`c` """) end + + it 'accepts arbitrary strings' do + SelectBuilder.new do + select do + all + end + from :users + where do + value "'a' = 'a'" + end + end.to_s.should be_like(""" + SELECT * + FROM `users` + WHERE 'a' = 'a' + """) + end end describe 'with inner join' do @@ -68,7 +84,26 @@ end end.to_s.should be_like(""" SELECT * - FROM `users` INNER JOIN `friendships` ON `users`.`id` = `friendships`.`user_id` + FROM `users` + INNER JOIN `friendships` + ON `users`.`id` = `friendships`.`user_id` + """) + end + + it 'accepts arbitrary on strings' do + SelectBuilder.new do + select do + all + end + from :users do + inner_join :friendships do + value "arbitrary" + end + end + end.to_s.should be_like(""" + SELECT * + FROM `users` + INNER JOIN `friendships` ON arbitrary """) end end diff --git a/spec/debug.log b/spec/debug.log deleted file mode 100644 index d38ed11d82f66..0000000000000 --- a/spec/debug.log +++ /dev/null @@ -1 +0,0 @@ -# Logfile created on Tue Jan 01 17:49:28 -0800 2008 by logger.rb/1.5.2.9 diff --git a/spec/extensions/range_spec.rb b/spec/extensions/range_spec.rb deleted file mode 100644 index 26ca8978ca260..0000000000000 --- a/spec/extensions/range_spec.rb +++ /dev/null @@ -1 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') diff --git a/spec/integration/debug.log b/spec/integration/debug.log deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/spec/spec_helpers/be_like.rb b/spec/matchers/be_like.rb similarity index 100% rename from spec/spec_helpers/be_like.rb rename to spec/matchers/be_like.rb diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb deleted file mode 100644 index d029827f216fd..0000000000000 --- a/spec/relations/relation_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', 'spec_helper') - -describe Relation do - before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :id) - @attribute2 = Attribute.new(@relation1, :name) - end - - describe 'joins' do - describe '<=>' do - it "manufactures an inner join operation between those two relations" do - (@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2) - end - end - - describe '<<' do - it "manufactures a left outer join operation between those two relations" do - (@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2) - end - end - end - - describe '[]' do - it "manufactures an attribute when given a symbol" do - @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) - end - - it "manufactures a range relation when given a range" do - @relation1[1..2].should == RangeRelation.new(@relation1, 1..2) - end - end - - describe '#include?' do - it "manufactures an inclusion predicate" do - @relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1) - end - end - - describe '#project' do - it "collapses identical projections" do - pending - end - - it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) - end - end - - describe '#rename' do - it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1 => :foo) - end - end - - describe '#select' do - before do - @predicate = EqualityPredicate.new(@attribute1, @attribute2) - end - - it "manufactures a selection relation" do - @relation1.select(@attribute1, @attribute2).should == SelectionRelation.new(@relation1, @attribute1, @attribute2) - end - end - - describe 'order' do - it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) - end - end -end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8d90e0dd51808..8f5d76370ce27 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,9 @@ require 'rubygems' require 'spec' -require 'rr' -require File.join(File.dirname(__FILE__), '..', 'lib', 'sql_algebra') -require File.join(File.dirname(__FILE__), 'spec_helpers', 'be_like') +dir = File.dirname(__FILE__) +$LOAD_PATH.unshift "#{dir}/../lib" +Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" } +require 'active_relation' ActiveRecord::Base.configurations = { 'sql_algebra_test' => { From 2fa1ff4e63f27d49a529116bb5e9933a0f385c3e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 7 Jan 2008 18:59:32 -0800 Subject: [PATCH 0020/1492] nk --- lib/active_relation.rb | 2 -- lib/active_relation/extensions/range.rb | 0 lib/active_relation/predicates/binary_predicate.rb | 5 ----- .../predicates/range_inclusion_predicate.rb | 0 lib/active_relation/relations/attribute.rb | 4 ++-- lib/active_relation/relations/rename_relation.rb | 12 ++++++------ spec/active_relation/relations/attribute_spec.rb | 2 +- .../relations/rename_relation_spec.rb | 2 +- 8 files changed, 10 insertions(+), 17 deletions(-) delete mode 100644 lib/active_relation/extensions/range.rb delete mode 100644 lib/active_relation/predicates/range_inclusion_predicate.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 0d7af7bfb8fdf..7cdbd5c02d6f7 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -30,11 +30,9 @@ require 'active_relation/predicates/less_than_or_equal_to_predicate' require 'active_relation/predicates/greater_than_predicate' require 'active_relation/predicates/greater_than_or_equal_to_predicate' -require 'active_relation/predicates/range_inclusion_predicate' require 'active_relation/predicates/relation_inclusion_predicate' require 'active_relation/predicates/match_predicate' -require 'active_relation/extensions/range' require 'active_relation/extensions/object' require 'active_relation/extensions/array' require 'active_relation/extensions/base' diff --git a/lib/active_relation/extensions/range.rb b/lib/active_relation/extensions/range.rb deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/lib/active_relation/predicates/binary_predicate.rb b/lib/active_relation/predicates/binary_predicate.rb index f5c420c83312b..c467d63310aae 100644 --- a/lib/active_relation/predicates/binary_predicate.rb +++ b/lib/active_relation/predicates/binary_predicate.rb @@ -5,11 +5,6 @@ def initialize(attribute1, attribute2) @attribute1, @attribute2 = attribute1, attribute2 end - def ==(other) - super and - (attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) - end - def qualify self.class.new(attribute1.qualify, attribute2.qualify) end diff --git a/lib/active_relation/predicates/range_inclusion_predicate.rb b/lib/active_relation/predicates/range_inclusion_predicate.rb deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/lib/active_relation/relations/attribute.rb b/lib/active_relation/relations/attribute.rb index 7583553b8001c..9ccbb495ea944 100644 --- a/lib/active_relation/relations/attribute.rb +++ b/lib/active_relation/relations/attribute.rb @@ -5,7 +5,7 @@ def initialize(relation, name, aliaz = nil) @relation, @name, @aliaz = relation, name, aliaz end - def aliazz(aliaz) + def alias(aliaz) Attribute.new(relation, name, aliaz) end @@ -14,7 +14,7 @@ def qualified_name end def qualify - aliazz(qualified_name) + self.alias(qualified_name) end module Predications diff --git a/lib/active_relation/relations/rename_relation.rb b/lib/active_relation/relations/rename_relation.rb index 8acf5091b26c5..3218889f33e22 100644 --- a/lib/active_relation/relations/rename_relation.rb +++ b/lib/active_relation/relations/rename_relation.rb @@ -1,13 +1,13 @@ class RenameRelation < CompoundRelation - attr_reader :relation, :schmattribute, :aliaz + attr_reader :relation, :schmattribute, :alias def initialize(relation, renames) - @schmattribute, @aliaz = renames.shift + @schmattribute, @alias = renames.shift @relation = renames.empty?? relation : RenameRelation.new(relation, renames) end def ==(other) - relation == other.relation and schmattribute.eql?(other.schmattribute) and aliaz == other.aliaz + relation == other.relation and schmattribute.eql?(other.schmattribute) and self.alias == other.alias end def attributes @@ -15,13 +15,13 @@ def attributes end def qualify - RenameRelation.new(relation.qualify, schmattribute.qualify => aliaz) + RenameRelation.new(relation.qualify, schmattribute.qualify => self.alias) end protected def attribute(name) case - when name == aliaz then schmattribute.aliazz(aliaz) + when name == self.alias then schmattribute.alias(self.alias) when relation[name].eql?(schmattribute) then nil else relation[name] end @@ -29,6 +29,6 @@ def attribute(name) private def substitute(a) - a.eql?(schmattribute) ? a.aliazz(aliaz) : a + a.eql?(schmattribute) ? a.alias(self.alias) : a end end \ No newline at end of file diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb index ddfc22fe280fa..68ff147ab54f3 100644 --- a/spec/active_relation/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -6,7 +6,7 @@ @relation2 = TableRelation.new(:bar) end - describe '#aliazz' do + describe '#alias' do it "manufactures an aliased attributed" do pending end diff --git a/spec/active_relation/relations/rename_relation_spec.rb b/spec/active_relation/relations/rename_relation_spec.rb index 9b1d2d5cc8926..00a93d10ac5a7 100644 --- a/spec/active_relation/relations/rename_relation_spec.rb +++ b/spec/active_relation/relations/rename_relation_spec.rb @@ -26,7 +26,7 @@ describe '#attributes' do it "manufactures a list of attributes with the renamed attribute aliased" do RenameRelation.new(@relation, @relation[:id] => :schmid).attributes.should == - (@relation.attributes - [@relation[:id]]) + [@relation[:id].aliazz(:schmid)] + (@relation.attributes - [@relation[:id]]) + [@relation[:id].alias(:schmid)] end end From 5f03d1616cc6f66013fbaae9c92553df74a7aee4 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 7 Jan 2008 22:32:16 -0800 Subject: [PATCH 0021/1492] removed sql builder --- lib/active_relation.rb | 20 +-- lib/active_relation/extensions/hash.rb | 6 +- lib/active_relation/extensions/object.rb | 10 +- lib/active_relation/predicates.rb | 4 + .../predicates/binary_predicate.rb | 13 +- .../predicates/equality_predicate.rb | 4 +- lib/active_relation/relations/attribute.rb | 26 +-- .../relations/compound_relation.rb | 4 +- .../relations/deletion_relation.rb | 23 +-- .../relations/inner_join_relation.rb | 4 +- .../relations/insertion_relation.rb | 34 ++-- lib/active_relation/relations/join.rb | 15 -- .../relations/join_relation.rb | 7 +- .../relations/left_outer_join_relation.rb | 4 +- .../relations/order_relation.rb | 20 +-- .../relations/projection_relation.rb | 10 +- .../relations/range_relation.rb | 15 +- lib/active_relation/relations/relation.rb | 45 +++--- lib/active_relation/sql_builder.rb | 7 + .../sql_builder/columns_builder.rb | 16 -- .../sql_builder/conditions_builder.rb | 20 --- .../sql_builder/delete_builder.rb | 32 ---- .../sql_builder/equals_condition_builder.rb | 18 --- .../sql_builder/inner_join_builder.rb | 5 - .../sql_builder/insert_builder.rb | 41 ----- .../sql_builder/join_builder.rb | 13 -- .../sql_builder/joins_builder.rb | 18 --- .../sql_builder/left_outer_join_builder.rb | 5 - .../sql_builder/order_builder.rb | 16 -- .../sql_builder/select_builder.rb | 61 -------- .../sql_builder/selects_builder.rb | 9 -- .../sql_builder/sql_builder.rb | 35 ----- .../sql_builder/values_builder.rb | 16 -- .../integration/scratch_spec.rb | 16 +- .../predicates/binary_predicate_spec.rb | 19 +-- .../relations/attribute_spec.rb | 15 +- .../relations/deletion_relation_spec.rb | 24 +-- .../relations/insertion_relation_spec.rb | 31 ++-- .../relations/join_relation_spec.rb | 32 +--- .../relations/order_relation_spec.rb | 25 +-- .../relations/projection_relation_spec.rb | 10 +- .../relations/range_relation_spec.rb | 25 +-- .../relations/relation_spec.rb | 24 +-- .../relations/rename_relation_spec.rb | 11 +- .../relations/selection_relation_spec.rb | 37 ++--- .../relations/table_relation_spec.rb | 11 +- .../sql_builder/conditions_spec.rb | 18 --- .../sql_builder/delete_builder_spec.rb | 22 --- .../sql_builder/insert_builder_spec.rb | 24 --- .../sql_builder/select_builder_spec.rb | 148 ------------------ 50 files changed, 206 insertions(+), 862 deletions(-) create mode 100644 lib/active_relation/predicates.rb delete mode 100644 lib/active_relation/relations/join.rb create mode 100644 lib/active_relation/sql_builder.rb delete mode 100644 lib/active_relation/sql_builder/columns_builder.rb delete mode 100644 lib/active_relation/sql_builder/conditions_builder.rb delete mode 100644 lib/active_relation/sql_builder/delete_builder.rb delete mode 100644 lib/active_relation/sql_builder/equals_condition_builder.rb delete mode 100644 lib/active_relation/sql_builder/inner_join_builder.rb delete mode 100644 lib/active_relation/sql_builder/insert_builder.rb delete mode 100644 lib/active_relation/sql_builder/join_builder.rb delete mode 100644 lib/active_relation/sql_builder/joins_builder.rb delete mode 100644 lib/active_relation/sql_builder/left_outer_join_builder.rb delete mode 100644 lib/active_relation/sql_builder/order_builder.rb delete mode 100644 lib/active_relation/sql_builder/select_builder.rb delete mode 100644 lib/active_relation/sql_builder/selects_builder.rb delete mode 100644 lib/active_relation/sql_builder/sql_builder.rb delete mode 100644 lib/active_relation/sql_builder/values_builder.rb delete mode 100644 spec/active_relation/sql_builder/conditions_spec.rb delete mode 100644 spec/active_relation/sql_builder/delete_builder_spec.rb delete mode 100644 spec/active_relation/sql_builder/insert_builder_spec.rb delete mode 100644 spec/active_relation/sql_builder/select_builder_spec.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 7cdbd5c02d6f7..2120d09bc87fa 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -4,6 +4,8 @@ require 'activesupport' require 'activerecord' +require 'active_relation/sql_builder' + require 'active_relation/relations/relation' require 'active_relation/relations/compound_relation' require 'active_relation/relations/table_relation' @@ -19,7 +21,6 @@ require 'active_relation/relations/order_relation' require 'active_relation/relations/range_relation' require 'active_relation/relations/rename_relation' -require 'active_relation/relations/join' require 'active_relation/relations/deletion_relation' require 'active_relation/relations/insertion_relation' @@ -36,19 +37,4 @@ require 'active_relation/extensions/object' require 'active_relation/extensions/array' require 'active_relation/extensions/base' -require 'active_relation/extensions/hash' - -require 'active_relation/sql_builder/sql_builder' -require 'active_relation/sql_builder/select_builder' -require 'active_relation/sql_builder/delete_builder' -require 'active_relation/sql_builder/insert_builder' -require 'active_relation/sql_builder/joins_builder' -require 'active_relation/sql_builder/join_builder' -require 'active_relation/sql_builder/inner_join_builder' -require 'active_relation/sql_builder/left_outer_join_builder' -require 'active_relation/sql_builder/equals_condition_builder' -require 'active_relation/sql_builder/conditions_builder' -require 'active_relation/sql_builder/order_builder' -require 'active_relation/sql_builder/columns_builder' -require 'active_relation/sql_builder/selects_builder' -require 'active_relation/sql_builder/values_builder' \ No newline at end of file +require 'active_relation/extensions/hash' \ No newline at end of file diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index f643ac17ab3e2..d9496df2e90ba 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -5,9 +5,7 @@ def alias(&block) end end - def to_sql(builder = ValuesBuilder.new) - builder.call do - row *values - end + def to_sql(options = {}) + "(#{values.collect(&:to_sql).join(', ')})" end end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index c241581f861df..79d7613d9a445 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -1,12 +1,12 @@ class Object + include SqlBuilder + def qualify self end - def to_sql(builder = EqualsConditionBuilder.new) - me = self - builder.call do - value me.to_s - end + def to_sql(options = {}) + options.reverse_merge!(:quote => true) + options[:quote] ? quote(self) : self end end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb new file mode 100644 index 0000000000000..0179a15035672 --- /dev/null +++ b/lib/active_relation/predicates.rb @@ -0,0 +1,4 @@ +module ActiveRelation + module Predicates + end +end \ No newline at end of file diff --git a/lib/active_relation/predicates/binary_predicate.rb b/lib/active_relation/predicates/binary_predicate.rb index c467d63310aae..f3ce430d00b70 100644 --- a/lib/active_relation/predicates/binary_predicate.rb +++ b/lib/active_relation/predicates/binary_predicate.rb @@ -5,16 +5,15 @@ def initialize(attribute1, attribute2) @attribute1, @attribute2 = attribute1, attribute2 end + def ==(other) + super and @attribute1.eql?(other.attribute1) and @attribute2.eql?(other.attribute2) + end + def qualify self.class.new(attribute1.qualify, attribute2.qualify) end - def to_sql(builder = ConditionsBuilder.new) - builder.call do - send(predicate_name) do - attribute1.to_sql(self) - attribute2.to_sql(self) - end - end + def to_sql(options = {}) + "#{attribute1.to_sql} #{predicate_sql} #{attribute2.to_sql}" end end \ No newline at end of file diff --git a/lib/active_relation/predicates/equality_predicate.rb b/lib/active_relation/predicates/equality_predicate.rb index 7040c45f6704d..4f4113c7405ea 100644 --- a/lib/active_relation/predicates/equality_predicate.rb +++ b/lib/active_relation/predicates/equality_predicate.rb @@ -6,7 +6,7 @@ def ==(other) end protected - def predicate_name - :equals + def predicate_sql + '=' end end \ No newline at end of file diff --git a/lib/active_relation/relations/attribute.rb b/lib/active_relation/relations/attribute.rb index 9ccbb495ea944..8193132de6507 100644 --- a/lib/active_relation/relations/attribute.rb +++ b/lib/active_relation/relations/attribute.rb @@ -1,12 +1,14 @@ class Attribute - attr_reader :relation, :name, :aliaz + include SqlBuilder + + attr_reader :relation, :name, :alias def initialize(relation, name, aliaz = nil) - @relation, @name, @aliaz = relation, name, aliaz + @relation, @name, @alias = relation, name, aliaz end - def alias(aliaz) - Attribute.new(relation, name, aliaz) + def alias(aliaz = nil) + aliaz ? Attribute.new(relation, name, aliaz) : @alias end def qualified_name @@ -16,12 +18,12 @@ def qualified_name def qualify self.alias(qualified_name) end - - module Predications - def eql?(other) - relation == other.relation and name == other.name and aliaz == other.aliaz - end + def eql?(other) + relation == other.relation and name == other.name and self.alias == other.alias + end + + module Predications def ==(other) EqualityPredicate.new(self, other) end @@ -48,9 +50,7 @@ def =~(regexp) end include Predications - def to_sql(builder = SelectsBuilder.new) - builder.call do - column relation.table, name, aliaz - end + def to_sql(options = {}) + "#{quote_table_name(relation.table)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") end end \ No newline at end of file diff --git a/lib/active_relation/relations/compound_relation.rb b/lib/active_relation/relations/compound_relation.rb index fe92905d922b9..b18921e06d9c6 100644 --- a/lib/active_relation/relations/compound_relation.rb +++ b/lib/active_relation/relations/compound_relation.rb @@ -1,3 +1,5 @@ class CompoundRelation < Relation - delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :to => :relation + attr_reader :relation + + delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :to => :relation end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion_relation.rb b/lib/active_relation/relations/deletion_relation.rb index e060efd5f90e8..8418319055325 100644 --- a/lib/active_relation/relations/deletion_relation.rb +++ b/lib/active_relation/relations/deletion_relation.rb @@ -1,22 +1,13 @@ class DeletionRelation < CompoundRelation - attr_reader :relation - - def ==(other) - relation == other.relation - end - def initialize(relation) @relation = relation end - def to_sql(builder = DeleteBuilder.new) - builder.call do - delete - from table - where do - selects.each { |s| s.to_sql(self) } - end - end - end - + def to_sql(options = {}) + [ + "DELETE", + "FROM #{quote_table_name(table)}", + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ].compact.join("\n") + end end \ No newline at end of file diff --git a/lib/active_relation/relations/inner_join_relation.rb b/lib/active_relation/relations/inner_join_relation.rb index 5e58f241f8f92..74160c559ff70 100644 --- a/lib/active_relation/relations/inner_join_relation.rb +++ b/lib/active_relation/relations/inner_join_relation.rb @@ -1,6 +1,6 @@ class InnerJoinRelation < JoinRelation protected - def join_type - :inner_join + def join_sql + "INNER JOIN" end end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion_relation.rb b/lib/active_relation/relations/insertion_relation.rb index 84752d13f936b..002ebbf062f71 100644 --- a/lib/active_relation/relations/insertion_relation.rb +++ b/lib/active_relation/relations/insertion_relation.rb @@ -1,29 +1,21 @@ class InsertionRelation < CompoundRelation - attr_reader :relation, :tuple + attr_reader :record - def initialize(relation, tuple) - @relation, @tuple = relation, tuple - end - - def to_sql(builder = InsertBuilder.new) - builder.call do - insert - into table - columns do - tuple.keys.each { |attribute| attribute.to_sql(self) } - end - values do - inserts.each { |insert| insert.to_sql(self) } - end - end + def initialize(relation, record) + @relation, @record = relation, record end - def ==(other) - relation == other.relation and tuple == other.tuple - end - + def to_sql(options = {}) + [ + "INSERT", + "INTO #{quote_table_name(table)}", + "(#{record.keys.collect(&:to_sql).join(', ')})", + "VALUES #{inserts.collect(&:to_sql).join(', ')}" + ].join("\n") + end + protected def inserts - relation.inserts + [tuple] + relation.inserts + [record] end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb deleted file mode 100644 index 9a6196deacf51..0000000000000 --- a/lib/active_relation/relations/join.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Join - attr_reader :relation1, :relation2, :predicates, :join_type - - def initialize(relation1, relation2, predicates, join_type) - @relation1, @relation2, @predicates, @join_type = relation1, relation2, predicates, join_type - end - - def to_sql(builder = JoinsBuilder.new) - builder.call do - send(join_type, relation2.table) do - predicates.each { |p| p.to_sql(self) } - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/join_relation.rb b/lib/active_relation/relations/join_relation.rb index 79c8a915b89ec..845dfd732f49e 100644 --- a/lib/active_relation/relations/join_relation.rb +++ b/lib/active_relation/relations/join_relation.rb @@ -17,7 +17,7 @@ def qualify protected def joins - relation1.joins + relation2.joins + [Join.new(relation1, relation2, predicates, join_type)] + [relation1.joins, relation2.joins, join].compact.join(" ") end def selects @@ -33,4 +33,9 @@ def attribute(name) end delegate :table, :to => :relation1 + + private + def join + "#{join_sql} #{quote_table_name(relation2.table)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" + end end \ No newline at end of file diff --git a/lib/active_relation/relations/left_outer_join_relation.rb b/lib/active_relation/relations/left_outer_join_relation.rb index 6d13d8da07d8a..57eda4e1fc91d 100644 --- a/lib/active_relation/relations/left_outer_join_relation.rb +++ b/lib/active_relation/relations/left_outer_join_relation.rb @@ -1,6 +1,6 @@ class LeftOuterJoinRelation < JoinRelation protected - def join_type - :left_outer_join + def join_sql + "LEFT OUTER JOIN" end end \ No newline at end of file diff --git a/lib/active_relation/relations/order_relation.rb b/lib/active_relation/relations/order_relation.rb index b39dc45c3f72f..dfb0c0bf2567d 100644 --- a/lib/active_relation/relations/order_relation.rb +++ b/lib/active_relation/relations/order_relation.rb @@ -1,25 +1,15 @@ class OrderRelation < CompoundRelation - attr_reader :relation, :attributes + attr_reader :relation, :orders - def initialize(relation, *attributes) - @relation, @attributes = relation, attributes + def initialize(relation, *orders) + @relation, @orders = relation, orders end def ==(other) - relation == other.relation and attributes.eql?(other.attributes) + relation == other.relation and orders.eql?(other.orders) end def qualify - OrderRelation.new(relation.qualify, *attributes.collect { |a| a.qualify }) - end - - def to_sql(builder = SelectBuilder.new) - relation.to_sql(builder).call do - attributes.each do |attribute| - order_by do - attribute.to_sql(self) - end - end - end + OrderRelation.new(relation.qualify, *orders.collect { |o| o.qualify }) end end \ No newline at end of file diff --git a/lib/active_relation/relations/projection_relation.rb b/lib/active_relation/relations/projection_relation.rb index 1a0e8dbfe40b0..53b0ad1e91b9e 100644 --- a/lib/active_relation/relations/projection_relation.rb +++ b/lib/active_relation/relations/projection_relation.rb @@ -1,4 +1,4 @@ -class ProjectionRelation < Relation +class ProjectionRelation < CompoundRelation attr_reader :relation, :attributes def initialize(relation, *attributes) @@ -12,12 +12,4 @@ def ==(other) def qualify ProjectionRelation.new(relation.qualify, *attributes.collect(&:qualify)) end - - def to_sql(builder = SelectBuilder.new) - relation.to_sql(builder).call do - select do - attributes.collect { |a| a.to_sql(self) } - end - end - end end \ No newline at end of file diff --git a/lib/active_relation/relations/range_relation.rb b/lib/active_relation/relations/range_relation.rb index 9225d5615b0fa..6a2b0b34700c2 100644 --- a/lib/active_relation/relations/range_relation.rb +++ b/lib/active_relation/relations/range_relation.rb @@ -1,5 +1,5 @@ -class RangeRelation < Relation - attr_reader :relation, :range +class RangeRelation < CompoundRelation + attr_reader :range def initialize(relation, range) @relation, @range = relation, range @@ -9,10 +9,11 @@ def ==(other) relation == other.relation and range == other.range end - def to_sql(builder = SelectBuilder.new) - relation.to_sql(builder).call do - limit range.last - range.first + 1 - offset range.first - end + def limit + range.end - range.begin + 1 + end + + def offset + range.begin end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index be6ee760a5e0e..0a8455b39caf3 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -1,4 +1,6 @@ class Relation + include SqlBuilder + module Iteration include Enumerable @@ -50,8 +52,8 @@ def rename(attribute, aliaz) RenameRelation.new(self, attribute => aliaz) end - def insert(tuple) - InsertionRelation.new(self, tuple) + def insert(record) + InsertionRelation.new(self, record) end def delete @@ -64,28 +66,25 @@ def connection ActiveRecord::Base.connection end - def to_sql(builder = SelectBuilder.new) - builder.call do - select do - attributes.each { |a| a.to_sql(self) } - end - from table do - joins.each { |j| j.to_sql(self) } - end - where do - selects.each { |s| s.to_sql(self) } - end - order_by do - orders.each { |o| o.to_sql(self) } - end - end + def to_sql(options = {}) + [ + "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", + "FROM #{quote_table_name(table)}", + (joins.to_sql(:quote => false) unless joins.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), + ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), + ("LIMIT #{limit.to_sql}" unless limit.blank?), + ("OFFSET #{offset.to_sql}" unless offset.blank?) + ].compact.join("\n") end - delegate :to_s, :to => :to_sql + alias_method :to_s, :to_sql protected - def attributes; [] end - def joins; [] end - def selects; [] end - def orders; [] end - def inserts; [] end + def attributes; [] end + def selects; [] end + def orders; [] end + def inserts; [] end + def joins; nil end + def limit; nil end + def offset; nil end end \ No newline at end of file diff --git a/lib/active_relation/sql_builder.rb b/lib/active_relation/sql_builder.rb new file mode 100644 index 0000000000000..0d2187173eba6 --- /dev/null +++ b/lib/active_relation/sql_builder.rb @@ -0,0 +1,7 @@ +module SqlBuilder + def connection + ActiveRecord::Base.connection + end + + delegate :quote_table_name, :quote_column_name, :quote, :to => :connection +end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/columns_builder.rb b/lib/active_relation/sql_builder/columns_builder.rb deleted file mode 100644 index a8a5d0e4ca4a7..0000000000000 --- a/lib/active_relation/sql_builder/columns_builder.rb +++ /dev/null @@ -1,16 +0,0 @@ -class ColumnsBuilder < SqlBuilder - def initialize(&block) - @columns = [] - super(&block) - end - - def to_s - @columns.join(', ') - end - - def column(table, column, aliaz = nil) - @columns << "#{quote_table_name(table)}.#{quote_column_name(column)}" - end - - delegate :blank?, :to => :@columns -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/conditions_builder.rb b/lib/active_relation/sql_builder/conditions_builder.rb deleted file mode 100644 index 60430f65d8a37..0000000000000 --- a/lib/active_relation/sql_builder/conditions_builder.rb +++ /dev/null @@ -1,20 +0,0 @@ -class ConditionsBuilder < SqlBuilder - def initialize(&block) - @conditions = [] - super(&block) - end - - def equals(&block) - @conditions << EqualsConditionBuilder.new(&block) - end - - def value(value) - @conditions << value - end - - def to_s - @conditions.join(' AND ') - end - - delegate :blank?, :to => :@conditions -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/delete_builder.rb b/lib/active_relation/sql_builder/delete_builder.rb deleted file mode 100644 index 2e8be94dfe0fa..0000000000000 --- a/lib/active_relation/sql_builder/delete_builder.rb +++ /dev/null @@ -1,32 +0,0 @@ -class DeleteBuilder < SqlBuilder - def delete - end - - def from(table) - @table = table - end - - def where(&block) - @conditions = ConditionsBuilder.new(&block) - end - - def to_s - [delete_clause, - from_clause, - where_clause - ].compact.join("\n") - end - - private - def delete_clause - "DELETE" - end - - def from_clause - "FROM #{quote_table_name(@table)}" - end - - def where_clause - "WHERE #{@conditions}" unless @conditions.blank? - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/equals_condition_builder.rb b/lib/active_relation/sql_builder/equals_condition_builder.rb deleted file mode 100644 index cfa919c34c9f8..0000000000000 --- a/lib/active_relation/sql_builder/equals_condition_builder.rb +++ /dev/null @@ -1,18 +0,0 @@ -class EqualsConditionBuilder < SqlBuilder - def initialize(&block) - @operands = [] - super(&block) - end - - def column(table, column, aliaz = nil) - @operands << "#{quote_table_name(table)}.#{quote_column_name(column)}" - end - - def value(value) - @operands << value - end - - def to_s - "#{@operands[0]} = #{@operands[1]}" - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/inner_join_builder.rb b/lib/active_relation/sql_builder/inner_join_builder.rb deleted file mode 100644 index 6aec703325707..0000000000000 --- a/lib/active_relation/sql_builder/inner_join_builder.rb +++ /dev/null @@ -1,5 +0,0 @@ -class InnerJoinBuilder < JoinBuilder - def join_type - "INNER JOIN" - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/insert_builder.rb b/lib/active_relation/sql_builder/insert_builder.rb deleted file mode 100644 index 09deefad1057b..0000000000000 --- a/lib/active_relation/sql_builder/insert_builder.rb +++ /dev/null @@ -1,41 +0,0 @@ -class InsertBuilder < SqlBuilder - def insert - end - - def into(table) - @table = table - end - - def columns(&block) - @columns = ColumnsBuilder.new(&block) - end - - def values(&block) - @values = ValuesBuilder.new(&block) - end - - def to_s - [insert_clause, - into_clause, - columns_clause, - values_clause - ].compact.join("\n") - end - - private - def insert_clause - "INSERT" - end - - def into_clause - "INTO #{quote_table_name(@table)}" - end - - def values_clause - "VALUES #{@values}" unless @values.blank? - end - - def columns_clause - "(#{@columns})" unless @columns.blank? - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/join_builder.rb b/lib/active_relation/sql_builder/join_builder.rb deleted file mode 100644 index ef63d1fcb16e2..0000000000000 --- a/lib/active_relation/sql_builder/join_builder.rb +++ /dev/null @@ -1,13 +0,0 @@ -class JoinBuilder < SqlBuilder - def initialize(table, &block) - @table = table - @conditions = ConditionsBuilder.new - super(&block) - end - - delegate :call, :to => :@conditions - - def to_s - "#{join_type} #{quote_table_name(@table)} ON #{@conditions}" - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/joins_builder.rb b/lib/active_relation/sql_builder/joins_builder.rb deleted file mode 100644 index 36a92e9922cd5..0000000000000 --- a/lib/active_relation/sql_builder/joins_builder.rb +++ /dev/null @@ -1,18 +0,0 @@ -class JoinsBuilder < SqlBuilder - def initialize(&block) - @joins = [] - super(&block) - end - - def inner_join(table, &block) - @joins << InnerJoinBuilder.new(table, &block) - end - - def left_outer_join(table, &block) - @joins << LeftOuterJoinBuilder.new(table, &block) - end - - def to_s - @joins.join(' ') - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/left_outer_join_builder.rb b/lib/active_relation/sql_builder/left_outer_join_builder.rb deleted file mode 100644 index dad3f85810cda..0000000000000 --- a/lib/active_relation/sql_builder/left_outer_join_builder.rb +++ /dev/null @@ -1,5 +0,0 @@ -class LeftOuterJoinBuilder < JoinBuilder - def join_type - "LEFT OUTER JOIN" - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/order_builder.rb b/lib/active_relation/sql_builder/order_builder.rb deleted file mode 100644 index 66a8cfdba95ab..0000000000000 --- a/lib/active_relation/sql_builder/order_builder.rb +++ /dev/null @@ -1,16 +0,0 @@ -class OrderBuilder < SqlBuilder - def initialize(&block) - @orders = [] - super(&block) - end - - def column(table, column, aliaz = nil) - @orders << "#{quote_table_name(table)}.#{quote_column_name(column)}" - end - - def to_s - @orders.join(', ') - end - - delegate :blank?, :to => :@orders -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/select_builder.rb b/lib/active_relation/sql_builder/select_builder.rb deleted file mode 100644 index 57116cb64b52d..0000000000000 --- a/lib/active_relation/sql_builder/select_builder.rb +++ /dev/null @@ -1,61 +0,0 @@ -class SelectBuilder < SqlBuilder - def select(&block) - @selects = SelectsBuilder.new(&block) - end - - def from(table, &block) - @table = table - @joins = JoinsBuilder.new(&block) - end - - def where(&block) - @conditions = ConditionsBuilder.new(&block) - end - - def order_by(&block) - @orders = OrderBuilder.new(&block) - end - - def limit(i, offset = nil) - @limit = i - offset(offset) if offset - end - - def offset(i) - @offset = i - end - - def to_s - [select_clause, - from_clause, - where_clause, - order_by_clause, - limit_clause, - offset_clause].compact.join("\n") - end - - private - def select_clause - "SELECT #{@selects}" unless @selects.blank? - end - - def from_clause - "FROM #{quote_table_name(@table)} #{@joins}" unless @table.blank? - end - - def where_clause - "WHERE #{@conditions}" unless @conditions.blank? - end - - def order_by_clause - "ORDER BY #{@orders}" unless @orders.blank? - end - - def limit_clause - "LIMIT #{@limit}" unless @limit.blank? - end - - def offset_clause - "OFFSET #{@offset}" unless @offset.blank? - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/selects_builder.rb b/lib/active_relation/sql_builder/selects_builder.rb deleted file mode 100644 index 6ad06d0ae4e2b..0000000000000 --- a/lib/active_relation/sql_builder/selects_builder.rb +++ /dev/null @@ -1,9 +0,0 @@ -class SelectsBuilder < ColumnsBuilder - def all - @columns << :* - end - - def column(table, column, aliaz = nil) - @columns << "#{quote_table_name(table)}.#{quote_column_name(column)}" + (aliaz ? " AS #{quote(aliaz)}" : '') - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/sql_builder.rb b/lib/active_relation/sql_builder/sql_builder.rb deleted file mode 100644 index c984444e41bd1..0000000000000 --- a/lib/active_relation/sql_builder/sql_builder.rb +++ /dev/null @@ -1,35 +0,0 @@ -class SqlBuilder - def initialize(&block) - @callers = [] - call(&block) if block - end - - def method_missing(method, *args) - @callers.last.send(method, *args) - end - - def ==(other) - to_s == other.to_s - end - - def to_s - end - - def call(&block) - returning self do |builder| - @callers << eval("self", block.binding) - begin - instance_eval &block - ensure - @callers.pop - end - end - end - - private - delegate :quote_table_name, :quote_column_name, :quote, :to => :connection - - def connection - ActiveRecord::Base.connection - end -end \ No newline at end of file diff --git a/lib/active_relation/sql_builder/values_builder.rb b/lib/active_relation/sql_builder/values_builder.rb deleted file mode 100644 index f22b1e507ed8b..0000000000000 --- a/lib/active_relation/sql_builder/values_builder.rb +++ /dev/null @@ -1,16 +0,0 @@ -class ValuesBuilder < SqlBuilder - def initialize(&block) - @values = [] - super(&block) - end - - def row(*values) - @values << "(#{values.collect { |v| quote(v) }.join(', ')})" - end - - def to_s - @values.join(', ') - end - - delegate :blank?, :to => :@values -end \ No newline at end of file diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb index fba587e4ba177..93d332eea76b2 100644 --- a/spec/active_relation/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -71,7 +71,7 @@ def photo_belongs_to_camera(photo_relation) # the 'project' operator limits the columns that come back from the query. # Note how all the operators are compositional: 'project' is applied to a query # that previously had been joined and selected. - user_photos.project(*@photos.attributes).to_s.should be_like(""" + user_photos.project(*@photos.attributes).to_sql.should be_like(""" SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` LEFT OUTER JOIN `photos` @@ -86,7 +86,7 @@ def photo_belongs_to_camera(photo_relation) it 'generates the query for User.has_many :cameras :through => :photos' do # note, again, the compositionality of the operators: user_cameras = photo_belongs_to_camera(user_has_many_photos(@user)) - user_cameras.project(*@cameras.attributes).to_s.should be_like(""" + user_cameras.project(*@cameras.attributes).to_sql.should be_like(""" SELECT `cameras`.`id` FROM `users` LEFT OUTER JOIN `photos` @@ -101,7 +101,7 @@ def photo_belongs_to_camera(photo_relation) it 'generates the query for an eager join for a collection using the same logic as for an association on an individual row' do users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)) - users_cameras.to_s.should be_like(""" + users_cameras.to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`, `cameras`.`id` FROM `users` LEFT OUTER JOIN `photos` @@ -113,7 +113,7 @@ def photo_belongs_to_camera(photo_relation) it 'is trivial to disambiguate columns' do users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify - users_cameras.to_s.should be_like(""" + users_cameras.to_sql.should be_like(""" SELECT `users`.`name` AS 'users.name', `users`.`id` AS 'users.id', `photos`.`id` AS 'photos.id', `photos`.`user_id` AS 'photos.user_id', `photos`.`camera_id` AS 'photos.camera_id', `cameras`.`id` AS 'cameras.id' FROM `users` LEFT OUTER JOIN `photos` @@ -124,13 +124,13 @@ def photo_belongs_to_camera(photo_relation) end it 'allows arbitrary sql to be passed through' do - (@users << @photos).on("asdf").to_s.should be_like(""" + (@users << @photos).on("asdf").to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` LEFT OUTER JOIN `photos` ON asdf """) - @users.select("asdf").to_s.should be_like(""" + @users.select("asdf").to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id` FROM `users` WHERE asdf @@ -139,7 +139,7 @@ def photo_belongs_to_camera(photo_relation) describe 'write operations' do it 'generates the query for user.destroy' do - @user.delete.to_s.should be_like(""" + @user.delete.to_sql.should be_like(""" DELETE FROM `users` WHERE `users`.`id` = 1 @@ -147,7 +147,7 @@ def photo_belongs_to_camera(photo_relation) end it 'generates an efficient query for two User.creates -- UnitOfWork is within reach!' do - @users.insert(@users[:name] => "humpty").insert(@users[:name] => "dumpty").to_s.should be_like(""" + @users.insert(@users[:name] => "humpty").insert(@users[:name] => "dumpty").to_sql.should be_like(""" INSERT INTO `users` (`users`.`name`) VALUES ('humpty'), ('dumpty') diff --git a/spec/active_relation/predicates/binary_predicate_spec.rb b/spec/active_relation/predicates/binary_predicate_spec.rb index 5de559df41231..0bddae8491281 100644 --- a/spec/active_relation/predicates/binary_predicate_spec.rb +++ b/spec/active_relation/predicates/binary_predicate_spec.rb @@ -7,18 +7,12 @@ @attribute1 = Attribute.new(@relation1, :name1) @attribute2 = Attribute.new(@relation2, :name2) class ConcreteBinaryPredicate < BinaryPredicate - def predicate_name - :equals + def predicate_sql + "<=>" end end end - describe '#initialize' do - it "requires that both columns come from the same relation" do - pending - end - end - describe '==' do it "obtains if attribute1 and attribute2 are identical" do BinaryPredicate.new(@attribute1, @attribute2).should == BinaryPredicate.new(@attribute1, @attribute2) @@ -40,12 +34,9 @@ def predicate_name describe '#to_sql' do it 'manufactures correct sql' do - ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should == ConditionsBuilder.new do - equals do - column :foo, :name1 - column :bar, :name2 - end - end + ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should be_like(""" + `foo`.`name1` <=> `bar`.`name2` + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb index 68ff147ab54f3..4154a91b85f76 100644 --- a/spec/active_relation/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -8,12 +8,7 @@ describe '#alias' do it "manufactures an aliased attributed" do - pending - end - - it "should be renamed to #alias!" do - pending - @relation1.alias + @relation1[:id].alias(:alias).should == Attribute.new(@relation1, :id, :alias) end end @@ -79,12 +74,4 @@ end end end - - describe '#to_sql' do - it "manufactures a column" do - Attribute.new(@relation1, :name, :alias).to_sql.should == SelectsBuilder.new do - column :foo, :name, :alias - end - end - end end diff --git a/spec/active_relation/relations/deletion_relation_spec.rb b/spec/active_relation/relations/deletion_relation_spec.rb index 4f75a261f4835..5e8c5137b26e4 100644 --- a/spec/active_relation/relations/deletion_relation_spec.rb +++ b/spec/active_relation/relations/deletion_relation_spec.rb @@ -6,17 +6,19 @@ end describe '#to_sql' do - it 'manufactures sql deleting the relation' do - DeletionRelation.new(@relation.select(@relation[:id] == 1)).to_sql.to_s.should == DeleteBuilder.new do - delete - from :users - where do - equals do - column :users, :id - value 1 - end - end - end.to_s + it 'manufactures sql deleting a table relation' do + DeletionRelation.new(@relation).to_sql.should be_like(""" + DELETE + FROM `users` + """) + end + + it 'manufactures sql deleting a selection relation' do + DeletionRelation.new(@relation.select(@relation[:id] == 1)).to_sql.should be_like(""" + DELETE + FROM `users` + WHERE `users`.`id` = 1 + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/insertion_relation_spec.rb b/spec/active_relation/relations/insertion_relation_spec.rb index 6bafabb473738..177918a94ac6f 100644 --- a/spec/active_relation/relations/insertion_relation_spec.rb +++ b/spec/active_relation/relations/insertion_relation_spec.rb @@ -7,31 +7,20 @@ describe '#to_sql' do it 'manufactures sql inserting the data for one item' do - InsertionRelation.new(@relation, @relation[:name] => "nick").to_sql.should == InsertBuilder.new do - insert - into :users - columns do - column :users, :name - end - values do - row "nick" - end - end + InsertionRelation.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick') + """) end it 'manufactures sql inserting the data for multiple items' do nested_insertion = InsertionRelation.new(@relation, @relation[:name] => "cobra") - InsertionRelation.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.to_s.should == InsertBuilder.new do - insert - into :users - columns do - column :users, :name - end - values do - row "cobra" - row "commander" - end - end.to_s + InsertionRelation.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('cobra'), ('commander') + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/join_relation_spec.rb b/spec/active_relation/relations/join_relation_spec.rb index d0be2708378c8..3e60cc4c3441f 100644 --- a/spec/active_relation/relations/join_relation_spec.rb +++ b/spec/active_relation/relations/join_relation_spec.rb @@ -27,33 +27,17 @@ describe '#to_sql' do before do - @relation1 = @relation1.select(@relation1[:id] == @relation2[:foo_id]) + @relation1 = @relation1.select(@relation1[:id] == 1) end it 'manufactures sql joining the two tables on the predicate, merging the selects' do - InnerJoinRelation.new(@relation1, @relation2, @predicate).to_s.should == SelectBuilder.new do - select do - column :foo, :name - column :foo, :id - column :bar, :name - column :bar, :foo_id - column :bar, :id - end - from :foo do - inner_join :bar do - equals do - column :foo, :id - column :bar, :id - end - end - end - where do - equals do - column :foo, :id - column :bar, :foo_id - end - end - end.to_s + InnerJoinRelation.new(@relation1, @relation2, @predicate).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` + FROM `foo` + INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` + WHERE + `foo`.`id` = 1 + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/order_relation_spec.rb b/spec/active_relation/relations/order_relation_spec.rb index 17f730b564fd5..8655780c37c8d 100644 --- a/spec/active_relation/relations/order_relation_spec.rb +++ b/spec/active_relation/relations/order_relation_spec.rb @@ -7,15 +7,7 @@ @attribute1 = @relation1[:id] @attribute2 = @relation2[:id] end - - describe '==' do - it "obtains if the relation and attributes are identical" do - OrderRelation.new(@relation1, @attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) - OrderRelation.new(@relation1, @attribute1).should_not == OrderRelation.new(@relation2, @attribute1) - OrderRelation.new(@relation1, @attribute1, @attribute2).should_not == OrderRelation.new(@relation1, @attribute2, @attribute1) - end - end - + describe '#qualify' do it "distributes over the relation and attributes" do OrderRelation.new(@relation1, @attribute1).qualify. \ @@ -25,16 +17,11 @@ describe '#to_sql' do it "manufactures sql with an order clause" do - OrderRelation.new(@relation1, @attribute1).to_s.should == SelectBuilder.new do - select do - column :foo, :name - column :foo, :id - end - from :foo - order_by do - column :foo, :id - end - end.to_s + OrderRelation.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + ORDER BY `foo`.`id` + """) end end diff --git a/spec/active_relation/relations/projection_relation_spec.rb b/spec/active_relation/relations/projection_relation_spec.rb index 164c4857610a6..77722a17c5920 100644 --- a/spec/active_relation/relations/projection_relation_spec.rb +++ b/spec/active_relation/relations/projection_relation_spec.rb @@ -25,12 +25,10 @@ describe '#to_sql' do it "manufactures sql with a limited select clause" do - ProjectionRelation.new(@relation1, @attribute1).to_s.should == SelectBuilder.new do - select do - column :foo, :id - end - from :foo - end.to_s + ProjectionRelation.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`id` + FROM `foo` + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/range_relation_spec.rb b/spec/active_relation/relations/range_relation_spec.rb index ac9f887d9b497..67e2b0d16400f 100644 --- a/spec/active_relation/relations/range_relation_spec.rb +++ b/spec/active_relation/relations/range_relation_spec.rb @@ -7,15 +7,7 @@ @range1 = 1..2 @range2 = 4..9 end - - describe '==' do - it "obtains if the relation and range are identical" do - RangeRelation.new(@relation1, @range1).should == RangeRelation.new(@relation1, @range1) - RangeRelation.new(@relation1, @range1).should_not == RangeRelation.new(@relation2, @range1) - RangeRelation.new(@relation1, @range1).should_not == RangeRelation.new(@relation1, @range2) - end - end - + describe '#qualify' do it "distributes over the relation and attributes" do pending @@ -26,15 +18,12 @@ it "manufactures sql with limit and offset" do range_size = @range2.last - @range2.first + 1 range_start = @range2.first - RangeRelation.new(@relation1, @range2).to_s.should == SelectBuilder.new do - select do - column :foo, :name - column :foo, :id - end - from :foo - limit range_size - offset range_start - end.to_s + RangeRelation.new(@relation1, @range2).to_s.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + LIMIT #{range_size} + OFFSET #{range_start} + """) end end diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index 9ed42a98cbd00..5d7c40a53047b 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -10,17 +10,17 @@ describe '[]' do it "manufactures an attribute when given a symbol" do - @relation1[:id].should be_eql(Attribute.new(@relation1, :id)) + @relation1[:id].should be_kind_of(Attribute) end it "manufactures a range relation when given a range" do - @relation1[1..2].should == RangeRelation.new(@relation1, 1..2) + @relation1[1..2].should be_kind_of(RangeRelation) end end describe '#include?' do it "manufactures an inclusion predicate" do - @relation1.include?(@attribute1).should == RelationInclusionPredicate.new(@attribute1, @relation1) + @relation1.include?(@attribute1).should be_kind_of(RelationInclusionPredicate) end end @@ -28,13 +28,13 @@ describe 'joins' do describe '<=>' do it "manufactures an inner join operation between those two relations" do - (@relation1 <=> @relation2).should == InnerJoinOperation.new(@relation1, @relation2) + (@relation1 <=> @relation2).should be_kind_of(InnerJoinOperation) end end describe '<<' do it "manufactures a left outer join operation between those two relations" do - (@relation1 << @relation2).should == LeftOuterJoinOperation.new(@relation1, @relation2) + (@relation1 << @relation2).should be_kind_of(LeftOuterJoinOperation) end end end @@ -45,13 +45,13 @@ end it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) + @relation1.project(@attribute1, @attribute2).should be_kind_of(ProjectionRelation) end end describe '#rename' do it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should == RenameRelation.new(@relation1, @attribute1 => :foo) + @relation1.rename(@attribute1, :foo).should be_kind_of(RenameRelation) end end @@ -61,17 +61,17 @@ end it "manufactures a selection relation" do - @relation1.select(@predicate).should == SelectionRelation.new(@relation1, @predicate) + @relation1.select(@predicate).should be_kind_of(SelectionRelation) end it "accepts arbitrary strings" do - @relation1.select("arbitrary").should == SelectionRelation.new(@relation1, "arbitrary") + @relation1.select("arbitrary").should be_kind_of(SelectionRelation) end end describe '#order' do it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should == OrderRelation.new(@relation1, @attribute1, @attribute2) + @relation1.order(@attribute1, @attribute2).should be_kind_of(OrderRelation) end end end @@ -79,13 +79,13 @@ describe 'write operations' do describe '#delete' do it 'manufactures a deletion relation' do - @relation1.delete.should == DeletionRelation.new(@relation1) + @relation1.delete.should be_kind_of(DeletionRelation) end end describe '#insert' do it 'manufactures an insertion relation' do - @relation1.insert(tuple = {:id => 1}).should == InsertionRelation.new(@relation1, tuple) + @relation1.insert(record = {:id => 1}).should be_kind_of(InsertionRelation) end end end diff --git a/spec/active_relation/relations/rename_relation_spec.rb b/spec/active_relation/relations/rename_relation_spec.rb index 00a93d10ac5a7..664e9c61454ce 100644 --- a/spec/active_relation/relations/rename_relation_spec.rb +++ b/spec/active_relation/relations/rename_relation_spec.rb @@ -52,13 +52,10 @@ describe '#to_sql' do it 'manufactures sql aliasing the attribute' do - @renamed_relation.to_s.should == SelectBuilder.new do - select do - column :foo, :name - column :foo, :id, :schmid - end - from :foo - end.to_s + @renamed_relation.to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` AS 'schmid' + FROM `foo` + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/selection_relation_spec.rb b/spec/active_relation/relations/selection_relation_spec.rb index c4aadc807ba3e..ac1f227c67e77 100644 --- a/spec/active_relation/relations/selection_relation_spec.rb +++ b/spec/active_relation/relations/selection_relation_spec.rb @@ -8,17 +8,6 @@ @predicate2 = LessThanPredicate.new(@relation1[:age], 2) end - describe '==' do - it "obtains if both the predicate and the relation are identical" do - SelectionRelation.new(@relation1, @predicate1). \ - should == SelectionRelation.new(@relation1, @predicate1) - SelectionRelation.new(@relation1, @predicate1). \ - should_not == SelectionRelation.new(@relation2, @predicate1) - SelectionRelation.new(@relation1, @predicate1). \ - should_not == SelectionRelation.new(@relation1, @predicate2) - end - end - describe '#initialize' do it "manufactures nested selection relations if multiple predicates are provided" do SelectionRelation.new(@relation1, @predicate1, @predicate2). \ @@ -35,19 +24,19 @@ describe '#to_sql' do it "manufactures sql with where clause conditions" do - SelectionRelation.new(@relation1, @predicate1).to_s.should == SelectBuilder.new do - select do - column :foo, :name - column :foo, :id - end - from :foo - where do - equals do - column :foo, :id - column :bar, :foo_id - end - end - end.to_s + SelectionRelation.new(@relation1, @predicate1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE `foo`.`id` = `bar`.`foo_id` + """) + end + + it "allows arbitrary sql" do + SelectionRelation.new(@relation1, "asdf").to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE asdf + """) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/table_relation_spec.rb b/spec/active_relation/relations/table_relation_spec.rb index c943fe6c9201d..79e9610e1b710 100644 --- a/spec/active_relation/relations/table_relation_spec.rb +++ b/spec/active_relation/relations/table_relation_spec.rb @@ -7,13 +7,10 @@ describe '#to_sql' do it "returns a simple SELECT query" do - @relation.to_sql.should == SelectBuilder.new do |s| - select do - column :users, :name - column :users, :id - end - from :users - end + @relation.to_sql.should be_like(""" + SELECT `users`.`name`, `users`.`id` + FROM `users` + """) end end diff --git a/spec/active_relation/sql_builder/conditions_spec.rb b/spec/active_relation/sql_builder/conditions_spec.rb deleted file mode 100644 index dc2d10a2f6924..0000000000000 --- a/spec/active_relation/sql_builder/conditions_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ConditionsBuilder do - describe '#to_s' do - describe 'with aliased columns' do - it 'manufactures correct sql' do - ConditionsBuilder.new do - equals do - column(:a, :b) - column(:c, :d, 'e') - end - end.to_s.should be_like(""" - `a`.`b` = `c`.`d` - """) - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/sql_builder/delete_builder_spec.rb b/spec/active_relation/sql_builder/delete_builder_spec.rb deleted file mode 100644 index fd62fde155354..0000000000000 --- a/spec/active_relation/sql_builder/delete_builder_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe DeleteBuilder do - describe '#to_s' do - it 'manufactures correct sql' do - DeleteBuilder.new do - delete - from :users - where do - equals do - column :users, :id - value 1 - end - end - end.to_s.should be_like(""" - DELETE - FROM `users` - WHERE `users`.`id` = 1 - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/sql_builder/insert_builder_spec.rb b/spec/active_relation/sql_builder/insert_builder_spec.rb deleted file mode 100644 index dddc971986fb1..0000000000000 --- a/spec/active_relation/sql_builder/insert_builder_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe InsertBuilder do - describe '#to_s' do - it 'manufactures correct sql' do - InsertBuilder.new do - insert - into :users - columns do - column :users, :id - column :users, :name - end - values do - row 1, 'bob' - row 2, 'moe' - end - end.to_s.should be_like(""" - INSERT - INTO `users` - (`users`.`id`, `users`.`name`) VALUES (1, 'bob'), (2, 'moe') - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/sql_builder/select_builder_spec.rb b/spec/active_relation/sql_builder/select_builder_spec.rb deleted file mode 100644 index 6539afe0c4425..0000000000000 --- a/spec/active_relation/sql_builder/select_builder_spec.rb +++ /dev/null @@ -1,148 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe SelectBuilder do - describe '#to_s' do - describe 'with select and from clauses' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users - end.to_s.should be_like(""" - SELECT * - FROM `users` - """) - end - end - - describe 'with specified columns and column aliases' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - column :a, :b, 'c' - column :e, :f - end - from :users - end.to_s.should be_like(""" - SELECT `a`.`b` AS 'c', `e`.`f` - FROM `users` - """) - end - end - - describe 'with where clause' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users - where do - equals do - value 1 - column :b, :c - end - end - end.to_s.should be_like(""" - SELECT * - FROM `users` - WHERE 1 = `b`.`c` - """) - end - - it 'accepts arbitrary strings' do - SelectBuilder.new do - select do - all - end - from :users - where do - value "'a' = 'a'" - end - end.to_s.should be_like(""" - SELECT * - FROM `users` - WHERE 'a' = 'a' - """) - end - end - - describe 'with inner join' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users do - inner_join(:friendships) do - equals do - column :users, :id - column :friendships, :user_id - end - end - end - end.to_s.should be_like(""" - SELECT * - FROM `users` - INNER JOIN `friendships` - ON `users`.`id` = `friendships`.`user_id` - """) - end - - it 'accepts arbitrary on strings' do - SelectBuilder.new do - select do - all - end - from :users do - inner_join :friendships do - value "arbitrary" - end - end - end.to_s.should be_like(""" - SELECT * - FROM `users` - INNER JOIN `friendships` ON arbitrary - """) - end - end - - describe 'with order' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users - order_by do - column :users, :id - column :users, :created_at, 'alias' - end - end.to_s.should be_like(""" - SELECT * - FROM `users` - ORDER BY `users`.`id`, `users`.`created_at` - """) - end - end - - describe 'with limit and/or offset' do - it 'manufactures correct sql' do - SelectBuilder.new do - select do - all - end - from :users - limit 10 - offset 10 - end.to_s.should be_like(""" - SELECT * - FROM `users` - LIMIT 10 - OFFSET 10 - """) - end - end - end -end \ No newline at end of file From 45b6111c2961e018df87fe2230caf1d5a14f2aee Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 10 Jan 2008 21:33:35 -0800 Subject: [PATCH 0022/1492] namespacing --- lib/active_relation.rb | 15 +- lib/active_relation/extensions/base.rb | 2 +- lib/active_relation/extensions/object.rb | 2 +- lib/active_relation/predicates.rb | 70 ++++++++ .../predicates/binary_predicate.rb | 19 -- .../predicates/equality_predicate.rb | 12 -- .../greater_than_or_equal_to_predicate.rb | 2 - .../predicates/greater_than_predicate.rb | 2 - .../less_than_or_equal_to_predicate.rb | 2 - .../predicates/less_than_predicate.rb | 2 - .../predicates/match_predicate.rb | 7 - lib/active_relation/predicates/predicate.rb | 5 - .../relation_inclusion_predicate.rb | 11 -- lib/active_relation/relations/attribute.rb | 96 +++++----- .../relations/compound_relation.rb | 10 +- .../relations/deletion_relation.rb | 26 +-- .../relations/inner_join_operation.rb | 6 - .../relations/inner_join_relation.rb | 6 - .../relations/insertion_relation.rb | 36 ++-- .../relations/join_operation.rb | 16 -- .../relations/join_relation.rb | 80 +++++---- .../relations/left_outer_join_operation.rb | 6 - .../relations/left_outer_join_relation.rb | 6 - .../relations/order_relation.rb | 24 +-- .../relations/projection_relation.rb | 24 +-- .../relations/range_relation.rb | 30 ++-- lib/active_relation/relations/relation.rb | 167 ++++++++++-------- .../relations/rename_relation.rb | 56 +++--- .../relations/selection_relation.rb | 34 ++-- .../relations/table_relation.rb | 50 +++--- lib/active_relation/sql_builder.rb | 12 +- .../predicates/binary_predicate_spec.rb | 28 +-- .../predicates/equality_predicate_spec.rb | 18 +- .../relation_inclusion_predicate_spec.rb | 12 +- .../relations/attribute_spec.rb | 30 ++-- .../relations/deletion_relation_spec.rb | 8 +- .../relations/insertion_relation_spec.rb | 10 +- .../relations/join_operation_spec.rb | 39 ---- .../relations/join_relation_spec.rb | 20 +-- .../relations/order_relation_spec.rb | 12 +- .../relations/projection_relation_spec.rb | 18 +- .../relations/range_relation_spec.rb | 8 +- .../relations/relation_spec.rb | 40 +++-- .../relations/rename_relation_spec.rb | 16 +- .../relations/selection_relation_spec.rb | 22 +-- .../relations/table_relation_spec.rb | 8 +- 46 files changed, 556 insertions(+), 569 deletions(-) delete mode 100644 lib/active_relation/predicates/binary_predicate.rb delete mode 100644 lib/active_relation/predicates/equality_predicate.rb delete mode 100644 lib/active_relation/predicates/greater_than_or_equal_to_predicate.rb delete mode 100644 lib/active_relation/predicates/greater_than_predicate.rb delete mode 100644 lib/active_relation/predicates/less_than_or_equal_to_predicate.rb delete mode 100644 lib/active_relation/predicates/less_than_predicate.rb delete mode 100644 lib/active_relation/predicates/match_predicate.rb delete mode 100644 lib/active_relation/predicates/predicate.rb delete mode 100644 lib/active_relation/predicates/relation_inclusion_predicate.rb delete mode 100644 lib/active_relation/relations/inner_join_operation.rb delete mode 100644 lib/active_relation/relations/inner_join_relation.rb delete mode 100644 lib/active_relation/relations/join_operation.rb delete mode 100644 lib/active_relation/relations/left_outer_join_operation.rb delete mode 100644 lib/active_relation/relations/left_outer_join_relation.rb delete mode 100644 spec/active_relation/relations/join_operation_spec.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 2120d09bc87fa..3f277df1a5548 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -9,12 +9,7 @@ require 'active_relation/relations/relation' require 'active_relation/relations/compound_relation' require 'active_relation/relations/table_relation' -require 'active_relation/relations/join_operation' -require 'active_relation/relations/inner_join_operation' -require 'active_relation/relations/left_outer_join_operation' require 'active_relation/relations/join_relation' -require 'active_relation/relations/inner_join_relation' -require 'active_relation/relations/left_outer_join_relation' require 'active_relation/relations/attribute' require 'active_relation/relations/projection_relation' require 'active_relation/relations/selection_relation' @@ -24,15 +19,7 @@ require 'active_relation/relations/deletion_relation' require 'active_relation/relations/insertion_relation' -require 'active_relation/predicates/predicate' -require 'active_relation/predicates/binary_predicate' -require 'active_relation/predicates/equality_predicate' -require 'active_relation/predicates/less_than_predicate' -require 'active_relation/predicates/less_than_or_equal_to_predicate' -require 'active_relation/predicates/greater_than_predicate' -require 'active_relation/predicates/greater_than_or_equal_to_predicate' -require 'active_relation/predicates/relation_inclusion_predicate' -require 'active_relation/predicates/match_predicate' +require 'active_relation/predicates' require 'active_relation/extensions/object' require 'active_relation/extensions/array' diff --git a/lib/active_relation/extensions/base.rb b/lib/active_relation/extensions/base.rb index 0dbdef703ff7a..53523e9d12faf 100644 --- a/lib/active_relation/extensions/base.rb +++ b/lib/active_relation/extensions/base.rb @@ -5,7 +5,7 @@ def cache end def relation - @relation ||= TableRelation.new(table_name) + @relation ||= ActiveRelation::Relations::Table.new(table_name) end end diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 79d7613d9a445..ea582d1ca1819 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -1,5 +1,5 @@ class Object - include SqlBuilder + include ActiveRelation::SqlBuilder def qualify self diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 0179a15035672..5ac879899bffb 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -1,4 +1,74 @@ module ActiveRelation module Predicates + class Base + def ==(other) + self.class == other.class + end + end + + class Binary < Base + attr_reader :attribute1, :attribute2 + + def initialize(attribute1, attribute2) + @attribute1, @attribute2 = attribute1, attribute2 + end + + def ==(other) + super and @attribute1.eql?(other.attribute1) and @attribute2.eql?(other.attribute2) + end + + def qualify + self.class.new(attribute1.qualify, attribute2.qualify) + end + + def to_sql(options = {}) + "#{attribute1.to_sql} #{predicate_sql} #{attribute2.to_sql}" + end + end + + class Equality < Binary + def ==(other) + self.class == other.class and + ((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or + (attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1))) + end + + protected + def predicate_sql + '=' + end + end + + class GreaterThanOrEqualTo < Binary + end + + class GreaterThan < Binary + end + + class LessThanOrEqualTo < Binary + end + + class LessThan < Binary + end + + class Match < Base + attr_reader :attribute, :regexp + + def initialize(attribute, regexp) + @attribute, @regexp = attribute, regexp + end + end + + class RelationInclusion < Base + attr_reader :attribute, :relation + + def initialize(attribute, relation) + @attribute, @relation = attribute, relation + end + + def ==(other) + super and attribute == other.attribute and relation == other.relation + end + end end end \ No newline at end of file diff --git a/lib/active_relation/predicates/binary_predicate.rb b/lib/active_relation/predicates/binary_predicate.rb deleted file mode 100644 index f3ce430d00b70..0000000000000 --- a/lib/active_relation/predicates/binary_predicate.rb +++ /dev/null @@ -1,19 +0,0 @@ -class BinaryPredicate < Predicate - attr_reader :attribute1, :attribute2 - - def initialize(attribute1, attribute2) - @attribute1, @attribute2 = attribute1, attribute2 - end - - def ==(other) - super and @attribute1.eql?(other.attribute1) and @attribute2.eql?(other.attribute2) - end - - def qualify - self.class.new(attribute1.qualify, attribute2.qualify) - end - - def to_sql(options = {}) - "#{attribute1.to_sql} #{predicate_sql} #{attribute2.to_sql}" - end -end \ No newline at end of file diff --git a/lib/active_relation/predicates/equality_predicate.rb b/lib/active_relation/predicates/equality_predicate.rb deleted file mode 100644 index 4f4113c7405ea..0000000000000 --- a/lib/active_relation/predicates/equality_predicate.rb +++ /dev/null @@ -1,12 +0,0 @@ -class EqualityPredicate < BinaryPredicate - def ==(other) - self.class == other.class and - ((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or - (attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1))) - end - - protected - def predicate_sql - '=' - end -end \ No newline at end of file diff --git a/lib/active_relation/predicates/greater_than_or_equal_to_predicate.rb b/lib/active_relation/predicates/greater_than_or_equal_to_predicate.rb deleted file mode 100644 index 49127c312c041..0000000000000 --- a/lib/active_relation/predicates/greater_than_or_equal_to_predicate.rb +++ /dev/null @@ -1,2 +0,0 @@ -class GreaterThanOrEqualToPredicate < BinaryPredicate -end \ No newline at end of file diff --git a/lib/active_relation/predicates/greater_than_predicate.rb b/lib/active_relation/predicates/greater_than_predicate.rb deleted file mode 100644 index 03aecaed62601..0000000000000 --- a/lib/active_relation/predicates/greater_than_predicate.rb +++ /dev/null @@ -1,2 +0,0 @@ -class GreaterThanPredicate < BinaryPredicate -end \ No newline at end of file diff --git a/lib/active_relation/predicates/less_than_or_equal_to_predicate.rb b/lib/active_relation/predicates/less_than_or_equal_to_predicate.rb deleted file mode 100644 index fee6ea7f35627..0000000000000 --- a/lib/active_relation/predicates/less_than_or_equal_to_predicate.rb +++ /dev/null @@ -1,2 +0,0 @@ -class LessThanOrEqualToPredicate < BinaryPredicate -end \ No newline at end of file diff --git a/lib/active_relation/predicates/less_than_predicate.rb b/lib/active_relation/predicates/less_than_predicate.rb deleted file mode 100644 index 03cbdcf0002e4..0000000000000 --- a/lib/active_relation/predicates/less_than_predicate.rb +++ /dev/null @@ -1,2 +0,0 @@ -class LessThanPredicate < BinaryPredicate -end \ No newline at end of file diff --git a/lib/active_relation/predicates/match_predicate.rb b/lib/active_relation/predicates/match_predicate.rb deleted file mode 100644 index 90a13090d43e7..0000000000000 --- a/lib/active_relation/predicates/match_predicate.rb +++ /dev/null @@ -1,7 +0,0 @@ -class MatchPredicate < Predicate - attr_reader :attribute, :regexp - - def initialize(attribute, regexp) - @attribute, @regexp = attribute, regexp - end -end \ No newline at end of file diff --git a/lib/active_relation/predicates/predicate.rb b/lib/active_relation/predicates/predicate.rb deleted file mode 100644 index 4c395a3fdc2b3..0000000000000 --- a/lib/active_relation/predicates/predicate.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Predicate - def ==(other) - self.class == other.class - end -end \ No newline at end of file diff --git a/lib/active_relation/predicates/relation_inclusion_predicate.rb b/lib/active_relation/predicates/relation_inclusion_predicate.rb deleted file mode 100644 index 5881a85d997b4..0000000000000 --- a/lib/active_relation/predicates/relation_inclusion_predicate.rb +++ /dev/null @@ -1,11 +0,0 @@ -class RelationInclusionPredicate < Predicate - attr_reader :attribute, :relation - - def initialize(attribute, relation) - @attribute, @relation = attribute, relation - end - - def ==(other) - super and attribute == other.attribute and relation == other.relation - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/attribute.rb b/lib/active_relation/relations/attribute.rb index 8193132de6507..30cd9798d9bca 100644 --- a/lib/active_relation/relations/attribute.rb +++ b/lib/active_relation/relations/attribute.rb @@ -1,56 +1,60 @@ -class Attribute - include SqlBuilder +module ActiveRelation + module Primitives + class Attribute + include ::ActiveRelation::SqlBuilder - attr_reader :relation, :name, :alias + attr_reader :relation, :name, :alias - def initialize(relation, name, aliaz = nil) - @relation, @name, @alias = relation, name, aliaz - end + def initialize(relation, name, aliaz = nil) + @relation, @name, @alias = relation, name, aliaz + end - def alias(aliaz = nil) - aliaz ? Attribute.new(relation, name, aliaz) : @alias - end + def alias(aliaz = nil) + aliaz ? ActiveRelation::Primitives::Attribute.new(relation, name, aliaz) : @alias + end - def qualified_name - "#{relation.table}.#{name}" - end + def qualified_name + "#{relation.table}.#{name}" + end - def qualify - self.alias(qualified_name) - end + def qualify + self.alias(qualified_name) + end - def eql?(other) - relation == other.relation and name == other.name and self.alias == other.alias - end + def eql?(other) + relation == other.relation and name == other.name and self.alias == other.alias + end - module Predications - def ==(other) - EqualityPredicate.new(self, other) - end - - def <(other) - LessThanPredicate.new(self, other) - end - - def <=(other) - LessThanOrEqualToPredicate.new(self, other) + module Predications + def ==(other) + Predicates::Equality.new(self, other) + end + + def <(other) + Predicates::LessThan.new(self, other) + end + + def <=(other) + Predicates::LessThanOrEqualTo.new(self, other) + end + + def >(other) + Predicates::GreaterThan.new(self, other) + end + + def >=(other) + Predicates::GreaterThanOrEqualTo.new(self, other) + end + + def =~(regexp) + Predicates::Match.new(self, regexp) + end + end + include Predications + + def to_sql(options = {}) + "#{quote_table_name(relation.table)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") + end end - - def >(other) - GreaterThanPredicate.new(self, other) - end - - def >=(other) - GreaterThanOrEqualToPredicate.new(self, other) - end - - def =~(regexp) - MatchPredicate.new(self, regexp) - end - end - include Predications - - def to_sql(options = {}) - "#{quote_table_name(relation.table)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") end end \ No newline at end of file diff --git a/lib/active_relation/relations/compound_relation.rb b/lib/active_relation/relations/compound_relation.rb index b18921e06d9c6..442224a011e28 100644 --- a/lib/active_relation/relations/compound_relation.rb +++ b/lib/active_relation/relations/compound_relation.rb @@ -1,5 +1,9 @@ -class CompoundRelation < Relation - attr_reader :relation +module ActiveRelation + module Relations + class Compound < Base + attr_reader :relation - delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :to => :relation + delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :to => :relation + end + end end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion_relation.rb b/lib/active_relation/relations/deletion_relation.rb index 8418319055325..f218d9da6d4f5 100644 --- a/lib/active_relation/relations/deletion_relation.rb +++ b/lib/active_relation/relations/deletion_relation.rb @@ -1,13 +1,17 @@ -class DeletionRelation < CompoundRelation - def initialize(relation) - @relation = relation - end +module ActiveRelation + module Relations + class Deletion < Compound + def initialize(relation) + @relation = relation + end - def to_sql(options = {}) - [ - "DELETE", - "FROM #{quote_table_name(table)}", - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) - ].compact.join("\n") - end + def to_sql(options = {}) + [ + "DELETE", + "FROM #{quote_table_name(table)}", + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ].compact.join("\n") + end + end + end end \ No newline at end of file diff --git a/lib/active_relation/relations/inner_join_operation.rb b/lib/active_relation/relations/inner_join_operation.rb deleted file mode 100644 index 6b5c5ce8d0bb3..0000000000000 --- a/lib/active_relation/relations/inner_join_operation.rb +++ /dev/null @@ -1,6 +0,0 @@ -class InnerJoinOperation < JoinOperation - protected - def relation_class - InnerJoinRelation - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/inner_join_relation.rb b/lib/active_relation/relations/inner_join_relation.rb deleted file mode 100644 index 74160c559ff70..0000000000000 --- a/lib/active_relation/relations/inner_join_relation.rb +++ /dev/null @@ -1,6 +0,0 @@ -class InnerJoinRelation < JoinRelation - protected - def join_sql - "INNER JOIN" - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion_relation.rb b/lib/active_relation/relations/insertion_relation.rb index 002ebbf062f71..a0042a18a5fbe 100644 --- a/lib/active_relation/relations/insertion_relation.rb +++ b/lib/active_relation/relations/insertion_relation.rb @@ -1,21 +1,25 @@ -class InsertionRelation < CompoundRelation - attr_reader :record +module ActiveRelation + module Relations + class Insertion < Compound + attr_reader :record - def initialize(relation, record) - @relation, @record = relation, record - end + def initialize(relation, record) + @relation, @record = relation, record + end - def to_sql(options = {}) - [ - "INSERT", - "INTO #{quote_table_name(table)}", - "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES #{inserts.collect(&:to_sql).join(', ')}" - ].join("\n") - end + def to_sql(options = {}) + [ + "INSERT", + "INTO #{quote_table_name(table)}", + "(#{record.keys.collect(&:to_sql).join(', ')})", + "VALUES #{inserts.collect(&:to_sql).join(', ')}" + ].join("\n") + end - protected - def inserts - relation.inserts + [record] + protected + def inserts + relation.inserts + [record] + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join_operation.rb b/lib/active_relation/relations/join_operation.rb deleted file mode 100644 index 2b4548a041af3..0000000000000 --- a/lib/active_relation/relations/join_operation.rb +++ /dev/null @@ -1,16 +0,0 @@ -class JoinOperation - attr_reader :relation1, :relation2 - - def initialize(relation1, relation2) - @relation1, @relation2 = relation1, relation2 - end - - def on(*predicates) - relation_class.new(relation1, relation2, *predicates) - end - - def ==(other) - (relation1 == other.relation1 and relation2 == other.relation2) or - (relation1 == other.relation2 and relation2 == other.relation1) - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/join_relation.rb b/lib/active_relation/relations/join_relation.rb index 845dfd732f49e..1bd1439dd64be 100644 --- a/lib/active_relation/relations/join_relation.rb +++ b/lib/active_relation/relations/join_relation.rb @@ -1,41 +1,45 @@ -class JoinRelation < Relation - attr_reader :relation1, :relation2, :predicates - - def initialize(relation1, relation2, *predicates) - @relation1, @relation2, @predicates = relation1, relation2, predicates - end - - def ==(other) - predicates == other.predicates and - ((relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2)) - end +module ActiveRelation + module Relations + class Join < Base + attr_reader :join_sql, :relation1, :relation2, :predicates + + def initialize(join_sql, relation1, relation2, *predicates) + @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + end + + def ==(other) + predicates == other.predicates and + ((relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2)) + end - def qualify - self.class.new(relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) - end - - protected - def joins - [relation1.joins, relation2.joins, join].compact.join(" ") - end - - def selects - relation1.send(:selects) + relation2.send(:selects) - end - - def attributes - relation1.attributes + relation2.attributes - end - - def attribute(name) - relation1[name] || relation2[name] - end - - delegate :table, :to => :relation1 - - private - def join - "#{join_sql} #{quote_table_name(relation2.table)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" + def qualify + Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + end + + protected + def joins + [relation1.joins, relation2.joins, join].compact.join(" ") + end + + def selects + relation1.send(:selects) + relation2.send(:selects) + end + + def attributes + relation1.attributes + relation2.attributes + end + + def attribute(name) + relation1[name] || relation2[name] + end + + delegate :table, :to => :relation1 + + private + def join + "#{join_sql} #{quote_table_name(relation2.table)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/left_outer_join_operation.rb b/lib/active_relation/relations/left_outer_join_operation.rb deleted file mode 100644 index fbb2a4e2ed482..0000000000000 --- a/lib/active_relation/relations/left_outer_join_operation.rb +++ /dev/null @@ -1,6 +0,0 @@ -class LeftOuterJoinOperation < JoinOperation - protected - def relation_class - LeftOuterJoinRelation - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/left_outer_join_relation.rb b/lib/active_relation/relations/left_outer_join_relation.rb deleted file mode 100644 index 57eda4e1fc91d..0000000000000 --- a/lib/active_relation/relations/left_outer_join_relation.rb +++ /dev/null @@ -1,6 +0,0 @@ -class LeftOuterJoinRelation < JoinRelation - protected - def join_sql - "LEFT OUTER JOIN" - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/order_relation.rb b/lib/active_relation/relations/order_relation.rb index dfb0c0bf2567d..99ff939528345 100644 --- a/lib/active_relation/relations/order_relation.rb +++ b/lib/active_relation/relations/order_relation.rb @@ -1,15 +1,19 @@ -class OrderRelation < CompoundRelation - attr_reader :relation, :orders +module ActiveRelation + module Relations + class Order < Compound + attr_reader :relation, :orders - def initialize(relation, *orders) - @relation, @orders = relation, orders - end + def initialize(relation, *orders) + @relation, @orders = relation, orders + end - def ==(other) - relation == other.relation and orders.eql?(other.orders) - end + def ==(other) + relation == other.relation and orders.eql?(other.orders) + end - def qualify - OrderRelation.new(relation.qualify, *orders.collect { |o| o.qualify }) + def qualify + Order.new(relation.qualify, *orders.collect { |o| o.qualify }) + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/projection_relation.rb b/lib/active_relation/relations/projection_relation.rb index 53b0ad1e91b9e..b30c76898df7d 100644 --- a/lib/active_relation/relations/projection_relation.rb +++ b/lib/active_relation/relations/projection_relation.rb @@ -1,15 +1,19 @@ -class ProjectionRelation < CompoundRelation - attr_reader :relation, :attributes +module ActiveRelation + module Relations + class Projection < Compound + attr_reader :relation, :attributes - def initialize(relation, *attributes) - @relation, @attributes = relation, attributes - end + def initialize(relation, *attributes) + @relation, @attributes = relation, attributes + end - def ==(other) - relation == other.relation and attributes.eql?(other.attributes) - end + def ==(other) + relation == other.relation and attributes.eql?(other.attributes) + end - def qualify - ProjectionRelation.new(relation.qualify, *attributes.collect(&:qualify)) + def qualify + Projection.new(relation.qualify, *attributes.collect(&:qualify)) + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/range_relation.rb b/lib/active_relation/relations/range_relation.rb index 6a2b0b34700c2..d7e08efa0637f 100644 --- a/lib/active_relation/relations/range_relation.rb +++ b/lib/active_relation/relations/range_relation.rb @@ -1,19 +1,23 @@ -class RangeRelation < CompoundRelation - attr_reader :range +module ActiveRelation + module Relations + class Range < Compound + attr_reader :range - def initialize(relation, range) - @relation, @range = relation, range - end + def initialize(relation, range) + @relation, @range = relation, range + end - def ==(other) - relation == other.relation and range == other.range - end + def ==(other) + relation == other.relation and range == other.range + end - def limit - range.end - range.begin + 1 - end + def limit + range.end - range.begin + 1 + end - def offset - range.begin + def offset + range.begin + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 0a8455b39caf3..c4a887eecdcaa 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -1,90 +1,111 @@ -class Relation - include SqlBuilder +module ActiveRelation + module Relations + class Base + include SqlBuilder - module Iteration - include Enumerable + module Iteration + include Enumerable - def each(&block) - connection.select_all(to_s).each(&block) - end + def each(&block) + connection.select_all(to_s).each(&block) + end - def first - connection.select_one(to_s) - end - end - include Iteration + def first + connection.select_one(to_s) + end + end + include Iteration - module Operations - def <=>(other) - InnerJoinOperation.new(self, other) - end + module Operations + def <=>(other) + JoinOperation.new("INNER JOIN", self, other) + end - def <<(other) - LeftOuterJoinOperation.new(self, other) - end + def <<(other) + JoinOperation.new("LEFT OUTER JOIN", self, other) + end - def [](index) - case index - when Symbol - attribute(index) - when Range - RangeRelation.new(self, index) - end - end + def [](index) + case index + when Symbol + attribute(index) + when ::Range + Range.new(self, index) + end + end - def include?(attribute) - RelationInclusionPredicate.new(attribute, self) - end + def include?(attribute) + Predicates::RelationInclusion.new(attribute, self) + end - def select(*predicates) - SelectionRelation.new(self, *predicates) - end + def select(*s) + Selection.new(self, *s) + end - def project(*attributes) - ProjectionRelation.new(self, *attributes) - end + def project(*attributes) + Projection.new(self, *attributes) + end - def order(*attributes) - OrderRelation.new(self, *attributes) - end + def order(*attributes) + Order.new(self, *attributes) + end - def rename(attribute, aliaz) - RenameRelation.new(self, attribute => aliaz) - end + def rename(attribute, aliaz) + Rename.new(self, attribute => aliaz) + end - def insert(record) - InsertionRelation.new(self, record) - end + def insert(record) + Insertion.new(self, record) + end - def delete - DeletionRelation.new(self) - end - end - include Operations + def delete + Deletion.new(self) + end + + class JoinOperation + attr_reader :join_sql, :relation1, :relation2 + + def initialize(join_sql, relation1, relation2) + @join_sql, @relation1, @relation2 = join_sql, relation1, relation2 + end + + def on(*predicates) + Join.new(join_sql, relation1, relation2, *predicates) + end + + def ==(other) + (relation1 == other.relation1 and relation2 == other.relation2) or + (relation1 == other.relation2 and relation2 == other.relation1) + end + end + end + include Operations - def connection - ActiveRecord::Base.connection - end + def connection + ActiveRecord::Base.connection + end - def to_sql(options = {}) - [ - "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", - "FROM #{quote_table_name(table)}", - (joins.to_sql(:quote => false) unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), - ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), - ("LIMIT #{limit.to_sql}" unless limit.blank?), - ("OFFSET #{offset.to_sql}" unless offset.blank?) - ].compact.join("\n") - end - alias_method :to_s, :to_sql + def to_sql(options = {}) + [ + "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", + "FROM #{quote_table_name(table)}", + (joins.to_sql(:quote => false) unless joins.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), + ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), + ("LIMIT #{limit.to_sql}" unless limit.blank?), + ("OFFSET #{offset.to_sql}" unless offset.blank?) + ].compact.join("\n") + end + alias_method :to_s, :to_sql - protected - def attributes; [] end - def selects; [] end - def orders; [] end - def inserts; [] end - def joins; nil end - def limit; nil end - def offset; nil end + protected + def attributes; [] end + def selects; [] end + def orders; [] end + def inserts; [] end + def joins; nil end + def limit; nil end + def offset; nil end + end + end end \ No newline at end of file diff --git a/lib/active_relation/relations/rename_relation.rb b/lib/active_relation/relations/rename_relation.rb index 3218889f33e22..7a1693df579e6 100644 --- a/lib/active_relation/relations/rename_relation.rb +++ b/lib/active_relation/relations/rename_relation.rb @@ -1,34 +1,38 @@ -class RenameRelation < CompoundRelation - attr_reader :relation, :schmattribute, :alias +module ActiveRelation + module Relations + class Rename < Compound + attr_reader :relation, :schmattribute, :alias - def initialize(relation, renames) - @schmattribute, @alias = renames.shift - @relation = renames.empty?? relation : RenameRelation.new(relation, renames) - end + def initialize(relation, renames) + @schmattribute, @alias = renames.shift + @relation = renames.empty?? relation : Rename.new(relation, renames) + end - def ==(other) - relation == other.relation and schmattribute.eql?(other.schmattribute) and self.alias == other.alias - end + def ==(other) + relation == other.relation and schmattribute.eql?(other.schmattribute) and self.alias == other.alias + end - def attributes - relation.attributes.collect { |a| substitute(a) } - end + def attributes + relation.attributes.collect { |a| substitute(a) } + end - def qualify - RenameRelation.new(relation.qualify, schmattribute.qualify => self.alias) - end + def qualify + Rename.new(relation.qualify, schmattribute.qualify => self.alias) + end - protected - def attribute(name) - case - when name == self.alias then schmattribute.alias(self.alias) - when relation[name].eql?(schmattribute) then nil - else relation[name] - end - end + protected + def attribute(name) + case + when name == self.alias then schmattribute.alias(self.alias) + when relation[name].eql?(schmattribute) then nil + else relation[name] + end + end - private - def substitute(a) - a.eql?(schmattribute) ? a.alias(self.alias) : a + private + def substitute(a) + a.eql?(schmattribute) ? a.alias(self.alias) : a + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/selection_relation.rb b/lib/active_relation/relations/selection_relation.rb index 77864efb285f3..e102d105a0cf4 100644 --- a/lib/active_relation/relations/selection_relation.rb +++ b/lib/active_relation/relations/selection_relation.rb @@ -1,21 +1,25 @@ -class SelectionRelation < CompoundRelation - attr_reader :relation, :predicate +module ActiveRelation + module Relations + class Selection < Compound + attr_reader :relation, :predicate - def initialize(relation, *predicates) - @predicate = predicates.shift - @relation = predicates.empty?? relation : SelectionRelation.new(relation, *predicates) - end + def initialize(relation, *predicates) + @predicate = predicates.shift + @relation = predicates.empty?? relation : Selection.new(relation, *predicates) + end - def ==(other) - relation == other.relation and predicate == other.predicate - end + def ==(other) + relation == other.relation and predicate == other.predicate + end - def qualify - SelectionRelation.new(relation.qualify, predicate.qualify) - end + def qualify + Selection.new(relation.qualify, predicate.qualify) + end - protected - def selects - relation.send(:selects) + [predicate] + protected + def selects + relation.send(:selects) + [predicate] + end + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/table_relation.rb b/lib/active_relation/relations/table_relation.rb index 5a47ae7a3426c..38f540cc5229a 100644 --- a/lib/active_relation/relations/table_relation.rb +++ b/lib/active_relation/relations/table_relation.rb @@ -1,31 +1,35 @@ -class TableRelation < Relation - attr_reader :table +module ActiveRelation + module Relations + class Table < Base + attr_reader :table - def initialize(table) - @table = table - end + def initialize(table) + @table = table + end - def attributes - attributes_by_name.values - end + def attributes + attributes_by_name.values + end - def qualify - RenameRelation.new self, qualifications - end + def qualify + Rename.new self, qualifications + end - protected - def attribute(name) - attributes_by_name[name.to_s] - end + protected + def attribute(name) + attributes_by_name[name.to_s] + end - private - def attributes_by_name - @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| - attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym)) - end - end + private + def attributes_by_name + @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| + attributes_by_name.merge(column.name => ActiveRelation::Primitives::Attribute.new(self, column.name.to_sym)) + end + end - def qualifications - attributes.zip(attributes.collect(&:qualified_name)).to_hash + def qualifications + attributes.zip(attributes.collect(&:qualified_name)).to_hash + end + end end end \ No newline at end of file diff --git a/lib/active_relation/sql_builder.rb b/lib/active_relation/sql_builder.rb index 0d2187173eba6..07a4ebabb7115 100644 --- a/lib/active_relation/sql_builder.rb +++ b/lib/active_relation/sql_builder.rb @@ -1,7 +1,9 @@ -module SqlBuilder - def connection - ActiveRecord::Base.connection - end +module ActiveRelation + module SqlBuilder + def connection + ActiveRecord::Base.connection + end - delegate :quote_table_name, :quote_column_name, :quote, :to => :connection + delegate :quote_table_name, :quote_column_name, :quote, :to => :connection + end end \ No newline at end of file diff --git a/spec/active_relation/predicates/binary_predicate_spec.rb b/spec/active_relation/predicates/binary_predicate_spec.rb index 0bddae8491281..02c72ef96d23d 100644 --- a/spec/active_relation/predicates/binary_predicate_spec.rb +++ b/spec/active_relation/predicates/binary_predicate_spec.rb @@ -1,12 +1,12 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe BinaryPredicate do +describe ActiveRelation::Predicates::Binary do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :name1) - @attribute2 = Attribute.new(@relation2, :name2) - class ConcreteBinaryPredicate < BinaryPredicate + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name1) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name2) + class ActiveRelation::Predicates::ConcreteBinary < ActiveRelation::Predicates::Binary def predicate_sql "<=>" end @@ -15,26 +15,26 @@ def predicate_sql describe '==' do it "obtains if attribute1 and attribute2 are identical" do - BinaryPredicate.new(@attribute1, @attribute2).should == BinaryPredicate.new(@attribute1, @attribute2) - BinaryPredicate.new(@attribute1, @attribute2).should_not == BinaryPredicate.new(@attribute1, @attribute1) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute1) end - it "obtains if the concrete type of the BinaryPredicates are identical" do - ConcreteBinaryPredicate.new(@attribute1, @attribute2).should == ConcreteBinaryPredicate.new(@attribute1, @attribute2) - BinaryPredicate.new(@attribute1, @attribute2).should_not == ConcreteBinaryPredicate.new(@attribute1, @attribute2) + it "obtains if the concrete type of the ActiveRelation::Predicates::Binarys are identical" do + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2) end end describe '#qualify' do it "distributes over the predicates and attributes" do - ConcreteBinaryPredicate.new(@attribute1, @attribute2).qualify. \ - should == ConcreteBinaryPredicate.new(@attribute1.qualify, @attribute2.qualify) + ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).qualify. \ + should == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) end end describe '#to_sql' do it 'manufactures correct sql' do - ConcreteBinaryPredicate.new(@attribute1, @attribute2).to_sql.should be_like(""" + ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" `foo`.`name1` <=> `bar`.`name2` """) end diff --git a/spec/active_relation/predicates/equality_predicate_spec.rb b/spec/active_relation/predicates/equality_predicate_spec.rb index af43b754e093f..b3c7b597a0802 100644 --- a/spec/active_relation/predicates/equality_predicate_spec.rb +++ b/spec/active_relation/predicates/equality_predicate_spec.rb @@ -1,25 +1,25 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe EqualityPredicate do +describe ActiveRelation::Predicates::Equality do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :name) - @attribute2 = Attribute.new(@relation2, :name) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) end describe '==' do it "obtains if attribute1 and attribute2 are identical" do - EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2) - EqualityPredicate.new(@attribute1, @attribute2).should_not == EqualityPredicate.new(@attribute1, @attribute1) + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute1) end it "obtains if the concrete type of the predicates are identical" do - EqualityPredicate.new(@attribute1, @attribute2).should_not == BinaryPredicate.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) end it "is commutative on the attributes" do - EqualityPredicate.new(@attribute1, @attribute2).should == EqualityPredicate.new(@attribute2, @attribute1) + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute2, @attribute1) end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb b/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb index f8c911429b351..a01f4fb76b3ca 100644 --- a/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb +++ b/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb @@ -1,16 +1,16 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe RelationInclusionPredicate do +describe ActiveRelation::Predicates::RelationInclusion do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) @attribute = @relation1[:baz] end - describe RelationInclusionPredicate, '==' do + describe ActiveRelation::Predicates::RelationInclusion, '==' do it "obtains if attribute1 and attribute2 are identical" do - RelationInclusionPredicate.new(@attribute, @relation1).should == RelationInclusionPredicate.new(@attribute, @relation1) - RelationInclusionPredicate.new(@attribute, @relation1).should_not == RelationInclusionPredicate.new(@attribute, @relation2) + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) end end end \ No newline at end of file diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb index 4154a91b85f76..71bba26aff7e1 100644 --- a/spec/active_relation/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -1,14 +1,14 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe Attribute do +describe ActiveRelation::Primitives::Attribute do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) end describe '#alias' do it "manufactures an aliased attributed" do - @relation1[:id].alias(:alias).should == Attribute.new(@relation1, :id, :alias) + @relation1[:id].alias(:alias).should == ActiveRelation::Primitives::Attribute.new(@relation1, :id, :alias) end end @@ -26,51 +26,51 @@ describe '#eql?' do it "obtains if the relation and attribute name are identical" do - Attribute.new(@relation1, :name).should be_eql(Attribute.new(@relation1, :name)) - Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation1, :another_name)) - Attribute.new(@relation1, :name).should_not be_eql(Attribute.new(@relation2, :name)) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should be_eql(ActiveRelation::Primitives::Attribute.new(@relation1, :name)) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not be_eql(ActiveRelation::Primitives::Attribute.new(@relation1, :another_name)) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not be_eql(ActiveRelation::Primitives::Attribute.new(@relation2, :name)) end end describe 'predications' do before do - @attribute1 = Attribute.new(@relation1, :name) - @attribute2 = Attribute.new(@relation2, :name) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) end describe '==' do it "manufactures an equality predicate" do - (@attribute1 == @attribute2).should == EqualityPredicate.new(@attribute1, @attribute2) + (@attribute1 == @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) end end describe '<' do it "manufactures a less-than predicate" do - (@attribute1 < @attribute2).should == LessThanPredicate.new(@attribute1, @attribute2) + (@attribute1 < @attribute2).should == ActiveRelation::Predicates::LessThan.new(@attribute1, @attribute2) end end describe '<=' do it "manufactures a less-than or equal-to predicate" do - (@attribute1 <= @attribute2).should == LessThanOrEqualToPredicate.new(@attribute1, @attribute2) + (@attribute1 <= @attribute2).should == ActiveRelation::Predicates::LessThanOrEqualTo.new(@attribute1, @attribute2) end end describe '>' do it "manufactures a greater-than predicate" do - (@attribute1 > @attribute2).should == GreaterThanPredicate.new(@attribute1, @attribute2) + (@attribute1 > @attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) end end describe '>=' do it "manufactures a greater-than or equal to predicate" do - (@attribute1 >= @attribute2).should == GreaterThanOrEqualToPredicate.new(@attribute1, @attribute2) + (@attribute1 >= @attribute2).should == ActiveRelation::Predicates::GreaterThanOrEqualTo.new(@attribute1, @attribute2) end end describe '=~' do it "manufactures a match predicate" do - (@attribute1 =~ /.*/).should == MatchPredicate.new(@attribute1, @attribute2) + (@attribute1 =~ /.*/).should == ActiveRelation::Predicates::Match.new(@attribute1, @attribute2) end end end diff --git a/spec/active_relation/relations/deletion_relation_spec.rb b/spec/active_relation/relations/deletion_relation_spec.rb index 5e8c5137b26e4..b80589bde605c 100644 --- a/spec/active_relation/relations/deletion_relation_spec.rb +++ b/spec/active_relation/relations/deletion_relation_spec.rb @@ -1,20 +1,20 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe DeletionRelation do +describe ActiveRelation::Relations::Deletion do before do - @relation = TableRelation.new(:users) + @relation = ActiveRelation::Relations::Table.new(:users) end describe '#to_sql' do it 'manufactures sql deleting a table relation' do - DeletionRelation.new(@relation).to_sql.should be_like(""" + ActiveRelation::Relations::Deletion.new(@relation).to_sql.should be_like(""" DELETE FROM `users` """) end it 'manufactures sql deleting a selection relation' do - DeletionRelation.new(@relation.select(@relation[:id] == 1)).to_sql.should be_like(""" + ActiveRelation::Relations::Deletion.new(@relation.select(@relation[:id] == 1)).to_sql.should be_like(""" DELETE FROM `users` WHERE `users`.`id` = 1 diff --git a/spec/active_relation/relations/insertion_relation_spec.rb b/spec/active_relation/relations/insertion_relation_spec.rb index 177918a94ac6f..da39edf773346 100644 --- a/spec/active_relation/relations/insertion_relation_spec.rb +++ b/spec/active_relation/relations/insertion_relation_spec.rb @@ -1,13 +1,13 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe InsertionRelation do +describe ActiveRelation::Relations::Insertion do before do - @relation = TableRelation.new(:users) + @relation = ActiveRelation::Relations::Table.new(:users) end describe '#to_sql' do it 'manufactures sql inserting the data for one item' do - InsertionRelation.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" INSERT INTO `users` (`users`.`name`) VALUES ('nick') @@ -15,8 +15,8 @@ end it 'manufactures sql inserting the data for multiple items' do - nested_insertion = InsertionRelation.new(@relation, @relation[:name] => "cobra") - InsertionRelation.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" + nested_insertion = ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "cobra") + ActiveRelation::Relations::Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" INSERT INTO `users` (`users`.`name`) VALUES ('cobra'), ('commander') diff --git a/spec/active_relation/relations/join_operation_spec.rb b/spec/active_relation/relations/join_operation_spec.rb deleted file mode 100644 index a8ab85123b01e..0000000000000 --- a/spec/active_relation/relations/join_operation_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe 'between two relations' do - before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - end - - describe '==' do - it "obtains if the relations of both joins are identical" do - JoinOperation.new(@relation1, @relation2).should == JoinOperation.new(@relation1, @relation2) - JoinOperation.new(@relation1, @relation2).should_not == JoinOperation.new(@relation1, @relation1) - end - - it "is commutative on the relations" do - JoinOperation.new(@relation1, @relation2).should == JoinOperation.new(@relation2, @relation1) - end - end - - describe 'on' do - before do - @predicate = Predicate.new - @join_operation = JoinOperation.new(@relation1, @relation2) - class << @join_operation - def relation_class - JoinRelation - end - end - end - - it "manufactures a join relation of the appropriate type" do - @join_operation.on(@predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) - end - - it "accepts arbitrary strings" do - @join_operation.on("arbitrary").should == JoinRelation.new(@relation1, @relation2, "arbitrary") - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/join_relation_spec.rb b/spec/active_relation/relations/join_relation_spec.rb index 3e60cc4c3441f..32771428a8ad5 100644 --- a/spec/active_relation/relations/join_relation_spec.rb +++ b/spec/active_relation/relations/join_relation_spec.rb @@ -1,27 +1,27 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe JoinRelation do +describe ActiveRelation::Relations::Join do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - @predicate = EqualityPredicate.new(@relation1[:id], @relation2[:id]) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @predicate = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:id]) end describe '==' do it 'obtains if the two relations and the predicate are identical' do - JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation1, @relation2, @predicate) - JoinRelation.new(@relation1, @relation2, @predicate).should_not == JoinRelation.new(@relation1, @relation1, @predicate) + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation1, @predicate) end it 'is commutative on the relations' do - JoinRelation.new(@relation1, @relation2, @predicate).should == JoinRelation.new(@relation2, @relation1, @predicate) + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation2, @relation1, @predicate) end end describe '#qualify' do it 'distributes over the relations and predicates' do - InnerJoinRelation.new(@relation1, @relation2, @predicate).qualify. \ - should == InnerJoinRelation.new(@relation1.qualify, @relation2.qualify, @predicate.qualify) + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ + should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) end end @@ -31,7 +31,7 @@ end it 'manufactures sql joining the two tables on the predicate, merging the selects' do - InnerJoinRelation.new(@relation1, @relation2, @predicate).to_sql.should be_like(""" + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` FROM `foo` INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` diff --git a/spec/active_relation/relations/order_relation_spec.rb b/spec/active_relation/relations/order_relation_spec.rb index 8655780c37c8d..edf2faf4559de 100644 --- a/spec/active_relation/relations/order_relation_spec.rb +++ b/spec/active_relation/relations/order_relation_spec.rb @@ -1,23 +1,23 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe OrderRelation do +describe ActiveRelation::Relations::Order do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) @attribute1 = @relation1[:id] @attribute2 = @relation2[:id] end describe '#qualify' do it "distributes over the relation and attributes" do - OrderRelation.new(@relation1, @attribute1).qualify. \ - should == OrderRelation.new(@relation1.qualify, @attribute1.qualify) + ActiveRelation::Relations::Order.new(@relation1, @attribute1).qualify. \ + should == ActiveRelation::Relations::Order.new(@relation1.qualify, @attribute1.qualify) end end describe '#to_sql' do it "manufactures sql with an order clause" do - OrderRelation.new(@relation1, @attribute1).to_sql.should be_like(""" + ActiveRelation::Relations::Order.new(@relation1, @attribute1).to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id` FROM `foo` ORDER BY `foo`.`id` diff --git a/spec/active_relation/relations/projection_relation_spec.rb b/spec/active_relation/relations/projection_relation_spec.rb index 77722a17c5920..8ba571e06ce00 100644 --- a/spec/active_relation/relations/projection_relation_spec.rb +++ b/spec/active_relation/relations/projection_relation_spec.rb @@ -1,31 +1,31 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ProjectionRelation do +describe ActiveRelation::Relations::Projection do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) @attribute1 = @relation1[:id] @attribute2 = @relation2[:id] end describe '==' do it "obtains if the relations and attributes are identical" do - ProjectionRelation.new(@relation1, @attribute1, @attribute2).should == ProjectionRelation.new(@relation1, @attribute1, @attribute2) - ProjectionRelation.new(@relation1, @attribute1).should_not == ProjectionRelation.new(@relation2, @attribute1) - ProjectionRelation.new(@relation1, @attribute1).should_not == ProjectionRelation.new(@relation1, @attribute2) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation2, @attribute1) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation1, @attribute2) end end describe '#qualify' do it "distributes over teh relation and attributes" do - ProjectionRelation.new(@relation1, @attribute1).qualify. \ - should == ProjectionRelation.new(@relation1.qualify, @attribute1.qualify) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).qualify. \ + should == ActiveRelation::Relations::Projection.new(@relation1.qualify, @attribute1.qualify) end end describe '#to_sql' do it "manufactures sql with a limited select clause" do - ProjectionRelation.new(@relation1, @attribute1).to_sql.should be_like(""" + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).to_sql.should be_like(""" SELECT `foo`.`id` FROM `foo` """) diff --git a/spec/active_relation/relations/range_relation_spec.rb b/spec/active_relation/relations/range_relation_spec.rb index 67e2b0d16400f..d4107259aac2b 100644 --- a/spec/active_relation/relations/range_relation_spec.rb +++ b/spec/active_relation/relations/range_relation_spec.rb @@ -1,9 +1,9 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe RangeRelation do +describe ActiveRelation::Relations::Range do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) @range1 = 1..2 @range2 = 4..9 end @@ -18,7 +18,7 @@ it "manufactures sql with limit and offset" do range_size = @range2.last - @range2.first + 1 range_start = @range2.first - RangeRelation.new(@relation1, @range2).to_s.should be_like(""" + ActiveRelation::Relations::Range.new(@relation1, @range2).to_s.should be_like(""" SELECT `foo`.`name`, `foo`.`id` FROM `foo` LIMIT #{range_size} diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index 5d7c40a53047b..caee3bb527953 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -1,40 +1,44 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe Relation do +describe ActiveRelation::Relations::Base do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - @attribute1 = Attribute.new(@relation1, :id) - @attribute2 = Attribute.new(@relation1, :name) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :id) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) end describe '[]' do it "manufactures an attribute when given a symbol" do - @relation1[:id].should be_kind_of(Attribute) + @relation1[:id].should == ActiveRelation::Primitives::Attribute.new(@relation1, :id) end it "manufactures a range relation when given a range" do - @relation1[1..2].should be_kind_of(RangeRelation) + @relation1[1..2].should == ActiveRelation::Relations::Range.new(@relation1, 1..2) end end describe '#include?' do it "manufactures an inclusion predicate" do - @relation1.include?(@attribute1).should be_kind_of(RelationInclusionPredicate) + @relation1.include?(@attribute1).should be_kind_of(ActiveRelation::Predicates::RelationInclusion) end end describe 'read operations' do describe 'joins' do + before do + @predicate = @relation1[:id] == @relation2[:id] + end + describe '<=>' do it "manufactures an inner join operation between those two relations" do - (@relation1 <=> @relation2).should be_kind_of(InnerJoinOperation) + (@relation1 <=> @relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) end end describe '<<' do it "manufactures a left outer join operation between those two relations" do - (@relation1 << @relation2).should be_kind_of(LeftOuterJoinOperation) + (@relation1 << @relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) end end end @@ -45,33 +49,33 @@ end it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should be_kind_of(ProjectionRelation) + @relation1.project(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Projection) end end describe '#rename' do it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should be_kind_of(RenameRelation) + @relation1.rename(@attribute1, :foo).should be_kind_of(ActiveRelation::Relations::Rename) end end describe '#select' do before do - @predicate = EqualityPredicate.new(@attribute1, @attribute2) + @predicate = ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) end it "manufactures a selection relation" do - @relation1.select(@predicate).should be_kind_of(SelectionRelation) + @relation1.select(@predicate).should be_kind_of(ActiveRelation::Relations::Selection) end it "accepts arbitrary strings" do - @relation1.select("arbitrary").should be_kind_of(SelectionRelation) + @relation1.select("arbitrary").should be_kind_of(ActiveRelation::Relations::Selection) end end describe '#order' do it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should be_kind_of(OrderRelation) + @relation1.order(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Order) end end end @@ -79,13 +83,13 @@ describe 'write operations' do describe '#delete' do it 'manufactures a deletion relation' do - @relation1.delete.should be_kind_of(DeletionRelation) + @relation1.delete.should be_kind_of(ActiveRelation::Relations::Deletion) end end describe '#insert' do it 'manufactures an insertion relation' do - @relation1.insert(record = {:id => 1}).should be_kind_of(InsertionRelation) + @relation1.insert(record = {:id => 1}).should be_kind_of(ActiveRelation::Relations::Insertion) end end end diff --git a/spec/active_relation/relations/rename_relation_spec.rb b/spec/active_relation/relations/rename_relation_spec.rb index 664e9c61454ce..6fac206ff12fe 100644 --- a/spec/active_relation/relations/rename_relation_spec.rb +++ b/spec/active_relation/relations/rename_relation_spec.rb @@ -1,15 +1,15 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe RenameRelation do +describe ActiveRelation::Relations::Rename do before do - @relation = TableRelation.new(:foo) - @renamed_relation = RenameRelation.new(@relation, @relation[:id] => :schmid) + @relation = ActiveRelation::Relations::Table.new(:foo) + @renamed_relation = ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid) end describe '#initialize' do it "manufactures nested rename relations if multiple renames are provided" do - RenameRelation.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ - should == RenameRelation.new(RenameRelation.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ + should == ActiveRelation::Relations::Rename.new(ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) end it "raises an exception if the alias provided is already used" do @@ -25,7 +25,7 @@ describe '#attributes' do it "manufactures a list of attributes with the renamed attribute aliased" do - RenameRelation.new(@relation, @relation[:id] => :schmid).attributes.should == + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == (@relation.attributes - [@relation[:id]]) + [@relation[:id].alias(:schmid)] end end @@ -45,8 +45,8 @@ describe '#qualify' do it "distributes over the relation and renames" do - RenameRelation.new(@relation, @relation[:id] => :schmid).qualify. \ - should == RenameRelation.new(@relation.qualify, @relation[:id].qualify => :schmid) + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).qualify. \ + should == ActiveRelation::Relations::Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) end end diff --git a/spec/active_relation/relations/selection_relation_spec.rb b/spec/active_relation/relations/selection_relation_spec.rb index ac1f227c67e77..90dc3169b6ca5 100644 --- a/spec/active_relation/relations/selection_relation_spec.rb +++ b/spec/active_relation/relations/selection_relation_spec.rb @@ -1,30 +1,30 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe SelectionRelation do +describe ActiveRelation::Relations::Selection do before do - @relation1 = TableRelation.new(:foo) - @relation2 = TableRelation.new(:bar) - @predicate1 = EqualityPredicate.new(@relation1[:id], @relation2[:foo_id]) - @predicate2 = LessThanPredicate.new(@relation1[:age], 2) + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @predicate1 = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:foo_id]) + @predicate2 = ActiveRelation::Predicates::LessThan.new(@relation1[:age], 2) end describe '#initialize' do it "manufactures nested selection relations if multiple predicates are provided" do - SelectionRelation.new(@relation1, @predicate1, @predicate2). \ - should == SelectionRelation.new(SelectionRelation.new(@relation1, @predicate2), @predicate1) + ActiveRelation::Relations::Selection.new(@relation1, @predicate1, @predicate2). \ + should == ActiveRelation::Relations::Selection.new(ActiveRelation::Relations::Selection.new(@relation1, @predicate2), @predicate1) end end describe '#qualify' do it "distributes over the relation and predicates" do - SelectionRelation.new(@relation1, @predicate1).qualify. \ - should == SelectionRelation.new(@relation1.qualify, @predicate1.qualify) + ActiveRelation::Relations::Selection.new(@relation1, @predicate1).qualify. \ + should == ActiveRelation::Relations::Selection.new(@relation1.qualify, @predicate1.qualify) end end describe '#to_sql' do it "manufactures sql with where clause conditions" do - SelectionRelation.new(@relation1, @predicate1).to_sql.should be_like(""" + ActiveRelation::Relations::Selection.new(@relation1, @predicate1).to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id` FROM `foo` WHERE `foo`.`id` = `bar`.`foo_id` @@ -32,7 +32,7 @@ end it "allows arbitrary sql" do - SelectionRelation.new(@relation1, "asdf").to_sql.should be_like(""" + ActiveRelation::Relations::Selection.new(@relation1, "asdf").to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id` FROM `foo` WHERE asdf diff --git a/spec/active_relation/relations/table_relation_spec.rb b/spec/active_relation/relations/table_relation_spec.rb index 79e9610e1b710..62b8e4498030d 100644 --- a/spec/active_relation/relations/table_relation_spec.rb +++ b/spec/active_relation/relations/table_relation_spec.rb @@ -1,8 +1,8 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe TableRelation do +describe ActiveRelation::Relations::Table do before do - @relation = TableRelation.new(:users) + @relation = ActiveRelation::Relations::Table.new(:users) end describe '#to_sql' do @@ -22,8 +22,8 @@ describe '#qualify' do it 'manufactures a rename relation with all attribute names qualified' do - @relation.qualify.should == RenameRelation.new( - RenameRelation.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' + @relation.qualify.should == ActiveRelation::Relations::Rename.new( + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' ) end end From dbdd86c689e962641d98ed0474a60d401582eac9 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 10 Jan 2008 21:54:09 -0800 Subject: [PATCH 0023/1492] renamed files, removed _relation suffix --- lib/active_relation.rb | 22 ++-- .../relations/compound_relation.rb | 9 -- .../relations/deletion_relation.rb | 17 --- .../relations/insertion_relation.rb | 25 ---- .../relations/join_relation.rb | 45 ------- .../relations/order_relation.rb | 19 --- .../relations/projection_relation.rb | 19 --- .../relations/range_relation.rb | 23 ---- lib/active_relation/relations/relation.rb | 111 ------------------ .../relations/rename_relation.rb | 38 ------ .../relations/selection_relation.rb | 25 ---- .../relations/table_relation.rb | 35 ------ 12 files changed, 11 insertions(+), 377 deletions(-) delete mode 100644 lib/active_relation/relations/compound_relation.rb delete mode 100644 lib/active_relation/relations/deletion_relation.rb delete mode 100644 lib/active_relation/relations/insertion_relation.rb delete mode 100644 lib/active_relation/relations/join_relation.rb delete mode 100644 lib/active_relation/relations/order_relation.rb delete mode 100644 lib/active_relation/relations/projection_relation.rb delete mode 100644 lib/active_relation/relations/range_relation.rb delete mode 100644 lib/active_relation/relations/relation.rb delete mode 100644 lib/active_relation/relations/rename_relation.rb delete mode 100644 lib/active_relation/relations/selection_relation.rb delete mode 100644 lib/active_relation/relations/table_relation.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 3f277df1a5548..61235a5ae80de 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -6,18 +6,18 @@ require 'active_relation/sql_builder' -require 'active_relation/relations/relation' -require 'active_relation/relations/compound_relation' -require 'active_relation/relations/table_relation' -require 'active_relation/relations/join_relation' +require 'active_relation/relations/base' +require 'active_relation/relations/compound' +require 'active_relation/relations/table' +require 'active_relation/relations/join' require 'active_relation/relations/attribute' -require 'active_relation/relations/projection_relation' -require 'active_relation/relations/selection_relation' -require 'active_relation/relations/order_relation' -require 'active_relation/relations/range_relation' -require 'active_relation/relations/rename_relation' -require 'active_relation/relations/deletion_relation' -require 'active_relation/relations/insertion_relation' +require 'active_relation/relations/projection' +require 'active_relation/relations/selection' +require 'active_relation/relations/order' +require 'active_relation/relations/range' +require 'active_relation/relations/rename' +require 'active_relation/relations/deletion' +require 'active_relation/relations/insertion' require 'active_relation/predicates' diff --git a/lib/active_relation/relations/compound_relation.rb b/lib/active_relation/relations/compound_relation.rb deleted file mode 100644 index 442224a011e28..0000000000000 --- a/lib/active_relation/relations/compound_relation.rb +++ /dev/null @@ -1,9 +0,0 @@ -module ActiveRelation - module Relations - class Compound < Base - attr_reader :relation - - delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :to => :relation - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion_relation.rb b/lib/active_relation/relations/deletion_relation.rb deleted file mode 100644 index f218d9da6d4f5..0000000000000 --- a/lib/active_relation/relations/deletion_relation.rb +++ /dev/null @@ -1,17 +0,0 @@ -module ActiveRelation - module Relations - class Deletion < Compound - def initialize(relation) - @relation = relation - end - - def to_sql(options = {}) - [ - "DELETE", - "FROM #{quote_table_name(table)}", - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) - ].compact.join("\n") - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion_relation.rb b/lib/active_relation/relations/insertion_relation.rb deleted file mode 100644 index a0042a18a5fbe..0000000000000 --- a/lib/active_relation/relations/insertion_relation.rb +++ /dev/null @@ -1,25 +0,0 @@ -module ActiveRelation - module Relations - class Insertion < Compound - attr_reader :record - - def initialize(relation, record) - @relation, @record = relation, record - end - - def to_sql(options = {}) - [ - "INSERT", - "INTO #{quote_table_name(table)}", - "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES #{inserts.collect(&:to_sql).join(', ')}" - ].join("\n") - end - - protected - def inserts - relation.inserts + [record] - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/join_relation.rb b/lib/active_relation/relations/join_relation.rb deleted file mode 100644 index 1bd1439dd64be..0000000000000 --- a/lib/active_relation/relations/join_relation.rb +++ /dev/null @@ -1,45 +0,0 @@ -module ActiveRelation - module Relations - class Join < Base - attr_reader :join_sql, :relation1, :relation2, :predicates - - def initialize(join_sql, relation1, relation2, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates - end - - def ==(other) - predicates == other.predicates and - ((relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2)) - end - - def qualify - Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) - end - - protected - def joins - [relation1.joins, relation2.joins, join].compact.join(" ") - end - - def selects - relation1.send(:selects) + relation2.send(:selects) - end - - def attributes - relation1.attributes + relation2.attributes - end - - def attribute(name) - relation1[name] || relation2[name] - end - - delegate :table, :to => :relation1 - - private - def join - "#{join_sql} #{quote_table_name(relation2.table)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/order_relation.rb b/lib/active_relation/relations/order_relation.rb deleted file mode 100644 index 99ff939528345..0000000000000 --- a/lib/active_relation/relations/order_relation.rb +++ /dev/null @@ -1,19 +0,0 @@ -module ActiveRelation - module Relations - class Order < Compound - attr_reader :relation, :orders - - def initialize(relation, *orders) - @relation, @orders = relation, orders - end - - def ==(other) - relation == other.relation and orders.eql?(other.orders) - end - - def qualify - Order.new(relation.qualify, *orders.collect { |o| o.qualify }) - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/projection_relation.rb b/lib/active_relation/relations/projection_relation.rb deleted file mode 100644 index b30c76898df7d..0000000000000 --- a/lib/active_relation/relations/projection_relation.rb +++ /dev/null @@ -1,19 +0,0 @@ -module ActiveRelation - module Relations - class Projection < Compound - attr_reader :relation, :attributes - - def initialize(relation, *attributes) - @relation, @attributes = relation, attributes - end - - def ==(other) - relation == other.relation and attributes.eql?(other.attributes) - end - - def qualify - Projection.new(relation.qualify, *attributes.collect(&:qualify)) - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/range_relation.rb b/lib/active_relation/relations/range_relation.rb deleted file mode 100644 index d7e08efa0637f..0000000000000 --- a/lib/active_relation/relations/range_relation.rb +++ /dev/null @@ -1,23 +0,0 @@ -module ActiveRelation - module Relations - class Range < Compound - attr_reader :range - - def initialize(relation, range) - @relation, @range = relation, range - end - - def ==(other) - relation == other.relation and range == other.range - end - - def limit - range.end - range.begin + 1 - end - - def offset - range.begin - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb deleted file mode 100644 index c4a887eecdcaa..0000000000000 --- a/lib/active_relation/relations/relation.rb +++ /dev/null @@ -1,111 +0,0 @@ -module ActiveRelation - module Relations - class Base - include SqlBuilder - - module Iteration - include Enumerable - - def each(&block) - connection.select_all(to_s).each(&block) - end - - def first - connection.select_one(to_s) - end - end - include Iteration - - module Operations - def <=>(other) - JoinOperation.new("INNER JOIN", self, other) - end - - def <<(other) - JoinOperation.new("LEFT OUTER JOIN", self, other) - end - - def [](index) - case index - when Symbol - attribute(index) - when ::Range - Range.new(self, index) - end - end - - def include?(attribute) - Predicates::RelationInclusion.new(attribute, self) - end - - def select(*s) - Selection.new(self, *s) - end - - def project(*attributes) - Projection.new(self, *attributes) - end - - def order(*attributes) - Order.new(self, *attributes) - end - - def rename(attribute, aliaz) - Rename.new(self, attribute => aliaz) - end - - def insert(record) - Insertion.new(self, record) - end - - def delete - Deletion.new(self) - end - - class JoinOperation - attr_reader :join_sql, :relation1, :relation2 - - def initialize(join_sql, relation1, relation2) - @join_sql, @relation1, @relation2 = join_sql, relation1, relation2 - end - - def on(*predicates) - Join.new(join_sql, relation1, relation2, *predicates) - end - - def ==(other) - (relation1 == other.relation1 and relation2 == other.relation2) or - (relation1 == other.relation2 and relation2 == other.relation1) - end - end - end - include Operations - - def connection - ActiveRecord::Base.connection - end - - def to_sql(options = {}) - [ - "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", - "FROM #{quote_table_name(table)}", - (joins.to_sql(:quote => false) unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), - ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), - ("LIMIT #{limit.to_sql}" unless limit.blank?), - ("OFFSET #{offset.to_sql}" unless offset.blank?) - ].compact.join("\n") - end - alias_method :to_s, :to_sql - - protected - def attributes; [] end - def selects; [] end - def orders; [] end - def inserts; [] end - def joins; nil end - def limit; nil end - def offset; nil end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/rename_relation.rb b/lib/active_relation/relations/rename_relation.rb deleted file mode 100644 index 7a1693df579e6..0000000000000 --- a/lib/active_relation/relations/rename_relation.rb +++ /dev/null @@ -1,38 +0,0 @@ -module ActiveRelation - module Relations - class Rename < Compound - attr_reader :relation, :schmattribute, :alias - - def initialize(relation, renames) - @schmattribute, @alias = renames.shift - @relation = renames.empty?? relation : Rename.new(relation, renames) - end - - def ==(other) - relation == other.relation and schmattribute.eql?(other.schmattribute) and self.alias == other.alias - end - - def attributes - relation.attributes.collect { |a| substitute(a) } - end - - def qualify - Rename.new(relation.qualify, schmattribute.qualify => self.alias) - end - - protected - def attribute(name) - case - when name == self.alias then schmattribute.alias(self.alias) - when relation[name].eql?(schmattribute) then nil - else relation[name] - end - end - - private - def substitute(a) - a.eql?(schmattribute) ? a.alias(self.alias) : a - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/selection_relation.rb b/lib/active_relation/relations/selection_relation.rb deleted file mode 100644 index e102d105a0cf4..0000000000000 --- a/lib/active_relation/relations/selection_relation.rb +++ /dev/null @@ -1,25 +0,0 @@ -module ActiveRelation - module Relations - class Selection < Compound - attr_reader :relation, :predicate - - def initialize(relation, *predicates) - @predicate = predicates.shift - @relation = predicates.empty?? relation : Selection.new(relation, *predicates) - end - - def ==(other) - relation == other.relation and predicate == other.predicate - end - - def qualify - Selection.new(relation.qualify, predicate.qualify) - end - - protected - def selects - relation.send(:selects) + [predicate] - end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/table_relation.rb b/lib/active_relation/relations/table_relation.rb deleted file mode 100644 index 38f540cc5229a..0000000000000 --- a/lib/active_relation/relations/table_relation.rb +++ /dev/null @@ -1,35 +0,0 @@ -module ActiveRelation - module Relations - class Table < Base - attr_reader :table - - def initialize(table) - @table = table - end - - def attributes - attributes_by_name.values - end - - def qualify - Rename.new self, qualifications - end - - protected - def attribute(name) - attributes_by_name[name.to_s] - end - - private - def attributes_by_name - @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| - attributes_by_name.merge(column.name => ActiveRelation::Primitives::Attribute.new(self, column.name.to_sym)) - end - end - - def qualifications - attributes.zip(attributes.collect(&:qualified_name)).to_hash - end - end - end -end \ No newline at end of file From 2e8ba954f4a8d14a1b2c147477cba3410aca0414 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 10 Jan 2008 22:01:33 -0800 Subject: [PATCH 0024/1492] reorganized requires --- lib/active_relation.rb | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 61235a5ae80de..ee207d418ebcd 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -6,22 +6,10 @@ require 'active_relation/sql_builder' -require 'active_relation/relations/base' -require 'active_relation/relations/compound' -require 'active_relation/relations/table' -require 'active_relation/relations/join' -require 'active_relation/relations/attribute' -require 'active_relation/relations/projection' -require 'active_relation/relations/selection' -require 'active_relation/relations/order' -require 'active_relation/relations/range' -require 'active_relation/relations/rename' -require 'active_relation/relations/deletion' -require 'active_relation/relations/insertion' - -require 'active_relation/predicates' - require 'active_relation/extensions/object' require 'active_relation/extensions/array' require 'active_relation/extensions/base' -require 'active_relation/extensions/hash' \ No newline at end of file +require 'active_relation/extensions/hash' + +require 'active_relation/relations' +require 'active_relation/predicates' \ No newline at end of file From 984b1833b9c82f2f44fe6960bb8df5e41c478e07 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 10 Jan 2008 22:02:47 -0800 Subject: [PATCH 0025/1492] reorganized requires --- lib/active_relation.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/active_relation.rb b/lib/active_relation.rb index ee207d418ebcd..cdac17facbd2f 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -5,11 +5,6 @@ require 'activerecord' require 'active_relation/sql_builder' - -require 'active_relation/extensions/object' -require 'active_relation/extensions/array' -require 'active_relation/extensions/base' -require 'active_relation/extensions/hash' - +require 'active_relation/extensions' require 'active_relation/relations' require 'active_relation/predicates' \ No newline at end of file From eeb43fc8987c2ee4a774eeab31ba8cddad11f9af Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 10 Jan 2008 22:55:59 -0800 Subject: [PATCH 0026/1492] new files? --- lib/active_relation/extensions.rb | 4 + lib/active_relation/relations.rb | 12 +++ lib/active_relation/relations/base.rb | 111 ++++++++++++++++++++ lib/active_relation/relations/compound.rb | 9 ++ lib/active_relation/relations/deletion.rb | 17 +++ lib/active_relation/relations/insertion.rb | 25 +++++ lib/active_relation/relations/join.rb | 45 ++++++++ lib/active_relation/relations/order.rb | 19 ++++ lib/active_relation/relations/projection.rb | 19 ++++ lib/active_relation/relations/range.rb | 23 ++++ lib/active_relation/relations/rename.rb | 38 +++++++ lib/active_relation/relations/selection.rb | 25 +++++ lib/active_relation/relations/table.rb | 35 ++++++ 13 files changed, 382 insertions(+) create mode 100644 lib/active_relation/extensions.rb create mode 100644 lib/active_relation/relations.rb create mode 100644 lib/active_relation/relations/base.rb create mode 100644 lib/active_relation/relations/compound.rb create mode 100644 lib/active_relation/relations/deletion.rb create mode 100644 lib/active_relation/relations/insertion.rb create mode 100644 lib/active_relation/relations/join.rb create mode 100644 lib/active_relation/relations/order.rb create mode 100644 lib/active_relation/relations/projection.rb create mode 100644 lib/active_relation/relations/range.rb create mode 100644 lib/active_relation/relations/rename.rb create mode 100644 lib/active_relation/relations/selection.rb create mode 100644 lib/active_relation/relations/table.rb diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb new file mode 100644 index 0000000000000..3751088483555 --- /dev/null +++ b/lib/active_relation/extensions.rb @@ -0,0 +1,4 @@ +require 'active_relation/extensions/object' +require 'active_relation/extensions/array' +require 'active_relation/extensions/base' +require 'active_relation/extensions/hash' diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb new file mode 100644 index 0000000000000..f7d1bc207a840 --- /dev/null +++ b/lib/active_relation/relations.rb @@ -0,0 +1,12 @@ +require 'active_relation/relations/base' +require 'active_relation/relations/compound' +require 'active_relation/relations/table' +require 'active_relation/relations/join' +require 'active_relation/relations/attribute' +require 'active_relation/relations/projection' +require 'active_relation/relations/selection' +require 'active_relation/relations/order' +require 'active_relation/relations/range' +require 'active_relation/relations/rename' +require 'active_relation/relations/deletion' +require 'active_relation/relations/insertion' \ No newline at end of file diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb new file mode 100644 index 0000000000000..c4a887eecdcaa --- /dev/null +++ b/lib/active_relation/relations/base.rb @@ -0,0 +1,111 @@ +module ActiveRelation + module Relations + class Base + include SqlBuilder + + module Iteration + include Enumerable + + def each(&block) + connection.select_all(to_s).each(&block) + end + + def first + connection.select_one(to_s) + end + end + include Iteration + + module Operations + def <=>(other) + JoinOperation.new("INNER JOIN", self, other) + end + + def <<(other) + JoinOperation.new("LEFT OUTER JOIN", self, other) + end + + def [](index) + case index + when Symbol + attribute(index) + when ::Range + Range.new(self, index) + end + end + + def include?(attribute) + Predicates::RelationInclusion.new(attribute, self) + end + + def select(*s) + Selection.new(self, *s) + end + + def project(*attributes) + Projection.new(self, *attributes) + end + + def order(*attributes) + Order.new(self, *attributes) + end + + def rename(attribute, aliaz) + Rename.new(self, attribute => aliaz) + end + + def insert(record) + Insertion.new(self, record) + end + + def delete + Deletion.new(self) + end + + class JoinOperation + attr_reader :join_sql, :relation1, :relation2 + + def initialize(join_sql, relation1, relation2) + @join_sql, @relation1, @relation2 = join_sql, relation1, relation2 + end + + def on(*predicates) + Join.new(join_sql, relation1, relation2, *predicates) + end + + def ==(other) + (relation1 == other.relation1 and relation2 == other.relation2) or + (relation1 == other.relation2 and relation2 == other.relation1) + end + end + end + include Operations + + def connection + ActiveRecord::Base.connection + end + + def to_sql(options = {}) + [ + "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", + "FROM #{quote_table_name(table)}", + (joins.to_sql(:quote => false) unless joins.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), + ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), + ("LIMIT #{limit.to_sql}" unless limit.blank?), + ("OFFSET #{offset.to_sql}" unless offset.blank?) + ].compact.join("\n") + end + alias_method :to_s, :to_sql + + protected + def attributes; [] end + def selects; [] end + def orders; [] end + def inserts; [] end + def joins; nil end + def limit; nil end + def offset; nil end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb new file mode 100644 index 0000000000000..442224a011e28 --- /dev/null +++ b/lib/active_relation/relations/compound.rb @@ -0,0 +1,9 @@ +module ActiveRelation + module Relations + class Compound < Base + attr_reader :relation + + delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :to => :relation + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb new file mode 100644 index 0000000000000..f218d9da6d4f5 --- /dev/null +++ b/lib/active_relation/relations/deletion.rb @@ -0,0 +1,17 @@ +module ActiveRelation + module Relations + class Deletion < Compound + def initialize(relation) + @relation = relation + end + + def to_sql(options = {}) + [ + "DELETE", + "FROM #{quote_table_name(table)}", + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ].compact.join("\n") + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb new file mode 100644 index 0000000000000..a0042a18a5fbe --- /dev/null +++ b/lib/active_relation/relations/insertion.rb @@ -0,0 +1,25 @@ +module ActiveRelation + module Relations + class Insertion < Compound + attr_reader :record + + def initialize(relation, record) + @relation, @record = relation, record + end + + def to_sql(options = {}) + [ + "INSERT", + "INTO #{quote_table_name(table)}", + "(#{record.keys.collect(&:to_sql).join(', ')})", + "VALUES #{inserts.collect(&:to_sql).join(', ')}" + ].join("\n") + end + + protected + def inserts + relation.inserts + [record] + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb new file mode 100644 index 0000000000000..1bd1439dd64be --- /dev/null +++ b/lib/active_relation/relations/join.rb @@ -0,0 +1,45 @@ +module ActiveRelation + module Relations + class Join < Base + attr_reader :join_sql, :relation1, :relation2, :predicates + + def initialize(join_sql, relation1, relation2, *predicates) + @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + end + + def ==(other) + predicates == other.predicates and + ((relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2)) + end + + def qualify + Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + end + + protected + def joins + [relation1.joins, relation2.joins, join].compact.join(" ") + end + + def selects + relation1.send(:selects) + relation2.send(:selects) + end + + def attributes + relation1.attributes + relation2.attributes + end + + def attribute(name) + relation1[name] || relation2[name] + end + + delegate :table, :to => :relation1 + + private + def join + "#{join_sql} #{quote_table_name(relation2.table)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb new file mode 100644 index 0000000000000..99ff939528345 --- /dev/null +++ b/lib/active_relation/relations/order.rb @@ -0,0 +1,19 @@ +module ActiveRelation + module Relations + class Order < Compound + attr_reader :relation, :orders + + def initialize(relation, *orders) + @relation, @orders = relation, orders + end + + def ==(other) + relation == other.relation and orders.eql?(other.orders) + end + + def qualify + Order.new(relation.qualify, *orders.collect { |o| o.qualify }) + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb new file mode 100644 index 0000000000000..b30c76898df7d --- /dev/null +++ b/lib/active_relation/relations/projection.rb @@ -0,0 +1,19 @@ +module ActiveRelation + module Relations + class Projection < Compound + attr_reader :relation, :attributes + + def initialize(relation, *attributes) + @relation, @attributes = relation, attributes + end + + def ==(other) + relation == other.relation and attributes.eql?(other.attributes) + end + + def qualify + Projection.new(relation.qualify, *attributes.collect(&:qualify)) + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb new file mode 100644 index 0000000000000..d7e08efa0637f --- /dev/null +++ b/lib/active_relation/relations/range.rb @@ -0,0 +1,23 @@ +module ActiveRelation + module Relations + class Range < Compound + attr_reader :range + + def initialize(relation, range) + @relation, @range = relation, range + end + + def ==(other) + relation == other.relation and range == other.range + end + + def limit + range.end - range.begin + 1 + end + + def offset + range.begin + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb new file mode 100644 index 0000000000000..7a1693df579e6 --- /dev/null +++ b/lib/active_relation/relations/rename.rb @@ -0,0 +1,38 @@ +module ActiveRelation + module Relations + class Rename < Compound + attr_reader :relation, :schmattribute, :alias + + def initialize(relation, renames) + @schmattribute, @alias = renames.shift + @relation = renames.empty?? relation : Rename.new(relation, renames) + end + + def ==(other) + relation == other.relation and schmattribute.eql?(other.schmattribute) and self.alias == other.alias + end + + def attributes + relation.attributes.collect { |a| substitute(a) } + end + + def qualify + Rename.new(relation.qualify, schmattribute.qualify => self.alias) + end + + protected + def attribute(name) + case + when name == self.alias then schmattribute.alias(self.alias) + when relation[name].eql?(schmattribute) then nil + else relation[name] + end + end + + private + def substitute(a) + a.eql?(schmattribute) ? a.alias(self.alias) : a + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb new file mode 100644 index 0000000000000..e102d105a0cf4 --- /dev/null +++ b/lib/active_relation/relations/selection.rb @@ -0,0 +1,25 @@ +module ActiveRelation + module Relations + class Selection < Compound + attr_reader :relation, :predicate + + def initialize(relation, *predicates) + @predicate = predicates.shift + @relation = predicates.empty?? relation : Selection.new(relation, *predicates) + end + + def ==(other) + relation == other.relation and predicate == other.predicate + end + + def qualify + Selection.new(relation.qualify, predicate.qualify) + end + + protected + def selects + relation.send(:selects) + [predicate] + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb new file mode 100644 index 0000000000000..38f540cc5229a --- /dev/null +++ b/lib/active_relation/relations/table.rb @@ -0,0 +1,35 @@ +module ActiveRelation + module Relations + class Table < Base + attr_reader :table + + def initialize(table) + @table = table + end + + def attributes + attributes_by_name.values + end + + def qualify + Rename.new self, qualifications + end + + protected + def attribute(name) + attributes_by_name[name.to_s] + end + + private + def attributes_by_name + @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| + attributes_by_name.merge(column.name => ActiveRelation::Primitives::Attribute.new(self, column.name.to_sym)) + end + end + + def qualifications + attributes.zip(attributes.collect(&:qualified_name)).to_hash + end + end + end +end \ No newline at end of file From 49c251eded06fe028949624f1e0c4dd7748c7925 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Jan 2008 00:00:08 -0800 Subject: [PATCH 0027/1492] fixed erroneous test --- schema.sql | 126 ++++++++++++++++++ .../relations/attribute_spec.rb | 2 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 schema.sql diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000000000..d42eb9694424e --- /dev/null +++ b/schema.sql @@ -0,0 +1,126 @@ +-- MySQL dump 10.10 +-- +-- Host: localhost Database: sql_algebra_test +-- ------------------------------------------------------ +-- Server version 5.0.27-standard + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `bar` +-- + +DROP TABLE IF EXISTS `bar`; +CREATE TABLE `bar` ( + `id` int(11) default NULL, + `name` varchar(255) default NULL, + `foo_id` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `bar` +-- + +LOCK TABLES `bar` WRITE; +/*!40000 ALTER TABLE `bar` DISABLE KEYS */; +/*!40000 ALTER TABLE `bar` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cameras` +-- + +DROP TABLE IF EXISTS `cameras`; +CREATE TABLE `cameras` ( + `id` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `cameras` +-- + +LOCK TABLES `cameras` WRITE; +/*!40000 ALTER TABLE `cameras` DISABLE KEYS */; +INSERT INTO `cameras` VALUES (1); +/*!40000 ALTER TABLE `cameras` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `foo` +-- + +DROP TABLE IF EXISTS `foo`; +CREATE TABLE `foo` ( + `id` int(11) default NULL, + `name` varchar(255) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `foo` +-- + +LOCK TABLES `foo` WRITE; +/*!40000 ALTER TABLE `foo` DISABLE KEYS */; +/*!40000 ALTER TABLE `foo` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `photos` +-- + +DROP TABLE IF EXISTS `photos`; +CREATE TABLE `photos` ( + `id` int(11) default NULL, + `user_id` int(11) default NULL, + `camera_id` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `photos` +-- + +LOCK TABLES `photos` WRITE; +/*!40000 ALTER TABLE `photos` DISABLE KEYS */; +INSERT INTO `photos` VALUES (1,1,1); +/*!40000 ALTER TABLE `photos` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +CREATE TABLE `users` ( + `id` int(11) default NULL, + `name` varchar(255) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,'hai'),(NULL,'bai'),(NULL,'dumpty'); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2008-01-11 7:15:17 diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb index 71bba26aff7e1..0c79e13b93f79 100644 --- a/spec/active_relation/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -20,7 +20,7 @@ describe '#qualify' do it "manufactures an attribute aliased with that attributes qualified name" do - @relation1[:id].qualify == @relation1[:id].qualify + @relation1[:id].qualify.should == @relation1[:id].qualify end end From d9f200f2fb14907137a27d5c9522575274bb0cde Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Jan 2008 00:05:22 -0800 Subject: [PATCH 0028/1492] minor cleanup - using a struct, a bit more terse --- lib/active_relation/relations/base.rb | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index c4a887eecdcaa..67a64b9aa6f6d 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -38,8 +38,8 @@ def include?(attribute) Predicates::RelationInclusion.new(attribute, self) end - def select(*s) - Selection.new(self, *s) + def select(*predicates) + Selection.new(self, *predicates) end def project(*attributes) @@ -62,21 +62,10 @@ def delete Deletion.new(self) end - class JoinOperation - attr_reader :join_sql, :relation1, :relation2 - - def initialize(join_sql, relation1, relation2) - @join_sql, @relation1, @relation2 = join_sql, relation1, relation2 - end - + JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do def on(*predicates) Join.new(join_sql, relation1, relation2, *predicates) end - - def ==(other) - (relation1 == other.relation1 and relation2 == other.relation2) or - (relation1 == other.relation2 and relation2 == other.relation1) - end end end include Operations From cebfc0c1d830799c8b26834760fe40b44efb2d08 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 17:57:35 -0800 Subject: [PATCH 0029/1492] removed operator overloading; renamed spec files --- lib/active_relation/relations/attribute.rb | 2 +- lib/active_relation/relations/base.rb | 4 +- .../integration/scratch_spec.rb | 7 +- .../predicates/binary_predicate_spec.rb | 42 -------- .../predicates/equality_predicate_spec.rb | 25 ----- .../relation_inclusion_predicate_spec.rb | 16 ---- .../relations/deletion_relation_spec.rb | 24 ----- .../relations/insertion_relation_spec.rb | 26 ----- .../relations/join_relation_spec.rb | 43 --------- .../relations/order_relation_spec.rb | 28 ------ .../relations/projection_relation_spec.rb | 34 ------- .../relations/range_relation_spec.rb | 30 ------ .../relations/relation_spec.rb | 96 ------------------- .../relations/rename_relation_spec.rb | 61 ------------ .../relations/selection_relation_spec.rb | 42 -------- .../relations/table_relation_spec.rb | 30 ------ 16 files changed, 6 insertions(+), 504 deletions(-) delete mode 100644 spec/active_relation/predicates/binary_predicate_spec.rb delete mode 100644 spec/active_relation/predicates/equality_predicate_spec.rb delete mode 100644 spec/active_relation/predicates/relation_inclusion_predicate_spec.rb delete mode 100644 spec/active_relation/relations/deletion_relation_spec.rb delete mode 100644 spec/active_relation/relations/insertion_relation_spec.rb delete mode 100644 spec/active_relation/relations/join_relation_spec.rb delete mode 100644 spec/active_relation/relations/order_relation_spec.rb delete mode 100644 spec/active_relation/relations/projection_relation_spec.rb delete mode 100644 spec/active_relation/relations/range_relation_spec.rb delete mode 100644 spec/active_relation/relations/relation_spec.rb delete mode 100644 spec/active_relation/relations/rename_relation_spec.rb delete mode 100644 spec/active_relation/relations/selection_relation_spec.rb delete mode 100644 spec/active_relation/relations/table_relation_spec.rb diff --git a/lib/active_relation/relations/attribute.rb b/lib/active_relation/relations/attribute.rb index 30cd9798d9bca..b7233a4b17a64 100644 --- a/lib/active_relation/relations/attribute.rb +++ b/lib/active_relation/relations/attribute.rb @@ -22,7 +22,7 @@ def qualify end def eql?(other) - relation == other.relation and name == other.name and self.alias == other.alias + relation == other.relation and name == other.name and @alias == other.alias end module Predications diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index 67a64b9aa6f6d..960735f07fb58 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -17,11 +17,11 @@ def first include Iteration module Operations - def <=>(other) + def join(other) JoinOperation.new("INNER JOIN", self, other) end - def <<(other) + def outer_join(other) JoinOperation.new("LEFT OUTER JOIN", self, other) end diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb index 93d332eea76b2..cd4b4cd00489b 100644 --- a/spec/active_relation/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -51,15 +51,14 @@ def user_has_many_photos(user_relation) primary_key = User.reflections[:photos].klass.primary_key.to_sym foreign_key = User.reflections[:photos].primary_key_name.to_sym - # << is the left outer join operator - (user_relation << @photos).on(user_relation[primary_key] == @photos[foreign_key]) + user_relation.outer_join(@photos).on(user_relation[primary_key] == @photos[foreign_key]) end def photo_belongs_to_camera(photo_relation) primary_key = Photo.reflections[:camera].klass.primary_key.to_sym foreign_key = Photo.reflections[:camera].primary_key_name.to_sym - (photo_relation << @cameras).on(photo_relation[foreign_key] == @cameras[primary_key]) + photo_relation.outer_join(@cameras).on(photo_relation[foreign_key] == @cameras[primary_key]) end describe 'Relational Algebra', 'a relational algebra allows the implementation of @@ -124,7 +123,7 @@ def photo_belongs_to_camera(photo_relation) end it 'allows arbitrary sql to be passed through' do - (@users << @photos).on("asdf").to_sql.should be_like(""" + @users.outer_join(@photos).on("asdf").to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` LEFT OUTER JOIN `photos` diff --git a/spec/active_relation/predicates/binary_predicate_spec.rb b/spec/active_relation/predicates/binary_predicate_spec.rb deleted file mode 100644 index 02c72ef96d23d..0000000000000 --- a/spec/active_relation/predicates/binary_predicate_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Predicates::Binary do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name1) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name2) - class ActiveRelation::Predicates::ConcreteBinary < ActiveRelation::Predicates::Binary - def predicate_sql - "<=>" - end - end - end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the ActiveRelation::Predicates::Binarys are identical" do - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2) - end - end - - describe '#qualify' do - it "distributes over the predicates and attributes" do - ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).qualify. \ - should == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) - end - end - - describe '#to_sql' do - it 'manufactures correct sql' do - ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" - `foo`.`name1` <=> `bar`.`name2` - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/predicates/equality_predicate_spec.rb b/spec/active_relation/predicates/equality_predicate_spec.rb deleted file mode 100644 index b3c7b597a0802..0000000000000 --- a/spec/active_relation/predicates/equality_predicate_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Predicates::Equality do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) - end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the predicates are identical" do - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - end - - it "is commutative on the attributes" do - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute2, @attribute1) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb b/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb deleted file mode 100644 index a01f4fb76b3ca..0000000000000 --- a/spec/active_relation/predicates/relation_inclusion_predicate_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Predicates::RelationInclusion do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute = @relation1[:baz] - end - - describe ActiveRelation::Predicates::RelationInclusion, '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/deletion_relation_spec.rb b/spec/active_relation/relations/deletion_relation_spec.rb deleted file mode 100644 index b80589bde605c..0000000000000 --- a/spec/active_relation/relations/deletion_relation_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Deletion do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql deleting a table relation' do - ActiveRelation::Relations::Deletion.new(@relation).to_sql.should be_like(""" - DELETE - FROM `users` - """) - end - - it 'manufactures sql deleting a selection relation' do - ActiveRelation::Relations::Deletion.new(@relation.select(@relation[:id] == 1)).to_sql.should be_like(""" - DELETE - FROM `users` - WHERE `users`.`id` = 1 - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/insertion_relation_spec.rb b/spec/active_relation/relations/insertion_relation_spec.rb deleted file mode 100644 index da39edf773346..0000000000000 --- a/spec/active_relation/relations/insertion_relation_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Insertion do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql inserting the data for one item' do - ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" - INSERT - INTO `users` - (`users`.`name`) VALUES ('nick') - """) - end - - it 'manufactures sql inserting the data for multiple items' do - nested_insertion = ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "cobra") - ActiveRelation::Relations::Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" - INSERT - INTO `users` - (`users`.`name`) VALUES ('cobra'), ('commander') - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/join_relation_spec.rb b/spec/active_relation/relations/join_relation_spec.rb deleted file mode 100644 index 32771428a8ad5..0000000000000 --- a/spec/active_relation/relations/join_relation_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Join do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @predicate = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:id]) - end - - describe '==' do - it 'obtains if the two relations and the predicate are identical' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation1, @predicate) - end - - it 'is commutative on the relations' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation2, @relation1, @predicate) - end - end - - describe '#qualify' do - it 'distributes over the relations and predicates' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ - should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) - end - end - - describe '#to_sql' do - before do - @relation1 = @relation1.select(@relation1[:id] == 1) - end - - it 'manufactures sql joining the two tables on the predicate, merging the selects' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` - FROM `foo` - INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` - WHERE - `foo`.`id` = 1 - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/order_relation_spec.rb b/spec/active_relation/relations/order_relation_spec.rb deleted file mode 100644 index edf2faf4559de..0000000000000 --- a/spec/active_relation/relations/order_relation_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Order do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] - end - - describe '#qualify' do - it "distributes over the relation and attributes" do - ActiveRelation::Relations::Order.new(@relation1, @attribute1).qualify. \ - should == ActiveRelation::Relations::Order.new(@relation1.qualify, @attribute1.qualify) - end - end - - describe '#to_sql' do - it "manufactures sql with an order clause" do - ActiveRelation::Relations::Order.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - ORDER BY `foo`.`id` - """) - end - end - -end \ No newline at end of file diff --git a/spec/active_relation/relations/projection_relation_spec.rb b/spec/active_relation/relations/projection_relation_spec.rb deleted file mode 100644 index 8ba571e06ce00..0000000000000 --- a/spec/active_relation/relations/projection_relation_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Projection do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] - end - - describe '==' do - it "obtains if the relations and attributes are identical" do - ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation2, @attribute1) - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation1, @attribute2) - end - end - - describe '#qualify' do - it "distributes over teh relation and attributes" do - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).qualify. \ - should == ActiveRelation::Relations::Projection.new(@relation1.qualify, @attribute1.qualify) - end - end - - describe '#to_sql' do - it "manufactures sql with a limited select clause" do - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`id` - FROM `foo` - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/range_relation_spec.rb b/spec/active_relation/relations/range_relation_spec.rb deleted file mode 100644 index d4107259aac2b..0000000000000 --- a/spec/active_relation/relations/range_relation_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Range do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @range1 = 1..2 - @range2 = 4..9 - end - - describe '#qualify' do - it "distributes over the relation and attributes" do - pending - end - end - - describe '#to_sql' do - it "manufactures sql with limit and offset" do - range_size = @range2.last - @range2.first + 1 - range_start = @range2.first - ActiveRelation::Relations::Range.new(@relation1, @range2).to_s.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - LIMIT #{range_size} - OFFSET #{range_start} - """) - end - end - -end \ No newline at end of file diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb deleted file mode 100644 index caee3bb527953..0000000000000 --- a/spec/active_relation/relations/relation_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Base do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :id) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - end - - describe '[]' do - it "manufactures an attribute when given a symbol" do - @relation1[:id].should == ActiveRelation::Primitives::Attribute.new(@relation1, :id) - end - - it "manufactures a range relation when given a range" do - @relation1[1..2].should == ActiveRelation::Relations::Range.new(@relation1, 1..2) - end - end - - describe '#include?' do - it "manufactures an inclusion predicate" do - @relation1.include?(@attribute1).should be_kind_of(ActiveRelation::Predicates::RelationInclusion) - end - end - - describe 'read operations' do - describe 'joins' do - before do - @predicate = @relation1[:id] == @relation2[:id] - end - - describe '<=>' do - it "manufactures an inner join operation between those two relations" do - (@relation1 <=> @relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) - end - end - - describe '<<' do - it "manufactures a left outer join operation between those two relations" do - (@relation1 << @relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) - end - end - end - - describe '#project' do - it "collapses identical projections" do - pending - end - - it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Projection) - end - end - - describe '#rename' do - it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should be_kind_of(ActiveRelation::Relations::Rename) - end - end - - describe '#select' do - before do - @predicate = ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) - end - - it "manufactures a selection relation" do - @relation1.select(@predicate).should be_kind_of(ActiveRelation::Relations::Selection) - end - - it "accepts arbitrary strings" do - @relation1.select("arbitrary").should be_kind_of(ActiveRelation::Relations::Selection) - end - end - - describe '#order' do - it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Order) - end - end - end - - describe 'write operations' do - describe '#delete' do - it 'manufactures a deletion relation' do - @relation1.delete.should be_kind_of(ActiveRelation::Relations::Deletion) - end - end - - describe '#insert' do - it 'manufactures an insertion relation' do - @relation1.insert(record = {:id => 1}).should be_kind_of(ActiveRelation::Relations::Insertion) - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/rename_relation_spec.rb b/spec/active_relation/relations/rename_relation_spec.rb deleted file mode 100644 index 6fac206ff12fe..0000000000000 --- a/spec/active_relation/relations/rename_relation_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Rename do - before do - @relation = ActiveRelation::Relations::Table.new(:foo) - @renamed_relation = ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid) - end - - describe '#initialize' do - it "manufactures nested rename relations if multiple renames are provided" do - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ - should == ActiveRelation::Relations::Rename.new(ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) - end - - it "raises an exception if the alias provided is already used" do - pending - end - end - - describe '==' do - it "obtains if the relation, attribute, and alias are identical" do - pending - end - end - - describe '#attributes' do - it "manufactures a list of attributes with the renamed attribute aliased" do - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == - (@relation.attributes - [@relation[:id]]) + [@relation[:id].alias(:schmid)] - end - end - - describe '[]' do - it 'indexes attributes by alias' do - @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation[:id] - end - end - - describe '#schmattribute' do - it "should be renamed" do - pending - end - end - - describe '#qualify' do - it "distributes over the relation and renames" do - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).qualify. \ - should == ActiveRelation::Relations::Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) - end - end - - describe '#to_sql' do - it 'manufactures sql aliasing the attribute' do - @renamed_relation.to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` AS 'schmid' - FROM `foo` - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/selection_relation_spec.rb b/spec/active_relation/relations/selection_relation_spec.rb deleted file mode 100644 index 90dc3169b6ca5..0000000000000 --- a/spec/active_relation/relations/selection_relation_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Selection do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @predicate1 = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:foo_id]) - @predicate2 = ActiveRelation::Predicates::LessThan.new(@relation1[:age], 2) - end - - describe '#initialize' do - it "manufactures nested selection relations if multiple predicates are provided" do - ActiveRelation::Relations::Selection.new(@relation1, @predicate1, @predicate2). \ - should == ActiveRelation::Relations::Selection.new(ActiveRelation::Relations::Selection.new(@relation1, @predicate2), @predicate1) - end - end - - describe '#qualify' do - it "distributes over the relation and predicates" do - ActiveRelation::Relations::Selection.new(@relation1, @predicate1).qualify. \ - should == ActiveRelation::Relations::Selection.new(@relation1.qualify, @predicate1.qualify) - end - end - - describe '#to_sql' do - it "manufactures sql with where clause conditions" do - ActiveRelation::Relations::Selection.new(@relation1, @predicate1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - WHERE `foo`.`id` = `bar`.`foo_id` - """) - end - - it "allows arbitrary sql" do - ActiveRelation::Relations::Selection.new(@relation1, "asdf").to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - WHERE asdf - """) - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/table_relation_spec.rb b/spec/active_relation/relations/table_relation_spec.rb deleted file mode 100644 index 62b8e4498030d..0000000000000 --- a/spec/active_relation/relations/table_relation_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Table do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - end - - describe '#to_sql' do - it "returns a simple SELECT query" do - @relation.to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id` - FROM `users` - """) - end - end - - describe '#attributes' do - it 'manufactures attributes corresponding to columns in the table' do - pending - end - end - - describe '#qualify' do - it 'manufactures a rename relation with all attribute names qualified' do - @relation.qualify.should == ActiveRelation::Relations::Rename.new( - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' - ) - end - end -end \ No newline at end of file From c1e223f8a9e7394ede2fcd5621f7d43721023a20 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 18:08:25 -0800 Subject: [PATCH 0030/1492] removed operator overloading of the predications (==, etc.) --- lib/active_relation/predicates.rb | 6 ++-- lib/active_relation/relations/attribute.rb | 14 ++++---- lib/active_relation/relations/order.rb | 2 +- lib/active_relation/relations/projection.rb | 2 +- lib/active_relation/relations/rename.rb | 6 ++-- .../integration/scratch_spec.rb | 8 ++--- .../relations/attribute_spec.rb | 32 +++++++++---------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 5ac879899bffb..6616cfd41450a 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -14,7 +14,7 @@ def initialize(attribute1, attribute2) end def ==(other) - super and @attribute1.eql?(other.attribute1) and @attribute2.eql?(other.attribute2) + super and @attribute1 == other.attribute1 and @attribute2 == other.attribute2 end def qualify @@ -29,8 +29,8 @@ def to_sql(options = {}) class Equality < Binary def ==(other) self.class == other.class and - ((attribute1.eql?(other.attribute1) and attribute2.eql?(other.attribute2)) or - (attribute1.eql?(other.attribute2) and attribute2.eql?(other.attribute1))) + ((attribute1 == other.attribute1 and attribute2 == other.attribute2) or + (attribute1 == other.attribute2 and attribute2 == other.attribute1)) end protected diff --git a/lib/active_relation/relations/attribute.rb b/lib/active_relation/relations/attribute.rb index b7233a4b17a64..2fe702cb143b2 100644 --- a/lib/active_relation/relations/attribute.rb +++ b/lib/active_relation/relations/attribute.rb @@ -21,32 +21,32 @@ def qualify self.alias(qualified_name) end - def eql?(other) + def ==(other) relation == other.relation and name == other.name and @alias == other.alias end module Predications - def ==(other) + def equals(other) Predicates::Equality.new(self, other) end - def <(other) + def less_than(other) Predicates::LessThan.new(self, other) end - def <=(other) + def less_than_or_equal_to(other) Predicates::LessThanOrEqualTo.new(self, other) end - def >(other) + def greater_than(other) Predicates::GreaterThan.new(self, other) end - def >=(other) + def greater_than_or_equal_to(other) Predicates::GreaterThanOrEqualTo.new(self, other) end - def =~(regexp) + def matches(regexp) Predicates::Match.new(self, regexp) end end diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index 99ff939528345..c8034d2f179c5 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -8,7 +8,7 @@ def initialize(relation, *orders) end def ==(other) - relation == other.relation and orders.eql?(other.orders) + relation == other.relation and orders == other.orders end def qualify diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index b30c76898df7d..df25d16234651 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -8,7 +8,7 @@ def initialize(relation, *attributes) end def ==(other) - relation == other.relation and attributes.eql?(other.attributes) + relation == other.relation and attributes == other.attributes end def qualify diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 7a1693df579e6..8f28c94d523ea 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -9,7 +9,7 @@ def initialize(relation, renames) end def ==(other) - relation == other.relation and schmattribute.eql?(other.schmattribute) and self.alias == other.alias + relation == other.relation and schmattribute == other.schmattribute and self.alias == other.alias end def attributes @@ -24,14 +24,14 @@ def qualify def attribute(name) case when name == self.alias then schmattribute.alias(self.alias) - when relation[name].eql?(schmattribute) then nil + when relation[name] == schmattribute then nil else relation[name] end end private def substitute(a) - a.eql?(schmattribute) ? a.alias(self.alias) : a + a == schmattribute ? a.alias(self.alias) : a end end end diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb index cd4b4cd00489b..6aa27bc1fee33 100644 --- a/spec/active_relation/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -40,7 +40,7 @@ class Camera < ActiveRecord::Base; end @photos = Photo.relation @cameras = Camera.relation # A first taste of a Relational Algebra: User.find(1) - @user = @users.select(@users[:id] == 1) + @user = @users.select(@users[:id].equals(1)) # == is overridden on attributes to return a predicate, not true or false end @@ -51,14 +51,14 @@ def user_has_many_photos(user_relation) primary_key = User.reflections[:photos].klass.primary_key.to_sym foreign_key = User.reflections[:photos].primary_key_name.to_sym - user_relation.outer_join(@photos).on(user_relation[primary_key] == @photos[foreign_key]) + user_relation.outer_join(@photos).on(user_relation[primary_key].equals(@photos[foreign_key])) end def photo_belongs_to_camera(photo_relation) primary_key = Photo.reflections[:camera].klass.primary_key.to_sym foreign_key = Photo.reflections[:camera].primary_key_name.to_sym - photo_relation.outer_join(@cameras).on(photo_relation[foreign_key] == @cameras[primary_key]) + photo_relation.outer_join(@cameras).on(photo_relation[foreign_key].equals(@cameras[primary_key])) end describe 'Relational Algebra', 'a relational algebra allows the implementation of @@ -184,7 +184,7 @@ class User < ActiveRecord::Base end class Person < ActiveRecord::Base - set_relation @accounts.join(@profiles).on(@accounts[:id] == @profiles[:account_id]) + set_relation @accounts.join(@profiles).on(@accounts[:id].equals(@profiles[:account_id])) end # I know this sounds crazy, but even writes are possible in the last example. # calling #save on a person can write to two tables! diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb index 0c79e13b93f79..28fb0c3754533 100644 --- a/spec/active_relation/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -24,11 +24,11 @@ end end - describe '#eql?' do + describe '==' do it "obtains if the relation and attribute name are identical" do - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should be_eql(ActiveRelation::Primitives::Attribute.new(@relation1, :name)) - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not be_eql(ActiveRelation::Primitives::Attribute.new(@relation1, :another_name)) - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not be_eql(ActiveRelation::Primitives::Attribute.new(@relation2, :name)) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should == ActiveRelation::Primitives::Attribute.new(@relation1, :name) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation1, :another_name) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation2, :name) end end @@ -38,39 +38,39 @@ @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) end - describe '==' do + describe '#equals' do it "manufactures an equality predicate" do - (@attribute1 == @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + @attribute1.equals(@attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) end end - describe '<' do + describe '#less_than' do it "manufactures a less-than predicate" do - (@attribute1 < @attribute2).should == ActiveRelation::Predicates::LessThan.new(@attribute1, @attribute2) + @attribute1.less_than(@attribute2).should == ActiveRelation::Predicates::LessThan.new(@attribute1, @attribute2) end end - describe '<=' do + describe '#less_than_or_equal_to' do it "manufactures a less-than or equal-to predicate" do - (@attribute1 <= @attribute2).should == ActiveRelation::Predicates::LessThanOrEqualTo.new(@attribute1, @attribute2) + @attribute1.less_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::LessThanOrEqualTo.new(@attribute1, @attribute2) end end - describe '>' do + describe 'greater_than' do it "manufactures a greater-than predicate" do - (@attribute1 > @attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) + @attribute1.greater_than(@attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) end end - describe '>=' do + describe '#greater_than_or_equal_to' do it "manufactures a greater-than or equal to predicate" do - (@attribute1 >= @attribute2).should == ActiveRelation::Predicates::GreaterThanOrEqualTo.new(@attribute1, @attribute2) + @attribute1.greater_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::GreaterThanOrEqualTo.new(@attribute1, @attribute2) end end - describe '=~' do + describe '#matches' do it "manufactures a match predicate" do - (@attribute1 =~ /.*/).should == ActiveRelation::Predicates::Match.new(@attribute1, @attribute2) + @attribute1.matches(/.*/).should == ActiveRelation::Predicates::Match.new(@attribute1, @attribute2) end end end From c2cbe7bb27b6cd2e136ac06f4f36d6de0ec52459 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 18:29:33 -0800 Subject: [PATCH 0031/1492] relation inclusion operator --- lib/active_relation/predicates.rb | 20 ++++++++++++++++++++ lib/active_relation/relations/order.rb | 2 +- lib/active_relation/relations/projection.rb | 4 ++-- lib/active_relation/relations/rename.rb | 2 +- lib/active_relation/relations/selection.rb | 2 +- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 6616cfd41450a..fba1cc90b6cd1 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -40,15 +40,31 @@ def predicate_sql end class GreaterThanOrEqualTo < Binary + protected + def predicate_sql + '>=' + end end class GreaterThan < Binary + protected + def predicate_sql + '>' + end end class LessThanOrEqualTo < Binary + protected + def predicate_sql + '<=' + end end class LessThan < Binary + protected + def predicate_sql + '<' + end end class Match < Base @@ -69,6 +85,10 @@ def initialize(attribute, relation) def ==(other) super and attribute == other.attribute and relation == other.relation end + + def to_sql(options = {}) + "#{attribute.to_sql} IN (#{relation.to_sql})" + end end end end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index c8034d2f179c5..bca81c1b6dc50 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -1,7 +1,7 @@ module ActiveRelation module Relations class Order < Compound - attr_reader :relation, :orders + attr_reader :orders def initialize(relation, *orders) @relation, @orders = relation, orders diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index df25d16234651..131db916f0c48 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -1,14 +1,14 @@ module ActiveRelation module Relations class Projection < Compound - attr_reader :relation, :attributes + attr_reader :attributes def initialize(relation, *attributes) @relation, @attributes = relation, attributes end def ==(other) - relation == other.relation and attributes == other.attributes + self.class == other.class and relation == other.relation and attributes == other.attributes end def qualify diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 8f28c94d523ea..c7b99c2127c39 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -1,7 +1,7 @@ module ActiveRelation module Relations class Rename < Compound - attr_reader :relation, :schmattribute, :alias + attr_reader :schmattribute, :alias def initialize(relation, renames) @schmattribute, @alias = renames.shift diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index e102d105a0cf4..e86dc627dbb46 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -1,7 +1,7 @@ module ActiveRelation module Relations class Selection < Compound - attr_reader :relation, :predicate + attr_reader :predicate def initialize(relation, *predicates) @predicate = predicates.shift From 45d2557ae097da1e5dd3dc532444233b4fed0b31 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 18:57:22 -0800 Subject: [PATCH 0032/1492] missing files --- .../active_relation/predicates/binary_spec.rb | 42 ++++++++ .../predicates/equality_spec.rb | 25 +++++ spec/active_relation/predicates/match_spec.rb | 16 ++++ .../predicates/relation_inclusion_spec.rb | 25 +++++ spec/active_relation/relations/base_spec.rb | 96 +++++++++++++++++++ .../relations/deletion_spec.rb | 24 +++++ .../relations/insertion_spec.rb | 26 +++++ spec/active_relation/relations/join_spec.rb | 43 +++++++++ spec/active_relation/relations/order_spec.rb | 28 ++++++ .../relations/projection_spec.rb | 34 +++++++ spec/active_relation/relations/range_spec.rb | 30 ++++++ spec/active_relation/relations/rename_spec.rb | 61 ++++++++++++ .../relations/selection_spec.rb | 42 ++++++++ spec/active_relation/relations/table_spec.rb | 30 ++++++ 14 files changed, 522 insertions(+) create mode 100644 spec/active_relation/predicates/binary_spec.rb create mode 100644 spec/active_relation/predicates/equality_spec.rb create mode 100644 spec/active_relation/predicates/match_spec.rb create mode 100644 spec/active_relation/predicates/relation_inclusion_spec.rb create mode 100644 spec/active_relation/relations/base_spec.rb create mode 100644 spec/active_relation/relations/deletion_spec.rb create mode 100644 spec/active_relation/relations/insertion_spec.rb create mode 100644 spec/active_relation/relations/join_spec.rb create mode 100644 spec/active_relation/relations/order_spec.rb create mode 100644 spec/active_relation/relations/projection_spec.rb create mode 100644 spec/active_relation/relations/range_spec.rb create mode 100644 spec/active_relation/relations/rename_spec.rb create mode 100644 spec/active_relation/relations/selection_spec.rb create mode 100644 spec/active_relation/relations/table_spec.rb diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb new file mode 100644 index 0000000000000..02c72ef96d23d --- /dev/null +++ b/spec/active_relation/predicates/binary_spec.rb @@ -0,0 +1,42 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::Binary do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name1) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name2) + class ActiveRelation::Predicates::ConcreteBinary < ActiveRelation::Predicates::Binary + def predicate_sql + "<=>" + end + end + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the ActiveRelation::Predicates::Binarys are identical" do + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2) + end + end + + describe '#qualify' do + it "distributes over the predicates and attributes" do + ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).qualify. \ + should == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) + end + end + + describe '#to_sql' do + it 'manufactures correct sql' do + ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" + `foo`.`name1` <=> `bar`.`name2` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/predicates/equality_spec.rb b/spec/active_relation/predicates/equality_spec.rb new file mode 100644 index 0000000000000..b3c7b597a0802 --- /dev/null +++ b/spec/active_relation/predicates/equality_spec.rb @@ -0,0 +1,25 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::Equality do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) + end + + it "is commutative on the attributes" do + ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute2, @attribute1) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/predicates/match_spec.rb b/spec/active_relation/predicates/match_spec.rb new file mode 100644 index 0000000000000..a01f4fb76b3ca --- /dev/null +++ b/spec/active_relation/predicates/match_spec.rb @@ -0,0 +1,16 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::RelationInclusion do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute = @relation1[:baz] + end + + describe ActiveRelation::Predicates::RelationInclusion, '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/predicates/relation_inclusion_spec.rb b/spec/active_relation/predicates/relation_inclusion_spec.rb new file mode 100644 index 0000000000000..de3dcf7747cf9 --- /dev/null +++ b/spec/active_relation/predicates/relation_inclusion_spec.rb @@ -0,0 +1,25 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Predicates::RelationInclusion do + before do + foo = ActiveRelation::Relations::Table.new(:foo) + @relation1 = foo.project(foo[:id]) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute = @relation1[:id] + end + + describe ActiveRelation::Predicates::RelationInclusion, '==' do + it "obtains if attribute1 and attribute2 are identical" do + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) + end + end + + describe ActiveRelation::Predicates::RelationInclusion, '#to_sql' do + it "manufactures subselect sql" do + ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(""" + `foo`.`id` IN (SELECT `foo`.`id` FROM `foo`) + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/base_spec.rb b/spec/active_relation/relations/base_spec.rb new file mode 100644 index 0000000000000..689e3ecadb03e --- /dev/null +++ b/spec/active_relation/relations/base_spec.rb @@ -0,0 +1,96 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Base do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :id) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + end + + describe '[]' do + it "manufactures an attribute when given a symbol" do + @relation1[:id].should == ActiveRelation::Primitives::Attribute.new(@relation1, :id) + end + + it "manufactures a range relation when given a range" do + @relation1[1..2].should == ActiveRelation::Relations::Range.new(@relation1, 1..2) + end + end + + describe '#include?' do + it "manufactures an inclusion predicate" do + @relation1.include?(@attribute1).should be_kind_of(ActiveRelation::Predicates::RelationInclusion) + end + end + + describe 'read operations' do + describe 'joins' do + before do + @predicate = @relation1[:id].equals(@relation2[:id]) + end + + describe '#join' do + it "manufactures an inner join operation between those two relations" do + @relation1.join(@relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) + end + end + + describe '#outer_join' do + it "manufactures a left outer join operation between those two relations" do + @relation1.outer_join(@relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) + end + end + end + + describe '#project' do + it "collapses identical projections" do + pending + end + + it "manufactures a projection relation" do + @relation1.project(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Projection) + end + end + + describe '#rename' do + it "manufactures a rename relation" do + @relation1.rename(@attribute1, :foo).should be_kind_of(ActiveRelation::Relations::Rename) + end + end + + describe '#select' do + before do + @predicate = ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + end + + it "manufactures a selection relation" do + @relation1.select(@predicate).should be_kind_of(ActiveRelation::Relations::Selection) + end + + it "accepts arbitrary strings" do + @relation1.select("arbitrary").should be_kind_of(ActiveRelation::Relations::Selection) + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation1.order(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Order) + end + end + end + + describe 'write operations' do + describe '#delete' do + it 'manufactures a deletion relation' do + @relation1.delete.should be_kind_of(ActiveRelation::Relations::Deletion) + end + end + + describe '#insert' do + it 'manufactures an insertion relation' do + @relation1.insert(record = {:id => 1}).should be_kind_of(ActiveRelation::Relations::Insertion) + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/deletion_spec.rb b/spec/active_relation/relations/deletion_spec.rb new file mode 100644 index 0000000000000..ed201ac0d980c --- /dev/null +++ b/spec/active_relation/relations/deletion_spec.rb @@ -0,0 +1,24 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Deletion do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql deleting a table relation' do + ActiveRelation::Relations::Deletion.new(@relation).to_sql.should be_like(""" + DELETE + FROM `users` + """) + end + + it 'manufactures sql deleting a selection relation' do + ActiveRelation::Relations::Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(""" + DELETE + FROM `users` + WHERE `users`.`id` = 1 + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/insertion_spec.rb b/spec/active_relation/relations/insertion_spec.rb new file mode 100644 index 0000000000000..da39edf773346 --- /dev/null +++ b/spec/active_relation/relations/insertion_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Insertion do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql inserting the data for one item' do + ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick') + """) + end + + it 'manufactures sql inserting the data for multiple items' do + nested_insertion = ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "cobra") + ActiveRelation::Relations::Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('cobra'), ('commander') + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb new file mode 100644 index 0000000000000..2a84a92b70df2 --- /dev/null +++ b/spec/active_relation/relations/join_spec.rb @@ -0,0 +1,43 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Join do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @predicate = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:id]) + end + + describe '==' do + it 'obtains if the two relations and the predicate are identical' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation1, @predicate) + end + + it 'is commutative on the relations' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation2, @relation1, @predicate) + end + end + + describe '#qualify' do + it 'distributes over the relations and predicates' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ + should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) + end + end + + describe '#to_sql' do + before do + @relation1 = @relation1.select(@relation1[:id].equals(1)) + end + + it 'manufactures sql joining the two tables on the predicate, merging the selects' do + ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` + FROM `foo` + INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` + WHERE + `foo`.`id` = 1 + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/order_spec.rb b/spec/active_relation/relations/order_spec.rb new file mode 100644 index 0000000000000..edf2faf4559de --- /dev/null +++ b/spec/active_relation/relations/order_spec.rb @@ -0,0 +1,28 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Order do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end + + describe '#qualify' do + it "distributes over the relation and attributes" do + ActiveRelation::Relations::Order.new(@relation1, @attribute1).qualify. \ + should == ActiveRelation::Relations::Order.new(@relation1.qualify, @attribute1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with an order clause" do + ActiveRelation::Relations::Order.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + ORDER BY `foo`.`id` + """) + end + end + +end \ No newline at end of file diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb new file mode 100644 index 0000000000000..8ba571e06ce00 --- /dev/null +++ b/spec/active_relation/relations/projection_spec.rb @@ -0,0 +1,34 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Projection do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end + + describe '==' do + it "obtains if the relations and attributes are identical" do + ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation2, @attribute1) + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation1, @attribute2) + end + end + + describe '#qualify' do + it "distributes over teh relation and attributes" do + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).qualify. \ + should == ActiveRelation::Relations::Projection.new(@relation1.qualify, @attribute1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with a limited select clause" do + ActiveRelation::Relations::Projection.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`id` + FROM `foo` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/relations/range_spec.rb new file mode 100644 index 0000000000000..d4107259aac2b --- /dev/null +++ b/spec/active_relation/relations/range_spec.rb @@ -0,0 +1,30 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Range do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @range1 = 1..2 + @range2 = 4..9 + end + + describe '#qualify' do + it "distributes over the relation and attributes" do + pending + end + end + + describe '#to_sql' do + it "manufactures sql with limit and offset" do + range_size = @range2.last - @range2.first + 1 + range_start = @range2.first + ActiveRelation::Relations::Range.new(@relation1, @range2).to_s.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + LIMIT #{range_size} + OFFSET #{range_start} + """) + end + end + +end \ No newline at end of file diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb new file mode 100644 index 0000000000000..e52abab3a1144 --- /dev/null +++ b/spec/active_relation/relations/rename_spec.rb @@ -0,0 +1,61 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Rename do + before do + @relation = ActiveRelation::Relations::Table.new(:foo) + @renamed_relation = ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid) + end + + describe '#initialize' do + it "manufactures nested rename relations if multiple renames are provided" do + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ + should == ActiveRelation::Relations::Rename.new(ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) + end + + it "raises an exception if the alias provided is already used" do + pending + end + end + + describe '==' do + it "obtains if the relation, attribute, and alias are identical" do + pending + end + end + + describe '#attributes' do + it "manufactures a list of attributes with the renamed attribute aliased" do + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == + (@relation.attributes - [@relation[:id]]) + [@relation[:id].alias(:schmid)] + end + end + + describe '[]' do + it 'indexes attributes by alias' do + @renamed_relation[:id].should be_nil + @renamed_relation[:schmid].should == @relation[:id].alias(:schmid) + end + end + + describe '#schmattribute' do + it "should be renamed" do + pending + end + end + + describe '#qualify' do + it "distributes over the relation and renames" do + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).qualify. \ + should == ActiveRelation::Relations::Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) + end + end + + describe '#to_sql' do + it 'manufactures sql aliasing the attribute' do + @renamed_relation.to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` AS 'schmid' + FROM `foo` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/selection_spec.rb b/spec/active_relation/relations/selection_spec.rb new file mode 100644 index 0000000000000..90dc3169b6ca5 --- /dev/null +++ b/spec/active_relation/relations/selection_spec.rb @@ -0,0 +1,42 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Selection do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + @predicate1 = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:foo_id]) + @predicate2 = ActiveRelation::Predicates::LessThan.new(@relation1[:age], 2) + end + + describe '#initialize' do + it "manufactures nested selection relations if multiple predicates are provided" do + ActiveRelation::Relations::Selection.new(@relation1, @predicate1, @predicate2). \ + should == ActiveRelation::Relations::Selection.new(ActiveRelation::Relations::Selection.new(@relation1, @predicate2), @predicate1) + end + end + + describe '#qualify' do + it "distributes over the relation and predicates" do + ActiveRelation::Relations::Selection.new(@relation1, @predicate1).qualify. \ + should == ActiveRelation::Relations::Selection.new(@relation1.qualify, @predicate1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with where clause conditions" do + ActiveRelation::Relations::Selection.new(@relation1, @predicate1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE `foo`.`id` = `bar`.`foo_id` + """) + end + + it "allows arbitrary sql" do + ActiveRelation::Relations::Selection.new(@relation1, "asdf").to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE asdf + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb new file mode 100644 index 0000000000000..62b8e4498030d --- /dev/null +++ b/spec/active_relation/relations/table_spec.rb @@ -0,0 +1,30 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Table do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + end + + describe '#to_sql' do + it "returns a simple SELECT query" do + @relation.to_sql.should be_like(""" + SELECT `users`.`name`, `users`.`id` + FROM `users` + """) + end + end + + describe '#attributes' do + it 'manufactures attributes corresponding to columns in the table' do + pending + end + end + + describe '#qualify' do + it 'manufactures a rename relation with all attribute names qualified' do + @relation.qualify.should == ActiveRelation::Relations::Rename.new( + ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' + ) + end + end +end \ No newline at end of file From a83efc5d5d94d50589a80bdd27ddf5b83ed39810 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 20:18:52 -0800 Subject: [PATCH 0033/1492] added aggregations --- lib/active_relation.rb | 3 +- lib/active_relation/primitives.rb | 3 ++ lib/active_relation/primitives/aggregation.rb | 21 +++++++++ .../{relations => primitives}/attribute.rb | 43 +++++++++++++++---- lib/active_relation/relations.rb | 1 - lib/active_relation/relations/table.rb | 2 +- .../relations/attribute_spec.rb | 40 ++++++++++++++++- 7 files changed, 100 insertions(+), 13 deletions(-) create mode 100644 lib/active_relation/primitives.rb create mode 100644 lib/active_relation/primitives/aggregation.rb rename lib/active_relation/{relations => primitives}/attribute.rb (55%) diff --git a/lib/active_relation.rb b/lib/active_relation.rb index cdac17facbd2f..0b55ed74d0e6c 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -6,5 +6,6 @@ require 'active_relation/sql_builder' require 'active_relation/extensions' +require 'active_relation/predicates' require 'active_relation/relations' -require 'active_relation/predicates' \ No newline at end of file +require 'active_relation/primitives' \ No newline at end of file diff --git a/lib/active_relation/primitives.rb b/lib/active_relation/primitives.rb new file mode 100644 index 0000000000000..5d35f4256419c --- /dev/null +++ b/lib/active_relation/primitives.rb @@ -0,0 +1,3 @@ +require 'active_relation/primitives/attribute' +require 'active_relation/primitives/aggregation' + diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb new file mode 100644 index 0000000000000..20fdcf46c5f88 --- /dev/null +++ b/lib/active_relation/primitives/aggregation.rb @@ -0,0 +1,21 @@ +module ActiveRelation + module Primitives + class Aggregation + include SqlBuilder + + attr_reader :attribute, :function_sql + + def initialize(attribute, function_sql) + @attribute, @function_sql = attribute, function_sql + end + + def to_sql(options = {}) + "#{function_sql}(@attribute.to_sql)" + end + + def ==(other) + self.class == other.class and attribute == other.attribute and function_sql == other.function_sql + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/attribute.rb b/lib/active_relation/primitives/attribute.rb similarity index 55% rename from lib/active_relation/relations/attribute.rb rename to lib/active_relation/primitives/attribute.rb index 2fe702cb143b2..65ae12cf36787 100644 --- a/lib/active_relation/relations/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -1,7 +1,7 @@ module ActiveRelation module Primitives class Attribute - include ::ActiveRelation::SqlBuilder + include SqlBuilder attr_reader :relation, :name, :alias @@ -10,7 +10,7 @@ def initialize(relation, name, aliaz = nil) end def alias(aliaz = nil) - aliaz ? ActiveRelation::Primitives::Attribute.new(relation, name, aliaz) : @alias + aliaz ? Attribute.new(relation, name, aliaz) : @alias end def qualified_name @@ -25,32 +25,57 @@ def ==(other) relation == other.relation and name == other.name and @alias == other.alias end - module Predications + module Predications + include Predicates + def equals(other) - Predicates::Equality.new(self, other) + Equality.new(self, other) end def less_than(other) - Predicates::LessThan.new(self, other) + LessThan.new(self, other) end def less_than_or_equal_to(other) - Predicates::LessThanOrEqualTo.new(self, other) + LessThanOrEqualTo.new(self, other) end def greater_than(other) - Predicates::GreaterThan.new(self, other) + GreaterThan.new(self, other) end def greater_than_or_equal_to(other) - Predicates::GreaterThanOrEqualTo.new(self, other) + GreaterThanOrEqualTo.new(self, other) end def matches(regexp) - Predicates::Match.new(self, regexp) + Match.new(self, regexp) end end include Predications + + module Aggregations + def count + Aggregation.new(self, "COUNT") + end + + def sum + Aggregation.new(self, "SUM") + end + + def maximum + Aggregation.new(self, "MAX") + end + + def minimum + Aggregation.new(self, "MIN") + end + + def average + Aggregation.new(self, "AVG") + end + end + include Aggregations def to_sql(options = {}) "#{quote_table_name(relation.table)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index f7d1bc207a840..a25e82f607024 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -2,7 +2,6 @@ require 'active_relation/relations/compound' require 'active_relation/relations/table' require 'active_relation/relations/join' -require 'active_relation/relations/attribute' require 'active_relation/relations/projection' require 'active_relation/relations/selection' require 'active_relation/relations/order' diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 38f540cc5229a..d64285168761b 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -23,7 +23,7 @@ def attribute(name) private def attributes_by_name @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| - attributes_by_name.merge(column.name => ActiveRelation::Primitives::Attribute.new(self, column.name.to_sym)) + attributes_by_name.merge(column.name => Primitives::Attribute.new(self, column.name.to_sym)) end end diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb index 28fb0c3754533..2a6deca22a8d6 100644 --- a/spec/active_relation/relations/attribute_spec.rb +++ b/spec/active_relation/relations/attribute_spec.rb @@ -56,7 +56,7 @@ end end - describe 'greater_than' do + describe '#greater_than' do it "manufactures a greater-than predicate" do @attribute1.greater_than(@attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) end @@ -74,4 +74,42 @@ end end end + + describe 'aggregations' do + before do + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + end + + describe '#count' do + it "manufactures a count aggregation" do + @attribute1.count.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "COUNT") + end + end + + describe '#sum' do + it "manufactures a sum aggregation" do + @attribute1.sum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "SUM") + end + end + + describe '#maximum' do + it "manufactures a maximum aggregation" do + @attribute1.maximum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MAX") + end + end + + describe '#minimum' do + it "manufactures a minimum aggregation" do + @attribute1.minimum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MIN") + end + end + + describe '#average' do + it "manufactures an average aggregation" do + @attribute1.average.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "AVG") + end + end + + + end end From 19a63d1acfc9b7668bc19fa2796d4e11a2180cef Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 20:20:24 -0800 Subject: [PATCH 0034/1492] comment --- lib/active_relation/extensions/base.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/active_relation/extensions/base.rb b/lib/active_relation/extensions/base.rb index 53523e9d12faf..8fe00146d27f3 100644 --- a/lib/active_relation/extensions/base.rb +++ b/lib/active_relation/extensions/base.rb @@ -20,6 +20,8 @@ def get(record, &block) end end +# all of the below disables normal AR behavior. It's rather destructive and purely for demonstration purposes (see scratch_spec). + class ActiveRecord::Associations::BelongsToAssociation def instantiate(record, joins = []) @target = proxy_reflection.klass.instantiate(record, joins) From 0cba6cde9958969933da79626d00464f7d07b22f Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 20:34:18 -0800 Subject: [PATCH 0035/1492] bug with aggregation to_Sql --- lib/active_relation/extensions/base.rb | 1 - lib/active_relation/primitives/aggregation.rb | 2 +- .../relations/attribute_spec.rb | 115 ------------------ spec/spec_helper.rb | 3 + 4 files changed, 4 insertions(+), 117 deletions(-) delete mode 100644 spec/active_relation/relations/attribute_spec.rb diff --git a/lib/active_relation/extensions/base.rb b/lib/active_relation/extensions/base.rb index 8fe00146d27f3..0115586b00d7b 100644 --- a/lib/active_relation/extensions/base.rb +++ b/lib/active_relation/extensions/base.rb @@ -21,7 +21,6 @@ def get(record, &block) end # all of the below disables normal AR behavior. It's rather destructive and purely for demonstration purposes (see scratch_spec). - class ActiveRecord::Associations::BelongsToAssociation def instantiate(record, joins = []) @target = proxy_reflection.klass.instantiate(record, joins) diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index 20fdcf46c5f88..a3c77471658fa 100644 --- a/lib/active_relation/primitives/aggregation.rb +++ b/lib/active_relation/primitives/aggregation.rb @@ -10,7 +10,7 @@ def initialize(attribute, function_sql) end def to_sql(options = {}) - "#{function_sql}(@attribute.to_sql)" + "#{function_sql}(#{@attribute.to_sql})" end def ==(other) diff --git a/spec/active_relation/relations/attribute_spec.rb b/spec/active_relation/relations/attribute_spec.rb deleted file mode 100644 index 2a6deca22a8d6..0000000000000 --- a/spec/active_relation/relations/attribute_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Primitives::Attribute do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - end - - describe '#alias' do - it "manufactures an aliased attributed" do - @relation1[:id].alias(:alias).should == ActiveRelation::Primitives::Attribute.new(@relation1, :id, :alias) - end - end - - describe '#qualified_name' do - it "manufactures an attribute name prefixed with the relation's name" do - @relation1[:id].qualified_name.should == 'foo.id' - end - end - - describe '#qualify' do - it "manufactures an attribute aliased with that attributes qualified name" do - @relation1[:id].qualify.should == @relation1[:id].qualify - end - end - - describe '==' do - it "obtains if the relation and attribute name are identical" do - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should == ActiveRelation::Primitives::Attribute.new(@relation1, :name) - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation1, :another_name) - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation2, :name) - end - end - - describe 'predications' do - before do - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) - end - - describe '#equals' do - it "manufactures an equality predicate" do - @attribute1.equals(@attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) - end - end - - describe '#less_than' do - it "manufactures a less-than predicate" do - @attribute1.less_than(@attribute2).should == ActiveRelation::Predicates::LessThan.new(@attribute1, @attribute2) - end - end - - describe '#less_than_or_equal_to' do - it "manufactures a less-than or equal-to predicate" do - @attribute1.less_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::LessThanOrEqualTo.new(@attribute1, @attribute2) - end - end - - describe '#greater_than' do - it "manufactures a greater-than predicate" do - @attribute1.greater_than(@attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) - end - end - - describe '#greater_than_or_equal_to' do - it "manufactures a greater-than or equal to predicate" do - @attribute1.greater_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::GreaterThanOrEqualTo.new(@attribute1, @attribute2) - end - end - - describe '#matches' do - it "manufactures a match predicate" do - @attribute1.matches(/.*/).should == ActiveRelation::Predicates::Match.new(@attribute1, @attribute2) - end - end - end - - describe 'aggregations' do - before do - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - end - - describe '#count' do - it "manufactures a count aggregation" do - @attribute1.count.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "COUNT") - end - end - - describe '#sum' do - it "manufactures a sum aggregation" do - @attribute1.sum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "SUM") - end - end - - describe '#maximum' do - it "manufactures a maximum aggregation" do - @attribute1.maximum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MAX") - end - end - - describe '#minimum' do - it "manufactures a minimum aggregation" do - @attribute1.minimum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MIN") - end - end - - describe '#average' do - it "manufactures an average aggregation" do - @attribute1.average.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "AVG") - end - end - - - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8f5d76370ce27..e799aed3392fd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -26,5 +26,8 @@ def shift Spec::Runner.configure do |config| config.include(BeLikeMatcher) + config.include(ActiveRelation::Relations) + config.include(ActiveRelation::Primitives) + config.include(ActiveRelation::Predicates) config.mock_with :rr end \ No newline at end of file From 7c7044085617a66abb3f9bd37dc7c072701f03c7 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 23:30:12 -0800 Subject: [PATCH 0036/1492] aliasing of relations --- lib/active_relation/primitives/attribute.rb | 6 +- lib/active_relation/relations.rb | 3 +- lib/active_relation/relations/alias.rb | 19 +++ lib/active_relation/relations/base.rb | 10 +- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/rename.rb | 4 +- .../active_relation/predicates/binary_spec.rb | 10 +- .../primitives/aggregation_spec.rb | 25 ++++ .../primitives/attribute_spec.rb | 115 ++++++++++++++++++ spec/active_relation/relations/base_spec.rb | 22 +++- .../relations/compound_spec.rb | 13 ++ .../relations/projection_spec.rb | 2 +- spec/active_relation/relations/rename_spec.rb | 4 +- 13 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 lib/active_relation/relations/alias.rb create mode 100644 spec/active_relation/primitives/aggregation_spec.rb create mode 100644 spec/active_relation/primitives/attribute_spec.rb create mode 100644 spec/active_relation/relations/compound_spec.rb diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 65ae12cf36787..b13f9befe1549 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -9,8 +9,8 @@ def initialize(relation, name, aliaz = nil) @relation, @name, @alias = relation, name, aliaz end - def alias(aliaz = nil) - aliaz ? Attribute.new(relation, name, aliaz) : @alias + def as(aliaz = nil) + Attribute.new(relation, name, aliaz) end def qualified_name @@ -18,7 +18,7 @@ def qualified_name end def qualify - self.alias(qualified_name) + self.as(qualified_name) end def ==(other) diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index a25e82f607024..1eb58d3b42123 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -8,4 +8,5 @@ require 'active_relation/relations/range' require 'active_relation/relations/rename' require 'active_relation/relations/deletion' -require 'active_relation/relations/insertion' \ No newline at end of file +require 'active_relation/relations/insertion' +require 'active_relation/relations/alias' \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb new file mode 100644 index 0000000000000..97950ea5b3f12 --- /dev/null +++ b/lib/active_relation/relations/alias.rb @@ -0,0 +1,19 @@ +module ActiveRelation + module Relations + class Alias < Compound + attr_reader :alias + + def initialize(relation, aliaz) + @relation, @alias = relation, aliaz + end + + def ==(other) + relation == other.relation and self.alias == other.alias + end + + def to_sql(options = {}) + super + " AS #{@alias}" + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index 960735f07fb58..b4654f8f4b027 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -45,6 +45,10 @@ def select(*predicates) def project(*attributes) Projection.new(self, *attributes) end + + def as(aliaz) + Alias.new(self, aliaz) + end def order(*attributes) Order.new(self, *attributes) @@ -75,8 +79,8 @@ def connection end def to_sql(options = {}) - [ - "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", + sql = [ + "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true, :use_parens => true) }.join(', ')}", "FROM #{quote_table_name(table)}", (joins.to_sql(:quote => false) unless joins.blank?), ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), @@ -84,6 +88,7 @@ def to_sql(options = {}) ("LIMIT #{limit.to_sql}" unless limit.blank?), ("OFFSET #{offset.to_sql}" unless offset.blank?) ].compact.join("\n") + options[:use_parens] ? "(#{sql})" : sql end alias_method :to_s, :to_sql @@ -95,6 +100,7 @@ def inserts; [] end def joins; nil end def limit; nil end def offset; nil end + def alias; nil end end end end \ No newline at end of file diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 442224a011e28..26ee92b365062 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -3,7 +3,7 @@ module Relations class Compound < Base attr_reader :relation - delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :to => :relation + delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :alias, :to => :relation end end end \ No newline at end of file diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index c7b99c2127c39..cff042dbc64f7 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -23,7 +23,7 @@ def qualify protected def attribute(name) case - when name == self.alias then schmattribute.alias(self.alias) + when name == self.alias then schmattribute.as(self.alias) when relation[name] == schmattribute then nil else relation[name] end @@ -31,7 +31,7 @@ def attribute(name) private def substitute(a) - a == schmattribute ? a.alias(self.alias) : a + a == schmattribute ? a.as(self.alias) : a end end end diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index 02c72ef96d23d..be607efd95f2d 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -6,7 +6,7 @@ @relation2 = ActiveRelation::Relations::Table.new(:bar) @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name1) @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name2) - class ActiveRelation::Predicates::ConcreteBinary < ActiveRelation::Predicates::Binary + class ConcreteBinary < ActiveRelation::Predicates::Binary def predicate_sql "<=>" end @@ -21,20 +21,20 @@ def predicate_sql it "obtains if the concrete type of the ActiveRelation::Predicates::Binarys are identical" do ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2) + ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ConcreteBinary.new(@attribute1, @attribute2) end end describe '#qualify' do it "distributes over the predicates and attributes" do - ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).qualify. \ - should == ActiveRelation::Predicates::ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) + ConcreteBinary.new(@attribute1, @attribute2).qualify. \ + should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) end end describe '#to_sql' do it 'manufactures correct sql' do - ActiveRelation::Predicates::ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" + ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" `foo`.`name1` <=> `bar`.`name2` """) end diff --git a/spec/active_relation/primitives/aggregation_spec.rb b/spec/active_relation/primitives/aggregation_spec.rb new file mode 100644 index 0000000000000..60bb4a6aa86d1 --- /dev/null +++ b/spec/active_relation/primitives/aggregation_spec.rb @@ -0,0 +1,25 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Primitives::Aggregation do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + end + + describe '==' do + it 'obtains if the attribute and function sql are identical' do + @relation1[:id].sum.should == @relation1[:id].sum + @relation1[:id].sum.should_not == @relation1[:name].sum + @relation1[:id].sum.should_not == @relation1[:name].average + @relation1[:id].sum.should_not == @relation2[:id].sum + end + end + + describe '#to_sql' do + it 'manufactures sql with an aggregation function' do + @relation1[:id].maximum.to_sql.should be_like(""" + MAX(`foo`.`id`) + """) + end + end +end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb new file mode 100644 index 0000000000000..2aad8446596cd --- /dev/null +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -0,0 +1,115 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Primitives::Attribute do + before do + @relation1 = ActiveRelation::Relations::Table.new(:foo) + @relation2 = ActiveRelation::Relations::Table.new(:bar) + end + + describe '#as' do + it "manufactures an aliased attributed when provided a parameter" do + @relation1[:id].as(:alias).should == ActiveRelation::Primitives::Attribute.new(@relation1, :id, :alias) + end + end + + describe '#qualified_name' do + it "manufactures an attribute name prefixed with the relation's name" do + @relation1[:id].qualified_name.should == 'foo.id' + end + end + + describe '#qualify' do + it "manufactures an attribute aliased with that attributes qualified name" do + @relation1[:id].qualify.should == @relation1[:id].qualify + end + end + + describe '==' do + it "obtains if the relation and attribute name are identical" do + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should == ActiveRelation::Primitives::Attribute.new(@relation1, :name) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation1, :another_name) + ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation2, :name) + end + end + + describe 'predications' do + before do + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) + end + + describe '#equals' do + it "manufactures an equality predicate" do + @attribute1.equals(@attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + end + end + + describe '#less_than' do + it "manufactures a less-than predicate" do + @attribute1.less_than(@attribute2).should == ActiveRelation::Predicates::LessThan.new(@attribute1, @attribute2) + end + end + + describe '#less_than_or_equal_to' do + it "manufactures a less-than or equal-to predicate" do + @attribute1.less_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::LessThanOrEqualTo.new(@attribute1, @attribute2) + end + end + + describe '#greater_than' do + it "manufactures a greater-than predicate" do + @attribute1.greater_than(@attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) + end + end + + describe '#greater_than_or_equal_to' do + it "manufactures a greater-than or equal to predicate" do + @attribute1.greater_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::GreaterThanOrEqualTo.new(@attribute1, @attribute2) + end + end + + describe '#matches' do + it "manufactures a match predicate" do + @attribute1.matches(/.*/).should == ActiveRelation::Predicates::Match.new(@attribute1, @attribute2) + end + end + end + + describe 'aggregations' do + before do + @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) + end + + describe '#count' do + it "manufactures a count aggregation" do + @attribute1.count.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "COUNT") + end + end + + describe '#sum' do + it "manufactures a sum aggregation" do + @attribute1.sum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "SUM") + end + end + + describe '#maximum' do + it "manufactures a maximum aggregation" do + @attribute1.maximum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MAX") + end + end + + describe '#minimum' do + it "manufactures a minimum aggregation" do + @attribute1.minimum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MIN") + end + end + + describe '#average' do + it "manufactures an average aggregation" do + @attribute1.average.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "AVG") + end + end + + + end +end diff --git a/spec/active_relation/relations/base_spec.rb b/spec/active_relation/relations/base_spec.rb index 689e3ecadb03e..db112e679a769 100644 --- a/spec/active_relation/relations/base_spec.rb +++ b/spec/active_relation/relations/base_spec.rb @@ -49,13 +49,19 @@ end it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Projection) + @relation1.project(@attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) + end + end + + describe '#as' do + it "manufactures an alias relation" do + @relation1.as(:thucydides).should == ActiveRelation::Relations::Alias.new(@relation1, :thucydides) end end describe '#rename' do it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should be_kind_of(ActiveRelation::Relations::Rename) + @relation1.rename(@attribute1, :foo).should == ActiveRelation::Relations::Rename.new(@relation1, @attribute1 => :foo) end end @@ -65,11 +71,11 @@ end it "manufactures a selection relation" do - @relation1.select(@predicate).should be_kind_of(ActiveRelation::Relations::Selection) + @relation1.select(@predicate).should == ActiveRelation::Relations::Selection.new(@relation1, @predicate) end it "accepts arbitrary strings" do - @relation1.select("arbitrary").should be_kind_of(ActiveRelation::Relations::Selection) + @relation1.select("arbitrary").should == ActiveRelation::Relations::Selection.new(@relation1, "arbitrary") end end @@ -93,4 +99,12 @@ end end end + + describe '#to_sql' do + it "manufactures sql with scalar selects" do + @relation1.as(:tobias).to_sql(:use_parens => true).should be_like(""" + (SELECT `foo`.`name`, `foo`.`id` FROM `foo`) AS tobias + """) + end + end end \ No newline at end of file diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/relations/compound_spec.rb new file mode 100644 index 0000000000000..f383ff4dfd8ed --- /dev/null +++ b/spec/active_relation/relations/compound_spec.rb @@ -0,0 +1,13 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Compound do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + + class ConcreteCompound < ActiveRelation::Relations::Compound + def initialize(relation) + @relation = relation + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb index 8ba571e06ce00..6ffdeb8e09d4b 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/relations/projection_spec.rb @@ -17,7 +17,7 @@ end describe '#qualify' do - it "distributes over teh relation and attributes" do + it "distributes over the relation and attributes" do ActiveRelation::Relations::Projection.new(@relation1, @attribute1).qualify. \ should == ActiveRelation::Relations::Projection.new(@relation1.qualify, @attribute1.qualify) end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index e52abab3a1144..76b70691903d6 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -26,14 +26,14 @@ describe '#attributes' do it "manufactures a list of attributes with the renamed attribute aliased" do ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == - (@relation.attributes - [@relation[:id]]) + [@relation[:id].alias(:schmid)] + (@relation.attributes - [@relation[:id]]) + [@relation[:id].as(:schmid)] end end describe '[]' do it 'indexes attributes by alias' do @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation[:id].alias(:schmid) + @renamed_relation[:schmid].should == @relation[:id].as(:schmid) end end From eecab85b331c6bb716978262b418ab02ff4a22e9 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Jan 2008 23:36:28 -0800 Subject: [PATCH 0037/1492] experimenting with new aliasing terminology and interface --- lib/active_relation/primitives/aggregation.rb | 2 +- lib/active_relation/relations/alias.rb | 4 ---- lib/active_relation/relations/base.rb | 2 +- lib/active_relation/relations/rename.rb | 12 ++++++------ spec/active_relation/relations/rename_spec.rb | 10 +++++----- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index a3c77471658fa..403c03fab5edd 100644 --- a/lib/active_relation/primitives/aggregation.rb +++ b/lib/active_relation/primitives/aggregation.rb @@ -10,7 +10,7 @@ def initialize(attribute, function_sql) end def to_sql(options = {}) - "#{function_sql}(#{@attribute.to_sql})" + "#{function_sql}(#{attribute.to_sql})" end def ==(other) diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 97950ea5b3f12..5f4a10a672ad9 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -10,10 +10,6 @@ def initialize(relation, aliaz) def ==(other) relation == other.relation and self.alias == other.alias end - - def to_sql(options = {}) - super + " AS #{@alias}" - end end end end \ No newline at end of file diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index b4654f8f4b027..ea3404e7af614 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -88,7 +88,7 @@ def to_sql(options = {}) ("LIMIT #{limit.to_sql}" unless limit.blank?), ("OFFSET #{offset.to_sql}" unless offset.blank?) ].compact.join("\n") - options[:use_parens] ? "(#{sql})" : sql + (options[:use_parens] ? "(#{sql})" : sql) + (self.alias ? " AS #{self.alias}" : "") end alias_method :to_s, :to_sql diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index cff042dbc64f7..563b28922c6d0 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -1,15 +1,15 @@ module ActiveRelation module Relations class Rename < Compound - attr_reader :schmattribute, :alias + attr_reader :schmattribute, :rename def initialize(relation, renames) - @schmattribute, @alias = renames.shift + @schmattribute, @rename = renames.shift @relation = renames.empty?? relation : Rename.new(relation, renames) end def ==(other) - relation == other.relation and schmattribute == other.schmattribute and self.alias == other.alias + relation == other.relation and schmattribute == other.schmattribute and self.rename == other.rename end def attributes @@ -17,13 +17,13 @@ def attributes end def qualify - Rename.new(relation.qualify, schmattribute.qualify => self.alias) + Rename.new(relation.qualify, schmattribute.qualify => self.rename) end protected def attribute(name) case - when name == self.alias then schmattribute.as(self.alias) + when name == self.rename then schmattribute.as(self.rename) when relation[name] == schmattribute then nil else relation[name] end @@ -31,7 +31,7 @@ def attribute(name) private def substitute(a) - a == schmattribute ? a.as(self.alias) : a + a == schmattribute ? a.as(self.rename) : a end end end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 76b70691903d6..bdc5c97492733 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -12,26 +12,26 @@ should == ActiveRelation::Relations::Rename.new(ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) end - it "raises an exception if the alias provided is already used" do + it "raises an exception if the rename provided is already used" do pending end end describe '==' do - it "obtains if the relation, attribute, and alias are identical" do + it "obtains if the relation, attribute, and rename are identical" do pending end end describe '#attributes' do - it "manufactures a list of attributes with the renamed attribute aliased" do + it "manufactures a list of attributes with the renamed attribute renameed" do ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == (@relation.attributes - [@relation[:id]]) + [@relation[:id].as(:schmid)] end end describe '[]' do - it 'indexes attributes by alias' do + it 'indexes attributes by rename' do @renamed_relation[:id].should be_nil @renamed_relation[:schmid].should == @relation[:id].as(:schmid) end @@ -51,7 +51,7 @@ end describe '#to_sql' do - it 'manufactures sql aliasing the attribute' do + it 'manufactures sql renameing the attribute' do @renamed_relation.to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id` AS 'schmid' FROM `foo` From 59cc0e235285feeeb652ebc17a128c769e2c9d8c Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Jan 2008 00:37:05 -0800 Subject: [PATCH 0038/1492] removed to_sql invocation for joins in base.rb... unnecessary, but perhaps confusing? --- lib/active_relation/relations/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index ea3404e7af614..2c79911900049 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -82,7 +82,7 @@ def to_sql(options = {}) sql = [ "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true, :use_parens => true) }.join(', ')}", "FROM #{quote_table_name(table)}", - (joins.to_sql(:quote => false) unless joins.blank?), + (joins unless joins.blank?), ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), From 2e63ac91302e2df397a286fdaf9cea51635071a6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Jan 2008 17:43:00 -0800 Subject: [PATCH 0039/1492] removed support for scalar select (will return later); added support for aliased tables --- lib/active_relation/primitives/attribute.rb | 4 +-- lib/active_relation/relations/alias.rb | 23 +++++++++++- lib/active_relation/relations/base.rb | 5 ++- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/deletion.rb | 2 +- lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/join.rb | 4 +-- lib/active_relation/relations/rename.rb | 2 +- lib/active_relation/relations/table.rb | 12 ++++--- .../primitives/attribute_spec.rb | 4 +++ spec/active_relation/relations/alias_spec.rb | 36 +++++++++++++++++++ spec/active_relation/relations/base_spec.rb | 8 ----- spec/active_relation/relations/table_spec.rb | 2 +- 13 files changed, 81 insertions(+), 25 deletions(-) create mode 100644 spec/active_relation/relations/alias_spec.rb diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index b13f9befe1549..5ce3dfd531407 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -14,7 +14,7 @@ def as(aliaz = nil) end def qualified_name - "#{relation.table}.#{name}" + "#{relation.name}.#{name}" end def qualify @@ -78,7 +78,7 @@ def average include Aggregations def to_sql(options = {}) - "#{quote_table_name(relation.table)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") + "#{quote_table_name(relation.name)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") end end end diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 5f4a10a672ad9..2d1b9c14765fb 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -2,14 +2,35 @@ module ActiveRelation module Relations class Alias < Compound attr_reader :alias + alias_method :name, :alias def initialize(relation, aliaz) @relation, @alias = relation, aliaz end - + + def attributes + relation.attributes.collect(&method(:substitute)) + end + def ==(other) relation == other.relation and self.alias == other.alias end + + protected + def table_sql + "#{quote_table_name(relation.name)} AS #{quote_table_name(@alias)}" + end + + def attribute(name) + if unaliased_attribute = relation[name] + substitute(unaliased_attribute) + end + end + + private + def substitute(attribute) + Primitives::Attribute.new(self, attribute.name, attribute.alias) + end end end end \ No newline at end of file diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index 2c79911900049..71d15f31f1220 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -80,15 +80,14 @@ def connection def to_sql(options = {}) sql = [ - "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true, :use_parens => true) }.join(', ')}", - "FROM #{quote_table_name(table)}", + "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", + "FROM #{table_sql}", (joins unless joins.blank?), ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), ("OFFSET #{offset.to_sql}" unless offset.blank?) ].compact.join("\n") - (options[:use_parens] ? "(#{sql})" : sql) + (self.alias ? " AS #{self.alias}" : "") end alias_method :to_s, :to_sql diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 26ee92b365062..46454eb628898 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -3,7 +3,7 @@ module Relations class Compound < Base attr_reader :relation - delegate :attributes, :attribute, :joins, :selects, :orders, :table, :inserts, :limit, :offset, :alias, :to => :relation + delegate :attributes, :attribute, :joins, :selects, :orders, :table_sql, :inserts, :limit, :offset, :to => :relation end end end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index f218d9da6d4f5..0276dc1bc4f62 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -8,7 +8,7 @@ def initialize(relation) def to_sql(options = {}) [ "DELETE", - "FROM #{quote_table_name(table)}", + "FROM #{table_sql}", ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) ].compact.join("\n") end diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index a0042a18a5fbe..86581c23d7e4c 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -10,7 +10,7 @@ def initialize(relation, record) def to_sql(options = {}) [ "INSERT", - "INTO #{quote_table_name(table)}", + "INTO #{table_sql}", "(#{record.keys.collect(&:to_sql).join(', ')})", "VALUES #{inserts.collect(&:to_sql).join(', ')}" ].join("\n") diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 1bd1439dd64be..3d50365c409a1 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -34,11 +34,11 @@ def attribute(name) relation1[name] || relation2[name] end - delegate :table, :to => :relation1 + delegate :table_sql, :to => :relation1 private def join - "#{join_sql} #{quote_table_name(relation2.table)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" + "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" end end end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 563b28922c6d0..c4ba6ded887fa 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -13,7 +13,7 @@ def ==(other) end def attributes - relation.attributes.collect { |a| substitute(a) } + relation.attributes.collect(&method(:substitute)) end def qualify diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index d64285168761b..a370b4266d914 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -1,10 +1,10 @@ module ActiveRelation module Relations class Table < Base - attr_reader :table + attr_reader :name - def initialize(table) - @table = table + def initialize(name) + @name = name end def attributes @@ -19,10 +19,14 @@ def qualify def attribute(name) attributes_by_name[name.to_s] end + + def table_sql + "#{quote_table_name(name)}" + end private def attributes_by_name - @attributes_by_name ||= connection.columns(table, "#{table} Columns").inject({}) do |attributes_by_name, column| + @attributes_by_name ||= connection.columns(name, "#{name} Columns").inject({}) do |attributes_by_name, column| attributes_by_name.merge(column.name => Primitives::Attribute.new(self, column.name.to_sym)) end end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 2aad8446596cd..f1aa404a34241 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -16,6 +16,10 @@ it "manufactures an attribute name prefixed with the relation's name" do @relation1[:id].qualified_name.should == 'foo.id' end + + it "manufactures an attribute name prefixed with the relation's aliased name" do + @relation1.as(:bar)[:id].qualified_name.should == 'bar.id' + end end describe '#qualify' do diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb new file mode 100644 index 0000000000000..6f25df3ddb307 --- /dev/null +++ b/spec/active_relation/relations/alias_spec.rb @@ -0,0 +1,36 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +describe ActiveRelation::Relations::Alias do + before do + @relation = ActiveRelation::Relations::Table.new(:users) + @alias_relation = @relation.as(:foo) + end + + describe '#name' do + it 'returns the alias' do + @alias_relation.name.should == :foo + end + end + + describe '#attributes' do + it 'manufactures sql deleting a table relation' do + @alias_relation.attributes.should == @relation.attributes.collect { |a| ActiveRelation::Primitives::Attribute.new(@alias_relation, a.name) } + end + end + + describe '[]' do + it 'manufactures attributes associated with the aliased relation' do + @alias_relation[:id].relation.should == @alias_relation + @alias_relation[:does_not_exist].should be_nil + end + end + + describe '#to_sql' do + it "manufactures an aliased select query" do + @alias_relation.to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `users` AS `foo` + """) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/base_spec.rb b/spec/active_relation/relations/base_spec.rb index db112e679a769..18063757df4ba 100644 --- a/spec/active_relation/relations/base_spec.rb +++ b/spec/active_relation/relations/base_spec.rb @@ -99,12 +99,4 @@ end end end - - describe '#to_sql' do - it "manufactures sql with scalar selects" do - @relation1.as(:tobias).to_sql(:use_parens => true).should be_like(""" - (SELECT `foo`.`name`, `foo`.`id` FROM `foo`) AS tobias - """) - end - end end \ No newline at end of file diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 62b8e4498030d..1418ac203f0c4 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -6,7 +6,7 @@ end describe '#to_sql' do - it "returns a simple SELECT query" do + it "manufactures a simple select query" do @relation.to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id` FROM `users` From bc4f6b8a29fc96c05efe0304ce7fad075818d2a2 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Jan 2008 18:31:35 -0800 Subject: [PATCH 0040/1492] experimenting with strategy pattern rather than conditional; not as terse, nor transparent, but i still feel it's better --- lib/active_relation.rb | 2 +- lib/active_relation/extensions/hash.rb | 2 +- lib/active_relation/extensions/object.rb | 7 +-- lib/active_relation/predicates.rb | 39 ++++++-------- lib/active_relation/primitives/aggregation.rb | 6 +-- lib/active_relation/primitives/attribute.rb | 6 +-- lib/active_relation/relations/base.rb | 10 ++-- lib/active_relation/relations/deletion.rb | 2 +- lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/join.rb | 2 +- lib/active_relation/sql.rb | 51 +++++++++++++++++++ lib/active_relation/sql_builder.rb | 9 ---- .../predicates/equality_spec.rb | 3 ++ 13 files changed, 86 insertions(+), 55 deletions(-) create mode 100644 lib/active_relation/sql.rb delete mode 100644 lib/active_relation/sql_builder.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 0b55ed74d0e6c..23a80a9c381ec 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -4,7 +4,7 @@ require 'activesupport' require 'activerecord' -require 'active_relation/sql_builder' +require 'active_relation/sql' require 'active_relation/extensions' require 'active_relation/predicates' require 'active_relation/relations' diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index d9496df2e90ba..50864912bf806 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -5,7 +5,7 @@ def alias(&block) end end - def to_sql(options = {}) + def to_sql(strategy = nil) "(#{values.collect(&:to_sql).join(', ')})" end end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index ea582d1ca1819..2d43120f70f93 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -1,12 +1,9 @@ class Object - include ActiveRelation::SqlBuilder - def qualify self end - def to_sql(options = {}) - options.reverse_merge!(:quote => true) - options[:quote] ? quote(self) : self + def to_sql(strategy = ActiveRelation::Sql::Scalar.new) + strategy.scalar self end end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index fba1cc90b6cd1..84db60e3b9406 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -7,30 +7,30 @@ def ==(other) end class Binary < Base - attr_reader :attribute1, :attribute2 + attr_reader :attribute, :operand - def initialize(attribute1, attribute2) - @attribute1, @attribute2 = attribute1, attribute2 + def initialize(attribute, operand) + @attribute, @operand = attribute, operand end def ==(other) - super and @attribute1 == other.attribute1 and @attribute2 == other.attribute2 + super and @attribute == other.attribute and @operand == other.operand end def qualify - self.class.new(attribute1.qualify, attribute2.qualify) + self.class.new(attribute.qualify, operand.qualify) end - def to_sql(options = {}) - "#{attribute1.to_sql} #{predicate_sql} #{attribute2.to_sql}" + def to_sql(strategy = Sql::Predicate.new) + "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" end end class Equality < Binary def ==(other) self.class == other.class and - ((attribute1 == other.attribute1 and attribute2 == other.attribute2) or - (attribute1 == other.attribute2 and attribute2 == other.attribute1)) + ((attribute == other.attribute and operand == other.operand) or + (attribute == other.operand and operand == other.attribute)) end protected @@ -67,27 +67,20 @@ def predicate_sql end end - class Match < Base - attr_reader :attribute, :regexp + class Match < Binary + alias_method :regexp, :operand def initialize(attribute, regexp) @attribute, @regexp = attribute, regexp end end - class RelationInclusion < Base - attr_reader :attribute, :relation - - def initialize(attribute, relation) - @attribute, @relation = attribute, relation - end - - def ==(other) - super and attribute == other.attribute and relation == other.relation - end + class RelationInclusion < Binary + alias_method :relation, :operand - def to_sql(options = {}) - "#{attribute.to_sql} IN (#{relation.to_sql})" + protected + def predicate_sql + 'IN' end end end diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index 403c03fab5edd..189eb33ac9303 100644 --- a/lib/active_relation/primitives/aggregation.rb +++ b/lib/active_relation/primitives/aggregation.rb @@ -1,15 +1,13 @@ module ActiveRelation module Primitives - class Aggregation - include SqlBuilder - + class Aggregation attr_reader :attribute, :function_sql def initialize(attribute, function_sql) @attribute, @function_sql = attribute, function_sql end - def to_sql(options = {}) + def to_sql(strategy = nil) "#{function_sql}(#{attribute.to_sql})" end diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 5ce3dfd531407..6ebaf1b292370 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -1,8 +1,6 @@ module ActiveRelation module Primitives class Attribute - include SqlBuilder - attr_reader :relation, :name, :alias def initialize(relation, name, aliaz = nil) @@ -77,8 +75,8 @@ def average end include Aggregations - def to_sql(options = {}) - "#{quote_table_name(relation.name)}.#{quote_column_name(name)}" + (options[:use_alias] && self.alias ? " AS #{self.alias.to_s.to_sql}" : "") + def to_sql(strategy = Sql::Predicate.new) + strategy.attribute relation.name, name, self.alias end end end diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index 71d15f31f1220..c464b6bc31a7e 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -1,7 +1,7 @@ module ActiveRelation module Relations class Base - include SqlBuilder + include Sql::Quoting module Iteration include Enumerable @@ -78,12 +78,12 @@ def connection ActiveRecord::Base.connection end - def to_sql(options = {}) - sql = [ - "SELECT #{attributes.collect{ |a| a.to_sql(:use_alias => true) }.join(', ')}", + def to_sql(strategy = Sql::Select.new) + strategy.select [ + "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(:quote => false)}.join("\n\tAND ")}" unless selects.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), ("OFFSET #{offset.to_sql}" unless offset.blank?) diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index 0276dc1bc4f62..add6440c2aee5 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -5,7 +5,7 @@ def initialize(relation) @relation = relation end - def to_sql(options = {}) + def to_sql(strategy = nil) [ "DELETE", "FROM #{table_sql}", diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 86581c23d7e4c..c82513ce0f935 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -7,7 +7,7 @@ def initialize(relation, record) @relation, @record = relation, record end - def to_sql(options = {}) + def to_sql(strategy = nil) [ "INSERT", "INTO #{table_sql}", diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 3d50365c409a1..4e6c85979e827 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -38,7 +38,7 @@ def attribute(name) private def join - "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(:quote => false) }.join(' AND ')}" + "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" end end end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb new file mode 100644 index 0000000000000..89f6193cd84d4 --- /dev/null +++ b/lib/active_relation/sql.rb @@ -0,0 +1,51 @@ +module ActiveRelation + module Sql + module Quoting + def connection + ActiveRecord::Base.connection + end + + delegate :quote_table_name, :quote_column_name, :quote, :to => :connection + end + + class Strategy + include Quoting + end + + class Projection < Strategy + def attribute(relation_name, attribute_name, aliaz) + "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") + end + + def select(select_sql) + "(#{select_sql})" + end + end + + class Predicate < Strategy + def attribute(relation_name, attribute_name, aliaz) + "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + end + + def scalar(scalar) + scalar + end + + def select(select_sql) + "(#{select_sql})" + end + end + + class Select < Strategy + def select(select_sql) + select_sql + end + end + + class Scalar < Strategy + def scalar(scalar) + quote(scalar) + end + end + end +end \ No newline at end of file diff --git a/lib/active_relation/sql_builder.rb b/lib/active_relation/sql_builder.rb deleted file mode 100644 index 07a4ebabb7115..0000000000000 --- a/lib/active_relation/sql_builder.rb +++ /dev/null @@ -1,9 +0,0 @@ -module ActiveRelation - module SqlBuilder - def connection - ActiveRecord::Base.connection - end - - delegate :quote_table_name, :quote_column_name, :quote, :to => :connection - end -end \ No newline at end of file diff --git a/spec/active_relation/predicates/equality_spec.rb b/spec/active_relation/predicates/equality_spec.rb index b3c7b597a0802..9394e63835356 100644 --- a/spec/active_relation/predicates/equality_spec.rb +++ b/spec/active_relation/predicates/equality_spec.rb @@ -22,4 +22,7 @@ ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute2, @attribute1) end end + + describe '#to_sql' do + end end \ No newline at end of file From 17a5fd13bc4ba8405d95e90d12b87dcd7e5bea5b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Jan 2008 18:44:48 -0800 Subject: [PATCH 0041/1492] strategy pattern --- lib/active_relation/relations/base.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb index c464b6bc31a7e..d90d8ae3e637c 100644 --- a/lib/active_relation/relations/base.rb +++ b/lib/active_relation/relations/base.rb @@ -74,10 +74,6 @@ def on(*predicates) end include Operations - def connection - ActiveRecord::Base.connection - end - def to_sql(strategy = Sql::Select.new) strategy.select [ "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", @@ -92,6 +88,10 @@ def to_sql(strategy = Sql::Select.new) alias_method :to_s, :to_sql protected + def connection + ActiveRecord::Base.connection + end + def attributes; [] end def selects; [] end def orders; [] end From 553eb0ad490abc7f85d9836c3ba959ab771d3cf4 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 14 Jan 2008 10:50:46 -0500 Subject: [PATCH 0042/1492] Remove ActiveRelation sub-modules and refactor specs --- lib/active_relation/extensions/base.rb | 2 +- lib/active_relation/predicates.rb | 136 +++++++-------- lib/active_relation/primitives/aggregation.rb | 28 ++- lib/active_relation/primitives/attribute.rb | 134 +++++++------- lib/active_relation/relations.rb | 2 +- lib/active_relation/relations/alias.rb | 56 +++--- lib/active_relation/relations/base.rb | 105 ----------- lib/active_relation/relations/compound.rb | 10 +- lib/active_relation/relations/deletion.rb | 24 ++- lib/active_relation/relations/insertion.rb | 36 ++-- lib/active_relation/relations/join.rb | 80 +++++---- lib/active_relation/relations/order.rb | 28 ++- lib/active_relation/relations/projection.rb | 28 ++- lib/active_relation/relations/range.rb | 36 ++-- lib/active_relation/relations/relation.rb | 103 +++++++++++ lib/active_relation/relations/rename.rb | 64 ++++--- lib/active_relation/relations/selection.rb | 40 ++--- lib/active_relation/relations/table.rb | 62 ++++--- .../active_relation/predicates/binary_spec.rb | 60 +++---- .../predicates/equality_spec.rb | 40 +++-- spec/active_relation/predicates/match_spec.rb | 22 +-- .../predicates/relation_inclusion_spec.rb | 36 ++-- .../primitives/aggregation_spec.rb | 38 ++-- .../primitives/attribute_spec.rb | 164 +++++++++--------- spec/active_relation/relations/alias_spec.rb | 50 +++--- spec/active_relation/relations/base_spec.rb | 102 ----------- .../relations/compound_spec.rb | 14 +- .../relations/deletion_spec.rb | 36 ++-- .../relations/insertion_spec.rb | 40 +++-- spec/active_relation/relations/join_spec.rb | 64 +++---- spec/active_relation/relations/order_spec.rb | 44 ++--- .../relations/projection_spec.rb | 50 +++--- spec/active_relation/relations/range_spec.rb | 45 ++--- .../relations/relation_spec.rb | 104 +++++++++++ spec/active_relation/relations/rename_spec.rb | 86 ++++----- .../relations/selection_spec.rb | 64 +++---- spec/active_relation/relations/table_spec.rb | 42 ++--- spec/spec_helper.rb | 5 +- 38 files changed, 1039 insertions(+), 1041 deletions(-) delete mode 100644 lib/active_relation/relations/base.rb create mode 100644 lib/active_relation/relations/relation.rb delete mode 100644 spec/active_relation/relations/base_spec.rb create mode 100644 spec/active_relation/relations/relation_spec.rb diff --git a/lib/active_relation/extensions/base.rb b/lib/active_relation/extensions/base.rb index 0115586b00d7b..c1b823f9a761d 100644 --- a/lib/active_relation/extensions/base.rb +++ b/lib/active_relation/extensions/base.rb @@ -5,7 +5,7 @@ def cache end def relation - @relation ||= ActiveRelation::Relations::Table.new(table_name) + @relation ||= ActiveRelation::Table.new(table_name) end end diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 84db60e3b9406..55a6c852e2952 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -1,87 +1,85 @@ module ActiveRelation - module Predicates - class Base - def ==(other) - self.class == other.class - end + class Predicate + def ==(other) + self.class == other.class end - - class Binary < Base - attr_reader :attribute, :operand + end + + class Binary < Predicate + attr_reader :attribute, :operand - def initialize(attribute, operand) - @attribute, @operand = attribute, operand - end + def initialize(attribute, operand) + @attribute, @operand = attribute, operand + end + + def ==(other) + super and @attribute == other.attribute and @operand == other.operand + end - def ==(other) - super and @attribute == other.attribute and @operand == other.operand - end + def qualify + self.class.new(attribute.qualify, operand.qualify) + end - def qualify - self.class.new(attribute.qualify, operand.qualify) - end + def to_sql(strategy = Sql::Predicate.new) + "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" + end + end - def to_sql(strategy = Sql::Predicate.new) - "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" - end + class Equality < Binary + def ==(other) + self.class == other.class and + ((attribute == other.attribute and operand == other.operand) or + (attribute == other.operand and operand == other.attribute)) end - - class Equality < Binary - def ==(other) - self.class == other.class and - ((attribute == other.attribute and operand == other.operand) or - (attribute == other.operand and operand == other.attribute)) - end - protected - def predicate_sql - '=' - end + protected + def predicate_sql + '=' end - - class GreaterThanOrEqualTo < Binary - protected - def predicate_sql - '>=' - end + end + + class GreaterThanOrEqualTo < Binary + protected + def predicate_sql + '>=' end - - class GreaterThan < Binary - protected - def predicate_sql - '>' - end + end + + class GreaterThan < Binary + protected + def predicate_sql + '>' end - - class LessThanOrEqualTo < Binary - protected - def predicate_sql - '<=' - end + end + + class LessThanOrEqualTo < Binary + protected + def predicate_sql + '<=' end - - class LessThan < Binary - protected - def predicate_sql - '<' - end + end + + class LessThan < Binary + protected + def predicate_sql + '<' end - - class Match < Binary - alias_method :regexp, :operand + end + + class Match < Binary + alias_method :regexp, :operand - def initialize(attribute, regexp) - @attribute, @regexp = attribute, regexp - end + def initialize(attribute, regexp) + @attribute, @regexp = attribute, regexp end - - class RelationInclusion < Binary - alias_method :relation, :operand - - protected - def predicate_sql - 'IN' - end + end + + class RelationInclusion < Binary + alias_method :relation, :operand + + protected + def predicate_sql + 'IN' end end end \ No newline at end of file diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index 189eb33ac9303..48f8946835ea2 100644 --- a/lib/active_relation/primitives/aggregation.rb +++ b/lib/active_relation/primitives/aggregation.rb @@ -1,19 +1,17 @@ module ActiveRelation - module Primitives - class Aggregation - attr_reader :attribute, :function_sql - - def initialize(attribute, function_sql) - @attribute, @function_sql = attribute, function_sql - end - - def to_sql(strategy = nil) - "#{function_sql}(#{attribute.to_sql})" - end - - def ==(other) - self.class == other.class and attribute == other.attribute and function_sql == other.function_sql - end + class Aggregation + attr_reader :attribute, :function_sql + + def initialize(attribute, function_sql) + @attribute, @function_sql = attribute, function_sql + end + + def to_sql(strategy = nil) + "#{function_sql}(#{attribute.to_sql})" + end + + def ==(other) + self.class == other.class and attribute == other.attribute and function_sql == other.function_sql end end end \ No newline at end of file diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 6ebaf1b292370..90bbe8012bcb4 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -1,83 +1,79 @@ module ActiveRelation - module Primitives - class Attribute - attr_reader :relation, :name, :alias - - def initialize(relation, name, aliaz = nil) - @relation, @name, @alias = relation, name, aliaz + class Attribute + attr_reader :relation, :name, :alias + + def initialize(relation, name, aliaz = nil) + @relation, @name, @alias = relation, name, aliaz + end + + def as(aliaz = nil) + Attribute.new(relation, name, aliaz) + end + + def qualified_name + "#{relation.name}.#{name}" + end + + def qualify + self.as(qualified_name) + end + + def ==(other) + relation == other.relation and name == other.name and @alias == other.alias + end + + module Predications + def equals(other) + Equality.new(self, other) end - - def as(aliaz = nil) - Attribute.new(relation, name, aliaz) + + def less_than(other) + LessThan.new(self, other) end - - def qualified_name - "#{relation.name}.#{name}" + + def less_than_or_equal_to(other) + LessThanOrEqualTo.new(self, other) end - - def qualify - self.as(qualified_name) + + def greater_than(other) + GreaterThan.new(self, other) end - - def ==(other) - relation == other.relation and name == other.name and @alias == other.alias + + def greater_than_or_equal_to(other) + GreaterThanOrEqualTo.new(self, other) end - module Predications - include Predicates - - def equals(other) - Equality.new(self, other) - end - - def less_than(other) - LessThan.new(self, other) - end - - def less_than_or_equal_to(other) - LessThanOrEqualTo.new(self, other) - end - - def greater_than(other) - GreaterThan.new(self, other) - end - - def greater_than_or_equal_to(other) - GreaterThanOrEqualTo.new(self, other) - end - - def matches(regexp) - Match.new(self, regexp) - end + def matches(regexp) + Match.new(self, regexp) + end + end + include Predications + + module Aggregations + def count + Aggregation.new(self, "COUNT") + end + + def sum + Aggregation.new(self, "SUM") + end + + def maximum + Aggregation.new(self, "MAX") end - include Predications - module Aggregations - def count - Aggregation.new(self, "COUNT") - end - - def sum - Aggregation.new(self, "SUM") - end - - def maximum - Aggregation.new(self, "MAX") - end - - def minimum - Aggregation.new(self, "MIN") - end - - def average - Aggregation.new(self, "AVG") - end + def minimum + Aggregation.new(self, "MIN") end - include Aggregations - - def to_sql(strategy = Sql::Predicate.new) - strategy.attribute relation.name, name, self.alias + + def average + Aggregation.new(self, "AVG") end end + include Aggregations + + def to_sql(strategy = Sql::Predicate.new) + strategy.attribute relation.name, name, self.alias + end end end \ No newline at end of file diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 1eb58d3b42123..9ae8f16524b7e 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -1,4 +1,4 @@ -require 'active_relation/relations/base' +require 'active_relation/relations/relation' require 'active_relation/relations/compound' require 'active_relation/relations/table' require 'active_relation/relations/join' diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 2d1b9c14765fb..63a92ccba1467 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -1,36 +1,34 @@ module ActiveRelation - module Relations - class Alias < Compound - attr_reader :alias - alias_method :name, :alias - - def initialize(relation, aliaz) - @relation, @alias = relation, aliaz - end - - def attributes - relation.attributes.collect(&method(:substitute)) - end + class Alias < Compound + attr_reader :alias + alias_method :name, :alias - def ==(other) - relation == other.relation and self.alias == other.alias - end - - protected - def table_sql - "#{quote_table_name(relation.name)} AS #{quote_table_name(@alias)}" - end - - def attribute(name) - if unaliased_attribute = relation[name] - substitute(unaliased_attribute) - end - end + def initialize(relation, aliaz) + @relation, @alias = relation, aliaz + end - private - def substitute(attribute) - Primitives::Attribute.new(self, attribute.name, attribute.alias) + def attributes + relation.attributes.collect(&method(:substitute)) + end + + def ==(other) + relation == other.relation and self.alias == other.alias + end + + protected + def table_sql + "#{quote_table_name(relation.name)} AS #{quote_table_name(@alias)}" + end + + def attribute(name) + if unaliased_attribute = relation[name] + substitute(unaliased_attribute) end end + + private + def substitute(attribute) + Attribute.new(self, attribute.name, attribute.alias) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/base.rb b/lib/active_relation/relations/base.rb deleted file mode 100644 index d90d8ae3e637c..0000000000000 --- a/lib/active_relation/relations/base.rb +++ /dev/null @@ -1,105 +0,0 @@ -module ActiveRelation - module Relations - class Base - include Sql::Quoting - - module Iteration - include Enumerable - - def each(&block) - connection.select_all(to_s).each(&block) - end - - def first - connection.select_one(to_s) - end - end - include Iteration - - module Operations - def join(other) - JoinOperation.new("INNER JOIN", self, other) - end - - def outer_join(other) - JoinOperation.new("LEFT OUTER JOIN", self, other) - end - - def [](index) - case index - when Symbol - attribute(index) - when ::Range - Range.new(self, index) - end - end - - def include?(attribute) - Predicates::RelationInclusion.new(attribute, self) - end - - def select(*predicates) - Selection.new(self, *predicates) - end - - def project(*attributes) - Projection.new(self, *attributes) - end - - def as(aliaz) - Alias.new(self, aliaz) - end - - def order(*attributes) - Order.new(self, *attributes) - end - - def rename(attribute, aliaz) - Rename.new(self, attribute => aliaz) - end - - def insert(record) - Insertion.new(self, record) - end - - def delete - Deletion.new(self) - end - - JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do - def on(*predicates) - Join.new(join_sql, relation1, relation2, *predicates) - end - end - end - include Operations - - def to_sql(strategy = Sql::Select.new) - strategy.select [ - "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", - "FROM #{table_sql}", - (joins unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), - ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), - ("LIMIT #{limit.to_sql}" unless limit.blank?), - ("OFFSET #{offset.to_sql}" unless offset.blank?) - ].compact.join("\n") - end - alias_method :to_s, :to_sql - - protected - def connection - ActiveRecord::Base.connection - end - - def attributes; [] end - def selects; [] end - def orders; [] end - def inserts; [] end - def joins; nil end - def limit; nil end - def offset; nil end - def alias; nil end - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 46454eb628898..d6da8eb8fa37f 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -1,9 +1,7 @@ module ActiveRelation - module Relations - class Compound < Base - attr_reader :relation - - delegate :attributes, :attribute, :joins, :selects, :orders, :table_sql, :inserts, :limit, :offset, :to => :relation - end + class Compound < Relation + attr_reader :relation + + delegate :attributes, :attribute, :joins, :selects, :orders, :table_sql, :inserts, :limit, :offset, :to => :relation end end \ No newline at end of file diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index add6440c2aee5..4ac40a146b2a5 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -1,17 +1,15 @@ module ActiveRelation - module Relations - class Deletion < Compound - def initialize(relation) - @relation = relation - end - - def to_sql(strategy = nil) - [ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) - ].compact.join("\n") - end + class Deletion < Compound + def initialize(relation) + @relation = relation end + + def to_sql(strategy = nil) + [ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ].compact.join("\n") + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index c82513ce0f935..31e4339ee084e 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -1,25 +1,23 @@ module ActiveRelation - module Relations - class Insertion < Compound - attr_reader :record - - def initialize(relation, record) - @relation, @record = relation, record - end + class Insertion < Compound + attr_reader :record - def to_sql(strategy = nil) - [ - "INSERT", - "INTO #{table_sql}", - "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES #{inserts.collect(&:to_sql).join(', ')}" - ].join("\n") - end + def initialize(relation, record) + @relation, @record = relation, record + end + + def to_sql(strategy = nil) + [ + "INSERT", + "INTO #{table_sql}", + "(#{record.keys.collect(&:to_sql).join(', ')})", + "VALUES #{inserts.collect(&:to_sql).join(', ')}" + ].join("\n") + end - protected - def inserts - relation.inserts + [record] - end + protected + def inserts + relation.inserts + [record] end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 4e6c85979e827..8ccd1e9c6c0b5 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -1,45 +1,43 @@ module ActiveRelation - module Relations - class Join < Base - attr_reader :join_sql, :relation1, :relation2, :predicates - - def initialize(join_sql, relation1, relation2, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates - end - - def ==(other) - predicates == other.predicates and - ((relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2)) - end - - def qualify - Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) - end - - protected - def joins - [relation1.joins, relation2.joins, join].compact.join(" ") - end - - def selects - relation1.send(:selects) + relation2.send(:selects) - end - - def attributes - relation1.attributes + relation2.attributes - end - - def attribute(name) - relation1[name] || relation2[name] - end - - delegate :table_sql, :to => :relation1 - - private - def join - "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" - end + class Join < Relation + attr_reader :join_sql, :relation1, :relation2, :predicates + + def initialize(join_sql, relation1, relation2, *predicates) + @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + end + + def ==(other) + predicates == other.predicates and + ((relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2)) + end + + def qualify + Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + end + + protected + def joins + [relation1.joins, relation2.joins, join].compact.join(" ") + end + + def selects + relation1.send(:selects) + relation2.send(:selects) + end + + def attributes + relation1.attributes + relation2.attributes + end + + def attribute(name) + relation1[name] || relation2[name] + end + + delegate :table_sql, :to => :relation1 + + private + def join + "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" end end end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index bca81c1b6dc50..d5c2a54cd181c 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -1,19 +1,17 @@ module ActiveRelation - module Relations - class Order < Compound - attr_reader :orders - - def initialize(relation, *orders) - @relation, @orders = relation, orders - end - - def ==(other) - relation == other.relation and orders == other.orders - end - - def qualify - Order.new(relation.qualify, *orders.collect { |o| o.qualify }) - end + class Order < Compound + attr_reader :orders + + def initialize(relation, *orders) + @relation, @orders = relation, orders + end + + def ==(other) + relation == other.relation and orders == other.orders + end + + def qualify + Order.new(relation.qualify, *orders.collect { |o| o.qualify }) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index 131db916f0c48..211e0607ac328 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -1,19 +1,17 @@ module ActiveRelation - module Relations - class Projection < Compound - attr_reader :attributes - - def initialize(relation, *attributes) - @relation, @attributes = relation, attributes - end - - def ==(other) - self.class == other.class and relation == other.relation and attributes == other.attributes - end - - def qualify - Projection.new(relation.qualify, *attributes.collect(&:qualify)) - end + class Projection < Compound + attr_reader :attributes + + def initialize(relation, *attributes) + @relation, @attributes = relation, attributes + end + + def ==(other) + self.class == other.class and relation == other.relation and attributes == other.attributes + end + + def qualify + Projection.new(relation.qualify, *attributes.collect(&:qualify)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb index d7e08efa0637f..e8b7f4b69d3e3 100644 --- a/lib/active_relation/relations/range.rb +++ b/lib/active_relation/relations/range.rb @@ -1,23 +1,21 @@ module ActiveRelation - module Relations - class Range < Compound - attr_reader :range - - def initialize(relation, range) - @relation, @range = relation, range - end - - def ==(other) - relation == other.relation and range == other.range - end - - def limit - range.end - range.begin + 1 - end - - def offset - range.begin - end + class Range < Compound + attr_reader :range + + def initialize(relation, range) + @relation, @range = relation, range + end + + def ==(other) + relation == other.relation and range == other.range + end + + def limit + range.end - range.begin + 1 + end + + def offset + range.begin end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb new file mode 100644 index 0000000000000..663450e69c50c --- /dev/null +++ b/lib/active_relation/relations/relation.rb @@ -0,0 +1,103 @@ +module ActiveRelation + class Relation + include Sql::Quoting + + module Iteration + include Enumerable + + def each(&block) + connection.select_all(to_s).each(&block) + end + + def first + connection.select_one(to_s) + end + end + include Iteration + + module Operations + def join(other) + JoinOperation.new("INNER JOIN", self, other) + end + + def outer_join(other) + JoinOperation.new("LEFT OUTER JOIN", self, other) + end + + def [](index) + case index + when Symbol + attribute(index) + when ::Range + Range.new(self, index) + end + end + + def include?(attribute) + RelationInclusion.new(attribute, self) + end + + def select(*predicates) + Selection.new(self, *predicates) + end + + def project(*attributes) + Projection.new(self, *attributes) + end + + def as(aliaz) + Alias.new(self, aliaz) + end + + def order(*attributes) + Order.new(self, *attributes) + end + + def rename(attribute, aliaz) + Rename.new(self, attribute => aliaz) + end + + def insert(record) + Insertion.new(self, record) + end + + def delete + Deletion.new(self) + end + + JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do + def on(*predicates) + Join.new(join_sql, relation1, relation2, *predicates) + end + end + end + include Operations + + def to_sql(strategy = Sql::Select.new) + strategy.select [ + "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", + "FROM #{table_sql}", + (joins unless joins.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), + ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), + ("LIMIT #{limit.to_sql}" unless limit.blank?), + ("OFFSET #{offset.to_sql}" unless offset.blank?) + ].compact.join("\n") + end + alias_method :to_s, :to_sql + + protected + def connection + ActiveRecord::Base.connection + end + + def attributes; [] end + def selects; [] end + def orders; [] end + def inserts; [] end + def joins; nil end + def limit; nil end + def offset; nil end + def alias; nil end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index c4ba6ded887fa..2977804db14d1 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -1,38 +1,36 @@ module ActiveRelation - module Relations - class Rename < Compound - attr_reader :schmattribute, :rename - - def initialize(relation, renames) - @schmattribute, @rename = renames.shift - @relation = renames.empty?? relation : Rename.new(relation, renames) - end - - def ==(other) - relation == other.relation and schmattribute == other.schmattribute and self.rename == other.rename - end - - def attributes - relation.attributes.collect(&method(:substitute)) - end - - def qualify - Rename.new(relation.qualify, schmattribute.qualify => self.rename) - end - - protected - def attribute(name) - case - when name == self.rename then schmattribute.as(self.rename) - when relation[name] == schmattribute then nil - else relation[name] - end - end - - private - def substitute(a) - a == schmattribute ? a.as(self.rename) : a + class Rename < Compound + attr_reader :schmattribute, :rename + + def initialize(relation, renames) + @schmattribute, @rename = renames.shift + @relation = renames.empty?? relation : Rename.new(relation, renames) + end + + def ==(other) + relation == other.relation and schmattribute == other.schmattribute and self.rename == other.rename + end + + def attributes + relation.attributes.collect(&method(:substitute)) + end + + def qualify + Rename.new(relation.qualify, schmattribute.qualify => self.rename) + end + + protected + def attribute(name) + case + when name == self.rename then schmattribute.as(self.rename) + when relation[name] == schmattribute then nil + else relation[name] end end + + private + def substitute(a) + a == schmattribute ? a.as(self.rename) : a + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index e86dc627dbb46..3ecea059d5121 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -1,25 +1,23 @@ module ActiveRelation - module Relations - class Selection < Compound - attr_reader :predicate - - def initialize(relation, *predicates) - @predicate = predicates.shift - @relation = predicates.empty?? relation : Selection.new(relation, *predicates) - end - - def ==(other) - relation == other.relation and predicate == other.predicate - end - - def qualify - Selection.new(relation.qualify, predicate.qualify) - end - - protected - def selects - relation.send(:selects) + [predicate] - end + class Selection < Compound + attr_reader :predicate + + def initialize(relation, *predicates) + @predicate = predicates.shift + @relation = predicates.empty?? relation : Selection.new(relation, *predicates) + end + + def ==(other) + relation == other.relation and predicate == other.predicate + end + + def qualify + Selection.new(relation.qualify, predicate.qualify) + end + + protected + def selects + relation.send(:selects) + [predicate] end end end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index a370b4266d914..5220087318695 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -1,39 +1,37 @@ module ActiveRelation - module Relations - class Table < Base - attr_reader :name - - def initialize(name) - @name = name - end - - def attributes - attributes_by_name.values - end + class Table < Relation + attr_reader :name + + def initialize(name) + @name = name + end + + def attributes + attributes_by_name.values + end + + def qualify + Rename.new self, qualifications + end - def qualify - Rename.new self, qualifications - end + protected + def attribute(name) + attributes_by_name[name.to_s] + end - protected - def attribute(name) - attributes_by_name[name.to_s] - end - - def table_sql - "#{quote_table_name(name)}" - end - - private - def attributes_by_name - @attributes_by_name ||= connection.columns(name, "#{name} Columns").inject({}) do |attributes_by_name, column| - attributes_by_name.merge(column.name => Primitives::Attribute.new(self, column.name.to_sym)) - end - end - - def qualifications - attributes.zip(attributes.collect(&:qualified_name)).to_hash + def table_sql + "#{quote_table_name(name)}" + end + + private + def attributes_by_name + @attributes_by_name ||= connection.columns(name, "#{name} Columns").inject({}) do |attributes_by_name, column| + attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym)) end end + + def qualifications + attributes.zip(attributes.collect(&:qualified_name)).to_hash + end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index be607efd95f2d..a6878e4898bad 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -1,42 +1,44 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Predicates::Binary do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name1) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name2) - class ConcreteBinary < ActiveRelation::Predicates::Binary - def predicate_sql - "<=>" +module ActiveRelation + describe Binary do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute1 = Attribute.new(@relation1, :name1) + @attribute2 = Attribute.new(@relation2, :name2) + class ConcreteBinary < Binary + def predicate_sql + "<=>" + end end end - end - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute1) - end + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) + Binary.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute1) + end - it "obtains if the concrete type of the ActiveRelation::Predicates::Binarys are identical" do - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2).should_not == ConcreteBinary.new(@attribute1, @attribute2) + it "obtains if the concrete type of the Predicates::Binarys are identical" do + Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) + Binary.new(@attribute1, @attribute2).should_not == ConcreteBinary.new(@attribute1, @attribute2) + end end - end - describe '#qualify' do - it "distributes over the predicates and attributes" do - ConcreteBinary.new(@attribute1, @attribute2).qualify. \ - should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) + describe '#qualify' do + it "distributes over the predicates and attributes" do + ConcreteBinary.new(@attribute1, @attribute2).qualify. \ + should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) + end end - end - describe '#to_sql' do - it 'manufactures correct sql' do - ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" - `foo`.`name1` <=> `bar`.`name2` - """) + describe '#to_sql' do + it 'manufactures correct sql' do + ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" + `foo`.`name1` <=> `bar`.`name2` + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/equality_spec.rb b/spec/active_relation/predicates/equality_spec.rb index 9394e63835356..d23893e438e2f 100644 --- a/spec/active_relation/predicates/equality_spec.rb +++ b/spec/active_relation/predicates/equality_spec.rb @@ -1,28 +1,30 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Predicates::Equality do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) - end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute1) +module ActiveRelation + describe Equality do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute1 = Attribute.new(@relation1, :name) + @attribute2 = Attribute.new(@relation2, :name) end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) + Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) + end - it "obtains if the concrete type of the predicates are identical" do - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should_not == ActiveRelation::Predicates::Binary.new(@attribute1, @attribute2) - end + it "obtains if the concrete type of the predicates are identical" do + Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) + end - it "is commutative on the attributes" do - ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute2, @attribute1) + it "is commutative on the attributes" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) + end end - end - describe '#to_sql' do + describe '#to_sql' do + end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/match_spec.rb b/spec/active_relation/predicates/match_spec.rb index a01f4fb76b3ca..3d01ce105510e 100644 --- a/spec/active_relation/predicates/match_spec.rb +++ b/spec/active_relation/predicates/match_spec.rb @@ -1,16 +1,18 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Predicates::RelationInclusion do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute = @relation1[:baz] - end +module ActiveRelation + describe RelationInclusion do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute = @relation1[:baz] + end - describe ActiveRelation::Predicates::RelationInclusion, '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) + describe RelationInclusion, '==' do + it "obtains if attribute1 and attribute2 are identical" do + RelationInclusion.new(@attribute, @relation1).should == RelationInclusion.new(@attribute, @relation1) + RelationInclusion.new(@attribute, @relation1).should_not == RelationInclusion.new(@attribute, @relation2) + end end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/relation_inclusion_spec.rb b/spec/active_relation/predicates/relation_inclusion_spec.rb index de3dcf7747cf9..05039028eeb26 100644 --- a/spec/active_relation/predicates/relation_inclusion_spec.rb +++ b/spec/active_relation/predicates/relation_inclusion_spec.rb @@ -1,25 +1,27 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Predicates::RelationInclusion do - before do - foo = ActiveRelation::Relations::Table.new(:foo) - @relation1 = foo.project(foo[:id]) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute = @relation1[:id] - end +module ActiveRelation + describe RelationInclusion do + before do + foo = Table.new(:foo) + @relation1 = foo.project(foo[:id]) + @relation2 = Table.new(:bar) + @attribute = @relation1[:id] + end - describe ActiveRelation::Predicates::RelationInclusion, '==' do - it "obtains if attribute1 and attribute2 are identical" do - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1) - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).should_not == ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation2) + describe RelationInclusion, '==' do + it "obtains if attribute1 and attribute2 are identical" do + RelationInclusion.new(@attribute, @relation1).should == RelationInclusion.new(@attribute, @relation1) + RelationInclusion.new(@attribute, @relation1).should_not == RelationInclusion.new(@attribute, @relation2) + end end - end - describe ActiveRelation::Predicates::RelationInclusion, '#to_sql' do - it "manufactures subselect sql" do - ActiveRelation::Predicates::RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(""" - `foo`.`id` IN (SELECT `foo`.`id` FROM `foo`) - """) + describe RelationInclusion, '#to_sql' do + it "manufactures subselect sql" do + RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(""" + `foo`.`id` IN (SELECT `foo`.`id` FROM `foo`) + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/primitives/aggregation_spec.rb b/spec/active_relation/primitives/aggregation_spec.rb index 60bb4a6aa86d1..bdfa152bca698 100644 --- a/spec/active_relation/primitives/aggregation_spec.rb +++ b/spec/active_relation/primitives/aggregation_spec.rb @@ -1,25 +1,27 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Primitives::Aggregation do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - end +module ActiveRelation + describe Aggregation do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + end - describe '==' do - it 'obtains if the attribute and function sql are identical' do - @relation1[:id].sum.should == @relation1[:id].sum - @relation1[:id].sum.should_not == @relation1[:name].sum - @relation1[:id].sum.should_not == @relation1[:name].average - @relation1[:id].sum.should_not == @relation2[:id].sum + describe '==' do + it 'obtains if the attribute and function sql are identical' do + @relation1[:id].sum.should == @relation1[:id].sum + @relation1[:id].sum.should_not == @relation1[:name].sum + @relation1[:id].sum.should_not == @relation1[:name].average + @relation1[:id].sum.should_not == @relation2[:id].sum + end end - end - describe '#to_sql' do - it 'manufactures sql with an aggregation function' do - @relation1[:id].maximum.to_sql.should be_like(""" - MAX(`foo`.`id`) - """) + describe '#to_sql' do + it 'manufactures sql with an aggregation function' do + @relation1[:id].maximum.to_sql.should be_like(""" + MAX(`foo`.`id`) + """) + end end end -end +end \ No newline at end of file diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index f1aa404a34241..6078da08f3e1d 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -1,119 +1,119 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Primitives::Attribute do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - end - - describe '#as' do - it "manufactures an aliased attributed when provided a parameter" do - @relation1[:id].as(:alias).should == ActiveRelation::Primitives::Attribute.new(@relation1, :id, :alias) +module ActiveRelation + describe Attribute do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) end - end - describe '#qualified_name' do - it "manufactures an attribute name prefixed with the relation's name" do - @relation1[:id].qualified_name.should == 'foo.id' + describe '#as' do + it "manufactures an aliased attributed when provided a parameter" do + @relation1[:id].as(:alias).should == Attribute.new(@relation1, :id, :alias) + end end + + describe '#qualified_name' do + it "manufactures an attribute name prefixed with the relation's name" do + @relation1[:id].qualified_name.should == 'foo.id' + end - it "manufactures an attribute name prefixed with the relation's aliased name" do - @relation1.as(:bar)[:id].qualified_name.should == 'bar.id' + it "manufactures an attribute name prefixed with the relation's aliased name" do + @relation1.as(:bar)[:id].qualified_name.should == 'bar.id' + end end - end - describe '#qualify' do - it "manufactures an attribute aliased with that attributes qualified name" do - @relation1[:id].qualify.should == @relation1[:id].qualify + describe '#qualify' do + it "manufactures an attribute aliased with that attributes qualified name" do + @relation1[:id].qualify.should == @relation1[:id].qualify + end end - end - describe '==' do - it "obtains if the relation and attribute name are identical" do - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should == ActiveRelation::Primitives::Attribute.new(@relation1, :name) - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation1, :another_name) - ActiveRelation::Primitives::Attribute.new(@relation1, :name).should_not == ActiveRelation::Primitives::Attribute.new(@relation2, :name) + describe '==' do + it "obtains if the relation and attribute name are identical" do + Attribute.new(@relation1, :name).should == Attribute.new(@relation1, :name) + Attribute.new(@relation1, :name).should_not == Attribute.new(@relation1, :another_name) + Attribute.new(@relation1, :name).should_not == Attribute.new(@relation2, :name) + end end - end - describe 'predications' do - before do - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation2, :name) - end + describe 'predications' do + before do + @attribute1 = Attribute.new(@relation1, :name) + @attribute2 = Attribute.new(@relation2, :name) + end - describe '#equals' do - it "manufactures an equality predicate" do - @attribute1.equals(@attribute2).should == ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) + describe '#equals' do + it "manufactures an equality predicate" do + @attribute1.equals(@attribute2).should == Equality.new(@attribute1, @attribute2) + end end - end - describe '#less_than' do - it "manufactures a less-than predicate" do - @attribute1.less_than(@attribute2).should == ActiveRelation::Predicates::LessThan.new(@attribute1, @attribute2) + describe '#less_than' do + it "manufactures a less-than predicate" do + @attribute1.less_than(@attribute2).should == LessThan.new(@attribute1, @attribute2) + end end - end - describe '#less_than_or_equal_to' do - it "manufactures a less-than or equal-to predicate" do - @attribute1.less_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::LessThanOrEqualTo.new(@attribute1, @attribute2) + describe '#less_than_or_equal_to' do + it "manufactures a less-than or equal-to predicate" do + @attribute1.less_than_or_equal_to(@attribute2).should == LessThanOrEqualTo.new(@attribute1, @attribute2) + end end - end - describe '#greater_than' do - it "manufactures a greater-than predicate" do - @attribute1.greater_than(@attribute2).should == ActiveRelation::Predicates::GreaterThan.new(@attribute1, @attribute2) + describe '#greater_than' do + it "manufactures a greater-than predicate" do + @attribute1.greater_than(@attribute2).should == GreaterThan.new(@attribute1, @attribute2) + end end - end - describe '#greater_than_or_equal_to' do - it "manufactures a greater-than or equal to predicate" do - @attribute1.greater_than_or_equal_to(@attribute2).should == ActiveRelation::Predicates::GreaterThanOrEqualTo.new(@attribute1, @attribute2) + describe '#greater_than_or_equal_to' do + it "manufactures a greater-than or equal to predicate" do + @attribute1.greater_than_or_equal_to(@attribute2).should == GreaterThanOrEqualTo.new(@attribute1, @attribute2) + end end - end - describe '#matches' do - it "manufactures a match predicate" do - @attribute1.matches(/.*/).should == ActiveRelation::Predicates::Match.new(@attribute1, @attribute2) + describe '#matches' do + it "manufactures a match predicate" do + @attribute1.matches(/.*/).should == Match.new(@attribute1, @attribute2) + end end end - end - describe 'aggregations' do - before do - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - end - - describe '#count' do - it "manufactures a count aggregation" do - @attribute1.count.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "COUNT") + describe 'aggregations' do + before do + @attribute1 = Attribute.new(@relation1, :name) end - end - describe '#sum' do - it "manufactures a sum aggregation" do - @attribute1.sum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "SUM") + describe '#count' do + it "manufactures a count aggregation" do + @attribute1.count.should == Aggregation.new(@attribute1, "COUNT") + end end - end - describe '#maximum' do - it "manufactures a maximum aggregation" do - @attribute1.maximum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MAX") + describe '#sum' do + it "manufactures a sum aggregation" do + @attribute1.sum.should == Aggregation.new(@attribute1, "SUM") + end end - end - describe '#minimum' do - it "manufactures a minimum aggregation" do - @attribute1.minimum.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "MIN") + describe '#maximum' do + it "manufactures a maximum aggregation" do + @attribute1.maximum.should == Aggregation.new(@attribute1, "MAX") + end end - end - describe '#average' do - it "manufactures an average aggregation" do - @attribute1.average.should == ActiveRelation::Primitives::Aggregation.new(@attribute1, "AVG") + describe '#minimum' do + it "manufactures a minimum aggregation" do + @attribute1.minimum.should == Aggregation.new(@attribute1, "MIN") + end end - end - + describe '#average' do + it "manufactures an average aggregation" do + @attribute1.average.should == Aggregation.new(@attribute1, "AVG") + end + end + end end -end +end \ No newline at end of file diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb index 6f25df3ddb307..418af7fe662ef 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/relations/alias_spec.rb @@ -1,36 +1,38 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Alias do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - @alias_relation = @relation.as(:foo) - end +module ActiveRelation + describe Alias do + before do + @relation = Table.new(:users) + @alias_relation = @relation.as(:foo) + end - describe '#name' do - it 'returns the alias' do - @alias_relation.name.should == :foo + describe '#name' do + it 'returns the alias' do + @alias_relation.name.should == :foo + end end - end - describe '#attributes' do - it 'manufactures sql deleting a table relation' do - @alias_relation.attributes.should == @relation.attributes.collect { |a| ActiveRelation::Primitives::Attribute.new(@alias_relation, a.name) } + describe '#attributes' do + it 'manufactures sql deleting a table relation' do + @alias_relation.attributes.should == @relation.attributes.collect { |a| Attribute.new(@alias_relation, a.name) } + end end - end - describe '[]' do - it 'manufactures attributes associated with the aliased relation' do - @alias_relation[:id].relation.should == @alias_relation - @alias_relation[:does_not_exist].should be_nil + describe '[]' do + it 'manufactures attributes associated with the aliased relation' do + @alias_relation[:id].relation.should == @alias_relation + @alias_relation[:does_not_exist].should be_nil + end end - end - describe '#to_sql' do - it "manufactures an aliased select query" do - @alias_relation.to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `users` AS `foo` - """) + describe '#to_sql' do + it "manufactures an aliased select query" do + @alias_relation.to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `users` AS `foo` + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/base_spec.rb b/spec/active_relation/relations/base_spec.rb deleted file mode 100644 index 18063757df4ba..0000000000000 --- a/spec/active_relation/relations/base_spec.rb +++ /dev/null @@ -1,102 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe ActiveRelation::Relations::Base do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = ActiveRelation::Primitives::Attribute.new(@relation1, :id) - @attribute2 = ActiveRelation::Primitives::Attribute.new(@relation1, :name) - end - - describe '[]' do - it "manufactures an attribute when given a symbol" do - @relation1[:id].should == ActiveRelation::Primitives::Attribute.new(@relation1, :id) - end - - it "manufactures a range relation when given a range" do - @relation1[1..2].should == ActiveRelation::Relations::Range.new(@relation1, 1..2) - end - end - - describe '#include?' do - it "manufactures an inclusion predicate" do - @relation1.include?(@attribute1).should be_kind_of(ActiveRelation::Predicates::RelationInclusion) - end - end - - describe 'read operations' do - describe 'joins' do - before do - @predicate = @relation1[:id].equals(@relation2[:id]) - end - - describe '#join' do - it "manufactures an inner join operation between those two relations" do - @relation1.join(@relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) - end - end - - describe '#outer_join' do - it "manufactures a left outer join operation between those two relations" do - @relation1.outer_join(@relation2).on(@predicate).should == ActiveRelation::Relations::Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) - end - end - end - - describe '#project' do - it "collapses identical projections" do - pending - end - - it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) - end - end - - describe '#as' do - it "manufactures an alias relation" do - @relation1.as(:thucydides).should == ActiveRelation::Relations::Alias.new(@relation1, :thucydides) - end - end - - describe '#rename' do - it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should == ActiveRelation::Relations::Rename.new(@relation1, @attribute1 => :foo) - end - end - - describe '#select' do - before do - @predicate = ActiveRelation::Predicates::Equality.new(@attribute1, @attribute2) - end - - it "manufactures a selection relation" do - @relation1.select(@predicate).should == ActiveRelation::Relations::Selection.new(@relation1, @predicate) - end - - it "accepts arbitrary strings" do - @relation1.select("arbitrary").should == ActiveRelation::Relations::Selection.new(@relation1, "arbitrary") - end - end - - describe '#order' do - it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should be_kind_of(ActiveRelation::Relations::Order) - end - end - end - - describe 'write operations' do - describe '#delete' do - it 'manufactures a deletion relation' do - @relation1.delete.should be_kind_of(ActiveRelation::Relations::Deletion) - end - end - - describe '#insert' do - it 'manufactures an insertion relation' do - @relation1.insert(record = {:id => 1}).should be_kind_of(ActiveRelation::Relations::Insertion) - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/relations/compound_spec.rb index f383ff4dfd8ed..6309547c7d549 100644 --- a/spec/active_relation/relations/compound_spec.rb +++ b/spec/active_relation/relations/compound_spec.rb @@ -1,12 +1,14 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Compound do - before do - @relation = ActiveRelation::Relations::Table.new(:users) +module ActiveRelation + describe Compound do + before do + @relation = Table.new(:users) - class ConcreteCompound < ActiveRelation::Relations::Compound - def initialize(relation) - @relation = relation + class ConcreteCompound < Compound + def initialize(relation) + @relation = relation + end end end end diff --git a/spec/active_relation/relations/deletion_spec.rb b/spec/active_relation/relations/deletion_spec.rb index ed201ac0d980c..64b75d060083f 100644 --- a/spec/active_relation/relations/deletion_spec.rb +++ b/spec/active_relation/relations/deletion_spec.rb @@ -1,24 +1,26 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Deletion do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql deleting a table relation' do - ActiveRelation::Relations::Deletion.new(@relation).to_sql.should be_like(""" - DELETE - FROM `users` - """) +module ActiveRelation + describe Deletion do + before do + @relation = Table.new(:users) end + + describe '#to_sql' do + it 'manufactures sql deleting a table relation' do + Deletion.new(@relation).to_sql.should be_like(""" + DELETE + FROM `users` + """) + end - it 'manufactures sql deleting a selection relation' do - ActiveRelation::Relations::Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(""" - DELETE - FROM `users` - WHERE `users`.`id` = 1 - """) + it 'manufactures sql deleting a selection relation' do + Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(""" + DELETE + FROM `users` + WHERE `users`.`id` = 1 + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/insertion_spec.rb b/spec/active_relation/relations/insertion_spec.rb index da39edf773346..f16ab8cc23cf9 100644 --- a/spec/active_relation/relations/insertion_spec.rb +++ b/spec/active_relation/relations/insertion_spec.rb @@ -1,26 +1,28 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Insertion do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql inserting the data for one item' do - ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" - INSERT - INTO `users` - (`users`.`name`) VALUES ('nick') - """) +module ActiveRelation + describe Insertion do + before do + @relation = Table.new(:users) end + + describe '#to_sql' do + it 'manufactures sql inserting the data for one item' do + Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick') + """) + end - it 'manufactures sql inserting the data for multiple items' do - nested_insertion = ActiveRelation::Relations::Insertion.new(@relation, @relation[:name] => "cobra") - ActiveRelation::Relations::Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" - INSERT - INTO `users` - (`users`.`name`) VALUES ('cobra'), ('commander') - """) + it 'manufactures sql inserting the data for multiple items' do + nested_insertion = Insertion.new(@relation, @relation[:name] => "cobra") + Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" + INSERT + INTO `users` + (`users`.`name`) VALUES ('cobra'), ('commander') + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 2a84a92b70df2..25c505e371979 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -1,43 +1,45 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Join do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @predicate = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:id]) - end - - describe '==' do - it 'obtains if the two relations and the predicate are identical' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate) - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation1, @predicate) +module ActiveRelation + describe Join do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @predicate = Equality.new(@relation1[:id], @relation2[:id]) end - it 'is commutative on the relations' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation2, @relation1, @predicate) - end - end + describe '==' do + it 'obtains if the two relations and the predicate are identical' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate) + Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @relation1, @predicate) + end - describe '#qualify' do - it 'distributes over the relations and predicates' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ - should == ActiveRelation::Relations::Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) + it 'is commutative on the relations' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation2, @relation1, @predicate) + end end - end - describe '#to_sql' do - before do - @relation1 = @relation1.select(@relation1[:id].equals(1)) + describe '#qualify' do + it 'distributes over the relations and predicates' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ + should == Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) + end end + + describe '#to_sql' do + before do + @relation1 = @relation1.select(@relation1[:id].equals(1)) + end - it 'manufactures sql joining the two tables on the predicate, merging the selects' do - ActiveRelation::Relations::Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` - FROM `foo` - INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` - WHERE - `foo`.`id` = 1 - """) + it 'manufactures sql joining the two tables on the predicate, merging the selects' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` + FROM `foo` + INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` + WHERE + `foo`.`id` = 1 + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/order_spec.rb b/spec/active_relation/relations/order_spec.rb index edf2faf4559de..204558daec8ad 100644 --- a/spec/active_relation/relations/order_spec.rb +++ b/spec/active_relation/relations/order_spec.rb @@ -1,28 +1,30 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Order do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] - end +module ActiveRelation + describe Order do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end - describe '#qualify' do - it "distributes over the relation and attributes" do - ActiveRelation::Relations::Order.new(@relation1, @attribute1).qualify. \ - should == ActiveRelation::Relations::Order.new(@relation1.qualify, @attribute1.qualify) + describe '#qualify' do + it "distributes over the relation and attributes" do + Order.new(@relation1, @attribute1).qualify. \ + should == Order.new(@relation1.qualify, @attribute1.qualify) + end end - end - describe '#to_sql' do - it "manufactures sql with an order clause" do - ActiveRelation::Relations::Order.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - ORDER BY `foo`.`id` - """) + describe '#to_sql' do + it "manufactures sql with an order clause" do + Order.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + ORDER BY `foo`.`id` + """) + end end end - -end \ No newline at end of file +end + \ No newline at end of file diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb index 6ffdeb8e09d4b..8d6a093af242b 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/relations/projection_spec.rb @@ -1,34 +1,36 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Projection do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] - end +module ActiveRelation + describe Projection do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end - describe '==' do - it "obtains if the relations and attributes are identical" do - ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2).should == ActiveRelation::Relations::Projection.new(@relation1, @attribute1, @attribute2) - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation2, @attribute1) - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).should_not == ActiveRelation::Relations::Projection.new(@relation1, @attribute2) + describe '==' do + it "obtains if the relations and attributes are identical" do + Projection.new(@relation1, @attribute1, @attribute2).should == Projection.new(@relation1, @attribute1, @attribute2) + Projection.new(@relation1, @attribute1).should_not == Projection.new(@relation2, @attribute1) + Projection.new(@relation1, @attribute1).should_not == Projection.new(@relation1, @attribute2) + end end - end - describe '#qualify' do - it "distributes over the relation and attributes" do - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).qualify. \ - should == ActiveRelation::Relations::Projection.new(@relation1.qualify, @attribute1.qualify) + describe '#qualify' do + it "distributes over the relation and attributes" do + Projection.new(@relation1, @attribute1).qualify. \ + should == Projection.new(@relation1.qualify, @attribute1.qualify) + end end - end - describe '#to_sql' do - it "manufactures sql with a limited select clause" do - ActiveRelation::Relations::Projection.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`id` - FROM `foo` - """) + describe '#to_sql' do + it "manufactures sql with a limited select clause" do + Projection.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`id` + FROM `foo` + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/relations/range_spec.rb index d4107259aac2b..f417626feda43 100644 --- a/spec/active_relation/relations/range_spec.rb +++ b/spec/active_relation/relations/range_spec.rb @@ -1,30 +1,31 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Range do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @range1 = 1..2 - @range2 = 4..9 - end +module ActiveRelation + describe Range do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @range1 = 1..2 + @range2 = 4..9 + end - describe '#qualify' do - it "distributes over the relation and attributes" do - pending + describe '#qualify' do + it "distributes over the relation and attributes" do + pending + end end - end - describe '#to_sql' do - it "manufactures sql with limit and offset" do - range_size = @range2.last - @range2.first + 1 - range_start = @range2.first - ActiveRelation::Relations::Range.new(@relation1, @range2).to_s.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - LIMIT #{range_size} - OFFSET #{range_start} - """) + describe '#to_sql' do + it "manufactures sql with limit and offset" do + range_size = @range2.last - @range2.first + 1 + range_start = @range2.first + Range.new(@relation1, @range2).to_s.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + LIMIT #{range_size} + OFFSET #{range_start} + """) + end end end - end \ No newline at end of file diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb new file mode 100644 index 0000000000000..72b7d14389c6f --- /dev/null +++ b/spec/active_relation/relations/relation_spec.rb @@ -0,0 +1,104 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +module ActiveRelation + describe Relation do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute1 = Attribute.new(@relation1, :id) + @attribute2 = Attribute.new(@relation1, :name) + end + + describe '[]' do + it "manufactures an attribute when given a symbol" do + @relation1[:id].should == Attribute.new(@relation1, :id) + end + + it "manufactures a range relation when given a range" do + @relation1[1..2].should == Range.new(@relation1, 1..2) + end + end + + describe '#include?' do + it "manufactures an inclusion predicate" do + @relation1.include?(@attribute1).should be_kind_of(RelationInclusion) + end + end + + describe 'read operations' do + describe 'joins' do + before do + @predicate = @relation1[:id].equals(@relation2[:id]) + end + + describe '#join' do + it "manufactures an inner join operation between those two relations" do + @relation1.join(@relation2).on(@predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate) + end + end + + describe '#outer_join' do + it "manufactures a left outer join operation between those two relations" do + @relation1.outer_join(@relation2).on(@predicate).should == Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) + end + end + end + + describe '#project' do + it "collapses identical projections" do + pending + end + + it "manufactures a projection relation" do + @relation1.project(@attribute1, @attribute2).should == Projection.new(@relation1, @attribute1, @attribute2) + end + end + + describe '#as' do + it "manufactures an alias relation" do + @relation1.as(:thucydides).should == Alias.new(@relation1, :thucydides) + end + end + + describe '#rename' do + it "manufactures a rename relation" do + @relation1.rename(@attribute1, :foo).should == Rename.new(@relation1, @attribute1 => :foo) + end + end + + describe '#select' do + before do + @predicate = Equality.new(@attribute1, @attribute2) + end + + it "manufactures a selection relation" do + @relation1.select(@predicate).should == Selection.new(@relation1, @predicate) + end + + it "accepts arbitrary strings" do + @relation1.select("arbitrary").should == Selection.new(@relation1, "arbitrary") + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation1.order(@attribute1, @attribute2).should be_kind_of(Order) + end + end + end + + describe 'write operations' do + describe '#delete' do + it 'manufactures a deletion relation' do + @relation1.delete.should be_kind_of(Deletion) + end + end + + describe '#insert' do + it 'manufactures an insertion relation' do + @relation1.insert(record = {:id => 1}).should be_kind_of(Insertion) + end + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index bdc5c97492733..3f8d5e3dbd190 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -1,61 +1,63 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Rename do - before do - @relation = ActiveRelation::Relations::Table.new(:foo) - @renamed_relation = ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid) - end - - describe '#initialize' do - it "manufactures nested rename relations if multiple renames are provided" do - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ - should == ActiveRelation::Relations::Rename.new(ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) +module ActiveRelation + describe Rename do + before do + @relation = Table.new(:foo) + @renamed_relation = Rename.new(@relation, @relation[:id] => :schmid) end - it "raises an exception if the rename provided is already used" do - pending + describe '#initialize' do + it "manufactures nested rename relations if multiple renames are provided" do + Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ + should == Rename.new(Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) + end + + it "raises an exception if the rename provided is already used" do + pending + end end - end - describe '==' do - it "obtains if the relation, attribute, and rename are identical" do - pending + describe '==' do + it "obtains if the relation, attribute, and rename are identical" do + pending + end end - end - describe '#attributes' do - it "manufactures a list of attributes with the renamed attribute renameed" do - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).attributes.should == - (@relation.attributes - [@relation[:id]]) + [@relation[:id].as(:schmid)] + describe '#attributes' do + it "manufactures a list of attributes with the renamed attribute renameed" do + Rename.new(@relation, @relation[:id] => :schmid).attributes.should == + (@relation.attributes - [@relation[:id]]) + [@relation[:id].as(:schmid)] + end end - end - describe '[]' do - it 'indexes attributes by rename' do - @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation[:id].as(:schmid) + describe '[]' do + it 'indexes attributes by rename' do + @renamed_relation[:id].should be_nil + @renamed_relation[:schmid].should == @relation[:id].as(:schmid) + end end - end - describe '#schmattribute' do - it "should be renamed" do - pending + describe '#schmattribute' do + it "should be renamed" do + pending + end end - end - describe '#qualify' do - it "distributes over the relation and renames" do - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => :schmid).qualify. \ - should == ActiveRelation::Relations::Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) + describe '#qualify' do + it "distributes over the relation and renames" do + Rename.new(@relation, @relation[:id] => :schmid).qualify. \ + should == Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) + end end - end - describe '#to_sql' do - it 'manufactures sql renameing the attribute' do - @renamed_relation.to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` AS 'schmid' - FROM `foo` - """) + describe '#to_sql' do + it 'manufactures sql renameing the attribute' do + @renamed_relation.to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` AS 'schmid' + FROM `foo` + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/selection_spec.rb b/spec/active_relation/relations/selection_spec.rb index 90dc3169b6ca5..95d9e68625682 100644 --- a/spec/active_relation/relations/selection_spec.rb +++ b/spec/active_relation/relations/selection_spec.rb @@ -1,42 +1,44 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Selection do - before do - @relation1 = ActiveRelation::Relations::Table.new(:foo) - @relation2 = ActiveRelation::Relations::Table.new(:bar) - @predicate1 = ActiveRelation::Predicates::Equality.new(@relation1[:id], @relation2[:foo_id]) - @predicate2 = ActiveRelation::Predicates::LessThan.new(@relation1[:age], 2) - end - - describe '#initialize' do - it "manufactures nested selection relations if multiple predicates are provided" do - ActiveRelation::Relations::Selection.new(@relation1, @predicate1, @predicate2). \ - should == ActiveRelation::Relations::Selection.new(ActiveRelation::Relations::Selection.new(@relation1, @predicate2), @predicate1) +module ActiveRelation + describe Selection do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @predicate1 = Equality.new(@relation1[:id], @relation2[:foo_id]) + @predicate2 = LessThan.new(@relation1[:age], 2) end - end - describe '#qualify' do - it "distributes over the relation and predicates" do - ActiveRelation::Relations::Selection.new(@relation1, @predicate1).qualify. \ - should == ActiveRelation::Relations::Selection.new(@relation1.qualify, @predicate1.qualify) + describe '#initialize' do + it "manufactures nested selection relations if multiple predicates are provided" do + Selection.new(@relation1, @predicate1, @predicate2). \ + should == Selection.new(Selection.new(@relation1, @predicate2), @predicate1) + end end - end - describe '#to_sql' do - it "manufactures sql with where clause conditions" do - ActiveRelation::Relations::Selection.new(@relation1, @predicate1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - WHERE `foo`.`id` = `bar`.`foo_id` - """) + describe '#qualify' do + it "distributes over the relation and predicates" do + Selection.new(@relation1, @predicate1).qualify. \ + should == Selection.new(@relation1.qualify, @predicate1.qualify) + end end + + describe '#to_sql' do + it "manufactures sql with where clause conditions" do + Selection.new(@relation1, @predicate1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE `foo`.`id` = `bar`.`foo_id` + """) + end - it "allows arbitrary sql" do - ActiveRelation::Relations::Selection.new(@relation1, "asdf").to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - WHERE asdf - """) + it "allows arbitrary sql" do + Selection.new(@relation1, "asdf").to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + WHERE asdf + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 1418ac203f0c4..ec6e6e10bd20a 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -1,30 +1,32 @@ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') -describe ActiveRelation::Relations::Table do - before do - @relation = ActiveRelation::Relations::Table.new(:users) - end +module ActiveRelation + describe Table do + before do + @relation = Table.new(:users) + end - describe '#to_sql' do - it "manufactures a simple select query" do - @relation.to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id` - FROM `users` - """) + describe '#to_sql' do + it "manufactures a simple select query" do + @relation.to_sql.should be_like(""" + SELECT `users`.`name`, `users`.`id` + FROM `users` + """) + end end - end - describe '#attributes' do - it 'manufactures attributes corresponding to columns in the table' do - pending + describe '#attributes' do + it 'manufactures attributes corresponding to columns in the table' do + pending + end end - end - describe '#qualify' do - it 'manufactures a rename relation with all attribute names qualified' do - @relation.qualify.should == ActiveRelation::Relations::Rename.new( - ActiveRelation::Relations::Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' - ) + describe '#qualify' do + it 'manufactures a rename relation with all attribute names qualified' do + @relation.qualify.should == Rename.new( + Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' + ) + end end end end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e799aed3392fd..ab9a14f3bda96 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,7 +9,7 @@ 'sql_algebra_test' => { :adapter => 'mysql', :username => 'root', - :password => 'password', + :password => '', :encoding => 'utf8', :database => 'sql_algebra_test', }, @@ -26,8 +26,5 @@ def shift Spec::Runner.configure do |config| config.include(BeLikeMatcher) - config.include(ActiveRelation::Relations) - config.include(ActiveRelation::Primitives) - config.include(ActiveRelation::Predicates) config.mock_with :rr end \ No newline at end of file From 124b104ae82aad8687d9f266de086d343b2b037c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 14 Jan 2008 11:09:46 -0500 Subject: [PATCH 0043/1492] Add rake task for coverage --- .gitignore | 1 + Rakefile | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000..22f348a1650dc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +coverage/* \ No newline at end of file diff --git a/Rakefile b/Rakefile index 2557babbc03cc..e45ade4f7df70 100644 --- a/Rakefile +++ b/Rakefile @@ -6,5 +6,11 @@ Spec::Rake::SpecTask.new do |t| t.spec_files = FileList['spec/**/*_spec.rb'] end +Spec::Rake::SpecTask.new(:coverage) do |t| + t.spec_files = FileList['spec/**/*_spec.rb'] + t.rcov = true + t.rcov_opts = ['-x', 'spec,gems'] +end + desc "Default task is to run specs" task :default => :spec \ No newline at end of file From b5a2057fcd5dfcac3682a565f2ba15281f5dcbb2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 14 Jan 2008 11:41:31 -0500 Subject: [PATCH 0044/1492] Removed dupe spec --- spec/active_relation/predicates/match_spec.rb | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 spec/active_relation/predicates/match_spec.rb diff --git a/spec/active_relation/predicates/match_spec.rb b/spec/active_relation/predicates/match_spec.rb deleted file mode 100644 index 3d01ce105510e..0000000000000 --- a/spec/active_relation/predicates/match_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -module ActiveRelation - describe RelationInclusion do - before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute = @relation1[:baz] - end - - describe RelationInclusion, '==' do - it "obtains if attribute1 and attribute2 are identical" do - RelationInclusion.new(@attribute, @relation1).should == RelationInclusion.new(@attribute, @relation1) - RelationInclusion.new(@attribute, @relation1).should_not == RelationInclusion.new(@attribute, @relation2) - end - end - end -end \ No newline at end of file From b47ac80a17d7a74e1b5deac0e63a72960a4da453 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 16 Jan 2008 22:55:06 -0800 Subject: [PATCH 0045/1492] adding grouping functionality; added some dummy code ("Schmoin") for experimenting with aggregate joins. need to resolve the ambiguity in the #as operator between (SELECT * FROM foo AS bar) vs. (SELECT * FROM foo) AS bar --- lib/active_relation/primitives/aggregation.rb | 4 ++ lib/active_relation/primitives/attribute.rb | 21 ++++++--- lib/active_relation/relations.rb | 2 + lib/active_relation/relations/alias.rb | 9 +--- lib/active_relation/relations/compound.rb | 3 +- lib/active_relation/relations/group.rb | 17 ++++++++ lib/active_relation/relations/order.rb | 2 +- lib/active_relation/relations/relation.rb | 6 +++ lib/active_relation/relations/schmoin.rb | 43 +++++++++++++++++++ .../primitives/aggregation_spec.rb | 15 +++++-- .../primitives/attribute_spec.rb | 6 +++ spec/active_relation/relations/group_spec.rb | 29 +++++++++++++ .../relations/relation_spec.rb | 8 +++- .../active_relation/relations/schmoin_spec.rb | 24 +++++++++++ spec/spec_helper.rb | 2 +- 15 files changed, 169 insertions(+), 22 deletions(-) create mode 100644 lib/active_relation/relations/group.rb create mode 100644 lib/active_relation/relations/schmoin.rb create mode 100644 spec/active_relation/relations/group_spec.rb create mode 100644 spec/active_relation/relations/schmoin_spec.rb diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index 48f8946835ea2..26348fb35e9bc 100644 --- a/lib/active_relation/primitives/aggregation.rb +++ b/lib/active_relation/primitives/aggregation.rb @@ -6,6 +6,10 @@ def initialize(attribute, function_sql) @attribute, @function_sql = attribute, function_sql end + def substitute(new_relation) + Aggregation.new(attribute.substitute(new_relation), function_sql) + end + def to_sql(strategy = nil) "#{function_sql}(#{attribute.to_sql})" end diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 90bbe8012bcb4..eb167b1a6645b 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -6,18 +6,25 @@ def initialize(relation, name, aliaz = nil) @relation, @name, @alias = relation, name, aliaz end - def as(aliaz = nil) - Attribute.new(relation, name, aliaz) - end + module Transformations + def as(aliaz = nil) + Attribute.new(relation, name, aliaz) + end + + def substitute(new_relation) + Attribute.new(new_relation, name, @alias) + end + def qualify + self.as(qualified_name) + end + end + include Transformations + def qualified_name "#{relation.name}.#{name}" end - def qualify - self.as(qualified_name) - end - def ==(other) relation == other.relation and name == other.name and @alias == other.alias end diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 9ae8f16524b7e..c9b9de93b207b 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -2,6 +2,8 @@ require 'active_relation/relations/compound' require 'active_relation/relations/table' require 'active_relation/relations/join' +require 'active_relation/relations/schmoin' +require 'active_relation/relations/group' require 'active_relation/relations/projection' require 'active_relation/relations/selection' require 'active_relation/relations/order' diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 63a92ccba1467..f40e51475e893 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -8,7 +8,7 @@ def initialize(relation, aliaz) end def attributes - relation.attributes.collect(&method(:substitute)) + relation.attributes.collect { |attribute| attribute.substitute(self) } end def ==(other) @@ -22,13 +22,8 @@ def table_sql def attribute(name) if unaliased_attribute = relation[name] - substitute(unaliased_attribute) + unaliased_attribute.substitute(self) end end - - private - def substitute(attribute) - Attribute.new(self, attribute.name, attribute.alias) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index d6da8eb8fa37f..bbc7ff1baebf1 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,6 +2,7 @@ module ActiveRelation class Compound < Relation attr_reader :relation - delegate :attributes, :attribute, :joins, :selects, :orders, :table_sql, :inserts, :limit, :offset, :to => :relation + delegate :attributes, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, + :to => :relation end end \ No newline at end of file diff --git a/lib/active_relation/relations/group.rb b/lib/active_relation/relations/group.rb new file mode 100644 index 0000000000000..bc363970c7bf8 --- /dev/null +++ b/lib/active_relation/relations/group.rb @@ -0,0 +1,17 @@ +module ActiveRelation + class Group < Compound + attr_reader :groupings + + def initialize(relation, *groupings) + @relation, @groupings = relation, groupings + end + + def ==(other) + relation == other.relation and groupings == other.groupings + end + + def qualify + Group.new(relation.qualify, *groupings.collect(&:qualify)) + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index d5c2a54cd181c..688207f7a9afd 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -11,7 +11,7 @@ def ==(other) end def qualify - Order.new(relation.qualify, *orders.collect { |o| o.qualify }) + Order.new(relation.qualify, *orders.collect(&:qualify)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 663450e69c50c..18ba5491b1998 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -64,6 +64,10 @@ def insert(record) def delete Deletion.new(self) end + + def group(*attributes) + Group.new(self, *attributes) + end JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do def on(*predicates) @@ -80,6 +84,7 @@ def to_sql(strategy = Sql::Select.new) (joins unless joins.blank?), ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), + ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), ("OFFSET #{offset.to_sql}" unless offset.blank?) ].compact.join("\n") @@ -95,6 +100,7 @@ def attributes; [] end def selects; [] end def orders; [] end def inserts; [] end + def groupings; [] end def joins; nil end def limit; nil end def offset; nil end diff --git a/lib/active_relation/relations/schmoin.rb b/lib/active_relation/relations/schmoin.rb new file mode 100644 index 0000000000000..398cfb7b2883e --- /dev/null +++ b/lib/active_relation/relations/schmoin.rb @@ -0,0 +1,43 @@ +module ActiveRelation + class Schmoin < Relation + attr_reader :join_sql, :relation1, :relation2, :predicates + + def initialize(join_sql, relation1, relation2, *predicates) + @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + end + + def ==(other) + predicates == other.predicates and + ((relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2)) + end + + def qualify + Schmoin.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + end + + protected + def joins + [relation1.joins, relation2.joins, join].compact.join(" ") + end + + def selects + relation1.send(:selects) + relation2.send(:selects) + end + + def attributes + relation1.attributes + relation2.attributes + end + + def attribute(name) + relation1[name] || relation2[name] + end + + delegate :table_sql, :to => :relation1 + + private + def join + "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" + end + end +end \ No newline at end of file diff --git a/spec/active_relation/primitives/aggregation_spec.rb b/spec/active_relation/primitives/aggregation_spec.rb index bdfa152bca698..fbd846ffed3e6 100644 --- a/spec/active_relation/primitives/aggregation_spec.rb +++ b/spec/active_relation/primitives/aggregation_spec.rb @@ -9,10 +9,17 @@ module ActiveRelation describe '==' do it 'obtains if the attribute and function sql are identical' do - @relation1[:id].sum.should == @relation1[:id].sum - @relation1[:id].sum.should_not == @relation1[:name].sum - @relation1[:id].sum.should_not == @relation1[:name].average - @relation1[:id].sum.should_not == @relation2[:id].sum + Aggregation.new(@relation1[:id], "SUM").should == Aggregation.new(@relation1[:id], "SUM") + Aggregation.new(@relation1[:id], "SUM").should_not == Aggregation.new(@relation1[:name], "SUM") + Aggregation.new(@relation1[:id], "SUM").should_not == Aggregation.new(@relation1[:name], "SUM") + Aggregation.new(@relation1[:id], "SUM").should_not == Aggregation.new(@relation2[:id], "SUM") + end + end + + describe '#substitute' do + it "distributes over the attribute" do + Aggregation.new(@relation1[:id], "SUM").substitute(@relation2). \ + should == Aggregation.new(@relation1[:id].substitute(@relation2), "SUM") end end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 6078da08f3e1d..543217b9cf94f 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -12,6 +12,12 @@ module ActiveRelation @relation1[:id].as(:alias).should == Attribute.new(@relation1, :id, :alias) end end + + describe '#substitute' do + it "manufactures an attribute with the relation substituted" do + @relation1[:id].substitute(@relation2).should == Attribute.new(@relation2, :id) + end + end describe '#qualified_name' do it "manufactures an attribute name prefixed with the relation's name" do diff --git a/spec/active_relation/relations/group_spec.rb b/spec/active_relation/relations/group_spec.rb new file mode 100644 index 0000000000000..256d7dde458e4 --- /dev/null +++ b/spec/active_relation/relations/group_spec.rb @@ -0,0 +1,29 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +module ActiveRelation + describe Group do + before do + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] + end + + describe '#qualify' do + it "distributes over the relation and attributes" do + Group.new(@relation1, @attribute1).qualify. \ + should == Group.new(@relation1.qualify, @attribute1.qualify) + end + end + + describe '#to_sql' do + it "manufactures sql with an order clause" do + Group.new(@relation1, @attribute1).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id` + FROM `foo` + GROUP BY `foo`.`id` + """) + end + end + end +end diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index 72b7d14389c6f..1b4ab785b7ba5 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -82,7 +82,13 @@ module ActiveRelation describe '#order' do it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should be_kind_of(Order) + @relation1.order(@attribute1, @attribute2).should == Order.new(@relation1, @attribute1, @attribute2) + end + end + + describe '#group' do + it 'manufactures a group relation' do + @relation1.group(@attribute1).should == Group.new(@relation1, @attribute1) end end end diff --git a/spec/active_relation/relations/schmoin_spec.rb b/spec/active_relation/relations/schmoin_spec.rb new file mode 100644 index 0000000000000..14e583afab164 --- /dev/null +++ b/spec/active_relation/relations/schmoin_spec.rb @@ -0,0 +1,24 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +module ActiveRelation + describe Schmoin do + before do + @relation = Table.new(:users) + photos = Table.new(:photos) + @aggregate_relation = photos.project(photos[:user_id], photos[:id].count).group(photos[:user_id]).as(:photo_count) + @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) + end + + describe '#to_sql' do + it 'manufactures sql joining the two tables on the predicate, merging the selects' do + pending + Schmoin.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" + SELECT `users`.`name` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, count(`photos`.`id`) FROM `photos`) AS `photo_count` + ON `photo_count`.`user_id` = `users`.`id` + """) + end + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ab9a14f3bda96..8f5d76370ce27 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,7 +9,7 @@ 'sql_algebra_test' => { :adapter => 'mysql', :username => 'root', - :password => '', + :password => 'password', :encoding => 'utf8', :database => 'sql_algebra_test', }, From d62ace142ce873c72eb916f5a14aa33a67ecfb86 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 21 Jan 2008 18:22:55 -0800 Subject: [PATCH 0046/1492] completed initial functionality for joining with aggregation (the meaning of which is joining on a subselect/derived table); the big change is the introduction of a #projections protected method; this is a private version of #attributes which preserves implementation information (e.g., the name of the function called) --- lib/active_relation/primitives/aggregation.rb | 26 ++++++++--- lib/active_relation/primitives/attribute.rb | 6 ++- lib/active_relation/relations/alias.rb | 4 -- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/join.rb | 14 +++--- lib/active_relation/relations/projection.rb | 12 ++--- lib/active_relation/relations/relation.rb | 10 +++-- lib/active_relation/relations/rename.rb | 28 ++++++------ lib/active_relation/relations/schmoin.rb | 12 ++--- lib/active_relation/relations/table.rb | 2 + lib/active_relation/sql.rb | 14 ++++-- .../primitives/aggregation_spec.rb | 38 +++++++++++++--- .../primitives/attribute_spec.rb | 45 ++++++++++++------- spec/active_relation/relations/alias_spec.rb | 9 ---- spec/active_relation/relations/join_spec.rb | 7 +++ spec/active_relation/relations/rename_spec.rb | 6 --- .../active_relation/relations/schmoin_spec.rb | 8 ++-- spec/spec_helper.rb | 1 + 18 files changed, 152 insertions(+), 92 deletions(-) diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index 26348fb35e9bc..51ceee6e6694f 100644 --- a/lib/active_relation/primitives/aggregation.rb +++ b/lib/active_relation/primitives/aggregation.rb @@ -1,17 +1,31 @@ module ActiveRelation class Aggregation - attr_reader :attribute, :function_sql + include Sql::Quoting - def initialize(attribute, function_sql) - @attribute, @function_sql = attribute, function_sql + attr_reader :attribute, :function_sql, :alias + delegate :relation, :to => :attribute + + def initialize(attribute, function_sql, aliaz = nil) + @attribute, @function_sql, @alias = attribute, function_sql, aliaz end - def substitute(new_relation) - Aggregation.new(attribute.substitute(new_relation), function_sql) + module Transformations + def substitute(new_relation) + Aggregation.new(attribute.substitute(new_relation), function_sql, @alias) + end + + def as(aliaz) + Aggregation.new(attribute, function_sql, aliaz) + end + + def to_attribute + Attribute.new(relation, @alias) + end end + include Transformations def to_sql(strategy = nil) - "#{function_sql}(#{attribute.to_sql})" + "#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '') end def ==(other) diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index eb167b1a6645b..3b63bf985b383 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -18,6 +18,10 @@ def substitute(new_relation) def qualify self.as(qualified_name) end + + def to_attribute + self + end end include Transformations @@ -26,7 +30,7 @@ def qualified_name end def ==(other) - relation == other.relation and name == other.name and @alias == other.alias + self.class == other.class and relation == other.relation and name == other.name and @alias == other.alias end module Predications diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index f40e51475e893..701ab189d0042 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -16,10 +16,6 @@ def ==(other) end protected - def table_sql - "#{quote_table_name(relation.name)} AS #{quote_table_name(@alias)}" - end - def attribute(name) if unaliased_attribute = relation[name] unaliased_attribute.substitute(self) diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index bbc7ff1baebf1..e870f12affc01 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,7 +2,7 @@ module ActiveRelation class Compound < Relation attr_reader :relation - delegate :attributes, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, + delegate :projections, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :to => :relation end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 8ccd1e9c6c0b5..b624df8d72f4d 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -1,6 +1,7 @@ module ActiveRelation class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates + delegate :table_sql, :to => :relation1 def initialize(join_sql, relation1, relation2, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates @@ -24,17 +25,16 @@ def joins def selects relation1.send(:selects) + relation2.send(:selects) end - - def attributes - relation1.attributes + relation2.attributes - end - + def attribute(name) relation1[name] || relation2[name] end - delegate :table_sql, :to => :relation1 - + protected + def projections + relation1.send(:projections) + relation2.send(:projections) + end + private def join "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index 211e0607ac328..9651acd0212a8 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -1,17 +1,17 @@ module ActiveRelation class Projection < Compound - attr_reader :attributes - - def initialize(relation, *attributes) - @relation, @attributes = relation, attributes + attr_reader :projections + + def initialize(relation, *projections) + @relation, @projections = relation, projections end def ==(other) - self.class == other.class and relation == other.relation and attributes == other.attributes + self.class == other.class and relation == other.relation and projections == other.projections end def qualify - Projection.new(relation.qualify, *attributes.collect(&:qualify)) + Projection.new(relation.qualify, *projections.collect(&:qualify)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 18ba5491b1998..f1febc497cd07 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -77,9 +77,13 @@ def on(*predicates) end include Operations + def attributes + projections.collect(&:to_attribute) + end + def to_sql(strategy = Sql::Select.new) strategy.select [ - "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", + "SELECT #{projections.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank?), ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), @@ -87,7 +91,7 @@ def to_sql(strategy = Sql::Select.new) ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), ("OFFSET #{offset.to_sql}" unless offset.blank?) - ].compact.join("\n") + ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql @@ -96,7 +100,7 @@ def connection ActiveRecord::Base.connection end - def attributes; [] end + def projections; [] end def selects; [] end def orders; [] end def inserts; [] end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 2977804db14d1..c9c47f95b835d 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -1,36 +1,36 @@ module ActiveRelation class Rename < Compound - attr_reader :schmattribute, :rename + attr_reader :autonym, :pseudonym - def initialize(relation, renames) - @schmattribute, @rename = renames.shift - @relation = renames.empty?? relation : Rename.new(relation, renames) + def initialize(relation, pseudonyms) + @autonym, @pseudonym = pseudonyms.shift + @relation = pseudonyms.empty?? relation : Rename.new(relation, pseudonyms) end def ==(other) - relation == other.relation and schmattribute == other.schmattribute and self.rename == other.rename - end - - def attributes - relation.attributes.collect(&method(:substitute)) + relation == other.relation and autonym == other.autonym and pseudonym == other.pseudonym end def qualify - Rename.new(relation.qualify, schmattribute.qualify => self.rename) + Rename.new(relation.qualify, autonym.qualify => self.pseudonym) end protected + def projections + relation.send(:projections).collect(&method(:substitute)) + end + def attribute(name) case - when name == self.rename then schmattribute.as(self.rename) - when relation[name] == schmattribute then nil + when name == pseudonym then autonym.as(pseudonym) + when relation[name] == autonym then nil else relation[name] end end private - def substitute(a) - a == schmattribute ? a.as(self.rename) : a + def substitute(attribute) + attribute == autonym ? attribute.as(pseudonym) : attribute end end end \ No newline at end of file diff --git a/lib/active_relation/relations/schmoin.rb b/lib/active_relation/relations/schmoin.rb index 398cfb7b2883e..6d0cb6f171e6c 100644 --- a/lib/active_relation/relations/schmoin.rb +++ b/lib/active_relation/relations/schmoin.rb @@ -1,6 +1,7 @@ module ActiveRelation class Schmoin < Relation attr_reader :join_sql, :relation1, :relation2, :predicates + delegate :table_sql, :to => :relation1 def initialize(join_sql, relation1, relation2, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates @@ -24,20 +25,19 @@ def joins def selects relation1.send(:selects) + relation2.send(:selects) end - - def attributes - relation1.attributes + relation2.attributes + + # this is magick!!! + def projections + relation1.projections + relation2.attributes end def attribute(name) relation1[name] || relation2[name] end - delegate :table_sql, :to => :relation1 - private def join - "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" + "#{join_sql} #{relation2.to_sql(Sql::Aggregation.new)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" end end end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 5220087318695..637273f949073 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -15,6 +15,8 @@ def qualify end protected + alias_method :projections, :attributes + def attribute(name) attributes_by_name[name.to_s] end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 89f6193cd84d4..bc658271c3f1b 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -17,8 +17,8 @@ def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") end - def select(select_sql) - "(#{select_sql})" + def select(select_sql, aliaz) + "(#{select_sql}) AS #{quote_column_name(aliaz)}" end end @@ -31,17 +31,23 @@ def scalar(scalar) scalar end - def select(select_sql) + def select(select_sql, aliaz) "(#{select_sql})" end end class Select < Strategy - def select(select_sql) + def select(select_sql, aliaz) select_sql end end + class Aggregation < Strategy + def select(select_sql, aliaz) + "(#{select_sql}) AS #{quote_table_name(aliaz)}" + end + end + class Scalar < Strategy def scalar(scalar) quote(scalar) diff --git a/spec/active_relation/primitives/aggregation_spec.rb b/spec/active_relation/primitives/aggregation_spec.rb index fbd846ffed3e6..5daf774e06d27 100644 --- a/spec/active_relation/primitives/aggregation_spec.rb +++ b/spec/active_relation/primitives/aggregation_spec.rb @@ -16,19 +16,47 @@ module ActiveRelation end end - describe '#substitute' do - it "distributes over the attribute" do - Aggregation.new(@relation1[:id], "SUM").substitute(@relation2). \ - should == Aggregation.new(@relation1[:id].substitute(@relation2), "SUM") + describe Aggregation::Transformations do + describe '#substitute' do + it "distributes over the attribute and alias" do + Aggregation.new(@relation1[:id], "SUM", "alias").substitute(@relation2). \ + should == Aggregation.new(@relation1[:id].substitute(@relation2), "SUM", "alias") + end + end + + describe '#as' do + it "manufactures an aliased aggregation" do + Aggregation.new(@relation1[:id], "SUM").as(:doof). \ + should == Aggregation.new(@relation1[:id], "SUM", :doof) + end + end + + describe '#to_attribute' do + it "manufactures an attribute the name of which corresponds to the aggregation's alias" do + Aggregation.new(@relation1[:id], "SUM", :schmaggregation).to_attribute. \ + should == Attribute.new(@relation1, :schmaggregation) + end + end + end + + describe '#relation' do + it "delegates to the attribute" do + Aggregation.new(@relation1[:id], "SUM").relation.should == @relation1 end end describe '#to_sql' do it 'manufactures sql with an aggregation function' do - @relation1[:id].maximum.to_sql.should be_like(""" + Aggregation.new(@relation1[:id], "MAX").to_sql.should be_like(""" MAX(`foo`.`id`) """) end + + it 'manufactures sql with an aliased aggregation function' do + Aggregation.new(@relation1[:id], "MAX", "marx").to_sql.should be_like(""" + MAX(`foo`.`id`) AS `marx` + """) + end end end end \ No newline at end of file diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 543217b9cf94f..7f5d4922b89c7 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -7,31 +7,43 @@ module ActiveRelation @relation2 = Table.new(:bar) end - describe '#as' do - it "manufactures an aliased attributed when provided a parameter" do - @relation1[:id].as(:alias).should == Attribute.new(@relation1, :id, :alias) + describe Attribute::Transformations do + before do + @attribute = Attribute.new(@relation1, :id) + end + + describe '#as' do + it "manufactures an aliased attributed" do + @attribute.as(:alias).should == Attribute.new(@relation1, @attribute.name, :alias) + end end - end - describe '#substitute' do - it "manufactures an attribute with the relation substituted" do - @relation1[:id].substitute(@relation2).should == Attribute.new(@relation2, :id) + describe '#substitute' do + it "manufactures an attribute with the relation substituted" do + @attribute.substitute(@relation2).should == Attribute.new(@relation2, @attribute.name) + end + end + + describe '#qualify' do + it "manufactures an attribute aliased with that attributes qualified name" do + @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, @attribute.qualified_name) + end + end + + describe '#to_attribute' do + it "returns self" do + @attribute.to_attribute.should == @attribute + end end end - + describe '#qualified_name' do it "manufactures an attribute name prefixed with the relation's name" do - @relation1[:id].qualified_name.should == 'foo.id' + Attribute.new(@relation1, :id).qualified_name.should == 'foo.id' end it "manufactures an attribute name prefixed with the relation's aliased name" do - @relation1.as(:bar)[:id].qualified_name.should == 'bar.id' - end - end - - describe '#qualify' do - it "manufactures an attribute aliased with that attributes qualified name" do - @relation1[:id].qualify.should == @relation1[:id].qualify + Attribute.new(@relation1.as(:bar), :id).qualified_name.should == 'bar.id' end end @@ -40,6 +52,7 @@ module ActiveRelation Attribute.new(@relation1, :name).should == Attribute.new(@relation1, :name) Attribute.new(@relation1, :name).should_not == Attribute.new(@relation1, :another_name) Attribute.new(@relation1, :name).should_not == Attribute.new(@relation2, :name) + Attribute.new(@relation1, :name).should_not == Aggregation.new(Attribute.new(@relation1, :name), "SUM") end end diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb index 418af7fe662ef..6c203990ebb3b 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/relations/alias_spec.rb @@ -25,14 +25,5 @@ module ActiveRelation @alias_relation[:does_not_exist].should be_nil end end - - describe '#to_sql' do - it "manufactures an aliased select query" do - @alias_relation.to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `users` AS `foo` - """) - end - end end end \ No newline at end of file diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 25c505e371979..68d7b83a12445 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -25,6 +25,13 @@ module ActiveRelation should == Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) end end + + describe '#attributes' do + it 'combines the attributes of the two relations' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).attributes.should == + @relation1.attributes + @relation2.attributes + end + end describe '#to_sql' do before do diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 3f8d5e3dbd190..eb0e1f48dd348 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -38,12 +38,6 @@ module ActiveRelation end end - describe '#schmattribute' do - it "should be renamed" do - pending - end - end - describe '#qualify' do it "distributes over the relation and renames" do Rename.new(@relation, @relation[:id] => :schmid).qualify. \ diff --git a/spec/active_relation/relations/schmoin_spec.rb b/spec/active_relation/relations/schmoin_spec.rb index 14e583afab164..e5ed9be393cb4 100644 --- a/spec/active_relation/relations/schmoin_spec.rb +++ b/spec/active_relation/relations/schmoin_spec.rb @@ -5,17 +5,17 @@ module ActiveRelation before do @relation = Table.new(:users) photos = Table.new(:photos) - @aggregate_relation = photos.project(photos[:user_id], photos[:id].count).group(photos[:user_id]).as(:photo_count) + @aggregate_relation = photos.project(photos[:user_id], photos[:id].count).rename(photos[:id].count, :cnt) \ + .group(photos[:user_id]).as(:photo_count) @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) end describe '#to_sql' do it 'manufactures sql joining the two tables on the predicate, merging the selects' do - pending Schmoin.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" - SELECT `users`.`name` + SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, count(`photos`.`id`) FROM `photos`) AS `photo_count` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` ON `photo_count`.`user_id` = `users`.`id` """) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8f5d76370ce27..e3508aac906ee 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,6 @@ require 'rubygems' require 'spec' +require 'pp' dir = File.dirname(__FILE__) $LOAD_PATH.unshift "#{dir}/../lib" Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" } From 559d9bbfe09034e807e5eae169bea26df780aa36 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 21 Jan 2008 18:47:22 -0800 Subject: [PATCH 0047/1492] merging "schmoin" experiment with joining aggregations into regular "join" functionality; half-way done... --- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/group.rb | 4 ++ lib/active_relation/relations/join.rb | 18 ++++-- lib/active_relation/relations/relation.rb | 4 ++ spec/active_relation/relations/group_spec.rb | 6 ++ spec/active_relation/relations/join_spec.rb | 56 ++++++++++++++----- .../relations/relation_spec.rb | 6 ++ 7 files changed, 76 insertions(+), 20 deletions(-) diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index e870f12affc01..a7595c9e3d025 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,7 +2,7 @@ module ActiveRelation class Compound < Relation attr_reader :relation - delegate :projections, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, + delegate :projections, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :to => :relation end end \ No newline at end of file diff --git a/lib/active_relation/relations/group.rb b/lib/active_relation/relations/group.rb index bc363970c7bf8..31de6f4bd845e 100644 --- a/lib/active_relation/relations/group.rb +++ b/lib/active_relation/relations/group.rb @@ -13,5 +13,9 @@ def ==(other) def qualify Group.new(relation.qualify, *groupings.collect(&:qualify)) end + + def aggregation? + true + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index b624df8d72f4d..d4cfe192398da 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -26,18 +26,26 @@ def selects relation1.send(:selects) + relation2.send(:selects) end + # this is magick!!! + def projections + relation1.send(:projections) + relation2.attributes + end + def attribute(name) relation1[name] || relation2[name] end - - protected - def projections - relation1.send(:projections) + relation2.send(:projections) - end private def join "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" end + + def join + [join_sql, right_table, "ON", predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") + end + + def right_table + relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index f1febc497cd07..cb981eb3de0e1 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -80,6 +80,10 @@ def on(*predicates) def attributes projections.collect(&:to_attribute) end + + def aggregation? + false + end def to_sql(strategy = Sql::Select.new) strategy.select [ diff --git a/spec/active_relation/relations/group_spec.rb b/spec/active_relation/relations/group_spec.rb index 256d7dde458e4..532d6faea6e3d 100644 --- a/spec/active_relation/relations/group_spec.rb +++ b/spec/active_relation/relations/group_spec.rb @@ -15,6 +15,12 @@ module ActiveRelation should == Group.new(@relation1.qualify, @attribute1.qualify) end end + + describe '#aggregation?' do + it "is true" do + Group.new(@relation1, @attribute1).should be_aggregation + end + end describe '#to_sql' do it "manufactures sql with an order clause" do diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 68d7b83a12445..00a6218c03b7d 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -27,25 +27,53 @@ module ActiveRelation end describe '#attributes' do - it 'combines the attributes of the two relations' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).attributes.should == - @relation1.attributes + @relation2.attributes + describe 'with simple relations' do + it 'combines the attributes of the two relations' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).attributes.should == + @relation1.attributes + @relation2.attributes + end + end + + describe 'with aggregated relations' do + it '' do + end end end describe '#to_sql' do - before do - @relation1 = @relation1.select(@relation1[:id].equals(1)) + describe 'with simple relations' do + before do + @relation1 = @relation1.select(@relation1[:id].equals(1)) + end + + it 'manufactures sql joining the two tables on the predicate, merging the selects' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` + FROM `foo` + INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` + WHERE + `foo`.`id` = 1 + """) + end end - - it 'manufactures sql joining the two tables on the predicate, merging the selects' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` - FROM `foo` - INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` - WHERE - `foo`.`id` = 1 - """) + + describe 'with aggregated relations' do + before do + @relation = Table.new(:users) + photos = Table.new(:photos) + @aggregate_relation = photos.project(photos[:user_id], photos[:id].count).rename(photos[:id].count, :cnt) \ + .group(photos[:user_id]).as(:photo_count) + @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) + end + + it 'manufactures sql joining the left table to a derived table' do + Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" + SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` + ON `photo_count`.`user_id` = `users`.`id` + """) + end end end end diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index 1b4ab785b7ba5..f78f1b31b7a28 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -24,6 +24,12 @@ module ActiveRelation @relation1.include?(@attribute1).should be_kind_of(RelationInclusion) end end + + describe '#aggregation?' do + it "returns false" do + @relation1.should_not be_aggregation + end + end describe 'read operations' do describe 'joins' do From 7f35d492372fd91cd35e7f9a2408efd64d28ccf5 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 21 Jan 2008 20:02:48 -0800 Subject: [PATCH 0048/1492] joining on aggregations; this time where the aggregation is on the right. --- lib/active_relation/relations/alias.rb | 4 +- lib/active_relation/relations/compound.rb | 3 +- lib/active_relation/relations/join.rb | 28 +++++++----- lib/active_relation/relations/relation.rb | 4 -- lib/active_relation/relations/rename.rb | 6 ++- spec/active_relation/relations/join_spec.rb | 50 ++++++++++++++++----- 6 files changed, 66 insertions(+), 29 deletions(-) diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 701ab189d0042..26b582e98abd5 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -8,11 +8,11 @@ def initialize(relation, aliaz) end def attributes - relation.attributes.collect { |attribute| attribute.substitute(self) } + relation.attributes.collect { |a| a.substitute(self) } end def ==(other) - relation == other.relation and self.alias == other.alias + relation == other.relation and @alias == other.alias end protected diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index a7595c9e3d025..d71d0ffeb59d3 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,7 +2,8 @@ module ActiveRelation class Compound < Relation attr_reader :relation - delegate :projections, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, + delegate :projections, :attributes, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, + :offset, :name, :alias, :aggregation?, :to => :relation end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index d4cfe192398da..37ed558e9f6d1 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -1,7 +1,6 @@ module ActiveRelation class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates - delegate :table_sql, :to => :relation1 def initialize(join_sql, relation1, relation2, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates @@ -16,6 +15,10 @@ def ==(other) def qualify Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) end + + def attributes + projections.map(&:to_attribute) + end protected def joins @@ -23,28 +26,33 @@ def joins end def selects - relation1.send(:selects) + relation2.send(:selects) + [ + (relation1.send(:selects) unless relation1.aggregation?), + (relation2.send(:selects) unless relation2.aggregation?) + ].compact.flatten end - # this is magick!!! def projections - relation1.send(:projections) + relation2.attributes + [ + relation1.aggregation?? relation1.attributes : relation1.send(:projections), + relation2.aggregation?? relation2.attributes : relation2.send(:projections), + ].flatten end def attribute(name) relation1[name] || relation2[name] end - - private - def join - "#{join_sql} #{relation2.send(:table_sql)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" + + def table_sql + relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) end + private def join - [join_sql, right_table, "ON", predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") + [join_sql, right_table_sql, "ON", predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") end - def right_table + def right_table_sql relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql) end end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index cb981eb3de0e1..d09ee058efd96 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -77,10 +77,6 @@ def on(*predicates) end include Operations - def attributes - projections.collect(&:to_attribute) - end - def aggregation? false end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index c9c47f95b835d..94e5edcd47c56 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -14,7 +14,11 @@ def ==(other) def qualify Rename.new(relation.qualify, autonym.qualify => self.pseudonym) end - + + def attributes + projections.collect(&:to_attribute) + end + protected def projections relation.send(:projections).collect(&method(:substitute)) diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 00a6218c03b7d..422a93772d997 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -42,22 +42,27 @@ module ActiveRelation describe '#to_sql' do describe 'with simple relations' do - before do - @relation1 = @relation1.select(@relation1[:id].equals(1)) - end - - it 'manufactures sql joining the two tables on the predicate, merging the selects' do + it 'manufactures sql joining the two tables on the predicate' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` FROM `foo` INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` - WHERE - `foo`.`id` = 1 """) end + + it 'manufactures sql joining the two tables, merging any selects' do + Join.new("INNER JOIN", @relation1.select(@relation1[:id].equals(1)), + @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(""" + SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` + FROM `foo` + INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` + WHERE `foo`.`id` = 1 + AND `bar`.`id` = 2 + """) + end end - describe 'with aggregated relations' do + describe 'aggregated relations' do before do @relation = Table.new(:users) photos = Table.new(:photos) @@ -66,11 +71,34 @@ module ActiveRelation @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) end - it 'manufactures sql joining the left table to a derived table' do - Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" + describe 'with the aggregation on the right' do + it 'manufactures sql joining the left table to a derived table' do + Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" + SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` + ON `photo_count`.`user_id` = `users`.`id` + """) + end + end + + describe 'with the aggregation on the left' do + it 'manufactures sql joining the right table to a derived table' do + Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like(""" + SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`name`, `users`.`id` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` + INNER JOIN `users` + ON `photo_count`.`user_id` = `users`.`id` + """) + end + end + + it "keeps selects on the aggregation within the derived table" do + pending + Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count` ON `photo_count`.`user_id` = `users`.`id` """) end From 3f50d5c23719b6877124fcd9669bbf4811f4c2eb Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 21 Jan 2008 20:12:21 -0800 Subject: [PATCH 0049/1492] filling out some pending specs --- lib/active_relation/relations/compound.rb | 1 - lib/active_relation/relations/range.rb | 4 +++ spec/active_relation/relations/range_spec.rb | 4 +-- .../relations/relation_spec.rb | 4 --- spec/active_relation/relations/rename_spec.rb | 27 +++++++++---------- spec/active_relation/relations/table_spec.rb | 5 +++- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index d71d0ffeb59d3..332147523e214 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -1,7 +1,6 @@ module ActiveRelation class Compound < Relation attr_reader :relation - delegate :projections, :attributes, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :to => :relation diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb index e8b7f4b69d3e3..83af03fc0e5fd 100644 --- a/lib/active_relation/relations/range.rb +++ b/lib/active_relation/relations/range.rb @@ -17,5 +17,9 @@ def limit def offset range.begin end + + def qualify + Range.new(relation.qualify, range) + end end end \ No newline at end of file diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/relations/range_spec.rb index f417626feda43..51171c759b71a 100644 --- a/spec/active_relation/relations/range_spec.rb +++ b/spec/active_relation/relations/range_spec.rb @@ -10,8 +10,8 @@ module ActiveRelation end describe '#qualify' do - it "distributes over the relation and attributes" do - pending + it "distributes over the relation" do + Range.new(@relation1, @range1).qualify.should == Range.new(@relation1.qualify, @range1) end end diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index f78f1b31b7a28..05330206e0385 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -51,10 +51,6 @@ module ActiveRelation end describe '#project' do - it "collapses identical projections" do - pending - end - it "manufactures a projection relation" do @relation1.project(@attribute1, @attribute2).should == Projection.new(@relation1, @attribute1, @attribute2) end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index eb0e1f48dd348..1616d5fdb74e1 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -3,45 +3,44 @@ module ActiveRelation describe Rename do before do - @relation = Table.new(:foo) - @renamed_relation = Rename.new(@relation, @relation[:id] => :schmid) + @relation1 = Table.new(:foo) + @relation2 = Table.new(:bar) + @renamed_relation = Rename.new(@relation1, @relation1[:id] => :schmid) end describe '#initialize' do it "manufactures nested rename relations if multiple renames are provided" do - Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ - should == Rename.new(Rename.new(@relation, @relation[:id] => :humpty), @relation[:name] => :dumpty) - end - - it "raises an exception if the rename provided is already used" do - pending + Rename.new(@relation1, @relation1[:id] => :humpty, @relation1[:name] => :dumpty). \ + should == Rename.new(Rename.new(@relation1, @relation1[:id] => :humpty), @relation1[:name] => :dumpty) end end describe '==' do it "obtains if the relation, attribute, and rename are identical" do - pending + Rename.new(@relation1, @relation1[:id] => :humpty).should == Rename.new(@relation1, @relation1[:id] => :humpty) + Rename.new(@relation1, @relation1[:id] => :humpty).should_not == Rename.new(@relation1, @relation1[:id] => :dumpty) + Rename.new(@relation1, @relation1[:id] => :humpty).should_not == Rename.new(@relation2, @relation2[:id] => :humpty) end end describe '#attributes' do it "manufactures a list of attributes with the renamed attribute renameed" do - Rename.new(@relation, @relation[:id] => :schmid).attributes.should == - (@relation.attributes - [@relation[:id]]) + [@relation[:id].as(:schmid)] + Rename.new(@relation1, @relation1[:id] => :schmid).attributes.should == + (@relation1.attributes - [@relation1[:id]]) + [@relation1[:id].as(:schmid)] end end describe '[]' do it 'indexes attributes by rename' do @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation[:id].as(:schmid) + @renamed_relation[:schmid].should == @relation1[:id].as(:schmid) end end describe '#qualify' do it "distributes over the relation and renames" do - Rename.new(@relation, @relation[:id] => :schmid).qualify. \ - should == Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) + Rename.new(@relation1, @relation1[:id] => :schmid).qualify. \ + should == Rename.new(@relation1.qualify, @relation1[:id].qualify => :schmid) end end diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index ec6e6e10bd20a..c8679707f5e3a 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -17,7 +17,10 @@ module ActiveRelation describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do - pending + @relation.attributes.should == [ + Attribute.new(@relation, :name), + Attribute.new(@relation, :id) + ] end end From 9c4403f67a8f2ac40fc0c964d8c24ecc6c6d7f27 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 27 Jan 2008 16:44:32 -0800 Subject: [PATCH 0050/1492] cleanup --- .../integration/scratch_spec.rb | 2 +- spec/active_relation/relations/join_spec.rb | 23 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb index 6aa27bc1fee33..a31c2ea9f645e 100644 --- a/spec/active_relation/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -82,7 +82,7 @@ def photo_belongs_to_camera(photo_relation) # MysqlAdapter from ActiveRecord is used to do the escaping. end - it 'generates the query for User.has_many :cameras :through => :photos' do + it 'generates the query for User.has_many :cameras, :through => :photos' do # note, again, the compositionality of the operators: user_cameras = photo_belongs_to_camera(user_has_many_photos(@user)) user_cameras.project(*@cameras.attributes).to_sql.should be_like(""" diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 422a93772d997..0f30d11f982db 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -7,7 +7,7 @@ module ActiveRelation @relation2 = Table.new(:bar) @predicate = Equality.new(@relation1[:id], @relation2[:id]) end - + describe '==' do it 'obtains if the two relations and the predicate are identical' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate) @@ -18,14 +18,14 @@ module ActiveRelation Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation2, @relation1, @predicate) end end - + describe '#qualify' do it 'distributes over the relations and predicates' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ should == Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) end end - + describe '#attributes' do describe 'with simple relations' do it 'combines the attributes of the two relations' do @@ -33,13 +33,14 @@ module ActiveRelation @relation1.attributes + @relation2.attributes end end - + describe 'with aggregated relations' do it '' do + pending end end end - + describe '#to_sql' do describe 'with simple relations' do it 'manufactures sql joining the two tables on the predicate' do @@ -49,7 +50,7 @@ module ActiveRelation INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` """) end - + it 'manufactures sql joining the two tables, merging any selects' do Join.new("INNER JOIN", @relation1.select(@relation1[:id].equals(1)), @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(""" @@ -61,7 +62,8 @@ module ActiveRelation """) end end - + + describe 'aggregated relations' do before do @relation = Table.new(:users) @@ -70,7 +72,7 @@ module ActiveRelation .group(photos[:user_id]).as(:photo_count) @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) end - + describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" @@ -81,9 +83,10 @@ module ActiveRelation """) end end - + describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do + pending Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like(""" SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`name`, `users`.`id` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` @@ -92,7 +95,7 @@ module ActiveRelation """) end end - + it "keeps selects on the aggregation within the derived table" do pending Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" From 6c73e3dbc714a9752a66a6da51e7e41f372797b3 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 3 Feb 2008 15:43:16 -0800 Subject: [PATCH 0051/1492] i know it doesn't work but need to anchor here... --- lib/active_relation/primitives.rb | 2 +- lib/active_relation/primitives/aggregation.rb | 35 ----------- lib/active_relation/primitives/attribute.rb | 14 ++--- lib/active_relation/relations.rb | 3 +- lib/active_relation/relations/aggregation.rb | 27 ++++++++ lib/active_relation/relations/alias.rb | 12 ---- lib/active_relation/relations/compound.rb | 19 +++++- lib/active_relation/relations/group.rb | 21 ------- lib/active_relation/relations/join.rb | 18 +++--- lib/active_relation/relations/projection.rb | 1 + lib/active_relation/relations/relation.rb | 46 +++++++++----- lib/active_relation/relations/rename.rb | 40 +++++++----- lib/active_relation/relations/schmoin.rb | 43 ------------- lib/active_relation/relations/table.rb | 12 ++-- .../predicates/equality_spec.rb | 3 - .../primitives/aggregation_spec.rb | 62 ------------------- .../primitives/attribute_spec.rb | 55 +++++++++++----- spec/active_relation/relations/alias_spec.rb | 19 ------ .../relations/compound_spec.rb | 41 +++++++++++- spec/active_relation/relations/group_spec.rb | 35 ----------- spec/active_relation/relations/join_spec.rb | 18 +++--- .../relations/projection_spec.rb | 4 ++ .../relations/relation_spec.rb | 11 ++-- spec/active_relation/relations/rename_spec.rb | 58 +++++++++++++++-- .../active_relation/relations/schmoin_spec.rb | 24 ------- spec/active_relation/relations/table_spec.rb | 30 ++++++++- 26 files changed, 304 insertions(+), 349 deletions(-) delete mode 100644 lib/active_relation/primitives/aggregation.rb create mode 100644 lib/active_relation/relations/aggregation.rb delete mode 100644 lib/active_relation/relations/group.rb delete mode 100644 lib/active_relation/relations/schmoin.rb delete mode 100644 spec/active_relation/primitives/aggregation_spec.rb delete mode 100644 spec/active_relation/relations/group_spec.rb delete mode 100644 spec/active_relation/relations/schmoin_spec.rb diff --git a/lib/active_relation/primitives.rb b/lib/active_relation/primitives.rb index 5d35f4256419c..2ac157297ea7a 100644 --- a/lib/active_relation/primitives.rb +++ b/lib/active_relation/primitives.rb @@ -1,3 +1,3 @@ require 'active_relation/primitives/attribute' -require 'active_relation/primitives/aggregation' +require 'active_relation/primitives/expression' diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb deleted file mode 100644 index 51ceee6e6694f..0000000000000 --- a/lib/active_relation/primitives/aggregation.rb +++ /dev/null @@ -1,35 +0,0 @@ -module ActiveRelation - class Aggregation - include Sql::Quoting - - attr_reader :attribute, :function_sql, :alias - delegate :relation, :to => :attribute - - def initialize(attribute, function_sql, aliaz = nil) - @attribute, @function_sql, @alias = attribute, function_sql, aliaz - end - - module Transformations - def substitute(new_relation) - Aggregation.new(attribute.substitute(new_relation), function_sql, @alias) - end - - def as(aliaz) - Aggregation.new(attribute, function_sql, aliaz) - end - - def to_attribute - Attribute.new(relation, @alias) - end - end - include Transformations - - def to_sql(strategy = nil) - "#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '') - end - - def ==(other) - self.class == other.class and attribute == other.attribute and function_sql == other.function_sql - end - end -end \ No newline at end of file diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 3b63bf985b383..8d40a4141f72e 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -60,28 +60,28 @@ def matches(regexp) end include Predications - module Aggregations + module Expressions def count - Aggregation.new(self, "COUNT") + Expression.new(self, "COUNT") end def sum - Aggregation.new(self, "SUM") + Expression.new(self, "SUM") end def maximum - Aggregation.new(self, "MAX") + Expression.new(self, "MAX") end def minimum - Aggregation.new(self, "MIN") + Expression.new(self, "MIN") end def average - Aggregation.new(self, "AVG") + Expression.new(self, "AVG") end end - include Aggregations + include Expressions def to_sql(strategy = Sql::Predicate.new) strategy.attribute relation.name, name, self.alias diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index c9b9de93b207b..27dd229f3fde3 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -2,8 +2,7 @@ require 'active_relation/relations/compound' require 'active_relation/relations/table' require 'active_relation/relations/join' -require 'active_relation/relations/schmoin' -require 'active_relation/relations/group' +require 'active_relation/relations/aggregation' require 'active_relation/relations/projection' require 'active_relation/relations/selection' require 'active_relation/relations/order' diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb new file mode 100644 index 0000000000000..161a7485676b9 --- /dev/null +++ b/lib/active_relation/relations/aggregation.rb @@ -0,0 +1,27 @@ +module ActiveRelation + class Aggregation < Compound + attr_reader :expressions, :groupings + alias_method :attributes, :expressions + + def initialize(relation, options) + @relation, @expressions, @groupings = relation, options[:expressions], options[:groupings] + end + + def ==(other) + relation == other.relation and groupings == other.groupings and expressions == other.expressions + end + + def qualify + Aggregation.new(relation.qualify, :expressions => expressions.collect(&:qualify), :groupings => groupings.collect(&:qualify)) + end + + protected + def aggregation? + true + end + + def attribute_for_expression(expression) + expression.relation == self ? expression : (e = @expressions.detect { |e| e == expression }) && e.substitute(self) + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 26b582e98abd5..5460413b25926 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -1,25 +1,13 @@ module ActiveRelation class Alias < Compound attr_reader :alias - alias_method :name, :alias def initialize(relation, aliaz) @relation, @alias = relation, aliaz end - def attributes - relation.attributes.collect { |a| a.substitute(self) } - end - def ==(other) relation == other.relation and @alias == other.alias end - - protected - def attribute(name) - if unaliased_attribute = relation[name] - unaliased_attribute.substitute(self) - end - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 332147523e214..7c4a7e707b38e 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -1,8 +1,25 @@ module ActiveRelation class Compound < Relation attr_reader :relation - delegate :projections, :attributes, :attribute, :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, + delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :to => :relation + + def attributes + relation.attributes.collect { |a| a.substitute(self) } + end + + protected + def attribute_for_name(name) + (a = relation[name]) && a.substitute(self) + end + + def attribute_for_attribute(attribute) + attribute.relation == self ? attribute : (a = relation[attribute]) && a.substitute(self) + end + + def attribute_for_expression(expression) + expression.relation == self ? expression : (a = relation[expression]) && a.substitute(self) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/group.rb b/lib/active_relation/relations/group.rb deleted file mode 100644 index 31de6f4bd845e..0000000000000 --- a/lib/active_relation/relations/group.rb +++ /dev/null @@ -1,21 +0,0 @@ -module ActiveRelation - class Group < Compound - attr_reader :groupings - - def initialize(relation, *groupings) - @relation, @groupings = relation, groupings - end - - def ==(other) - relation == other.relation and groupings == other.groupings - end - - def qualify - Group.new(relation.qualify, *groupings.collect(&:qualify)) - end - - def aggregation? - true - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 37ed558e9f6d1..dfc9992f0bc44 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -17,7 +17,10 @@ def qualify end def attributes - projections.map(&:to_attribute) + [ + relation1.aggregation?? relation1.attributes.collect(&:to_attribute) : relation1.attributes, + relation2.aggregation?? relation2.attributes.collect(&:to_attribute) : relation2.attributes, + ].flatten end protected @@ -32,16 +35,13 @@ def selects ].compact.flatten end - def projections - [ - relation1.aggregation?? relation1.attributes : relation1.send(:projections), - relation2.aggregation?? relation2.attributes : relation2.send(:projections), - ].flatten - end - - def attribute(name) + def attribute_for_name(name) relation1[name] || relation2[name] end + + def attribute_for_attribute(attribute) + relation1[attribute] || relation2[attribute] + end def table_sql relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index 9651acd0212a8..78698603f04f0 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -1,6 +1,7 @@ module ActiveRelation class Projection < Compound attr_reader :projections + alias_method :attributes, :projections def initialize(relation, *projections) @relation, @projections = relation, projections diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index d09ee058efd96..838697a2ac4cd 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -26,10 +26,14 @@ def outer_join(other) def [](index) case index - when Symbol - attribute(index) + when Symbol, String + attribute_for_name(index) when ::Range Range.new(self, index) + when Attribute + attribute_for_attribute(index) + when Expression + attribute_for_expression(index) end end @@ -65,8 +69,8 @@ def delete Deletion.new(self) end - def group(*attributes) - Group.new(self, *attributes) + def aggregate(*expressions) + AggregateOperation.new(self, expressions) end JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do @@ -74,6 +78,12 @@ def on(*predicates) Join.new(join_sql, relation1, relation2, *predicates) end end + + AggregateOperation = Struct.new(:relation, :expressions) do + def group(*groupings) + Aggregation.new(relation, :expressions => expressions, :groupings => groupings) + end + end end include Operations @@ -83,7 +93,7 @@ def aggregation? def to_sql(strategy = Sql::Select.new) strategy.select [ - "SELECT #{projections.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", + "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank?), ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), @@ -99,15 +109,23 @@ def to_sql(strategy = Sql::Select.new) def connection ActiveRecord::Base.connection end + + def attribute_for_attribute(attribute) + self == attribute.relation ? attribute : nil + end + + def attribute_for_expression(expression) + nil + end - def projections; [] end - def selects; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def joins; nil end - def limit; nil end - def offset; nil end - def alias; nil end + def attributes; [] end + def selects; [] end + def orders; [] end + def inserts; [] end + def groupings; [] end + def joins; nil end + def limit; nil end + def offset; nil end + def alias; nil end end end \ No newline at end of file diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 94e5edcd47c56..8942ffbe29a53 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -1,40 +1,52 @@ module ActiveRelation class Rename < Compound - attr_reader :autonym, :pseudonym + attr_reader :attribute, :pseudonym def initialize(relation, pseudonyms) - @autonym, @pseudonym = pseudonyms.shift + @attribute, @pseudonym = pseudonyms.shift @relation = pseudonyms.empty?? relation : Rename.new(relation, pseudonyms) end def ==(other) - relation == other.relation and autonym == other.autonym and pseudonym == other.pseudonym + self.class == other.class and relation == other.relation and attribute == other.attribute and pseudonym == other.pseudonym end def qualify - Rename.new(relation.qualify, autonym.qualify => self.pseudonym) + Rename.new(relation.qualify, attribute.qualify => pseudonym) end def attributes - projections.collect(&:to_attribute) + relation.attributes.collect(&method(:substitute)) end protected - def projections - relation.send(:projections).collect(&method(:substitute)) - end - - def attribute(name) + def attribute_for_name(name) case - when name == pseudonym then autonym.as(pseudonym) - when relation[name] == autonym then nil - else relation[name] + when referring_by_autonym?(name) then nil + when referring_by_pseudonym?(name) then attribute.as(pseudonym).substitute(self) + else (a = relation[name]) && a.substitute(self) end end + + def attribute_for_attribute(attribute) + attribute.relation == self ? attribute : substitute(relation[attribute]) + end + + def attribute_for_expression(expression) + expression.relation == self ? expression : substitute(relation[expression]) + end private def substitute(attribute) - attribute == autonym ? attribute.as(pseudonym) : attribute + (relation[attribute] == relation[self.attribute] ? attribute.as(pseudonym) : attribute).substitute(self) if attribute + end + + def referring_by_autonym?(name) + relation[name] == relation[attribute] + end + + def referring_by_pseudonym?(name) + name == pseudonym end end end \ No newline at end of file diff --git a/lib/active_relation/relations/schmoin.rb b/lib/active_relation/relations/schmoin.rb deleted file mode 100644 index 6d0cb6f171e6c..0000000000000 --- a/lib/active_relation/relations/schmoin.rb +++ /dev/null @@ -1,43 +0,0 @@ -module ActiveRelation - class Schmoin < Relation - attr_reader :join_sql, :relation1, :relation2, :predicates - delegate :table_sql, :to => :relation1 - - def initialize(join_sql, relation1, relation2, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates - end - - def ==(other) - predicates == other.predicates and - ((relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2)) - end - - def qualify - Schmoin.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) - end - - protected - def joins - [relation1.joins, relation2.joins, join].compact.join(" ") - end - - def selects - relation1.send(:selects) + relation2.send(:selects) - end - - # this is magick!!! - def projections - relation1.projections + relation2.attributes - end - - def attribute(name) - relation1[name] || relation2[name] - end - - private - def join - "#{join_sql} #{relation2.to_sql(Sql::Aggregation.new)} ON #{predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')}" - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 637273f949073..ffc9077076756 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -13,14 +13,16 @@ def attributes def qualify Rename.new self, qualifications end - - protected - alias_method :projections, :attributes - def attribute(name) + def inspect + "" + end + + protected + def attribute_for_name(name) attributes_by_name[name.to_s] end - + def table_sql "#{quote_table_name(name)}" end diff --git a/spec/active_relation/predicates/equality_spec.rb b/spec/active_relation/predicates/equality_spec.rb index d23893e438e2f..f947bc6fe70d7 100644 --- a/spec/active_relation/predicates/equality_spec.rb +++ b/spec/active_relation/predicates/equality_spec.rb @@ -23,8 +23,5 @@ module ActiveRelation Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) end end - - describe '#to_sql' do - end end end \ No newline at end of file diff --git a/spec/active_relation/primitives/aggregation_spec.rb b/spec/active_relation/primitives/aggregation_spec.rb deleted file mode 100644 index 5daf774e06d27..0000000000000 --- a/spec/active_relation/primitives/aggregation_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -module ActiveRelation - describe Aggregation do - before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - end - - describe '==' do - it 'obtains if the attribute and function sql are identical' do - Aggregation.new(@relation1[:id], "SUM").should == Aggregation.new(@relation1[:id], "SUM") - Aggregation.new(@relation1[:id], "SUM").should_not == Aggregation.new(@relation1[:name], "SUM") - Aggregation.new(@relation1[:id], "SUM").should_not == Aggregation.new(@relation1[:name], "SUM") - Aggregation.new(@relation1[:id], "SUM").should_not == Aggregation.new(@relation2[:id], "SUM") - end - end - - describe Aggregation::Transformations do - describe '#substitute' do - it "distributes over the attribute and alias" do - Aggregation.new(@relation1[:id], "SUM", "alias").substitute(@relation2). \ - should == Aggregation.new(@relation1[:id].substitute(@relation2), "SUM", "alias") - end - end - - describe '#as' do - it "manufactures an aliased aggregation" do - Aggregation.new(@relation1[:id], "SUM").as(:doof). \ - should == Aggregation.new(@relation1[:id], "SUM", :doof) - end - end - - describe '#to_attribute' do - it "manufactures an attribute the name of which corresponds to the aggregation's alias" do - Aggregation.new(@relation1[:id], "SUM", :schmaggregation).to_attribute. \ - should == Attribute.new(@relation1, :schmaggregation) - end - end - end - - describe '#relation' do - it "delegates to the attribute" do - Aggregation.new(@relation1[:id], "SUM").relation.should == @relation1 - end - end - - describe '#to_sql' do - it 'manufactures sql with an aggregation function' do - Aggregation.new(@relation1[:id], "MAX").to_sql.should be_like(""" - MAX(`foo`.`id`) - """) - end - - it 'manufactures sql with an aliased aggregation function' do - Aggregation.new(@relation1[:id], "MAX", "marx").to_sql.should be_like(""" - MAX(`foo`.`id`) AS `marx` - """) - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 7f5d4922b89c7..f76018c49361a 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -41,10 +41,6 @@ module ActiveRelation it "manufactures an attribute name prefixed with the relation's name" do Attribute.new(@relation1, :id).qualified_name.should == 'foo.id' end - - it "manufactures an attribute name prefixed with the relation's aliased name" do - Attribute.new(@relation1.as(:bar), :id).qualified_name.should == 'bar.id' - end end describe '==' do @@ -52,11 +48,36 @@ module ActiveRelation Attribute.new(@relation1, :name).should == Attribute.new(@relation1, :name) Attribute.new(@relation1, :name).should_not == Attribute.new(@relation1, :another_name) Attribute.new(@relation1, :name).should_not == Attribute.new(@relation2, :name) - Attribute.new(@relation1, :name).should_not == Aggregation.new(Attribute.new(@relation1, :name), "SUM") + Attribute.new(@relation1, :name).should_not == Expression.new(Attribute.new(@relation1, :name), "SUM") + end + end + + describe '#to_sql' do + describe Sql::Strategy do + it "manufactures sql without an alias if the strategy is Predicate" do + Attribute.new(@relation1, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`foo`.`name`") + end + + it "manufactures sql with an alias if the strategy is Projection" do + Attribute.new(@relation1, :name, :alias).to_sql(Sql::Projection.new).should be_like("`foo`.`name` AS 'alias'") + end + end + + describe 'binding' do + before do + @attribute = Attribute.new(@relation1, :name, :alias) + @aliased_relation = @relation1.as(:schmoo) + end + + it "is fancy pants" do + pending + @attribute.to_sql.should be_like("`foo`.`name`") + @attribute.substitute(@aliased_relation).to_sql.should be_like("`schmoo`.`alias`") + end end end - describe 'predications' do + describe Attribute::Predications do before do @attribute1 = Attribute.new(@relation1, :name) @attribute2 = Attribute.new(@relation2, :name) @@ -99,38 +120,38 @@ module ActiveRelation end end - describe 'aggregations' do + describe 'Expressions' do before do @attribute1 = Attribute.new(@relation1, :name) end describe '#count' do - it "manufactures a count aggregation" do - @attribute1.count.should == Aggregation.new(@attribute1, "COUNT") + it "manufactures a count Expression" do + @attribute1.count.should == Expression.new(@attribute1, "COUNT") end end describe '#sum' do - it "manufactures a sum aggregation" do - @attribute1.sum.should == Aggregation.new(@attribute1, "SUM") + it "manufactures a sum Expression" do + @attribute1.sum.should == Expression.new(@attribute1, "SUM") end end describe '#maximum' do - it "manufactures a maximum aggregation" do - @attribute1.maximum.should == Aggregation.new(@attribute1, "MAX") + it "manufactures a maximum Expression" do + @attribute1.maximum.should == Expression.new(@attribute1, "MAX") end end describe '#minimum' do - it "manufactures a minimum aggregation" do - @attribute1.minimum.should == Aggregation.new(@attribute1, "MIN") + it "manufactures a minimum Expression" do + @attribute1.minimum.should == Expression.new(@attribute1, "MIN") end end describe '#average' do - it "manufactures an average aggregation" do - @attribute1.average.should == Aggregation.new(@attribute1, "AVG") + it "manufactures an average Expression" do + @attribute1.average.should == Expression.new(@attribute1, "AVG") end end end diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb index 6c203990ebb3b..c02b0df453d0e 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/relations/alias_spec.rb @@ -6,24 +6,5 @@ module ActiveRelation @relation = Table.new(:users) @alias_relation = @relation.as(:foo) end - - describe '#name' do - it 'returns the alias' do - @alias_relation.name.should == :foo - end - end - - describe '#attributes' do - it 'manufactures sql deleting a table relation' do - @alias_relation.attributes.should == @relation.attributes.collect { |a| Attribute.new(@alias_relation, a.name) } - end - end - - describe '[]' do - it 'manufactures attributes associated with the aliased relation' do - @alias_relation[:id].relation.should == @alias_relation - @alias_relation[:does_not_exist].should be_nil - end - end end end \ No newline at end of file diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/relations/compound_spec.rb index 6309547c7d549..a03b0206a985e 100644 --- a/spec/active_relation/relations/compound_spec.rb +++ b/spec/active_relation/relations/compound_spec.rb @@ -3,13 +3,50 @@ module ActiveRelation describe Compound do before do - @relation = Table.new(:users) - class ConcreteCompound < Compound def initialize(relation) @relation = relation end end + @relation = Table.new(:users) + @compound_relation = ConcreteCompound.new(@relation) + end + + describe '#attributes' do + it 'manufactures attributes associated with the compound relation' do + @compound_relation.attributes.should == @relation.attributes.collect { |a| Attribute.new(@compound_relation, a.name) } + end + end + + describe '[]' do + describe 'when given a', Symbol do + it 'manufactures attributes associated with the compound relation if the symbol names an attribute within the relation' do + @compound_relation[:id].relation.should == @compound_relation + @compound_relation[:does_not_exist].should be_nil + end + end + + describe 'when given an', Attribute do + it "manufactures a substituted attribute when given an attribute within the relation" do + @compound_relation[Attribute.new(@relation, :id)].should == Attribute.new(@compound_relation, :id) + @compound_relation[Attribute.new(@compound_relation, :id)].should == Attribute.new(@compound_relation, :id) + @compound_relation[Attribute.new(another_relation = Table.new(:photos), :id)].should be_nil + end + end + + describe 'when given an', Expression do + before do + @nested_expression = Expression.new(Attribute.new(@relation, :id), "COUNT") + @unprojected_expression = Expression.new(Attribute.new(@relation, :id), "SUM") + @compound_relation = ConcreteCompound.new(Aggregation.new(@relation, :expressions => [@nested_expression])) + end + + it "manufactures a substituted Expression when given an Expression within the relation" do + @compound_relation[@nested_expression].should == @nested_expression.substitute(@compound_relation) + @compound_relation[@compound_relation[@expression]].should == @compound_relation[@expression] + @compound_relation[@unprojected_expression].should be_nil + end + end end end end \ No newline at end of file diff --git a/spec/active_relation/relations/group_spec.rb b/spec/active_relation/relations/group_spec.rb deleted file mode 100644 index 532d6faea6e3d..0000000000000 --- a/spec/active_relation/relations/group_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -module ActiveRelation - describe Group do - before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] - end - - describe '#qualify' do - it "distributes over the relation and attributes" do - Group.new(@relation1, @attribute1).qualify. \ - should == Group.new(@relation1.qualify, @attribute1.qualify) - end - end - - describe '#aggregation?' do - it "is true" do - Group.new(@relation1, @attribute1).should be_aggregation - end - end - - describe '#to_sql' do - it "manufactures sql with an order clause" do - Group.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - GROUP BY `foo`.`id` - """) - end - end - end -end diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 0f30d11f982db..5235a5b528395 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -18,6 +18,12 @@ module ActiveRelation Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation2, @relation1, @predicate) end end + + describe '[]' do + it "" do + pending + end + end describe '#qualify' do it 'distributes over the relations and predicates' do @@ -63,17 +69,16 @@ module ActiveRelation end end - describe 'aggregated relations' do before do @relation = Table.new(:users) photos = Table.new(:photos) - @aggregate_relation = photos.project(photos[:user_id], photos[:id].count).rename(photos[:id].count, :cnt) \ - .group(photos[:user_id]).as(:photo_count) + @aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]).rename(photos[:id].count, :cnt) \ + .as(:photo_count) @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) end - describe 'with the aggregation on the right' do + describe 'with the expression on the right' do it 'manufactures sql joining the left table to a derived table' do Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` @@ -84,9 +89,8 @@ module ActiveRelation end end - describe 'with the aggregation on the left' do + describe 'with the expression on the left' do it 'manufactures sql joining the right table to a derived table' do - pending Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like(""" SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`name`, `users`.`id` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` @@ -96,7 +100,7 @@ module ActiveRelation end end - it "keeps selects on the aggregation within the derived table" do + it "keeps selects on the expression within the derived table" do pending Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb index 8d6a093af242b..e792eec3b8f1f 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/relations/projection_spec.rb @@ -9,6 +9,10 @@ module ActiveRelation @attribute2 = @relation2[:id] end + it "needs to test that [] is limited" do + pending + end + describe '==' do it "obtains if the relations and attributes are identical" do Projection.new(@relation1, @attribute1, @attribute2).should == Projection.new(@relation1, @attribute1, @attribute2) diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index 05330206e0385..e28487b373d97 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -10,10 +10,6 @@ module ActiveRelation end describe '[]' do - it "manufactures an attribute when given a symbol" do - @relation1[:id].should == Attribute.new(@relation1, :id) - end - it "manufactures a range relation when given a range" do @relation1[1..2].should == Range.new(@relation1, 1..2) end @@ -25,7 +21,7 @@ module ActiveRelation end end - describe '#aggregation?' do + describe '#Expression?' do it "returns false" do @relation1.should_not be_aggregation end @@ -88,9 +84,10 @@ module ActiveRelation end end - describe '#group' do + describe '#aggregate' do it 'manufactures a group relation' do - @relation1.group(@attribute1).should == Group.new(@relation1, @attribute1) + @relation1.aggregate(@expression1, @expression2).group(@attribute1, @attribute2). \ + should == Aggregation.new(@relation1, :expressions => [@expresion, @expression2], :groupings => [@attribute1, @attribute2]) end end end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 1616d5fdb74e1..65ad9c51bd820 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -25,15 +25,61 @@ module ActiveRelation describe '#attributes' do it "manufactures a list of attributes with the renamed attribute renameed" do - Rename.new(@relation1, @relation1[:id] => :schmid).attributes.should == - (@relation1.attributes - [@relation1[:id]]) + [@relation1[:id].as(:schmid)] + @renamed_relation.attributes.should include(Attribute.new(@renamed_relation, :id, :schmid)) + @renamed_relation.should have(@relation1.attributes.size).attributes end end describe '[]' do - it 'indexes attributes by rename' do - @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation1[:id].as(:schmid) + describe 'when given a', Symbol do + it 'indexes attributes by rename if the symbol names an attribute within the relation' do + @renamed_relation[:id].should be_nil + @renamed_relation[:schmid].should == Attribute.new(@renamed_relation, :id, :schmid) + @renamed_relation[:does_not_exist].should be_nil + end + end + + describe 'when given an', Attribute do + it 'manufactures a substituted and renamed attribute if the attribute is within the relation' do + @renamed_relation[Attribute.new(@relation1, :id)].should == Attribute.new(@renamed_relation, :id, :schmid) + @renamed_relation[Attribute.new(@relation1, :name)].should == Attribute.new(@renamed_relation, :name) + @renamed_relation[Attribute.new(@renamed_relation, :name)].should == Attribute.new(@renamed_relation, :name) + @renamed_relation[Attribute.new(@relation2, :id)].should be_nil + end + end + + describe 'when given an', Expression do + it "manufactures a substituted and renamed expression if the expression is within the relation" do + end + end + + describe 'when the rename is constructed with a derived attribute' do + before do + @renamed_renamed_relation = Rename.new(@renamed_relation, @relation1[:id] => :flid) + end + + describe 'when given a', Symbol do + it 'manufactures a substituted and renamed attribute if the attribute is within the relation' do + @renamed_renamed_relation[:id].should be_nil + @renamed_renamed_relation[:schmid].should be_nil + @renamed_renamed_relation[:flid].should == Attribute.new(@renamed_renamed_relation, :id, :flid) + end + end + + describe 'when given an', Attribute do + it "manufactures a substituted and renamed attribute if the attribute is within the relation -- even if the provided attribute derived" do + @renamed_renamed_relation[Attribute.new(@renamed_relation, :id, :schmid)].should == Attribute.new(@renamed_renamed_relation, :id, :flid) + @renamed_renamed_relation[Attribute.new(@relation1, :id)].should == Attribute.new(@renamed_renamed_relation, :id, :flid) + end + end + + describe 'when given an', Expression do + it "manufactures a substituted and renamed expression if the expression is within the relation" do + renamed_relation = Rename.new(Aggregation.new(@relation1, :expressions => [@relation1[:id].count]), @relation1[:id].count => :cnt) + renamed_relation[@relation1[:id].count].should == @relation1[:id].count.as(:cnt).substitute(renamed_relation) + renamed_relation.attributes.should == [@relation1[:id].count.as(:cnt).substitute(renamed_relation)] + end + end end end @@ -45,7 +91,7 @@ module ActiveRelation end describe '#to_sql' do - it 'manufactures sql renameing the attribute' do + it 'manufactures sql renaming the attribute' do @renamed_relation.to_sql.should be_like(""" SELECT `foo`.`name`, `foo`.`id` AS 'schmid' FROM `foo` diff --git a/spec/active_relation/relations/schmoin_spec.rb b/spec/active_relation/relations/schmoin_spec.rb deleted file mode 100644 index e5ed9be393cb4..0000000000000 --- a/spec/active_relation/relations/schmoin_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -module ActiveRelation - describe Schmoin do - before do - @relation = Table.new(:users) - photos = Table.new(:photos) - @aggregate_relation = photos.project(photos[:user_id], photos[:id].count).rename(photos[:id].count, :cnt) \ - .group(photos[:user_id]).as(:photo_count) - @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) - end - - describe '#to_sql' do - it 'manufactures sql joining the two tables on the predicate, merging the selects' do - Schmoin.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` - ON `photo_count`.`user_id` = `users`.`id` - """) - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index c8679707f5e3a..140346e6f62ee 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -6,6 +6,32 @@ module ActiveRelation @relation = Table.new(:users) end + describe '[]' do + describe 'when given a', Symbol do + it "manufactures an attribute if the symbol names an attribute within the relation" do + @relation[:id].should == Attribute.new(@relation, :id) + @relation[:does_not_exist].should be_nil + end + end + + describe 'when given an', Attribute do + it "returns the attribute if the attribute is within the relation" do + @relation[Attribute.new(@relation, :id)].should == Attribute.new(@relation, :id) + @relation[Attribute.new(another_relation = Table.new(:photos), :id)].should be_nil + end + end + + describe 'when given an', Expression do + before do + @expression = Expression.new(Attribute.new(@relation, :id), "COUNT") + end + + it "returns the Expression if the Expression is within the relation" do + @relation[@expression].should be_nil + end + end + end + describe '#to_sql' do it "manufactures a simple select query" do @relation.to_sql.should be_like(""" @@ -26,9 +52,7 @@ module ActiveRelation describe '#qualify' do it 'manufactures a rename relation with all attribute names qualified' do - @relation.qualify.should == Rename.new( - Rename.new(@relation, @relation[:id] => 'users.id'), @relation[:name] => 'users.name' - ) + @relation.qualify.should == Rename.new(@relation, @relation[:id] => 'users.id', @relation[:name] => 'users.name') end end end From b6c0de24fadc6b9e124a36aa35718edc027130de Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 3 Feb 2008 22:10:38 -0800 Subject: [PATCH 0052/1492] this is very messy but it is finally close to feature-complete --- lib/active_relation/extensions/object.rb | 4 ++ lib/active_relation/predicates.rb | 4 ++ lib/active_relation/primitives/attribute.rb | 29 ++++++++--- lib/active_relation/primitives/expression.rb | 50 +++++++++++++++++++ lib/active_relation/relations/aggregation.rb | 11 ++-- lib/active_relation/relations/alias.rb | 6 ++- lib/active_relation/relations/compound.rb | 12 +---- lib/active_relation/relations/join.rb | 18 +++++-- lib/active_relation/relations/relation.rb | 12 ++--- lib/active_relation/relations/rename.rb | 14 ++---- lib/active_relation/relations/selection.rb | 2 +- lib/active_relation/relations/table.rb | 12 +++-- .../primitives/attribute_spec.rb | 25 +++------- .../relations/compound_spec.rb | 15 +++--- spec/active_relation/relations/join_spec.rb | 12 +++-- spec/active_relation/relations/rename_spec.rb | 28 ++++++----- spec/active_relation/relations/table_spec.rb | 31 +++++++----- 17 files changed, 180 insertions(+), 105 deletions(-) create mode 100644 lib/active_relation/primitives/expression.rb diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 2d43120f70f93..1db4c845be574 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -3,6 +3,10 @@ def qualify self end + def substitute(relation) + self + end + def to_sql(strategy = ActiveRelation::Sql::Scalar.new) strategy.scalar self end diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 55a6c852e2952..54cc1fa5a0929 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -19,6 +19,10 @@ def ==(other) def qualify self.class.new(attribute.qualify, operand.qualify) end + + def substitute(relation) + self.class.new(attribute.substitute(relation), operand.substitute(relation)) + end def to_sql(strategy = Sql::Predicate.new) "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 8d40a4141f72e..c17118f1e8062 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -1,18 +1,18 @@ module ActiveRelation class Attribute - attr_reader :relation, :name, :alias + attr_reader :relation, :name, :alias, :ancestor - def initialize(relation, name, aliaz = nil) - @relation, @name, @alias = relation, name, aliaz + def initialize(relation, name, aliaz = nil, ancestor = nil) + @relation, @name, @alias, @ancestor = relation, name, aliaz, ancestor end module Transformations def as(aliaz = nil) - Attribute.new(relation, name, aliaz) + Attribute.new(relation, name, aliaz, self) end def substitute(new_relation) - Attribute.new(new_relation, name, @alias) + relation == new_relation ? self : Attribute.new(new_relation, name, @alias, self) end def qualify @@ -26,11 +26,19 @@ def to_attribute include Transformations def qualified_name - "#{relation.name}.#{name}" + "#{prefix}.#{name}" end def ==(other) - self.class == other.class and relation == other.relation and name == other.name and @alias == other.alias + self.class == other.class and relation == other.relation and name == other.name and @alias == other.alias and ancestor == other.ancestor + end + + def =~(other) + !(history & other.history).empty? + end + + def history + [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) end module Predications @@ -84,7 +92,12 @@ def average include Expressions def to_sql(strategy = Sql::Predicate.new) - strategy.attribute relation.name, name, self.alias + strategy.attribute prefix, name, self.alias + end + + private + def prefix + relation.prefix_for(self) end end end \ No newline at end of file diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb new file mode 100644 index 0000000000000..47658c49da9c5 --- /dev/null +++ b/lib/active_relation/primitives/expression.rb @@ -0,0 +1,50 @@ +module ActiveRelation + class Expression + include Sql::Quoting + + attr_reader :attribute, :function_sql, :alias, :ancestor + delegate :relation, :to => :attribute + + def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) + @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor + end + + module Transformations + def substitute(new_relation) + Expression.new(attribute.substitute(new_relation), function_sql, @alias, self) + end + + def as(aliaz) + # key line -- note self + Expression.new(attribute, function_sql, aliaz, self) + end + + def to_attribute + # key line -- note self + Attribute.new(relation, @alias, nil, self) + end + end + include Transformations + + def to_sql(strategy = nil) + "#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '') + end + + def ==(other) + self.class == other.class and attribute == other.attribute and function_sql == other.function_sql and ancestor == other.ancestor and @alias == other.alias + end + alias_method :eql?, :== + + def hash + attribute.hash + function_sql.hash + end + + def =~(other) + !(history & other.history).empty? + end + + def history + [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index 161a7485676b9..efa6ea260c3c4 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -1,27 +1,26 @@ module ActiveRelation class Aggregation < Compound attr_reader :expressions, :groupings - alias_method :attributes, :expressions def initialize(relation, options) @relation, @expressions, @groupings = relation, options[:expressions], options[:groupings] end def ==(other) - relation == other.relation and groupings == other.groupings and expressions == other.expressions + self.class == other.class and relation == other.relation and groupings == other.groupings and expressions == other.expressions end def qualify Aggregation.new(relation.qualify, :expressions => expressions.collect(&:qualify), :groupings => groupings.collect(&:qualify)) end + def attributes + expressions.collect { |e| e.substitute(self) } + end + protected def aggregation? true end - - def attribute_for_expression(expression) - expression.relation == self ? expression : (e = @expressions.detect { |e| e == expression }) && e.substitute(self) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 5460413b25926..7b03a8c2ab9c1 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -1,13 +1,17 @@ module ActiveRelation class Alias < Compound attr_reader :alias + + def aliased_prefix_for(attribute) + @alias + end def initialize(relation, aliaz) @relation, @alias = relation, aliaz end def ==(other) - relation == other.relation and @alias == other.alias + self.class == other.class and relation == other.relation and @alias == other.alias end end end \ No newline at end of file diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 7c4a7e707b38e..776620732d8f6 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,7 +2,7 @@ module ActiveRelation class Compound < Relation attr_reader :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, - :offset, :name, :alias, :aggregation?, + :offset, :name, :alias, :aggregation?, :prefix_for, :aliased_prefix_for, :to => :relation def attributes @@ -11,15 +11,7 @@ def attributes protected def attribute_for_name(name) - (a = relation[name]) && a.substitute(self) - end - - def attribute_for_attribute(attribute) - attribute.relation == self ? attribute : (a = relation[attribute]) && a.substitute(self) - end - - def attribute_for_expression(expression) - expression.relation == self ? expression : (a = relation[expression]) && a.substitute(self) + relation[name].substitute(self) rescue nil end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index dfc9992f0bc44..0327b5cd87536 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -7,7 +7,8 @@ def initialize(join_sql, relation1, relation2, *predicates) end def ==(other) - predicates == other.predicates and + self.class == other.class and + predicates == other.predicates and ((relation1 == other.relation1 and relation2 == other.relation2) or (relation2 == other.relation1 and relation1 == other.relation2)) end @@ -20,8 +21,15 @@ def attributes [ relation1.aggregation?? relation1.attributes.collect(&:to_attribute) : relation1.attributes, relation2.aggregation?? relation2.attributes.collect(&:to_attribute) : relation2.attributes, - ].flatten + ].flatten.collect { |a| a.substitute(self) } end + + def prefix_for(attribute) + # test me + (relation1[attribute] && relation1.aliased_prefix_for(attribute)) || + (relation2[attribute] && relation2.aliased_prefix_for(attribute)) + end + alias_method :aliased_prefix_for, :prefix_for protected def joins @@ -36,11 +44,11 @@ def selects end def attribute_for_name(name) - relation1[name] || relation2[name] + (relation1[name] || relation2[name]) end def attribute_for_attribute(attribute) - relation1[attribute] || relation2[attribute] + (relation1[attribute] || relation2[attribute]) end def table_sql @@ -49,7 +57,7 @@ def table_sql private def join - [join_sql, right_table_sql, "ON", predicates.collect { |p| p.to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") + [join_sql, right_table_sql, "ON", predicates.collect { |p| p.substitute(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") end def right_table_sql diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 838697a2ac4cd..0f770e674c30e 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -30,10 +30,8 @@ def [](index) attribute_for_name(index) when ::Range Range.new(self, index) - when Attribute + when Attribute, Expression attribute_for_attribute(index) - when Expression - attribute_for_expression(index) end end @@ -110,12 +108,12 @@ def connection ActiveRecord::Base.connection end - def attribute_for_attribute(attribute) - self == attribute.relation ? attribute : nil + def attribute_for_name(name) + nil end - def attribute_for_expression(expression) - nil + def attribute_for_attribute(attribute) + attributes.detect { |a| a =~ attribute } end def attributes; [] end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 8942ffbe29a53..8d92e9422cdc5 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -23,22 +23,14 @@ def attributes def attribute_for_name(name) case when referring_by_autonym?(name) then nil - when referring_by_pseudonym?(name) then attribute.as(pseudonym).substitute(self) - else (a = relation[name]) && a.substitute(self) + when referring_by_pseudonym?(name) then substitute(relation[attribute]) + else relation[name].substitute(self) rescue nil end end - - def attribute_for_attribute(attribute) - attribute.relation == self ? attribute : substitute(relation[attribute]) - end - - def attribute_for_expression(expression) - expression.relation == self ? expression : substitute(relation[expression]) - end private def substitute(attribute) - (relation[attribute] == relation[self.attribute] ? attribute.as(pseudonym) : attribute).substitute(self) if attribute + (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).substitute(self) rescue nil end def referring_by_autonym?(name) diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index 3ecea059d5121..5f1726d3810ec 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -8,7 +8,7 @@ def initialize(relation, *predicates) end def ==(other) - relation == other.relation and predicate == other.predicate + self.class == other.class and relation == other.relation and predicate == other.predicate end def qualify diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index ffc9077076756..9e58404a517fd 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -14,15 +14,19 @@ def qualify Rename.new self, qualifications end - def inspect - "" + def prefix_for(attribute) + name end - + + def aliased_prefix_for(attribute) + name + end + protected def attribute_for_name(name) attributes_by_name[name.to_s] end - + def table_sql "#{quote_table_name(name)}" end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index f76018c49361a..0c6c44f1f4b15 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -14,19 +14,19 @@ module ActiveRelation describe '#as' do it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation1, @attribute.name, :alias) + @attribute.as(:alias).should == Attribute.new(@relation1, @attribute.name, :alias, @attribute) end end describe '#substitute' do it "manufactures an attribute with the relation substituted" do - @attribute.substitute(@relation2).should == Attribute.new(@relation2, @attribute.name) + @attribute.substitute(@relation2).should == Attribute.new(@relation2, @attribute.name, nil, @attribute) end end describe '#qualify' do it "manufactures an attribute aliased with that attributes qualified name" do - @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, @attribute.qualified_name) + @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, @attribute.qualified_name, @attribute) end end @@ -53,6 +53,10 @@ module ActiveRelation end describe '#to_sql' do + it "needs to test prefix_for" do + pending + end + describe Sql::Strategy do it "manufactures sql without an alias if the strategy is Predicate" do Attribute.new(@relation1, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`foo`.`name`") @@ -62,19 +66,6 @@ module ActiveRelation Attribute.new(@relation1, :name, :alias).to_sql(Sql::Projection.new).should be_like("`foo`.`name` AS 'alias'") end end - - describe 'binding' do - before do - @attribute = Attribute.new(@relation1, :name, :alias) - @aliased_relation = @relation1.as(:schmoo) - end - - it "is fancy pants" do - pending - @attribute.to_sql.should be_like("`foo`.`name`") - @attribute.substitute(@aliased_relation).to_sql.should be_like("`schmoo`.`alias`") - end - end end describe Attribute::Predications do @@ -120,7 +111,7 @@ module ActiveRelation end end - describe 'Expressions' do + describe Attribute::Expressions do before do @attribute1 = Attribute.new(@relation1, :name) end diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/relations/compound_spec.rb index a03b0206a985e..79ac965e63b89 100644 --- a/spec/active_relation/relations/compound_spec.rb +++ b/spec/active_relation/relations/compound_spec.rb @@ -14,35 +14,36 @@ def initialize(relation) describe '#attributes' do it 'manufactures attributes associated with the compound relation' do - @compound_relation.attributes.should == @relation.attributes.collect { |a| Attribute.new(@compound_relation, a.name) } + @compound_relation.attributes.should == @relation.attributes.collect { |a| a.substitute(@compound_relation) } end end describe '[]' do describe 'when given a', Symbol do it 'manufactures attributes associated with the compound relation if the symbol names an attribute within the relation' do - @compound_relation[:id].relation.should == @compound_relation + @compound_relation[:id].should == @relation[:id].substitute(@compound_relation) @compound_relation[:does_not_exist].should be_nil end end describe 'when given an', Attribute do it "manufactures a substituted attribute when given an attribute within the relation" do - @compound_relation[Attribute.new(@relation, :id)].should == Attribute.new(@compound_relation, :id) - @compound_relation[Attribute.new(@compound_relation, :id)].should == Attribute.new(@compound_relation, :id) - @compound_relation[Attribute.new(another_relation = Table.new(:photos), :id)].should be_nil + @compound_relation[@relation[:id]].should == @relation[:id].substitute(@compound_relation) + @compound_relation[@compound_relation[:id]].should == @compound_relation[:id] + pending "test nil" end end describe 'when given an', Expression do before do @nested_expression = Expression.new(Attribute.new(@relation, :id), "COUNT") + @nested_relation = Aggregation.new(@relation, :expressions => [@nested_expression]) @unprojected_expression = Expression.new(Attribute.new(@relation, :id), "SUM") - @compound_relation = ConcreteCompound.new(Aggregation.new(@relation, :expressions => [@nested_expression])) + @compound_relation = ConcreteCompound.new(@nested_relation) end it "manufactures a substituted Expression when given an Expression within the relation" do - @compound_relation[@nested_expression].should == @nested_expression.substitute(@compound_relation) + @compound_relation[@nested_expression].should == @nested_relation[@nested_expression].substitute(@compound_relation) @compound_relation[@compound_relation[@expression]].should == @compound_relation[@expression] @compound_relation[@unprojected_expression].should be_nil end diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 5235a5b528395..52915b62c72b9 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -34,9 +34,13 @@ module ActiveRelation describe '#attributes' do describe 'with simple relations' do + before do + @join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) + end + it 'combines the attributes of the two relations' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).attributes.should == - @relation1.attributes + @relation2.attributes + @join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.substitute(@join) } end end @@ -73,8 +77,8 @@ module ActiveRelation before do @relation = Table.new(:users) photos = Table.new(:photos) - @aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]).rename(photos[:id].count, :cnt) \ - .as(:photo_count) + aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]) + @aggregate_relation = aggregate_relation.rename(photos[:id].count, :cnt).as(:photo_count) @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 65ad9c51bd820..ebe95f13b9507 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -25,7 +25,7 @@ module ActiveRelation describe '#attributes' do it "manufactures a list of attributes with the renamed attribute renameed" do - @renamed_relation.attributes.should include(Attribute.new(@renamed_relation, :id, :schmid)) + @renamed_relation.attributes.should include(@renamed_relation[:schmid]) @renamed_relation.should have(@relation1.attributes.size).attributes end end @@ -34,17 +34,17 @@ module ActiveRelation describe 'when given a', Symbol do it 'indexes attributes by rename if the symbol names an attribute within the relation' do @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == Attribute.new(@renamed_relation, :id, :schmid) + @renamed_relation[:schmid].should == @relation1[:id].as(:schmid).substitute(@renamed_relation) @renamed_relation[:does_not_exist].should be_nil end end describe 'when given an', Attribute do it 'manufactures a substituted and renamed attribute if the attribute is within the relation' do - @renamed_relation[Attribute.new(@relation1, :id)].should == Attribute.new(@renamed_relation, :id, :schmid) - @renamed_relation[Attribute.new(@relation1, :name)].should == Attribute.new(@renamed_relation, :name) - @renamed_relation[Attribute.new(@renamed_relation, :name)].should == Attribute.new(@renamed_relation, :name) - @renamed_relation[Attribute.new(@relation2, :id)].should be_nil + @renamed_relation[@relation1[:id]].should == @relation1[:id].as(:schmid).substitute(@renamed_relation) + @renamed_relation[@relation1[:name]].should == @relation1[:name].substitute(@renamed_relation) + @renamed_relation[@renamed_relation[:name]].should == @renamed_relation[:name] + @renamed_relation[@relation2[:id]].should be_nil end end @@ -62,22 +62,26 @@ module ActiveRelation it 'manufactures a substituted and renamed attribute if the attribute is within the relation' do @renamed_renamed_relation[:id].should be_nil @renamed_renamed_relation[:schmid].should be_nil - @renamed_renamed_relation[:flid].should == Attribute.new(@renamed_renamed_relation, :id, :flid) + @renamed_renamed_relation[:flid].should == @renamed_relation[:schmid].as(:flid).substitute(@renamed_renamed_relation) end end describe 'when given an', Attribute do it "manufactures a substituted and renamed attribute if the attribute is within the relation -- even if the provided attribute derived" do - @renamed_renamed_relation[Attribute.new(@renamed_relation, :id, :schmid)].should == Attribute.new(@renamed_renamed_relation, :id, :flid) - @renamed_renamed_relation[Attribute.new(@relation1, :id)].should == Attribute.new(@renamed_renamed_relation, :id, :flid) + @renamed_renamed_relation[@renamed_relation[:schmid]].should == @renamed_relation[:schmid].as(:flid).substitute(@renamed_renamed_relation) + @renamed_renamed_relation[@relation1[:id]].should == @renamed_relation[:schmid].as(:flid).substitute(@renamed_renamed_relation) end end describe 'when given an', Expression do + before do + @expression = @relation1[:id].count + @aggregation = Aggregation.new(@relation1, :expressions => [@expression]) + @renamed_relation = Rename.new(@aggregation, @expression => :cnt) + end + it "manufactures a substituted and renamed expression if the expression is within the relation" do - renamed_relation = Rename.new(Aggregation.new(@relation1, :expressions => [@relation1[:id].count]), @relation1[:id].count => :cnt) - renamed_relation[@relation1[:id].count].should == @relation1[:id].count.as(:cnt).substitute(renamed_relation) - renamed_relation.attributes.should == [@relation1[:id].count.as(:cnt).substitute(renamed_relation)] + @renamed_relation[@expression].should == @aggregation[@expression].as(:cnt).substitute(@renamed_relation) end end end diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 140346e6f62ee..02e669a08b43f 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -3,56 +3,63 @@ module ActiveRelation describe Table do before do - @relation = Table.new(:users) + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) end describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do - @relation[:id].should == Attribute.new(@relation, :id) - @relation[:does_not_exist].should be_nil + @relation1[:id].should == Attribute.new(@relation1, :id) + @relation1[:does_not_exist].should be_nil end end describe 'when given an', Attribute do it "returns the attribute if the attribute is within the relation" do - @relation[Attribute.new(@relation, :id)].should == Attribute.new(@relation, :id) - @relation[Attribute.new(another_relation = Table.new(:photos), :id)].should be_nil + @relation1[@relation1[:id]].should == @relation1[:id] + @relation1[@relation2[:id]].should be_nil end end describe 'when given an', Expression do before do - @expression = Expression.new(Attribute.new(@relation, :id), "COUNT") + @expression = Expression.new(Attribute.new(@relation1, :id), "COUNT") end it "returns the Expression if the Expression is within the relation" do - @relation[@expression].should be_nil + @relation1[@expression].should be_nil end end end describe '#to_sql' do it "manufactures a simple select query" do - @relation.to_sql.should be_like(""" + @relation1.to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id` FROM `users` """) end end + + describe '#prefix_for' do + it "always returns the table name" do + @relation1.prefix_for(Attribute.new(@relation1, :id)).should == :users + end + end describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do - @relation.attributes.should == [ - Attribute.new(@relation, :name), - Attribute.new(@relation, :id) + @relation1.attributes.should == [ + Attribute.new(@relation1, :name), + Attribute.new(@relation1, :id) ] end end describe '#qualify' do it 'manufactures a rename relation with all attribute names qualified' do - @relation.qualify.should == Rename.new(@relation, @relation[:id] => 'users.id', @relation[:name] => 'users.name') + @relation1.qualify.should == Rename.new(@relation1, @relation1[:id] => 'users.id', @relation1[:name] => 'users.name') end end end From 7523c8690deda1b24def03eb049f61baf2f1b466 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 4 Feb 2008 20:36:17 -0800 Subject: [PATCH 0053/1492] cleaning up code and adding test coverage for attribute and expression. --- lib/active_relation/primitives/attribute.rb | 19 +++-- lib/active_relation/primitives/expression.rb | 13 ++-- .../active_relation/predicates/binary_spec.rb | 7 ++ .../primitives/attribute_spec.rb | 71 ++++++++++--------- .../primitives/expression_spec.rb | 56 +++++++++++++++ spec/active_relation/relations/join_spec.rb | 10 ++- spec/active_relation/relations/table_spec.rb | 38 ++++++---- 7 files changed, 147 insertions(+), 67 deletions(-) create mode 100644 spec/active_relation/primitives/expression_spec.rb diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index c17118f1e8062..e6df5cd87ce19 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -30,17 +30,18 @@ def qualified_name end def ==(other) - self.class == other.class and relation == other.relation and name == other.name and @alias == other.alias and ancestor == other.ancestor + self.class == other.class and + relation == other.relation and + name == other.name and + @alias == other.alias and + ancestor == other.ancestor end + alias_method :eql?, :== def =~(other) - !(history & other.history).empty? + !(history & other.send(:history)).empty? end - def history - [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) - end - module Predications def equals(other) Equality.new(self, other) @@ -96,8 +97,14 @@ def to_sql(strategy = Sql::Predicate.new) end private + delegate :hash, :to => :relation + def prefix relation.prefix_for(self) end + + def history + [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) + end end end \ No newline at end of file diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index 47658c49da9c5..a64219e9d156b 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -11,7 +11,7 @@ def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) module Transformations def substitute(new_relation) - Expression.new(attribute.substitute(new_relation), function_sql, @alias, self) + new_relation == relation ? self : Expression.new(attribute.substitute(new_relation), function_sql, @alias, self) end def as(aliaz) @@ -34,17 +34,18 @@ def ==(other) self.class == other.class and attribute == other.attribute and function_sql == other.function_sql and ancestor == other.ancestor and @alias == other.alias end alias_method :eql?, :== + + def =~(other) + !(history & other.send(:history)).empty? + end + private def hash attribute.hash + function_sql.hash end - def =~(other) - !(history & other.history).empty? - end - def history - [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) + [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index a6878e4898bad..5d1e7d12239a3 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -32,6 +32,13 @@ def predicate_sql should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) end end + + describe '#substitute' do + it "distributes over the predicates and attributes" do + ConcreteBinary.new(@attribute1, @attribute2).substitute(@relation2). \ + should == ConcreteBinary.new(@attribute1.substitute(@relation2), @attribute2.substitute(@relation2)) + end + end describe '#to_sql' do it 'manufactures correct sql' do diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 0c6c44f1f4b15..e79f0c994d3fb 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -3,24 +3,28 @@ module ActiveRelation describe Attribute do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) + @relation = Table.new(:users) end describe Attribute::Transformations do before do - @attribute = Attribute.new(@relation1, :id) + @attribute = Attribute.new(@relation, :id) end describe '#as' do it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation1, @attribute.name, :alias, @attribute) + @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias, @attribute) end end describe '#substitute' do - it "manufactures an attribute with the relation substituted" do - @attribute.substitute(@relation2).should == Attribute.new(@relation2, @attribute.name, nil, @attribute) + it "manufactures an attribute with the relation substituted and self as an ancestor" do + derived_relation = @relation.select(@relation[:id].equals(1)) + @attribute.substitute(derived_relation).should == Attribute.new(derived_relation, @attribute.name, nil, @attribute) + end + + it "returns self if the substituting to the same relation" do + @attribute.substitute(@relation).should == @attribute end end @@ -39,110 +43,107 @@ module ActiveRelation describe '#qualified_name' do it "manufactures an attribute name prefixed with the relation's name" do - Attribute.new(@relation1, :id).qualified_name.should == 'foo.id' + Attribute.new(@relation, :id).qualified_name.should == 'users.id' end end - - describe '==' do - it "obtains if the relation and attribute name are identical" do - Attribute.new(@relation1, :name).should == Attribute.new(@relation1, :name) - Attribute.new(@relation1, :name).should_not == Attribute.new(@relation1, :another_name) - Attribute.new(@relation1, :name).should_not == Attribute.new(@relation2, :name) - Attribute.new(@relation1, :name).should_not == Expression.new(Attribute.new(@relation1, :name), "SUM") + + describe '=~' do + it "obtains if the attributes are identical" do + Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name) + end + + it "obtains if the attributes have an overlapping history" do + Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)).should =~ Attribute.new(@relation, :name) + Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)) end end describe '#to_sql' do - it "needs to test prefix_for" do - pending - end - describe Sql::Strategy do it "manufactures sql without an alias if the strategy is Predicate" do - Attribute.new(@relation1, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`foo`.`name`") + Attribute.new(@relation, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`users`.`name`") end it "manufactures sql with an alias if the strategy is Projection" do - Attribute.new(@relation1, :name, :alias).to_sql(Sql::Projection.new).should be_like("`foo`.`name` AS 'alias'") + Attribute.new(@relation, :name, :alias).to_sql(Sql::Projection.new).should be_like("`users`.`name` AS 'alias'") end end end describe Attribute::Predications do before do - @attribute1 = Attribute.new(@relation1, :name) - @attribute2 = Attribute.new(@relation2, :name) + @attribute = Attribute.new(@relation, :name) end describe '#equals' do it "manufactures an equality predicate" do - @attribute1.equals(@attribute2).should == Equality.new(@attribute1, @attribute2) + @attribute.equals('name').should == Equality.new(@attribute, 'name') end end describe '#less_than' do it "manufactures a less-than predicate" do - @attribute1.less_than(@attribute2).should == LessThan.new(@attribute1, @attribute2) + @attribute.less_than(10).should == LessThan.new(@attribute, 10) end end describe '#less_than_or_equal_to' do it "manufactures a less-than or equal-to predicate" do - @attribute1.less_than_or_equal_to(@attribute2).should == LessThanOrEqualTo.new(@attribute1, @attribute2) + @attribute.less_than_or_equal_to(10).should == LessThanOrEqualTo.new(@attribute, 10) end end describe '#greater_than' do it "manufactures a greater-than predicate" do - @attribute1.greater_than(@attribute2).should == GreaterThan.new(@attribute1, @attribute2) + @attribute.greater_than(10).should == GreaterThan.new(@attribute, 10) end end describe '#greater_than_or_equal_to' do - it "manufactures a greater-than or equal to predicate" do - @attribute1.greater_than_or_equal_to(@attribute2).should == GreaterThanOrEqualTo.new(@attribute1, @attribute2) + it "manufactures a greater-than or equal-to predicate" do + @attribute.greater_than_or_equal_to(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end describe '#matches' do it "manufactures a match predicate" do - @attribute1.matches(/.*/).should == Match.new(@attribute1, @attribute2) + @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end end describe Attribute::Expressions do before do - @attribute1 = Attribute.new(@relation1, :name) + @attribute = Attribute.new(@relation, :name) end describe '#count' do it "manufactures a count Expression" do - @attribute1.count.should == Expression.new(@attribute1, "COUNT") + @attribute.count.should == Expression.new(@attribute, "COUNT") end end describe '#sum' do it "manufactures a sum Expression" do - @attribute1.sum.should == Expression.new(@attribute1, "SUM") + @attribute.sum.should == Expression.new(@attribute, "SUM") end end describe '#maximum' do it "manufactures a maximum Expression" do - @attribute1.maximum.should == Expression.new(@attribute1, "MAX") + @attribute.maximum.should == Expression.new(@attribute, "MAX") end end describe '#minimum' do it "manufactures a minimum Expression" do - @attribute1.minimum.should == Expression.new(@attribute1, "MIN") + @attribute.minimum.should == Expression.new(@attribute, "MIN") end end describe '#average' do it "manufactures an average Expression" do - @attribute1.average.should == Expression.new(@attribute1, "AVG") + @attribute.average.should == Expression.new(@attribute, "AVG") end end end diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/primitives/expression_spec.rb new file mode 100644 index 0000000000000..d699dfded0962 --- /dev/null +++ b/spec/active_relation/primitives/expression_spec.rb @@ -0,0 +1,56 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') + +module ActiveRelation + describe Expression do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Expression::Transformations do + before do + @expression = Expression.new(@attribute, "COUNT") + end + + describe '#substitute' do + it "manufactures an attribute with a substituted relation and self as the ancestor" do + derived_relation = @relation.select(@relation[:id] == 1) + @expression.substitute(derived_relation).should == Expression.new(@attribute.substitute(derived_relation), "COUNT", nil, @expression) + end + + it "returns self if the substituting to the same relation" do + @expression.substitute(@relation).should == @expression + end + end + + describe '#as' do + it "manufactures an aliased expression" do + @expression.as(:foo).should == Expression.new(@attribute, "COUNT", :foo, @expression) + end + end + + describe '#to_attribute' do + it "manufactures an attribute with the expression as an ancestor" do + @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, nil, @expression) + end + end + end + + describe '=~' do + it "obtains if the expressions are identical" do + Expression.new(@attribute, "COUNT").should =~ Expression.new(@attribute, "COUNT") + end + + it "obtains if the expressions have an overlapping history" do + Expression.new(@attribute, "COUNT", nil, Expression.new(@attribute, "COUNT")).should =~ Expression.new(@attribute, "COUNT") + Expression.new(@attribute, "COUNT").should =~ Expression.new(@attribute, "COUNT", nil, Expression.new(@attribute, "COUNT")) + end + end + + describe '#to_sql' do + it "manufactures sql with the expression and alias" do + Expression.new(@attribute, "COUNT", :alias).to_sql.should == "COUNT(`users`.`id`) AS `alias`" + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 52915b62c72b9..2df349dcd3284 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -77,12 +77,11 @@ module ActiveRelation before do @relation = Table.new(:users) photos = Table.new(:photos) - aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]) - @aggregate_relation = aggregate_relation.rename(photos[:id].count, :cnt).as(:photo_count) + @aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]).rename(photos[:id].count, :cnt).as(:photo_count) @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) end - describe 'with the expression on the right' do + describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` @@ -93,7 +92,7 @@ module ActiveRelation end end - describe 'with the expression on the left' do + describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like(""" SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`name`, `users`.`id` @@ -104,8 +103,7 @@ module ActiveRelation end end - it "keeps selects on the expression within the derived table" do - pending + it "keeps selects on the aggregation within the derived table" do Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 02e669a08b43f..e48d259fb8be9 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -3,39 +3,43 @@ module ActiveRelation describe Table do before do - @relation1 = Table.new(:users) + @table = Table.new(:users) @relation2 = Table.new(:photos) end describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do - @relation1[:id].should == Attribute.new(@relation1, :id) - @relation1[:does_not_exist].should be_nil + @table[:id].should == Attribute.new(@table, :id) + @table[:does_not_exist].should be_nil end end describe 'when given an', Attribute do it "returns the attribute if the attribute is within the relation" do - @relation1[@relation1[:id]].should == @relation1[:id] - @relation1[@relation2[:id]].should be_nil + @table[@table[:id]].should == @table[:id] + end + + it "returns nil if the attribtue is not within the relation" do + another_relation = Table.new(:photos) + @table[another_relation[:id]].should be_nil end end describe 'when given an', Expression do before do - @expression = Expression.new(Attribute.new(@relation1, :id), "COUNT") + @expression = Expression.new(Attribute.new(@table, :id), "COUNT") end it "returns the Expression if the Expression is within the relation" do - @relation1[@expression].should be_nil + @table[@expression].should be_nil end end end describe '#to_sql' do it "manufactures a simple select query" do - @relation1.to_sql.should be_like(""" + @table.to_sql.should be_like(""" SELECT `users`.`name`, `users`.`id` FROM `users` """) @@ -43,23 +47,29 @@ module ActiveRelation end describe '#prefix_for' do - it "always returns the table name" do - @relation1.prefix_for(Attribute.new(@relation1, :id)).should == :users + it "returns the table name" do + @table.prefix_for(Attribute.new(@table, :id)).should == :users + end + end + + describe '#aliased_prefix_for' do + it "returns the table name" do + @table.aliased_prefix_for(Attribute.new(@table, :id)).should == :users end end describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do - @relation1.attributes.should == [ - Attribute.new(@relation1, :name), - Attribute.new(@relation1, :id) + @table.attributes.should == [ + Attribute.new(@table, :name), + Attribute.new(@table, :id) ] end end describe '#qualify' do it 'manufactures a rename relation with all attribute names qualified' do - @relation1.qualify.should == Rename.new(@relation1, @relation1[:id] => 'users.id', @relation1[:name] => 'users.name') + @table.qualify.should == Rename.new(@table, @table[:name] => 'users.name', @table[:id] => 'users.id') end end end From 61d6c2c1c5215014971355892e024682ed148ebb Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 4 Feb 2008 22:00:11 -0800 Subject: [PATCH 0054/1492] nk - missing file? --- spec/active_relation/relations/alias_spec.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb index c02b0df453d0e..ddb0c59d087bc 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/relations/alias_spec.rb @@ -4,7 +4,19 @@ module ActiveRelation describe Alias do before do @relation = Table.new(:users) - @alias_relation = @relation.as(:foo) + @alias_relation = Alias.new(@relation, :foo) + end + + describe '#prefix_for' do + it "delegates to the underlying relation" do + @alias_relation.prefix_for(@relation[:id]).should == :users + end + end + + describe '#aliased_prefix_for' do + it "returns the alias" do + @alias_relation.aliased_prefix_for(@relation[:id]).should == :foo + end end end end \ No newline at end of file From 29d9b8e9b5899a8c52326dfca9343e79ba049d6b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 11 Feb 2008 22:56:12 -0800 Subject: [PATCH 0055/1492] removing code complexity concerning attribute lookup. --- lib/active_relation/primitives/attribute.rb | 10 +++++-- lib/active_relation/primitives/expression.rb | 3 -- lib/active_relation/relations/compound.rb | 5 ---- lib/active_relation/relations/join.rb | 8 ----- lib/active_relation/relations/relation.rb | 2 +- lib/active_relation/relations/rename.rb | 17 ----------- lib/active_relation/relations/table.rb | 14 ++------- .../integration/scratch_spec.rb | 8 ++--- spec/active_relation/relations/join_spec.rb | 26 ++++++++--------- spec/active_relation/relations/order_spec.rb | 18 +++++------- spec/active_relation/relations/range_spec.rb | 18 +++++------- spec/active_relation/relations/rename_spec.rb | 11 +++---- .../relations/selection_spec.rb | 29 +++++++++---------- spec/active_relation/relations/table_spec.rb | 6 ++-- 14 files changed, 68 insertions(+), 107 deletions(-) diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index e6df5cd87ce19..893feefef2eb5 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -5,6 +5,10 @@ class Attribute def initialize(relation, name, aliaz = nil, ancestor = nil) @relation, @name, @alias, @ancestor = relation, name, aliaz, ancestor end + + def alias_or_name + @alias || name + end module Transformations def as(aliaz = nil) @@ -96,9 +100,11 @@ def to_sql(strategy = Sql::Predicate.new) strategy.attribute prefix, name, self.alias end - private - delegate :hash, :to => :relation + def hash + relation.hash + name.hash + end + private def prefix relation.prefix_for(self) end diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index a64219e9d156b..ff07c40109766 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -15,12 +15,10 @@ def substitute(new_relation) end def as(aliaz) - # key line -- note self Expression.new(attribute, function_sql, aliaz, self) end def to_attribute - # key line -- note self Attribute.new(relation, @alias, nil, self) end end @@ -39,7 +37,6 @@ def =~(other) !(history & other.send(:history)).empty? end - private def hash attribute.hash + function_sql.hash end diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 776620732d8f6..befb7f26d2085 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -8,10 +8,5 @@ class Compound < Relation def attributes relation.attributes.collect { |a| a.substitute(self) } end - - protected - def attribute_for_name(name) - relation[name].substitute(self) rescue nil - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 0327b5cd87536..5b2efe727f527 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -42,14 +42,6 @@ def selects (relation2.send(:selects) unless relation2.aggregation?) ].compact.flatten end - - def attribute_for_name(name) - (relation1[name] || relation2[name]) - end - - def attribute_for_attribute(attribute) - (relation1[attribute] || relation2[attribute]) - end def table_sql relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 0f770e674c30e..c5409bc9ff609 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -109,7 +109,7 @@ def connection end def attribute_for_name(name) - nil + attributes.detect { |a| a.alias_or_name == name } end def attribute_for_attribute(attribute) diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 8d92e9422cdc5..c41cd1bdc5f37 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -19,26 +19,9 @@ def attributes relation.attributes.collect(&method(:substitute)) end - protected - def attribute_for_name(name) - case - when referring_by_autonym?(name) then nil - when referring_by_pseudonym?(name) then substitute(relation[attribute]) - else relation[name].substitute(self) rescue nil - end - end - private def substitute(attribute) (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).substitute(self) rescue nil end - - def referring_by_autonym?(name) - relation[name] == relation[attribute] - end - - def referring_by_pseudonym?(name) - name == pseudonym - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 9e58404a517fd..d6ab45dceacbc 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -7,7 +7,9 @@ def initialize(name) end def attributes - attributes_by_name.values + @attributes ||= connection.columns(name, "#{name} Columns").collect do |column| + Attribute.new(self, column.name.to_sym) + end end def qualify @@ -23,21 +25,11 @@ def aliased_prefix_for(attribute) end protected - def attribute_for_name(name) - attributes_by_name[name.to_s] - end - def table_sql "#{quote_table_name(name)}" end private - def attributes_by_name - @attributes_by_name ||= connection.columns(name, "#{name} Columns").inject({}) do |attributes_by_name, column| - attributes_by_name.merge(column.name => Attribute.new(self, column.name.to_sym)) - end - end - def qualifications attributes.zip(attributes.collect(&:qualified_name)).to_hash end diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb index a31c2ea9f645e..4b02b22a11fa0 100644 --- a/spec/active_relation/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -101,7 +101,7 @@ def photo_belongs_to_camera(photo_relation) for an association on an individual row' do users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)) users_cameras.to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`, `cameras`.`id` + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`, `cameras`.`id` FROM `users` LEFT OUTER JOIN `photos` ON `users`.`id` = `photos`.`user_id` @@ -113,7 +113,7 @@ def photo_belongs_to_camera(photo_relation) it 'is trivial to disambiguate columns' do users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify users_cameras.to_sql.should be_like(""" - SELECT `users`.`name` AS 'users.name', `users`.`id` AS 'users.id', `photos`.`id` AS 'photos.id', `photos`.`user_id` AS 'photos.user_id', `photos`.`camera_id` AS 'photos.camera_id', `cameras`.`id` AS 'cameras.id' + SELECT `users`.`id` AS 'users.id', `users`.`name` AS 'users.name', `photos`.`id` AS 'photos.id', `photos`.`user_id` AS 'photos.user_id', `photos`.`camera_id` AS 'photos.camera_id', `cameras`.`id` AS 'cameras.id' FROM `users` LEFT OUTER JOIN `photos` ON `users`.`id` = `photos`.`user_id` @@ -124,13 +124,13 @@ def photo_belongs_to_camera(photo_relation) it 'allows arbitrary sql to be passed through' do @users.outer_join(@photos).on("asdf").to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` LEFT OUTER JOIN `photos` ON asdf """) @users.select("asdf").to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id` + SELECT `users`.`id`, `users`.`name` FROM `users` WHERE asdf """) diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 2df349dcd3284..3b2ad88123585 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -3,8 +3,8 @@ module ActiveRelation describe Join do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) @predicate = Equality.new(@relation1[:id], @relation2[:id]) end @@ -55,20 +55,20 @@ module ActiveRelation describe 'with simple relations' do it 'manufactures sql joining the two tables on the predicate' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` - FROM `foo` - INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` ON `users`.`id` = `photos`.`id` """) end it 'manufactures sql joining the two tables, merging any selects' do Join.new("INNER JOIN", @relation1.select(@relation1[:id].equals(1)), @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id`, `bar`.`name`, `bar`.`foo_id`, `bar`.`id` - FROM `foo` - INNER JOIN `bar` ON `foo`.`id` = `bar`.`id` - WHERE `foo`.`id` = 1 - AND `bar`.`id` = 2 + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` ON `users`.`id` = `photos`.`id` + WHERE `users`.`id` = 1 + AND `photos`.`id` = 2 """) end end @@ -84,7 +84,7 @@ module ActiveRelation describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` + SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` ON `photo_count`.`user_id` = `users`.`id` @@ -95,7 +95,7 @@ module ActiveRelation describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like(""" - SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`name`, `users`.`id` + SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`id`, `users`.`name` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` INNER JOIN `users` ON `photo_count`.`user_id` = `users`.`id` @@ -105,7 +105,7 @@ module ActiveRelation it "keeps selects on the aggregation within the derived table" do Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id`, `photo_count`.`user_id`, `photo_count`.`cnt` + SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count` ON `photo_count`.`user_id` = `users`.`id` diff --git a/spec/active_relation/relations/order_spec.rb b/spec/active_relation/relations/order_spec.rb index 204558daec8ad..12b976143114e 100644 --- a/spec/active_relation/relations/order_spec.rb +++ b/spec/active_relation/relations/order_spec.rb @@ -3,25 +3,23 @@ module ActiveRelation describe Order do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] + @relation = Table.new(:users) + @attribute = @relation[:id] end describe '#qualify' do it "distributes over the relation and attributes" do - Order.new(@relation1, @attribute1).qualify. \ - should == Order.new(@relation1.qualify, @attribute1.qualify) + Order.new(@relation, @attribute).qualify. \ + should == Order.new(@relation.qualify, @attribute.qualify) end end describe '#to_sql' do it "manufactures sql with an order clause" do - Order.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - ORDER BY `foo`.`id` + Order.new(@relation, @attribute).to_sql.should be_like(""" + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id` """) end end diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/relations/range_spec.rb index 51171c759b71a..a2f84c2e88e68 100644 --- a/spec/active_relation/relations/range_spec.rb +++ b/spec/active_relation/relations/range_spec.rb @@ -3,25 +3,23 @@ module ActiveRelation describe Range do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @range1 = 1..2 - @range2 = 4..9 + @relation = Table.new(:users) + @range = 4..9 end describe '#qualify' do it "distributes over the relation" do - Range.new(@relation1, @range1).qualify.should == Range.new(@relation1.qualify, @range1) + Range.new(@relation, @range).qualify.should == Range.new(@relation.qualify, @range) end end describe '#to_sql' do it "manufactures sql with limit and offset" do - range_size = @range2.last - @range2.first + 1 - range_start = @range2.first - Range.new(@relation1, @range2).to_s.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` + range_size = @range.last - @range.first + 1 + range_start = @range.first + Range.new(@relation, @range).to_s.should be_like(""" + SELECT `users`.`id`, `users`.`name` + FROM `users` LIMIT #{range_size} OFFSET #{range_start} """) diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index ebe95f13b9507..695e51c191284 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -3,15 +3,15 @@ module ActiveRelation describe Rename do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) @renamed_relation = Rename.new(@relation1, @relation1[:id] => :schmid) end describe '#initialize' do it "manufactures nested rename relations if multiple renames are provided" do Rename.new(@relation1, @relation1[:id] => :humpty, @relation1[:name] => :dumpty). \ - should == Rename.new(Rename.new(@relation1, @relation1[:id] => :humpty), @relation1[:name] => :dumpty) + should == Rename.new(Rename.new(@relation1, @relation1[:name] => :dumpty), @relation1[:id] => :humpty) end end @@ -50,6 +50,7 @@ module ActiveRelation describe 'when given an', Expression do it "manufactures a substituted and renamed expression if the expression is within the relation" do + pending end end @@ -97,8 +98,8 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql renaming the attribute' do @renamed_relation.to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` AS 'schmid' - FROM `foo` + SELECT `users`.`id` AS 'schmid', `users`.`name` + FROM `users` """) end end diff --git a/spec/active_relation/relations/selection_spec.rb b/spec/active_relation/relations/selection_spec.rb index 95d9e68625682..66ad54de1962f 100644 --- a/spec/active_relation/relations/selection_spec.rb +++ b/spec/active_relation/relations/selection_spec.rb @@ -3,39 +3,38 @@ module ActiveRelation describe Selection do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @predicate1 = Equality.new(@relation1[:id], @relation2[:foo_id]) - @predicate2 = LessThan.new(@relation1[:age], 2) + @relation = Table.new(:users) + @predicate = Equality.new(@relation[:id], 1) end describe '#initialize' do it "manufactures nested selection relations if multiple predicates are provided" do - Selection.new(@relation1, @predicate1, @predicate2). \ - should == Selection.new(Selection.new(@relation1, @predicate2), @predicate1) + @predicate2 = LessThan.new(@relation[:age], 2) + Selection.new(@relation, @predicate, @predicate2). \ + should == Selection.new(Selection.new(@relation, @predicate2), @predicate) end end describe '#qualify' do it "distributes over the relation and predicates" do - Selection.new(@relation1, @predicate1).qualify. \ - should == Selection.new(@relation1.qualify, @predicate1.qualify) + Selection.new(@relation, @predicate).qualify. \ + should == Selection.new(@relation.qualify, @predicate.qualify) end end describe '#to_sql' do it "manufactures sql with where clause conditions" do - Selection.new(@relation1, @predicate1).to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` - WHERE `foo`.`id` = `bar`.`foo_id` + Selection.new(@relation, @predicate).to_sql.should be_like(""" + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE `users`.`id` = 1 """) end it "allows arbitrary sql" do - Selection.new(@relation1, "asdf").to_sql.should be_like(""" - SELECT `foo`.`name`, `foo`.`id` - FROM `foo` + Selection.new(@relation, "asdf").to_sql.should be_like(""" + SELECT `users`.`id`, `users`.`name` + FROM `users` WHERE asdf """) end diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index e48d259fb8be9..03b4836e80514 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -40,7 +40,7 @@ module ActiveRelation describe '#to_sql' do it "manufactures a simple select query" do @table.to_sql.should be_like(""" - SELECT `users`.`name`, `users`.`id` + SELECT `users`.`id`, `users`.`name` FROM `users` """) end @@ -61,8 +61,8 @@ module ActiveRelation describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do @table.attributes.should == [ - Attribute.new(@table, :name), - Attribute.new(@table, :id) + Attribute.new(@table, :id), + Attribute.new(@table, :name) ] end end From 82cd330dbac31d79e23cc06273321ecbac2b9077 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 11 Feb 2008 23:02:33 -0800 Subject: [PATCH 0056/1492] aesthetic considerations --- lib/active_relation/relations/aggregation.rb | 5 ++++- lib/active_relation/relations/alias.rb | 4 +++- lib/active_relation/relations/join.rb | 9 ++++++--- lib/active_relation/relations/order.rb | 3 ++- lib/active_relation/relations/projection.rb | 4 +++- lib/active_relation/relations/range.rb | 3 ++- lib/active_relation/relations/rename.rb | 5 ++++- lib/active_relation/relations/selection.rb | 4 +++- lib/active_relation/relations/table.rb | 7 ++----- 9 files changed, 29 insertions(+), 15 deletions(-) diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index efa6ea260c3c4..692a922ca79ec 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -7,7 +7,10 @@ def initialize(relation, options) end def ==(other) - self.class == other.class and relation == other.relation and groupings == other.groupings and expressions == other.expressions + self.class == other.class and + relation == other.relation and + groupings == other.groupings and + expressions == other.expressions end def qualify diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 7b03a8c2ab9c1..5b45d9dce4981 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -11,7 +11,9 @@ def initialize(relation, aliaz) end def ==(other) - self.class == other.class and relation == other.relation and @alias == other.alias + self.class == other.class and + relation == other.relation and + @alias == other.alias end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 5b2efe727f527..be2e89dd82ab5 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -8,9 +8,12 @@ def initialize(join_sql, relation1, relation2, *predicates) def ==(other) self.class == other.class and - predicates == other.predicates and - ((relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2)) + predicates == other.predicates and ( + (relation1 == other.relation1 and + relation2 == other.relation2) or + (relation2 == other.relation1 and + relation1 == other.relation2) + ) end def qualify diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index 688207f7a9afd..a23da967fde8d 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -7,7 +7,8 @@ def initialize(relation, *orders) end def ==(other) - relation == other.relation and orders == other.orders + relation == other.relation and + orders == other.orders end def qualify diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index 78698603f04f0..9e0725f6c5848 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -8,7 +8,9 @@ def initialize(relation, *projections) end def ==(other) - self.class == other.class and relation == other.relation and projections == other.projections + self.class == other.class and + relation == other.relation and + projections == other.projections end def qualify diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb index 83af03fc0e5fd..7f120ab9e5798 100644 --- a/lib/active_relation/relations/range.rb +++ b/lib/active_relation/relations/range.rb @@ -7,7 +7,8 @@ def initialize(relation, range) end def ==(other) - relation == other.relation and range == other.range + relation == other.relation and + range == other.range end def limit diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index c41cd1bdc5f37..83ab41df70b06 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -8,7 +8,10 @@ def initialize(relation, pseudonyms) end def ==(other) - self.class == other.class and relation == other.relation and attribute == other.attribute and pseudonym == other.pseudonym + self.class == other.class and + relation == other.relation and + attribute == other.attribute and + pseudonym == other.pseudonym end def qualify diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index 5f1726d3810ec..98f56b0cbd7e1 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -8,7 +8,9 @@ def initialize(relation, *predicates) end def ==(other) - self.class == other.class and relation == other.relation and predicate == other.predicate + self.class == other.class and + relation == other.relation and + predicate == other.predicate end def qualify diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index d6ab45dceacbc..c8ccb22fdd8e7 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -19,11 +19,8 @@ def qualify def prefix_for(attribute) name end - - def aliased_prefix_for(attribute) - name - end - + alias_method :aliased_prefix_for, :prefix_for + protected def table_sql "#{quote_table_name(name)}" From 0d70ce37e510c83d5fc42f88b04314f40d87fe96 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 11 Feb 2008 23:09:15 -0800 Subject: [PATCH 0057/1492] rename substitute to bind since it 'binds' an object to a new relation. --- lib/active_relation/extensions/object.rb | 2 +- lib/active_relation/predicates.rb | 4 ++-- lib/active_relation/primitives/attribute.rb | 2 +- lib/active_relation/primitives/expression.rb | 4 ++-- lib/active_relation/relations/aggregation.rb | 2 +- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/join.rb | 4 ++-- lib/active_relation/relations/rename.rb | 6 ++--- .../active_relation/predicates/binary_spec.rb | 6 ++--- .../primitives/attribute_spec.rb | 8 +++---- .../primitives/expression_spec.rb | 8 +++---- .../relations/compound_spec.rb | 12 +++++----- spec/active_relation/relations/join_spec.rb | 2 +- spec/active_relation/relations/rename_spec.rb | 24 +++++++++---------- 14 files changed, 43 insertions(+), 43 deletions(-) diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 1db4c845be574..35ffa9c661b75 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -3,7 +3,7 @@ def qualify self end - def substitute(relation) + def bind(relation) self end diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 54cc1fa5a0929..76288595dc5af 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -20,8 +20,8 @@ def qualify self.class.new(attribute.qualify, operand.qualify) end - def substitute(relation) - self.class.new(attribute.substitute(relation), operand.substitute(relation)) + def bind(relation) + self.class.new(attribute.bind(relation), operand.bind(relation)) end def to_sql(strategy = Sql::Predicate.new) diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 893feefef2eb5..de25a908682b5 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -15,7 +15,7 @@ def as(aliaz = nil) Attribute.new(relation, name, aliaz, self) end - def substitute(new_relation) + def bind(new_relation) relation == new_relation ? self : Attribute.new(new_relation, name, @alias, self) end diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index ff07c40109766..6ff06c7f81c7c 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -10,8 +10,8 @@ def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) end module Transformations - def substitute(new_relation) - new_relation == relation ? self : Expression.new(attribute.substitute(new_relation), function_sql, @alias, self) + def bind(new_relation) + new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) end def as(aliaz) diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index 692a922ca79ec..9e803b3587397 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -18,7 +18,7 @@ def qualify end def attributes - expressions.collect { |e| e.substitute(self) } + expressions.collect { |e| e.bind(self) } end protected diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index befb7f26d2085..d11d09fbf6766 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -6,7 +6,7 @@ class Compound < Relation :to => :relation def attributes - relation.attributes.collect { |a| a.substitute(self) } + relation.attributes.collect { |a| a.bind(self) } end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index be2e89dd82ab5..6d59ffcf392fc 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -24,7 +24,7 @@ def attributes [ relation1.aggregation?? relation1.attributes.collect(&:to_attribute) : relation1.attributes, relation2.aggregation?? relation2.attributes.collect(&:to_attribute) : relation2.attributes, - ].flatten.collect { |a| a.substitute(self) } + ].flatten.collect { |a| a.bind(self) } end def prefix_for(attribute) @@ -52,7 +52,7 @@ def table_sql private def join - [join_sql, right_table_sql, "ON", predicates.collect { |p| p.substitute(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") + [join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") end def right_table_sql diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 83ab41df70b06..6b1b29bf75574 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -19,12 +19,12 @@ def qualify end def attributes - relation.attributes.collect(&method(:substitute)) + relation.attributes.collect(&method(:baptize)) end private - def substitute(attribute) - (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).substitute(self) rescue nil + def baptize(attribute) + (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).bind(self) rescue nil end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index 5d1e7d12239a3..599cfa2942152 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -33,10 +33,10 @@ def predicate_sql end end - describe '#substitute' do + describe '#bind' do it "distributes over the predicates and attributes" do - ConcreteBinary.new(@attribute1, @attribute2).substitute(@relation2). \ - should == ConcreteBinary.new(@attribute1.substitute(@relation2), @attribute2.substitute(@relation2)) + ConcreteBinary.new(@attribute1, @attribute2).bind(@relation2). \ + should == ConcreteBinary.new(@attribute1.bind(@relation2), @attribute2.bind(@relation2)) end end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index e79f0c994d3fb..ecc9014658857 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -17,14 +17,14 @@ module ActiveRelation end end - describe '#substitute' do - it "manufactures an attribute with the relation substituted and self as an ancestor" do + describe '#bind' do + it "manufactures an attribute with the relation bindd and self as an ancestor" do derived_relation = @relation.select(@relation[:id].equals(1)) - @attribute.substitute(derived_relation).should == Attribute.new(derived_relation, @attribute.name, nil, @attribute) + @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, nil, @attribute) end it "returns self if the substituting to the same relation" do - @attribute.substitute(@relation).should == @attribute + @attribute.bind(@relation).should == @attribute end end diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/primitives/expression_spec.rb index d699dfded0962..2ec5130386b10 100644 --- a/spec/active_relation/primitives/expression_spec.rb +++ b/spec/active_relation/primitives/expression_spec.rb @@ -12,14 +12,14 @@ module ActiveRelation @expression = Expression.new(@attribute, "COUNT") end - describe '#substitute' do - it "manufactures an attribute with a substituted relation and self as the ancestor" do + describe '#bind' do + it "manufactures an attribute with a bindd relation and self as the ancestor" do derived_relation = @relation.select(@relation[:id] == 1) - @expression.substitute(derived_relation).should == Expression.new(@attribute.substitute(derived_relation), "COUNT", nil, @expression) + @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end it "returns self if the substituting to the same relation" do - @expression.substitute(@relation).should == @expression + @expression.bind(@relation).should == @expression end end diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/relations/compound_spec.rb index 79ac965e63b89..bb2919a31841e 100644 --- a/spec/active_relation/relations/compound_spec.rb +++ b/spec/active_relation/relations/compound_spec.rb @@ -14,21 +14,21 @@ def initialize(relation) describe '#attributes' do it 'manufactures attributes associated with the compound relation' do - @compound_relation.attributes.should == @relation.attributes.collect { |a| a.substitute(@compound_relation) } + @compound_relation.attributes.should == @relation.attributes.collect { |a| a.bind(@compound_relation) } end end describe '[]' do describe 'when given a', Symbol do it 'manufactures attributes associated with the compound relation if the symbol names an attribute within the relation' do - @compound_relation[:id].should == @relation[:id].substitute(@compound_relation) + @compound_relation[:id].should == @relation[:id].bind(@compound_relation) @compound_relation[:does_not_exist].should be_nil end end describe 'when given an', Attribute do - it "manufactures a substituted attribute when given an attribute within the relation" do - @compound_relation[@relation[:id]].should == @relation[:id].substitute(@compound_relation) + it "manufactures a bindd attribute when given an attribute within the relation" do + @compound_relation[@relation[:id]].should == @relation[:id].bind(@compound_relation) @compound_relation[@compound_relation[:id]].should == @compound_relation[:id] pending "test nil" end @@ -42,8 +42,8 @@ def initialize(relation) @compound_relation = ConcreteCompound.new(@nested_relation) end - it "manufactures a substituted Expression when given an Expression within the relation" do - @compound_relation[@nested_expression].should == @nested_relation[@nested_expression].substitute(@compound_relation) + it "manufactures a bindd Expression when given an Expression within the relation" do + @compound_relation[@nested_expression].should == @nested_relation[@nested_expression].bind(@compound_relation) @compound_relation[@compound_relation[@expression]].should == @compound_relation[@expression] @compound_relation[@unprojected_expression].should be_nil end diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 3b2ad88123585..5c86c72a18a42 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -40,7 +40,7 @@ module ActiveRelation it 'combines the attributes of the two relations' do @join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.substitute(@join) } + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(@join) } end end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 695e51c191284..5a6cecc39e02b 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -34,22 +34,22 @@ module ActiveRelation describe 'when given a', Symbol do it 'indexes attributes by rename if the symbol names an attribute within the relation' do @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation1[:id].as(:schmid).substitute(@renamed_relation) + @renamed_relation[:schmid].should == @relation1[:id].as(:schmid).bind(@renamed_relation) @renamed_relation[:does_not_exist].should be_nil end end describe 'when given an', Attribute do - it 'manufactures a substituted and renamed attribute if the attribute is within the relation' do - @renamed_relation[@relation1[:id]].should == @relation1[:id].as(:schmid).substitute(@renamed_relation) - @renamed_relation[@relation1[:name]].should == @relation1[:name].substitute(@renamed_relation) + it 'manufactures a bindd and renamed attribute if the attribute is within the relation' do + @renamed_relation[@relation1[:id]].should == @relation1[:id].as(:schmid).bind(@renamed_relation) + @renamed_relation[@relation1[:name]].should == @relation1[:name].bind(@renamed_relation) @renamed_relation[@renamed_relation[:name]].should == @renamed_relation[:name] @renamed_relation[@relation2[:id]].should be_nil end end describe 'when given an', Expression do - it "manufactures a substituted and renamed expression if the expression is within the relation" do + it "manufactures a bindd and renamed expression if the expression is within the relation" do pending end end @@ -60,17 +60,17 @@ module ActiveRelation end describe 'when given a', Symbol do - it 'manufactures a substituted and renamed attribute if the attribute is within the relation' do + it 'manufactures a bindd and renamed attribute if the attribute is within the relation' do @renamed_renamed_relation[:id].should be_nil @renamed_renamed_relation[:schmid].should be_nil - @renamed_renamed_relation[:flid].should == @renamed_relation[:schmid].as(:flid).substitute(@renamed_renamed_relation) + @renamed_renamed_relation[:flid].should == @renamed_relation[:schmid].as(:flid).bind(@renamed_renamed_relation) end end describe 'when given an', Attribute do - it "manufactures a substituted and renamed attribute if the attribute is within the relation -- even if the provided attribute derived" do - @renamed_renamed_relation[@renamed_relation[:schmid]].should == @renamed_relation[:schmid].as(:flid).substitute(@renamed_renamed_relation) - @renamed_renamed_relation[@relation1[:id]].should == @renamed_relation[:schmid].as(:flid).substitute(@renamed_renamed_relation) + it "manufactures a bindd and renamed attribute if the attribute is within the relation -- even if the provided attribute derived" do + @renamed_renamed_relation[@renamed_relation[:schmid]].should == @renamed_relation[:schmid].as(:flid).bind(@renamed_renamed_relation) + @renamed_renamed_relation[@relation1[:id]].should == @renamed_relation[:schmid].as(:flid).bind(@renamed_renamed_relation) end end @@ -81,8 +81,8 @@ module ActiveRelation @renamed_relation = Rename.new(@aggregation, @expression => :cnt) end - it "manufactures a substituted and renamed expression if the expression is within the relation" do - @renamed_relation[@expression].should == @aggregation[@expression].as(:cnt).substitute(@renamed_relation) + it "manufactures a bindd and renamed expression if the expression is within the relation" do + @renamed_relation[@expression].should == @aggregation[@expression].as(:cnt).bind(@renamed_relation) end end end From c910ac7554ad4989c8dd4e942fc14ae78eeddc3d Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 11 Feb 2008 23:17:45 -0800 Subject: [PATCH 0058/1492] removing unneccessary tests now that attribute lookup is so simple --- lib/active_relation/relations/join.rb | 1 - .../primitives/attribute_spec.rb | 2 +- .../primitives/expression_spec.rb | 2 +- .../relations/compound_spec.rb | 32 ---------- spec/active_relation/relations/join_spec.rb | 18 +++--- .../relations/relation_spec.rb | 4 ++ spec/active_relation/relations/rename_spec.rb | 59 +------------------ spec/active_relation/relations/table_spec.rb | 29 +++++---- 8 files changed, 29 insertions(+), 118 deletions(-) diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 6d59ffcf392fc..ede8b272cb9fb 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -28,7 +28,6 @@ def attributes end def prefix_for(attribute) - # test me (relation1[attribute] && relation1.aliased_prefix_for(attribute)) || (relation2[attribute] && relation2.aliased_prefix_for(attribute)) end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index ecc9014658857..6d0020d5da170 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -18,7 +18,7 @@ module ActiveRelation end describe '#bind' do - it "manufactures an attribute with the relation bindd and self as an ancestor" do + it "manufactures an attribute with the relation bound and self as an ancestor" do derived_relation = @relation.select(@relation[:id].equals(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, nil, @attribute) end diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/primitives/expression_spec.rb index 2ec5130386b10..f90ae899c37c4 100644 --- a/spec/active_relation/primitives/expression_spec.rb +++ b/spec/active_relation/primitives/expression_spec.rb @@ -13,7 +13,7 @@ module ActiveRelation end describe '#bind' do - it "manufactures an attribute with a bindd relation and self as the ancestor" do + it "manufactures an attribute with a rebound relation and self as the ancestor" do derived_relation = @relation.select(@relation[:id] == 1) @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/relations/compound_spec.rb index bb2919a31841e..b0f122ca979cd 100644 --- a/spec/active_relation/relations/compound_spec.rb +++ b/spec/active_relation/relations/compound_spec.rb @@ -17,37 +17,5 @@ def initialize(relation) @compound_relation.attributes.should == @relation.attributes.collect { |a| a.bind(@compound_relation) } end end - - describe '[]' do - describe 'when given a', Symbol do - it 'manufactures attributes associated with the compound relation if the symbol names an attribute within the relation' do - @compound_relation[:id].should == @relation[:id].bind(@compound_relation) - @compound_relation[:does_not_exist].should be_nil - end - end - - describe 'when given an', Attribute do - it "manufactures a bindd attribute when given an attribute within the relation" do - @compound_relation[@relation[:id]].should == @relation[:id].bind(@compound_relation) - @compound_relation[@compound_relation[:id]].should == @compound_relation[:id] - pending "test nil" - end - end - - describe 'when given an', Expression do - before do - @nested_expression = Expression.new(Attribute.new(@relation, :id), "COUNT") - @nested_relation = Aggregation.new(@relation, :expressions => [@nested_expression]) - @unprojected_expression = Expression.new(Attribute.new(@relation, :id), "SUM") - @compound_relation = ConcreteCompound.new(@nested_relation) - end - - it "manufactures a bindd Expression when given an Expression within the relation" do - @compound_relation[@nested_expression].should == @nested_relation[@nested_expression].bind(@compound_relation) - @compound_relation[@compound_relation[@expression]].should == @compound_relation[@expression] - @compound_relation[@unprojected_expression].should be_nil - end - end - end end end \ No newline at end of file diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index 5c86c72a18a42..b131ac69184a2 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -18,12 +18,6 @@ module ActiveRelation Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation2, @relation1, @predicate) end end - - describe '[]' do - it "" do - pending - end - end describe '#qualify' do it 'distributes over the relations and predicates' do @@ -42,15 +36,19 @@ module ActiveRelation @join.attributes.should == (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(@join) } end - end - - describe 'with aggregated relations' do - it '' do + + it 'does something peculiar with expressions when aggregate' do pending end end end + describe '#prefix_for' do + it 'needs a test' do + pending + end + end + describe '#to_sql' do describe 'with simple relations' do it 'manufactures sql joining the two tables on the predicate' do diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index e28487b373d97..91eabe485b1cf 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -13,6 +13,10 @@ module ActiveRelation it "manufactures a range relation when given a range" do @relation1[1..2].should == Range.new(@relation1, 1..2) end + + it "needs to test attributes and names" do + pending + end end describe '#include?' do diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 5a6cecc39e02b..339bb2f39fa3d 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -27,64 +27,7 @@ module ActiveRelation it "manufactures a list of attributes with the renamed attribute renameed" do @renamed_relation.attributes.should include(@renamed_relation[:schmid]) @renamed_relation.should have(@relation1.attributes.size).attributes - end - end - - describe '[]' do - describe 'when given a', Symbol do - it 'indexes attributes by rename if the symbol names an attribute within the relation' do - @renamed_relation[:id].should be_nil - @renamed_relation[:schmid].should == @relation1[:id].as(:schmid).bind(@renamed_relation) - @renamed_relation[:does_not_exist].should be_nil - end - end - - describe 'when given an', Attribute do - it 'manufactures a bindd and renamed attribute if the attribute is within the relation' do - @renamed_relation[@relation1[:id]].should == @relation1[:id].as(:schmid).bind(@renamed_relation) - @renamed_relation[@relation1[:name]].should == @relation1[:name].bind(@renamed_relation) - @renamed_relation[@renamed_relation[:name]].should == @renamed_relation[:name] - @renamed_relation[@relation2[:id]].should be_nil - end - end - - describe 'when given an', Expression do - it "manufactures a bindd and renamed expression if the expression is within the relation" do - pending - end - end - - describe 'when the rename is constructed with a derived attribute' do - before do - @renamed_renamed_relation = Rename.new(@renamed_relation, @relation1[:id] => :flid) - end - - describe 'when given a', Symbol do - it 'manufactures a bindd and renamed attribute if the attribute is within the relation' do - @renamed_renamed_relation[:id].should be_nil - @renamed_renamed_relation[:schmid].should be_nil - @renamed_renamed_relation[:flid].should == @renamed_relation[:schmid].as(:flid).bind(@renamed_renamed_relation) - end - end - - describe 'when given an', Attribute do - it "manufactures a bindd and renamed attribute if the attribute is within the relation -- even if the provided attribute derived" do - @renamed_renamed_relation[@renamed_relation[:schmid]].should == @renamed_relation[:schmid].as(:flid).bind(@renamed_renamed_relation) - @renamed_renamed_relation[@relation1[:id]].should == @renamed_relation[:schmid].as(:flid).bind(@renamed_renamed_relation) - end - end - - describe 'when given an', Expression do - before do - @expression = @relation1[:id].count - @aggregation = Aggregation.new(@relation1, :expressions => [@expression]) - @renamed_relation = Rename.new(@aggregation, @expression => :cnt) - end - - it "manufactures a bindd and renamed expression if the expression is within the relation" do - @renamed_relation[@expression].should == @aggregation[@expression].as(:cnt).bind(@renamed_relation) - end - end + pending "this should be more rigorous" end end diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 03b4836e80514..498d8410401a4 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -3,43 +3,42 @@ module ActiveRelation describe Table do before do - @table = Table.new(:users) - @relation2 = Table.new(:photos) + @relation = Table.new(:users) end describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do - @table[:id].should == Attribute.new(@table, :id) - @table[:does_not_exist].should be_nil + @relation[:id].should == Attribute.new(@relation, :id) + @relation[:does_not_exist].should be_nil end end describe 'when given an', Attribute do it "returns the attribute if the attribute is within the relation" do - @table[@table[:id]].should == @table[:id] + @relation[@relation[:id]].should == @relation[:id] end it "returns nil if the attribtue is not within the relation" do another_relation = Table.new(:photos) - @table[another_relation[:id]].should be_nil + @relation[another_relation[:id]].should be_nil end end describe 'when given an', Expression do before do - @expression = Expression.new(Attribute.new(@table, :id), "COUNT") + @expression = Expression.new(Attribute.new(@relation, :id), "COUNT") end it "returns the Expression if the Expression is within the relation" do - @table[@expression].should be_nil + @relation[@expression].should be_nil end end end describe '#to_sql' do it "manufactures a simple select query" do - @table.to_sql.should be_like(""" + @relation.to_sql.should be_like(""" SELECT `users`.`id`, `users`.`name` FROM `users` """) @@ -48,28 +47,28 @@ module ActiveRelation describe '#prefix_for' do it "returns the table name" do - @table.prefix_for(Attribute.new(@table, :id)).should == :users + @relation.prefix_for(Attribute.new(@relation, :id)).should == :users end end describe '#aliased_prefix_for' do it "returns the table name" do - @table.aliased_prefix_for(Attribute.new(@table, :id)).should == :users + @relation.aliased_prefix_for(Attribute.new(@relation, :id)).should == :users end end describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do - @table.attributes.should == [ - Attribute.new(@table, :id), - Attribute.new(@table, :name) + @relation.attributes.should == [ + Attribute.new(@relation, :id), + Attribute.new(@relation, :name) ] end end describe '#qualify' do it 'manufactures a rename relation with all attribute names qualified' do - @table.qualify.should == Rename.new(@table, @table[:name] => 'users.name', @table[:id] => 'users.id') + @relation.qualify.should == Rename.new(@relation, @relation[:name] => 'users.name', @relation[:id] => 'users.id') end end end From d5d7a8eb9935cd937441bd5233b410e5a0cfd41b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 16:09:37 -0800 Subject: [PATCH 0059/1492] attribute is now a concrete ancestor of expression. seems logical. --- lib/active_relation/primitives/attribute.rb | 10 +++--- lib/active_relation/primitives/expression.rb | 31 +++++++------------ .../primitives/attribute_spec.rb | 2 +- .../primitives/expression_spec.rb | 6 ++++ 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index de25a908682b5..4a10dffbe5ee6 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -34,11 +34,11 @@ def qualified_name end def ==(other) - self.class == other.class and - relation == other.relation and - name == other.name and - @alias == other.alias and - ancestor == other.ancestor + self.class == other.class and + relation == other.relation and + name == other.name and + @alias == other.alias and + ancestor == other.ancestor end alias_method :eql?, :== diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index 6ff06c7f81c7c..4d28ef108c151 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -1,23 +1,24 @@ module ActiveRelation - class Expression + class Expression < Attribute include Sql::Quoting - attr_reader :attribute, :function_sql, :alias, :ancestor + attr_reader :attribute, :function_sql delegate :relation, :to => :attribute + alias_method :name, :alias def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor end module Transformations - def bind(new_relation) - new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) - end - def as(aliaz) Expression.new(attribute, function_sql, aliaz, self) end + def bind(new_relation) + new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + end + def to_attribute Attribute.new(relation, @alias, nil, self) end @@ -29,20 +30,12 @@ def to_sql(strategy = nil) end def ==(other) - self.class == other.class and attribute == other.attribute and function_sql == other.function_sql and ancestor == other.ancestor and @alias == other.alias + self.class == other.class and + attribute == other.attribute and + function_sql == other.function_sql and + ancestor == other.ancestor and + @alias == other.alias end alias_method :eql?, :== - - def =~(other) - !(history & other.send(:history)).empty? - end - - def hash - attribute.hash + function_sql.hash - end - - def history - [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) - end end end \ No newline at end of file diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 6d0020d5da170..535e6245b5db2 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -29,7 +29,7 @@ module ActiveRelation end describe '#qualify' do - it "manufactures an attribute aliased with that attributes qualified name" do + it "manufactures an attribute aliased with that attribute's qualified name" do @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, @attribute.qualified_name, @attribute) end end diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/primitives/expression_spec.rb index f90ae899c37c4..fa854d89f9a4d 100644 --- a/spec/active_relation/primitives/expression_spec.rb +++ b/spec/active_relation/primitives/expression_spec.rb @@ -34,6 +34,12 @@ module ActiveRelation @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, nil, @expression) end end + + describe '#qualify' do + it "manufactures an expression aliased with that expression's qualified name" do + @expression.qualify.should == Expression.new(@attribute, "COUNT", @expression.qualified_name, @expression) + end + end end describe '=~' do From 28b11fdf4d4e5cd4b98d6c79fc88999a41532103 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 16:14:11 -0800 Subject: [PATCH 0060/1492] white box testing --- .../primitives/expression_spec.rb | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/primitives/expression_spec.rb index fa854d89f9a4d..707407d41559f 100644 --- a/spec/active_relation/primitives/expression_spec.rb +++ b/spec/active_relation/primitives/expression_spec.rb @@ -34,23 +34,6 @@ module ActiveRelation @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, nil, @expression) end end - - describe '#qualify' do - it "manufactures an expression aliased with that expression's qualified name" do - @expression.qualify.should == Expression.new(@attribute, "COUNT", @expression.qualified_name, @expression) - end - end - end - - describe '=~' do - it "obtains if the expressions are identical" do - Expression.new(@attribute, "COUNT").should =~ Expression.new(@attribute, "COUNT") - end - - it "obtains if the expressions have an overlapping history" do - Expression.new(@attribute, "COUNT", nil, Expression.new(@attribute, "COUNT")).should =~ Expression.new(@attribute, "COUNT") - Expression.new(@attribute, "COUNT").should =~ Expression.new(@attribute, "COUNT", nil, Expression.new(@attribute, "COUNT")) - end end describe '#to_sql' do From d0ba361c93aa94865ccfe739e9ab65654771e38e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 16:37:00 -0800 Subject: [PATCH 0061/1492] more test coverage --- lib/active_relation/relations/join.rb | 10 ++-- lib/active_relation/relations/projection.rb | 7 ++- lib/active_relation/relations/relation.rb | 2 +- .../primitives/expression_spec.rb | 2 +- .../relations/projection_spec.rb | 39 ++++++++----- .../relations/relation_spec.rb | 57 +++++++++++-------- 6 files changed, 69 insertions(+), 48 deletions(-) diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index ede8b272cb9fb..4c4f2e66a2623 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -7,12 +7,10 @@ def initialize(join_sql, relation1, relation2, *predicates) end def ==(other) - self.class == other.class and - predicates == other.predicates and ( - (relation1 == other.relation1 and - relation2 == other.relation2) or - (relation2 == other.relation1 and - relation1 == other.relation2) + self.class == other.class and + predicates == other.predicates and ( + (relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2) ) end diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index 9e0725f6c5848..d0c68869bddd0 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -1,14 +1,17 @@ module ActiveRelation class Projection < Compound attr_reader :projections - alias_method :attributes, :projections def initialize(relation, *projections) @relation, @projections = relation, projections end + def attributes + projections.collect { |p| p.bind(self) } + end + def ==(other) - self.class == other.class and + self.class == other.class and relation == other.relation and projections == other.projections end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index c5409bc9ff609..c65120a75c2da 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -109,7 +109,7 @@ def connection end def attribute_for_name(name) - attributes.detect { |a| a.alias_or_name == name } + attributes.detect { |a| a.alias_or_name.to_s == name.to_s } end def attribute_for_attribute(attribute) diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/primitives/expression_spec.rb index 707407d41559f..753f189e821c2 100644 --- a/spec/active_relation/primitives/expression_spec.rb +++ b/spec/active_relation/primitives/expression_spec.rb @@ -25,7 +25,7 @@ module ActiveRelation describe '#as' do it "manufactures an aliased expression" do - @expression.as(:foo).should == Expression.new(@attribute, "COUNT", :foo, @expression) + @expression.as(:alias).should == Expression.new(@attribute, "COUNT", :alias, @expression) end end diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb index e792eec3b8f1f..739a16c8ef4f8 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/relations/projection_spec.rb @@ -3,36 +3,45 @@ module ActiveRelation describe Projection do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] + @relation = Table.new(:users) + @attribute = @relation[:id] end - - it "needs to test that [] is limited" do - pending + + describe '#attributes' do + before do + @projection = Projection.new(@relation, @attribute) + end + + it "manufactures attributes associated with the projection relation" do + @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } + end end describe '==' do + before do + @another_relation = Table.new(:photos) + @another_attribute = @relation[:name] + end + it "obtains if the relations and attributes are identical" do - Projection.new(@relation1, @attribute1, @attribute2).should == Projection.new(@relation1, @attribute1, @attribute2) - Projection.new(@relation1, @attribute1).should_not == Projection.new(@relation2, @attribute1) - Projection.new(@relation1, @attribute1).should_not == Projection.new(@relation1, @attribute2) + Projection.new(@relation, @attribute).should == Projection.new(@relation, @attribute) + Projection.new(@relation, @attribute).should_not == Projection.new(@another_relation, @attribute) + Projection.new(@relation, @attribute).should_not == Projection.new(@relation, @another_attribute) end end describe '#qualify' do it "distributes over the relation and attributes" do - Projection.new(@relation1, @attribute1).qualify. \ - should == Projection.new(@relation1.qualify, @attribute1.qualify) + Projection.new(@relation, @attribute).qualify. \ + should == Projection.new(@relation.qualify, @attribute.qualify) end end describe '#to_sql' do it "manufactures sql with a limited select clause" do - Projection.new(@relation1, @attribute1).to_sql.should be_like(""" - SELECT `foo`.`id` - FROM `foo` + Projection.new(@relation, @attribute).to_sql.should be_like(""" + SELECT `users`.`id` + FROM `users` """) end end diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/relations/relation_spec.rb index 91eabe485b1cf..a25dc4b1db352 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/relations/relation_spec.rb @@ -3,68 +3,79 @@ module ActiveRelation describe Relation do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute1 = Attribute.new(@relation1, :id) - @attribute2 = Attribute.new(@relation1, :name) + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] end describe '[]' do - it "manufactures a range relation when given a range" do - @relation1[1..2].should == Range.new(@relation1, 1..2) + describe 'when given a', Range do + it "manufactures a range relation when given a range" do + @relation[1..2].should == Range.new(@relation, 1..2) + end end - it "needs to test attributes and names" do - pending + describe 'when given an', Attribute do + it "return the attribute congruent to the provided attribute" do + @relation[@attribute1].should == @attribute1 + end + end + + describe 'when given a', Symbol, String do + it "returns the attribute with the same name, if it exists" do + @relation[:id].should == @attribute1 + @relation['id'].should == @attribute1 + @relation[:does_not_exist].should be_nil + end end end describe '#include?' do it "manufactures an inclusion predicate" do - @relation1.include?(@attribute1).should be_kind_of(RelationInclusion) + @relation.include?(@attribute1).should be_kind_of(RelationInclusion) end end describe '#Expression?' do it "returns false" do - @relation1.should_not be_aggregation + @relation.should_not be_aggregation end end describe 'read operations' do describe 'joins' do before do - @predicate = @relation1[:id].equals(@relation2[:id]) + @predicate = @relation[:id].equals(@relation[:id]) end describe '#join' do it "manufactures an inner join operation between those two relations" do - @relation1.join(@relation2).on(@predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate) + @relation.join(@relation).on(@predicate).should == Join.new("INNER JOIN", @relation, @relation, @predicate) end end describe '#outer_join' do it "manufactures a left outer join operation between those two relations" do - @relation1.outer_join(@relation2).on(@predicate).should == Join.new("LEFT OUTER JOIN", @relation1, @relation2, @predicate) + @relation.outer_join(@relation).on(@predicate).should == Join.new("LEFT OUTER JOIN", @relation, @relation, @predicate) end end end describe '#project' do it "manufactures a projection relation" do - @relation1.project(@attribute1, @attribute2).should == Projection.new(@relation1, @attribute1, @attribute2) + @relation.project(@attribute1, @attribute2).should == Projection.new(@relation, @attribute1, @attribute2) end end describe '#as' do it "manufactures an alias relation" do - @relation1.as(:thucydides).should == Alias.new(@relation1, :thucydides) + @relation.as(:thucydides).should == Alias.new(@relation, :thucydides) end end describe '#rename' do it "manufactures a rename relation" do - @relation1.rename(@attribute1, :foo).should == Rename.new(@relation1, @attribute1 => :foo) + @relation.rename(@attribute1, :users).should == Rename.new(@relation, @attribute1 => :users) end end @@ -74,24 +85,24 @@ module ActiveRelation end it "manufactures a selection relation" do - @relation1.select(@predicate).should == Selection.new(@relation1, @predicate) + @relation.select(@predicate).should == Selection.new(@relation, @predicate) end it "accepts arbitrary strings" do - @relation1.select("arbitrary").should == Selection.new(@relation1, "arbitrary") + @relation.select("arbitrary").should == Selection.new(@relation, "arbitrary") end end describe '#order' do it "manufactures an order relation" do - @relation1.order(@attribute1, @attribute2).should == Order.new(@relation1, @attribute1, @attribute2) + @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) end end describe '#aggregate' do it 'manufactures a group relation' do - @relation1.aggregate(@expression1, @expression2).group(@attribute1, @attribute2). \ - should == Aggregation.new(@relation1, :expressions => [@expresion, @expression2], :groupings => [@attribute1, @attribute2]) + @relation.aggregate(@expression1, @expression2).group(@attribute1, @attribute2). \ + should == Aggregation.new(@relation, :expressions => [@expresion, @expression2], :groupings => [@attribute1, @attribute2]) end end end @@ -99,13 +110,13 @@ module ActiveRelation describe 'write operations' do describe '#delete' do it 'manufactures a deletion relation' do - @relation1.delete.should be_kind_of(Deletion) + @relation.delete.should be_kind_of(Deletion) end end describe '#insert' do it 'manufactures an insertion relation' do - @relation1.insert(record = {:id => 1}).should be_kind_of(Insertion) + @relation.insert(record = {:id => 1}).should be_kind_of(Insertion) end end end From a2339b41746b92231dfbb15ab19d0f7e1aa2e69a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 16:42:46 -0800 Subject: [PATCH 0062/1492] organized congruence stuff in attribute --- lib/active_relation/primitives/attribute.rb | 30 ++++++++++++------- lib/active_relation/primitives/expression.rb | 1 - .../primitives/attribute_spec.rb | 16 +++++----- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 4a10dffbe5ee6..e55dd0bdc4a9a 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -40,11 +40,27 @@ def ==(other) @alias == other.alias and ancestor == other.ancestor end - alias_method :eql?, :== - def =~(other) - !(history & other.send(:history)).empty? + module Congruence + def self.included(klass) + klass.class_eval do + alias_method :eql?, :== + end + end + + def hash + relation.hash + name.hash + end + + def history + [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) + end + + def =~(other) + !(history & other.send(:history)).empty? + end end + include Congruence module Predications def equals(other) @@ -100,17 +116,9 @@ def to_sql(strategy = Sql::Predicate.new) strategy.attribute prefix, name, self.alias end - def hash - relation.hash + name.hash - end - private def prefix relation.prefix_for(self) end - - def history - [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) - end end end \ No newline at end of file diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index 4d28ef108c151..35c1b5ff655a5 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -36,6 +36,5 @@ def ==(other) ancestor == other.ancestor and @alias == other.alias end - alias_method :eql?, :== end end \ No newline at end of file diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 535e6245b5db2..39feacbac7ca7 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -47,14 +47,16 @@ module ActiveRelation end end - describe '=~' do - it "obtains if the attributes are identical" do - Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name) - end + describe Attribute::Congruence do + describe '=~' do + it "obtains if the attributes are identical" do + Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name) + end - it "obtains if the attributes have an overlapping history" do - Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)).should =~ Attribute.new(@relation, :name) - Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)) + it "obtains if the attributes have an overlapping history" do + Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)).should =~ Attribute.new(@relation, :name) + Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)) + end end end From 49c2620bc63d4611db979b0a2151b3e080bb1acf Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 19:42:19 -0800 Subject: [PATCH 0063/1492] cleanup --- lib/active_relation/relations/aggregation.rb | 1 - lib/active_relation/relations/alias.rb | 2 +- lib/active_relation/relations/join.rb | 21 ++--- lib/active_relation/relations/rename.rb | 4 +- lib/active_relation/relations/table.rb | 2 +- .../active_relation/predicates/binary_spec.rb | 10 +-- .../primitives/attribute_spec.rb | 8 +- spec/active_relation/relations/alias_spec.rb | 1 + spec/active_relation/relations/join_spec.rb | 81 ++++++++++--------- spec/active_relation/relations/rename_spec.rb | 35 ++++---- spec/active_relation/relations/table_spec.rb | 9 ++- 11 files changed, 94 insertions(+), 80 deletions(-) diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index 9e803b3587397..7910223673fb4 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -21,7 +21,6 @@ def attributes expressions.collect { |e| e.bind(self) } end - protected def aggregation? true end diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 5b45d9dce4981..941a95c58e9c4 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -3,7 +3,7 @@ class Alias < Compound attr_reader :alias def aliased_prefix_for(attribute) - @alias + self[attribute] and @alias end def initialize(relation, aliaz) diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 4c4f2e66a2623..c61680fd55a3c 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -20,20 +20,22 @@ def qualify def attributes [ - relation1.aggregation?? relation1.attributes.collect(&:to_attribute) : relation1.attributes, - relation2.aggregation?? relation2.attributes.collect(&:to_attribute) : relation2.attributes, + relation1.attributes.collect(&:to_attribute), + relation2.attributes.collect(&:to_attribute), ].flatten.collect { |a| a.bind(self) } end def prefix_for(attribute) - (relation1[attribute] && relation1.aliased_prefix_for(attribute)) || - (relation2[attribute] && relation2.aliased_prefix_for(attribute)) + relation1.aliased_prefix_for(attribute) or + relation2.aliased_prefix_for(attribute) end alias_method :aliased_prefix_for, :prefix_for protected def joins - [relation1.joins, relation2.joins, join].compact.join(" ") + right_table_sql = relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql) + this_join = [join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") + [relation1.joins, relation2.joins, this_join].compact.join(" ") end def selects @@ -46,14 +48,5 @@ def selects def table_sql relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) end - - private - def join - [join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") - end - - def right_table_sql - relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 6b1b29bf75574..20e79ebefb8dd 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -8,8 +8,8 @@ def initialize(relation, pseudonyms) end def ==(other) - self.class == other.class and - relation == other.relation and + self.class == other.class and + relation == other.relation and attribute == other.attribute and pseudonym == other.pseudonym end diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index c8ccb22fdd8e7..d85c2680198ae 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -17,7 +17,7 @@ def qualify end def prefix_for(attribute) - name + self[attribute] and name end alias_method :aliased_prefix_for, :prefix_for diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index 599cfa2942152..127375f24cced 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -3,10 +3,10 @@ module ActiveRelation describe Binary do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute1 = Attribute.new(@relation1, :name1) - @attribute2 = Attribute.new(@relation2, :name2) + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:id] class ConcreteBinary < Binary def predicate_sql "<=>" @@ -43,7 +43,7 @@ def predicate_sql describe '#to_sql' do it 'manufactures correct sql' do ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" - `foo`.`name1` <=> `bar`.`name2` + `users`.`id` <=> `photos`.`id` """) end end diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/primitives/attribute_spec.rb index 39feacbac7ca7..a931ea21503f6 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/primitives/attribute_spec.rb @@ -62,12 +62,16 @@ module ActiveRelation describe '#to_sql' do describe Sql::Strategy do + before do + stub(@relation).prefix_for(anything) { 'bruisers' } + end + it "manufactures sql without an alias if the strategy is Predicate" do - Attribute.new(@relation, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`users`.`name`") + Attribute.new(@relation, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`bruisers`.`name`") end it "manufactures sql with an alias if the strategy is Projection" do - Attribute.new(@relation, :name, :alias).to_sql(Sql::Projection.new).should be_like("`users`.`name` AS 'alias'") + Attribute.new(@relation, :name, :alias).to_sql(Sql::Projection.new).should be_like("`bruisers`.`name` AS 'alias'") end end end diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb index ddb0c59d087bc..a2deae2840cec 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/relations/alias_spec.rb @@ -16,6 +16,7 @@ module ActiveRelation describe '#aliased_prefix_for' do it "returns the alias" do @alias_relation.aliased_prefix_for(@relation[:id]).should == :foo + @alias_relation.aliased_prefix_for(:does_not_exist).should be_nil end end end diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index b131ac69184a2..b60238fa7ef75 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -5,13 +5,19 @@ module ActiveRelation before do @relation1 = Table.new(:users) @relation2 = Table.new(:photos) - @predicate = Equality.new(@relation1[:id], @relation2[:id]) + @predicate = @relation1[:id].equals(@relation2[:user_id]) end describe '==' do + before do + @another_predicate = @relation1[:id].equals(1) + @another_relation = Table.new(:cameras) + end + it 'obtains if the two relations and the predicate are identical' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate) - Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @relation1, @predicate) + Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @another_relation, @predicate) + Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @relation2, @another_predicate) end it 'is commutative on the relations' do @@ -26,22 +32,6 @@ module ActiveRelation end end - describe '#attributes' do - describe 'with simple relations' do - before do - @join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) - end - - it 'combines the attributes of the two relations' do - @join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(@join) } - end - - it 'does something peculiar with expressions when aggregate' do - pending - end - end - end describe '#prefix_for' do it 'needs a test' do @@ -49,13 +39,21 @@ module ActiveRelation end end - describe '#to_sql' do - describe 'with simple relations' do + describe 'with simple relations' do + describe '#attributes' do + it 'combines the attributes of the two relations' do + simple_join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) + simple_join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(simple_join) } + end + end + + describe '#to_sql' do it 'manufactures sql joining the two tables on the predicate' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`id` + INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` """) end @@ -64,49 +62,60 @@ module ActiveRelation @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(""" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`id` + INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` WHERE `users`.`id` = 1 AND `photos`.`id` = 2 """) end end - - describe 'aggregated relations' do - before do - @relation = Table.new(:users) - photos = Table.new(:photos) - @aggregate_relation = photos.aggregate(photos[:user_id], photos[:id].count).group(photos[:user_id]).rename(photos[:id].count, :cnt).as(:photo_count) - @predicate = Equality.new(@aggregate_relation[:user_id], @relation[:id]) + end + + describe 'with aggregated relations' do + before do + @aggregation = @relation2 \ + .aggregate(@relation2[:user_id], @relation2[:id].count) \ + .group(@relation2[:user_id]) \ + .rename(@relation2[:id].count, :cnt) \ + .as(:photo_count) + end + + describe '#attributes' do + it 'it transforms aggregate expressions into attributes' do + join_with_aggregation = Join.new("INNER JOIN", @relation1, @aggregation, @predicate) + join_with_aggregation.attributes.should == + (@relation1.attributes + @aggregation.attributes).collect(&:to_attribute).collect { |a| a.bind(join_with_aggregation) } end - + end + + describe '#to_sql' do describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do - Join.new("INNER JOIN", @relation, @aggregate_relation, @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(""" SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` - ON `photo_count`.`user_id` = `users`.`id` + ON `users`.`id` = `photo_count`.`user_id` """) end end describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do - Join.new("INNER JOIN", @aggregate_relation, @relation, @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(""" SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`id`, `users`.`name` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` INNER JOIN `users` - ON `photo_count`.`user_id` = `users`.`id` + ON `users`.`id` = `photo_count`.`user_id` """) end end it "keeps selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @relation, @aggregate_relation.select(@aggregate_relation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count` - ON `photo_count`.`user_id` = `users`.`id` + ON `users`.`id` = `photo_count`.`user_id` """) end end diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index 339bb2f39fa3d..deb538615b163 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -3,44 +3,51 @@ module ActiveRelation describe Rename do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @renamed_relation = Rename.new(@relation1, @relation1[:id] => :schmid) + @relation = Table.new(:users) end describe '#initialize' do it "manufactures nested rename relations if multiple renames are provided" do - Rename.new(@relation1, @relation1[:id] => :humpty, @relation1[:name] => :dumpty). \ - should == Rename.new(Rename.new(@relation1, @relation1[:name] => :dumpty), @relation1[:id] => :humpty) + Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ + should == Rename.new(Rename.new(@relation, @relation[:name] => :dumpty), @relation[:id] => :humpty) end end describe '==' do + before do + @another_relation = Table.new(:photos) + end + it "obtains if the relation, attribute, and rename are identical" do - Rename.new(@relation1, @relation1[:id] => :humpty).should == Rename.new(@relation1, @relation1[:id] => :humpty) - Rename.new(@relation1, @relation1[:id] => :humpty).should_not == Rename.new(@relation1, @relation1[:id] => :dumpty) - Rename.new(@relation1, @relation1[:id] => :humpty).should_not == Rename.new(@relation2, @relation2[:id] => :humpty) + Rename.new(@relation, @relation[:id] => :humpty).should == Rename.new(@relation, @relation[:id] => :humpty) + Rename.new(@relation, @relation[:id] => :humpty).should_not == Rename.new(@relation, @relation[:id] => :dumpty) + Rename.new(@relation, @relation[:id] => :humpty).should_not == Rename.new(@another_relation, @relation[:id] => :humpty) end end describe '#attributes' do + before do + @renamed_relation = Rename.new(@relation, @relation[:id] => :schmid) + end + it "manufactures a list of attributes with the renamed attribute renameed" do - @renamed_relation.attributes.should include(@renamed_relation[:schmid]) - @renamed_relation.should have(@relation1.attributes.size).attributes - pending "this should be more rigorous" + @renamed_relation.attributes.should include(@relation[:id].as(:schmid).bind(@renamed_relation)) + @renamed_relation.attributes.should_not include(@relation[:id].bind(@renamed_relation)) + @renamed_relation.attributes.should include(@relation[:name].bind(@renamed_relation)) + @renamed_relation.should have(@relation.attributes.size).attributes end end describe '#qualify' do it "distributes over the relation and renames" do - Rename.new(@relation1, @relation1[:id] => :schmid).qualify. \ - should == Rename.new(@relation1.qualify, @relation1[:id].qualify => :schmid) + Rename.new(@relation, @relation[:id] => :schmid).qualify. \ + should == Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) end end describe '#to_sql' do it 'manufactures sql renaming the attribute' do - @renamed_relation.to_sql.should be_like(""" + Rename.new(@relation, @relation[:id] => :schmid).to_sql.should be_like(""" SELECT `users`.`id` AS 'schmid', `users`.`name` FROM `users` """) diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 498d8410401a4..13a919844758f 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -27,7 +27,7 @@ module ActiveRelation describe 'when given an', Expression do before do - @expression = Expression.new(Attribute.new(@relation, :id), "COUNT") + @expression = @relation[:id].count end it "returns the Expression if the Expression is within the relation" do @@ -46,14 +46,15 @@ module ActiveRelation end describe '#prefix_for' do - it "returns the table name" do - @relation.prefix_for(Attribute.new(@relation, :id)).should == :users + it "returns the table name if the relation contains the attribute" do + @relation.prefix_for(@relation[:id]).should == :users + @relation.prefix_for(:does_not_exist).should be_nil end end describe '#aliased_prefix_for' do it "returns the table name" do - @relation.aliased_prefix_for(Attribute.new(@relation, :id)).should == :users + @relation.aliased_prefix_for(@relation[:id]).should == :users end end From 99b2188f9495068399000b891c2c9b66331c4b02 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 20:46:05 -0800 Subject: [PATCH 0064/1492] introduced __collect__, an internal enumerating operator. This is a map down the tree representing the relation. Monadic map to be precise --- lib/active_relation/.DS_Store | Bin 0 -> 6148 bytes lib/active_relation/predicates.rb | 15 ++++++++++----- lib/active_relation/relations/aggregation.rb | 15 ++++++++------- lib/active_relation/relations/alias.rb | 12 ++++++++---- lib/active_relation/relations/compound.rb | 4 ++++ lib/active_relation/relations/join.rb | 6 +++++- lib/active_relation/relations/order.rb | 5 +++-- lib/active_relation/relations/projection.rb | 7 ++++--- lib/active_relation/relations/range.rb | 5 +++-- lib/active_relation/relations/relation.rb | 4 ++++ lib/active_relation/relations/rename.rb | 9 +++++---- lib/active_relation/relations/selection.rb | 11 ++++++----- lib/active_relation/relations/table.rb | 2 +- 13 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 lib/active_relation/.DS_Store diff --git a/lib/active_relation/.DS_Store b/lib/active_relation/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2a449ff62e35245aec99ff3f3ff49ea0048a9256 GIT binary patch literal 6148 zcmeHKyH3ME5S$Gzf@oY)UP}jmaEg*I$Pa*d#gb)9aY$Ozz_0L`%yf5Ad8oW8=wR*rzzuIhcR?sZG>6&oRP)W*r7&;7X8y<6#cV9bI-BGBO2V{ zD8Ih0ny%t(i4Un}S4Calw|m`ZDx*I%UHi=0x2cHzrr&g1e(b9*;&26A0aw5ka0O0M zfmBN|zc|U$`=MO{SKv1V^nM65<(PR$Y*z;dYXQgw-3C5eFF_9KAjix@VtNQkspOO@ zxy6u_PJhU8G4qf(r9*6Iu9J6`+@Xl=PJgg)NKEXbE8q%zS3rAjqSX4oqD}Pw8sl&U zT!DY8fE3I1a>2vp+B!O>*4jY3rG0_17S6#+G1*EnU$hio9>oQH=6uXNB(`+=EuHK? N0;-F{75EDUJ^?cwC)xl2 literal 0 HcmV?d00001 diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 76288595dc5af..880412fdb5d3f 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -15,18 +15,23 @@ def initialize(attribute, operand) def ==(other) super and @attribute == other.attribute and @operand == other.operand end - - def qualify - self.class.new(attribute.qualify, operand.qualify) - end def bind(relation) - self.class.new(attribute.bind(relation), operand.bind(relation)) + __collect__{ |x| x.bind(relation) } + end + + def qualify + __collect__(&:qualify) end def to_sql(strategy = Sql::Predicate.new) "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" end + + protected + def __collect__ + self.class.new(yield(attribute), yield(operand)) + end end class Equality < Binary diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index 7910223673fb4..bcdfaa7d537ad 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -7,15 +7,11 @@ def initialize(relation, options) end def ==(other) - self.class == other.class and - relation == other.relation and - groupings == other.groupings and + self.class == other.class and + relation == other.relation and + groupings == other.groupings and expressions == other.expressions end - - def qualify - Aggregation.new(relation.qualify, :expressions => expressions.collect(&:qualify), :groupings => groupings.collect(&:qualify)) - end def attributes expressions.collect { |e| e.bind(self) } @@ -24,5 +20,10 @@ def attributes def aggregation? true end + + protected + def __collect__(&block) + Aggregation.new(relation.__collect__(&block), :expressions => expressions.collect(&block), :groupings => groupings.collect(&block)) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 941a95c58e9c4..cc6e9b09b8a41 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -1,15 +1,19 @@ module ActiveRelation class Alias < Compound attr_reader :alias + + def initialize(relation, aliaz) + @relation, @alias = relation, aliaz + end def aliased_prefix_for(attribute) self[attribute] and @alias end - - def initialize(relation, aliaz) - @relation, @alias = relation, aliaz + + def __collect__(&block) + Alias.new(relation.__collect__(&block), @alias) end - + def ==(other) self.class == other.class and relation == other.relation and diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index d11d09fbf6766..a02fbbeef56b6 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -8,5 +8,9 @@ class Compound < Relation def attributes relation.attributes.collect { |a| a.bind(self) } end + + def qualify + __collect__(&:qualify) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index c61680fd55a3c..a5d2b5355b758 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -15,7 +15,7 @@ def ==(other) end def qualify - Join.new(join_sql, relation1.qualify, relation2.qualify, *predicates.collect(&:qualify)) + __collect__(&:qualify) end def attributes @@ -48,5 +48,9 @@ def selects def table_sql relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) end + + def __collect__(&block) + Join.new(join_sql, relation1.__collect__(&block), relation2.__collect__(&block), *predicates.collect(&block)) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index a23da967fde8d..90568a90ac3f8 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -11,8 +11,9 @@ def ==(other) orders == other.orders end - def qualify - Order.new(relation.qualify, *orders.collect(&:qualify)) + protected + def __collect__(&block) + Order.new(relation.__collect__(&block), *orders.collect(&block)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index d0c68869bddd0..3fb594e2bb78b 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -15,9 +15,10 @@ def ==(other) relation == other.relation and projections == other.projections end - - def qualify - Projection.new(relation.qualify, *projections.collect(&:qualify)) + + protected + def __collect__(&block) + Projection.new(relation.__collect__(&block), *projections.collect(&block)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb index 7f120ab9e5798..5cc5db094d510 100644 --- a/lib/active_relation/relations/range.rb +++ b/lib/active_relation/relations/range.rb @@ -19,8 +19,9 @@ def offset range.begin end - def qualify - Range.new(relation.qualify, range) + protected + def __collect__(&block) + Range.new(relation.__collect__(&block), range) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index c65120a75c2da..1c48d8be02403 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -104,6 +104,10 @@ def to_sql(strategy = Sql::Select.new) alias_method :to_s, :to_sql protected + def __collect__ + yield self + end + def connection ActiveRecord::Base.connection end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 20e79ebefb8dd..718dbfe30f93b 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -13,15 +13,16 @@ def ==(other) attribute == other.attribute and pseudonym == other.pseudonym end - - def qualify - Rename.new(relation.qualify, attribute.qualify => pseudonym) - end def attributes relation.attributes.collect(&method(:baptize)) end + protected + def __collect__(&block) + Rename.new(relation.__collect__(&block), yield(attribute) => pseudonym) + end + private def baptize(attribute) (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).bind(self) rescue nil diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index 98f56b0cbd7e1..93e0e16dc5276 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -12,14 +12,15 @@ def ==(other) relation == other.relation and predicate == other.predicate end - - def qualify - Selection.new(relation.qualify, predicate.qualify) - end - + protected def selects relation.send(:selects) + [predicate] end + + def __collect__(&block) + Selection.new(relation.__collect__(&block), yield(predicate)) + end + end end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index d85c2680198ae..18c851c847bdf 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -25,7 +25,7 @@ def prefix_for(attribute) def table_sql "#{quote_table_name(name)}" end - + private def qualifications attributes.zip(attributes.collect(&:qualified_name)).to_hash From 7354602f6f11db09f7e58a833dcf9cb141abf50a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 16 Feb 2008 20:55:29 -0800 Subject: [PATCH 0065/1492] adding support for scalar selects --- lib/active_relation/sql.rb | 4 ++-- spec/active_relation/predicates/binary_spec.rb | 2 +- spec/active_relation/relations/projection_spec.rb | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index bc658271c3f1b..0384de44ef8c7 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -18,7 +18,7 @@ def attribute(relation_name, attribute_name, aliaz) end def select(select_sql, aliaz) - "(#{select_sql}) AS #{quote_column_name(aliaz)}" + "(#{select_sql})" + (aliaz ? " AS #{quote_column_name(aliaz)}" : "") end end @@ -44,7 +44,7 @@ def select(select_sql, aliaz) class Aggregation < Strategy def select(select_sql, aliaz) - "(#{select_sql}) AS #{quote_table_name(aliaz)}" + "(#{select_sql}) AS #{quote_table_name(aliaz)}" end end diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index 127375f24cced..89a40d2bf366d 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -41,7 +41,7 @@ def predicate_sql end describe '#to_sql' do - it 'manufactures correct sql' do + it 'manufactures sql with a binary operation' do ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" `users`.`id` <=> `photos`.`id` """) diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb index 739a16c8ef4f8..2bc4ed1d6e7da 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/relations/projection_spec.rb @@ -44,6 +44,12 @@ module ActiveRelation FROM `users` """) end + + it "manufactures sql with scalar selects" do + Projection.new(@relation, Projection.new(@relation, @relation[:name])).to_sql.should be_like(""" + SELECT (SELECT `users`.`name` FROM `users`) FROM `users` + """) + end end end end \ No newline at end of file From b0eb6244122a5fd86beaaabb6381835aebb139d4 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 18 Feb 2008 11:31:14 -0800 Subject: [PATCH 0066/1492] rename __collect__ to descend since the double underscores were ugly. --- lib/active_relation/predicates.rb | 6 +++--- lib/active_relation/relations/aggregation.rb | 4 ++-- lib/active_relation/relations/alias.rb | 4 ++-- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/join.rb | 6 +++--- lib/active_relation/relations/order.rb | 4 ++-- lib/active_relation/relations/projection.rb | 4 ++-- lib/active_relation/relations/range.rb | 4 ++-- lib/active_relation/relations/relation.rb | 2 +- lib/active_relation/relations/rename.rb | 4 ++-- lib/active_relation/relations/selection.rb | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 880412fdb5d3f..67d910b9d140e 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -17,11 +17,11 @@ def ==(other) end def bind(relation) - __collect__{ |x| x.bind(relation) } + descend{ |x| x.bind(relation) } end def qualify - __collect__(&:qualify) + descend(&:qualify) end def to_sql(strategy = Sql::Predicate.new) @@ -29,7 +29,7 @@ def to_sql(strategy = Sql::Predicate.new) end protected - def __collect__ + def descend self.class.new(yield(attribute), yield(operand)) end end diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index bcdfaa7d537ad..de21d2f3839e1 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -22,8 +22,8 @@ def aggregation? end protected - def __collect__(&block) - Aggregation.new(relation.__collect__(&block), :expressions => expressions.collect(&block), :groupings => groupings.collect(&block)) + def descend(&block) + Aggregation.new(relation.descend(&block), :expressions => expressions.collect(&block), :groupings => groupings.collect(&block)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index cc6e9b09b8a41..0bfa895951f65 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -10,8 +10,8 @@ def aliased_prefix_for(attribute) self[attribute] and @alias end - def __collect__(&block) - Alias.new(relation.__collect__(&block), @alias) + def descend(&block) + Alias.new(relation.descend(&block), @alias) end def ==(other) diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index a02fbbeef56b6..2839862987fb6 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -10,7 +10,7 @@ def attributes end def qualify - __collect__(&:qualify) + descend(&:qualify) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index a5d2b5355b758..6185293c8aea4 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -15,7 +15,7 @@ def ==(other) end def qualify - __collect__(&:qualify) + descend(&:qualify) end def attributes @@ -49,8 +49,8 @@ def table_sql relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) end - def __collect__(&block) - Join.new(join_sql, relation1.__collect__(&block), relation2.__collect__(&block), *predicates.collect(&block)) + def descend(&block) + Join.new(join_sql, relation1.descend(&block), relation2.descend(&block), *predicates.collect(&block)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index 90568a90ac3f8..cee6278c802da 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -12,8 +12,8 @@ def ==(other) end protected - def __collect__(&block) - Order.new(relation.__collect__(&block), *orders.collect(&block)) + def descend(&block) + Order.new(relation.descend(&block), *orders.collect(&block)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index 3fb594e2bb78b..cd08a5aa5449a 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -17,8 +17,8 @@ def ==(other) end protected - def __collect__(&block) - Projection.new(relation.__collect__(&block), *projections.collect(&block)) + def descend(&block) + Projection.new(relation.descend(&block), *projections.collect(&block)) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb index 5cc5db094d510..14a86b8c65cd9 100644 --- a/lib/active_relation/relations/range.rb +++ b/lib/active_relation/relations/range.rb @@ -20,8 +20,8 @@ def offset end protected - def __collect__(&block) - Range.new(relation.__collect__(&block), range) + def descend(&block) + Range.new(relation.descend(&block), range) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 1c48d8be02403..7d33b42faf4cc 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -104,7 +104,7 @@ def to_sql(strategy = Sql::Select.new) alias_method :to_s, :to_sql protected - def __collect__ + def descend yield self end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 718dbfe30f93b..1705d9ba8c2ce 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -19,8 +19,8 @@ def attributes end protected - def __collect__(&block) - Rename.new(relation.__collect__(&block), yield(attribute) => pseudonym) + def descend(&block) + Rename.new(relation.descend(&block), yield(attribute) => pseudonym) end private diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index 93e0e16dc5276..f8cd235419959 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -18,8 +18,8 @@ def selects relation.send(:selects) + [predicate] end - def __collect__(&block) - Selection.new(relation.__collect__(&block), yield(predicate)) + def descend(&block) + Selection.new(relation.descend(&block), yield(predicate)) end end From 2a91d807538a4d39c5755fb83a5e9462e8056fa6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 18 Feb 2008 15:08:03 -0800 Subject: [PATCH 0067/1492] made descend public; added test coverage for it; tests for qualify are now in terms of descend --- lib/active_relation/predicates.rb | 1 - lib/active_relation/relations/aggregation.rb | 1 - lib/active_relation/relations/join.rb | 8 ++++---- lib/active_relation/relations/order.rb | 1 - lib/active_relation/relations/projection.rb | 1 - lib/active_relation/relations/range.rb | 1 - lib/active_relation/relations/relation.rb | 1 - lib/active_relation/relations/rename.rb | 1 - lib/active_relation/relations/selection.rb | 9 ++++----- spec/active_relation/predicates/binary_spec.rb | 9 ++++++++- spec/active_relation/relations/join_spec.rb | 3 +-- spec/active_relation/relations/order_spec.rb | 11 +++++++++-- spec/active_relation/relations/projection_spec.rb | 9 ++++++++- spec/active_relation/relations/range_spec.rb | 10 ++++++++-- spec/active_relation/relations/rename_spec.rb | 13 ++++++++++--- spec/active_relation/relations/selection_spec.rb | 11 +++++++++-- 16 files changed, 61 insertions(+), 29 deletions(-) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 67d910b9d140e..c4f7b835120fb 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -28,7 +28,6 @@ def to_sql(strategy = Sql::Predicate.new) "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" end - protected def descend self.class.new(yield(attribute), yield(operand)) end diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index de21d2f3839e1..d3a026820d315 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -21,7 +21,6 @@ def aggregation? true end - protected def descend(&block) Aggregation.new(relation.descend(&block), :expressions => expressions.collect(&block), :groupings => groupings.collect(&block)) end diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 6185293c8aea4..850a773ee5d46 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -31,6 +31,10 @@ def prefix_for(attribute) end alias_method :aliased_prefix_for, :prefix_for + def descend(&block) + Join.new(join_sql, relation1.descend(&block), relation2.descend(&block), *predicates.collect(&block)) + end + protected def joins right_table_sql = relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql) @@ -48,9 +52,5 @@ def selects def table_sql relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) end - - def descend(&block) - Join.new(join_sql, relation1.descend(&block), relation2.descend(&block), *predicates.collect(&block)) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index cee6278c802da..e6395aecd7607 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -11,7 +11,6 @@ def ==(other) orders == other.orders end - protected def descend(&block) Order.new(relation.descend(&block), *orders.collect(&block)) end diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index cd08a5aa5449a..c478ae145fa59 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -16,7 +16,6 @@ def ==(other) projections == other.projections end - protected def descend(&block) Projection.new(relation.descend(&block), *projections.collect(&block)) end diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb index 14a86b8c65cd9..fafdef5902b4e 100644 --- a/lib/active_relation/relations/range.rb +++ b/lib/active_relation/relations/range.rb @@ -19,7 +19,6 @@ def offset range.begin end - protected def descend(&block) Range.new(relation.descend(&block), range) end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 7d33b42faf4cc..e0ae882475b07 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -103,7 +103,6 @@ def to_sql(strategy = Sql::Select.new) end alias_method :to_s, :to_sql - protected def descend yield self end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 1705d9ba8c2ce..9a0e5552c701d 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -18,7 +18,6 @@ def attributes relation.attributes.collect(&method(:baptize)) end - protected def descend(&block) Rename.new(relation.descend(&block), yield(attribute) => pseudonym) end diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index f8cd235419959..e7a91f757245a 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -13,14 +13,13 @@ def ==(other) predicate == other.predicate end - protected - def selects - relation.send(:selects) + [predicate] - end - def descend(&block) Selection.new(relation.descend(&block), yield(predicate)) end + protected + def selects + relation.send(:selects) + [predicate] + end end end \ No newline at end of file diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/predicates/binary_spec.rb index 89a40d2bf366d..4f37a6aa7e451 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/predicates/binary_spec.rb @@ -27,8 +27,15 @@ def predicate_sql end describe '#qualify' do + it "descends" do + ConcreteBinary.new(@attribute1, @attribute2).qualify \ + .should == ConcreteBinary.new(@attribute1, @attribute2).descend(&:qualify) + end + end + + describe '#descend' do it "distributes over the predicates and attributes" do - ConcreteBinary.new(@attribute1, @attribute2).qualify. \ + ConcreteBinary.new(@attribute1, @attribute2).descend(&:qualify). \ should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) end end diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/relations/join_spec.rb index b60238fa7ef75..77c6baeac4436 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/relations/join_spec.rb @@ -25,14 +25,13 @@ module ActiveRelation end end - describe '#qualify' do + describe '#descend' do it 'distributes over the relations and predicates' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ should == Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) end end - describe '#prefix_for' do it 'needs a test' do pending diff --git a/spec/active_relation/relations/order_spec.rb b/spec/active_relation/relations/order_spec.rb index 12b976143114e..32a54e72fa9fe 100644 --- a/spec/active_relation/relations/order_spec.rb +++ b/spec/active_relation/relations/order_spec.rb @@ -8,9 +8,16 @@ module ActiveRelation end describe '#qualify' do - it "distributes over the relation and attributes" do + it "descends" do Order.new(@relation, @attribute).qualify. \ - should == Order.new(@relation.qualify, @attribute.qualify) + should == Order.new(@relation, @attribute).descend(&:qualify) + end + end + + describe '#descend' do + it "distributes over the relation and attributes" do + Order.new(@relation, @attribute).descend(&:qualify). \ + should == Order.new(@relation.descend(&:qualify), @attribute.qualify) end end diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/relations/projection_spec.rb index 2bc4ed1d6e7da..9f6b6797cecf6 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/relations/projection_spec.rb @@ -33,7 +33,14 @@ module ActiveRelation describe '#qualify' do it "distributes over the relation and attributes" do Projection.new(@relation, @attribute).qualify. \ - should == Projection.new(@relation.qualify, @attribute.qualify) + should == Projection.new(@relation, @attribute).descend(&:qualify) + end + end + + describe '#descend' do + it "distributes over the relation and attributes" do + Projection.new(@relation, @attribute).descend(&:qualify). \ + should == Projection.new(@relation.descend(&:qualify), @attribute.qualify) end end diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/relations/range_spec.rb index a2f84c2e88e68..f27b6106e87a6 100644 --- a/spec/active_relation/relations/range_spec.rb +++ b/spec/active_relation/relations/range_spec.rb @@ -8,11 +8,17 @@ module ActiveRelation end describe '#qualify' do + it "descends" do + Range.new(@relation, @range).qualify.should == Range.new(@relation, @range).descend(&:qualify) + end + end + + describe '#descend' do it "distributes over the relation" do - Range.new(@relation, @range).qualify.should == Range.new(@relation.qualify, @range) + Range.new(@relation, @range).descend(&:qualify).should == Range.new(@relation.descend(&:qualify), @range) end end - + describe '#to_sql' do it "manufactures sql with limit and offset" do range_size = @range.last - @range.first + 1 diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/relations/rename_spec.rb index deb538615b163..6c6bd450f54c9 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/relations/rename_spec.rb @@ -37,11 +37,18 @@ module ActiveRelation @renamed_relation.should have(@relation.attributes.size).attributes end end - + describe '#qualify' do - it "distributes over the relation and renames" do + it "descends" do Rename.new(@relation, @relation[:id] => :schmid).qualify. \ - should == Rename.new(@relation.qualify, @relation[:id].qualify => :schmid) + should == Rename.new(@relation, @relation[:id] => :schmid).descend(&:qualify) + end + end + + describe '#descend' do + it "distributes over the relation and renames" do + Rename.new(@relation, @relation[:id] => :schmid).descend(&:qualify). \ + should == Rename.new(@relation.descend(&:qualify), @relation[:id].qualify => :schmid) end end diff --git a/spec/active_relation/relations/selection_spec.rb b/spec/active_relation/relations/selection_spec.rb index 66ad54de1962f..b6db6bfd4ae63 100644 --- a/spec/active_relation/relations/selection_spec.rb +++ b/spec/active_relation/relations/selection_spec.rb @@ -16,9 +16,16 @@ module ActiveRelation end describe '#qualify' do - it "distributes over the relation and predicates" do + it "descends" do Selection.new(@relation, @predicate).qualify. \ - should == Selection.new(@relation.qualify, @predicate.qualify) + should == Selection.new(@relation, @predicate).descend(&:qualify) + end + end + + describe '#descend' do + it "distributes over the relation and predicates" do + Selection.new(@relation, @predicate).descend(&:qualify). \ + should == Selection.new(@relation.descend(&:qualify), @predicate.descend(&:qualify)) end end From ae217d5816c766443c6e6737d04073f40614b564 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 18 Feb 2008 20:20:51 -0800 Subject: [PATCH 0068/1492] extracted conditionals concerning the "externalizing" of relations under a join. --- lib/active_relation/relations/alias.rb | 4 +- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/join.rb | 51 ++++++++++++++------ lib/active_relation/relations/relation.rb | 4 ++ lib/active_relation/relations/table.rb | 1 - spec/active_relation/relations/alias_spec.rb | 11 +---- spec/active_relation/relations/table_spec.rb | 6 --- 7 files changed, 46 insertions(+), 33 deletions(-) diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index 0bfa895951f65..f24b1d743c76a 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -6,8 +6,8 @@ def initialize(relation, aliaz) @relation, @alias = relation, aliaz end - def aliased_prefix_for(attribute) - self[attribute] and @alias + def alias? + true end def descend(&block) diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 2839862987fb6..094c6e29dd41c 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,7 +2,7 @@ module ActiveRelation class Compound < Relation attr_reader :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, - :offset, :name, :alias, :aggregation?, :prefix_for, :aliased_prefix_for, + :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :to => :relation def attributes diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 850a773ee5d46..70c85bb1e0454 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -19,17 +19,14 @@ def qualify end def attributes - [ - relation1.attributes.collect(&:to_attribute), - relation2.attributes.collect(&:to_attribute), - ].flatten.collect { |a| a.bind(self) } + (externalize(relation1).attributes + + externalize(relation2).attributes).collect { |a| a.bind(self) } end def prefix_for(attribute) - relation1.aliased_prefix_for(attribute) or - relation2.aliased_prefix_for(attribute) + externalize(relation1).prefix_for(attribute) or + externalize(relation2).prefix_for(attribute) end - alias_method :aliased_prefix_for, :prefix_for def descend(&block) Join.new(join_sql, relation1.descend(&block), relation2.descend(&block), *predicates.collect(&block)) @@ -37,20 +34,46 @@ def descend(&block) protected def joins - right_table_sql = relation2.aggregation?? relation2.to_sql(Sql::Aggregation.new) : relation2.send(:table_sql) - this_join = [join_sql, right_table_sql, "ON", predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ')].join(" ") + this_join = [ + join_sql, + externalize(relation2).table_sql, + "ON", + predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ') + ].join(" ") [relation1.joins, relation2.joins, this_join].compact.join(" ") end def selects - [ - (relation1.send(:selects) unless relation1.aggregation?), - (relation2.send(:selects) unless relation2.aggregation?) - ].compact.flatten + externalize(relation1).selects + externalize(relation2).selects end def table_sql - relation1.aggregation?? relation1.to_sql(Sql::Aggregation.new) : relation1.send(:table_sql) + externalize(relation1).table_sql + end + + private + def externalize(relation) + Externalizer.new(relation) + end + + Externalizer = Struct.new(:relation) do + def table_sql + relation.aggregation?? relation.to_sql(Sql::Aggregation.new) : relation.send(:table_sql) + end + + def selects + relation.aggregation?? [] : relation.send(:selects) + end + + def attributes + relation.aggregation?? relation.attributes.collect(&:to_attribute) : relation.attributes + end + + def prefix_for(attribute) + if relation[attribute] + relation.alias?? relation.alias : relation.prefix_for(attribute) + end + end end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index e0ae882475b07..f20561c5b2594 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -88,6 +88,10 @@ def group(*groupings) def aggregation? false end + + def alias? + false + end def to_sql(strategy = Sql::Select.new) strategy.select [ diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 18c851c847bdf..d0fc2b24756ba 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -19,7 +19,6 @@ def qualify def prefix_for(attribute) self[attribute] and name end - alias_method :aliased_prefix_for, :prefix_for protected def table_sql diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/relations/alias_spec.rb index a2deae2840cec..6c9724bb3d602 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/relations/alias_spec.rb @@ -7,16 +7,9 @@ module ActiveRelation @alias_relation = Alias.new(@relation, :foo) end - describe '#prefix_for' do - it "delegates to the underlying relation" do - @alias_relation.prefix_for(@relation[:id]).should == :users - end - end - - describe '#aliased_prefix_for' do + describe '#alias' do it "returns the alias" do - @alias_relation.aliased_prefix_for(@relation[:id]).should == :foo - @alias_relation.aliased_prefix_for(:does_not_exist).should be_nil + @alias_relation.alias.should == :foo end end end diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/relations/table_spec.rb index 13a919844758f..a7b5b5f69bebe 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/relations/table_spec.rb @@ -52,12 +52,6 @@ module ActiveRelation end end - describe '#aliased_prefix_for' do - it "returns the table name" do - @relation.aliased_prefix_for(@relation[:id]).should == :users - end - end - describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do @relation.attributes.should == [ From f6d9b74ad0c9f061f9bca71d24132a0a7b066291 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 23 Feb 2008 16:12:16 -0800 Subject: [PATCH 0069/1492] organizing tests into unit/integration --- README | 1 + spec/active_relation/{ => unit}/predicates/binary_spec.rb | 2 +- spec/active_relation/{ => unit}/predicates/equality_spec.rb | 2 +- .../{ => unit}/predicates/relation_inclusion_spec.rb | 2 +- spec/active_relation/{ => unit}/primitives/attribute_spec.rb | 2 +- spec/active_relation/{ => unit}/primitives/expression_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/alias_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/compound_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/deletion_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/insertion_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/join_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/order_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/projection_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/range_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/relation_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/rename_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/selection_spec.rb | 2 +- spec/active_relation/{ => unit}/relations/table_spec.rb | 2 +- 18 files changed, 18 insertions(+), 17 deletions(-) rename spec/active_relation/{ => unit}/predicates/binary_spec.rb (96%) rename spec/active_relation/{ => unit}/predicates/equality_spec.rb (92%) rename spec/active_relation/{ => unit}/predicates/relation_inclusion_spec.rb (91%) rename spec/active_relation/{ => unit}/primitives/attribute_spec.rb (98%) rename spec/active_relation/{ => unit}/primitives/expression_spec.rb (94%) rename spec/active_relation/{ => unit}/relations/alias_spec.rb (78%) rename spec/active_relation/{ => unit}/relations/compound_spec.rb (87%) rename spec/active_relation/{ => unit}/relations/deletion_spec.rb (88%) rename spec/active_relation/{ => unit}/relations/insertion_spec.rb (90%) rename spec/active_relation/{ => unit}/relations/join_spec.rb (98%) rename spec/active_relation/{ => unit}/relations/order_spec.rb (91%) rename spec/active_relation/{ => unit}/relations/projection_spec.rb (96%) rename spec/active_relation/{ => unit}/relations/range_spec.rb (92%) rename spec/active_relation/{ => unit}/relations/relation_spec.rb (98%) rename spec/active_relation/{ => unit}/relations/rename_spec.rb (96%) rename spec/active_relation/{ => unit}/relations/selection_spec.rb (95%) rename spec/active_relation/{ => unit}/relations/table_spec.rb (96%) diff --git a/README b/README index e69de29bb2d1d..9e1efa331fb10 100644 --- a/README +++ b/README @@ -0,0 +1 @@ +ActiveRelation is a Relational Algebra for Ruby. It simplifies both the simplest and the most complex of SQL queries and it transparently 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 what makes your ORM different. It can also be used for in-memory relational modeling and querying, independent of a database. \ No newline at end of file diff --git a/spec/active_relation/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb similarity index 96% rename from spec/active_relation/predicates/binary_spec.rb rename to spec/active_relation/unit/predicates/binary_spec.rb index 4f37a6aa7e451..44c1a1a7a090d 100644 --- a/spec/active_relation/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Binary do diff --git a/spec/active_relation/predicates/equality_spec.rb b/spec/active_relation/unit/predicates/equality_spec.rb similarity index 92% rename from spec/active_relation/predicates/equality_spec.rb rename to spec/active_relation/unit/predicates/equality_spec.rb index f947bc6fe70d7..fd30846c70188 100644 --- a/spec/active_relation/predicates/equality_spec.rb +++ b/spec/active_relation/unit/predicates/equality_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Equality do diff --git a/spec/active_relation/predicates/relation_inclusion_spec.rb b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb similarity index 91% rename from spec/active_relation/predicates/relation_inclusion_spec.rb rename to spec/active_relation/unit/predicates/relation_inclusion_spec.rb index 05039028eeb26..799be2308578d 100644 --- a/spec/active_relation/predicates/relation_inclusion_spec.rb +++ b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe RelationInclusion do diff --git a/spec/active_relation/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb similarity index 98% rename from spec/active_relation/primitives/attribute_spec.rb rename to spec/active_relation/unit/primitives/attribute_spec.rb index a931ea21503f6..e5a3792d85dcd 100644 --- a/spec/active_relation/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Attribute do diff --git a/spec/active_relation/primitives/expression_spec.rb b/spec/active_relation/unit/primitives/expression_spec.rb similarity index 94% rename from spec/active_relation/primitives/expression_spec.rb rename to spec/active_relation/unit/primitives/expression_spec.rb index 753f189e821c2..5506f52b86e9e 100644 --- a/spec/active_relation/primitives/expression_spec.rb +++ b/spec/active_relation/unit/primitives/expression_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Expression do diff --git a/spec/active_relation/relations/alias_spec.rb b/spec/active_relation/unit/relations/alias_spec.rb similarity index 78% rename from spec/active_relation/relations/alias_spec.rb rename to spec/active_relation/unit/relations/alias_spec.rb index 6c9724bb3d602..4a2144db82336 100644 --- a/spec/active_relation/relations/alias_spec.rb +++ b/spec/active_relation/unit/relations/alias_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Alias do diff --git a/spec/active_relation/relations/compound_spec.rb b/spec/active_relation/unit/relations/compound_spec.rb similarity index 87% rename from spec/active_relation/relations/compound_spec.rb rename to spec/active_relation/unit/relations/compound_spec.rb index b0f122ca979cd..03de27fb05259 100644 --- a/spec/active_relation/relations/compound_spec.rb +++ b/spec/active_relation/unit/relations/compound_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Compound do diff --git a/spec/active_relation/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb similarity index 88% rename from spec/active_relation/relations/deletion_spec.rb rename to spec/active_relation/unit/relations/deletion_spec.rb index 64b75d060083f..1a536e7aedf34 100644 --- a/spec/active_relation/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Deletion do diff --git a/spec/active_relation/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb similarity index 90% rename from spec/active_relation/relations/insertion_spec.rb rename to spec/active_relation/unit/relations/insertion_spec.rb index f16ab8cc23cf9..a0427bc74f99b 100644 --- a/spec/active_relation/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Insertion do diff --git a/spec/active_relation/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb similarity index 98% rename from spec/active_relation/relations/join_spec.rb rename to spec/active_relation/unit/relations/join_spec.rb index 77c6baeac4436..bc55a72e55338 100644 --- a/spec/active_relation/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Join do diff --git a/spec/active_relation/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb similarity index 91% rename from spec/active_relation/relations/order_spec.rb rename to spec/active_relation/unit/relations/order_spec.rb index 32a54e72fa9fe..15f08d70ee901 100644 --- a/spec/active_relation/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Order do diff --git a/spec/active_relation/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb similarity index 96% rename from spec/active_relation/relations/projection_spec.rb rename to spec/active_relation/unit/relations/projection_spec.rb index 9f6b6797cecf6..75a4672642311 100644 --- a/spec/active_relation/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Projection do diff --git a/spec/active_relation/relations/range_spec.rb b/spec/active_relation/unit/relations/range_spec.rb similarity index 92% rename from spec/active_relation/relations/range_spec.rb rename to spec/active_relation/unit/relations/range_spec.rb index f27b6106e87a6..501a8d3641824 100644 --- a/spec/active_relation/relations/range_spec.rb +++ b/spec/active_relation/unit/relations/range_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Range do diff --git a/spec/active_relation/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb similarity index 98% rename from spec/active_relation/relations/relation_spec.rb rename to spec/active_relation/unit/relations/relation_spec.rb index a25dc4b1db352..a80df928c7365 100644 --- a/spec/active_relation/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Relation do diff --git a/spec/active_relation/relations/rename_spec.rb b/spec/active_relation/unit/relations/rename_spec.rb similarity index 96% rename from spec/active_relation/relations/rename_spec.rb rename to spec/active_relation/unit/relations/rename_spec.rb index 6c6bd450f54c9..33a89e6a49981 100644 --- a/spec/active_relation/relations/rename_spec.rb +++ b/spec/active_relation/unit/relations/rename_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Rename do diff --git a/spec/active_relation/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb similarity index 95% rename from spec/active_relation/relations/selection_spec.rb rename to spec/active_relation/unit/relations/selection_spec.rb index b6db6bfd4ae63..afe002186ed41 100644 --- a/spec/active_relation/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Selection do diff --git a/spec/active_relation/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb similarity index 96% rename from spec/active_relation/relations/table_spec.rb rename to spec/active_relation/unit/relations/table_spec.rb index a7b5b5f69bebe..3b02f80701ec9 100644 --- a/spec/active_relation/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation describe Table do From d3c7c37658aeba0c9cedb3c3a57e2a5a8968d58f Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 23 Feb 2008 16:49:49 -0800 Subject: [PATCH 0070/1492] added primitive update functionality --- README | 61 +++++++++++++++++++++++++++++++- lib/active_relation/relations.rb | 1 + 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/README b/README index 9e1efa331fb10..2b661bfebb169 100644 --- a/README +++ b/README @@ -1 +1,60 @@ -ActiveRelation is a Relational Algebra for Ruby. It simplifies both the simplest and the most complex of SQL queries and it transparently 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 what makes your ORM different. It can also be used for in-memory relational modeling and querying, independent of a database. \ No newline at end of file +== Abstract == + +ActiveRelation is a Relational Algebra for Ruby. It simplifies the generation of both the simplest and the most complex of SQL queries and it transparently 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. + +== 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: + + ActiveRelation::Table.new(:users).to_sql + +In fact, you will probably never call `#to_sql` directly. Let `users = ActiveRelation::Table.new(:users)`. You can iterate through all rows in the `users` table like this: + + users.each { |user| ... } + +In other words, Arel relations behave similar regular Ruby collections. Let's have a look at a concrete example: + + users.first # => {'id' => 10, 'name' => 'bob'} + +As you can see, Arel converts the rows into a hash, the values of which are the appropriate Ruby primitive (integers, strings, and so forth). + +== Relational Algebra == + +Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE`), rather they represent a collection of data that you can select from, insert into, update, and delete.For example, to insert a row into the users table, do the following: + + users.insert({'id' => 11, 'name' => 'amy'}) + +To delete all users: + + users.delete + +To update: + + users.update({'name' => 'carl'}) + +As you can see, the `relation` users does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate queries to do the various CRUD operations. + +=== More Sophisticated Queries === + +Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: + + users.select(users[:name].equals('amy')) # => SELECT * FROM users WHERE users.name = 'amy' + +What would, in SQL, be part of the `SELECT` clause is called here a `projection`: + + users.project(users[:id]) # => SELECT users.id FROM users + +The best property of the Relational is compositionality, or closure under all operations. For example, to combine the two previous queries: + + users \ + .select(users[:name].equals('amy')) \ + .project(users[:id]) + # => SELECT users.id FROM users WHERE users.name = 'amy' + +== Contributions == + +I appreciate all contributions to ActiveRelation. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. \ No newline at end of file diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 27dd229f3fde3..97c17b3792a79 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -10,4 +10,5 @@ require 'active_relation/relations/rename' require 'active_relation/relations/deletion' require 'active_relation/relations/insertion' +require 'active_relation/relations/update' require 'active_relation/relations/alias' \ No newline at end of file From da667908f6c84ecb5dbf7c3e2b9d22ffe4c386a7 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 23 Feb 2008 16:51:54 -0800 Subject: [PATCH 0071/1492] updating functionality --- .../unit/relations/update_spec.rb | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 spec/active_relation/unit/relations/update_spec.rb diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb new file mode 100644 index 0000000000000..c26e7fb525889 --- /dev/null +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module ActiveRelation + describe Update do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql updating attributes' do + Update.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + UPDATE `users` + SET `users`.`name` = 'nick' + """) + end + + it 'manufactures sql updating a selection relation' do + Update.new(@relation.select(@relation[:id].equals(1)), @relation[:name] => "nick").to_sql.should be_like(""" + UPDATE `users` + SET `users`.`name` = 'nick' + WHERE `users`.`id` = 1 + """) + end + + end + end +end \ No newline at end of file From f10d3be703cada60783c671866dd48194b800002 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 23 Feb 2008 16:52:06 -0800 Subject: [PATCH 0072/1492] updating functionality --- lib/active_relation/relations/update.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lib/active_relation/relations/update.rb diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb new file mode 100644 index 0000000000000..d28608fdd54b6 --- /dev/null +++ b/lib/active_relation/relations/update.rb @@ -0,0 +1,17 @@ +module ActiveRelation + class Update < Compound + attr_reader :assignments + + def initialize(relation, assignments) + @relation, @assignments = relation, assignments + end + + def to_sql(strategy = nil) + [ + "UPDATE #{table_sql} SET", + assignments.inject([]) { |assignments, (attribute, value)| assignments << "#{attribute.to_sql} = #{value.to_sql}" }.join(" "), + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ].join("\n") + end + end +end \ No newline at end of file From 51fdd769c0cb096d6e6f04afc3ebb91833d625bc Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 23 Feb 2008 19:29:18 -0800 Subject: [PATCH 0073/1492] Introduced concept of session. It does not yet support multiple databases, nor transactions, but it's a start! --- lib/active_relation/relations.rb | 3 +- lib/active_relation/relations/deletion.rb | 7 +- lib/active_relation/relations/insertion.rb | 13 ++-- lib/active_relation/relations/relation.rb | 45 +++++++----- lib/active_relation/relations/update.rb | 8 ++- lib/active_relation/sessions/session.rb | 38 ++++++++++ lib/active_relation/sql.rb | 2 +- .../integration/scratch_spec.rb | 18 ----- .../unit/relations/insertion_spec.rb | 9 --- .../unit/relations/relation_spec.rb | 41 +++++++---- .../unit/relations/update_spec.rb | 1 - .../unit/session/session_spec.rb | 70 +++++++++++++++++++ spec/spec_helper.rb | 4 +- 13 files changed, 189 insertions(+), 70 deletions(-) create mode 100644 lib/active_relation/sessions/session.rb create mode 100644 spec/active_relation/unit/session/session_spec.rb diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 97c17b3792a79..f992fca8be068 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -11,4 +11,5 @@ require 'active_relation/relations/deletion' require 'active_relation/relations/insertion' require 'active_relation/relations/update' -require 'active_relation/relations/alias' \ No newline at end of file +require 'active_relation/relations/alias' +require 'active_relation/sessions/session' \ No newline at end of file diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index 4ac40a146b2a5..f3d81baf27986 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -10,6 +10,11 @@ def to_sql(strategy = nil) "FROM #{table_sql}", ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) ].compact.join("\n") - end + end + + def ==(other) + self.class == other.class and + relation == other.relation + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 31e4339ee084e..dd5b8ec530051 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -11,13 +11,14 @@ def to_sql(strategy = nil) "INSERT", "INTO #{table_sql}", "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES #{inserts.collect(&:to_sql).join(', ')}" + "VALUES #{record.to_sql}" ].join("\n") - end - - protected - def inserts - relation.inserts + [record] + end + + def ==(other) + self.class == other.class and + relation == other.relation and + record == other.record end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index f20561c5b2594..1d5e194923e53 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -2,18 +2,22 @@ module ActiveRelation class Relation include Sql::Quoting - module Iteration - include Enumerable - + def session + Session.instance + end + + module Enumerable + include ::Enumerable + def each(&block) - connection.select_all(to_s).each(&block) + session.read(self).each(&block) end - + def first - connection.select_one(to_s) + session.read(self).first end end - include Iteration + include Enumerable module Operations def join(other) @@ -58,18 +62,25 @@ def order(*attributes) def rename(attribute, aliaz) Rename.new(self, attribute => aliaz) end - - def insert(record) - Insertion.new(self, record) - end - - def delete - Deletion.new(self) - end - + def aggregate(*expressions) AggregateOperation.new(self, expressions) end + + module Writes + def insert(record) + session.create Insertion.new(self, record); self + end + + def update(assignments) + session.update Update.new(self, assignments); self + end + + def delete + session.delete Deletion.new(self); self + end + end + include Writes JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do def on(*predicates) @@ -84,7 +95,7 @@ def group(*groupings) end end include Operations - + def aggregation? false end diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index d28608fdd54b6..8909ee80a016d 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -12,6 +12,12 @@ def to_sql(strategy = nil) assignments.inject([]) { |assignments, (attribute, value)| assignments << "#{attribute.to_sql} = #{value.to_sql}" }.join(" "), ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) ].join("\n") - end + end + + def ==(other) + self.class == other.class and + relation == other.relation and + assignments == other.assignments + end end end \ No newline at end of file diff --git a/lib/active_relation/sessions/session.rb b/lib/active_relation/sessions/session.rb new file mode 100644 index 0000000000000..d6e2ae71692c6 --- /dev/null +++ b/lib/active_relation/sessions/session.rb @@ -0,0 +1,38 @@ +require 'singleton' + +module ActiveRelation + class Session + include Singleton + + module CRUD + def connection + ActiveRecord::Base.connection + end + + def create(insert) + connection.insert(insert.to_sql) + end + + def read(select) + connection.select_all(select.to_sql) + end + + def update(update) + connection.update(update.to_sql) + end + + def delete(delete) + connection.delete(delete.to_sql) + end + end + include CRUD + + module Transactions + end + include Transactions + + module UnitOfWork + end + include UnitOfWork + end +end \ No newline at end of file diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 0384de44ef8c7..85bcb4107bd3c 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -2,7 +2,7 @@ module ActiveRelation module Sql module Quoting def connection - ActiveRecord::Base.connection + Session.instance.connection end delegate :quote_table_name, :quote_column_name, :quote, :to => :connection diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb index 4b02b22a11fa0..d6ec030518000 100644 --- a/spec/active_relation/integration/scratch_spec.rb +++ b/spec/active_relation/integration/scratch_spec.rb @@ -136,24 +136,6 @@ def photo_belongs_to_camera(photo_relation) """) end - describe 'write operations' do - it 'generates the query for user.destroy' do - @user.delete.to_sql.should be_like(""" - DELETE - FROM `users` - WHERE `users`.`id` = 1 - """) - end - - it 'generates an efficient query for two User.creates -- UnitOfWork is within reach!' do - @users.insert(@users[:name] => "humpty").insert(@users[:name] => "dumpty").to_sql.should be_like(""" - INSERT - INTO `users` - (`users`.`name`) VALUES ('humpty'), ('dumpty') - """) - end - end - describe 'with_scope' do it 'obviates the need for with_scope merging logic since, e.g., `with_scope :conditions => ...` is just a #select operation on the relation' do diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index a0427bc74f99b..a39c4aeaf367a 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -14,15 +14,6 @@ module ActiveRelation (`users`.`name`) VALUES ('nick') """) end - - it 'manufactures sql inserting the data for multiple items' do - nested_insertion = Insertion.new(@relation, @relation[:name] => "cobra") - Insertion.new(nested_insertion, nested_insertion[:name] => "commander").to_sql.should be_like(""" - INSERT - INTO `users` - (`users`.`name`) VALUES ('cobra'), ('commander') - """) - end end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index a80df928c7365..d3252c658bbb1 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -36,13 +36,13 @@ module ActiveRelation end end - describe '#Expression?' do + describe '#aggregation?' do it "returns false" do @relation.should_not be_aggregation end end - describe 'read operations' do + describe Relation::Operations do describe 'joins' do before do @predicate = @relation[:id].equals(@relation[:id]) @@ -105,20 +105,35 @@ module ActiveRelation should == Aggregation.new(@relation, :expressions => [@expresion, @expression2], :groupings => [@attribute1, @attribute2]) end end - end - - describe 'write operations' do - describe '#delete' do - it 'manufactures a deletion relation' do - @relation.delete.should be_kind_of(Deletion) + + describe Relation::Operations::Writes do + describe '#delete' do + it 'manufactures a deletion relation' do + mock(Session.instance).delete(Deletion.new(@relation)) + @relation.delete.should == @relation + end end - end - - describe '#insert' do - it 'manufactures an insertion relation' do - @relation.insert(record = {:id => 1}).should be_kind_of(Insertion) + + describe '#insert' do + it 'manufactures an insertion relation' do + mock(Session.instance).create(Insertion.new(@relation, record = {@relation[:name] => 'carl'})) + @relation.insert(record).should == @relation + end + end + + describe '#update' do + it 'manufactures an update relation' do + mock(Session.instance).update(Update.new(@relation, assignments = {@relation[:name] => 'bob'})) + @relation.update(assignments).should == @relation + end end end end + + describe Relation::Enumerable do + it "is enumerable" do + pending + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index c26e7fb525889..642d652057378 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -21,7 +21,6 @@ module ActiveRelation WHERE `users`.`id` = 1 """) end - end end end \ No newline at end of file diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/active_relation/unit/session/session_spec.rb new file mode 100644 index 0000000000000..ddd748334a9e7 --- /dev/null +++ b/spec/active_relation/unit/session/session_spec.rb @@ -0,0 +1,70 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module ActiveRelation + describe Session do + before do + @relation = Table.new(:users) + @session = Session.instance + end + + describe Singleton do + it "is a singleton" do + Session.instance.should be_equal(Session.instance) + lambda { Session.new }.should raise_error + end + end + + describe Session::CRUD do + before do + @insert = Insertion.new(@relation, @relation[:name] => 'nick') + @update = Update.new(@relation, @relation[:name] => 'nick') + @delete = Deletion.new(@relation) + @select = @relation + end + + describe '#create' do + it "should execute an insertion on the connection" do + mock(@session.connection).insert(@insert.to_sql) + @session.create(@insert) + end + end + + describe '#read' do + it "should execute an selection on the connection" do + mock(@session.connection).select_all(@select.to_sql) + @session.read(@select) + end + end + + describe '#update' do + it "should execute an update on the connection" do + mock(@session.connection).update(@update.to_sql) + @session.update(@update) + end + end + + describe '#delete' do + it "should execute a delete on the connection" do + mock(@session.connection).delete(@delete.to_sql) + @session.delete(@delete) + end + end + end + + describe Session::Transactions do + describe '#begin' do + end + + describe '#end' do + end + end + + describe Session::UnitOfWork do + describe '#flush' do + end + + describe '#clear' do + end + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e3508aac906ee..59202dc9f0a1d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,7 +7,7 @@ require 'active_relation' ActiveRecord::Base.configurations = { - 'sql_algebra_test' => { + 'test' => { :adapter => 'mysql', :username => 'root', :password => 'password', @@ -15,7 +15,7 @@ :database => 'sql_algebra_test', }, } -ActiveRecord::Base.establish_connection 'sql_algebra_test' +ActiveRecord::Base.establish_connection 'test' class Hash def shift From ecd072d21951573f59e9515b868224d3732dbdfa Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 24 Feb 2008 17:26:32 -0800 Subject: [PATCH 0074/1492] renamed attribute to operand per josh's suggestion --- README | 27 ++++++++++++++++----------- lib/active_relation/predicates.rb | 25 +++++++++++++------------ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/README b/README index 2b661bfebb169..d60a4ec0bb828 100644 --- a/README +++ b/README @@ -12,33 +12,33 @@ you construct a table relation and convert it to sql: ActiveRelation::Table.new(:users).to_sql -In fact, you will probably never call `#to_sql` directly. Let `users = ActiveRelation::Table.new(:users)`. You can iterate through all rows in the `users` table like this: +In fact, you will probably never call `#to_sql`. Let `users = ActiveRelation::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: users.each { |user| ... } -In other words, Arel relations behave similar regular Ruby collections. Let's have a look at a concrete example: +In other words, Arel relations behave implement Ruby's Eunmerable interface. Let's have a look at a concrete example: users.first # => {'id' => 10, 'name' => 'bob'} -As you can see, Arel converts the rows into a hash, the values of which are the appropriate Ruby primitive (integers, strings, and so forth). +As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). == Relational Algebra == -Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE`), rather they represent a collection of data that you can select from, insert into, update, and delete.For example, to insert a row into the users table, do the following: +Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: - users.insert({'id' => 11, 'name' => 'amy'}) + users.insert({users[:name] => 'amy'}) # => INSERT INTO users (users.name) VALUES ('amy') To delete all users: - users.delete + users.delete # => DELETE FROM users To update: - users.update({'name' => 'carl'}) + users.update({users[:name] => 'carl'}) # => UPDATE users SET name = 'carl' -As you can see, the `relation` users does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate queries to do the various CRUD operations. +As you can see, the `relation` named `users` does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate SQL queries to do the various CRUD operations. -=== More Sophisticated Queries === +=== More Sophisticated Queries Relations === Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: @@ -47,13 +47,18 @@ Following the Relational Algebra, Arel's interface uses some jargon that differs What would, in SQL, be part of the `SELECT` clause is called here a `projection`: users.project(users[:id]) # => SELECT users.id FROM users + +Joins are fairly straightforward: + + users.join(photos).on(users[:id].equals(photos[:user_id])) => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id -The best property of the Relational is compositionality, or closure under all operations. For example, to combine the two previous queries: +The best property of the Relational is compositionality, or closure under all operations. For example, to select and project: users \ .select(users[:name].equals('amy')) \ - .project(users[:id]) + .project(users[:id]) \ # => SELECT users.id FROM users WHERE users.name = 'amy' +s == Contributions == diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index c4f7b835120fb..7d0618f42e0ad 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -6,14 +6,15 @@ def ==(other) end class Binary < Predicate - attr_reader :attribute, :operand + # rename "operand21", "operand22" + attr_reader :operand1, :operand2 - def initialize(attribute, operand) - @attribute, @operand = attribute, operand + def initialize(operand1, operand2) + @operand1, @operand2 = operand1, operand2 end def ==(other) - super and @attribute == other.attribute and @operand == other.operand + super and @operand1 == other.operand1 and @operand2 == other.operand2 end def bind(relation) @@ -25,19 +26,19 @@ def qualify end def to_sql(strategy = Sql::Predicate.new) - "#{attribute.to_sql(strategy)} #{predicate_sql} #{operand.to_sql(strategy)}" + "#{operand1.to_sql(strategy)} #{predicate_sql} #{operand2.to_sql(strategy)}" end def descend - self.class.new(yield(attribute), yield(operand)) + self.class.new(yield(operand1), yield(operand2)) end end class Equality < Binary def ==(other) self.class == other.class and - ((attribute == other.attribute and operand == other.operand) or - (attribute == other.operand and operand == other.attribute)) + ((operand1 == other.operand1 and operand2 == other.operand2) or + (operand1 == other.operand2 and operand2 == other.operand1)) end protected @@ -75,15 +76,15 @@ def predicate_sql end class Match < Binary - alias_method :regexp, :operand + alias_method :regexp, :operand2 - def initialize(attribute, regexp) - @attribute, @regexp = attribute, regexp + def initialize(operand1, regexp) + @operand1, @regexp = operand1, regexp end end class RelationInclusion < Binary - alias_method :relation, :operand + alias_method :relation, :operand2 protected def predicate_sql From 92db013ba3ee4d0a9d92281e614d05f064c22e15 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 24 Feb 2008 22:19:32 -0800 Subject: [PATCH 0075/1492] quoting issues --- lib/active_relation/extensions.rb | 1 - lib/active_relation/extensions/base.rb | 48 ---- lib/active_relation/extensions/object.rb | 6 +- lib/active_relation/predicates.rb | 5 +- lib/active_relation/primitives/attribute.rb | 18 +- lib/active_relation/primitives/expression.rb | 2 +- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/join.rb | 2 +- lib/active_relation/relations/relation.rb | 4 +- lib/active_relation/relations/table.rb | 17 +- lib/active_relation/sql.rb | 23 +- .../integration/scratch_spec.rb | 252 ------------------ .../unit/predicates/binary_spec.rb | 3 + .../unit/predicates/equality_spec.rb | 8 +- .../unit/primitives/attribute_spec.rb | 41 ++- .../unit/primitives/expression_spec.rb | 2 +- .../unit/relations/table_spec.rb | 8 +- 17 files changed, 93 insertions(+), 349 deletions(-) delete mode 100644 lib/active_relation/extensions/base.rb delete mode 100644 spec/active_relation/integration/scratch_spec.rb diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb index 3751088483555..8a024947edffd 100644 --- a/lib/active_relation/extensions.rb +++ b/lib/active_relation/extensions.rb @@ -1,4 +1,3 @@ require 'active_relation/extensions/object' require 'active_relation/extensions/array' -require 'active_relation/extensions/base' require 'active_relation/extensions/hash' diff --git a/lib/active_relation/extensions/base.rb b/lib/active_relation/extensions/base.rb deleted file mode 100644 index c1b823f9a761d..0000000000000 --- a/lib/active_relation/extensions/base.rb +++ /dev/null @@ -1,48 +0,0 @@ -class ActiveRecord::Base - class << self - def cache - @identity_map ||= IdentityMap.new - end - - def relation - @relation ||= ActiveRelation::Table.new(table_name) - end - end - - class IdentityMap - def initialize - @map = {} - end - - def get(record, &block) - @map[record] ||= yield - end - end -end - -# all of the below disables normal AR behavior. It's rather destructive and purely for demonstration purposes (see scratch_spec). -class ActiveRecord::Associations::BelongsToAssociation - def instantiate(record, joins = []) - @target = proxy_reflection.klass.instantiate(record, joins) - loaded - end - - # this basically disables belongs_to from loading themselves - def reload - @target = 'hack' - end -end - -class ActiveRecord::Associations::AssociationCollection - def instantiate(record, joins = []) - @target << proxy_reflection.klass.instantiate(record, joins) - loaded # technically, this isn't true. doesn't matter though - end -end - -class ActiveRecord::Associations::HasManyThroughAssociation - def instantiate(record, joins = []) - @target << proxy_reflection.klass.instantiate(record, joins) - loaded # again, not really true. - end -end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 35ffa9c661b75..0cc87bf262bf2 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -7,7 +7,11 @@ def bind(relation) self end - def to_sql(strategy = ActiveRelation::Sql::Scalar.new) + def to_sql(strategy = self.strategy) strategy.scalar self end + + def strategy + ActiveRelation::Sql::Scalar.new + end end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 7d0618f42e0ad..2a36e650420ec 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -6,7 +6,6 @@ def ==(other) end class Binary < Predicate - # rename "operand21", "operand22" attr_reader :operand1, :operand2 def initialize(operand1, operand2) @@ -25,8 +24,8 @@ def qualify descend(&:qualify) end - def to_sql(strategy = Sql::Predicate.new) - "#{operand1.to_sql(strategy)} #{predicate_sql} #{operand2.to_sql(strategy)}" + def to_sql(strategy = nil) + "#{operand1.to_sql(operand2.strategy)} #{predicate_sql} #{operand2.to_sql(operand1.strategy)}" end def descend diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index e55dd0bdc4a9a..75f19605c7b93 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -2,8 +2,8 @@ module ActiveRelation class Attribute attr_reader :relation, :name, :alias, :ancestor - def initialize(relation, name, aliaz = nil, ancestor = nil) - @relation, @name, @alias, @ancestor = relation, name, aliaz, ancestor + def initialize(relation, name, options = {}) + @relation, @name, @alias, @ancestor, @column = relation, name, options[:alias], options[:ancestor] end def alias_or_name @@ -12,11 +12,11 @@ def alias_or_name module Transformations def as(aliaz = nil) - Attribute.new(relation, name, aliaz, self) + Attribute.new(relation, name, :alias => aliaz, :ancestor => self) end def bind(new_relation) - relation == new_relation ? self : Attribute.new(new_relation, name, @alias, self) + relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) end def qualify @@ -32,6 +32,10 @@ def to_attribute def qualified_name "#{prefix}.#{name}" end + + def column + relation.column_for(self) + end def ==(other) self.class == other.class and @@ -112,10 +116,14 @@ def average end include Expressions - def to_sql(strategy = Sql::Predicate.new) + def to_sql(strategy = self.strategy) strategy.attribute prefix, name, self.alias end + def strategy + Sql::Attribute.new(self) + end + private def prefix relation.prefix_for(self) diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index 35c1b5ff655a5..11aa558977a64 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -20,7 +20,7 @@ def bind(new_relation) end def to_attribute - Attribute.new(relation, @alias, nil, self) + Attribute.new(relation, @alias, :ancestor => self) end end include Transformations diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 094c6e29dd41c..115315a76acec 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -2,7 +2,7 @@ module ActiveRelation class Compound < Relation attr_reader :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, - :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, + :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, :to => :relation def attributes diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 70c85bb1e0454..8e0dcb2a4b182 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -38,7 +38,7 @@ def joins join_sql, externalize(relation2).table_sql, "ON", - predicates.collect { |p| p.bind(self).to_sql(Sql::Predicate.new) }.join(' AND ') + predicates.collect { |p| p.bind(self).to_sql }.join(' AND ') ].join(" ") [relation1.joins, relation2.joins, this_join].compact.join(" ") end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 1d5e194923e53..7536390aca531 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -104,12 +104,12 @@ def alias? false end - def to_sql(strategy = Sql::Select.new) + def to_sql(strategy = Sql::Relation.new) strategy.select [ "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(Sql::Predicate.new)}.join("\n\tAND ")}" unless selects.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(Sql::Selection.new)}.join("\n\tAND ")}" unless selects.blank?), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index d0fc2b24756ba..5720be30e37bf 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -3,11 +3,11 @@ class Table < Relation attr_reader :name def initialize(name) - @name = name + @name = name.to_s end def attributes - @attributes ||= connection.columns(name, "#{name} Columns").collect do |column| + @attributes ||= columns.collect do |column| Attribute.new(self, column.name.to_sym) end end @@ -19,7 +19,20 @@ def qualify def prefix_for(attribute) self[attribute] and name end + + def column_for(attribute) + self[attribute] and columns.detect { |c| c.name == attribute.name } + end + + def ==(other) + self.class == other.class and + name == other.name + end + def columns + @columns ||= connection.columns(name, "#{name} Columns") + end + protected def table_sql "#{quote_table_name(name)}" diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 85bcb4107bd3c..49ced3cbaaa5d 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -27,8 +27,8 @@ def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" end - def scalar(scalar) - scalar + def scalar(scalar, column = nil) + quote(scalar, column) end def select(select_sql, aliaz) @@ -36,7 +36,13 @@ def select(select_sql, aliaz) end end - class Select < Strategy + class Selection < Strategy + def scalar(scalar) + scalar + end + end + + class Relation < Strategy def select(select_sql, aliaz) select_sql end @@ -48,10 +54,17 @@ def select(select_sql, aliaz) end end - class Scalar < Strategy + class Attribute < Predicate + def initialize(attribute) + @attribute = attribute + end + def scalar(scalar) - quote(scalar) + quote(scalar, @attribute.column) end end + + class Scalar < Predicate + end end end \ No newline at end of file diff --git a/spec/active_relation/integration/scratch_spec.rb b/spec/active_relation/integration/scratch_spec.rb deleted file mode 100644 index d6ec030518000..0000000000000 --- a/spec/active_relation/integration/scratch_spec.rb +++ /dev/null @@ -1,252 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') - -describe 'ActiveRelation', 'A proposed refactoring to ActiveRecord, introducing both a SQL - Builder and a Relational Algebra to mediate between - ActiveRecord and the database. The goal of the refactoring is - to remove code duplication concerning AR associations; remove - complexity surrounding eager loading; comprehensively solve - quoting issues; remove the with_scope merging logic; minimize - the need for with_scope in general; simplify the - implementation of plugins like HasFinder and ActsAsParanoid; - introduce an identity map; and allow for query optimization. - All this while remaining backwards-compatible with the - existing ActiveRecord interface. - The Relational Algebra makes these ambitious goals - possible. There\'s no need to be scared by the math, it\'s - actually quite simple. Relational Algebras have some nice - advantages over flexible SQL builders like Sequel and and - SqlAlchemy (a beautiful Python library). Principally, a - relation is writable as well as readable. This obviates the - :create with_scope, and perhaps also - #set_belongs_to_association_for. - With so much complexity removed from ActiveRecord, I - propose a mild reconsideration of the architecture of Base, - AssocationProxy, AssociationCollection, and so forth. These - should all be understood as \'Repositories\': a factory that - given a relation can manufacture objects, and given an object - can manipulate a relation. This may sound trivial, but I - think it has the potential to make the code smaller and - more consistent.' do - before do - class User < ActiveRecord::Base; has_many :photos end - class Photo < ActiveRecord::Base; belongs_to :camera end - class Camera < ActiveRecord::Base; end - end - - before do - # Rather than being associated with a table, an ActiveRecord is now associated with - # a relation. - @users = User.relation - @photos = Photo.relation - @cameras = Camera.relation - # A first taste of a Relational Algebra: User.find(1) - @user = @users.select(@users[:id].equals(1)) - # == is overridden on attributes to return a predicate, not true or false - end - - # In a Relational Algebra, the various ActiveRecord associations become a simple - # mapping from one relation to another. The Reflection object parameterizes the - # mapping. - def user_has_many_photos(user_relation) - primary_key = User.reflections[:photos].klass.primary_key.to_sym - foreign_key = User.reflections[:photos].primary_key_name.to_sym - - user_relation.outer_join(@photos).on(user_relation[primary_key].equals(@photos[foreign_key])) - end - - def photo_belongs_to_camera(photo_relation) - primary_key = Photo.reflections[:camera].klass.primary_key.to_sym - foreign_key = Photo.reflections[:camera].primary_key_name.to_sym - - photo_relation.outer_join(@cameras).on(photo_relation[foreign_key].equals(@cameras[primary_key])) - end - - describe 'Relational Algebra', 'a relational algebra allows the implementation of - associations like has_many to be specified once, - regardless of eager-joins, has_many :through, and so - forth' do - it 'generates the query for User.has_many :photos' do - user_photos = user_has_many_photos(@user) - # the 'project' operator limits the columns that come back from the query. - # Note how all the operators are compositional: 'project' is applied to a query - # that previously had been joined and selected. - user_photos.project(*@photos.attributes).to_sql.should be_like(""" - SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - LEFT OUTER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - WHERE - `users`.`id` = 1 - """) - # Also note the correctly quoted columns and tables. In this instance the - # MysqlAdapter from ActiveRecord is used to do the escaping. - end - - it 'generates the query for User.has_many :cameras, :through => :photos' do - # note, again, the compositionality of the operators: - user_cameras = photo_belongs_to_camera(user_has_many_photos(@user)) - user_cameras.project(*@cameras.attributes).to_sql.should be_like(""" - SELECT `cameras`.`id` - FROM `users` - LEFT OUTER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - LEFT OUTER JOIN `cameras` - ON `photos`.`camera_id` = `cameras`.`id` - WHERE - `users`.`id` = 1 - """) - end - - it 'generates the query for an eager join for a collection using the same logic as - for an association on an individual row' do - users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)) - users_cameras.to_sql.should be_like(""" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id`, `cameras`.`id` - FROM `users` - LEFT OUTER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - LEFT OUTER JOIN `cameras` - ON `photos`.`camera_id` = `cameras`.`id` - """) - end - - it 'is trivial to disambiguate columns' do - users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify - users_cameras.to_sql.should be_like(""" - SELECT `users`.`id` AS 'users.id', `users`.`name` AS 'users.name', `photos`.`id` AS 'photos.id', `photos`.`user_id` AS 'photos.user_id', `photos`.`camera_id` AS 'photos.camera_id', `cameras`.`id` AS 'cameras.id' - FROM `users` - LEFT OUTER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - LEFT OUTER JOIN `cameras` - ON `photos`.`camera_id` = `cameras`.`id` - """) - end - - it 'allows arbitrary sql to be passed through' do - @users.outer_join(@photos).on("asdf").to_sql.should be_like(""" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - LEFT OUTER JOIN `photos` - ON asdf - """) - @users.select("asdf").to_sql.should be_like(""" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE asdf - """) - end - - describe 'with_scope' do - it 'obviates the need for with_scope merging logic since, e.g., - `with_scope :conditions => ...` is just a #select operation on the relation' do - end - - it 'may eliminate the need for with_scope altogether since the associations no longer - need it: the relation underlying the association fully encapsulates the scope' do - end - end - end - - describe 'Repository', 'ActiveRecord::Base, HasManyAssociation, and so forth are - all repositories: given a relation, they manufacture objects' do - before do - class << ActiveRecord::Base; public :instantiate end - end - - it 'manufactures objects' do - User.instantiate(@users.first).attributes.should == {"name" => "hai", "id" => 1} - end - - it 'frees ActiveRecords from being tied to tables' do - pending # pending, but trivial to implement: - - class User < ActiveRecord::Base - # acts_as_paranoid without alias_method_chain: - set_relation @users.select(@users[:deleted_at] != nil) - end - - class Person < ActiveRecord::Base - set_relation @accounts.join(@profiles).on(@accounts[:id].equals(@profiles[:account_id])) - end - # I know this sounds crazy, but even writes are possible in the last example. - # calling #save on a person can write to two tables! - end - - describe 'the n+1 problem' do - describe 'the eager join algorithm is vastly simpler' do - it 'loads three active records with only one query' do - # using 'rr' mocking framework: the real #select_all is called, but we assert - # that it only happens once: - mock.proxy(ActiveRecord::Base.connection).select_all.with_any_args.once - - users_cameras = photo_belongs_to_camera(user_has_many_photos(@users)).qualify - user = User.instantiate(users_cameras.first, [:photos => [:camera]]) - user.photos.first.camera.attributes.should == {"id" => 1} - end - - before do - class << ActiveRecord::Base - # An identity map makes this algorithm efficient. - def instantiate_with_cache(record) - cache.get(record) { instantiate_without_cache(record) } - end - alias_method_chain :instantiate, :cache - - # for each row in the result set, which may contain data from n tables, - # - instantiate that slice of the data corresponding to the current class - # - recusively walk the dependency chain and repeat. - def instantiate_with_joins(data, joins = []) - record = unqualify(data) - returning instantiate_without_joins(record) do |object| - joins.each do |join| - case join - when Symbol - object.send(association = join).instantiate(data) - when Hash - join.each do |association, nested_associations| - object.send(association).instantiate(data, nested_associations) - end - end - end - end - end - alias_method_chain :instantiate, :joins - - private - # Sometimes, attributes are qualified to remove ambiguity. Here, bring back - # ambiguity by translating 'users.id' to 'id' so we can call #attributes=. - # This code should work correctly if the attributes are qualified or not. - def unqualify(qualified_attributes) - qualified_attributes_for_this_class = qualified_attributes. \ - slice(*relation.attributes.collect(&:qualified_name)) - qualified_attributes_for_this_class.alias do |qualified_name| - qualified_name.split('.')[1] || qualified_name # the latter means it must not really be qualified - end - end - end - end - - it "is possible to be smarter about eager loading. DataMapper is smart enough - to notice when you do users.each { |u| u.photos } and make this two queries - rather than n+1: the first invocation of #photos is lazy but it preloads - photos for all subsequent users. This is substantially easier with the - Algebra since we can do @user.join(@photos).on(...) and transform that to - @users.join(@photos).on(...), relying on the IdentityMap to eliminate - the n+1 problem." do - pending - end - end - end - end - - describe 'The Architecture', 'I propose to produce a new gem, ActiveRelation, which encaplulates - the existing ActiveRecord Connection Adapter, the new SQL Builder, - and the Relational Algebra. ActiveRecord, then, should no longer - interact with the connection object directly.' do - end - - describe 'Miscellaneous Ideas' do - it 'may be easy to write a SQL parser that can take arbitrary SQL and produce a relation. - This has the advantage of permitting e.g., pagination with custom finder_sql' - end -end \ No newline at end of file diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 44c1a1a7a090d..1f6656b9d1f9a 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -53,6 +53,9 @@ def predicate_sql `users`.`id` <=> `photos`.`id` """) end + + it 'appropriately cooerces scalars' do + end end end end \ No newline at end of file diff --git a/spec/active_relation/unit/predicates/equality_spec.rb b/spec/active_relation/unit/predicates/equality_spec.rb index fd30846c70188..499b13383d9ba 100644 --- a/spec/active_relation/unit/predicates/equality_spec.rb +++ b/spec/active_relation/unit/predicates/equality_spec.rb @@ -3,10 +3,10 @@ module ActiveRelation describe Equality do before do - @relation1 = Table.new(:foo) - @relation2 = Table.new(:bar) - @attribute1 = Attribute.new(@relation1, :name) - @attribute2 = Attribute.new(@relation2, :name) + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:name] + @attribute2 = @relation2[:name] end describe '==' do diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index e5a3792d85dcd..8b4f52c43284e 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -4,23 +4,20 @@ module ActiveRelation describe Attribute do before do @relation = Table.new(:users) + @attribute = Attribute.new(@relation, :id) end describe Attribute::Transformations do - before do - @attribute = Attribute.new(@relation, :id) - end - describe '#as' do it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias, @attribute) + @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) end end describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do derived_relation = @relation.select(@relation[:id].equals(1)) - @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, nil, @attribute) + @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end it "returns self if the substituting to the same relation" do @@ -30,7 +27,7 @@ module ActiveRelation describe '#qualify' do it "manufactures an attribute aliased with that attribute's qualified name" do - @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, @attribute.qualified_name, @attribute) + @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, :alias => @attribute.qualified_name, :ancestor => @attribute) end end @@ -41,9 +38,16 @@ module ActiveRelation end end + describe '#column' do + it "" do + pending + end + end + describe '#qualified_name' do it "manufactures an attribute name prefixed with the relation's name" do - Attribute.new(@relation, :id).qualified_name.should == 'users.id' + stub(@relation).prefix_for(anything) { 'bruisers' } + Attribute.new(@relation, :id).qualified_name.should == 'bruisers.id' end end @@ -54,25 +58,20 @@ module ActiveRelation end it "obtains if the attributes have an overlapping history" do - Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)).should =~ Attribute.new(@relation, :name) - Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, nil, Attribute.new(@relation, :name)) + Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)).should =~ Attribute.new(@relation, :name) + Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)) end end end describe '#to_sql' do - describe Sql::Strategy do - before do - stub(@relation).prefix_for(anything) { 'bruisers' } - end - - it "manufactures sql without an alias if the strategy is Predicate" do - Attribute.new(@relation, :name, :alias).to_sql(Sql::Predicate.new).should be_like("`bruisers`.`name`") - end + it "" do + pending "this test is not sufficiently resilient" + end - it "manufactures sql with an alias if the strategy is Projection" do - Attribute.new(@relation, :name, :alias).to_sql(Sql::Projection.new).should be_like("`bruisers`.`name` AS 'alias'") - end + it "manufactures sql with an alias" do + stub(@relation).prefix_for(anything) { 'bruisers' } + Attribute.new(@relation, :name, :alias => :alias).to_sql.should be_like("`bruisers`.`name`") end end diff --git a/spec/active_relation/unit/primitives/expression_spec.rb b/spec/active_relation/unit/primitives/expression_spec.rb index 5506f52b86e9e..dda35157b055e 100644 --- a/spec/active_relation/unit/primitives/expression_spec.rb +++ b/spec/active_relation/unit/primitives/expression_spec.rb @@ -31,7 +31,7 @@ module ActiveRelation describe '#to_attribute' do it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, nil, @expression) + @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) end end end diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 3b02f80701ec9..f8d4431aa7dfb 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -45,9 +45,15 @@ module ActiveRelation end end + describe '#column_for' do + it "" do + pending + end + end + describe '#prefix_for' do it "returns the table name if the relation contains the attribute" do - @relation.prefix_for(@relation[:id]).should == :users + @relation.prefix_for(@relation[:id]).should == 'users' @relation.prefix_for(:does_not_exist).should be_nil end end From 86550ef2bee377a5e4134dc63dedb138bb9ab7dc Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 2 Mar 2008 17:05:06 -0800 Subject: [PATCH 0076/1492] new concept of session boundaries --- lib/active_relation/extensions/object.rb | 6 +++ lib/active_relation/predicates.rb | 2 +- lib/active_relation/primitives/attribute.rb | 5 +-- lib/active_relation/relations/compound.rb | 1 + lib/active_relation/relations/relation.rb | 10 ++--- lib/active_relation/relations/table.rb | 15 +++++-- lib/active_relation/sessions/session.rb | 28 +++++++++++-- lib/active_relation/sql.rb | 3 +- .../unit/predicates/binary_spec.rb | 9 ++-- .../predicates/relation_inclusion_spec.rb | 4 +- .../unit/relations/compound_spec.rb | 12 ++++++ .../unit/relations/deletion_spec.rb | 8 ++-- .../unit/relations/insertion_spec.rb | 4 +- .../unit/relations/join_spec.rb | 20 ++++----- .../unit/relations/order_spec.rb | 4 +- .../unit/relations/projection_spec.rb | 8 ++-- .../unit/relations/range_spec.rb | 4 +- .../unit/relations/relation_spec.rb | 18 +++++--- .../unit/relations/rename_spec.rb | 4 +- .../unit/relations/selection_spec.rb | 8 ++-- .../unit/relations/table_spec.rb | 14 +++++-- .../unit/relations/update_spec.rb | 8 ++-- .../unit/session/session_spec.rb | 42 ++++++++++++++----- 23 files changed, 162 insertions(+), 75 deletions(-) diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 0cc87bf262bf2..c8a0ff49e5484 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -14,4 +14,10 @@ def to_sql(strategy = self.strategy) def strategy ActiveRelation::Sql::Scalar.new end + + def metaclass + class << self + self + end + end end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 2a36e650420ec..ddc6eab02b92c 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -17,7 +17,7 @@ def ==(other) end def bind(relation) - descend{ |x| x.bind(relation) } + descend { |x| x.bind(relation) } end def qualify diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 75f19605c7b93..a72acb0c34322 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -49,13 +49,10 @@ module Congruence def self.included(klass) klass.class_eval do alias_method :eql?, :== + delegate :hash, :to => :name end end - def hash - relation.hash + name.hash - end - def history [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) end diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 115315a76acec..4e583e61e88a8 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -3,6 +3,7 @@ class Compound < Relation attr_reader :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, + :hash, :to => :relation def attributes diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 7536390aca531..889cf59d3ae09 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -3,7 +3,7 @@ class Relation include Sql::Quoting def session - Session.instance + Session.new end module Enumerable @@ -103,6 +103,10 @@ def aggregation? def alias? false end + + def eql?(other) + self == other + end def to_sql(strategy = Sql::Relation.new) strategy.select [ @@ -117,10 +121,6 @@ def to_sql(strategy = Sql::Relation.new) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql - - def descend - yield self - end def connection ActiveRecord::Base.connection diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 5720be30e37bf..271e76f362888 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -1,7 +1,8 @@ module ActiveRelation class Table < Relation attr_reader :name - + delegate :hash, :to => :name + def initialize(name) @name = name.to_s end @@ -21,17 +22,25 @@ def prefix_for(attribute) end def column_for(attribute) - self[attribute] and columns.detect { |c| c.name == attribute.name } + self[attribute] and columns.detect { |c| c.name == attribute.name.to_s } end def ==(other) self.class == other.class and name == other.name end - + def columns @columns ||= connection.columns(name, "#{name} Columns") end + + def descend + yield self + end + + def reset + @attributes = @columns = nil + end protected def table_sql diff --git a/lib/active_relation/sessions/session.rb b/lib/active_relation/sessions/session.rb index d6e2ae71692c6..7eb66a1395cb2 100644 --- a/lib/active_relation/sessions/session.rb +++ b/lib/active_relation/sessions/session.rb @@ -2,8 +2,29 @@ module ActiveRelation class Session - include Singleton - + class << self + def start + if @started + yield + else + begin + @started = true + @instance = new + manufacture = method(:new) + metaclass.class_eval do + define_method(:new) { @instance } + end + yield + ensure + metaclass.class_eval do + define_method(:new, &manufacture) + end + @started = false + end + end + end + end + module CRUD def connection ActiveRecord::Base.connection @@ -14,7 +35,8 @@ def create(insert) end def read(select) - connection.select_all(select.to_sql) + @read ||= {} + @read.has_key?(select) ? @read[select] : (@read[select] = connection.select_all(select.to_sql)) end def update(update) diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 49ced3cbaaa5d..0fc8b3e1bee74 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -2,12 +2,13 @@ module ActiveRelation module Sql module Quoting def connection - Session.instance.connection + Session.new.connection end delegate :quote_table_name, :quote_column_name, :quote, :to => :connection end + # module Formatting Context / Strategy # unit test me!!! class Strategy include Quoting end diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 1f6656b9d1f9a..f6466d9105277 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -49,12 +49,15 @@ def predicate_sql describe '#to_sql' do it 'manufactures sql with a binary operation' do - ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(""" + ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" `users`.`id` <=> `photos`.`id` - """) + ") end - it 'appropriately cooerces scalars' do + it 'appropriately quotes scalars' do + ConcreteBinary.new(@attribute1, "1-asdf").to_sql.should be_like(" + `users`.`id` <=> 1 + ") end end end diff --git a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb index 799be2308578d..0ac7ccb6e222f 100644 --- a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb +++ b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb @@ -18,9 +18,9 @@ module ActiveRelation describe RelationInclusion, '#to_sql' do it "manufactures subselect sql" do - RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(""" + RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(" `foo`.`id` IN (SELECT `foo`.`id` FROM `foo`) - """) + ") end end end diff --git a/spec/active_relation/unit/relations/compound_spec.rb b/spec/active_relation/unit/relations/compound_spec.rb index 03de27fb05259..d271529998ff2 100644 --- a/spec/active_relation/unit/relations/compound_spec.rb +++ b/spec/active_relation/unit/relations/compound_spec.rb @@ -7,6 +7,10 @@ class ConcreteCompound < Compound def initialize(relation) @relation = relation end + + def ==(other) + true + end end @relation = Table.new(:users) @compound_relation = ConcreteCompound.new(@relation) @@ -17,5 +21,13 @@ def initialize(relation) @compound_relation.attributes.should == @relation.attributes.collect { |a| a.bind(@compound_relation) } end end + + describe 'hashing' do + it 'implements hash equality' do + hash = {} + hash[@compound_relation] = 1 + hash[ConcreteCompound.new(@relation)].should == 1 + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb index 1a536e7aedf34..1f14ae5d34fa9 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -8,18 +8,18 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql deleting a table relation' do - Deletion.new(@relation).to_sql.should be_like(""" + Deletion.new(@relation).to_sql.should be_like(" DELETE FROM `users` - """) + ") end it 'manufactures sql deleting a selection relation' do - Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(""" + Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(" DELETE FROM `users` WHERE `users`.`id` = 1 - """) + ") end end end diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index a39c4aeaf367a..b2b239097addb 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -8,11 +8,11 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql inserting the data for one item' do - Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(" INSERT INTO `users` (`users`.`name`) VALUES ('nick') - """) + ") end end end diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index bc55a72e55338..532dc08753736 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -49,22 +49,22 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql joining the two tables on the predicate' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` - """) + ") end it 'manufactures sql joining the two tables, merging any selects' do Join.new("INNER JOIN", @relation1.select(@relation1[:id].equals(1)), - @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(""" + @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` WHERE `users`.`id` = 1 AND `photos`.`id` = 2 - """) + ") end end end @@ -89,33 +89,33 @@ module ActiveRelation describe '#to_sql' do describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do - Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` ON `users`.`id` = `photo_count`.`user_id` - """) + ") end end describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do - Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(" SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`id`, `users`.`name` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` INNER JOIN `users` ON `users`.`id` = `photo_count`.`user_id` - """) + ") end end it "keeps selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].equals(1)), @predicate).to_sql.should be_like(""" + Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].equals(1)), @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count` ON `users`.`id` = `photo_count`.`user_id` - """) + ") end end end diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb index 15f08d70ee901..032bd2b40f0d4 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -23,11 +23,11 @@ module ActiveRelation describe '#to_sql' do it "manufactures sql with an order clause" do - Order.new(@relation, @attribute).to_sql.should be_like(""" + Order.new(@relation, @attribute).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` ORDER BY `users`.`id` - """) + ") end end end diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index 75a4672642311..01a4d74bc6169 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -46,16 +46,16 @@ module ActiveRelation describe '#to_sql' do it "manufactures sql with a limited select clause" do - Projection.new(@relation, @attribute).to_sql.should be_like(""" + Projection.new(@relation, @attribute).to_sql.should be_like(" SELECT `users`.`id` FROM `users` - """) + ") end it "manufactures sql with scalar selects" do - Projection.new(@relation, Projection.new(@relation, @relation[:name])).to_sql.should be_like(""" + Projection.new(@relation, Projection.new(@relation, @relation[:name])).to_sql.should be_like(" SELECT (SELECT `users`.`name` FROM `users`) FROM `users` - """) + ") end end end diff --git a/spec/active_relation/unit/relations/range_spec.rb b/spec/active_relation/unit/relations/range_spec.rb index 501a8d3641824..7be2ca1b03a58 100644 --- a/spec/active_relation/unit/relations/range_spec.rb +++ b/spec/active_relation/unit/relations/range_spec.rb @@ -23,12 +23,12 @@ module ActiveRelation it "manufactures sql with limit and offset" do range_size = @range.last - @range.first + 1 range_start = @range.first - Range.new(@relation, @range).to_s.should be_like(""" + Range.new(@relation, @range).to_s.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` LIMIT #{range_size} OFFSET #{range_start} - """) + ") end end end diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index d3252c658bbb1..3af3b8aa9c6e5 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -109,22 +109,28 @@ module ActiveRelation describe Relation::Operations::Writes do describe '#delete' do it 'manufactures a deletion relation' do - mock(Session.instance).delete(Deletion.new(@relation)) - @relation.delete.should == @relation + Session.start do + mock(Session.new).delete(Deletion.new(@relation)) + @relation.delete.should == @relation + end end end describe '#insert' do it 'manufactures an insertion relation' do - mock(Session.instance).create(Insertion.new(@relation, record = {@relation[:name] => 'carl'})) - @relation.insert(record).should == @relation + Session.start do + mock(Session.new).create(Insertion.new(@relation, record = {@relation[:name] => 'carl'})) + @relation.insert(record).should == @relation + end end end describe '#update' do it 'manufactures an update relation' do - mock(Session.instance).update(Update.new(@relation, assignments = {@relation[:name] => 'bob'})) - @relation.update(assignments).should == @relation + Session.start do + mock(Session.new).update(Update.new(@relation, assignments = {@relation[:name] => 'bob'})) + @relation.update(assignments).should == @relation + end end end end diff --git a/spec/active_relation/unit/relations/rename_spec.rb b/spec/active_relation/unit/relations/rename_spec.rb index 33a89e6a49981..c960f767364f7 100644 --- a/spec/active_relation/unit/relations/rename_spec.rb +++ b/spec/active_relation/unit/relations/rename_spec.rb @@ -54,10 +54,10 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql renaming the attribute' do - Rename.new(@relation, @relation[:id] => :schmid).to_sql.should be_like(""" + Rename.new(@relation, @relation[:id] => :schmid).to_sql.should be_like(" SELECT `users`.`id` AS 'schmid', `users`.`name` FROM `users` - """) + ") end end end diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index afe002186ed41..3a18d4ae6e7a3 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -31,19 +31,19 @@ module ActiveRelation describe '#to_sql' do it "manufactures sql with where clause conditions" do - Selection.new(@relation, @predicate).to_sql.should be_like(""" + Selection.new(@relation, @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` WHERE `users`.`id` = 1 - """) + ") end it "allows arbitrary sql" do - Selection.new(@relation, "asdf").to_sql.should be_like(""" + Selection.new(@relation, "asdf").to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` WHERE asdf - """) + ") end end end diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index f8d4431aa7dfb..5c7fa35e63226 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -38,16 +38,16 @@ module ActiveRelation describe '#to_sql' do it "manufactures a simple select query" do - @relation.to_sql.should be_like(""" + @relation.to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - """) + ") end end describe '#column_for' do it "" do - pending + @relation[:id].column.should == @relation.columns.detect { |c| c.name == 'id' } end end @@ -72,5 +72,13 @@ module ActiveRelation @relation.qualify.should == Rename.new(@relation, @relation[:name] => 'users.name', @relation[:id] => 'users.id') end end + + describe 'hashing' do + it "implements hash equality" do + hash = {} + hash[Table.new(:users)] = 1 + hash[Table.new(:users)].should == 1 + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 642d652057378..2cd3eb9d118fd 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -8,18 +8,18 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql updating attributes' do - Update.new(@relation, @relation[:name] => "nick").to_sql.should be_like(""" + Update.new(@relation, @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` SET `users`.`name` = 'nick' - """) + ") end it 'manufactures sql updating a selection relation' do - Update.new(@relation.select(@relation[:id].equals(1)), @relation[:name] => "nick").to_sql.should be_like(""" + Update.new(@relation.select(@relation[:id].equals(1)), @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` SET `users`.`name` = 'nick' WHERE `users`.`id` = 1 - """) + ") end end end diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/active_relation/unit/session/session_spec.rb index ddd748334a9e7..118b99948c615 100644 --- a/spec/active_relation/unit/session/session_spec.rb +++ b/spec/active_relation/unit/session/session_spec.rb @@ -4,13 +4,29 @@ module ActiveRelation describe Session do before do @relation = Table.new(:users) - @session = Session.instance + @session = Session.new end - describe Singleton do - it "is a singleton" do - Session.instance.should be_equal(Session.instance) - lambda { Session.new }.should raise_error + describe '::start' do + describe '::instance' do + it "it is a singleton within the started session" do + Session.start do + Session.new.should == Session.new + end + end + + it "is a singleton across nested sessions" do + Session.start do + outside = Session.new + Session.start do + Session.new.should == outside + end + end + end + + it "manufactures new sessions outside of the started session" do + Session.new.should_not == Session.new + end end end @@ -23,28 +39,34 @@ module ActiveRelation end describe '#create' do - it "should execute an insertion on the connection" do + it "executes an insertion on the connection" do mock(@session.connection).insert(@insert.to_sql) @session.create(@insert) end end describe '#read' do - it "should execute an selection on the connection" do - mock(@session.connection).select_all(@select.to_sql) + it "executes an selection on the connection" do + mock(@session.connection).select_all(@select.to_sql).once + @session.read(@select) + end + + it "is memoized" do + mock(@session.connection).select_all(@select.to_sql).once + @session.read(@select) @session.read(@select) end end describe '#update' do - it "should execute an update on the connection" do + it "executes an update on the connection" do mock(@session.connection).update(@update.to_sql) @session.update(@update) end end describe '#delete' do - it "should execute a delete on the connection" do + it "executes a delete on the connection" do mock(@session.connection).delete(@delete.to_sql) @session.delete(@delete) end From c54392872f024d55e8a23ead3065e6119a52b234 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 2 Mar 2008 17:56:18 -0800 Subject: [PATCH 0077/1492] introduced engine dependency for sql strategies - hacked in default engine for scalars -- BAD --- lib/active_relation.rb | 1 + lib/active_relation/engines.rb | 1 + lib/active_relation/engines/engine.rb | 4 ++++ lib/active_relation/extensions/class.rb | 7 +++++++ lib/active_relation/extensions/object.rb | 2 +- lib/active_relation/primitives/attribute.rb | 1 + lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/join.rb | 5 ++++- lib/active_relation/relations/relation.rb | 14 ++++---------- lib/active_relation/relations/table.rb | 12 +++++++----- lib/active_relation/sessions/session.rb | 12 ++++-------- lib/active_relation/sql.rb | 15 ++++++++------- .../unit/primitives/attribute_spec.rb | 6 ++++++ spec/active_relation/unit/relations/join_spec.rb | 6 ++++++ spec/active_relation/unit/relations/table_spec.rb | 11 +++++++++++ spec/active_relation/unit/session/session_spec.rb | 10 +++++----- spec/spec_helper.rb | 3 +++ 17 files changed, 74 insertions(+), 38 deletions(-) create mode 100644 lib/active_relation/engines.rb create mode 100644 lib/active_relation/engines/engine.rb create mode 100644 lib/active_relation/extensions/class.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index 23a80a9c381ec..f04825ad4c379 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -8,4 +8,5 @@ require 'active_relation/extensions' require 'active_relation/predicates' require 'active_relation/relations' +require 'active_relation/engines' require 'active_relation/primitives' \ No newline at end of file diff --git a/lib/active_relation/engines.rb b/lib/active_relation/engines.rb new file mode 100644 index 0000000000000..55eb817b88318 --- /dev/null +++ b/lib/active_relation/engines.rb @@ -0,0 +1 @@ +require 'active_relation/engines/engine' \ No newline at end of file diff --git a/lib/active_relation/engines/engine.rb b/lib/active_relation/engines/engine.rb new file mode 100644 index 0000000000000..36b77b886e548 --- /dev/null +++ b/lib/active_relation/engines/engine.rb @@ -0,0 +1,4 @@ +module ActiveRelation + class Engine + end +end \ No newline at end of file diff --git a/lib/active_relation/extensions/class.rb b/lib/active_relation/extensions/class.rb new file mode 100644 index 0000000000000..72b3bf0c158e5 --- /dev/null +++ b/lib/active_relation/extensions/class.rb @@ -0,0 +1,7 @@ +class Class + def memoize(method) + define_method "#{method}_with_memoization" do |*args| + end + alias_method_chain method, :memoization + end +end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index c8a0ff49e5484..b0c7ada999943 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -12,7 +12,7 @@ def to_sql(strategy = self.strategy) end def strategy - ActiveRelation::Sql::Scalar.new + ActiveRelation::Sql::Scalar.new(ActiveRelation::Table.engine) end def metaclass diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index a72acb0c34322..baaae1973cf40 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -1,6 +1,7 @@ module ActiveRelation class Attribute attr_reader :relation, :name, :alias, :ancestor + delegate :engine, :to => :relation def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor, @column = relation, name, options[:alias], options[:ancestor] diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 4e583e61e88a8..a10b7588e7cf2 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -3,7 +3,7 @@ class Compound < Relation attr_reader :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, - :hash, + :hash, :engine, :to => :relation def attributes diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 8e0dcb2a4b182..043b237de757a 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -1,6 +1,7 @@ module ActiveRelation class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates + delegate :engine, :to => :relation1 def initialize(join_sql, relation1, relation2, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates @@ -57,8 +58,10 @@ def externalize(relation) end Externalizer = Struct.new(:relation) do + delegate :engine, :to => :relation + def table_sql - relation.aggregation?? relation.to_sql(Sql::Aggregation.new) : relation.send(:table_sql) + relation.aggregation?? relation.to_sql(Sql::Aggregation.new(engine)) : relation.send(:table_sql) end def selects diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 889cf59d3ae09..3d4ff6613c1a5 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -1,7 +1,5 @@ module ActiveRelation class Relation - include Sql::Quoting - def session Session.new end @@ -108,12 +106,12 @@ def eql?(other) self == other end - def to_sql(strategy = Sql::Relation.new) + def to_sql(strategy = Sql::Relation.new(engine)) strategy.select [ - "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new) }.join(', ')}", + "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new(engine)) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(Sql::Selection.new)}.join("\n\tAND ")}" unless selects.blank?), + ("WHERE #{selects.collect{|s| s.to_sql(Sql::Selection.new(engine))}.join("\n\tAND ")}" unless selects.blank?), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank?), ("LIMIT #{limit.to_sql}" unless limit.blank?), @@ -121,11 +119,7 @@ def to_sql(strategy = Sql::Relation.new) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql - - def connection - ActiveRecord::Base.connection - end - + def attribute_for_name(name) attributes.detect { |a| a.alias_or_name.to_s == name.to_s } end diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 271e76f362888..84eb1213ee791 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -1,10 +1,12 @@ module ActiveRelation class Table < Relation - attr_reader :name + cattr_accessor :engine + attr_reader :name, :engine + delegate :hash, :to => :name - def initialize(name) - @name = name.to_s + def initialize(name, engine = Table.engine) + @name, @engine = name.to_s, engine end def attributes @@ -31,7 +33,7 @@ def ==(other) end def columns - @columns ||= connection.columns(name, "#{name} Columns") + @columns ||= engine.columns(name, "#{name} Columns") end def descend @@ -44,7 +46,7 @@ def reset protected def table_sql - "#{quote_table_name(name)}" + "#{engine.quote_table_name(name)}" end private diff --git a/lib/active_relation/sessions/session.rb b/lib/active_relation/sessions/session.rb index 7eb66a1395cb2..0724abc5a7ba5 100644 --- a/lib/active_relation/sessions/session.rb +++ b/lib/active_relation/sessions/session.rb @@ -26,25 +26,21 @@ def start end module CRUD - def connection - ActiveRecord::Base.connection - end - def create(insert) - connection.insert(insert.to_sql) + insert.engine.insert(insert.to_sql) end def read(select) @read ||= {} - @read.has_key?(select) ? @read[select] : (@read[select] = connection.select_all(select.to_sql)) + @read.has_key?(select) ? @read[select] : (@read[select] = select.engine.select_all(select.to_sql)) end def update(update) - connection.update(update.to_sql) + update.engine.update(update.to_sql) end def delete(delete) - connection.delete(delete.to_sql) + delete.engine.delete(delete.to_sql) end end include CRUD diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 0fc8b3e1bee74..a5701ca8cda9b 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -1,16 +1,17 @@ module ActiveRelation module Sql module Quoting - def connection - Session.new.connection - end - - delegate :quote_table_name, :quote_column_name, :quote, :to => :connection + delegate :quote_table_name, :quote_column_name, :quote, :to => :engine end # module Formatting Context / Strategy # unit test me!!! class Strategy + attr_reader :engine include Quoting + + def initialize(engine) + @engine = engine + end end class Projection < Strategy @@ -51,13 +52,13 @@ def select(select_sql, aliaz) class Aggregation < Strategy def select(select_sql, aliaz) - "(#{select_sql}) AS #{quote_table_name(aliaz)}" + "(#{select_sql}) AS #{engine.quote_table_name(aliaz)}" end end class Attribute < Predicate def initialize(attribute) - @attribute = attribute + @attribute, @engine = attribute, attribute.engine end def scalar(scalar) diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index 8b4f52c43284e..95c972d814880 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -51,6 +51,12 @@ module ActiveRelation end end + describe '#engine' do + it "delegates to its relation" do + Attribute.new(@relation, :id).engine.should == @relation.engine + end + end + describe Attribute::Congruence do describe '=~' do it "obtains if the attributes are identical" do diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 532dc08753736..64d41effc51ae 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -38,6 +38,12 @@ module ActiveRelation end end + describe '#engine' do + it "delegates to a relation's engine" do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).engine.should == @relation1.engine + end + end + describe 'with simple relations' do describe '#attributes' do it 'combines the attributes of the two relations' do diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 5c7fa35e63226..8f14ce33cf0d4 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -80,5 +80,16 @@ module ActiveRelation hash[Table.new(:users)].should == 1 end end + + describe '#engine' do + it "defaults to global engine" do + Table.engine = engine = Engine.new + Table.new(:users).engine.should == engine + end + + it "can be specified" do + Table.new(:users, engine = Engine.new).engine.should == engine + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/active_relation/unit/session/session_spec.rb index 118b99948c615..1ac69976b590d 100644 --- a/spec/active_relation/unit/session/session_spec.rb +++ b/spec/active_relation/unit/session/session_spec.rb @@ -40,19 +40,19 @@ module ActiveRelation describe '#create' do it "executes an insertion on the connection" do - mock(@session.connection).insert(@insert.to_sql) + mock(@insert.engine).insert(@insert.to_sql) @session.create(@insert) end end describe '#read' do it "executes an selection on the connection" do - mock(@session.connection).select_all(@select.to_sql).once + mock(@select.engine).select_all(@select.to_sql).once @session.read(@select) end it "is memoized" do - mock(@session.connection).select_all(@select.to_sql).once + mock(@select.engine).select_all(@select.to_sql).once @session.read(@select) @session.read(@select) end @@ -60,14 +60,14 @@ module ActiveRelation describe '#update' do it "executes an update on the connection" do - mock(@session.connection).update(@update.to_sql) + mock(@update.engine).update(@update.to_sql) @session.update(@update) end end describe '#delete' do it "executes a delete on the connection" do - mock(@session.connection).delete(@delete.to_sql) + mock(@delete.engine).delete(@delete.to_sql) @session.delete(@delete) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 59202dc9f0a1d..cd9c8e96cba35 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -28,4 +28,7 @@ def shift Spec::Runner.configure do |config| config.include(BeLikeMatcher) config.mock_with :rr + config.before do + ActiveRelation::Table.engine = ActiveRecord::Base.connection + end end \ No newline at end of file From 6647a1e08eb9dc3512628882bcf60d421df74228 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 2 Mar 2008 21:10:35 -0800 Subject: [PATCH 0078/1492] scalars are now lifted; the heavy lifting is done by the operations on relation (select, join, etc.) --- lib/active_relation/extensions/array.rb | 4 +++ lib/active_relation/extensions/class.rb | 7 ---- lib/active_relation/extensions/hash.rb | 12 +++---- lib/active_relation/extensions/object.rb | 16 ++------- lib/active_relation/predicates.rb | 2 +- lib/active_relation/primitives.rb | 1 + lib/active_relation/primitives/scalar.rb | 25 ++++++++++++++ lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/order.rb | 5 +-- lib/active_relation/relations/relation.rb | 34 ++++++++++++------- lib/active_relation/relations/rename.rb | 4 +-- lib/active_relation/relations/update.rb | 4 ++- lib/active_relation/sql.rb | 2 +- .../unit/predicates/binary_spec.rb | 2 +- .../predicates/relation_inclusion_spec.rb | 19 ++++------- .../unit/relations/insertion_spec.rb | 2 +- .../unit/relations/join_spec.rb | 2 +- .../unit/relations/relation_spec.rb | 18 +++++++--- .../unit/relations/selection_spec.rb | 6 ++-- .../unit/relations/update_spec.rb | 4 +-- .../unit/session/session_spec.rb | 4 +-- 21 files changed, 100 insertions(+), 75 deletions(-) delete mode 100644 lib/active_relation/extensions/class.rb create mode 100644 lib/active_relation/primitives/scalar.rb diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index 5b6d6d6abd537..aa4354a78abf6 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -2,4 +2,8 @@ class Array def to_hash Hash[*flatten] end + + def to_sql(strategy = nil) + "(#{collect(&:to_sql).join(', ')})" + end end \ No newline at end of file diff --git a/lib/active_relation/extensions/class.rb b/lib/active_relation/extensions/class.rb deleted file mode 100644 index 72b3bf0c158e5..0000000000000 --- a/lib/active_relation/extensions/class.rb +++ /dev/null @@ -1,7 +0,0 @@ -class Class - def memoize(method) - define_method "#{method}_with_memoization" do |*args| - end - alias_method_chain method, :memoization - end -end \ No newline at end of file diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index 50864912bf806..a33ace573850b 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -1,11 +1,11 @@ class Hash - def alias(&block) - inject({}) do |aliased, (key, value)| - aliased.merge(yield(key) => value) - end + def bind(relation) + descend { |x| x.bind(relation) } end - def to_sql(strategy = nil) - "(#{values.collect(&:to_sql).join(', ')})" + def descend(&block) + inject({}) do |descendent, (key, value)| + descendent.merge(yield(key) => yield(value)) + end end end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index b0c7ada999943..d13cf9aabb48c 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -1,18 +1,6 @@ -class Object - def qualify - self - end - +class Object def bind(relation) - self - end - - def to_sql(strategy = self.strategy) - strategy.scalar self - end - - def strategy - ActiveRelation::Sql::Scalar.new(ActiveRelation::Table.engine) + ActiveRelation::Scalar.new(self, relation) end def metaclass diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index ddc6eab02b92c..ba926a86e5328 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -84,7 +84,7 @@ def initialize(operand1, regexp) class RelationInclusion < Binary alias_method :relation, :operand2 - + protected def predicate_sql 'IN' diff --git a/lib/active_relation/primitives.rb b/lib/active_relation/primitives.rb index 2ac157297ea7a..762925603450e 100644 --- a/lib/active_relation/primitives.rb +++ b/lib/active_relation/primitives.rb @@ -1,3 +1,4 @@ require 'active_relation/primitives/attribute' +require 'active_relation/primitives/scalar' require 'active_relation/primitives/expression' diff --git a/lib/active_relation/primitives/scalar.rb b/lib/active_relation/primitives/scalar.rb new file mode 100644 index 0000000000000..fa88404ee39f9 --- /dev/null +++ b/lib/active_relation/primitives/scalar.rb @@ -0,0 +1,25 @@ +module ActiveRelation + class Scalar + attr_reader :value, :relation + + def initialize(value, relation) + @value, @relation = value, relation + end + + def to_sql(strategy = self.strategy) + strategy.scalar value + end + + def strategy + ActiveRelation::Sql::Scalar.new(relation.engine) + end + + def ==(other) + value == other.value + end + + def qualify + self + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index dd5b8ec530051..16fe3d5f46927 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -11,7 +11,7 @@ def to_sql(strategy = nil) "INSERT", "INTO #{table_sql}", "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES #{record.to_sql}" + "VALUES #{record.values.to_sql}" ].join("\n") end diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index e6395aecd7607..6949b3acf7b7f 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -7,8 +7,9 @@ def initialize(relation, *orders) end def ==(other) - relation == other.relation and - orders == other.orders + self.class == other.class and + relation == other.relation and + orders == other.orders end def descend(&block) diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 3d4ff6613c1a5..1c97cc703546e 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -42,11 +42,11 @@ def include?(attribute) end def select(*predicates) - Selection.new(self, *predicates) + Selection.new(self, *predicates.collect {|p| p.bind(self)}) end def project(*attributes) - Projection.new(self, *attributes) + Projection.new(self, *attributes.collect {|a| a.bind(self)}) end def as(aliaz) @@ -54,7 +54,7 @@ def as(aliaz) end def order(*attributes) - Order.new(self, *attributes) + Order.new(self, *attributes.collect {|a| a.bind(self)}) end def rename(attribute, aliaz) @@ -67,11 +67,11 @@ def aggregate(*expressions) module Writes def insert(record) - session.create Insertion.new(self, record); self + session.create Insertion.new(self, record.bind(self)); self end def update(assignments) - session.update Update.new(self, assignments); self + session.update Update.new(self, assignments.bind(self)); self end def delete @@ -108,14 +108,14 @@ def eql?(other) def to_sql(strategy = Sql::Relation.new(engine)) strategy.select [ - "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new(engine)) }.join(', ')}", - "FROM #{table_sql}", - (joins unless joins.blank?), - ("WHERE #{selects.collect{|s| s.to_sql(Sql::Selection.new(engine))}.join("\n\tAND ")}" unless selects.blank?), - ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank?), - ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank?), - ("LIMIT #{limit.to_sql}" unless limit.blank?), - ("OFFSET #{offset.to_sql}" unless offset.blank?) + "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new(engine)) }.join(', ')}", + "FROM #{table_sql}", + (joins unless joins.blank? ), + ("WHERE #{selects.collect{|s| s.to_sql(Sql::Selection.new(engine))}.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank? ), + ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), + ("LIMIT #{limit}" unless limit.blank? ), + ("OFFSET #{offset}" unless offset.blank? ) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql @@ -127,6 +127,14 @@ def attribute_for_name(name) def attribute_for_attribute(attribute) attributes.detect { |a| a =~ attribute } end + + def bind(relation) + self + end + + def strategy + Sql::Predicate.new(engine) + end def attributes; [] end def selects; [] end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index 9a0e5552c701d..ac5484bfff247 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -15,7 +15,7 @@ def ==(other) end def attributes - relation.attributes.collect(&method(:baptize)) + relation.attributes.collect(&method(:christen)) end def descend(&block) @@ -23,7 +23,7 @@ def descend(&block) end private - def baptize(attribute) + def christen(attribute) (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).bind(self) rescue nil end end diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index 8909ee80a016d..c50919af3ea59 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -9,7 +9,9 @@ def initialize(relation, assignments) def to_sql(strategy = nil) [ "UPDATE #{table_sql} SET", - assignments.inject([]) { |assignments, (attribute, value)| assignments << "#{attribute.to_sql} = #{value.to_sql}" }.join(" "), + assignments.inject("") do |assignments, (attribute, value)| + assignments << " #{attribute.to_sql} = #{value.to_sql}" + end, ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) ].join("\n") end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index a5701ca8cda9b..99cfc66383fc8 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -20,7 +20,7 @@ def attribute(relation_name, attribute_name, aliaz) end def select(select_sql, aliaz) - "(#{select_sql})" + (aliaz ? " AS #{quote_column_name(aliaz)}" : "") + "(#{select_sql})" + (aliaz ? " AS #{quote(aliaz)}" : "") end end diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index f6466d9105277..677d8f3ab409a 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -55,7 +55,7 @@ def predicate_sql end it 'appropriately quotes scalars' do - ConcreteBinary.new(@attribute1, "1-asdf").to_sql.should be_like(" + ConcreteBinary.new(@attribute1, "1-asdf".bind(@relation1)).to_sql.should be_like(" `users`.`id` <=> 1 ") end diff --git a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb index 0ac7ccb6e222f..af5846b7476c5 100644 --- a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb +++ b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb @@ -3,23 +3,16 @@ module ActiveRelation describe RelationInclusion do before do - foo = Table.new(:foo) - @relation1 = foo.project(foo[:id]) - @relation2 = Table.new(:bar) - @attribute = @relation1[:id] - end - - describe RelationInclusion, '==' do - it "obtains if attribute1 and attribute2 are identical" do - RelationInclusion.new(@attribute, @relation1).should == RelationInclusion.new(@attribute, @relation1) - RelationInclusion.new(@attribute, @relation1).should_not == RelationInclusion.new(@attribute, @relation2) - end + users = Table.new(:users) + @relation = users.project(users[:id]) + @attribute = @relation[:id] end describe RelationInclusion, '#to_sql' do it "manufactures subselect sql" do - RelationInclusion.new(@attribute, @relation1).to_sql.should be_like(" - `foo`.`id` IN (SELECT `foo`.`id` FROM `foo`) + # remove when sufficient coverage of sql strategies exists + RelationInclusion.new(@attribute, @relation).to_sql.should be_like(" + `users`.`id` IN (SELECT `users`.`id` FROM `users`) ") end end diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index b2b239097addb..91bf7773c1598 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -8,7 +8,7 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql inserting the data for one item' do - Insertion.new(@relation, @relation[:name] => "nick").to_sql.should be_like(" + Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)).to_sql.should be_like(" INSERT INTO `users` (`users`.`name`) VALUES ('nick') diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 64d41effc51ae..a424239c4b20a 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -81,7 +81,7 @@ module ActiveRelation .aggregate(@relation2[:user_id], @relation2[:id].count) \ .group(@relation2[:user_id]) \ .rename(@relation2[:id].count, :cnt) \ - .as(:photo_count) + .as('photo_count') end describe '#attributes' do diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 3af3b8aa9c6e5..8f35760801e80 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -89,7 +89,7 @@ module ActiveRelation end it "accepts arbitrary strings" do - @relation.select("arbitrary").should == Selection.new(@relation, "arbitrary") + @relation.select("arbitrary").should == Selection.new(@relation, Scalar.new("arbitrary", @relation)) end end @@ -100,9 +100,17 @@ module ActiveRelation end describe '#aggregate' do + before do + @expression1 = @attribute1.sum + @expression2 = @attribute2.sum + end + it 'manufactures a group relation' do @relation.aggregate(@expression1, @expression2).group(@attribute1, @attribute2). \ - should == Aggregation.new(@relation, :expressions => [@expresion, @expression2], :groupings => [@attribute1, @attribute2]) + should == Aggregation.new(@relation, + :expressions => [@expression1, @expression2], + :groupings => [@attribute1, @attribute2] + ) end end @@ -119,7 +127,8 @@ module ActiveRelation describe '#insert' do it 'manufactures an insertion relation' do Session.start do - mock(Session.new).create(Insertion.new(@relation, record = {@relation[:name] => 'carl'})) + record = {@relation[:name] => 'carl'} + mock(Session.new).create(Insertion.new(@relation, record.bind(@relation))) @relation.insert(record).should == @relation end end @@ -128,7 +137,8 @@ module ActiveRelation describe '#update' do it 'manufactures an update relation' do Session.start do - mock(Session.new).update(Update.new(@relation, assignments = {@relation[:name] => 'bob'})) + assignments = {@relation[:name] => Scalar.new('bob', @relation)} + mock(Session.new).update(Update.new(@relation, assignments.bind(@relation))) @relation.update(assignments).should == @relation end end diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index 3a18d4ae6e7a3..d5e0c6a9f63ac 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -4,12 +4,12 @@ module ActiveRelation describe Selection do before do @relation = Table.new(:users) - @predicate = Equality.new(@relation[:id], 1) + @predicate = Equality.new(@relation[:id], 1.bind(@relation)) end describe '#initialize' do it "manufactures nested selection relations if multiple predicates are provided" do - @predicate2 = LessThan.new(@relation[:age], 2) + @predicate2 = LessThan.new(@relation[:age], 2.bind(@relation)) Selection.new(@relation, @predicate, @predicate2). \ should == Selection.new(Selection.new(@relation, @predicate2), @predicate) end @@ -39,7 +39,7 @@ module ActiveRelation end it "allows arbitrary sql" do - Selection.new(@relation, "asdf").to_sql.should be_like(" + Selection.new(@relation, "asdf".bind(@relation)).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` WHERE asdf diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 2cd3eb9d118fd..cad14fd5ec0da 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -8,14 +8,14 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql updating attributes' do - Update.new(@relation, @relation[:name] => "nick").to_sql.should be_like(" + Update.new(@relation, @relation[:name] => "nick".bind(@relation)).to_sql.should be_like(" UPDATE `users` SET `users`.`name` = 'nick' ") end it 'manufactures sql updating a selection relation' do - Update.new(@relation.select(@relation[:id].equals(1)), @relation[:name] => "nick").to_sql.should be_like(" + Update.new(@relation.select(@relation[:id].equals(1)), @relation[:name] => "nick".bind(@relation)).to_sql.should be_like(" UPDATE `users` SET `users`.`name` = 'nick' WHERE `users`.`id` = 1 diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/active_relation/unit/session/session_spec.rb index 1ac69976b590d..89d96ef3234e8 100644 --- a/spec/active_relation/unit/session/session_spec.rb +++ b/spec/active_relation/unit/session/session_spec.rb @@ -32,8 +32,8 @@ module ActiveRelation describe Session::CRUD do before do - @insert = Insertion.new(@relation, @relation[:name] => 'nick') - @update = Update.new(@relation, @relation[:name] => 'nick') + @insert = Insertion.new(@relation, @relation[:name] => 'nick'.bind(@relation)) + @update = Update.new(@relation, @relation[:name] => 'nick'.bind(@relation)) @delete = Deletion.new(@relation) @select = @relation end From 98527c8f7dd64f086895c1576fb33e8b91071142 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 5 Mar 2008 22:12:21 -0800 Subject: [PATCH 0079/1492] basic functionality for simplest active record find(id) - messy code, to be cleaned up this weekend --- lib/active_relation/engines/engine.rb | 14 ++++++++++++ lib/active_relation/sessions/session.rb | 22 +++++++++---------- .../unit/relations/table_spec.rb | 6 +++++ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/active_relation/engines/engine.rb b/lib/active_relation/engines/engine.rb index 36b77b886e548..d5b312607ec3f 100644 --- a/lib/active_relation/engines/engine.rb +++ b/lib/active_relation/engines/engine.rb @@ -1,4 +1,18 @@ module ActiveRelation + # this file is currently just a hack to adapt between activerecord::base which holds the connection specification + # and active relation. ultimately, this file should be in effect what the connection specification is in active record; + # that is: a spec of the database (url, password, etc.), a quoting adapter layer, and a connection pool. class Engine + def initialize(ar = nil) + @ar = ar + end + + def connection + @ar.connection + end + + def method_missing(method, *args, &block) + @ar.connection.send(method, *args, &block) + end end end \ No newline at end of file diff --git a/lib/active_relation/sessions/session.rb b/lib/active_relation/sessions/session.rb index 0724abc5a7ba5..4bdbe6997884c 100644 --- a/lib/active_relation/sessions/session.rb +++ b/lib/active_relation/sessions/session.rb @@ -1,24 +1,22 @@ require 'singleton' module ActiveRelation - class Session + class Session class << self + attr_accessor :instance + alias_method :manufacture, :new + def start if @started yield else begin @started = true - @instance = new - manufacture = method(:new) - metaclass.class_eval do - define_method(:new) { @instance } - end + @instance = manufacture + metaclass.send :alias_method, :new, :instance yield ensure - metaclass.class_eval do - define_method(:new, &manufacture) - end + metaclass.send :alias_method, :new, :manufacture @started = false end end @@ -31,8 +29,10 @@ def create(insert) end def read(select) - @read ||= {} - @read.has_key?(select) ? @read[select] : (@read[select] = select.engine.select_all(select.to_sql)) + @read ||= Hash.new do |hash, select| + hash[select] = select.engine.select_all(select.to_sql) + end + @read[select] end def update(update) diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 8f14ce33cf0d4..95ad7133db624 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -91,5 +91,11 @@ module ActiveRelation Table.new(:users, engine = Engine.new).engine.should == engine end end + + describe '#reset' do + it "" do + pending + end + end end end \ No newline at end of file From 5d7c8176f1df8df819dadb1973a202a1c2d9836d Mon Sep 17 00:00:00 2001 From: Josh Susser Date: Sun, 9 Mar 2008 15:40:11 -0700 Subject: [PATCH 0080/1492] change README to README.markdown --- README => README.markdown | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) rename README => README.markdown (93%) diff --git a/README b/README.markdown similarity index 93% rename from README rename to README.markdown index d60a4ec0bb828..4324b0b128f64 100644 --- a/README +++ b/README.markdown @@ -1,8 +1,11 @@ -== Abstract == +ActiveRelation +============== + +## Abstract ## ActiveRelation is a Relational Algebra for Ruby. It simplifies the generation of both the simplest and the most complex of SQL queries and it transparently 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. -== A Gentle Introduction == +## A Gentle Introduction ## Generating a query with ARel is simple. For example, in order to produce @@ -11,34 +14,34 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: ActiveRelation::Table.new(:users).to_sql - + In fact, you will probably never call `#to_sql`. Let `users = ActiveRelation::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: users.each { |user| ... } - + In other words, Arel relations behave implement Ruby's Eunmerable interface. Let's have a look at a concrete example: users.first # => {'id' => 10, 'name' => 'bob'} - + As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). -== Relational Algebra == +## Relational Algebra ## Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: users.insert({users[:name] => 'amy'}) # => INSERT INTO users (users.name) VALUES ('amy') - + To delete all users: users.delete # => DELETE FROM users - + To update: users.update({users[:name] => 'carl'}) # => UPDATE users SET name = 'carl' As you can see, the `relation` named `users` does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate SQL queries to do the various CRUD operations. -=== More Sophisticated Queries Relations === +### More Sophisticated Queries Relations ### Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: @@ -58,8 +61,7 @@ The best property of the Relational is compositionality, or closure under all op .select(users[:name].equals('amy')) \ .project(users[:id]) \ # => SELECT users.id FROM users WHERE users.name = 'amy' -s -== Contributions == +## Contributions ## -I appreciate all contributions to ActiveRelation. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. \ No newline at end of file +I appreciate all contributions to ActiveRelation. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. From a29ceffc9476c99ff02f0617d2e38627c526bac2 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 11 Mar 2008 22:42:47 -0700 Subject: [PATCH 0081/1492] implemented hashing macro; implemented custom matcher testing this macro --- lib/active_relation/.DS_Store | Bin 6148 -> 6148 bytes lib/active_relation/extensions/object.rb | 10 ++++++- lib/active_relation/primitives/attribute.rb | 5 +--- lib/active_relation/relations/relation.rb | 4 --- lib/active_relation/relations/table.rb | 2 +- .../unit/primitives/attribute_spec.rb | 7 +++++ .../unit/relations/table_spec.rb | 5 ++-- spec/matchers/hash_the_same_as.rb | 26 ++++++++++++++++++ spec/spec_helper.rb | 2 +- 9 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 spec/matchers/hash_the_same_as.rb diff --git a/lib/active_relation/.DS_Store b/lib/active_relation/.DS_Store index 2a449ff62e35245aec99ff3f3ff49ea0048a9256..9918127870d102c50de66d07fd25f40e6f54037c 100644 GIT binary patch delta 169 zcmZoMXfc=|#>B`mu~2NHo}wr#0|Nsi1A_nqLmophLncE$h@LFSxI7Xh!^M!wP{B|F zB#~s($}C%r9cd0n*<9#G5@t_AmngBgrFL delta 79 zcmZoMXfc=|#>CJ*u~2NHo}wr-0|Nsi1A_nqLkUABLq0 delegatee + end + def bind(relation) ActiveRelation::Scalar.new(self, relation) end diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index baaae1973cf40..20677f824bc39 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -48,10 +48,7 @@ def ==(other) module Congruence def self.included(klass) - klass.class_eval do - alias_method :eql?, :== - delegate :hash, :to => :name - end + klass.hash_on :name end def history diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 1c97cc703546e..f9823bf92d522 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -102,10 +102,6 @@ def alias? false end - def eql?(other) - self == other - end - def to_sql(strategy = Sql::Relation.new(engine)) strategy.select [ "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new(engine)) }.join(', ')}", diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 84eb1213ee791..4682298608bcc 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -3,7 +3,7 @@ class Table < Relation cattr_accessor :engine attr_reader :name, :engine - delegate :hash, :to => :name + hash_on :name def initialize(name, engine = Table.engine) @name, @engine = name.to_s, engine diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index 95c972d814880..d424bf4dff523 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -68,6 +68,13 @@ module ActiveRelation Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)) end end + + describe 'hashing' do + it "implements hash equality" do + Attribute.new(@relation, 'name').should hash_the_same_as(Attribute.new(@relation, 'name')) + Attribute.new(@relation, 'name').should_not hash_the_same_as(Attribute.new(@relation, 'id')) + end + end end describe '#to_sql' do diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 95ad7133db624..41ed2dc404b89 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -75,9 +75,8 @@ module ActiveRelation describe 'hashing' do it "implements hash equality" do - hash = {} - hash[Table.new(:users)] = 1 - hash[Table.new(:users)].should == 1 + Table.new(:users).should hash_the_same_as(Table.new(:users)) + Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) end end diff --git a/spec/matchers/hash_the_same_as.rb b/spec/matchers/hash_the_same_as.rb new file mode 100644 index 0000000000000..86e98f31a3dbb --- /dev/null +++ b/spec/matchers/hash_the_same_as.rb @@ -0,0 +1,26 @@ +module HashTheSameAsMatcher + class HashTheSameAs + def initialize(expected) + @expected = expected + end + + def matches?(target) + @target = target + hash = {} + hash[@expected] = :some_arbitrary_value + hash[@target] == :some_arbitrary_value + end + + def failure_message + "expected #{@target} to hash the same as #{@expected}; they must be `eql?` and have the same `#hash` value" + end + + def negative_failure_message + "expected #{@target} to hash differently than #{@expected}; they must not be `eql?` or have a differing `#hash` values" + end + end + + def hash_the_same_as(expected) + HashTheSameAs.new(expected) + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cd9c8e96cba35..6d00064e819c6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -26,7 +26,7 @@ def shift end Spec::Runner.configure do |config| - config.include(BeLikeMatcher) + config.include(BeLikeMatcher, HashTheSameAsMatcher) config.mock_with :rr config.before do ActiveRelation::Table.engine = ActiveRecord::Base.connection From 12ef6a5ad15078d2f634d3c6cdfc453848f90122 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 11 Mar 2008 23:22:26 -0700 Subject: [PATCH 0082/1492] refactored session's interaction with engine/connection - follows law of demeter - Table.engine uses AR::Base adapter --- TODO | 48 +++++++++++++++++++ lib/active_relation/relations/deletion.rb | 4 ++ lib/active_relation/relations/insertion.rb | 4 ++ lib/active_relation/relations/relation.rb | 4 ++ lib/active_relation/relations/update.rb | 4 ++ lib/active_relation/sessions/session.rb | 8 ++-- .../unit/relations/deletion_spec.rb | 8 ++++ .../unit/relations/insertion_spec.rb | 10 +++- .../unit/relations/relation_spec.rb | 10 +++- .../unit/relations/update_spec.rb | 9 ++++ .../unit/session/session_spec.rb | 18 +++---- spec/spec_helper.rb | 2 +- 12 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000000000..45bc9c4f2f6e9 --- /dev/null +++ b/TODO @@ -0,0 +1,48 @@ +todo: +- clarify distinction between engine and connection: an engine is a connection pool, plus the quoting operations +- #relation is now on scalar, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of +- clean up integration tests in join - i find the aggregate stuff too integrationy; unit testing would be better +- test relation, table reset +- cache expiry on write + - rewrite of querycache test in light of this +- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting strategy taken from the attribute + - descend on array, along with bind written in terms of it +- standardize quoting + - use strings everywhere, not symbols ? +- rename and test sql strategies + - the parallel names are confusing since it's not obvious what's what. plus, we lack unit tests; the biggest complaint is a lack of clarity concerning what purpose these serve in the system. Unit tests wont illustrate much unless we use concrete examples. +- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent +- re-evaluate bind + +done: +. Relation <=> Relation -> InnerJoinOperation +. Relation << Relation -> LeftOuterJoinOperation +. InnerJoinOperation.on(*Predicate) -> InnerJoinRelation +. LeftOuterJoinOperation.on(*Predicate) -> LeftOuterJoinRelation +. Relation[Symbol] -> Attribute +. Relation[Range] -> Relation +. Attribute == Attribute -> EqualityPredicate +. Attribute >= Attribute -> GreaterThanOrEqualToPredicate +. Relation.include?(Column) -> Predicate +. Relation.project(*Column) -> ProjectionRelation +. Relation.select(*Predicate) -> SelectionRelation +. Relation.order(*Column) -> OrderRelation +. #to_sql +. Remove Builder +. Namespace +. Audit SqlAlchemy for missing features +- Generalized denormalizations on any aggregation (count, yes, but also max, min, average) +- Remove operator overloading of << and <=> for joins. Make it just foo.join(bar) and foo.outer_join(bar). +- Remove operator overloading of == for predicates. make it a.equals(b) (note lack of question mark). +- hookup more predicates (=, <=, =>) +- get some basic aggregations working: users.project(user[:points].max) +- Alias Table Names +- When joining with any sort of aggregation, it needs to be a nested select +- get a scalar select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count)) +- Session +- sublimate scalars to deal with the fact that they must be quoted per engine +- clean-up singleton monstrosity +- extract hashing module +- hash custom matcher +- make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what + - session just calls execute, passing in a connection; by default it gets a connection from the relation. diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index f3d81baf27986..c5906e8bc8a25 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -12,6 +12,10 @@ def to_sql(strategy = nil) ].compact.join("\n") end + def call(connection = engine.connection) + connection.delete(to_sql) + end + def ==(other) self.class == other.class and relation == other.relation diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 16fe3d5f46927..036db1a3190df 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -15,6 +15,10 @@ def to_sql(strategy = nil) ].join("\n") end + def call(connection = engine.connection) + connection.insert(to_sql) + end + def ==(other) self.class == other.class and relation == other.relation and diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index f9823bf92d522..69935a7be0a23 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -115,6 +115,10 @@ def to_sql(strategy = Sql::Relation.new(engine)) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql + + def call(connection = engine.connection) + connection.select_all(to_sql) + end def attribute_for_name(name) attributes.detect { |a| a.alias_or_name.to_s == name.to_s } diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index c50919af3ea59..0914cda03593f 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -16,6 +16,10 @@ def to_sql(strategy = nil) ].join("\n") end + def call(connection = engine.connection) + connection.update(to_sql) + end + def ==(other) self.class == other.class and relation == other.relation and diff --git a/lib/active_relation/sessions/session.rb b/lib/active_relation/sessions/session.rb index 4bdbe6997884c..fe917a0e4dded 100644 --- a/lib/active_relation/sessions/session.rb +++ b/lib/active_relation/sessions/session.rb @@ -25,22 +25,22 @@ def start module CRUD def create(insert) - insert.engine.insert(insert.to_sql) + insert.call(insert.engine.connection) end def read(select) @read ||= Hash.new do |hash, select| - hash[select] = select.engine.select_all(select.to_sql) + hash[select] = select.call(select.engine.connection) end @read[select] end def update(update) - update.engine.update(update.to_sql) + update.call(update.engine.connection) end def delete(delete) - delete.engine.delete(delete.to_sql) + delete.call(delete.engine.connection) end end include CRUD diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb index 1f14ae5d34fa9..27d879e96fe3b 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -22,5 +22,13 @@ module ActiveRelation ") end end + + describe '#call' do + it 'executes a delete on the connection' do + deletion = Deletion.new(@relation) + mock(connection = Object.new).delete(deletion.to_sql) + deletion.call(connection) + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index 91bf7773c1598..f081743c507a1 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -4,16 +4,24 @@ module ActiveRelation describe Insertion do before do @relation = Table.new(:users) + @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) end describe '#to_sql' do it 'manufactures sql inserting the data for one item' do - Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)).to_sql.should be_like(" + @insertion.to_sql.should be_like(" INSERT INTO `users` (`users`.`name`) VALUES ('nick') ") end end + + describe '#call' do + it 'executes an insert on the connection' do + mock(connection = Object.new).insert(@insertion.to_sql) + @insertion.call(connection) + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 8f35760801e80..2e9f7fd3c8d65 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -69,7 +69,7 @@ module ActiveRelation describe '#as' do it "manufactures an alias relation" do - @relation.as(:thucydides).should == Alias.new(@relation, :thucydides) + @relation.as(:paul).should == Alias.new(@relation, :paul) end end @@ -99,6 +99,14 @@ module ActiveRelation end end + describe '#call' do + it 'executes a select_all on the connection' do + mock(connection = Object.new).select_all(@relation.to_sql) + @relation.call(connection) + end + end + + describe '#aggregate' do before do @expression1 = @attribute1.sum diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index cad14fd5ec0da..848760de83394 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -22,5 +22,14 @@ module ActiveRelation ") end end + + describe '#call' do + it 'executes an update on the connection' do + update = Update.new(@relation, @relation[:name] => "nick".bind(@relation)) + mock(connection = Object.new).update(update.to_sql) + update.call(connection) + end + end + end end \ No newline at end of file diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/active_relation/unit/session/session_spec.rb index 89d96ef3234e8..9fba6cc6b23bf 100644 --- a/spec/active_relation/unit/session/session_spec.rb +++ b/spec/active_relation/unit/session/session_spec.rb @@ -35,39 +35,39 @@ module ActiveRelation @insert = Insertion.new(@relation, @relation[:name] => 'nick'.bind(@relation)) @update = Update.new(@relation, @relation[:name] => 'nick'.bind(@relation)) @delete = Deletion.new(@relation) - @select = @relation + @read = @relation end describe '#create' do it "executes an insertion on the connection" do - mock(@insert.engine).insert(@insert.to_sql) + mock(@insert).call(@insert.engine.connection) @session.create(@insert) end end describe '#read' do it "executes an selection on the connection" do - mock(@select.engine).select_all(@select.to_sql).once - @session.read(@select) + mock(@read).call(@read.engine.connection) + @session.read(@read) end it "is memoized" do - mock(@select.engine).select_all(@select.to_sql).once - @session.read(@select) - @session.read(@select) + mock(@read).call(@read.engine.connection).once + @session.read(@read) + @session.read(@read) end end describe '#update' do it "executes an update on the connection" do - mock(@update.engine).update(@update.to_sql) + mock(@update).call(@update.engine.connection) @session.update(@update) end end describe '#delete' do it "executes a delete on the connection" do - mock(@delete.engine).delete(@delete.to_sql) + mock(@delete).call(@delete.engine.connection) @session.delete(@delete) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6d00064e819c6..01a703a7d4d84 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -29,6 +29,6 @@ def shift config.include(BeLikeMatcher, HashTheSameAsMatcher) config.mock_with :rr config.before do - ActiveRelation::Table.engine = ActiveRecord::Base.connection + ActiveRelation::Table.engine = ActiveRelation::Engine.new(ActiveRecord::Base) end end \ No newline at end of file From 8a62a733c107a33edee8cabc908c3ebc3b280e8b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 11 Mar 2008 23:39:40 -0700 Subject: [PATCH 0083/1492] renamed strategy method to format - strategy (the method on scalar and attribute) is a complex double-dispatching scheme to format (to_sql) a scalar in the light of the particular attribute; that is, it casts strings to integers if the column is int, etc. --- TODO | 3 ++- lib/active_relation/predicates.rb | 2 +- lib/active_relation/primitives/attribute.rb | 8 ++++++-- lib/active_relation/primitives/scalar.rb | 6 +++--- lib/active_relation/relations/relation.rb | 4 ++-- lib/active_relation/sql.rb | 14 +++++++------- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/TODO b/TODO index 45bc9c4f2f6e9..5ef1573c38f2b 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ todo: - clarify distinction between engine and connection: an engine is a connection pool, plus the quoting operations -- #relation is now on scalar, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - clean up integration tests in join - i find the aggregate stuff too integrationy; unit testing would be better - test relation, table reset - cache expiry on write @@ -46,3 +45,5 @@ done: - hash custom matcher - make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what - session just calls execute, passing in a connection; by default it gets a connection from the relation. +- #strategy is now on scalar, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of + - renamed to #format: operand1.format(operand2) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index ba926a86e5328..12ddd1b48d05b 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -25,7 +25,7 @@ def qualify end def to_sql(strategy = nil) - "#{operand1.to_sql(operand2.strategy)} #{predicate_sql} #{operand2.to_sql(operand1.strategy)}" + "#{operand2.format(operand1)} #{predicate_sql} #{operand1.format(operand2)}" end def descend diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 20677f824bc39..bbea7b4554085 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -111,15 +111,19 @@ def average end include Expressions - def to_sql(strategy = self.strategy) + def to_sql(strategy = Sql::Predicate.new(engine)) strategy.attribute prefix, name, self.alias end + def format(object) + object.to_sql(strategy) + end + + private def strategy Sql::Attribute.new(self) end - private def prefix relation.prefix_for(self) end diff --git a/lib/active_relation/primitives/scalar.rb b/lib/active_relation/primitives/scalar.rb index fa88404ee39f9..d428541a509df 100644 --- a/lib/active_relation/primitives/scalar.rb +++ b/lib/active_relation/primitives/scalar.rb @@ -6,12 +6,12 @@ def initialize(value, relation) @value, @relation = value, relation end - def to_sql(strategy = self.strategy) + def to_sql(strategy = Sql::Predicate.new(relation.engine)) strategy.scalar value end - def strategy - ActiveRelation::Sql::Scalar.new(relation.engine) + def format(object) + object.to_sql(Sql::Scalar.new(relation.engine)) end def ==(other) diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 69935a7be0a23..ee2e00aa214f5 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -132,8 +132,8 @@ def bind(relation) self end - def strategy - Sql::Predicate.new(engine) + def format(object) + object.to_sql(Sql::Predicate.new(engine)) end def attributes; [] end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 99cfc66383fc8..ff00223ce77f0 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -4,8 +4,8 @@ module Quoting delegate :quote_table_name, :quote_column_name, :quote, :to => :engine end - # module Formatting Context / Strategy # unit test me!!! - class Strategy + # unit test me!!! + class Formatter attr_reader :engine include Quoting @@ -14,7 +14,7 @@ def initialize(engine) end end - class Projection < Strategy + class Projection < Formatter def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") end @@ -24,7 +24,7 @@ def select(select_sql, aliaz) end end - class Predicate < Strategy + class Predicate < Formatter def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" end @@ -38,19 +38,19 @@ def select(select_sql, aliaz) end end - class Selection < Strategy + class Selection < Formatter def scalar(scalar) scalar end end - class Relation < Strategy + class Relation < Formatter def select(select_sql, aliaz) select_sql end end - class Aggregation < Strategy + class Aggregation < Formatter def select(select_sql, aliaz) "(#{select_sql}) AS #{engine.quote_table_name(aliaz)}" end From 181f28e2f9ddd1aa8e78709c45368ade9585287a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 12 Mar 2008 00:06:41 -0700 Subject: [PATCH 0084/1492] pending tests. better coverage though i dislike the strategy --- TODO | 4 ++-- spec/active_relation/unit/relations/relation_spec.rb | 6 +++++- spec/active_relation/unit/relations/table_spec.rb | 5 +++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/TODO b/TODO index 5ef1573c38f2b..f502b48a3d8a9 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ todo: -- clarify distinction between engine and connection: an engine is a connection pool, plus the quoting operations - clean up integration tests in join - i find the aggregate stuff too integrationy; unit testing would be better - test relation, table reset - cache expiry on write @@ -8,7 +7,8 @@ todo: - descend on array, along with bind written in terms of it - standardize quoting - use strings everywhere, not symbols ? -- rename and test sql strategies +- rename sql strategies +- test sql strategies - the parallel names are confusing since it's not obvious what's what. plus, we lack unit tests; the biggest complaint is a lack of clarity concerning what purpose these serve in the system. Unit tests wont illustrate much unless we use concrete examples. - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent - re-evaluate bind diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 2e9f7fd3c8d65..5e434e52a6135 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -156,7 +156,11 @@ module ActiveRelation describe Relation::Enumerable do it "is enumerable" do - pending + pending "I don't like this mock-based test" + data = [1,2,3] + mock.instance_of(Session).read(anything) { data } + @relation.collect.should == data + @relation.first.should == data.first end end end diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 41ed2dc404b89..e62f84d93ab11 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -92,8 +92,9 @@ module ActiveRelation end describe '#reset' do - it "" do - pending + it "reloads columns from the database" do + lambda { stub(@relation).columns { [] } }.should_not change { @relation.attributes } + lambda { @relation.reset }.should change { @relation.attributes } end end end From 46da601b2f5507325bba279d5c12ed88ce9e685e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 12 Mar 2008 00:12:41 -0700 Subject: [PATCH 0085/1492] more inadequate tests --- .../unit/primitives/attribute_spec.rb | 6 ++++-- spec/active_relation/unit/relations/table_spec.rb | 15 ++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index d424bf4dff523..bdd22721b3b3f 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -39,8 +39,10 @@ module ActiveRelation end describe '#column' do - it "" do - pending + it "returns the corresponding column in the relation" do + pending "damn mock based tests are too easy" + stub(@relation).column_for(@attribute) { 'bruisers' } + @attribute.column.should == 'bruisers' end end diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index e62f84d93ab11..6286ea9de16e4 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -65,6 +65,14 @@ module ActiveRelation Attribute.new(@relation, :name) ] end + + describe '#reset' do + it "reloads columns from the database" do + pending + lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } + lambda { @relation.reset }.should change { @relation.attributes } + end + end end describe '#qualify' do @@ -90,12 +98,5 @@ module ActiveRelation Table.new(:users, engine = Engine.new).engine.should == engine end end - - describe '#reset' do - it "reloads columns from the database" do - lambda { stub(@relation).columns { [] } }.should_not change { @relation.attributes } - lambda { @relation.reset }.should change { @relation.attributes } - end - end end end \ No newline at end of file From 2654c29bfdb2ccddfed8cceaaaba06e46892bdb9 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 12 Mar 2008 22:41:30 -0700 Subject: [PATCH 0086/1492] test coverage of #prefix_for on join. - it delegates to the relation containing the attribute - if the relation containing the attribute is an alias, it returns the alias --- README | 4 +-- .../unit/predicates/binary_spec.rb | 2 +- .../unit/relations/join_spec.rb | 30 +++++++++++++++++-- .../unit/relations/order_spec.rb | 2 +- .../unit/relations/projection_spec.rb | 4 +-- .../unit/relations/range_spec.rb | 2 +- .../unit/relations/rename_spec.rb | 2 +- .../unit/relations/selection_spec.rb | 2 +- 8 files changed, 37 insertions(+), 11 deletions(-) diff --git a/README b/README index d60a4ec0bb828..54a698c76821b 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ == Abstract == -ActiveRelation is a Relational Algebra for Ruby. It simplifies the generation of both the simplest and the most complex of SQL queries and it transparently 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. +ActiveRelation is a Relational Algebra for Ruby. It 1) simplifies the generation of both the simplest and the most complex of SQL queries and it 2) transparently 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. == A Gentle Introduction == @@ -58,7 +58,7 @@ The best property of the Relational is compositionality, or closure under all op .select(users[:name].equals('amy')) \ .project(users[:id]) \ # => SELECT users.id FROM users WHERE users.name = 'amy' -s + == Contributions == diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 677d8f3ab409a..d552d8b5013c4 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -34,7 +34,7 @@ def predicate_sql end describe '#descend' do - it "distributes over the predicates and attributes" do + it "distributes a block over the predicates and attributes" do ConcreteBinary.new(@attribute1, @attribute2).descend(&:qualify). \ should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) end diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index a424239c4b20a..fdc4a4cdf26e7 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -25,6 +25,13 @@ module ActiveRelation end end + describe '#qualify' do + it 'descends' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ + should == Join.new("INNER JOIN", @relation1, @relation2, @predicate).descend(&:qualify) + end + end + describe '#descend' do it 'distributes over the relations and predicates' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ @@ -33,8 +40,27 @@ module ActiveRelation end describe '#prefix_for' do - it 'needs a test' do - pending + describe 'when the joined relations are simple' do + it "returns the name of the relation containing the attribute" do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation1[:id]) \ + .should == @relation1.prefix_for(@relation1[:id]) + Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation2[:id]) \ + .should == @relation2.prefix_for(@relation2[:id]) + + end + end + + describe 'when one of the joined relations is an alias' do + before do + @aliased_relation = @relation1.as(:alias) + end + + it "returns the alias of the relation containing the attribute" do + Join.new("INNER JOIN", @aliased_relation, @relation2, @predicate).prefix_for(@aliased_relation[:id]) \ + .should == @aliased_relation.alias + Join.new("INNER JOIN", @aliased_relation, @relation2, @predicate).prefix_for(@relation2[:id]) \ + .should == @relation2.prefix_for(@relation2[:id]) + end end end diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb index 032bd2b40f0d4..6a9ce07024ef0 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -15,7 +15,7 @@ module ActiveRelation end describe '#descend' do - it "distributes over the relation and attributes" do + it "distributes a block over the relation and attributes" do Order.new(@relation, @attribute).descend(&:qualify). \ should == Order.new(@relation.descend(&:qualify), @attribute.qualify) end diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index 01a4d74bc6169..9acfead8b8e5b 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -31,14 +31,14 @@ module ActiveRelation end describe '#qualify' do - it "distributes over the relation and attributes" do + it "descends" do Projection.new(@relation, @attribute).qualify. \ should == Projection.new(@relation, @attribute).descend(&:qualify) end end describe '#descend' do - it "distributes over the relation and attributes" do + it "distributes a block over the relation and attributes" do Projection.new(@relation, @attribute).descend(&:qualify). \ should == Projection.new(@relation.descend(&:qualify), @attribute.qualify) end diff --git a/spec/active_relation/unit/relations/range_spec.rb b/spec/active_relation/unit/relations/range_spec.rb index 7be2ca1b03a58..a0207c7342b77 100644 --- a/spec/active_relation/unit/relations/range_spec.rb +++ b/spec/active_relation/unit/relations/range_spec.rb @@ -14,7 +14,7 @@ module ActiveRelation end describe '#descend' do - it "distributes over the relation" do + it "distributes a block over the relation" do Range.new(@relation, @range).descend(&:qualify).should == Range.new(@relation.descend(&:qualify), @range) end end diff --git a/spec/active_relation/unit/relations/rename_spec.rb b/spec/active_relation/unit/relations/rename_spec.rb index c960f767364f7..9a63c4fc807eb 100644 --- a/spec/active_relation/unit/relations/rename_spec.rb +++ b/spec/active_relation/unit/relations/rename_spec.rb @@ -46,7 +46,7 @@ module ActiveRelation end describe '#descend' do - it "distributes over the relation and renames" do + it "distributes a block over the relation and renames" do Rename.new(@relation, @relation[:id] => :schmid).descend(&:qualify). \ should == Rename.new(@relation.descend(&:qualify), @relation[:id].qualify => :schmid) end diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index d5e0c6a9f63ac..4bb3817bf5756 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -23,7 +23,7 @@ module ActiveRelation end describe '#descend' do - it "distributes over the relation and predicates" do + it "distributes a block over the relation and predicates" do Selection.new(@relation, @predicate).descend(&:qualify). \ should == Selection.new(@relation.descend(&:qualify), @predicate.descend(&:qualify)) end From b1acebaaf0823c093853ade5700bbf5117b4f31a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 12 Mar 2008 23:31:18 -0700 Subject: [PATCH 0087/1492] - renamed scalar to value - added better test coverage and documentation of binary spec #to_sql --- TODO | 6 +- lib/active_relation/extensions/array.rb | 2 +- lib/active_relation/extensions/object.rb | 2 +- lib/active_relation/primitives.rb | 2 +- .../primitives/{scalar.rb => value.rb} | 6 +- lib/active_relation/sql.rb | 14 +-- .../unit/predicates/binary_spec.rb | 96 +++++++++++++++---- .../predicates/relation_inclusion_spec.rb | 20 ---- .../unit/relations/join_spec.rb | 6 +- .../unit/relations/projection_spec.rb | 2 +- .../unit/relations/relation_spec.rb | 4 +- 11 files changed, 98 insertions(+), 62 deletions(-) rename lib/active_relation/primitives/{scalar.rb => value.rb} (78%) delete mode 100644 spec/active_relation/unit/predicates/relation_inclusion_spec.rb diff --git a/TODO b/TODO index f502b48a3d8a9..fb656ef084c69 100644 --- a/TODO +++ b/TODO @@ -37,13 +37,13 @@ done: - get some basic aggregations working: users.project(user[:points].max) - Alias Table Names - When joining with any sort of aggregation, it needs to be a nested select -- get a scalar select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count)) +- get a value select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count)) - Session -- sublimate scalars to deal with the fact that they must be quoted per engine +- sublimate values to deal with the fact that they must be quoted per engine - clean-up singleton monstrosity - extract hashing module - hash custom matcher - make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what - session just calls execute, passing in a connection; by default it gets a connection from the relation. -- #strategy is now on scalar, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of +- #strategy is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - renamed to #format: operand1.format(operand2) diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index aa4354a78abf6..4bd20d812132a 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -2,7 +2,7 @@ class Array def to_hash Hash[*flatten] end - + def to_sql(strategy = nil) "(#{collect(&:to_sql).join(', ')})" end diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index c1269ee37b7ae..ab874150ed55f 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -8,7 +8,7 @@ def eql?(other) end def bind(relation) - ActiveRelation::Scalar.new(self, relation) + ActiveRelation::Value.new(self, relation) end def metaclass diff --git a/lib/active_relation/primitives.rb b/lib/active_relation/primitives.rb index 762925603450e..9909734d24ec8 100644 --- a/lib/active_relation/primitives.rb +++ b/lib/active_relation/primitives.rb @@ -1,4 +1,4 @@ require 'active_relation/primitives/attribute' -require 'active_relation/primitives/scalar' +require 'active_relation/primitives/value' require 'active_relation/primitives/expression' diff --git a/lib/active_relation/primitives/scalar.rb b/lib/active_relation/primitives/value.rb similarity index 78% rename from lib/active_relation/primitives/scalar.rb rename to lib/active_relation/primitives/value.rb index d428541a509df..ce9497cf34353 100644 --- a/lib/active_relation/primitives/scalar.rb +++ b/lib/active_relation/primitives/value.rb @@ -1,5 +1,5 @@ module ActiveRelation - class Scalar + class Value attr_reader :value, :relation def initialize(value, relation) @@ -7,11 +7,11 @@ def initialize(value, relation) end def to_sql(strategy = Sql::Predicate.new(relation.engine)) - strategy.scalar value + strategy.value value end def format(object) - object.to_sql(Sql::Scalar.new(relation.engine)) + object.to_sql(Sql::Value.new(relation.engine)) end def ==(other) diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index ff00223ce77f0..fb2177a55b935 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -29,8 +29,8 @@ def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" end - def scalar(scalar, column = nil) - quote(scalar, column) + def value(value, column = nil) + quote(value, column) end def select(select_sql, aliaz) @@ -39,8 +39,8 @@ def select(select_sql, aliaz) end class Selection < Formatter - def scalar(scalar) - scalar + def value(value) + value end end @@ -61,12 +61,12 @@ def initialize(attribute) @attribute, @engine = attribute, attribute.engine end - def scalar(scalar) - quote(scalar, @attribute.column) + def value(value) + quote(value, @attribute.column) end end - class Scalar < Predicate + class Value < Predicate end end end \ No newline at end of file diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index d552d8b5013c4..13b3f10a8c578 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -3,17 +3,83 @@ module ActiveRelation describe Binary do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:id] + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + @value = "1-asdf".bind(@relation) class ConcreteBinary < Binary def predicate_sql "<=>" end end end - + + describe '#to_sql' do + describe 'when relating two attributes' do + it 'manufactures sql with a binary operation' do + ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" + `users`.`id` <=> `users`.`name` + ") + end + end + + describe 'when relating an attribute and a value' do + describe 'when relating to an integer attribute' do + it 'formats values as integers' do + ConcreteBinary.new(@attribute1, @value).to_sql.should be_like(" + `users`.`id` <=> 1 + ") + end + end + + describe 'when relating to a string attribute' do + it 'formats values as strings' do + ConcreteBinary.new(@attribute2, @value).to_sql.should be_like(" + `users`.`name` <=> '1-asdf' + ") + end + end + end + + describe 'when relating two values' do + before do + @another_value = 2.bind(@relation) + end + + it 'quotes values appropriate to their type' do + ConcreteBinary.new(string = @value, integer = @another_value).to_sql.should be_like(" + '1-asdf' <=> 2 + ") + end + end + + describe 'when relating to an array' do + it 'manufactures sql with a list' do + pending + array = [1, 2, 3] + ConcreteBinary.new(@attribute1, array).to_sql.should be_like(" + `users`.`id` <=> (1,2,3) + ") + end + + it 'formats values in the array in the type of the attribute' do + pending + array = ['1-asdf', 2, 3] + ConcreteBinary.new(@attribute1, array).to_sql.should be_like(" + `users`.`id` <=> (1,2,3) + ") + end + end + + describe 'when relating to a relation' do + it 'manufactures sql with a subselect' do + ConcreteBinary.new(@attribute1, @relation).to_sql.should be_like(" + `users`.`id` <=> (SELECT `users`.`id`, `users`.`name` FROM `users`) + ") + end + end + end + describe '==' do it "obtains if attribute1 and attribute2 are identical" do Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) @@ -41,23 +107,13 @@ def predicate_sql end describe '#bind' do - it "distributes over the predicates and attributes" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@relation2). \ - should == ConcreteBinary.new(@attribute1.bind(@relation2), @attribute2.bind(@relation2)) - end - end - - describe '#to_sql' do - it 'manufactures sql with a binary operation' do - ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" - `users`.`id` <=> `photos`.`id` - ") + before do + @another_relation = Table.new(:photos) end - it 'appropriately quotes scalars' do - ConcreteBinary.new(@attribute1, "1-asdf".bind(@relation1)).to_sql.should be_like(" - `users`.`id` <=> 1 - ") + it "descends" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@attribute1.bind(@another_relation), @attribute2.bind(@another_relation)) end end end diff --git a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb b/spec/active_relation/unit/predicates/relation_inclusion_spec.rb deleted file mode 100644 index af5846b7476c5..0000000000000 --- a/spec/active_relation/unit/predicates/relation_inclusion_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module ActiveRelation - describe RelationInclusion do - before do - users = Table.new(:users) - @relation = users.project(users[:id]) - @attribute = @relation[:id] - end - - describe RelationInclusion, '#to_sql' do - it "manufactures subselect sql" do - # remove when sufficient coverage of sql strategies exists - RelationInclusion.new(@attribute, @relation).to_sql.should be_like(" - `users`.`id` IN (SELECT `users`.`id` FROM `users`) - ") - end - end - end -end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index fdc4a4cdf26e7..fefe069d7b589 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -103,10 +103,10 @@ module ActiveRelation describe 'with aggregated relations' do before do - @aggregation = @relation2 \ + @aggregation = @relation2 \ .aggregate(@relation2[:user_id], @relation2[:id].count) \ - .group(@relation2[:user_id]) \ - .rename(@relation2[:id].count, :cnt) \ + .group(@relation2[:user_id]) \ + .rename(@relation2[:id].count, :cnt) \ .as('photo_count') end diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index 9acfead8b8e5b..78766d330804b 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -52,7 +52,7 @@ module ActiveRelation ") end - it "manufactures sql with scalar selects" do + it "manufactures sql with value selects" do Projection.new(@relation, Projection.new(@relation, @relation[:name])).to_sql.should be_like(" SELECT (SELECT `users`.`name` FROM `users`) FROM `users` ") diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 5e434e52a6135..b562ec2a2a0d7 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -89,7 +89,7 @@ module ActiveRelation end it "accepts arbitrary strings" do - @relation.select("arbitrary").should == Selection.new(@relation, Scalar.new("arbitrary", @relation)) + @relation.select("arbitrary").should == Selection.new(@relation, Value.new("arbitrary", @relation)) end end @@ -145,7 +145,7 @@ module ActiveRelation describe '#update' do it 'manufactures an update relation' do Session.start do - assignments = {@relation[:name] => Scalar.new('bob', @relation)} + assignments = {@relation[:name] => Value.new('bob', @relation)} mock(Session.new).update(Update.new(@relation, assignments.bind(@relation))) @relation.update(assignments).should == @relation end From c823c2c2cc3e5d0a709d67e585e73fde0f11512f Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 13 Mar 2008 22:39:51 -0700 Subject: [PATCH 0088/1492] renamed sql formatting strategies to correspond with sql grammar rule names in the mysql bnf --- lib/active_relation/primitives/attribute.rb | 2 +- lib/active_relation/primitives/value.rb | 2 +- lib/active_relation/relations/join.rb | 2 +- lib/active_relation/relations/relation.rb | 18 +++++++------- lib/active_relation/sql.rb | 27 ++++++++++----------- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index bbea7b4554085..0fed676727559 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -111,7 +111,7 @@ def average end include Expressions - def to_sql(strategy = Sql::Predicate.new(engine)) + def to_sql(strategy = Sql::WhereCondition.new(engine)) strategy.attribute prefix, name, self.alias end diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb index ce9497cf34353..096c876ecd92c 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/active_relation/primitives/value.rb @@ -6,7 +6,7 @@ def initialize(value, relation) @value, @relation = value, relation end - def to_sql(strategy = Sql::Predicate.new(relation.engine)) + def to_sql(strategy = Sql::WhereCondition.new(relation.engine)) strategy.value value end diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 043b237de757a..4a57795280a0f 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -61,7 +61,7 @@ def externalize(relation) delegate :engine, :to => :relation def table_sql - relation.aggregation?? relation.to_sql(Sql::Aggregation.new(engine)) : relation.send(:table_sql) + relation.aggregation?? relation.to_sql(Sql::TableReference.new(engine)) : relation.send(:table_sql) end def selects diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index ee2e00aa214f5..9847cf2b7c7f0 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -102,16 +102,16 @@ def alias? false end - def to_sql(strategy = Sql::Relation.new(engine)) + def to_sql(strategy = Sql::SelectStatement.new(engine)) strategy.select [ - "SELECT #{attributes.collect{ |a| a.to_sql(Sql::Projection.new(engine)) }.join(', ')}", + "SELECT #{attributes.collect{ |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}", "FROM #{table_sql}", - (joins unless joins.blank? ), - ("WHERE #{selects.collect{|s| s.to_sql(Sql::Selection.new(engine))}.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank? ), - ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), - ("LIMIT #{limit}" unless limit.blank? ), - ("OFFSET #{offset}" unless offset.blank? ) + (joins unless joins.blank? ), + ("WHERE #{selects.collect{|s| s.to_sql(Sql::WhereClause.new(engine))}.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank? ), + ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), + ("LIMIT #{limit}" unless limit.blank? ), + ("OFFSET #{offset}" unless offset.blank? ) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql @@ -133,7 +133,7 @@ def bind(relation) end def format(object) - object.to_sql(Sql::Predicate.new(engine)) + object.to_sql(Sql::WhereCondition.new(engine)) end def attributes; [] end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index fb2177a55b935..b38e6dc3927f6 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -4,7 +4,6 @@ module Quoting delegate :quote_table_name, :quote_column_name, :quote, :to => :engine end - # unit test me!!! class Formatter attr_reader :engine include Quoting @@ -14,7 +13,7 @@ def initialize(engine) end end - class Projection < Formatter + class SelectExpression < Formatter def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") end @@ -24,7 +23,13 @@ def select(select_sql, aliaz) end end - class Predicate < Formatter + class WhereClause < Formatter + def value(value) + value + end + end + + class WhereCondition < Formatter def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" end @@ -38,25 +43,19 @@ def select(select_sql, aliaz) end end - class Selection < Formatter - def value(value) - value - end - end - - class Relation < Formatter + class SelectStatement < Formatter def select(select_sql, aliaz) select_sql end end - class Aggregation < Formatter + class TableReference < Formatter def select(select_sql, aliaz) - "(#{select_sql}) AS #{engine.quote_table_name(aliaz)}" + "(#{select_sql}) AS #{quote_table_name(aliaz)}" end end - class Attribute < Predicate + class Attribute < WhereCondition def initialize(attribute) @attribute, @engine = attribute, attribute.engine end @@ -66,7 +65,7 @@ def value(value) end end - class Value < Predicate + class Value < WhereCondition end end end \ No newline at end of file From a8cf09a5b6bd4019e0f68e70d62d6e6be6b3784b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 13 Mar 2008 22:46:12 -0700 Subject: [PATCH 0089/1492] added abstract declaration --- lib/active_relation.rb | 2 +- lib/active_relation/extensions.rb | 1 + lib/active_relation/extensions/class.rb | 17 +++++++++++++++++ lib/active_relation/extensions/object.rb | 10 +--------- lib/active_relation/sql.rb | 2 ++ .../unit/relations/compound_spec.rb | 8 -------- 6 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 lib/active_relation/extensions/class.rb diff --git a/lib/active_relation.rb b/lib/active_relation.rb index f04825ad4c379..5b5c91706fd9b 100644 --- a/lib/active_relation.rb +++ b/lib/active_relation.rb @@ -4,8 +4,8 @@ require 'activesupport' require 'activerecord' -require 'active_relation/sql' require 'active_relation/extensions' +require 'active_relation/sql' require 'active_relation/predicates' require 'active_relation/relations' require 'active_relation/engines' diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb index 8a024947edffd..7268a5549b8b7 100644 --- a/lib/active_relation/extensions.rb +++ b/lib/active_relation/extensions.rb @@ -1,3 +1,4 @@ require 'active_relation/extensions/object' +require 'active_relation/extensions/class' require 'active_relation/extensions/array' require 'active_relation/extensions/hash' diff --git a/lib/active_relation/extensions/class.rb b/lib/active_relation/extensions/class.rb new file mode 100644 index 0000000000000..0e5b728c26550 --- /dev/null +++ b/lib/active_relation/extensions/class.rb @@ -0,0 +1,17 @@ +class Class + def abstract(*methods) + methods.each do |method| + define_method method do + raise NotImplementedError + end + end + end + + def hash_on(delegatee) + define_method :eql? do |other| + self == other + end + + delegate :hash, :to => delegatee + end +end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index ab874150ed55f..90eb73f0b0f56 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -1,12 +1,4 @@ -class Object - def self.hash_on(delegatee) - def eql?(other) - self == other - end - - delegate :hash, :to => delegatee - end - +class Object def bind(relation) ActiveRelation::Value.new(self, relation) end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index b38e6dc3927f6..e5a4eed08b91b 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -8,6 +8,8 @@ class Formatter attr_reader :engine include Quoting + abstract :attribute, :select, :value + def initialize(engine) @engine = engine end diff --git a/spec/active_relation/unit/relations/compound_spec.rb b/spec/active_relation/unit/relations/compound_spec.rb index d271529998ff2..e8fcd12e2cdbf 100644 --- a/spec/active_relation/unit/relations/compound_spec.rb +++ b/spec/active_relation/unit/relations/compound_spec.rb @@ -21,13 +21,5 @@ def ==(other) @compound_relation.attributes.should == @relation.attributes.collect { |a| a.bind(@compound_relation) } end end - - describe 'hashing' do - it 'implements hash equality' do - hash = {} - hash[@compound_relation] = 1 - hash[ConcreteCompound.new(@relation)].should == 1 - end - end end end \ No newline at end of file From 384008b04b48735a73dbba5a7d4a18e794c897ad Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 13 Mar 2008 22:52:18 -0700 Subject: [PATCH 0090/1492] annotated abstraction - in compound - created superclass for the create/insert/update write operations, marked :call as abstract --- lib/active_relation/relations.rb | 1 + lib/active_relation/relations/compound.rb | 2 ++ lib/active_relation/relations/deletion.rb | 2 +- lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/update.rb | 2 +- lib/active_relation/sql.rb | 5 +++-- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index f992fca8be068..7776fd3d18219 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -1,5 +1,6 @@ require 'active_relation/relations/relation' require 'active_relation/relations/compound' +require 'active_relation/relations/writing' require 'active_relation/relations/table' require 'active_relation/relations/join' require 'active_relation/relations/aggregation' diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index a10b7588e7cf2..fac0939c6f6c2 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -1,5 +1,7 @@ module ActiveRelation class Compound < Relation + abstract :==, :descend + attr_reader :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index c5906e8bc8a25..0fcf523efe27f 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -1,5 +1,5 @@ module ActiveRelation - class Deletion < Compound + class Deletion < Writing def initialize(relation) @relation = relation end diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 036db1a3190df..ce065b64c151c 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -1,5 +1,5 @@ module ActiveRelation - class Insertion < Compound + class Insertion < Writing attr_reader :record def initialize(relation, record) diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index 0914cda03593f..a51f248866864 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -1,5 +1,5 @@ module ActiveRelation - class Update < Compound + class Update < Writing attr_reader :assignments def initialize(relation, assignments) diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index e5a4eed08b91b..0d233b307e3bd 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -5,10 +5,11 @@ module Quoting end class Formatter + abstract :attribute, :select, :value + attr_reader :engine - include Quoting - abstract :attribute, :select, :value + include Quoting def initialize(engine) @engine = engine From cd9efb9eec6198f08b4fd5d754a33aa1b1669b37 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 13 Mar 2008 22:56:00 -0700 Subject: [PATCH 0091/1492] annotated abstract methods on relation --- lib/active_relation/relations/relation.rb | 17 +++++++++++------ lib/active_relation/relations/writing.rb | 5 +++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 lib/active_relation/relations/writing.rb diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 9847cf2b7c7f0..15782cde067d6 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -1,5 +1,7 @@ module ActiveRelation class Relation + abstract :attributes, :selects, :orders, :inserts, :groupings, :joins, :limit, :offset, :alias + def session Session.new end @@ -119,14 +121,17 @@ def to_sql(strategy = Sql::SelectStatement.new(engine)) def call(connection = engine.connection) connection.select_all(to_sql) end - - def attribute_for_name(name) - attributes.detect { |a| a.alias_or_name.to_s == name.to_s } - end + + module AttributeAccessors + def attribute_for_name(name) + attributes.detect { |a| a.alias_or_name.to_s == name.to_s } + end - def attribute_for_attribute(attribute) - attributes.detect { |a| a =~ attribute } + def attribute_for_attribute(attribute) + attributes.detect { |a| a =~ attribute } + end end + include AttributeAccessors def bind(relation) self diff --git a/lib/active_relation/relations/writing.rb b/lib/active_relation/relations/writing.rb new file mode 100644 index 0000000000000..3054e9b72fab8 --- /dev/null +++ b/lib/active_relation/relations/writing.rb @@ -0,0 +1,5 @@ +module ActiveRelation + class Writing < Compound + abstract :call, :to_sql + end +end \ No newline at end of file From 7f01134d1bdca70dcc9b16cf433894e7c8236815 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 15 Mar 2008 18:37:47 -0700 Subject: [PATCH 0092/1492] js/nk - fixed hashing --- TODO | 10 ++++++---- lib/active_relation/relations/compound.rb | 2 +- lib/active_relation/relations/relation.rb | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index fb656ef084c69..c7ff84fe280e2 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ todo: -- clean up integration tests in join - i find the aggregate stuff too integrationy; unit testing would be better +- try to make aggration testing in join spec to be a bit more unit-like +- finish pending tests - test relation, table reset - cache expiry on write - rewrite of querycache test in light of this @@ -7,11 +8,11 @@ todo: - descend on array, along with bind written in terms of it - standardize quoting - use strings everywhere, not symbols ? -- rename sql strategies -- test sql strategies - - the parallel names are confusing since it's not obvious what's what. plus, we lack unit tests; the biggest complaint is a lack of clarity concerning what purpose these serve in the system. Unit tests wont illustrate much unless we use concrete examples. +- "unit" test sql strategies + - use real world examples, so they should be like a tutorial. - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent - re-evaluate bind +- mock out database done: . Relation <=> Relation -> InnerJoinOperation @@ -47,3 +48,4 @@ done: - session just calls execute, passing in a connection; by default it gets a connection from the relation. - #strategy is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - renamed to #format: operand1.format(operand2) +- rename sql strategies diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index fac0939c6f6c2..04f8ed5a2f853 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -16,4 +16,4 @@ def qualify descend(&:qualify) end end -end \ No newline at end of file +end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 15782cde067d6..e0fe43a0a0b12 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -1,7 +1,9 @@ module ActiveRelation class Relation - abstract :attributes, :selects, :orders, :inserts, :groupings, :joins, :limit, :offset, :alias - + abstract :attributes, :selects, :orders, :inserts, :groupings, :joins, :limit, :offset, :alias, :hash + + hash_on :hash + def session Session.new end From 1a6a3a1c6aa2f75333edef9100951407c4f76f1f Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 15:40:15 -0700 Subject: [PATCH 0093/1492] properly quoting array values --- TODO | 21 ++++++++++++++ lib/active_relation/extensions/array.rb | 4 +-- lib/active_relation/extensions/hash.rb | 8 ++++++ lib/active_relation/extensions/object.rb | 4 +++ lib/active_relation/primitives/attribute.rb | 4 +-- lib/active_relation/relations/aggregation.rb | 2 +- lib/active_relation/relations/compound.rb | 9 +++--- lib/active_relation/relations/insertion.rb | 4 +-- lib/active_relation/relations/join.rb | 5 +++- lib/active_relation/relations/relation.rb | 8 ++---- lib/active_relation/relations/writing.rb | 1 - lib/active_relation/sql.rb | 12 ++++++-- .../unit/predicates/binary_spec.rb | 28 ++++++++++--------- .../unit/relations/compound_spec.rb | 6 ++++ .../unit/relations/join_spec.rb | 9 +++++- 15 files changed, 89 insertions(+), 36 deletions(-) diff --git a/TODO b/TODO index c7ff84fe280e2..8425057d5907a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,25 @@ todo: +- remove to_sql logic from array and hash, push it into a strategy +- string passthrough: + :joins=>"INNER JOIN posts ON comments.post_id = posts.id" + :conditions=>"(`posts`.author_id = 1)", + :select=>"`comments`.*" + :conditions=>"1 = 1" + +- need adapters for this form: + {:conditions=>["approved = ?", false]} + {:conditions=>{:approved=>false}} + {:conditions=>{"topics.approved"=>false}} + {:conditions=>{:address=>#, "customers.name"=>"David1"}} + +- need to_sql for ranges + {:conditions=>{:id=>2..3}} + +- orders need string pass through + :order=>"developers.name desc, developers.id desc", + +- orders need to be composable +- #bind in Attribute and Expression should be doing a descend? - try to make aggration testing in join spec to be a bit more unit-like - finish pending tests - test relation, table reset diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index 4bd20d812132a..3b4246fb1c890 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -3,7 +3,7 @@ def to_hash Hash[*flatten] end - def to_sql(strategy = nil) - "(#{collect(&:to_sql).join(', ')})" + def to_sql(strategy = Sql::SelectExpression.new) + strategy.array self end end \ No newline at end of file diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index a33ace573850b..ae3e48146fc9c 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -8,4 +8,12 @@ def descend(&block) descendent.merge(yield(key) => yield(value)) end end + + def to_sql(strategy = nil) + '(' + + inject([]) do |values, (key, value)| + values << key.format(value) + end.join(', ') + + ')' + end end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 90eb73f0b0f56..2682ed99fe224 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -3,6 +3,10 @@ def bind(relation) ActiveRelation::Value.new(self, relation) end + def to_sql(strategy = nil) + strategy.scalar self + end + def metaclass class << self self diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 0fed676727559..f2c484cc595a8 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -52,11 +52,11 @@ def self.included(klass) end def history - [self] + (ancestor ? [ancestor, ancestor.send(:history)].flatten : []) + [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) end def =~(other) - !(history & other.send(:history)).empty? + !(history & other.history).empty? end end include Congruence diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index d3a026820d315..38f1f2dda8da9 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -12,7 +12,7 @@ def ==(other) groupings == other.groupings and expressions == other.expressions end - + def attributes expressions.collect { |e| e.bind(self) } end diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 04f8ed5a2f853..5778fe9b22900 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -1,11 +1,12 @@ module ActiveRelation class Compound < Relation - abstract :==, :descend - attr_reader :relation + + hash_on :relation + delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, - :hash, :engine, + :engine, :to => :relation def attributes @@ -16,4 +17,4 @@ def qualify descend(&:qualify) end end -end +end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index ce065b64c151c..7a13bc06bb869 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -10,8 +10,8 @@ def to_sql(strategy = nil) [ "INSERT", "INTO #{table_sql}", - "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES #{record.values.to_sql}" + "(#{record.keys.collect(&:to_sql)})", + "VALUES #{record.to_sql}" ].join("\n") end diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 4a57795280a0f..835e965f72b5b 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -1,8 +1,11 @@ module ActiveRelation class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates + delegate :engine, :to => :relation1 + hash_on :relation1 + def initialize(join_sql, relation1, relation2, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end @@ -14,7 +17,7 @@ def ==(other) (relation2 == other.relation1 and relation1 == other.relation2) ) end - + def qualify descend(&:qualify) end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index e0fe43a0a0b12..039af619250bf 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -1,9 +1,5 @@ module ActiveRelation class Relation - abstract :attributes, :selects, :orders, :inserts, :groupings, :joins, :limit, :offset, :alias, :hash - - hash_on :hash - def session Session.new end @@ -108,10 +104,10 @@ def alias? def to_sql(strategy = Sql::SelectStatement.new(engine)) strategy.select [ - "SELECT #{attributes.collect{ |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}", + "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank? ), - ("WHERE #{selects.collect{|s| s.to_sql(Sql::WhereClause.new(engine))}.join("\n\tAND ")}" unless selects.blank? ), + ("WHERE #{selects.collect {|s| s.to_sql(Sql::WhereClause.new(engine))}.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), ("LIMIT #{limit}" unless limit.blank? ), diff --git a/lib/active_relation/relations/writing.rb b/lib/active_relation/relations/writing.rb index 3054e9b72fab8..2714ce4d0c067 100644 --- a/lib/active_relation/relations/writing.rb +++ b/lib/active_relation/relations/writing.rb @@ -1,5 +1,4 @@ module ActiveRelation class Writing < Compound - abstract :call, :to_sql end end \ No newline at end of file diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 0d233b307e3bd..85dd591860a0a 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -5,8 +5,6 @@ module Quoting end class Formatter - abstract :attribute, :select, :value - attr_reader :engine include Quoting @@ -64,7 +62,15 @@ def initialize(attribute) end def value(value) - quote(value, @attribute.column) + value.to_sql(self) + end + + def scalar(scalar) + quote(scalar, @attribute.column) + end + + def array(array) + "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" end end diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 13b3f10a8c578..62d894b0fa722 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -54,20 +54,22 @@ def predicate_sql end describe 'when relating to an array' do - it 'manufactures sql with a list' do - pending - array = [1, 2, 3] - ConcreteBinary.new(@attribute1, array).to_sql.should be_like(" - `users`.`id` <=> (1,2,3) - ") + describe 'when given an arry of elements of the same type of the attribute' do + it 'manufactures sql with a list' do + array = [1, 2, 3] + ConcreteBinary.new(@attribute1, array.bind(@relation)).to_sql.should be_like(" + `users`.`id` <=> (1, 2, 3) + ") + end end - - it 'formats values in the array in the type of the attribute' do - pending - array = ['1-asdf', 2, 3] - ConcreteBinary.new(@attribute1, array).to_sql.should be_like(" - `users`.`id` <=> (1,2,3) - ") + + describe 'when given an array, the elements of which are not the same type as the attribute' do + it 'formats values in the array in the type of the attribute' do + array = ['1-asdf', 2, 3] + ConcreteBinary.new(@attribute1, array.bind(@relation)).to_sql.should be_like(" + `users`.`id` <=> (1, 2, 3) + ") + end end end diff --git a/spec/active_relation/unit/relations/compound_spec.rb b/spec/active_relation/unit/relations/compound_spec.rb index e8fcd12e2cdbf..54a89f3f570e7 100644 --- a/spec/active_relation/unit/relations/compound_spec.rb +++ b/spec/active_relation/unit/relations/compound_spec.rb @@ -21,5 +21,11 @@ def ==(other) @compound_relation.attributes.should == @relation.attributes.collect { |a| a.bind(@compound_relation) } end end + + describe 'hashing' do + it 'implements hash equality' do + ConcreteCompound.new(@relation).should hash_the_same_as(ConcreteCompound.new(@relation)) + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index fefe069d7b589..a0e94a5b65fc2 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -24,6 +24,13 @@ module ActiveRelation Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation2, @relation1, @predicate) end end + + describe 'hashing' do + it 'implements hash equality' do + Join.new("INNER JOIN", @relation1, @relation2, @predicate) \ + .should hash_the_same_as(Join.new("INNER JOIN", @relation1, @relation2, @predicate)) + end + end describe '#qualify' do it 'descends' do @@ -150,6 +157,6 @@ module ActiveRelation ") end end - end + end end end \ No newline at end of file From ed9c8d4d828fe4e28c1e37ed8921acbee54450f2 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 15:41:27 -0700 Subject: [PATCH 0094/1492] renamed strategy to formatter --- TODO | 6 +++--- lib/active_relation/extensions/array.rb | 4 ++-- lib/active_relation/extensions/hash.rb | 2 +- lib/active_relation/extensions/object.rb | 4 ++-- lib/active_relation/predicates.rb | 2 +- lib/active_relation/primitives/attribute.rb | 8 ++++---- lib/active_relation/primitives/expression.rb | 2 +- lib/active_relation/primitives/value.rb | 4 ++-- lib/active_relation/relations/deletion.rb | 2 +- lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/relation.rb | 4 ++-- lib/active_relation/relations/update.rb | 2 +- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/TODO b/TODO index 8425057d5907a..c3d5e07647cb6 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ todo: -- remove to_sql logic from array and hash, push it into a strategy +- remove to_sql logic from array and hash, push it into a formatter - string passthrough: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" :conditions=>"(`posts`.author_id = 1)", @@ -25,7 +25,7 @@ todo: - test relation, table reset - cache expiry on write - rewrite of querycache test in light of this -- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting strategy taken from the attribute +- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute - descend on array, along with bind written in terms of it - standardize quoting - use strings everywhere, not symbols ? @@ -67,6 +67,6 @@ done: - hash custom matcher - make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what - session just calls execute, passing in a connection; by default it gets a connection from the relation. -- #strategy is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a strategy (Sql::Relation) ... should it be called predicate strategy? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of +- #formatter is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a formatter (Sql::Relation) ... should it be called predicate formatter? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - renamed to #format: operand1.format(operand2) - rename sql strategies diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index 3b4246fb1c890..5e2981a4c5241 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -3,7 +3,7 @@ def to_hash Hash[*flatten] end - def to_sql(strategy = Sql::SelectExpression.new) - strategy.array self + def to_sql(formatter = Sql::SelectExpression.new) + formatter.array self end end \ No newline at end of file diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index ae3e48146fc9c..133eab1026834 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -9,7 +9,7 @@ def descend(&block) end end - def to_sql(strategy = nil) + def to_sql(formatter = nil) '(' + inject([]) do |values, (key, value)| values << key.format(value) diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index 2682ed99fe224..cd51543c910ce 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -3,8 +3,8 @@ def bind(relation) ActiveRelation::Value.new(self, relation) end - def to_sql(strategy = nil) - strategy.scalar self + def to_sql(formatter = nil) + formatter.scalar self end def metaclass diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 12ddd1b48d05b..98a966507f52b 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -24,7 +24,7 @@ def qualify descend(&:qualify) end - def to_sql(strategy = nil) + def to_sql(formatter = nil) "#{operand2.format(operand1)} #{predicate_sql} #{operand1.format(operand2)}" end diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index f2c484cc595a8..fc857347fc937 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -111,16 +111,16 @@ def average end include Expressions - def to_sql(strategy = Sql::WhereCondition.new(engine)) - strategy.attribute prefix, name, self.alias + def to_sql(formatter = Sql::WhereCondition.new(engine)) + formatter.attribute prefix, name, self.alias end def format(object) - object.to_sql(strategy) + object.to_sql(formatter) end private - def strategy + def formatter Sql::Attribute.new(self) end diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index 11aa558977a64..2df2888ba0122 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -25,7 +25,7 @@ def to_attribute end include Transformations - def to_sql(strategy = nil) + def to_sql(formatter = nil) "#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '') end diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb index 096c876ecd92c..131610f2e9c9e 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/active_relation/primitives/value.rb @@ -6,8 +6,8 @@ def initialize(value, relation) @value, @relation = value, relation end - def to_sql(strategy = Sql::WhereCondition.new(relation.engine)) - strategy.value value + def to_sql(formatter = Sql::WhereCondition.new(relation.engine)) + formatter.value value end def format(object) diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index 0fcf523efe27f..1b94df8729707 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -4,7 +4,7 @@ def initialize(relation) @relation = relation end - def to_sql(strategy = nil) + def to_sql(formatter = nil) [ "DELETE", "FROM #{table_sql}", diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 7a13bc06bb869..bcf8e33e0aae0 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -6,7 +6,7 @@ def initialize(relation, record) @relation, @record = relation, record end - def to_sql(strategy = nil) + def to_sql(formatter = nil) [ "INSERT", "INTO #{table_sql}", diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 039af619250bf..8c93f948f724f 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -102,8 +102,8 @@ def alias? false end - def to_sql(strategy = Sql::SelectStatement.new(engine)) - strategy.select [ + def to_sql(formatter = Sql::SelectStatement.new(engine)) + formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank? ), diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index a51f248866864..dc88ea03623b7 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -6,7 +6,7 @@ def initialize(relation, assignments) @relation, @assignments = relation, assignments end - def to_sql(strategy = nil) + def to_sql(formatter = nil) [ "UPDATE #{table_sql} SET", assignments.inject("") do |assignments, (attribute, value)| From af3d7c5193eee90ad17b1ba8aaf5d76a2874c0a5 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 16:14:02 -0700 Subject: [PATCH 0095/1492] formatting insert and update statements - values need to be coerced to the type corresponding to the column --- TODO | 1 - lib/active_relation/extensions/array.rb | 4 +- lib/active_relation/extensions/hash.rb | 8 --- lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/update.rb | 6 +- .../unit/predicates/binary_spec.rb | 22 ++++--- .../unit/relations/insertion_spec.rb | 51 +++++++++++++--- .../unit/relations/update_spec.rb | 61 ++++++++++++++----- 8 files changed, 110 insertions(+), 45 deletions(-) diff --git a/TODO b/TODO index c3d5e07647cb6..465fd5530d864 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ todo: -- remove to_sql logic from array and hash, push it into a formatter - string passthrough: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" :conditions=>"(`posts`.author_id = 1)", diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index 5e2981a4c5241..c07819d35f8b4 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -3,7 +3,7 @@ def to_hash Hash[*flatten] end - def to_sql(formatter = Sql::SelectExpression.new) - formatter.array self + def to_sql(formatter = nil) + "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" end end \ No newline at end of file diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index 133eab1026834..a33ace573850b 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -8,12 +8,4 @@ def descend(&block) descendent.merge(yield(key) => yield(value)) end end - - def to_sql(formatter = nil) - '(' + - inject([]) do |values, (key, value)| - values << key.format(value) - end.join(', ') + - ')' - end end \ No newline at end of file diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index bcf8e33e0aae0..901ff6eb70688 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -11,7 +11,7 @@ def to_sql(formatter = nil) "INSERT", "INTO #{table_sql}", "(#{record.keys.collect(&:to_sql)})", - "VALUES #{record.to_sql}" + "VALUES (#{record.collect { |key, value| key.format(value) }})" ].join("\n") end diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index dc88ea03623b7..7eb78d5473c75 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -9,9 +9,9 @@ def initialize(relation, assignments) def to_sql(formatter = nil) [ "UPDATE #{table_sql} SET", - assignments.inject("") do |assignments, (attribute, value)| - assignments << " #{attribute.to_sql} = #{value.to_sql}" - end, + assignments.collect do |attribute, value| + "#{value.format(attribute)} = #{attribute.format(value)}" + end.join("\n"), ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) ].join("\n") end diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 62d894b0fa722..b63472a836396 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -54,19 +54,25 @@ def predicate_sql end describe 'when relating to an array' do - describe 'when given an arry of elements of the same type of the attribute' do - it 'manufactures sql with a list' do - array = [1, 2, 3] - ConcreteBinary.new(@attribute1, array.bind(@relation)).to_sql.should be_like(" + describe 'when the array\'s elements are the same type as the attribute' do + before do + @array = [1, 2, 3] + end + + it 'manufactures sql with a comma separated list' do + ConcreteBinary.new(@attribute1, @array.bind(@relation)).to_sql.should be_like(" `users`.`id` <=> (1, 2, 3) ") end end - describe 'when given an array, the elements of which are not the same type as the attribute' do - it 'formats values in the array in the type of the attribute' do - array = ['1-asdf', 2, 3] - ConcreteBinary.new(@attribute1, array.bind(@relation)).to_sql.should be_like(" + describe 'when the array\'s elements are not same type as the attribute' do + before do + @array = ['1-asdf', 2, 3] + end + + it 'formats values in the array as the type of the attribute' do + ConcreteBinary.new(@attribute1, @array.bind(@relation)).to_sql.should be_like(" `users`.`id` <=> (1, 2, 3) ") end diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index f081743c507a1..b74ec6c7cb908 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -4,20 +4,57 @@ module ActiveRelation describe Insertion do before do @relation = Table.new(:users) - @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) end describe '#to_sql' do - it 'manufactures sql inserting the data for one item' do - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`users`.`name`) VALUES ('nick') - ") + describe 'when given values whose types correspond to the types of the attributes' do + before do + @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) + end + + it 'manufactures sql inserting data' do + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick') + ") + end + end + + describe 'when given values whose types differ from from the types of the attributes' do + before do + @insertion = Insertion.new(@relation, @relation[:id] => '1-asdf'.bind(@relation)) + end + + it 'manufactures sql inserting data' do + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`id`) VALUES (1) + ") + end + end + + describe 'when given values whose types correspond to the type of the attribtues' do + before do + @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) + end + + it 'manufactures sql inserting data' do + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick') + ") + end end end describe '#call' do + before do + @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) + end + it 'executes an insert on the connection' do mock(connection = Object.new).insert(@insertion.to_sql) @insertion.call(connection) diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 848760de83394..485c86372d1b0 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -7,27 +7,58 @@ module ActiveRelation end describe '#to_sql' do - it 'manufactures sql updating attributes' do - Update.new(@relation, @relation[:name] => "nick".bind(@relation)).to_sql.should be_like(" - UPDATE `users` - SET `users`.`name` = 'nick' - ") + describe 'when given values whose types correspond to the types of the attributes' do + before do + @update = Update.new(@relation, @relation[:name] => "nick".bind(@relation)) + end + + it 'manufactures sql updating attributes' do + @update.to_sql.should be_like(" + UPDATE `users` + SET `users`.`name` = 'nick' + ") + end end - - it 'manufactures sql updating a selection relation' do - Update.new(@relation.select(@relation[:id].equals(1)), @relation[:name] => "nick".bind(@relation)).to_sql.should be_like(" - UPDATE `users` - SET `users`.`name` = 'nick' - WHERE `users`.`id` = 1 - ") + + describe 'when given values whose types differ from from the types of the attributes' do + before do + @update = Update.new(@relation, @relation[:id] => '1-asdf'.bind(@relation)) + end + + it 'manufactures sql updating attributes' do + @update.to_sql.should be_like(" + UPDATE `users` + SET `users`.`id` = 1 + ") + end + end + + describe 'when the relation is a selection' do + before do + @update = Update.new( + @relation.select(@relation[:id].equals(1)), + @relation[:name] => "nick".bind(@relation) + ) + end + + it 'manufactures sql updating a selection relation' do + @update.to_sql.should be_like(" + UPDATE `users` + SET `users`.`name` = 'nick' + WHERE `users`.`id` = 1 + ") + end end end describe '#call' do + before do + @update = Update.new(@relation, @relation[:name] => "nick".bind(@relation)) + end + it 'executes an update on the connection' do - update = Update.new(@relation, @relation[:name] => "nick".bind(@relation)) - mock(connection = Object.new).update(update.to_sql) - update.call(connection) + mock(connection = Object.new).update(@update.to_sql) + @update.call(connection) end end From 07f7f752fecb56316456f144c121e471fd0d0847 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 16:17:13 -0700 Subject: [PATCH 0096/1492] renamed operators - equals / eq - greater_than / gt - etc. --- README | 6 ++--- TODO | 2 +- lib/active_relation/primitives/attribute.rb | 10 ++++----- .../unit/primitives/attribute_spec.rb | 22 +++++++++---------- .../unit/relations/deletion_spec.rb | 2 +- .../unit/relations/join_spec.rb | 10 ++++----- .../unit/relations/relation_spec.rb | 2 +- .../unit/relations/update_spec.rb | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README b/README index 54a698c76821b..87e9678df609f 100644 --- a/README +++ b/README @@ -42,7 +42,7 @@ As you can see, the `relation` named `users` does not represent an individual qu Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: - users.select(users[:name].equals('amy')) # => SELECT * FROM users WHERE users.name = 'amy' + users.select(users[:name].eq('amy')) # => SELECT * FROM users WHERE users.name = 'amy' What would, in SQL, be part of the `SELECT` clause is called here a `projection`: @@ -50,12 +50,12 @@ What would, in SQL, be part of the `SELECT` clause is called here a `projection` Joins are fairly straightforward: - users.join(photos).on(users[:id].equals(photos[:user_id])) => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id + users.join(photos).on(users[:id].eq(photos[:user_id])) => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id The best property of the Relational is compositionality, or closure under all operations. For example, to select and project: users \ - .select(users[:name].equals('amy')) \ + .select(users[:name].eq('amy')) \ .project(users[:id]) \ # => SELECT users.id FROM users WHERE users.name = 'amy' diff --git a/TODO b/TODO index 465fd5530d864..4e7701917da20 100644 --- a/TODO +++ b/TODO @@ -53,7 +53,7 @@ done: . Audit SqlAlchemy for missing features - Generalized denormalizations on any aggregation (count, yes, but also max, min, average) - Remove operator overloading of << and <=> for joins. Make it just foo.join(bar) and foo.outer_join(bar). -- Remove operator overloading of == for predicates. make it a.equals(b) (note lack of question mark). +- Remove operator overloading of == for predicates. make it a.eq(b) (note lack of question mark). - hookup more predicates (=, <=, =>) - get some basic aggregations working: users.project(user[:points].max) - Alias Table Names diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index fc857347fc937..0ddbbb5cd4691 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -62,23 +62,23 @@ def =~(other) include Congruence module Predications - def equals(other) + def eq(other) Equality.new(self, other) end - def less_than(other) + def lt(other) LessThan.new(self, other) end - def less_than_or_equal_to(other) + def lteq(other) LessThanOrEqualTo.new(self, other) end - def greater_than(other) + def gt(other) GreaterThan.new(self, other) end - def greater_than_or_equal_to(other) + def gteq(other) GreaterThanOrEqualTo.new(self, other) end diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index bdd22721b3b3f..a0f6cde8f7550 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -16,7 +16,7 @@ module ActiveRelation describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do - derived_relation = @relation.select(@relation[:id].equals(1)) + derived_relation = @relation.select(@relation[:id].eq(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end @@ -95,33 +95,33 @@ module ActiveRelation @attribute = Attribute.new(@relation, :name) end - describe '#equals' do + describe '#eq' do it "manufactures an equality predicate" do - @attribute.equals('name').should == Equality.new(@attribute, 'name') + @attribute.eq('name').should == Equality.new(@attribute, 'name') end end - describe '#less_than' do + describe '#lt' do it "manufactures a less-than predicate" do - @attribute.less_than(10).should == LessThan.new(@attribute, 10) + @attribute.lt(10).should == LessThan.new(@attribute, 10) end end - describe '#less_than_or_equal_to' do + describe '#lteq' do it "manufactures a less-than or equal-to predicate" do - @attribute.less_than_or_equal_to(10).should == LessThanOrEqualTo.new(@attribute, 10) + @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) end end - describe '#greater_than' do + describe '#gt' do it "manufactures a greater-than predicate" do - @attribute.greater_than(10).should == GreaterThan.new(@attribute, 10) + @attribute.gt(10).should == GreaterThan.new(@attribute, 10) end end - describe '#greater_than_or_equal_to' do + describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do - @attribute.greater_than_or_equal_to(10).should == GreaterThanOrEqualTo.new(@attribute, 10) + @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb index 27d879e96fe3b..71ddd8d820337 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -15,7 +15,7 @@ module ActiveRelation end it 'manufactures sql deleting a selection relation' do - Deletion.new(@relation.select(@relation[:id].equals(1))).to_sql.should be_like(" + Deletion.new(@relation.select(@relation[:id].eq(1))).to_sql.should be_like(" DELETE FROM `users` WHERE `users`.`id` = 1 diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index a0e94a5b65fc2..515c9ce0f20a8 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -5,12 +5,12 @@ module ActiveRelation before do @relation1 = Table.new(:users) @relation2 = Table.new(:photos) - @predicate = @relation1[:id].equals(@relation2[:user_id]) + @predicate = @relation1[:id].eq(@relation2[:user_id]) end describe '==' do before do - @another_predicate = @relation1[:id].equals(1) + @another_predicate = @relation1[:id].eq(1) @another_relation = Table.new(:cameras) end @@ -96,8 +96,8 @@ module ActiveRelation end it 'manufactures sql joining the two tables, merging any selects' do - Join.new("INNER JOIN", @relation1.select(@relation1[:id].equals(1)), - @relation2.select(@relation2[:id].equals(2)), @predicate).to_sql.should be_like(" + Join.new("INNER JOIN", @relation1.select(@relation1[:id].eq(1)), + @relation2.select(@relation2[:id].eq(2)), @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` @@ -149,7 +149,7 @@ module ActiveRelation end it "keeps selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].equals(1)), @predicate).to_sql.should be_like(" + Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count` diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index b562ec2a2a0d7..b5e204abcf3ce 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -45,7 +45,7 @@ module ActiveRelation describe Relation::Operations do describe 'joins' do before do - @predicate = @relation[:id].equals(@relation[:id]) + @predicate = @relation[:id].eq(@relation[:id]) end describe '#join' do diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 485c86372d1b0..9053f292d654d 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -36,7 +36,7 @@ module ActiveRelation describe 'when the relation is a selection' do before do @update = Update.new( - @relation.select(@relation[:id].equals(1)), + @relation.select(@relation[:id].eq(1)), @relation[:name] => "nick".bind(@relation) ) end From aa5c9a19826c84bbb9c9f75f8d1a4b04b874780c Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 16:53:49 -0700 Subject: [PATCH 0097/1492] added support for `attribute IN ...` and `attribute BETWEEN ...` - IN and BETWEEN are chosen depending on the type of the second operand - ranges (1..2), arrays ([1,2,3]), and relations ("SELECT * ...") are all supported --- lib/active_relation/extensions.rb | 1 + lib/active_relation/extensions/array.rb | 4 ++ lib/active_relation/extensions/range.rb | 9 +++ lib/active_relation/predicates.rb | 14 +---- lib/active_relation/primitives/attribute.rb | 4 ++ lib/active_relation/primitives/value.rb | 2 + lib/active_relation/relations/relation.rb | 21 ++++--- lib/active_relation/sql.rb | 14 +++-- .../unit/predicates/binary_spec.rb | 44 +++----------- .../unit/predicates/in_spec.rb | 58 +++++++++++++++++++ .../unit/primitives/attribute_spec.rb | 6 ++ .../unit/relations/relation_spec.rb | 20 ++++--- 12 files changed, 126 insertions(+), 71 deletions(-) create mode 100644 lib/active_relation/extensions/range.rb create mode 100644 spec/active_relation/unit/predicates/in_spec.rb diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb index 7268a5549b8b7..21d67240046b5 100644 --- a/lib/active_relation/extensions.rb +++ b/lib/active_relation/extensions.rb @@ -2,3 +2,4 @@ require 'active_relation/extensions/class' require 'active_relation/extensions/array' require 'active_relation/extensions/hash' +require 'active_relation/extensions/range' \ No newline at end of file diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index c07819d35f8b4..2af5832707c55 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -6,4 +6,8 @@ def to_hash def to_sql(formatter = nil) "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" end + + def predicate_sql + "IN" + end end \ No newline at end of file diff --git a/lib/active_relation/extensions/range.rb b/lib/active_relation/extensions/range.rb new file mode 100644 index 0000000000000..0218a0ab445a4 --- /dev/null +++ b/lib/active_relation/extensions/range.rb @@ -0,0 +1,9 @@ +class Range + def to_sql(formatter = nil) + formatter.range self.begin, self.end + end + + def predicate_sql + "BETWEEN" + end +end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 98a966507f52b..f68ec991c3f6d 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -76,18 +76,10 @@ def predicate_sql class Match < Binary alias_method :regexp, :operand2 - - def initialize(operand1, regexp) - @operand1, @regexp = operand1, regexp - end end - - class RelationInclusion < Binary - alias_method :relation, :operand2 - + + class In < Binary protected - def predicate_sql - 'IN' - end + delegate :predicate_sql, :to => :operand2 end end \ No newline at end of file diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 0ddbbb5cd4691..ddf5ef5e07b16 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -85,6 +85,10 @@ def gteq(other) def matches(regexp) Match.new(self, regexp) end + + def in(array) + In.new(self, array) + end end include Predications diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb index 131610f2e9c9e..aeee89dc3b827 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/active_relation/primitives/value.rb @@ -2,6 +2,8 @@ module ActiveRelation class Value attr_reader :value, :relation + delegate :predicate_sql, :to => :value + def initialize(value, relation) @value, @relation = value, relation end diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 8c93f948f724f..1364911f0ceda 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -37,10 +37,6 @@ def [](index) end end - def include?(attribute) - RelationInclusion.new(attribute, self) - end - def select(*predicates) Selection.new(self, *predicates.collect {|p| p.bind(self)}) end @@ -94,13 +90,16 @@ def group(*groupings) end include Operations - def aggregation? - false - end + module Externalizable + def aggregation? + false + end - def alias? - false + def alias? + false + end end + include Externalizable def to_sql(formatter = Sql::SelectStatement.new(engine)) formatter.select [ @@ -116,6 +115,10 @@ def to_sql(formatter = Sql::SelectStatement.new(engine)) end alias_method :to_s, :to_sql + def predicate_sql + "IN" + end + def call(connection = engine.connection) connection.select_all(to_sql) end diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 85dd591860a0a..027356d4d7be0 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -35,7 +35,11 @@ def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" end - def value(value, column = nil) + def value(value) + value.to_sql(self) + end + + def scalar(value, column = nil) quote(value, column) end @@ -61,10 +65,6 @@ def initialize(attribute) @attribute, @engine = attribute, attribute.engine end - def value(value) - value.to_sql(self) - end - def scalar(scalar) quote(scalar, @attribute.column) end @@ -72,6 +72,10 @@ def scalar(scalar) def array(array) "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" end + + def range(left, right) + "#{left} AND #{right}" + end end class Value < WhereCondition diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index b63472a836396..04f8d4f305abc 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -6,7 +6,6 @@ module ActiveRelation @relation = Table.new(:users) @attribute1 = @relation[:id] @attribute2 = @relation[:name] - @value = "1-asdf".bind(@relation) class ConcreteBinary < Binary def predicate_sql "<=>" @@ -24,6 +23,10 @@ def predicate_sql end describe 'when relating an attribute and a value' do + before do + @value = "1-asdf".bind(@relation) + end + describe 'when relating to an integer attribute' do it 'formats values as integers' do ConcreteBinary.new(@attribute1, @value).to_sql.should be_like(" @@ -43,49 +46,16 @@ def predicate_sql describe 'when relating two values' do before do + @value = "1-asdf".bind(@relation) @another_value = 2.bind(@relation) end - it 'quotes values appropriate to their type' do + it 'formats values appropos of their type' do ConcreteBinary.new(string = @value, integer = @another_value).to_sql.should be_like(" '1-asdf' <=> 2 ") end end - - describe 'when relating to an array' do - describe 'when the array\'s elements are the same type as the attribute' do - before do - @array = [1, 2, 3] - end - - it 'manufactures sql with a comma separated list' do - ConcreteBinary.new(@attribute1, @array.bind(@relation)).to_sql.should be_like(" - `users`.`id` <=> (1, 2, 3) - ") - end - end - - describe 'when the array\'s elements are not same type as the attribute' do - before do - @array = ['1-asdf', 2, 3] - end - - it 'formats values in the array as the type of the attribute' do - ConcreteBinary.new(@attribute1, @array.bind(@relation)).to_sql.should be_like(" - `users`.`id` <=> (1, 2, 3) - ") - end - end - end - - describe 'when relating to a relation' do - it 'manufactures sql with a subselect' do - ConcreteBinary.new(@attribute1, @relation).to_sql.should be_like(" - `users`.`id` <=> (SELECT `users`.`id`, `users`.`name` FROM `users`) - ") - end - end end describe '==' do @@ -94,7 +64,7 @@ def predicate_sql Binary.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute1) end - it "obtains if the concrete type of the Predicates::Binarys are identical" do + it "obtains if the concrete type of the predicates are identical" do Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) Binary.new(@attribute1, @attribute2).should_not == ConcreteBinary.new(@attribute1, @attribute2) end diff --git a/spec/active_relation/unit/predicates/in_spec.rb b/spec/active_relation/unit/predicates/in_spec.rb new file mode 100644 index 0000000000000..9e60c29ce042e --- /dev/null +++ b/spec/active_relation/unit/predicates/in_spec.rb @@ -0,0 +1,58 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module ActiveRelation + describe In do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#to_sql' do + describe 'when relating to an array' do + describe 'when the array\'s elements are the same type as the attribute' do + before do + @array = [1, 2, 3].bind(@relation) + end + + it 'manufactures sql with a comma separated list' do + In.new(@attribute, @array).to_sql.should be_like(" + `users`.`id` IN (1, 2, 3) + ") + end + end + + describe 'when the array\'s elements are not same type as the attribute' do + before do + @array = ['1-asdf', 2, 3].bind(@relation) + end + + it 'formats values in the array as the type of the attribute' do + In.new(@attribute, @array).to_sql.should be_like(" + `users`.`id` IN (1, 2, 3) + ") + end + end + end + + describe 'when relating to a range' do + before do + @range = (1..2).bind(@relation) + end + + it 'manufactures sql with a between' do + In.new(@attribute, @range).to_sql.should be_like(" + `users`.`id` BETWEEN 1 AND 2 + ") + end + end + + describe 'when relating to a relation' do + it 'manufactures sql with a subselect' do + In.new(@attribute, @relation).to_sql.should be_like(" + `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) + ") + end + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index a0f6cde8f7550..2806d26330e29 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -130,6 +130,12 @@ module ActiveRelation @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end + + describe '#in' do + it "manufactures an in predicate" do + @attribute.in(1..30).should == In.new(@attribute, 1..30) + end + end end describe Attribute::Expressions do diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index b5e204abcf3ce..d434a1e317e64 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -30,18 +30,20 @@ module ActiveRelation end end - describe '#include?' do - it "manufactures an inclusion predicate" do - @relation.include?(@attribute1).should be_kind_of(RelationInclusion) + describe Relation::Externalizable do + describe '#aggregation?' do + it "returns false" do + @relation.should_not be_aggregation + end end - end - - describe '#aggregation?' do - it "returns false" do - @relation.should_not be_aggregation + + describe '#alias?' do + it "returns false" do + @relation.should_not be_alias + end end end - + describe Relation::Operations do describe 'joins' do before do From 7bd0d634867ccbdf4537ba3d62b865b1cb7beebf Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 17:27:40 -0700 Subject: [PATCH 0098/1492] allowing string passthrough for order clauses --- TODO | 5 +-- lib/active_relation/primitives/attribute.rb | 14 +++--- lib/active_relation/relations/relation.rb | 12 ++--- lib/active_relation/sql.rb | 11 ++++- .../unit/primitives/attribute_spec.rb | 14 +++--- .../unit/relations/order_spec.rb | 42 ++++++++++++++--- .../unit/relations/selection_spec.rb | 45 ++++++++++++------- 7 files changed, 96 insertions(+), 47 deletions(-) diff --git a/TODO b/TODO index 4e7701917da20..c58a6d091ff54 100644 --- a/TODO +++ b/TODO @@ -11,9 +11,6 @@ todo: {:conditions=>{"topics.approved"=>false}} {:conditions=>{:address=>#, "customers.name"=>"David1"}} -- need to_sql for ranges - {:conditions=>{:id=>2..3}} - - orders need string pass through :order=>"developers.name desc, developers.id desc", @@ -69,3 +66,5 @@ done: - #formatter is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a formatter (Sql::Relation) ... should it be called predicate formatter? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - renamed to #format: operand1.format(operand2) - rename sql strategies +- need to_sql for ranges + - {:conditions=>{:id=>2..3}} \ No newline at end of file diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index ddf5ef5e07b16..d78e940ffc541 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -63,31 +63,31 @@ def =~(other) module Predications def eq(other) - Equality.new(self, other) + Equality.new(self, other.bind(relation)) end def lt(other) - LessThan.new(self, other) + LessThan.new(self, other.bind(relation)) end def lteq(other) - LessThanOrEqualTo.new(self, other) + LessThanOrEqualTo.new(self, other.bind(relation)) end def gt(other) - GreaterThan.new(self, other) + GreaterThan.new(self, other.bind(relation)) end def gteq(other) - GreaterThanOrEqualTo.new(self, other) + GreaterThanOrEqualTo.new(self, other.bind(relation)) end def matches(regexp) - Match.new(self, regexp) + Match.new(self, regexp.bind(relation)) end def in(array) - In.new(self, array) + In.new(self, array.bind(relation)) end end include Predications diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 1364911f0ceda..fa66bd039bfe3 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -105,12 +105,12 @@ def to_sql(formatter = Sql::SelectStatement.new(engine)) formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}", "FROM #{table_sql}", - (joins unless joins.blank? ), - ("WHERE #{selects.collect {|s| s.to_sql(Sql::WhereClause.new(engine))}.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect(&:to_sql)}" unless orders.blank? ), - ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), - ("LIMIT #{limit}" unless limit.blank? ), - ("OFFSET #{offset}" unless offset.blank? ) + (joins unless joins.blank? ), + ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(engine)) }.join(', ')}" unless orders.blank? ), + ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), + ("LIMIT #{limit}" unless limit.blank? ), + ("OFFSET #{offset}" unless offset.blank? ) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 027356d4d7be0..3a773fdf6e8b2 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -24,12 +24,21 @@ def select(select_sql, aliaz) end end - class WhereClause < Formatter + class PassThrough < Formatter def value(value) value end end + class WhereClause < PassThrough + end + + class OrderClause < PassThrough + def attribute(relation_name, attribute_name, aliaz) + "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + end + end + class WhereCondition < Formatter def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index 2806d26330e29..0f6e5e289d754 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -97,43 +97,43 @@ module ActiveRelation describe '#eq' do it "manufactures an equality predicate" do - @attribute.eq('name').should == Equality.new(@attribute, 'name') + @attribute.eq('name').should == Equality.new(@attribute, 'name'.bind(@relation)) end end describe '#lt' do it "manufactures a less-than predicate" do - @attribute.lt(10).should == LessThan.new(@attribute, 10) + @attribute.lt(10).should == LessThan.new(@attribute, 10.bind(@relation)) end end describe '#lteq' do it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) + @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10.bind(@relation)) end end describe '#gt' do it "manufactures a greater-than predicate" do - @attribute.gt(10).should == GreaterThan.new(@attribute, 10) + @attribute.gt(10).should == GreaterThan.new(@attribute, 10.bind(@relation)) end end describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) + @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10.bind(@relation)) end end describe '#matches' do it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) + @attribute.matches(/.*/).should == Match.new(@attribute, /.*/.bind(@relation)) end end describe '#in' do it "manufactures an in predicate" do - @attribute.in(1..30).should == In.new(@attribute, 1..30) + @attribute.in(1..30).should == In.new(@attribute, (1..30).bind(@relation)) end end end diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb index 6a9ce07024ef0..f37a9f26e99ab 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -22,12 +22,42 @@ module ActiveRelation end describe '#to_sql' do - it "manufactures sql with an order clause" do - Order.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` - ") + describe "when given an attribute" do + it "manufactures sql with an order clause populated by the attribute" do + Order.new(@relation, @attribute).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id` + ") + end + end + + describe "when given multiple attributes" do + before do + @another_attribute = @relation[:name] + end + + it "manufactures sql with an order clause populated by comma-separated attributes" do + Order.new(@relation, @attribute, @another_attribute).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id`, `users`.`name` + ") + end + end + + describe "when given a string" do + before do + @string = "asdf".bind(@relation) + end + + it "passes the string through to the order clause" do + Order.new(@relation, @string).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY asdf + ") + end end end end diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index 4bb3817bf5756..001c38c370898 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -4,14 +4,17 @@ module ActiveRelation describe Selection do before do @relation = Table.new(:users) - @predicate = Equality.new(@relation[:id], 1.bind(@relation)) + @predicate = @relation[:id].eq(1) end describe '#initialize' do + before do + @another_predicate = @relation[:name].lt(2) + end + it "manufactures nested selection relations if multiple predicates are provided" do - @predicate2 = LessThan.new(@relation[:age], 2.bind(@relation)) - Selection.new(@relation, @predicate, @predicate2). \ - should == Selection.new(Selection.new(@relation, @predicate2), @predicate) + Selection.new(@relation, @predicate, @another_predicate). \ + should == Selection.new(Selection.new(@relation, @another_predicate), @predicate) end end @@ -30,20 +33,28 @@ module ActiveRelation end describe '#to_sql' do - it "manufactures sql with where clause conditions" do - Selection.new(@relation, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE `users`.`id` = 1 - ") + describe 'when given a predicate' do + it "manufactures sql with where clause conditions" do + Selection.new(@relation, @predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE `users`.`id` = 1 + ") + end end - - it "allows arbitrary sql" do - Selection.new(@relation, "asdf".bind(@relation)).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE asdf - ") + + describe 'when given a string' do + before do + @string = "asdf".bind(@relation) + end + + it "passes the string through to the where clause" do + Selection.new(@relation, @string).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE asdf + ") + end end end end From 2d3681bb3c9ed8136fc46857828b74ae39b6d990 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 17:35:11 -0700 Subject: [PATCH 0099/1492] nested orderings --- lib/active_relation/predicates.rb | 6 ----- lib/active_relation/relations/join.rb | 5 ++-- lib/active_relation/relations/order.rb | 9 +++++-- lib/active_relation/relations/selection.rb | 3 +-- lib/active_relation/relations/table.rb | 1 - .../unit/relations/order_spec.rb | 26 +++++++++++++++++++ 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index f68ec991c3f6d..6fcef3cfd6cc0 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -40,35 +40,30 @@ def ==(other) (operand1 == other.operand2 and operand2 == other.operand1)) end - protected def predicate_sql '=' end end class GreaterThanOrEqualTo < Binary - protected def predicate_sql '>=' end end class GreaterThan < Binary - protected def predicate_sql '>' end end class LessThanOrEqualTo < Binary - protected def predicate_sql '<=' end end class LessThan < Binary - protected def predicate_sql '<' end @@ -79,7 +74,6 @@ class Match < Binary end class In < Binary - protected delegate :predicate_sql, :to => :operand2 end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index 835e965f72b5b..ab5f440d9e43f 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -36,7 +36,6 @@ def descend(&block) Join.new(join_sql, relation1.descend(&block), relation2.descend(&block), *predicates.collect(&block)) end - protected def joins this_join = [ join_sql, @@ -64,11 +63,11 @@ def externalize(relation) delegate :engine, :to => :relation def table_sql - relation.aggregation?? relation.to_sql(Sql::TableReference.new(engine)) : relation.send(:table_sql) + relation.aggregation?? relation.to_sql(Sql::TableReference.new(engine)) : relation.table_sql end def selects - relation.aggregation?? [] : relation.send(:selects) + relation.aggregation?? [] : relation.selects end def attributes diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index 6949b3acf7b7f..bfd05f48b3e2d 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -1,9 +1,10 @@ module ActiveRelation class Order < Compound - attr_reader :orders + attr_reader :order def initialize(relation, *orders) - @relation, @orders = relation, orders + @order = orders.pop + @relation = orders.empty?? relation : Order.new(relation, *orders) end def ==(other) @@ -15,5 +16,9 @@ def ==(other) def descend(&block) Order.new(relation.descend(&block), *orders.collect(&block)) end + + def orders + relation.orders + [order] + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index e7a91f757245a..fe28908cc235e 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -17,9 +17,8 @@ def descend(&block) Selection.new(relation.descend(&block), yield(predicate)) end - protected def selects - relation.send(:selects) + [predicate] + relation.selects + [predicate] end end end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 4682298608bcc..72682bee55183 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -44,7 +44,6 @@ def reset @attributes = @columns = nil end - protected def table_sql "#{engine.quote_table_name(name)}" end diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb index f37a9f26e99ab..e4f925f21a6dc 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -7,6 +7,17 @@ module ActiveRelation @attribute = @relation[:id] end + describe '#initialize' do + before do + @another_attribtue = @relation[:name] + end + + it "manufactures nested Order relations if multiple predicates are provided" do + Order.new(@relation, @predicate, @another_attribute). \ + should == Order.new(Order.new(@relation, @another_attribute), @predicate) + end + end + describe '#qualify' do it "descends" do Order.new(@relation, @attribute).qualify. \ @@ -59,6 +70,21 @@ module ActiveRelation ") end end + + describe "when ordering an ordered relation" do + before do + @ordered_relation = Order.new(@relation, @attribute) + @another_attribute = @relation[:name] + end + + it "manufactures sql with an order clause populated by comma-separated attributes" do + Order.new(@ordered_relation, @another_attribute).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id`, `users`.`name` + ") + end + end end end end From cae95fc02af1fff885dca4a29b2fd3711b809cab Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 17:49:06 -0700 Subject: [PATCH 0100/1492] projections now support string passthrough - there is a weird inconsistency in where bind is called on values; this needs to be resolved --- CONVENTIONS | 17 +++++++++ TODO | 18 ++++----- lib/active_relation/relations/relation.rb | 4 +- lib/active_relation/sql.rb | 6 ++- .../unit/relations/projection_spec.rb | 38 ++++++++++++++----- 5 files changed, 61 insertions(+), 22 deletions(-) create mode 100644 CONVENTIONS diff --git a/CONVENTIONS b/CONVENTIONS new file mode 100644 index 0000000000000..0d7c1b4ef0ebe --- /dev/null +++ b/CONVENTIONS @@ -0,0 +1,17 @@ +This file should ultimately be replaced by a series of tests, something like a lint tool. + +- all describes and its should use single quotes unless they have nested quotes. +- object instantiation in tests for all objects that are not the SUT should be manufactured in a before +- 'should' and other counterfactuals/subjunctive forms should not be used in tests +- no doubles should be used except for behaviorist testing + - behaviorist testing is desirable only when interacting with the database or the session +- when unit testing, always demonstrate behavior by using a real world example (as in, a public use of the API), so as to provide documentation. +- use collect rather than map +- jargon: + - 'obtains' is preferred to 'returns true' + - 'manufactures' +- in tests + - when manufacturing expected values (right-hand-side of should), avoid convenience methods -- construct it by initializing the object directly (Foo.new(...)). This ensures equality expectations in tests is rigorous. + - the SUT should be manufactured inline inside the test, not in a before + - dependencies for the SUT should be manufactured using convenience methods (or whatever is most terse). +- group conceptually related methods in a class within an inline module; immediately include that module. \ No newline at end of file diff --git a/TODO b/TODO index c58a6d091ff54..8b60e671a16d9 100644 --- a/TODO +++ b/TODO @@ -1,34 +1,26 @@ todo: - string passthrough: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" - :conditions=>"(`posts`.author_id = 1)", :select=>"`comments`.*" - :conditions=>"1 = 1" - need adapters for this form: {:conditions=>["approved = ?", false]} {:conditions=>{:approved=>false}} {:conditions=>{"topics.approved"=>false}} {:conditions=>{:address=>#, "customers.name"=>"David1"}} - -- orders need string pass through - :order=>"developers.name desc, developers.id desc", -- orders need to be composable +- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? - #bind in Attribute and Expression should be doing a descend? - try to make aggration testing in join spec to be a bit more unit-like - finish pending tests - test relation, table reset - cache expiry on write - rewrite of querycache test in light of this -- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute - - descend on array, along with bind written in terms of it - standardize quoting - use strings everywhere, not symbols ? - "unit" test sql strategies - use real world examples, so they should be like a tutorial. - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent -- re-evaluate bind - mock out database done: @@ -67,4 +59,10 @@ done: - renamed to #format: operand1.format(operand2) - rename sql strategies - need to_sql for ranges - - {:conditions=>{:id=>2..3}} \ No newline at end of file + - {:conditions=>{:id=>2..3}} +- nested orderings +- string passthrough + - conditions + - orderings +- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute + - descend on array, along with bind written in terms of it diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index fa66bd039bfe3..88d1bce4a8744 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -42,7 +42,7 @@ def select(*predicates) end def project(*attributes) - Projection.new(self, *attributes.collect {|a| a.bind(self)}) + Projection.new(self, *attributes) end def as(aliaz) @@ -103,7 +103,7 @@ def alias? def to_sql(formatter = Sql::SelectStatement.new(engine)) formatter.select [ - "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectExpression.new(engine)) }.join(', ')}", + "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(engine)) }.join(', ')}", "FROM #{table_sql}", (joins unless joins.blank? ), ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), diff --git a/lib/active_relation/sql.rb b/lib/active_relation/sql.rb index 3a773fdf6e8b2..0b9b0fc18bc6f 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -14,7 +14,7 @@ def initialize(engine) end end - class SelectExpression < Formatter + class SelectClause < Formatter def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") end @@ -22,6 +22,10 @@ def attribute(relation_name, attribute_name, aliaz) def select(select_sql, aliaz) "(#{select_sql})" + (aliaz ? " AS #{quote(aliaz)}" : "") end + + def value(value) + value + end end class PassThrough < Formatter diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index 78766d330804b..f58564840bf82 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -45,17 +45,37 @@ module ActiveRelation end describe '#to_sql' do - it "manufactures sql with a limited select clause" do - Projection.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id` - FROM `users` - ") + describe 'when given an attribute' do + it "manufactures sql with a limited select clause" do + Projection.new(@relation, @attribute).to_sql.should be_like(" + SELECT `users`.`id` + FROM `users` + ") + end end - it "manufactures sql with value selects" do - Projection.new(@relation, Projection.new(@relation, @relation[:name])).to_sql.should be_like(" - SELECT (SELECT `users`.`name` FROM `users`) FROM `users` - ") + describe 'when given a relation' do + before do + @scalar_relation = Projection.new(@relation, @relation[:name]) + end + + it "manufactures sql with scalar selects" do + Projection.new(@relation, @scalar_relation).to_sql.should be_like(" + SELECT (SELECT `users`.`name` FROM `users`) FROM `users` + ") + end + end + + describe 'when given a string' do + before do + @string = "asdf" + end + + it "passes the string through to the select clause" do + Projection.new(@relation, @string).to_sql.should be_like(" + SELECT asdf FROM `users` + ") + end end end end From 9771b2f3a3fdb45517a132228a1129718acd2fac Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 18:32:57 -0700 Subject: [PATCH 0101/1492] test organization --- spec/active_relation/unit/relations/join_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 515c9ce0f20a8..30ac73b611b72 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -77,12 +77,12 @@ module ActiveRelation end end - describe 'with simple relations' do + describe 'when joining simple relations' do describe '#attributes' do it 'combines the attributes of the two relations' do - simple_join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) - simple_join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(simple_join) } + join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) + join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } end end From 89b354bf97d0a981376d36f2f8a7ba6a87fe2aa8 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 16 Mar 2008 20:47:02 -0700 Subject: [PATCH 0102/1492] added attribute.eq(nil) - produces attribute IS NULL --- TODO | 4 +-- lib/active_relation/extensions.rb | 3 ++- lib/active_relation/extensions/array.rb | 2 +- lib/active_relation/extensions/nil_class.rb | 5 ++++ lib/active_relation/extensions/object.rb | 4 +++ lib/active_relation/extensions/range.rb | 2 +- lib/active_relation/predicates.rb | 6 +++-- lib/active_relation/primitives/value.rb | 2 +- lib/active_relation/relations/relation.rb | 2 +- .../unit/predicates/equality_spec.rb | 26 +++++++++++++++++-- 10 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 lib/active_relation/extensions/nil_class.rb diff --git a/TODO b/TODO index 8b60e671a16d9..d7b57da4e2428 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,8 @@ todo: - string passthrough: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" - :select=>"`comments`.*" - + - shit this one is hard at the moment. + - need adapters for this form: {:conditions=>["approved = ?", false]} {:conditions=>{:approved=>false}} diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb index 21d67240046b5..ded830eb8c588 100644 --- a/lib/active_relation/extensions.rb +++ b/lib/active_relation/extensions.rb @@ -2,4 +2,5 @@ require 'active_relation/extensions/class' require 'active_relation/extensions/array' require 'active_relation/extensions/hash' -require 'active_relation/extensions/range' \ No newline at end of file +require 'active_relation/extensions/range' +require 'active_relation/extensions/nil_class' \ No newline at end of file diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index 2af5832707c55..793c06aad8d7c 100644 --- a/lib/active_relation/extensions/array.rb +++ b/lib/active_relation/extensions/array.rb @@ -7,7 +7,7 @@ def to_sql(formatter = nil) "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" end - def predicate_sql + def inclusion_predicate_sql "IN" end end \ No newline at end of file diff --git a/lib/active_relation/extensions/nil_class.rb b/lib/active_relation/extensions/nil_class.rb new file mode 100644 index 0000000000000..729c4cada7b5e --- /dev/null +++ b/lib/active_relation/extensions/nil_class.rb @@ -0,0 +1,5 @@ +class NilClass + def equality_predicate_sql + 'IS' + end +end \ No newline at end of file diff --git a/lib/active_relation/extensions/object.rb b/lib/active_relation/extensions/object.rb index cd51543c910ce..25cef989a4ee1 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -7,6 +7,10 @@ def to_sql(formatter = nil) formatter.scalar self end + def equality_predicate_sql + '=' + end + def metaclass class << self self diff --git a/lib/active_relation/extensions/range.rb b/lib/active_relation/extensions/range.rb index 0218a0ab445a4..d7329efe344a2 100644 --- a/lib/active_relation/extensions/range.rb +++ b/lib/active_relation/extensions/range.rb @@ -3,7 +3,7 @@ def to_sql(formatter = nil) formatter.range self.begin, self.end end - def predicate_sql + def inclusion_predicate_sql "BETWEEN" end end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 6fcef3cfd6cc0..22fbcd9f0bcfd 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -41,7 +41,7 @@ def ==(other) end def predicate_sql - '=' + operand2.equality_predicate_sql end end @@ -74,6 +74,8 @@ class Match < Binary end class In < Binary - delegate :predicate_sql, :to => :operand2 + def predicate_sql + operand2.inclusion_predicate_sql + end end end \ No newline at end of file diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb index aeee89dc3b827..6f251d442b57a 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/active_relation/primitives/value.rb @@ -2,7 +2,7 @@ module ActiveRelation class Value attr_reader :value, :relation - delegate :predicate_sql, :to => :value + delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value def initialize(value, relation) @value, @relation = value, relation diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 88d1bce4a8744..db61fce3def25 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -115,7 +115,7 @@ def to_sql(formatter = Sql::SelectStatement.new(engine)) end alias_method :to_s, :to_sql - def predicate_sql + def inclusion_predicate_sql "IN" end diff --git a/spec/active_relation/unit/predicates/equality_spec.rb b/spec/active_relation/unit/predicates/equality_spec.rb index 499b13383d9ba..613236ad042c6 100644 --- a/spec/active_relation/unit/predicates/equality_spec.rb +++ b/spec/active_relation/unit/predicates/equality_spec.rb @@ -5,8 +5,8 @@ module ActiveRelation before do @relation1 = Table.new(:users) @relation2 = Table.new(:photos) - @attribute1 = @relation1[:name] - @attribute2 = @relation2[:name] + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] end describe '==' do @@ -23,5 +23,27 @@ module ActiveRelation Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) end end + + describe '#to_sql' do + describe 'when relating to a non-nil value' do + it "manufactures an equality predicate" do + Equality.new(@attribute1, @attribute2).to_sql.should be_like(" + `users`.`id` = `photos`.`user_id` + ") + end + end + + describe 'when relation to a nil value' do + before do + @nil = nil.bind(@relation1) + end + + it "manufactures an is null predicate" do + Equality.new(@attribute1, @nil).to_sql.should be_like(" + `users`.`id` IS NULL + ") + end + end + end end end \ No newline at end of file From 42c42bfa50876b4221c024cebc47fc34fc6530a9 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 13:47:06 -0700 Subject: [PATCH 0103/1492] moved bind to factory of select --- Rakefile | 1 - CONVENTIONS => doc/CONVENTIONS | 0 TODO => doc/TODO | 23 ++++++++++--------- lib/active_relation/predicates.rb | 20 ++++------------ lib/active_relation/relations/relation.rb | 2 +- lib/active_relation/relations/selection.rb | 3 ++- .../unit/relations/relation_spec.rb | 2 +- .../unit/relations/selection_spec.rb | 10 +++++--- 8 files changed, 28 insertions(+), 33 deletions(-) rename CONVENTIONS => doc/CONVENTIONS (100%) rename TODO => doc/TODO (96%) diff --git a/Rakefile b/Rakefile index e45ade4f7df70..b1fc74a13c6fe 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,4 @@ require 'rubygems' -require 'spec' require 'spec/rake/spectask' Spec::Rake::SpecTask.new do |t| diff --git a/CONVENTIONS b/doc/CONVENTIONS similarity index 100% rename from CONVENTIONS rename to doc/CONVENTIONS diff --git a/TODO b/doc/TODO similarity index 96% rename from TODO rename to doc/TODO index d7b57da4e2428..6d6b82082a04d 100644 --- a/TODO +++ b/doc/TODO @@ -1,27 +1,28 @@ todo: +- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? +- - mock out database +- #bind in Attribute and Expression should be doing a descend? +- try to make aggegration testing in join spec to be a bit more unit-like +- finish pending tests +- test relation, table reset +- standardize quoting + - use strings everywhere, not symbols ? +- "unit" test sql strategies + - use real world examples, so they should be like a tutorial. + - string passthrough: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" - shit this one is hard at the moment. - + - need adapters for this form: {:conditions=>["approved = ?", false]} {:conditions=>{:approved=>false}} {:conditions=>{"topics.approved"=>false}} {:conditions=>{:address=>#, "customers.name"=>"David1"}} -- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? -- #bind in Attribute and Expression should be doing a descend? -- try to make aggration testing in join spec to be a bit more unit-like -- finish pending tests -- test relation, table reset - cache expiry on write - rewrite of querycache test in light of this -- standardize quoting - - use strings everywhere, not symbols ? -- "unit" test sql strategies - - use real world examples, so they should be like a tutorial. - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent -- mock out database done: . Relation <=> Relation -> InnerJoinOperation diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index 22fbcd9f0bcfd..e17a9f82fe40e 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -46,27 +46,19 @@ def predicate_sql end class GreaterThanOrEqualTo < Binary - def predicate_sql - '>=' - end + def predicate_sql; '>=' end end class GreaterThan < Binary - def predicate_sql - '>' - end + def predicate_sql; '>' end end class LessThanOrEqualTo < Binary - def predicate_sql - '<=' - end + def predicate_sql; '<=' end end class LessThan < Binary - def predicate_sql - '<' - end + def predicate_sql; '<' end end class Match < Binary @@ -74,8 +66,6 @@ class Match < Binary end class In < Binary - def predicate_sql - operand2.inclusion_predicate_sql - end + def predicate_sql; operand2.inclusion_predicate_sql end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index db61fce3def25..f7e47c2e50611 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -38,7 +38,7 @@ def [](index) end def select(*predicates) - Selection.new(self, *predicates.collect {|p| p.bind(self)}) + Selection.new(self, *predicates) end def project(*attributes) diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index fe28908cc235e..032de63d043a0 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -3,8 +3,9 @@ class Selection < Compound attr_reader :predicate def initialize(relation, *predicates) - @predicate = predicates.shift + predicate = predicates.shift @relation = predicates.empty?? relation : Selection.new(relation, *predicates) + @predicate = predicate.bind(@relation) end def ==(other) diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index d434a1e317e64..7bb85d7270289 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -91,7 +91,7 @@ module ActiveRelation end it "accepts arbitrary strings" do - @relation.select("arbitrary").should == Selection.new(@relation, Value.new("arbitrary", @relation)) + @relation.select("arbitrary").should == Selection.new(@relation, "arbitrary") end end diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index 001c38c370898..1919d3007eafc 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -26,9 +26,13 @@ module ActiveRelation end describe '#descend' do + before do + @selection = Selection.new(@relation, @predicate) + end + it "distributes a block over the relation and predicates" do - Selection.new(@relation, @predicate).descend(&:qualify). \ - should == Selection.new(@relation.descend(&:qualify), @predicate.descend(&:qualify)) + @selection.descend(&:qualify). \ + should == Selection.new(@selection.relation.descend(&:qualify), @selection.predicate.qualify) end end @@ -45,7 +49,7 @@ module ActiveRelation describe 'when given a string' do before do - @string = "asdf".bind(@relation) + @string = "asdf" end it "passes the string through to the where clause" do From e6f6fbc5c7bd12ac0c122cdfdfc448329919e603 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 13:48:18 -0700 Subject: [PATCH 0104/1492] refactored bind for order --- lib/active_relation/relations/order.rb | 3 ++- lib/active_relation/relations/relation.rb | 2 +- spec/active_relation/unit/relations/order_spec.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index bfd05f48b3e2d..95b73c5e908f0 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -3,8 +3,9 @@ class Order < Compound attr_reader :order def initialize(relation, *orders) - @order = orders.pop + order = orders.pop @relation = orders.empty?? relation : Order.new(relation, *orders) + @order = order.bind(@relation) end def ==(other) diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index f7e47c2e50611..36c13bec51355 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -50,7 +50,7 @@ def as(aliaz) end def order(*attributes) - Order.new(self, *attributes.collect {|a| a.bind(self)}) + Order.new(self, *attributes) end def rename(attribute, aliaz) diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb index e4f925f21a6dc..db322fe00b790 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -59,7 +59,7 @@ module ActiveRelation describe "when given a string" do before do - @string = "asdf".bind(@relation) + @string = "asdf" end it "passes the string through to the order clause" do From 8887dcce12cd80f673e28537800e7657be9969d8 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 13:55:17 -0700 Subject: [PATCH 0105/1492] removed bind for insertion and updation --- lib/active_relation/relations/insertion.rb | 2 +- lib/active_relation/relations/relation.rb | 4 ++-- lib/active_relation/relations/update.rb | 2 +- spec/active_relation/unit/relations/insertion_spec.rb | 8 ++++---- spec/active_relation/unit/relations/relation_spec.rb | 4 ++-- spec/active_relation/unit/relations/update_spec.rb | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 901ff6eb70688..30de6819f1c70 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -3,7 +3,7 @@ class Insertion < Writing attr_reader :record def initialize(relation, record) - @relation, @record = relation, record + @relation, @record = relation, record.bind(relation) end def to_sql(formatter = nil) diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 36c13bec51355..eebfd48e300fb 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -63,11 +63,11 @@ def aggregate(*expressions) module Writes def insert(record) - session.create Insertion.new(self, record.bind(self)); self + session.create Insertion.new(self, record); self end def update(assignments) - session.update Update.new(self, assignments.bind(self)); self + session.update Update.new(self, assignments); self end def delete diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index 7eb78d5473c75..46aafd38a5521 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -3,7 +3,7 @@ class Update < Writing attr_reader :assignments def initialize(relation, assignments) - @relation, @assignments = relation, assignments + @relation, @assignments = relation, assignments.bind(relation) end def to_sql(formatter = nil) diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index b74ec6c7cb908..e01e7792e2df3 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -9,7 +9,7 @@ module ActiveRelation describe '#to_sql' do describe 'when given values whose types correspond to the types of the attributes' do before do - @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) + @insertion = Insertion.new(@relation, @relation[:name] => "nick") end it 'manufactures sql inserting data' do @@ -23,7 +23,7 @@ module ActiveRelation describe 'when given values whose types differ from from the types of the attributes' do before do - @insertion = Insertion.new(@relation, @relation[:id] => '1-asdf'.bind(@relation)) + @insertion = Insertion.new(@relation, @relation[:id] => '1-asdf') end it 'manufactures sql inserting data' do @@ -37,7 +37,7 @@ module ActiveRelation describe 'when given values whose types correspond to the type of the attribtues' do before do - @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) + @insertion = Insertion.new(@relation, @relation[:name] => "nick") end it 'manufactures sql inserting data' do @@ -52,7 +52,7 @@ module ActiveRelation describe '#call' do before do - @insertion = Insertion.new(@relation, @relation[:name] => "nick".bind(@relation)) + @insertion = Insertion.new(@relation, @relation[:name] => "nick") end it 'executes an insert on the connection' do diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 7bb85d7270289..682ec88f10ece 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -138,7 +138,7 @@ module ActiveRelation it 'manufactures an insertion relation' do Session.start do record = {@relation[:name] => 'carl'} - mock(Session.new).create(Insertion.new(@relation, record.bind(@relation))) + mock(Session.new).create(Insertion.new(@relation, record)) @relation.insert(record).should == @relation end end @@ -148,7 +148,7 @@ module ActiveRelation it 'manufactures an update relation' do Session.start do assignments = {@relation[:name] => Value.new('bob', @relation)} - mock(Session.new).update(Update.new(@relation, assignments.bind(@relation))) + mock(Session.new).update(Update.new(@relation, assignments)) @relation.update(assignments).should == @relation end end diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 9053f292d654d..5c234fe7595ec 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -9,7 +9,7 @@ module ActiveRelation describe '#to_sql' do describe 'when given values whose types correspond to the types of the attributes' do before do - @update = Update.new(@relation, @relation[:name] => "nick".bind(@relation)) + @update = Update.new(@relation, @relation[:name] => "nick") end it 'manufactures sql updating attributes' do @@ -22,7 +22,7 @@ module ActiveRelation describe 'when given values whose types differ from from the types of the attributes' do before do - @update = Update.new(@relation, @relation[:id] => '1-asdf'.bind(@relation)) + @update = Update.new(@relation, @relation[:id] => '1-asdf') end it 'manufactures sql updating attributes' do @@ -37,7 +37,7 @@ module ActiveRelation before do @update = Update.new( @relation.select(@relation[:id].eq(1)), - @relation[:name] => "nick".bind(@relation) + @relation[:name] => "nick" ) end @@ -53,7 +53,7 @@ module ActiveRelation describe '#call' do before do - @update = Update.new(@relation, @relation[:name] => "nick".bind(@relation)) + @update = Update.new(@relation, @relation[:name] => "nick") end it 'executes an update on the connection' do From 89eff9708d9519f8a2724427d9ed9a3bcbc6d125 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 14:40:33 -0700 Subject: [PATCH 0106/1492] removed binding for attributes and predicates --- lib/active_relation/predicates.rb | 2 +- lib/active_relation/primitives/attribute.rb | 14 +++++++------- .../unit/predicates/binary_spec.rb | 15 +-------------- .../unit/predicates/equality_spec.rb | 2 +- .../unit/primitives/attribute_spec.rb | 16 ++++++++-------- spec/spec_helper.rb | 2 +- 6 files changed, 19 insertions(+), 32 deletions(-) diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index e17a9f82fe40e..dc4610b052d48 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -25,7 +25,7 @@ def qualify end def to_sql(formatter = nil) - "#{operand2.format(operand1)} #{predicate_sql} #{operand1.format(operand2)}" + "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end def descend diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index d78e940ffc541..ddf5ef5e07b16 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -63,31 +63,31 @@ def =~(other) module Predications def eq(other) - Equality.new(self, other.bind(relation)) + Equality.new(self, other) end def lt(other) - LessThan.new(self, other.bind(relation)) + LessThan.new(self, other) end def lteq(other) - LessThanOrEqualTo.new(self, other.bind(relation)) + LessThanOrEqualTo.new(self, other) end def gt(other) - GreaterThan.new(self, other.bind(relation)) + GreaterThan.new(self, other) end def gteq(other) - GreaterThanOrEqualTo.new(self, other.bind(relation)) + GreaterThanOrEqualTo.new(self, other) end def matches(regexp) - Match.new(self, regexp.bind(relation)) + Match.new(self, regexp) end def in(array) - In.new(self, array.bind(relation)) + In.new(self, array) end end include Predications diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 04f8d4f305abc..5dd5e5599adec 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -24,7 +24,7 @@ def predicate_sql describe 'when relating an attribute and a value' do before do - @value = "1-asdf".bind(@relation) + @value = "1-asdf" end describe 'when relating to an integer attribute' do @@ -43,19 +43,6 @@ def predicate_sql end end end - - describe 'when relating two values' do - before do - @value = "1-asdf".bind(@relation) - @another_value = 2.bind(@relation) - end - - it 'formats values appropos of their type' do - ConcreteBinary.new(string = @value, integer = @another_value).to_sql.should be_like(" - '1-asdf' <=> 2 - ") - end - end end describe '==' do diff --git a/spec/active_relation/unit/predicates/equality_spec.rb b/spec/active_relation/unit/predicates/equality_spec.rb index 613236ad042c6..5415b35925b2f 100644 --- a/spec/active_relation/unit/predicates/equality_spec.rb +++ b/spec/active_relation/unit/predicates/equality_spec.rb @@ -35,7 +35,7 @@ module ActiveRelation describe 'when relation to a nil value' do before do - @nil = nil.bind(@relation1) + @nil = nil end it "manufactures an is null predicate" do diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index 0f6e5e289d754..fbbcbaef370e6 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -21,7 +21,7 @@ module ActiveRelation end it "returns self if the substituting to the same relation" do - @attribute.bind(@relation).should == @attribute + @attribute.should == @attribute end end @@ -97,43 +97,43 @@ module ActiveRelation describe '#eq' do it "manufactures an equality predicate" do - @attribute.eq('name').should == Equality.new(@attribute, 'name'.bind(@relation)) + @attribute.eq('name').should == Equality.new(@attribute, 'name') end end describe '#lt' do it "manufactures a less-than predicate" do - @attribute.lt(10).should == LessThan.new(@attribute, 10.bind(@relation)) + @attribute.lt(10).should == LessThan.new(@attribute, 10) end end describe '#lteq' do it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10.bind(@relation)) + @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) end end describe '#gt' do it "manufactures a greater-than predicate" do - @attribute.gt(10).should == GreaterThan.new(@attribute, 10.bind(@relation)) + @attribute.gt(10).should == GreaterThan.new(@attribute, 10) end end describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10.bind(@relation)) + @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end describe '#matches' do it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Match.new(@attribute, /.*/.bind(@relation)) + @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end describe '#in' do it "manufactures an in predicate" do - @attribute.in(1..30).should == In.new(@attribute, (1..30).bind(@relation)) + @attribute.in(1..30).should == In.new(@attribute, (1..30)) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 01a703a7d4d84..4b61ae8ca8b07 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,7 +19,7 @@ class Hash def shift - returning to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash }.shift do |key, value| + returning to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash }.shift do |key, _| delete(key) end end From ad50e772d32c261e4463d67d5c50a25b21a36370 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 14:56:59 -0700 Subject: [PATCH 0107/1492] removed spurious calls to bind --- spec/active_relation/unit/predicates/in_spec.rb | 6 +++--- spec/active_relation/unit/session/session_spec.rb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/active_relation/unit/predicates/in_spec.rb b/spec/active_relation/unit/predicates/in_spec.rb index 9e60c29ce042e..4ca7867dd0c4a 100644 --- a/spec/active_relation/unit/predicates/in_spec.rb +++ b/spec/active_relation/unit/predicates/in_spec.rb @@ -11,7 +11,7 @@ module ActiveRelation describe 'when relating to an array' do describe 'when the array\'s elements are the same type as the attribute' do before do - @array = [1, 2, 3].bind(@relation) + @array = [1, 2, 3] end it 'manufactures sql with a comma separated list' do @@ -23,7 +23,7 @@ module ActiveRelation describe 'when the array\'s elements are not same type as the attribute' do before do - @array = ['1-asdf', 2, 3].bind(@relation) + @array = ['1-asdf', 2, 3] end it 'formats values in the array as the type of the attribute' do @@ -36,7 +36,7 @@ module ActiveRelation describe 'when relating to a range' do before do - @range = (1..2).bind(@relation) + @range = 1..2 end it 'manufactures sql with a between' do diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/active_relation/unit/session/session_spec.rb index 9fba6cc6b23bf..5c3b668e1fb7d 100644 --- a/spec/active_relation/unit/session/session_spec.rb +++ b/spec/active_relation/unit/session/session_spec.rb @@ -32,8 +32,8 @@ module ActiveRelation describe Session::CRUD do before do - @insert = Insertion.new(@relation, @relation[:name] => 'nick'.bind(@relation)) - @update = Update.new(@relation, @relation[:name] => 'nick'.bind(@relation)) + @insert = Insertion.new(@relation, @relation[:name] => 'nick') + @update = Update.new(@relation, @relation[:name] => 'nick') @delete = Deletion.new(@relation) @read = @relation end From eee3a766160cd32a4d9b5e1352858597005c9cee Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 15:22:22 -0700 Subject: [PATCH 0108/1492] string passthrough for joins --- .gitignore | 3 ++- doc/TODO | 16 ++++++---------- lib/active_relation/primitives/attribute.rb | 2 +- lib/active_relation/relations.rb | 1 + lib/active_relation/relations/join.rb | 6 +++--- lib/active_relation/relations/nil.rb | 5 +++++ lib/active_relation/relations/table.rb | 2 +- spec/active_relation/unit/relations/join_spec.rb | 14 ++++++++++++-- .../unit/relations/selection_spec.rb | 6 +----- 9 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 lib/active_relation/relations/nil.rb diff --git a/.gitignore b/.gitignore index 22f348a1650dc..d6355b45d0d31 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -coverage/* \ No newline at end of file +coverage/* +*.DS_Store diff --git a/doc/TODO b/doc/TODO index 6d6b82082a04d..889f7fccb627e 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,8 +1,5 @@ todo: -- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? -- - mock out database -- #bind in Attribute and Expression should be doing a descend? -- try to make aggegration testing in join spec to be a bit more unit-like +- mock out database - finish pending tests - test relation, table reset - standardize quoting @@ -14,12 +11,6 @@ todo: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" - shit this one is hard at the moment. -- need adapters for this form: - {:conditions=>["approved = ?", false]} - {:conditions=>{:approved=>false}} - {:conditions=>{"topics.approved"=>false}} - {:conditions=>{:address=>#, "customers.name"=>"David1"}} - - cache expiry on write - rewrite of querycache test in light of this - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent @@ -67,3 +58,8 @@ done: - orderings - relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute - descend on array, along with bind written in terms of it +- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? + +icebox: +- #bind in Attribute and Expression should be doing a descend? +- try to make aggegration testing in join spec to be a bit more unit-like diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index ddf5ef5e07b16..9685d2ab4ae1c 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -4,7 +4,7 @@ class Attribute delegate :engine, :to => :relation def initialize(relation, name, options = {}) - @relation, @name, @alias, @ancestor, @column = relation, name, options[:alias], options[:ancestor] + @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end def alias_or_name diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 7776fd3d18219..d914fca094017 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -1,4 +1,5 @@ require 'active_relation/relations/relation' +require 'active_relation/relations/nil' require 'active_relation/relations/compound' require 'active_relation/relations/writing' require 'active_relation/relations/table' diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index ab5f440d9e43f..c5ce47b555cba 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -6,7 +6,7 @@ class Join < Relation hash_on :relation1 - def initialize(join_sql, relation1, relation2, *predicates) + def initialize(join_sql, relation1, relation2 = Nil.new, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end @@ -40,9 +40,9 @@ def joins this_join = [ join_sql, externalize(relation2).table_sql, - "ON", + ("ON" unless predicates.blank?), predicates.collect { |p| p.bind(self).to_sql }.join(' AND ') - ].join(" ") + ].compact.join(" ") [relation1.joins, relation2.joins, this_join].compact.join(" ") end diff --git a/lib/active_relation/relations/nil.rb b/lib/active_relation/relations/nil.rb new file mode 100644 index 0000000000000..b063db92c9763 --- /dev/null +++ b/lib/active_relation/relations/nil.rb @@ -0,0 +1,5 @@ +module ActiveRelation + class Nil < Relation + def table_sql; '' end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 72682bee55183..5ad27c1fcfb37 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -45,7 +45,7 @@ def reset end def table_sql - "#{engine.quote_table_name(name)}" + engine.quote_table_name(name) end private diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 30ac73b611b72..b274da7565d16 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -108,7 +108,7 @@ module ActiveRelation end end - describe 'with aggregated relations' do + describe 'when joining aggregated relations' do before do @aggregation = @relation2 \ .aggregate(@relation2[:user_id], @relation2[:id].count) \ @@ -157,6 +157,16 @@ module ActiveRelation ") end end - end + end + + describe 'when joining with a string' do + it "passes the string through to the where clause" do + Join.new("INNER JOIN ON asdf", @relation1).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + INNER JOIN ON asdf + ") + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index 1919d3007eafc..20833de58dda3 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -48,12 +48,8 @@ module ActiveRelation end describe 'when given a string' do - before do - @string = "asdf" - end - it "passes the string through to the where clause" do - Selection.new(@relation, @string).to_sql.should be_like(" + Selection.new(@relation, 'asdf').to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` WHERE asdf From 3967bd524da7b3c0b985c57670ceb7f5d48a0f1b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 15:53:45 -0700 Subject: [PATCH 0109/1492] string passthrough for joins --- lib/active_relation/relations/nil.rb | 7 +++++ lib/active_relation/relations/relation.rb | 7 ++++- .../unit/relations/join_spec.rb | 4 +-- .../unit/relations/relation_spec.rb | 27 +++++++++++++------ 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/active_relation/relations/nil.rb b/lib/active_relation/relations/nil.rb index b063db92c9763..289ba834d855a 100644 --- a/lib/active_relation/relations/nil.rb +++ b/lib/active_relation/relations/nil.rb @@ -1,5 +1,12 @@ module ActiveRelation class Nil < Relation def table_sql; '' end + + def to_s; '' end + + def ==(other) + self.class == other.class + end end + end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index eebfd48e300fb..1b80494cd764a 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -19,7 +19,12 @@ def first module Operations def join(other) - JoinOperation.new("INNER JOIN", self, other) + case other + when String + Join.new(other, self) + when Relation + JoinOperation.new("INNER JOIN", self, other) + end end def outer_join(other) diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index b274da7565d16..423e513be4d1f 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -161,10 +161,10 @@ module ActiveRelation describe 'when joining with a string' do it "passes the string through to the where clause" do - Join.new("INNER JOIN ON asdf", @relation1).to_sql.should be_like(" + Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - INNER JOIN ON asdf + INNER JOIN asdf ON fdsa ") end end diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 682ec88f10ece..70bf87271a02c 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -51,24 +51,35 @@ module ActiveRelation end describe '#join' do - it "manufactures an inner join operation between those two relations" do - @relation.join(@relation).on(@predicate).should == Join.new("INNER JOIN", @relation, @relation, @predicate) + describe 'when given a relation' do + it "manufactures an inner join operation between those two relations" do + @relation.join(@relation).on(@predicate). \ + should == Join.new("INNER JOIN", @relation, @relation, @predicate) + end + end + + describe "when given a string" do + it "manufactures a join operation with the string passed through" do + @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + end end end - + describe '#outer_join' do it "manufactures a left outer join operation between those two relations" do - @relation.outer_join(@relation).on(@predicate).should == Join.new("LEFT OUTER JOIN", @relation, @relation, @predicate) - end + @relation.outer_join(@relation).on(@predicate). \ + should == Join.new("LEFT OUTER JOIN", @relation, @relation, @predicate) + end end end - + describe '#project' do it "manufactures a projection relation" do - @relation.project(@attribute1, @attribute2).should == Projection.new(@relation, @attribute1, @attribute2) + @relation.project(@attribute1, @attribute2). \ + should == Projection.new(@relation, @attribute1, @attribute2) end end - + describe '#as' do it "manufactures an alias relation" do @relation.as(:paul).should == Alias.new(@relation, :paul) From ae0fe8f6c8c41b5abf8ced6a99b19dacdf8f57eb Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 18:24:18 -0700 Subject: [PATCH 0110/1492] redesigned the way limit and offset work - was range now have special 'take' and 'skip' operations. (the terminology comes from linq) --- lib/active_relation/relations.rb | 3 +- lib/active_relation/relations/compound.rb | 4 +-- lib/active_relation/relations/range.rb | 26 --------------- lib/active_relation/relations/relation.rb | 18 +++++++---- lib/active_relation/relations/skip.rb | 18 +++++++++++ lib/active_relation/relations/take.rb | 18 +++++++++++ .../unit/relations/relation_spec.rb | 6 ---- .../relations/{range_spec.rb => skip_spec.rb} | 15 ++++----- .../unit/relations/take_spec.rb | 32 +++++++++++++++++++ 9 files changed, 90 insertions(+), 50 deletions(-) delete mode 100644 lib/active_relation/relations/range.rb create mode 100644 lib/active_relation/relations/skip.rb create mode 100644 lib/active_relation/relations/take.rb rename spec/active_relation/unit/relations/{range_spec.rb => skip_spec.rb} (52%) create mode 100644 spec/active_relation/unit/relations/take_spec.rb diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index d914fca094017..240c20736e4c7 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -8,7 +8,8 @@ require 'active_relation/relations/projection' require 'active_relation/relations/selection' require 'active_relation/relations/order' -require 'active_relation/relations/range' +require 'active_relation/relations/take' +require 'active_relation/relations/skip' require 'active_relation/relations/rename' require 'active_relation/relations/deletion' require 'active_relation/relations/insertion' diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index 5778fe9b22900..c5af453e4b657 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -4,8 +4,8 @@ class Compound < Relation hash_on :relation - delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :limit, - :offset, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, + delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :take, + :skip, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, :engine, :to => :relation diff --git a/lib/active_relation/relations/range.rb b/lib/active_relation/relations/range.rb deleted file mode 100644 index fafdef5902b4e..0000000000000 --- a/lib/active_relation/relations/range.rb +++ /dev/null @@ -1,26 +0,0 @@ -module ActiveRelation - class Range < Compound - attr_reader :range - - def initialize(relation, range) - @relation, @range = relation, range - end - - def ==(other) - relation == other.relation and - range == other.range - end - - def limit - range.end - range.begin + 1 - end - - def offset - range.begin - end - - def descend(&block) - Range.new(relation.descend(&block), range) - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 1b80494cd764a..b26fac4e859a5 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -35,8 +35,6 @@ def [](index) case index when Symbol, String attribute_for_name(index) - when ::Range - Range.new(self, index) when Attribute, Expression attribute_for_attribute(index) end @@ -57,6 +55,14 @@ def as(aliaz) def order(*attributes) Order.new(self, *attributes) end + + def take(taken) + Take.new(self, taken) + end + + def skip(skipped) + Skip.new(self, skipped) + end def rename(attribute, aliaz) Rename.new(self, attribute => aliaz) @@ -114,8 +120,8 @@ def to_sql(formatter = Sql::SelectStatement.new(engine)) ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(engine)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), - ("LIMIT #{limit}" unless limit.blank? ), - ("OFFSET #{offset}" unless offset.blank? ) + ("LIMIT #{take}" unless take.blank? ), + ("OFFSET #{skip}" unless skip.blank? ) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql @@ -153,8 +159,8 @@ def orders; [] end def inserts; [] end def groupings; [] end def joins; nil end - def limit; nil end - def offset; nil end + def take; nil end + def skip; nil end def alias; nil end end end \ No newline at end of file diff --git a/lib/active_relation/relations/skip.rb b/lib/active_relation/relations/skip.rb new file mode 100644 index 0000000000000..f963ee64687bd --- /dev/null +++ b/lib/active_relation/relations/skip.rb @@ -0,0 +1,18 @@ +module ActiveRelation + class Skip < Compound + attr_reader :skip + + def initialize(relation, skip) + @relation, @skip = relation, skip + end + + def ==(other) + relation == other.relation and + skip == other.skip + end + + def descend(&block) + Skip.new(relation.descend(&block), skip) + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/take.rb b/lib/active_relation/relations/take.rb new file mode 100644 index 0000000000000..9f98207798b32 --- /dev/null +++ b/lib/active_relation/relations/take.rb @@ -0,0 +1,18 @@ +module ActiveRelation + class Take < Compound + attr_reader :take + + def initialize(relation, take) + @relation, @take = relation, take + end + + def ==(other) + relation == other.relation and + take == other.take + end + + def descend(&block) + Take.new(relation.descend(&block), take) + end + end +end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 70bf87271a02c..d10ae490defd4 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -9,12 +9,6 @@ module ActiveRelation end describe '[]' do - describe 'when given a', Range do - it "manufactures a range relation when given a range" do - @relation[1..2].should == Range.new(@relation, 1..2) - end - end - describe 'when given an', Attribute do it "return the attribute congruent to the provided attribute" do @relation[@attribute1].should == @attribute1 diff --git a/spec/active_relation/unit/relations/range_spec.rb b/spec/active_relation/unit/relations/skip_spec.rb similarity index 52% rename from spec/active_relation/unit/relations/range_spec.rb rename to spec/active_relation/unit/relations/skip_spec.rb index a0207c7342b77..77f2b8db272d0 100644 --- a/spec/active_relation/unit/relations/range_spec.rb +++ b/spec/active_relation/unit/relations/skip_spec.rb @@ -1,33 +1,30 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module ActiveRelation - describe Range do + describe Skip do before do @relation = Table.new(:users) - @range = 4..9 + @skip = 4 end describe '#qualify' do it "descends" do - Range.new(@relation, @range).qualify.should == Range.new(@relation, @range).descend(&:qualify) + Skip.new(@relation, @skip).qualify.should == Skip.new(@relation, @skip).descend(&:qualify) end end describe '#descend' do it "distributes a block over the relation" do - Range.new(@relation, @range).descend(&:qualify).should == Range.new(@relation.descend(&:qualify), @range) + Skip.new(@relation, @skip).descend(&:qualify).should == Skip.new(@relation.descend(&:qualify), @skip) end end describe '#to_sql' do it "manufactures sql with limit and offset" do - range_size = @range.last - @range.first + 1 - range_start = @range.first - Range.new(@relation, @range).to_s.should be_like(" + Skip.new(@relation, @skip).to_s.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - LIMIT #{range_size} - OFFSET #{range_start} + OFFSET #{@skip} ") end end diff --git a/spec/active_relation/unit/relations/take_spec.rb b/spec/active_relation/unit/relations/take_spec.rb new file mode 100644 index 0000000000000..6523ff85f98b0 --- /dev/null +++ b/spec/active_relation/unit/relations/take_spec.rb @@ -0,0 +1,32 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module ActiveRelation + describe Take do + before do + @relation = Table.new(:users) + @take = 4 + end + + describe '#qualify' do + it "descends" do + Take.new(@relation, @take).qualify.should == Take.new(@relation, @take).descend(&:qualify) + end + end + + describe '#descend' do + it "distributes a block over the relation" do + Take.new(@relation, @take).descend(&:qualify).should == Take.new(@relation.descend(&:qualify), @take) + end + end + + describe '#to_sql' do + it "manufactures sql with limit and offset" do + Take.new(@relation, @take).to_s.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + LIMIT #{@take} + ") + end + end + end +end \ No newline at end of file From a0dc6900330b7ec78785a80fe8b72595384635a0 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 11 Apr 2008 18:32:47 -0700 Subject: [PATCH 0111/1492] fixed bug with take/skip --- lib/active_relation/relations/compound.rb | 4 ++-- lib/active_relation/relations/relation.rb | 8 ++++---- lib/active_relation/relations/skip.rb | 10 +++++----- lib/active_relation/relations/take.rb | 10 +++++----- spec/active_relation/unit/relations/relation_spec.rb | 12 ++++++++++++ spec/active_relation/unit/relations/skip_spec.rb | 10 +++++----- spec/active_relation/unit/relations/take_spec.rb | 10 +++++----- 7 files changed, 38 insertions(+), 26 deletions(-) diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index c5af453e4b657..aa3274cbd3f0a 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -4,8 +4,8 @@ class Compound < Relation hash_on :relation - delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :take, - :skip, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, + delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :taken, + :skipped, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, :engine, :to => :relation diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index b26fac4e859a5..29c6fbbed090f 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -120,8 +120,8 @@ def to_sql(formatter = Sql::SelectStatement.new(engine)) ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(engine)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), - ("LIMIT #{take}" unless take.blank? ), - ("OFFSET #{skip}" unless skip.blank? ) + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n"), self.alias end alias_method :to_s, :to_sql @@ -159,8 +159,8 @@ def orders; [] end def inserts; [] end def groupings; [] end def joins; nil end - def take; nil end - def skip; nil end + def taken; nil end + def skipped; nil end def alias; nil end end end \ No newline at end of file diff --git a/lib/active_relation/relations/skip.rb b/lib/active_relation/relations/skip.rb index f963ee64687bd..7fd5e1603a7cb 100644 --- a/lib/active_relation/relations/skip.rb +++ b/lib/active_relation/relations/skip.rb @@ -1,18 +1,18 @@ module ActiveRelation class Skip < Compound - attr_reader :skip + attr_reader :skipped - def initialize(relation, skip) - @relation, @skip = relation, skip + def initialize(relation, skipped) + @relation, @skipped = relation, skipped end def ==(other) relation == other.relation and - skip == other.skip + skipped == other.skipped end def descend(&block) - Skip.new(relation.descend(&block), skip) + Skip.new(relation.descend(&block), skipped) end end end \ No newline at end of file diff --git a/lib/active_relation/relations/take.rb b/lib/active_relation/relations/take.rb index 9f98207798b32..efeff11bf2c29 100644 --- a/lib/active_relation/relations/take.rb +++ b/lib/active_relation/relations/take.rb @@ -1,18 +1,18 @@ module ActiveRelation class Take < Compound - attr_reader :take + attr_reader :taken - def initialize(relation, take) - @relation, @take = relation, take + def initialize(relation, taken) + @relation, @taken = relation, taken end def ==(other) relation == other.relation and - take == other.take + taken == other.taken end def descend(&block) - Take.new(relation.descend(&block), take) + Take.new(relation.descend(&block), taken) end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index d10ae490defd4..2a04276aeb4ed 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -106,6 +106,18 @@ module ActiveRelation end end + describe '#take' do + it "manufactures a take relation" do + @relation.take(5).should == Take.new(@relation, 5) + end + end + + describe '#skip' do + it "manufactures a skip relation" do + @relation.skip(4).should == Skip.new(@relation, 4) + end + end + describe '#call' do it 'executes a select_all on the connection' do mock(connection = Object.new).select_all(@relation.to_sql) diff --git a/spec/active_relation/unit/relations/skip_spec.rb b/spec/active_relation/unit/relations/skip_spec.rb index 77f2b8db272d0..d50ef715eec03 100644 --- a/spec/active_relation/unit/relations/skip_spec.rb +++ b/spec/active_relation/unit/relations/skip_spec.rb @@ -4,27 +4,27 @@ module ActiveRelation describe Skip do before do @relation = Table.new(:users) - @skip = 4 + @skipped = 4 end describe '#qualify' do it "descends" do - Skip.new(@relation, @skip).qualify.should == Skip.new(@relation, @skip).descend(&:qualify) + Skip.new(@relation, @skipped).qualify.should == Skip.new(@relation, @skipped).descend(&:qualify) end end describe '#descend' do it "distributes a block over the relation" do - Skip.new(@relation, @skip).descend(&:qualify).should == Skip.new(@relation.descend(&:qualify), @skip) + Skip.new(@relation, @skipped).descend(&:qualify).should == Skip.new(@relation.descend(&:qualify), @skipped) end end describe '#to_sql' do it "manufactures sql with limit and offset" do - Skip.new(@relation, @skip).to_s.should be_like(" + Skip.new(@relation, @skipped).to_s.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - OFFSET #{@skip} + OFFSET #{@skipped} ") end end diff --git a/spec/active_relation/unit/relations/take_spec.rb b/spec/active_relation/unit/relations/take_spec.rb index 6523ff85f98b0..beaa9e2f8c1f3 100644 --- a/spec/active_relation/unit/relations/take_spec.rb +++ b/spec/active_relation/unit/relations/take_spec.rb @@ -4,27 +4,27 @@ module ActiveRelation describe Take do before do @relation = Table.new(:users) - @take = 4 + @takene = 4 end describe '#qualify' do it "descends" do - Take.new(@relation, @take).qualify.should == Take.new(@relation, @take).descend(&:qualify) + Take.new(@relation, @takene).qualify.should == Take.new(@relation, @takene).descend(&:qualify) end end describe '#descend' do it "distributes a block over the relation" do - Take.new(@relation, @take).descend(&:qualify).should == Take.new(@relation.descend(&:qualify), @take) + Take.new(@relation, @takene).descend(&:qualify).should == Take.new(@relation.descend(&:qualify), @takene) end end describe '#to_sql' do it "manufactures sql with limit and offset" do - Take.new(@relation, @take).to_s.should be_like(" + Take.new(@relation, @takene).to_s.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - LIMIT #{@take} + LIMIT #{@takene} ") end end From 8feaf2b8bd0c2c9fcc137c7f5fa5f30b74fa35ef Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 12 Apr 2008 18:36:43 -0400 Subject: [PATCH 0112/1492] Use a git-ignored database.yml file for test DB configuration --- .gitignore | 1 + config/database.yml.example | 6 ++++++ spec/spec_helper.rb | 12 +++--------- 3 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 config/database.yml.example diff --git a/.gitignore b/.gitignore index d6355b45d0d31..2bab52ab219aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ coverage/* +config/database.yml *.DS_Store diff --git a/config/database.yml.example b/config/database.yml.example new file mode 100644 index 0000000000000..2230912f7d531 --- /dev/null +++ b/config/database.yml.example @@ -0,0 +1,6 @@ +test: + adapter: mysql + username: root + password: password + encoding: utf8 + database: sql_algebra_test diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4b61ae8ca8b07..b633d17257fe8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,15 +6,9 @@ Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" } require 'active_relation' -ActiveRecord::Base.configurations = { - 'test' => { - :adapter => 'mysql', - :username => 'root', - :password => 'password', - :encoding => 'utf8', - :database => 'sql_algebra_test', - }, -} +FileUtils.cp("#{dir}/../config/database.yml.example", "#{dir}/../config/database.yml") unless File.exist?("#{dir}/../config/database.yml") + +ActiveRecord::Base.configurations = YAML::load(IO.read("#{dir}/../config/database.yml")) ActiveRecord::Base.establish_connection 'test' class Hash From 6de1f350ce117129e46353f12f90a138ca3d3ead Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 15:56:07 -0700 Subject: [PATCH 0113/1492] - string passthrough for joins - blank checks --- doc/CONVENTIONS | 2 +- doc/TODO | 7 ++++--- lib/active_relation/primitives/value.rb | 4 ++++ lib/active_relation/relations/order.rb | 12 ++++++------ lib/active_relation/relations/relation.rb | 12 ++++++------ lib/active_relation/relations/skip.rb | 5 +++-- lib/active_relation/relations/take.rb | 5 +++-- .../unit/primitives/expression_spec.rb | 2 +- spec/active_relation/unit/primitives/value_spec.rb | 1 + 9 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 spec/active_relation/unit/primitives/value_spec.rb diff --git a/doc/CONVENTIONS b/doc/CONVENTIONS index 0d7c1b4ef0ebe..c415a527e170b 100644 --- a/doc/CONVENTIONS +++ b/doc/CONVENTIONS @@ -11,7 +11,7 @@ This file should ultimately be replaced by a series of tests, something like a l - 'obtains' is preferred to 'returns true' - 'manufactures' - in tests - - when manufacturing expected values (right-hand-side of should), avoid convenience methods -- construct it by initializing the object directly (Foo.new(...)). This ensures equality expectations in tests is rigorous. + - when manufacturing expected values (right-hand-side of should), avoid convenience methods -- construct it by initializing the object directly (Foo.new(...)). This ensures equality expectations in tests are rigorous. - the SUT should be manufactured inline inside the test, not in a before - dependencies for the SUT should be manufactured using convenience methods (or whatever is most terse). - group conceptually related methods in a class within an inline module; immediately include that module. \ No newline at end of file diff --git a/doc/TODO b/doc/TODO index 889f7fccb627e..7890daa503ca7 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,4 +1,6 @@ todo: +- test Value, in particular bind. +- test blank checks in relation.rb - mock out database - finish pending tests - test relation, table reset @@ -7,9 +9,6 @@ todo: - "unit" test sql strategies - use real world examples, so they should be like a tutorial. -- string passthrough: - :joins=>"INNER JOIN posts ON comments.post_id = posts.id" - - shit this one is hard at the moment. - cache expiry on write - rewrite of querycache test in light of this @@ -59,6 +58,8 @@ done: - relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute - descend on array, along with bind written in terms of it - re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? +- string passthrough: + :joins=>"INNER JOIN posts ON comments.post_id = posts.id" icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb index 6f251d442b57a..3fbe907324fa9 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/active_relation/primitives/value.rb @@ -23,5 +23,9 @@ def ==(other) def qualify self end + + def bind(relation) + Value.new(value, relation) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index 95b73c5e908f0..d71ff09c41596 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -1,25 +1,25 @@ module ActiveRelation class Order < Compound - attr_reader :order + attr_reader :ordering def initialize(relation, *orders) - order = orders.pop + ordering = orders.pop @relation = orders.empty?? relation : Order.new(relation, *orders) - @order = order.bind(@relation) + @ordering = ordering.bind(@relation) end def ==(other) self.class == other.class and relation == other.relation and - orders == other.orders + ordering == other.ordering end def descend(&block) - Order.new(relation.descend(&block), *orders.collect(&block)) + Order.new(relation.descend(&block), yield(ordering)) end def orders - relation.orders + [order] + relation.orders + [ordering] end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index 29c6fbbed090f..f5f2809724d74 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -41,27 +41,27 @@ def [](index) end def select(*predicates) - Selection.new(self, *predicates) + predicates.all?(&:blank?) ? self : Selection.new(self, *predicates) end def project(*attributes) - Projection.new(self, *attributes) + attributes.all?(&:blank?) ? self : Projection.new(self, *attributes) end def as(aliaz) - Alias.new(self, aliaz) + aliaz.blank?? self : Alias.new(self, aliaz) end def order(*attributes) - Order.new(self, *attributes) + attributes.all?(&:blank?) ? self : Order.new(self, *attributes) end def take(taken) - Take.new(self, taken) + taken.blank?? self : Take.new(self, taken) end def skip(skipped) - Skip.new(self, skipped) + skipped.blank?? self : Skip.new(self, skipped) end def rename(attribute, aliaz) diff --git a/lib/active_relation/relations/skip.rb b/lib/active_relation/relations/skip.rb index 7fd5e1603a7cb..3133a3af41f1b 100644 --- a/lib/active_relation/relations/skip.rb +++ b/lib/active_relation/relations/skip.rb @@ -7,8 +7,9 @@ def initialize(relation, skipped) end def ==(other) - relation == other.relation and - skipped == other.skipped + self.class == other.class and + relation == other.relation and + skipped == other.skipped end def descend(&block) diff --git a/lib/active_relation/relations/take.rb b/lib/active_relation/relations/take.rb index efeff11bf2c29..02d507753d8e6 100644 --- a/lib/active_relation/relations/take.rb +++ b/lib/active_relation/relations/take.rb @@ -7,8 +7,9 @@ def initialize(relation, taken) end def ==(other) - relation == other.relation and - taken == other.taken + self.class == other.class and + relation == other.relation and + taken == other.taken end def descend(&block) diff --git a/spec/active_relation/unit/primitives/expression_spec.rb b/spec/active_relation/unit/primitives/expression_spec.rb index dda35157b055e..c15b073ba3726 100644 --- a/spec/active_relation/unit/primitives/expression_spec.rb +++ b/spec/active_relation/unit/primitives/expression_spec.rb @@ -14,7 +14,7 @@ module ActiveRelation describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do - derived_relation = @relation.select(@relation[:id] == 1) + derived_relation = @relation.select(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end diff --git a/spec/active_relation/unit/primitives/value_spec.rb b/spec/active_relation/unit/primitives/value_spec.rb new file mode 100644 index 0000000000000..f87f5c14cbbd7 --- /dev/null +++ b/spec/active_relation/unit/primitives/value_spec.rb @@ -0,0 +1 @@ +# TODO \ No newline at end of file From 1b8f72746b38ce1e08b5fab48f3251eb09f2cba0 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 16:43:48 -0700 Subject: [PATCH 0114/1492] - removed #qualify and #descend helper - qualify seems no longer neccessary since everything is fully qualified - finished pending specs --- lib/active_relation/extensions/hash.rb | 8 ++--- lib/active_relation/predicates.rb | 10 +----- lib/active_relation/primitives/attribute.rb | 4 --- lib/active_relation/primitives/value.rb | 4 --- lib/active_relation/relations/aggregation.rb | 4 --- lib/active_relation/relations/alias.rb | 4 --- lib/active_relation/relations/compound.rb | 4 --- lib/active_relation/relations/join.rb | 8 ----- lib/active_relation/relations/order.rb | 4 --- lib/active_relation/relations/projection.rb | 4 --- lib/active_relation/relations/rename.rb | 4 --- lib/active_relation/relations/selection.rb | 4 --- lib/active_relation/relations/skip.rb | 4 --- lib/active_relation/relations/table.rb | 8 ----- lib/active_relation/relations/take.rb | 4 --- .../unit/predicates/binary_spec.rb | 14 -------- .../unit/primitives/attribute_spec.rb | 33 +++++++++---------- .../unit/relations/join_spec.rb | 14 -------- .../unit/relations/order_spec.rb | 14 -------- .../unit/relations/projection_spec.rb | 14 -------- .../unit/relations/relation_spec.rb | 9 ++--- .../unit/relations/rename_spec.rb | 14 -------- .../unit/relations/selection_spec.rb | 20 +---------- .../unit/relations/skip_spec.rb | 12 ------- .../unit/relations/table_spec.rb | 11 ++----- .../unit/relations/take_spec.rb | 18 ++-------- 26 files changed, 28 insertions(+), 223 deletions(-) diff --git a/lib/active_relation/extensions/hash.rb b/lib/active_relation/extensions/hash.rb index a33ace573850b..7472b5aa731ad 100644 --- a/lib/active_relation/extensions/hash.rb +++ b/lib/active_relation/extensions/hash.rb @@ -1,11 +1,7 @@ class Hash def bind(relation) - descend { |x| x.bind(relation) } - end - - def descend(&block) - inject({}) do |descendent, (key, value)| - descendent.merge(yield(key) => yield(value)) + inject({}) do |bound, (key, value)| + bound.merge(key.bind(relation) => value.bind(relation)) end end end \ No newline at end of file diff --git a/lib/active_relation/predicates.rb b/lib/active_relation/predicates.rb index dc4610b052d48..2cab1721d084e 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -17,20 +17,12 @@ def ==(other) end def bind(relation) - descend { |x| x.bind(relation) } + self.class.new(operand1.bind(relation), operand2.bind(relation)) end - def qualify - descend(&:qualify) - end - def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end - - def descend - self.class.new(yield(operand1), yield(operand2)) - end end class Equality < Binary diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index 9685d2ab4ae1c..d81565679434f 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -20,10 +20,6 @@ def bind(new_relation) relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) end - def qualify - self.as(qualified_name) - end - def to_attribute self end diff --git a/lib/active_relation/primitives/value.rb b/lib/active_relation/primitives/value.rb index 3fbe907324fa9..9042aea067b75 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/active_relation/primitives/value.rb @@ -20,10 +20,6 @@ def ==(other) value == other.value end - def qualify - self - end - def bind(relation) Value.new(value, relation) end diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb index 38f1f2dda8da9..62432408e18dd 100644 --- a/lib/active_relation/relations/aggregation.rb +++ b/lib/active_relation/relations/aggregation.rb @@ -20,9 +20,5 @@ def attributes def aggregation? true end - - def descend(&block) - Aggregation.new(relation.descend(&block), :expressions => expressions.collect(&block), :groupings => groupings.collect(&block)) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index f24b1d743c76a..cf410c6462b6b 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -9,10 +9,6 @@ def initialize(relation, aliaz) def alias? true end - - def descend(&block) - Alias.new(relation.descend(&block), @alias) - end def ==(other) self.class == other.class and diff --git a/lib/active_relation/relations/compound.rb b/lib/active_relation/relations/compound.rb index aa3274cbd3f0a..7c844821158b1 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/active_relation/relations/compound.rb @@ -12,9 +12,5 @@ class Compound < Relation def attributes relation.attributes.collect { |a| a.bind(self) } end - - def qualify - descend(&:qualify) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index c5ce47b555cba..dbcb520b926de 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -18,10 +18,6 @@ def ==(other) ) end - def qualify - descend(&:qualify) - end - def attributes (externalize(relation1).attributes + externalize(relation2).attributes).collect { |a| a.bind(self) } @@ -31,10 +27,6 @@ def prefix_for(attribute) externalize(relation1).prefix_for(attribute) or externalize(relation2).prefix_for(attribute) end - - def descend(&block) - Join.new(join_sql, relation1.descend(&block), relation2.descend(&block), *predicates.collect(&block)) - end def joins this_join = [ diff --git a/lib/active_relation/relations/order.rb b/lib/active_relation/relations/order.rb index d71ff09c41596..b5495fad67ca1 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -13,10 +13,6 @@ def ==(other) relation == other.relation and ordering == other.ordering end - - def descend(&block) - Order.new(relation.descend(&block), yield(ordering)) - end def orders relation.orders + [ordering] diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index c478ae145fa59..c1495c1742bae 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -15,9 +15,5 @@ def ==(other) relation == other.relation and projections == other.projections end - - def descend(&block) - Projection.new(relation.descend(&block), *projections.collect(&block)) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb index ac5484bfff247..9ab07707a0003 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -18,10 +18,6 @@ def attributes relation.attributes.collect(&method(:christen)) end - def descend(&block) - Rename.new(relation.descend(&block), yield(attribute) => pseudonym) - end - private def christen(attribute) (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).bind(self) rescue nil diff --git a/lib/active_relation/relations/selection.rb b/lib/active_relation/relations/selection.rb index 032de63d043a0..fb90405b01aea 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/active_relation/relations/selection.rb @@ -14,10 +14,6 @@ def ==(other) predicate == other.predicate end - def descend(&block) - Selection.new(relation.descend(&block), yield(predicate)) - end - def selects relation.selects + [predicate] end diff --git a/lib/active_relation/relations/skip.rb b/lib/active_relation/relations/skip.rb index 3133a3af41f1b..5973dff8b9b24 100644 --- a/lib/active_relation/relations/skip.rb +++ b/lib/active_relation/relations/skip.rb @@ -11,9 +11,5 @@ def ==(other) relation == other.relation and skipped == other.skipped end - - def descend(&block) - Skip.new(relation.descend(&block), skipped) - end end end \ No newline at end of file diff --git a/lib/active_relation/relations/table.rb b/lib/active_relation/relations/table.rb index 5ad27c1fcfb37..e645f710303cb 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -15,10 +15,6 @@ def attributes end end - def qualify - Rename.new self, qualifications - end - def prefix_for(attribute) self[attribute] and name end @@ -36,10 +32,6 @@ def columns @columns ||= engine.columns(name, "#{name} Columns") end - def descend - yield self - end - def reset @attributes = @columns = nil end diff --git a/lib/active_relation/relations/take.rb b/lib/active_relation/relations/take.rb index 02d507753d8e6..d9d439b3f5627 100644 --- a/lib/active_relation/relations/take.rb +++ b/lib/active_relation/relations/take.rb @@ -11,9 +11,5 @@ def ==(other) relation == other.relation and taken == other.taken end - - def descend(&block) - Take.new(relation.descend(&block), taken) - end end end \ No newline at end of file diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/active_relation/unit/predicates/binary_spec.rb index 5dd5e5599adec..56c568b07819e 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -57,20 +57,6 @@ def predicate_sql end end - describe '#qualify' do - it "descends" do - ConcreteBinary.new(@attribute1, @attribute2).qualify \ - .should == ConcreteBinary.new(@attribute1, @attribute2).descend(&:qualify) - end - end - - describe '#descend' do - it "distributes a block over the predicates and attributes" do - ConcreteBinary.new(@attribute1, @attribute2).descend(&:qualify). \ - should == ConcreteBinary.new(@attribute1.qualify, @attribute2.qualify) - end - end - describe '#bind' do before do @another_relation = Table.new(:photos) diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index fbbcbaef370e6..08ed6d3621c4b 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -21,16 +21,10 @@ module ActiveRelation end it "returns self if the substituting to the same relation" do - @attribute.should == @attribute + @attribute.bind(@relation).should == @attribute end end - describe '#qualify' do - it "manufactures an attribute aliased with that attribute's qualified name" do - @attribute.qualify.should == Attribute.new(@attribute.relation, @attribute.name, :alias => @attribute.qualified_name, :ancestor => @attribute) - end - end - describe '#to_attribute' do it "returns self" do @attribute.to_attribute.should == @attribute @@ -40,16 +34,13 @@ module ActiveRelation describe '#column' do it "returns the corresponding column in the relation" do - pending "damn mock based tests are too easy" - stub(@relation).column_for(@attribute) { 'bruisers' } - @attribute.column.should == 'bruisers' + @attribute.column.should == @relation.column_for(@attribute) end end describe '#qualified_name' do it "manufactures an attribute name prefixed with the relation's name" do - stub(@relation).prefix_for(anything) { 'bruisers' } - Attribute.new(@relation, :id).qualified_name.should == 'bruisers.id' + @attribute.qualified_name.should == "#{@relation.prefix_for(@attribute)}.id" end end @@ -80,13 +71,21 @@ module ActiveRelation end describe '#to_sql' do - it "" do - pending "this test is not sufficiently resilient" + describe 'for a simple attribute' do + it "manufactures sql with an alias" do + @attribute.to_sql.should be_like("`users`.`id`") + end end - it "manufactures sql with an alias" do - stub(@relation).prefix_for(anything) { 'bruisers' } - Attribute.new(@relation, :name, :alias => :alias).to_sql.should be_like("`bruisers`.`name`") + describe 'for an attribute in a join relation where the source relation is aliased' do + before do + another_relation = Table.new(:photos) + @join_with_alias = @relation.as(:alias).join(another_relation).on(@relation[:id].eq(another_relation[:user_id])) + end + + it "manufactures sql with an alias" do + @join_with_alias[@attribute].to_sql.should be_like("`alias`.`id`") + end end end diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 423e513be4d1f..73dd67bec8654 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -32,20 +32,6 @@ module ActiveRelation end end - describe '#qualify' do - it 'descends' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ - should == Join.new("INNER JOIN", @relation1, @relation2, @predicate).descend(&:qualify) - end - end - - describe '#descend' do - it 'distributes over the relations and predicates' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).qualify. \ - should == Join.new("INNER JOIN", @relation1.qualify, @relation2.qualify, @predicate.qualify) - end - end - describe '#prefix_for' do describe 'when the joined relations are simple' do it "returns the name of the relation containing the attribute" do diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/active_relation/unit/relations/order_spec.rb index db322fe00b790..e8a2f4c227852 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/active_relation/unit/relations/order_spec.rb @@ -18,20 +18,6 @@ module ActiveRelation end end - describe '#qualify' do - it "descends" do - Order.new(@relation, @attribute).qualify. \ - should == Order.new(@relation, @attribute).descend(&:qualify) - end - end - - describe '#descend' do - it "distributes a block over the relation and attributes" do - Order.new(@relation, @attribute).descend(&:qualify). \ - should == Order.new(@relation.descend(&:qualify), @attribute.qualify) - end - end - describe '#to_sql' do describe "when given an attribute" do it "manufactures sql with an order clause populated by the attribute" do diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index f58564840bf82..529998a8d4cb3 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -30,20 +30,6 @@ module ActiveRelation end end - describe '#qualify' do - it "descends" do - Projection.new(@relation, @attribute).qualify. \ - should == Projection.new(@relation, @attribute).descend(&:qualify) - end - end - - describe '#descend' do - it "distributes a block over the relation and attributes" do - Projection.new(@relation, @attribute).descend(&:qualify). \ - should == Projection.new(@relation.descend(&:qualify), @attribute.qualify) - end - end - describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 2a04276aeb4ed..fa66352c91c3b 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -174,12 +174,9 @@ module ActiveRelation end describe Relation::Enumerable do - it "is enumerable" do - pending "I don't like this mock-based test" - data = [1,2,3] - mock.instance_of(Session).read(anything) { data } - @relation.collect.should == data - @relation.first.should == data.first + it "implements enumerable" do + @relation.collect.should == @relation.session.read(@relation) + @relation.first.should == @relation.session.read(@relation).first end end end diff --git a/spec/active_relation/unit/relations/rename_spec.rb b/spec/active_relation/unit/relations/rename_spec.rb index 9a63c4fc807eb..192c81984819b 100644 --- a/spec/active_relation/unit/relations/rename_spec.rb +++ b/spec/active_relation/unit/relations/rename_spec.rb @@ -38,20 +38,6 @@ module ActiveRelation end end - describe '#qualify' do - it "descends" do - Rename.new(@relation, @relation[:id] => :schmid).qualify. \ - should == Rename.new(@relation, @relation[:id] => :schmid).descend(&:qualify) - end - end - - describe '#descend' do - it "distributes a block over the relation and renames" do - Rename.new(@relation, @relation[:id] => :schmid).descend(&:qualify). \ - should == Rename.new(@relation.descend(&:qualify), @relation[:id].qualify => :schmid) - end - end - describe '#to_sql' do it 'manufactures sql renaming the attribute' do Rename.new(@relation, @relation[:id] => :schmid).to_sql.should be_like(" diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/active_relation/unit/relations/selection_spec.rb index 20833de58dda3..d87e075f983b5 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/active_relation/unit/relations/selection_spec.rb @@ -17,25 +17,7 @@ module ActiveRelation should == Selection.new(Selection.new(@relation, @another_predicate), @predicate) end end - - describe '#qualify' do - it "descends" do - Selection.new(@relation, @predicate).qualify. \ - should == Selection.new(@relation, @predicate).descend(&:qualify) - end - end - - describe '#descend' do - before do - @selection = Selection.new(@relation, @predicate) - end - - it "distributes a block over the relation and predicates" do - @selection.descend(&:qualify). \ - should == Selection.new(@selection.relation.descend(&:qualify), @selection.predicate.qualify) - end - end - + describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do diff --git a/spec/active_relation/unit/relations/skip_spec.rb b/spec/active_relation/unit/relations/skip_spec.rb index d50ef715eec03..219bfdd80ef48 100644 --- a/spec/active_relation/unit/relations/skip_spec.rb +++ b/spec/active_relation/unit/relations/skip_spec.rb @@ -7,18 +7,6 @@ module ActiveRelation @skipped = 4 end - describe '#qualify' do - it "descends" do - Skip.new(@relation, @skipped).qualify.should == Skip.new(@relation, @skipped).descend(&:qualify) - end - end - - describe '#descend' do - it "distributes a block over the relation" do - Skip.new(@relation, @skipped).descend(&:qualify).should == Skip.new(@relation.descend(&:qualify), @skipped) - end - end - describe '#to_sql' do it "manufactures sql with limit and offset" do Skip.new(@relation, @skipped).to_s.should be_like(" diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 6286ea9de16e4..2751d9cb6389f 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -46,8 +46,8 @@ module ActiveRelation end describe '#column_for' do - it "" do - @relation[:id].column.should == @relation.columns.detect { |c| c.name == 'id' } + it "returns the column corresponding to the attribute" do + @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } end end @@ -68,19 +68,12 @@ module ActiveRelation describe '#reset' do it "reloads columns from the database" do - pending lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } lambda { @relation.reset }.should change { @relation.attributes } end end end - describe '#qualify' do - it 'manufactures a rename relation with all attribute names qualified' do - @relation.qualify.should == Rename.new(@relation, @relation[:name] => 'users.name', @relation[:id] => 'users.id') - end - end - describe 'hashing' do it "implements hash equality" do Table.new(:users).should hash_the_same_as(Table.new(:users)) diff --git a/spec/active_relation/unit/relations/take_spec.rb b/spec/active_relation/unit/relations/take_spec.rb index beaa9e2f8c1f3..8c13732258c93 100644 --- a/spec/active_relation/unit/relations/take_spec.rb +++ b/spec/active_relation/unit/relations/take_spec.rb @@ -4,27 +4,15 @@ module ActiveRelation describe Take do before do @relation = Table.new(:users) - @takene = 4 + @taken = 4 end - describe '#qualify' do - it "descends" do - Take.new(@relation, @takene).qualify.should == Take.new(@relation, @takene).descend(&:qualify) - end - end - - describe '#descend' do - it "distributes a block over the relation" do - Take.new(@relation, @takene).descend(&:qualify).should == Take.new(@relation.descend(&:qualify), @takene) - end - end - describe '#to_sql' do it "manufactures sql with limit and offset" do - Take.new(@relation, @takene).to_s.should be_like(" + Take.new(@relation, @taken).to_s.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - LIMIT #{@takene} + LIMIT #{@taken} ") end end From 84bc172dbcab98d4dd55a044e44b907e6bafd7b0 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 16:47:31 -0700 Subject: [PATCH 0115/1492] considering deprecating rename operation - this may still be necessary when you join the same table to itself ... but not sure --- spec/active_relation/unit/relations/join_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 73dd67bec8654..60ede711a994e 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -96,10 +96,11 @@ module ActiveRelation describe 'when joining aggregated relations' do before do - @aggregation = @relation2 \ - .aggregate(@relation2[:user_id], @relation2[:id].count) \ - .group(@relation2[:user_id]) \ - .rename(@relation2[:id].count, :cnt) \ + @aggregation = @relation2 \ + .aggregate(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ + .group(@relation2[:user_id]) \ + + git .as('photo_count') end From f2bc41e6f2f6b22e7a9378a43f804cd4f7a8c1da Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 16:47:53 -0700 Subject: [PATCH 0116/1492] typo --- spec/active_relation/unit/relations/join_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 60ede711a994e..c25629536d99c 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -99,8 +99,6 @@ module ActiveRelation @aggregation = @relation2 \ .aggregate(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ .group(@relation2[:user_id]) \ - - git .as('photo_count') end From 0f3657fb70bc14720e32e5f78e521764d7a9bc06 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 17:23:10 -0700 Subject: [PATCH 0117/1492] added pending test for (difficult) problem of aliasing tables for adjacency lists --- lib/active_relation/relations/alias.rb | 4 ++-- spec/active_relation/unit/relations/join_spec.rb | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/active_relation/relations/alias.rb b/lib/active_relation/relations/alias.rb index cf410c6462b6b..4cb4913da5f26 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -1,7 +1,7 @@ module ActiveRelation class Alias < Compound attr_reader :alias - + def initialize(relation, aliaz) @relation, @alias = relation, aliaz end @@ -9,7 +9,7 @@ def initialize(relation, aliaz) def alias? true end - + def ==(other) self.class == other.class and relation == other.relation and diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index c25629536d99c..5d554cd9abd2e 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -144,6 +144,19 @@ module ActiveRelation end end + describe 'when joining aliased relations' do + it 'aliases the table and attributes properly' do + pending + aliased_relation = @relation1.as(:alias) + @relation1.join(aliased_relation).on(@relation1[:id].eq(aliased_relation[:id])).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `alias`.`id`, `alias`.`name` + FROM `users` + INNER JOIN `alias` + ON `users`.`id` = `alias`.`id` + ") + end + end + describe 'when joining with a string' do it "passes the string through to the where clause" do Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql.should be_like(" From 97f89cde2af330771d0df80491e718f8b0cb7dd6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 17:33:56 -0700 Subject: [PATCH 0118/1492] tests of Value --- doc/TODO | 10 +++++-- .../unit/primitives/value_spec.rb | 29 ++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/doc/TODO b/doc/TODO index 7890daa503ca7..97e89c3e0ed94 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,14 +1,16 @@ todo: - test Value, in particular bind. +- rename ActiveRelation to arel - test blank checks in relation.rb - mock out database -- finish pending tests -- test relation, table reset - standardize quoting - use strings everywhere, not symbols ? - "unit" test sql strategies - use real world examples, so they should be like a tutorial. - +- investigage complex joining cases: + - aggregations + - left outer joins + - adjacency lists - cache expiry on write - rewrite of querycache test in light of this @@ -60,6 +62,8 @@ done: - re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? - string passthrough: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" +- finish pending tests +- test relation, table reset icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/spec/active_relation/unit/primitives/value_spec.rb b/spec/active_relation/unit/primitives/value_spec.rb index f87f5c14cbbd7..ab632ef98755c 100644 --- a/spec/active_relation/unit/primitives/value_spec.rb +++ b/spec/active_relation/unit/primitives/value_spec.rb @@ -1 +1,28 @@ -# TODO \ No newline at end of file +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module ActiveRelation + describe Value do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "appropriately quotes the value" do + Value.new(1, @relation).to_sql.should be_like('1') + Value.new('asdf', @relation).to_sql.should be_like("'asdf'") + end + end + + describe '#format' do + it "returns the sql of the provided object" do + Value.new(1, @relation).format(@relation[:id]).should == @relation[:id].to_sql + end + end + + describe '#bind' do + it "manufactures a new value whose relation is the provided relation" do + Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) + end + end + end +end \ No newline at end of file From 2f9b70b6179d0b66f80d6edd3eca1017aec70659 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 12 Apr 2008 17:45:36 -0700 Subject: [PATCH 0119/1492] better test coverage of relational operations with blank data --- doc/TODO | 3 +- lib/active_relation/relations.rb | 1 - lib/active_relation/relations/relation.rb | 14 ++--- lib/active_relation/relations/rename.rb | 26 -------- .../unit/relations/relation_spec.rb | 61 +++++++++++++++---- .../unit/relations/rename_spec.rb | 50 --------------- 6 files changed, 56 insertions(+), 99 deletions(-) delete mode 100644 lib/active_relation/relations/rename.rb delete mode 100644 spec/active_relation/unit/relations/rename_spec.rb diff --git a/doc/TODO b/doc/TODO index 97e89c3e0ed94..878e240a4f3dc 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,6 +1,6 @@ todo: -- test Value, in particular bind. - rename ActiveRelation to arel +- investigate linq vocabularity - test blank checks in relation.rb - mock out database - standardize quoting @@ -64,6 +64,7 @@ done: :joins=>"INNER JOIN posts ON comments.post_id = posts.id" - finish pending tests - test relation, table reset +- test Value, in particular bind. icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 240c20736e4c7..9cede2a6d181e 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -10,7 +10,6 @@ require 'active_relation/relations/order' require 'active_relation/relations/take' require 'active_relation/relations/skip' -require 'active_relation/relations/rename' require 'active_relation/relations/deletion' require 'active_relation/relations/insertion' require 'active_relation/relations/update' diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index f5f2809724d74..b62a5d9fb9cc6 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -18,12 +18,14 @@ def first include Enumerable module Operations - def join(other) + def join(other = nil) case other when String Join.new(other, self) when Relation JoinOperation.new("INNER JOIN", self, other) + else + self end end @@ -48,7 +50,7 @@ def project(*attributes) attributes.all?(&:blank?) ? self : Projection.new(self, *attributes) end - def as(aliaz) + def as(aliaz = nil) aliaz.blank?? self : Alias.new(self, aliaz) end @@ -56,18 +58,14 @@ def order(*attributes) attributes.all?(&:blank?) ? self : Order.new(self, *attributes) end - def take(taken) + def take(taken = nil) taken.blank?? self : Take.new(self, taken) end - def skip(skipped) + def skip(skipped = nil) skipped.blank?? self : Skip.new(self, skipped) end - def rename(attribute, aliaz) - Rename.new(self, attribute => aliaz) - end - def aggregate(*expressions) AggregateOperation.new(self, expressions) end diff --git a/lib/active_relation/relations/rename.rb b/lib/active_relation/relations/rename.rb deleted file mode 100644 index 9ab07707a0003..0000000000000 --- a/lib/active_relation/relations/rename.rb +++ /dev/null @@ -1,26 +0,0 @@ -module ActiveRelation - class Rename < Compound - attr_reader :attribute, :pseudonym - - def initialize(relation, pseudonyms) - @attribute, @pseudonym = pseudonyms.shift - @relation = pseudonyms.empty?? relation : Rename.new(relation, pseudonyms) - end - - def ==(other) - self.class == other.class and - relation == other.relation and - attribute == other.attribute and - pseudonym == other.pseudonym - end - - def attributes - relation.attributes.collect(&method(:christen)) - end - - private - def christen(attribute) - (attribute =~ self.attribute ? attribute.as(pseudonym) : attribute).bind(self) rescue nil - end - end -end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index fa66352c91c3b..2b62c8db5ed45 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -57,6 +57,12 @@ module ActiveRelation @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) end end + + describe "when given something blank" do + it "returns self" do + @relation.join.should == @relation + end + end end describe '#outer_join' do @@ -72,17 +78,23 @@ module ActiveRelation @relation.project(@attribute1, @attribute2). \ should == Projection.new(@relation, @attribute1, @attribute2) end + + describe "when given blank attributes" do + it "returns self" do + @relation.project.should == @relation + end + end end describe '#as' do it "manufactures an alias relation" do @relation.as(:paul).should == Alias.new(@relation, :paul) end - end - - describe '#rename' do - it "manufactures a rename relation" do - @relation.rename(@attribute1, :users).should == Rename.new(@relation, @attribute1 => :users) + + describe 'when given a blank alias' do + it 'returns self' do + @relation.as.should == @relation + end end end @@ -98,34 +110,50 @@ module ActiveRelation it "accepts arbitrary strings" do @relation.select("arbitrary").should == Selection.new(@relation, "arbitrary") end + + describe 'when given a blank predicate' do + it 'returns self' do + @relation.select.should == @relation + end + end end describe '#order' do it "manufactures an order relation" do @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) end + + describe 'when given a blank ordering' do + it 'returns self' do + @relation.order.should == @relation + end + end end describe '#take' do it "manufactures a take relation" do @relation.take(5).should == Take.new(@relation, 5) end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.take.should == @relation + end + end end describe '#skip' do it "manufactures a skip relation" do @relation.skip(4).should == Skip.new(@relation, 4) end - end - - describe '#call' do - it 'executes a select_all on the connection' do - mock(connection = Object.new).select_all(@relation.to_sql) - @relation.call(connection) + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.skip.should == @relation + end end end - - + describe '#aggregate' do before do @expression1 = @attribute1.sum @@ -179,5 +207,12 @@ module ActiveRelation @relation.first.should == @relation.session.read(@relation).first end end + + describe '#call' do + it 'executes a select_all on the connection' do + mock(connection = Object.new).select_all(@relation.to_sql) + @relation.call(connection) + end + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/rename_spec.rb b/spec/active_relation/unit/relations/rename_spec.rb deleted file mode 100644 index 192c81984819b..0000000000000 --- a/spec/active_relation/unit/relations/rename_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module ActiveRelation - describe Rename do - before do - @relation = Table.new(:users) - end - - describe '#initialize' do - it "manufactures nested rename relations if multiple renames are provided" do - Rename.new(@relation, @relation[:id] => :humpty, @relation[:name] => :dumpty). \ - should == Rename.new(Rename.new(@relation, @relation[:name] => :dumpty), @relation[:id] => :humpty) - end - end - - describe '==' do - before do - @another_relation = Table.new(:photos) - end - - it "obtains if the relation, attribute, and rename are identical" do - Rename.new(@relation, @relation[:id] => :humpty).should == Rename.new(@relation, @relation[:id] => :humpty) - Rename.new(@relation, @relation[:id] => :humpty).should_not == Rename.new(@relation, @relation[:id] => :dumpty) - Rename.new(@relation, @relation[:id] => :humpty).should_not == Rename.new(@another_relation, @relation[:id] => :humpty) - end - end - - describe '#attributes' do - before do - @renamed_relation = Rename.new(@relation, @relation[:id] => :schmid) - end - - it "manufactures a list of attributes with the renamed attribute renameed" do - @renamed_relation.attributes.should include(@relation[:id].as(:schmid).bind(@renamed_relation)) - @renamed_relation.attributes.should_not include(@relation[:id].bind(@renamed_relation)) - @renamed_relation.attributes.should include(@relation[:name].bind(@renamed_relation)) - @renamed_relation.should have(@relation.attributes.size).attributes - end - end - - describe '#to_sql' do - it 'manufactures sql renaming the attribute' do - Rename.new(@relation, @relation[:id] => :schmid).to_sql.should be_like(" - SELECT `users`.`id` AS 'schmid', `users`.`name` - FROM `users` - ") - end - end - end -end \ No newline at end of file From bfcb7ca25d86491fb4e1edeb463a99006f6c7151 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 13 Apr 2008 16:24:51 -0400 Subject: [PATCH 0120/1492] Remove duplicate Insertion spec --- .../unit/relations/insertion_spec.rb | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index e01e7792e2df3..7aca7f24c13c8 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -34,20 +34,6 @@ module ActiveRelation ") end end - - describe 'when given values whose types correspond to the type of the attribtues' do - before do - @insertion = Insertion.new(@relation, @relation[:name] => "nick") - end - - it 'manufactures sql inserting data' do - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`users`.`name`) VALUES ('nick') - ") - end - end end describe '#call' do From 1215d8b0b9a44619ea1e77dbce723da12f7f73ea Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 13 Apr 2008 17:08:14 -0400 Subject: [PATCH 0121/1492] Un-pending a Table spec that passes now --- spec/active_relation/unit/relations/table_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/active_relation/unit/relations/table_spec.rb index 6286ea9de16e4..6b562cff895ce 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/active_relation/unit/relations/table_spec.rb @@ -68,7 +68,6 @@ module ActiveRelation describe '#reset' do it "reloads columns from the database" do - pending lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } lambda { @relation.reset }.should change { @relation.attributes } end From 968271f718929311797342e211f5ca29506463b9 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 13 Apr 2008 17:09:59 -0400 Subject: [PATCH 0122/1492] Some pending specs for Insertion, Deletion and Update relating to LIMITs, multiple values and multiple rows --- .../unit/relations/deletion_spec.rb | 10 ++++++++ .../unit/relations/insertion_spec.rb | 24 +++++++++++++++++++ .../unit/relations/update_spec.rb | 19 +++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb index 71ddd8d820337..72f3f81b2a672 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -21,6 +21,16 @@ module ActiveRelation WHERE `users`.`id` = 1 ") end + + it "manufactures sql deleting a ranged relation" do + pending do + Deletion.new(@relation[0..0]).to_sql.should be_like(" + DELETE + FROM `users` + LIMIT 1 + ") + end + end end describe '#call' do diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index 7aca7f24c13c8..e1718e3b25867 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -7,6 +7,30 @@ module ActiveRelation end describe '#to_sql' do + it 'manufactures sql inserting data when given multiple rows' do + pending do + @insertion = Insertion.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) + + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick'), ('bryan') + ") + end + end + + it 'manufactures sql inserting data when given multiple values' do + pending do + @insertion = Insertion.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") + + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`name`, `users`.`id`) VALUES ('nick', 1) + ") + end + end + describe 'when given values whose types correspond to the types of the attributes' do before do @insertion = Insertion.new(@relation, @relation[:name] => "nick") diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 5c234fe7595ec..6634dc67d174d 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -7,6 +7,25 @@ module ActiveRelation end describe '#to_sql' do + it "manufactures sql updating attributes when given multiple attributes" do + pending do + Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" + UPDATE `users` + SET `users`.`name` = 'nick', `users`.`id` = 1 + ") + end + end + + it "manufactures sql updating attributes when given a ranged relation" do + pending do + Update.new(@relation[0..0], @relation[:name] => "nick").to_sql.should be_like(" + UPDATE `users` + SET `users`.`name` = 'nick' + LIMIT 1 + ") + end + end + describe 'when given values whose types correspond to the types of the attributes' do before do @update = Update.new(@relation, @relation[:name] => "nick") From 4466409205d697f854f98ac0908a792a1601ecc6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Apr 2008 17:03:03 -0700 Subject: [PATCH 0123/1492] adjacency lists work - implementation is a bit complex, but i can't think of anything simpler --- doc/TODO | 23 ++++++++----------- lib/active_relation/primitives/attribute.rb | 8 +++++++ lib/active_relation/relations/join.rb | 22 +++++++++++++++--- .../unit/primitives/attribute_spec.rb | 1 + .../unit/relations/join_spec.rb | 3 +-- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/doc/TODO b/doc/TODO index 878e240a4f3dc..16cbc0d77a611 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,20 +1,11 @@ todo: - rename ActiveRelation to arel -- investigate linq vocabularity -- test blank checks in relation.rb +- incorporate linq vocabularity - mock out database -- standardize quoting - - use strings everywhere, not symbols ? -- "unit" test sql strategies - - use real world examples, so they should be like a tutorial. -- investigage complex joining cases: - - aggregations - - left outer joins - - adjacency lists - +- fix complex joining cases: +- extract adapters - cache expiry on write - - rewrite of querycache test in light of this -- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent + - rewrite of arecord querycache test in light of this done: . Relation <=> Relation -> InnerJoinOperation @@ -65,7 +56,13 @@ done: - finish pending tests - test relation, table reset - test Value, in particular bind. +- test blank checks in relation.rb icebox: - #bind in Attribute and Expression should be doing a descend? - try to make aggegration testing in join spec to be a bit more unit-like +- standardize quoting + - use strings everywhere, not symbols ? +- "unit" test sql strategies + - use real world examples, so they should be like a tutorial. +- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index d81565679434f..d37271490aa05 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -54,6 +54,14 @@ def history def =~(other) !(history & other.history).empty? end + + def %(other) + if other + (history - other.history) + (other.history - history) + else + history + end + end end include Congruence diff --git a/lib/active_relation/relations/join.rb b/lib/active_relation/relations/join.rb index dbcb520b926de..a3e45f7f8189d 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -24,8 +24,17 @@ def attributes end def prefix_for(attribute) - externalize(relation1).prefix_for(attribute) or - externalize(relation2).prefix_for(attribute) + if relation1[attribute] && !relation2[attribute] + externalize(relation1).prefix_for(attribute) + elsif relation2[attribute] && !relation1[attribute] + externalize(relation2).prefix_for(attribute) + else + if (attribute % relation1[attribute]).size < (attribute % relation2[attribute]).size + externalize(relation1).prefix_for(attribute) + else + externalize(relation2).prefix_for(attribute) + end + end end def joins @@ -55,7 +64,14 @@ def externalize(relation) delegate :engine, :to => :relation def table_sql - relation.aggregation?? relation.to_sql(Sql::TableReference.new(engine)) : relation.table_sql + case + when relation.aggregation? + relation.to_sql(Sql::TableReference.new(engine)) + when relation.alias? + relation.table_sql + ' AS ' + engine.quote_table_name(relation.alias.to_s) + else + relation.table_sql + end end def selects diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/active_relation/unit/primitives/attribute_spec.rb index 08ed6d3621c4b..471ae91b5bff1 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/active_relation/unit/primitives/attribute_spec.rb @@ -52,6 +52,7 @@ module ActiveRelation describe Attribute::Congruence do describe '=~' do + it "obtains if the attributes are identical" do Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name) end diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 5d554cd9abd2e..22b0a9f2373a7 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -146,12 +146,11 @@ module ActiveRelation describe 'when joining aliased relations' do it 'aliases the table and attributes properly' do - pending aliased_relation = @relation1.as(:alias) @relation1.join(aliased_relation).on(@relation1[:id].eq(aliased_relation[:id])).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `alias`.`id`, `alias`.`name` FROM `users` - INNER JOIN `alias` + INNER JOIN `users` AS `alias` ON `users`.`id` = `alias`.`id` ") end From 04c8e48311231d0b8332a7050a48defc9d7b075e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Apr 2008 18:45:20 -0700 Subject: [PATCH 0124/1492] new conception of grouping and aggregation functionality --- lib/active_relation/primitives/attribute.rb | 10 +++--- lib/active_relation/primitives/expression.rb | 4 +++ lib/active_relation/relations.rb | 2 +- lib/active_relation/relations/aggregation.rb | 24 -------------- lib/active_relation/relations/grouping.rb | 19 +++++++++++ lib/active_relation/relations/projection.rb | 4 +++ lib/active_relation/relations/relation.rb | 10 ++---- .../unit/relations/grouping_spec.rb | 33 +++++++++++++++++++ .../unit/relations/join_spec.rb | 2 +- .../unit/relations/projection_spec.rb | 23 ++++++++++--- .../unit/relations/relation_spec.rb | 17 ++++------ 11 files changed, 95 insertions(+), 53 deletions(-) delete mode 100644 lib/active_relation/relations/aggregation.rb create mode 100644 lib/active_relation/relations/grouping.rb create mode 100644 spec/active_relation/unit/relations/grouping_spec.rb diff --git a/lib/active_relation/primitives/attribute.rb b/lib/active_relation/primitives/attribute.rb index d37271490aa05..5b1ef4d7c041e 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -10,6 +10,10 @@ def initialize(relation, name, options = {}) def alias_or_name @alias || name end + + def aggregation? + false + end module Transformations def as(aliaz = nil) @@ -56,10 +60,8 @@ def =~(other) end def %(other) - if other - (history - other.history) + (other.history - history) - else - history + if other then (history - other.history) + (other.history - history) + else history end end end diff --git a/lib/active_relation/primitives/expression.rb b/lib/active_relation/primitives/expression.rb index 2df2888ba0122..ae4c61d1b1d24 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -29,6 +29,10 @@ def to_sql(formatter = nil) "#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '') end + def aggregation? + true + end + def ==(other) self.class == other.class and attribute == other.attribute and diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb index 9cede2a6d181e..d8e211c85392a 100644 --- a/lib/active_relation/relations.rb +++ b/lib/active_relation/relations.rb @@ -4,7 +4,7 @@ require 'active_relation/relations/writing' require 'active_relation/relations/table' require 'active_relation/relations/join' -require 'active_relation/relations/aggregation' +require 'active_relation/relations/grouping' require 'active_relation/relations/projection' require 'active_relation/relations/selection' require 'active_relation/relations/order' diff --git a/lib/active_relation/relations/aggregation.rb b/lib/active_relation/relations/aggregation.rb deleted file mode 100644 index 62432408e18dd..0000000000000 --- a/lib/active_relation/relations/aggregation.rb +++ /dev/null @@ -1,24 +0,0 @@ -module ActiveRelation - class Aggregation < Compound - attr_reader :expressions, :groupings - - def initialize(relation, options) - @relation, @expressions, @groupings = relation, options[:expressions], options[:groupings] - end - - def ==(other) - self.class == other.class and - relation == other.relation and - groupings == other.groupings and - expressions == other.expressions - end - - def attributes - expressions.collect { |e| e.bind(self) } - end - - def aggregation? - true - end - end -end \ No newline at end of file diff --git a/lib/active_relation/relations/grouping.rb b/lib/active_relation/relations/grouping.rb new file mode 100644 index 0000000000000..57323e90f308f --- /dev/null +++ b/lib/active_relation/relations/grouping.rb @@ -0,0 +1,19 @@ +module ActiveRelation + class Grouping < Compound + attr_reader :expressions, :groupings + + def initialize(relation, *groupings) + @relation, @groupings = relation, groupings.collect { |g| g.bind(relation) } + end + + def ==(other) + self.class == other.class and + relation == other.relation and + groupings == other.groupings + end + + def aggregation? + true + end + end +end \ No newline at end of file diff --git a/lib/active_relation/relations/projection.rb b/lib/active_relation/relations/projection.rb index c1495c1742bae..0f8ea5175c847 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/active_relation/relations/projection.rb @@ -15,5 +15,9 @@ def ==(other) relation == other.relation and projections == other.projections end + + def aggregation? + attributes.any?(&:aggregation?) + end end end \ No newline at end of file diff --git a/lib/active_relation/relations/relation.rb b/lib/active_relation/relations/relation.rb index b62a5d9fb9cc6..8ab266c53dac1 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -66,8 +66,8 @@ def skip(skipped = nil) skipped.blank?? self : Skip.new(self, skipped) end - def aggregate(*expressions) - AggregateOperation.new(self, expressions) + def group(*groupings) + groupings.all?(&:blank?) ? self : Grouping.new(self, *groupings) end module Writes @@ -90,12 +90,6 @@ def on(*predicates) Join.new(join_sql, relation1, relation2, *predicates) end end - - AggregateOperation = Struct.new(:relation, :expressions) do - def group(*groupings) - Aggregation.new(relation, :expressions => expressions, :groupings => groupings) - end - end end include Operations diff --git a/spec/active_relation/unit/relations/grouping_spec.rb b/spec/active_relation/unit/relations/grouping_spec.rb new file mode 100644 index 0000000000000..4b5badbb8b5ff --- /dev/null +++ b/spec/active_relation/unit/relations/grouping_spec.rb @@ -0,0 +1,33 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module ActiveRelation + describe Grouping do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#to_sql' do + describe 'when given a predicate' do + it "manufactures sql with where clause conditions" do + Grouping.new(@relation, @attribute).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY `users`.`id` + ") + end + end + + describe 'when given a string' do + it "passes the string through to the where clause" do + pending 'it should not quote asdf' + Grouping.new(@relation, 'asdf').to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY asdf + ") + end + end + end + end +end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/active_relation/unit/relations/join_spec.rb index 22b0a9f2373a7..c1a13cee6e0d5 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/active_relation/unit/relations/join_spec.rb @@ -97,8 +97,8 @@ module ActiveRelation describe 'when joining aggregated relations' do before do @aggregation = @relation2 \ - .aggregate(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ .group(@relation2[:user_id]) \ + .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ .as('photo_count') end diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/active_relation/unit/relations/projection_spec.rb index 529998a8d4cb3..5936cbc45f7b8 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/active_relation/unit/relations/projection_spec.rb @@ -53,16 +53,29 @@ module ActiveRelation end describe 'when given a string' do - before do - @string = "asdf" - end - it "passes the string through to the select clause" do - Projection.new(@relation, @string).to_sql.should be_like(" + Projection.new(@relation, 'asdf').to_sql.should be_like(" SELECT asdf FROM `users` ") end end end + + describe Projection::Externalizable do + describe '#aggregation?' do + describe 'when the projections are attributes' do + it 'returns false' do + Projection.new(@relation, @attribute).should_not be_aggregation + end + end + + describe 'when the projections include an aggregation' do + it "obtains" do + Projection.new(@relation, @attribute.sum).should be_aggregation + end + end + end + + end end end \ No newline at end of file diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 2b62c8db5ed45..c40974e136197 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -154,18 +154,15 @@ module ActiveRelation end end - describe '#aggregate' do - before do - @expression1 = @attribute1.sum - @expression2 = @attribute2.sum + describe '#group' do + it 'manufactures a group relation' do + @relation.group(@attribute1, @attribute2).should == Grouping.new(@relation, @attribute1, @attribute2) end - it 'manufactures a group relation' do - @relation.aggregate(@expression1, @expression2).group(@attribute1, @attribute2). \ - should == Aggregation.new(@relation, - :expressions => [@expression1, @expression2], - :groupings => [@attribute1, @attribute2] - ) + describe 'when given blank groupings' do + it 'returns self' do + @relation.group.should == @relation + end end end From 61cdfe916cbe822faff5cd52480c45126bde244e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Apr 2008 19:20:05 -0700 Subject: [PATCH 0125/1492] implementing one pending feature --- lib/active_relation/relations/insertion.rb | 4 +-- .../unit/relations/insertion_spec.rb | 33 +++++++++---------- spec/spec_helper.rb | 1 + 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/lib/active_relation/relations/insertion.rb b/lib/active_relation/relations/insertion.rb index 30de6819f1c70..58defe4b016e3 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -10,8 +10,8 @@ def to_sql(formatter = nil) [ "INSERT", "INTO #{table_sql}", - "(#{record.keys.collect(&:to_sql)})", - "VALUES (#{record.collect { |key, value| key.format(value) }})" + "(#{record.keys.collect(&:to_sql).join(', ')})", + "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" ].join("\n") end diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/active_relation/unit/relations/insertion_spec.rb index e1718e3b25867..543e2d51a985e 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/active_relation/unit/relations/insertion_spec.rb @@ -8,27 +8,24 @@ module ActiveRelation describe '#to_sql' do it 'manufactures sql inserting data when given multiple rows' do - pending do - @insertion = Insertion.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) - - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`users`.`name`) VALUES ('nick'), ('bryan') - ") - end + pending 'it should insert multiple rows' + @insertion = Insertion.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) + + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`name`) VALUES ('nick'), ('bryan') + ") end it 'manufactures sql inserting data when given multiple values' do - pending do - @insertion = Insertion.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") - - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`users`.`name`, `users`.`id`) VALUES ('nick', 1) - ") - end + @insertion = Insertion.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") + + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`users`.`id`, `users`.`name`) VALUES (1, 'nick') + ") end describe 'when given values whose types correspond to the types of the attributes' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b633d17257fe8..0d1613e223ab6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,7 @@ require 'rubygems' require 'spec' require 'pp' +require 'fileutils' dir = File.dirname(__FILE__) $LOAD_PATH.unshift "#{dir}/../lib" Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" } From 7a93ce0b1e8560ef5bad7cb7f7a170507bfde16d Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Apr 2008 19:23:23 -0700 Subject: [PATCH 0126/1492] fixed problem with updating multiple values --- lib/active_relation/relations/update.rb | 2 +- spec/active_relation/unit/relations/deletion_spec.rb | 2 +- spec/active_relation/unit/relations/update_spec.rb | 12 +++++------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index 46aafd38a5521..5a7be3129052e 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -11,7 +11,7 @@ def to_sql(formatter = nil) "UPDATE #{table_sql} SET", assignments.collect do |attribute, value| "#{value.format(attribute)} = #{attribute.format(value)}" - end.join("\n"), + end.join(",\n"), ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) ].join("\n") end diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb index 72f3f81b2a672..46a962cb5c8f8 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -24,7 +24,7 @@ module ActiveRelation it "manufactures sql deleting a ranged relation" do pending do - Deletion.new(@relation[0..0]).to_sql.should be_like(" + Deletion.new(@relation.take(1)).to_sql.should be_like(" DELETE FROM `users` LIMIT 1 diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 6634dc67d174d..969b17436f12b 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -8,17 +8,15 @@ module ActiveRelation describe '#to_sql' do it "manufactures sql updating attributes when given multiple attributes" do - pending do - Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" - UPDATE `users` - SET `users`.`name` = 'nick', `users`.`id` = 1 - ") - end + Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" + UPDATE `users` + SET `users`.`id` = 1, `users`.`name` = 'nick' + ") end it "manufactures sql updating attributes when given a ranged relation" do pending do - Update.new(@relation[0..0], @relation[:name] => "nick").to_sql.should be_like(" + Update.new(@relation.take(1), @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` SET `users`.`name` = 'nick' LIMIT 1 From 722623dab397427df7a99b7aeefe4356cadcce25 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 13 Apr 2008 19:55:07 -0700 Subject: [PATCH 0127/1492] adding limit options to update and destroy --- lib/active_relation/relations/deletion.rb | 3 ++- lib/active_relation/relations/update.rb | 3 ++- spec/active_relation/unit/relations/deletion_spec.rb | 12 +++++------- spec/active_relation/unit/relations/update_spec.rb | 12 +++++------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/active_relation/relations/deletion.rb b/lib/active_relation/relations/deletion.rb index 1b94df8729707..f1d121d68fe2e 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/active_relation/relations/deletion.rb @@ -8,7 +8,8 @@ def to_sql(formatter = nil) [ "DELETE", "FROM #{table_sql}", - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), ].compact.join("\n") end diff --git a/lib/active_relation/relations/update.rb b/lib/active_relation/relations/update.rb index 5a7be3129052e..6262ead1870e0 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -12,7 +12,8 @@ def to_sql(formatter = nil) assignments.collect do |attribute, value| "#{value.format(attribute)} = #{attribute.format(value)}" end.join(",\n"), - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank?) + ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) ].join("\n") end diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/active_relation/unit/relations/deletion_spec.rb index 46a962cb5c8f8..08f7bc03bbef5 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/active_relation/unit/relations/deletion_spec.rb @@ -23,13 +23,11 @@ module ActiveRelation end it "manufactures sql deleting a ranged relation" do - pending do - Deletion.new(@relation.take(1)).to_sql.should be_like(" - DELETE - FROM `users` - LIMIT 1 - ") - end + Deletion.new(@relation.take(1)).to_sql.should be_like(" + DELETE + FROM `users` + LIMIT 1 + ") end end diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 969b17436f12b..24beb315e5461 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -15,13 +15,11 @@ module ActiveRelation end it "manufactures sql updating attributes when given a ranged relation" do - pending do - Update.new(@relation.take(1), @relation[:name] => "nick").to_sql.should be_like(" - UPDATE `users` - SET `users`.`name` = 'nick' - LIMIT 1 - ") - end + Update.new(@relation.take(1), @relation[:name] => "nick").to_sql.should be_like(" + UPDATE `users` + SET `users`.`name` = 'nick' + LIMIT 1 + ") end describe 'when given values whose types correspond to the types of the attributes' do From 5a2d4f5475b8a040e2ed2da826afe50f0b3824c7 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 15 Apr 2008 01:24:15 -0400 Subject: [PATCH 0128/1492] Fake database implementation. MySQL not required to run the tests --- config/database.yml.example | 6 -- doc/TODO | 2 +- schema.sql | 126 ------------------------------------ spec/fakes/database.rb | 48 ++++++++++++++ spec/spec_helper.rb | 8 +-- 5 files changed, 51 insertions(+), 139 deletions(-) delete mode 100644 config/database.yml.example delete mode 100644 schema.sql create mode 100644 spec/fakes/database.rb diff --git a/config/database.yml.example b/config/database.yml.example deleted file mode 100644 index 2230912f7d531..0000000000000 --- a/config/database.yml.example +++ /dev/null @@ -1,6 +0,0 @@ -test: - adapter: mysql - username: root - password: password - encoding: utf8 - database: sql_algebra_test diff --git a/doc/TODO b/doc/TODO index 16cbc0d77a611..7a6be568e892d 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,13 +1,13 @@ todo: - rename ActiveRelation to arel - incorporate linq vocabularity -- mock out database - fix complex joining cases: - extract adapters - cache expiry on write - rewrite of arecord querycache test in light of this done: +- mock out database . Relation <=> Relation -> InnerJoinOperation . Relation << Relation -> LeftOuterJoinOperation . InnerJoinOperation.on(*Predicate) -> InnerJoinRelation diff --git a/schema.sql b/schema.sql deleted file mode 100644 index d42eb9694424e..0000000000000 --- a/schema.sql +++ /dev/null @@ -1,126 +0,0 @@ --- MySQL dump 10.10 --- --- Host: localhost Database: sql_algebra_test --- ------------------------------------------------------ --- Server version 5.0.27-standard - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; -/*!40103 SET TIME_ZONE='+00:00' */; -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - --- --- Table structure for table `bar` --- - -DROP TABLE IF EXISTS `bar`; -CREATE TABLE `bar` ( - `id` int(11) default NULL, - `name` varchar(255) default NULL, - `foo_id` int(11) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Dumping data for table `bar` --- - -LOCK TABLES `bar` WRITE; -/*!40000 ALTER TABLE `bar` DISABLE KEYS */; -/*!40000 ALTER TABLE `bar` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `cameras` --- - -DROP TABLE IF EXISTS `cameras`; -CREATE TABLE `cameras` ( - `id` int(11) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Dumping data for table `cameras` --- - -LOCK TABLES `cameras` WRITE; -/*!40000 ALTER TABLE `cameras` DISABLE KEYS */; -INSERT INTO `cameras` VALUES (1); -/*!40000 ALTER TABLE `cameras` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `foo` --- - -DROP TABLE IF EXISTS `foo`; -CREATE TABLE `foo` ( - `id` int(11) default NULL, - `name` varchar(255) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Dumping data for table `foo` --- - -LOCK TABLES `foo` WRITE; -/*!40000 ALTER TABLE `foo` DISABLE KEYS */; -/*!40000 ALTER TABLE `foo` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `photos` --- - -DROP TABLE IF EXISTS `photos`; -CREATE TABLE `photos` ( - `id` int(11) default NULL, - `user_id` int(11) default NULL, - `camera_id` int(11) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Dumping data for table `photos` --- - -LOCK TABLES `photos` WRITE; -/*!40000 ALTER TABLE `photos` DISABLE KEYS */; -INSERT INTO `photos` VALUES (1,1,1); -/*!40000 ALTER TABLE `photos` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `users` --- - -DROP TABLE IF EXISTS `users`; -CREATE TABLE `users` ( - `id` int(11) default NULL, - `name` varchar(255) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Dumping data for table `users` --- - -LOCK TABLES `users` WRITE; -/*!40000 ALTER TABLE `users` DISABLE KEYS */; -INSERT INTO `users` VALUES (1,'hai'),(NULL,'bai'),(NULL,'dumpty'); -/*!40000 ALTER TABLE `users` ENABLE KEYS */; -UNLOCK TABLES; -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; - -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; - --- Dump completed on 2008-01-11 7:15:17 diff --git a/spec/fakes/database.rb b/spec/fakes/database.rb new file mode 100644 index 0000000000000..1b73986e0b484 --- /dev/null +++ b/spec/fakes/database.rb @@ -0,0 +1,48 @@ +class FakeDatabase + def self.connection + @@conn ||= FakeConnection.new + end +end + +class FakeConnection + include ActiveRecord::ConnectionAdapters::Quoting + + def columns(table_name, comment) + case table_name + when "users" + [ + FakeColumn.new("id", :integer), + FakeColumn.new("name", :string) + ] + when "photos" + [ + FakeColumn.new("id", :integer), + FakeColumn.new("user_id", :integer), + FakeColumn.new("camera_id", :integer) + ] + else + raise "unknown table: #{table_name}" + end + end + + def select_all(*args) + [] + end + + def quote_column_name(column_name) + "`#{column_name}`" + end + + def quote_table_name(table_name) + "`#{table_name}`" + end +end + +class FakeColumn + attr_reader :name, :type + + def initialize(name, type) + @name = name + @type = type + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0d1613e223ab6..af4e71d2d3978 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,11 +6,7 @@ $LOAD_PATH.unshift "#{dir}/../lib" Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" } require 'active_relation' - -FileUtils.cp("#{dir}/../config/database.yml.example", "#{dir}/../config/database.yml") unless File.exist?("#{dir}/../config/database.yml") - -ActiveRecord::Base.configurations = YAML::load(IO.read("#{dir}/../config/database.yml")) -ActiveRecord::Base.establish_connection 'test' +require "#{dir}/fakes/database" class Hash def shift @@ -24,6 +20,6 @@ def shift config.include(BeLikeMatcher, HashTheSameAsMatcher) config.mock_with :rr config.before do - ActiveRelation::Table.engine = ActiveRelation::Engine.new(ActiveRecord::Base) + ActiveRelation::Table.engine = ActiveRelation::Engine.new(FakeDatabase) end end \ No newline at end of file From 3d3e15985218c329b9d0507d389bb1e56eba99d2 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 14 Apr 2008 23:38:50 -0700 Subject: [PATCH 0129/1492] - fixed hash ordering - organized doubles (previously called 'fakes') --- .../unit/relations/relation_spec.rb | 1 - .../unit/relations/update_spec.rb | 2 +- spec/doubles/database.rb | 47 ++++++++++++++++++ spec/doubles/hash.rb | 23 +++++++++ spec/fakes/database.rb | 48 ------------------- spec/spec_helper.rb | 17 +++---- 6 files changed, 77 insertions(+), 61 deletions(-) create mode 100644 spec/doubles/database.rb create mode 100644 spec/doubles/hash.rb delete mode 100644 spec/fakes/database.rb diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index c40974e136197..0509c19c946ce 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -201,7 +201,6 @@ module ActiveRelation describe Relation::Enumerable do it "implements enumerable" do @relation.collect.should == @relation.session.read(@relation) - @relation.first.should == @relation.session.read(@relation).first end end diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/active_relation/unit/relations/update_spec.rb index 24beb315e5461..29dd4e12dd544 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/active_relation/unit/relations/update_spec.rb @@ -5,7 +5,7 @@ module ActiveRelation before do @relation = Table.new(:users) end - + describe '#to_sql' do it "manufactures sql updating attributes when given multiple attributes" do Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb new file mode 100644 index 0000000000000..cc445966908d6 --- /dev/null +++ b/spec/doubles/database.rb @@ -0,0 +1,47 @@ +module Fake + class Engine + def connection + @conn ||= Connection.new + end + end + + class Connection + include ActiveRecord::ConnectionAdapters::Quoting + + def columns(table_name, comment) + { "users" => + [ + Column.new("id", :integer), + Column.new("name", :string) + ], + "photos" => + [ + Column.new("id", :integer), + Column.new("user_id", :integer), + Column.new("camera_id", :integer) + ] + }[table_name] + end + + def select_all(*args) + [] + end + + def quote_column_name(column_name) + "`#{column_name}`" + end + + def quote_table_name(table_name) + "`#{table_name}`" + end + end + + class Column + attr_reader :name, :type + + def initialize(name, type) + @name = name + @type = type + end + end +end \ No newline at end of file diff --git a/spec/doubles/hash.rb b/spec/doubles/hash.rb new file mode 100644 index 0000000000000..97d25742cbabd --- /dev/null +++ b/spec/doubles/hash.rb @@ -0,0 +1,23 @@ +class Hash + def ordered_array + to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash } + end + + def keys + ordered_array.collect(&:first) + end + + def values + ordered_array.collect { |_, v| v } + end + + def each(&block) + ordered_array.each(&block) + end + + def shift + returning to_a.first do |k, v| + delete(k) + end + end +end diff --git a/spec/fakes/database.rb b/spec/fakes/database.rb deleted file mode 100644 index 1b73986e0b484..0000000000000 --- a/spec/fakes/database.rb +++ /dev/null @@ -1,48 +0,0 @@ -class FakeDatabase - def self.connection - @@conn ||= FakeConnection.new - end -end - -class FakeConnection - include ActiveRecord::ConnectionAdapters::Quoting - - def columns(table_name, comment) - case table_name - when "users" - [ - FakeColumn.new("id", :integer), - FakeColumn.new("name", :string) - ] - when "photos" - [ - FakeColumn.new("id", :integer), - FakeColumn.new("user_id", :integer), - FakeColumn.new("camera_id", :integer) - ] - else - raise "unknown table: #{table_name}" - end - end - - def select_all(*args) - [] - end - - def quote_column_name(column_name) - "`#{column_name}`" - end - - def quote_table_name(table_name) - "`#{table_name}`" - end -end - -class FakeColumn - attr_reader :name, :type - - def initialize(name, type) - @name = name - @type = type - end -end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index af4e71d2d3978..6180f822bd4fc 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,25 +1,20 @@ +dir = File.dirname(__FILE__) +$LOAD_PATH.unshift "#{dir}/../lib" + require 'rubygems' require 'spec' require 'pp' require 'fileutils' -dir = File.dirname(__FILE__) -$LOAD_PATH.unshift "#{dir}/../lib" -Dir["#{dir}/matchers/*"].each { |m| require "#{dir}/matchers/#{File.basename(m)}" } require 'active_relation' -require "#{dir}/fakes/database" -class Hash - def shift - returning to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash }.shift do |key, _| - delete(key) - end - end +[:matchers, :doubles].each do |helper| + Dir["#{dir}/#{helper}/*"].each { |m| require "#{dir}/#{helper}/#{File.basename(m)}" } end Spec::Runner.configure do |config| config.include(BeLikeMatcher, HashTheSameAsMatcher) config.mock_with :rr config.before do - ActiveRelation::Table.engine = ActiveRelation::Engine.new(FakeDatabase) + ActiveRelation::Table.engine = ActiveRelation::Engine.new(Fake::Engine.new) end end \ No newline at end of file From d27ab7bb8ba0d8f136af2ed955d9e489ba45daec Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 14 Apr 2008 23:40:01 -0700 Subject: [PATCH 0130/1492] test is meaningless but serves as documentation --- spec/active_relation/unit/relations/relation_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/active_relation/unit/relations/relation_spec.rb index 0509c19c946ce..c40974e136197 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/active_relation/unit/relations/relation_spec.rb @@ -201,6 +201,7 @@ module ActiveRelation describe Relation::Enumerable do it "implements enumerable" do @relation.collect.should == @relation.session.read(@relation) + @relation.first.should == @relation.session.read(@relation).first end end From d51139751eae2be6ee32b44edec39fcf09ed2333 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 18 Apr 2008 12:59:29 -0700 Subject: [PATCH 0131/1492] officially renamed active_relation to arel --- README | 10 +++++----- doc/TODO | 2 +- lib/active_relation.rb | 12 ------------ lib/active_relation/engines.rb | 1 - lib/active_relation/extensions.rb | 6 ------ lib/active_relation/primitives.rb | 4 ---- lib/active_relation/relations.rb | 17 ----------------- lib/arel.rb | 12 ++++++++++++ lib/{active_relation => arel}/.DS_Store | Bin lib/arel/engines.rb | 1 + .../engines/engine.rb | 2 +- lib/arel/extensions.rb | 6 ++++++ .../extensions/array.rb | 0 .../extensions/class.rb | 0 .../extensions/hash.rb | 0 .../extensions/nil_class.rb | 0 .../extensions/object.rb | 2 +- .../extensions/range.rb | 0 lib/{active_relation => arel}/predicates.rb | 2 +- lib/arel/primitives.rb | 4 ++++ .../primitives/attribute.rb | 2 +- .../primitives/expression.rb | 2 +- .../primitives/value.rb | 2 +- lib/arel/relations.rb | 17 +++++++++++++++++ .../relations/alias.rb | 2 +- .../relations/compound.rb | 2 +- .../relations/deletion.rb | 2 +- .../relations/grouping.rb | 2 +- .../relations/insertion.rb | 2 +- .../relations/join.rb | 2 +- lib/{active_relation => arel}/relations/nil.rb | 2 +- .../relations/order.rb | 2 +- .../relations/projection.rb | 2 +- .../relations/relation.rb | 2 +- .../relations/selection.rb | 2 +- .../relations/skip.rb | 2 +- .../relations/table.rb | 2 +- .../relations/take.rb | 2 +- .../relations/update.rb | 2 +- .../relations/writing.rb | 2 +- .../sessions/session.rb | 2 +- lib/{active_relation => arel}/sql.rb | 2 +- .../unit/predicates/binary_spec.rb | 2 +- .../unit/predicates/equality_spec.rb | 2 +- .../unit/predicates/in_spec.rb | 2 +- .../unit/primitives/attribute_spec.rb | 2 +- .../unit/primitives/expression_spec.rb | 2 +- .../unit/primitives/value_spec.rb | 2 +- .../unit/relations/alias_spec.rb | 2 +- .../unit/relations/compound_spec.rb | 2 +- .../unit/relations/deletion_spec.rb | 2 +- .../unit/relations/grouping_spec.rb | 2 +- .../unit/relations/insertion_spec.rb | 2 +- .../unit/relations/join_spec.rb | 2 +- .../unit/relations/order_spec.rb | 2 +- .../unit/relations/projection_spec.rb | 2 +- .../unit/relations/relation_spec.rb | 2 +- .../unit/relations/selection_spec.rb | 2 +- .../unit/relations/skip_spec.rb | 2 +- .../unit/relations/table_spec.rb | 2 +- .../unit/relations/take_spec.rb | 2 +- .../unit/relations/update_spec.rb | 2 +- .../unit/session/session_spec.rb | 2 +- spec/spec_helper.rb | 4 ++-- 64 files changed, 93 insertions(+), 93 deletions(-) delete mode 100644 lib/active_relation.rb delete mode 100644 lib/active_relation/engines.rb delete mode 100644 lib/active_relation/extensions.rb delete mode 100644 lib/active_relation/primitives.rb delete mode 100644 lib/active_relation/relations.rb create mode 100644 lib/arel.rb rename lib/{active_relation => arel}/.DS_Store (100%) create mode 100644 lib/arel/engines.rb rename lib/{active_relation => arel}/engines/engine.rb (95%) create mode 100644 lib/arel/extensions.rb rename lib/{active_relation => arel}/extensions/array.rb (100%) rename lib/{active_relation => arel}/extensions/class.rb (100%) rename lib/{active_relation => arel}/extensions/hash.rb (100%) rename lib/{active_relation => arel}/extensions/nil_class.rb (100%) rename lib/{active_relation => arel}/extensions/object.rb (81%) rename lib/{active_relation => arel}/extensions/range.rb (100%) rename lib/{active_relation => arel}/predicates.rb (98%) create mode 100644 lib/arel/primitives.rb rename lib/{active_relation => arel}/primitives/attribute.rb (99%) rename lib/{active_relation => arel}/primitives/expression.rb (98%) rename lib/{active_relation => arel}/primitives/value.rb (95%) create mode 100644 lib/arel/relations.rb rename lib/{active_relation => arel}/relations/alias.rb (92%) rename lib/{active_relation => arel}/relations/compound.rb (94%) rename lib/{active_relation => arel}/relations/deletion.rb (95%) rename lib/{active_relation => arel}/relations/grouping.rb (94%) rename lib/{active_relation => arel}/relations/insertion.rb (96%) rename lib/{active_relation => arel}/relations/join.rb (99%) rename lib/{active_relation => arel}/relations/nil.rb (85%) rename lib/{active_relation => arel}/relations/order.rb (94%) rename lib/{active_relation => arel}/relations/projection.rb (94%) rename lib/{active_relation => arel}/relations/relation.rb (99%) rename lib/{active_relation => arel}/relations/selection.rb (95%) rename lib/{active_relation => arel}/relations/skip.rb (92%) rename lib/{active_relation => arel}/relations/table.rb (97%) rename lib/{active_relation => arel}/relations/take.rb (91%) rename lib/{active_relation => arel}/relations/update.rb (97%) rename lib/{active_relation => arel}/relations/writing.rb (56%) rename lib/{active_relation => arel}/sessions/session.rb (97%) rename lib/{active_relation => arel}/sql.rb (98%) rename spec/{active_relation => arel}/unit/predicates/binary_spec.rb (98%) rename spec/{active_relation => arel}/unit/predicates/equality_spec.rb (98%) rename spec/{active_relation => arel}/unit/predicates/in_spec.rb (98%) rename spec/{active_relation => arel}/unit/primitives/attribute_spec.rb (99%) rename spec/{active_relation => arel}/unit/primitives/expression_spec.rb (98%) rename spec/{active_relation => arel}/unit/primitives/value_spec.rb (96%) rename spec/{active_relation => arel}/unit/relations/alias_spec.rb (93%) rename spec/{active_relation => arel}/unit/relations/compound_spec.rb (97%) rename spec/{active_relation => arel}/unit/relations/deletion_spec.rb (97%) rename spec/{active_relation => arel}/unit/relations/grouping_spec.rb (97%) rename spec/{active_relation => arel}/unit/relations/insertion_spec.rb (98%) rename spec/{active_relation => arel}/unit/relations/join_spec.rb (99%) rename spec/{active_relation => arel}/unit/relations/order_spec.rb (98%) rename spec/{active_relation => arel}/unit/relations/projection_spec.rb (99%) rename spec/{active_relation => arel}/unit/relations/relation_spec.rb (99%) rename spec/{active_relation => arel}/unit/relations/selection_spec.rb (98%) rename spec/{active_relation => arel}/unit/relations/skip_spec.rb (94%) rename spec/{active_relation => arel}/unit/relations/table_spec.rb (99%) rename spec/{active_relation => arel}/unit/relations/take_spec.rb (94%) rename spec/{active_relation => arel}/unit/relations/update_spec.rb (98%) rename spec/{active_relation => arel}/unit/session/session_spec.rb (98%) diff --git a/README b/README index 87e9678df609f..bb8c6eb71a497 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ == Abstract == -ActiveRelation is a Relational Algebra for Ruby. It 1) simplifies the generation of both the simplest and the most complex of SQL queries and it 2) transparently 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. +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation of both the simplest and the most complex of SQL queries and it 2) transparently 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. == A Gentle Introduction == @@ -10,9 +10,9 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: - ActiveRelation::Table.new(:users).to_sql + Arel::Table.new(:users).to_sql -In fact, you will probably never call `#to_sql`. Let `users = ActiveRelation::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: +In fact, you will probably never call `#to_sql`. Let `users = Arel::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: users.each { |user| ... } @@ -24,7 +24,7 @@ As you can see, Arel converts the rows from the database into a hash, the values == Relational Algebra == -Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: +Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. Arel::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: users.insert({users[:name] => 'amy'}) # => INSERT INTO users (users.name) VALUES ('amy') @@ -62,4 +62,4 @@ The best property of the Relational is compositionality, or closure under all op == Contributions == -I appreciate all contributions to ActiveRelation. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. \ No newline at end of file +I appreciate all contributions to Arel. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. \ No newline at end of file diff --git a/doc/TODO b/doc/TODO index 7a6be568e892d..a51a730c90336 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,5 @@ todo: -- rename ActiveRelation to arel +- rename Arel to arel - incorporate linq vocabularity - fix complex joining cases: - extract adapters diff --git a/lib/active_relation.rb b/lib/active_relation.rb deleted file mode 100644 index 5b5c91706fd9b..0000000000000 --- a/lib/active_relation.rb +++ /dev/null @@ -1,12 +0,0 @@ -$LOAD_PATH.unshift(File.dirname(__FILE__)) - -require 'rubygems' -require 'activesupport' -require 'activerecord' - -require 'active_relation/extensions' -require 'active_relation/sql' -require 'active_relation/predicates' -require 'active_relation/relations' -require 'active_relation/engines' -require 'active_relation/primitives' \ No newline at end of file diff --git a/lib/active_relation/engines.rb b/lib/active_relation/engines.rb deleted file mode 100644 index 55eb817b88318..0000000000000 --- a/lib/active_relation/engines.rb +++ /dev/null @@ -1 +0,0 @@ -require 'active_relation/engines/engine' \ No newline at end of file diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb deleted file mode 100644 index ded830eb8c588..0000000000000 --- a/lib/active_relation/extensions.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'active_relation/extensions/object' -require 'active_relation/extensions/class' -require 'active_relation/extensions/array' -require 'active_relation/extensions/hash' -require 'active_relation/extensions/range' -require 'active_relation/extensions/nil_class' \ No newline at end of file diff --git a/lib/active_relation/primitives.rb b/lib/active_relation/primitives.rb deleted file mode 100644 index 9909734d24ec8..0000000000000 --- a/lib/active_relation/primitives.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'active_relation/primitives/attribute' -require 'active_relation/primitives/value' -require 'active_relation/primitives/expression' - diff --git a/lib/active_relation/relations.rb b/lib/active_relation/relations.rb deleted file mode 100644 index d8e211c85392a..0000000000000 --- a/lib/active_relation/relations.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'active_relation/relations/relation' -require 'active_relation/relations/nil' -require 'active_relation/relations/compound' -require 'active_relation/relations/writing' -require 'active_relation/relations/table' -require 'active_relation/relations/join' -require 'active_relation/relations/grouping' -require 'active_relation/relations/projection' -require 'active_relation/relations/selection' -require 'active_relation/relations/order' -require 'active_relation/relations/take' -require 'active_relation/relations/skip' -require 'active_relation/relations/deletion' -require 'active_relation/relations/insertion' -require 'active_relation/relations/update' -require 'active_relation/relations/alias' -require 'active_relation/sessions/session' \ No newline at end of file diff --git a/lib/arel.rb b/lib/arel.rb new file mode 100644 index 0000000000000..75489c9c6e5cc --- /dev/null +++ b/lib/arel.rb @@ -0,0 +1,12 @@ +$LOAD_PATH.unshift(File.dirname(__FILE__)) + +require 'rubygems' +require 'activesupport' +require 'activerecord' + +require 'arel/extensions' +require 'arel/sql' +require 'arel/predicates' +require 'arel/relations' +require 'arel/engines' +require 'arel/primitives' \ No newline at end of file diff --git a/lib/active_relation/.DS_Store b/lib/arel/.DS_Store similarity index 100% rename from lib/active_relation/.DS_Store rename to lib/arel/.DS_Store diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb new file mode 100644 index 0000000000000..bb71537e9c890 --- /dev/null +++ b/lib/arel/engines.rb @@ -0,0 +1 @@ +require 'arel/engines/engine' \ No newline at end of file diff --git a/lib/active_relation/engines/engine.rb b/lib/arel/engines/engine.rb similarity index 95% rename from lib/active_relation/engines/engine.rb rename to lib/arel/engines/engine.rb index d5b312607ec3f..b0b7b4e95501f 100644 --- a/lib/active_relation/engines/engine.rb +++ b/lib/arel/engines/engine.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel # this file is currently just a hack to adapt between activerecord::base which holds the connection specification # and active relation. ultimately, this file should be in effect what the connection specification is in active record; # that is: a spec of the database (url, password, etc.), a quoting adapter layer, and a connection pool. diff --git a/lib/arel/extensions.rb b/lib/arel/extensions.rb new file mode 100644 index 0000000000000..160cf36e5b379 --- /dev/null +++ b/lib/arel/extensions.rb @@ -0,0 +1,6 @@ +require 'arel/extensions/object' +require 'arel/extensions/class' +require 'arel/extensions/array' +require 'arel/extensions/hash' +require 'arel/extensions/range' +require 'arel/extensions/nil_class' \ No newline at end of file diff --git a/lib/active_relation/extensions/array.rb b/lib/arel/extensions/array.rb similarity index 100% rename from lib/active_relation/extensions/array.rb rename to lib/arel/extensions/array.rb diff --git a/lib/active_relation/extensions/class.rb b/lib/arel/extensions/class.rb similarity index 100% rename from lib/active_relation/extensions/class.rb rename to lib/arel/extensions/class.rb diff --git a/lib/active_relation/extensions/hash.rb b/lib/arel/extensions/hash.rb similarity index 100% rename from lib/active_relation/extensions/hash.rb rename to lib/arel/extensions/hash.rb diff --git a/lib/active_relation/extensions/nil_class.rb b/lib/arel/extensions/nil_class.rb similarity index 100% rename from lib/active_relation/extensions/nil_class.rb rename to lib/arel/extensions/nil_class.rb diff --git a/lib/active_relation/extensions/object.rb b/lib/arel/extensions/object.rb similarity index 81% rename from lib/active_relation/extensions/object.rb rename to lib/arel/extensions/object.rb index 25cef989a4ee1..779098f7ea487 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -1,6 +1,6 @@ class Object def bind(relation) - ActiveRelation::Value.new(self, relation) + Arel::Value.new(self, relation) end def to_sql(formatter = nil) diff --git a/lib/active_relation/extensions/range.rb b/lib/arel/extensions/range.rb similarity index 100% rename from lib/active_relation/extensions/range.rb rename to lib/arel/extensions/range.rb diff --git a/lib/active_relation/predicates.rb b/lib/arel/predicates.rb similarity index 98% rename from lib/active_relation/predicates.rb rename to lib/arel/predicates.rb index 2cab1721d084e..ccaec1ad9374e 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/arel/predicates.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Predicate def ==(other) self.class == other.class diff --git a/lib/arel/primitives.rb b/lib/arel/primitives.rb new file mode 100644 index 0000000000000..d84713d3d51d0 --- /dev/null +++ b/lib/arel/primitives.rb @@ -0,0 +1,4 @@ +require 'arel/primitives/attribute' +require 'arel/primitives/value' +require 'arel/primitives/expression' + diff --git a/lib/active_relation/primitives/attribute.rb b/lib/arel/primitives/attribute.rb similarity index 99% rename from lib/active_relation/primitives/attribute.rb rename to lib/arel/primitives/attribute.rb index 5b1ef4d7c041e..280fc9f439015 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Attribute attr_reader :relation, :name, :alias, :ancestor delegate :engine, :to => :relation diff --git a/lib/active_relation/primitives/expression.rb b/lib/arel/primitives/expression.rb similarity index 98% rename from lib/active_relation/primitives/expression.rb rename to lib/arel/primitives/expression.rb index ae4c61d1b1d24..bf674cc9e1408 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Expression < Attribute include Sql::Quoting diff --git a/lib/active_relation/primitives/value.rb b/lib/arel/primitives/value.rb similarity index 95% rename from lib/active_relation/primitives/value.rb rename to lib/arel/primitives/value.rb index 9042aea067b75..650557559a7b0 100644 --- a/lib/active_relation/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Value attr_reader :value, :relation diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb new file mode 100644 index 0000000000000..96aa8e9d358eb --- /dev/null +++ b/lib/arel/relations.rb @@ -0,0 +1,17 @@ +require 'arel/relations/relation' +require 'arel/relations/nil' +require 'arel/relations/compound' +require 'arel/relations/writing' +require 'arel/relations/table' +require 'arel/relations/join' +require 'arel/relations/grouping' +require 'arel/relations/projection' +require 'arel/relations/selection' +require 'arel/relations/order' +require 'arel/relations/take' +require 'arel/relations/skip' +require 'arel/relations/deletion' +require 'arel/relations/insertion' +require 'arel/relations/update' +require 'arel/relations/alias' +require 'arel/sessions/session' \ No newline at end of file diff --git a/lib/active_relation/relations/alias.rb b/lib/arel/relations/alias.rb similarity index 92% rename from lib/active_relation/relations/alias.rb rename to lib/arel/relations/alias.rb index 4cb4913da5f26..2dab52515f32e 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/arel/relations/alias.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Alias < Compound attr_reader :alias diff --git a/lib/active_relation/relations/compound.rb b/lib/arel/relations/compound.rb similarity index 94% rename from lib/active_relation/relations/compound.rb rename to lib/arel/relations/compound.rb index 7c844821158b1..4ffac6d1c3610 100644 --- a/lib/active_relation/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Compound < Relation attr_reader :relation diff --git a/lib/active_relation/relations/deletion.rb b/lib/arel/relations/deletion.rb similarity index 95% rename from lib/active_relation/relations/deletion.rb rename to lib/arel/relations/deletion.rb index f1d121d68fe2e..6c802ba905403 100644 --- a/lib/active_relation/relations/deletion.rb +++ b/lib/arel/relations/deletion.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Deletion < Writing def initialize(relation) @relation = relation diff --git a/lib/active_relation/relations/grouping.rb b/lib/arel/relations/grouping.rb similarity index 94% rename from lib/active_relation/relations/grouping.rb rename to lib/arel/relations/grouping.rb index 57323e90f308f..ccca600360206 100644 --- a/lib/active_relation/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Grouping < Compound attr_reader :expressions, :groupings diff --git a/lib/active_relation/relations/insertion.rb b/lib/arel/relations/insertion.rb similarity index 96% rename from lib/active_relation/relations/insertion.rb rename to lib/arel/relations/insertion.rb index 58defe4b016e3..37e7be87571fb 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/arel/relations/insertion.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Insertion < Writing attr_reader :record diff --git a/lib/active_relation/relations/join.rb b/lib/arel/relations/join.rb similarity index 99% rename from lib/active_relation/relations/join.rb rename to lib/arel/relations/join.rb index a3e45f7f8189d..fb51ea0260d5d 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates diff --git a/lib/active_relation/relations/nil.rb b/lib/arel/relations/nil.rb similarity index 85% rename from lib/active_relation/relations/nil.rb rename to lib/arel/relations/nil.rb index 289ba834d855a..3c1d413953746 100644 --- a/lib/active_relation/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Nil < Relation def table_sql; '' end diff --git a/lib/active_relation/relations/order.rb b/lib/arel/relations/order.rb similarity index 94% rename from lib/active_relation/relations/order.rb rename to lib/arel/relations/order.rb index b5495fad67ca1..91526da02cfc3 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/arel/relations/order.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Order < Compound attr_reader :ordering diff --git a/lib/active_relation/relations/projection.rb b/lib/arel/relations/projection.rb similarity index 94% rename from lib/active_relation/relations/projection.rb rename to lib/arel/relations/projection.rb index 0f8ea5175c847..f09d4f894bf77 100644 --- a/lib/active_relation/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Projection < Compound attr_reader :projections diff --git a/lib/active_relation/relations/relation.rb b/lib/arel/relations/relation.rb similarity index 99% rename from lib/active_relation/relations/relation.rb rename to lib/arel/relations/relation.rb index 8ab266c53dac1..60fb7bd00ac64 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Relation def session Session.new diff --git a/lib/active_relation/relations/selection.rb b/lib/arel/relations/selection.rb similarity index 95% rename from lib/active_relation/relations/selection.rb rename to lib/arel/relations/selection.rb index fb90405b01aea..38a40e1b76916 100644 --- a/lib/active_relation/relations/selection.rb +++ b/lib/arel/relations/selection.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Selection < Compound attr_reader :predicate diff --git a/lib/active_relation/relations/skip.rb b/lib/arel/relations/skip.rb similarity index 92% rename from lib/active_relation/relations/skip.rb rename to lib/arel/relations/skip.rb index 5973dff8b9b24..f17e439ebf8cf 100644 --- a/lib/active_relation/relations/skip.rb +++ b/lib/arel/relations/skip.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Skip < Compound attr_reader :skipped diff --git a/lib/active_relation/relations/table.rb b/lib/arel/relations/table.rb similarity index 97% rename from lib/active_relation/relations/table.rb rename to lib/arel/relations/table.rb index e645f710303cb..cdc03df623781 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Table < Relation cattr_accessor :engine attr_reader :name, :engine diff --git a/lib/active_relation/relations/take.rb b/lib/arel/relations/take.rb similarity index 91% rename from lib/active_relation/relations/take.rb rename to lib/arel/relations/take.rb index d9d439b3f5627..d2743d7a6e380 100644 --- a/lib/active_relation/relations/take.rb +++ b/lib/arel/relations/take.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Take < Compound attr_reader :taken diff --git a/lib/active_relation/relations/update.rb b/lib/arel/relations/update.rb similarity index 97% rename from lib/active_relation/relations/update.rb rename to lib/arel/relations/update.rb index 6262ead1870e0..f1f6776f15dcc 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/arel/relations/update.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Update < Writing attr_reader :assignments diff --git a/lib/active_relation/relations/writing.rb b/lib/arel/relations/writing.rb similarity index 56% rename from lib/active_relation/relations/writing.rb rename to lib/arel/relations/writing.rb index 2714ce4d0c067..b871e5a520b3c 100644 --- a/lib/active_relation/relations/writing.rb +++ b/lib/arel/relations/writing.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel class Writing < Compound end end \ No newline at end of file diff --git a/lib/active_relation/sessions/session.rb b/lib/arel/sessions/session.rb similarity index 97% rename from lib/active_relation/sessions/session.rb rename to lib/arel/sessions/session.rb index fe917a0e4dded..becf23b8b6a28 100644 --- a/lib/active_relation/sessions/session.rb +++ b/lib/arel/sessions/session.rb @@ -1,6 +1,6 @@ require 'singleton' -module ActiveRelation +module Arel class Session class << self attr_accessor :instance diff --git a/lib/active_relation/sql.rb b/lib/arel/sql.rb similarity index 98% rename from lib/active_relation/sql.rb rename to lib/arel/sql.rb index 0b9b0fc18bc6f..b6d646c047101 100644 --- a/lib/active_relation/sql.rb +++ b/lib/arel/sql.rb @@ -1,4 +1,4 @@ -module ActiveRelation +module Arel module Sql module Quoting delegate :quote_table_name, :quote_column_name, :quote, :to => :engine diff --git a/spec/active_relation/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb similarity index 98% rename from spec/active_relation/unit/predicates/binary_spec.rb rename to spec/arel/unit/predicates/binary_spec.rb index 56c568b07819e..f39b37d9138e0 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Binary do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/predicates/equality_spec.rb b/spec/arel/unit/predicates/equality_spec.rb similarity index 98% rename from spec/active_relation/unit/predicates/equality_spec.rb rename to spec/arel/unit/predicates/equality_spec.rb index 5415b35925b2f..8a58ba30966ca 100644 --- a/spec/active_relation/unit/predicates/equality_spec.rb +++ b/spec/arel/unit/predicates/equality_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Equality do before do @relation1 = Table.new(:users) diff --git a/spec/active_relation/unit/predicates/in_spec.rb b/spec/arel/unit/predicates/in_spec.rb similarity index 98% rename from spec/active_relation/unit/predicates/in_spec.rb rename to spec/arel/unit/predicates/in_spec.rb index 4ca7867dd0c4a..797798a77fdf1 100644 --- a/spec/active_relation/unit/predicates/in_spec.rb +++ b/spec/arel/unit/predicates/in_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe In do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb similarity index 99% rename from spec/active_relation/unit/primitives/attribute_spec.rb rename to spec/arel/unit/primitives/attribute_spec.rb index 471ae91b5bff1..ac9afa85c76bd 100644 --- a/spec/active_relation/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Attribute do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb similarity index 98% rename from spec/active_relation/unit/primitives/expression_spec.rb rename to spec/arel/unit/primitives/expression_spec.rb index c15b073ba3726..8a990231f6131 100644 --- a/spec/active_relation/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Expression do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/primitives/value_spec.rb b/spec/arel/unit/primitives/value_spec.rb similarity index 96% rename from spec/active_relation/unit/primitives/value_spec.rb rename to spec/arel/unit/primitives/value_spec.rb index ab632ef98755c..87425c780d6a1 100644 --- a/spec/active_relation/unit/primitives/value_spec.rb +++ b/spec/arel/unit/primitives/value_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Value do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb similarity index 93% rename from spec/active_relation/unit/relations/alias_spec.rb rename to spec/arel/unit/relations/alias_spec.rb index 4a2144db82336..420a91c80614f 100644 --- a/spec/active_relation/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Alias do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/compound_spec.rb b/spec/arel/unit/relations/compound_spec.rb similarity index 97% rename from spec/active_relation/unit/relations/compound_spec.rb rename to spec/arel/unit/relations/compound_spec.rb index 54a89f3f570e7..763e447db3dd6 100644 --- a/spec/active_relation/unit/relations/compound_spec.rb +++ b/spec/arel/unit/relations/compound_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Compound do before do class ConcreteCompound < Compound diff --git a/spec/active_relation/unit/relations/deletion_spec.rb b/spec/arel/unit/relations/deletion_spec.rb similarity index 97% rename from spec/active_relation/unit/relations/deletion_spec.rb rename to spec/arel/unit/relations/deletion_spec.rb index 08f7bc03bbef5..f975720d83a52 100644 --- a/spec/active_relation/unit/relations/deletion_spec.rb +++ b/spec/arel/unit/relations/deletion_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Deletion do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/grouping_spec.rb b/spec/arel/unit/relations/grouping_spec.rb similarity index 97% rename from spec/active_relation/unit/relations/grouping_spec.rb rename to spec/arel/unit/relations/grouping_spec.rb index 4b5badbb8b5ff..bef356689654e 100644 --- a/spec/active_relation/unit/relations/grouping_spec.rb +++ b/spec/arel/unit/relations/grouping_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Grouping do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/insertion_spec.rb b/spec/arel/unit/relations/insertion_spec.rb similarity index 98% rename from spec/active_relation/unit/relations/insertion_spec.rb rename to spec/arel/unit/relations/insertion_spec.rb index 543e2d51a985e..10b70a203693e 100644 --- a/spec/active_relation/unit/relations/insertion_spec.rb +++ b/spec/arel/unit/relations/insertion_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Insertion do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb similarity index 99% rename from spec/active_relation/unit/relations/join_spec.rb rename to spec/arel/unit/relations/join_spec.rb index c1a13cee6e0d5..f9d0d9561e5d5 100644 --- a/spec/active_relation/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Join do before do @relation1 = Table.new(:users) diff --git a/spec/active_relation/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb similarity index 98% rename from spec/active_relation/unit/relations/order_spec.rb rename to spec/arel/unit/relations/order_spec.rb index e8a2f4c227852..838a2f141e988 100644 --- a/spec/active_relation/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Order do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/projection_spec.rb b/spec/arel/unit/relations/projection_spec.rb similarity index 99% rename from spec/active_relation/unit/relations/projection_spec.rb rename to spec/arel/unit/relations/projection_spec.rb index 5936cbc45f7b8..cd59d6c3834ea 100644 --- a/spec/active_relation/unit/relations/projection_spec.rb +++ b/spec/arel/unit/relations/projection_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Projection do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb similarity index 99% rename from spec/active_relation/unit/relations/relation_spec.rb rename to spec/arel/unit/relations/relation_spec.rb index c40974e136197..46c3ee250d7c6 100644 --- a/spec/active_relation/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Relation do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/selection_spec.rb b/spec/arel/unit/relations/selection_spec.rb similarity index 98% rename from spec/active_relation/unit/relations/selection_spec.rb rename to spec/arel/unit/relations/selection_spec.rb index d87e075f983b5..61d9787df2088 100644 --- a/spec/active_relation/unit/relations/selection_spec.rb +++ b/spec/arel/unit/relations/selection_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Selection do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/skip_spec.rb b/spec/arel/unit/relations/skip_spec.rb similarity index 94% rename from spec/active_relation/unit/relations/skip_spec.rb rename to spec/arel/unit/relations/skip_spec.rb index 219bfdd80ef48..d83c969aa859f 100644 --- a/spec/active_relation/unit/relations/skip_spec.rb +++ b/spec/arel/unit/relations/skip_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Skip do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb similarity index 99% rename from spec/active_relation/unit/relations/table_spec.rb rename to spec/arel/unit/relations/table_spec.rb index 2751d9cb6389f..eb765ce7771cc 100644 --- a/spec/active_relation/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Table do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/take_spec.rb b/spec/arel/unit/relations/take_spec.rb similarity index 94% rename from spec/active_relation/unit/relations/take_spec.rb rename to spec/arel/unit/relations/take_spec.rb index 8c13732258c93..dca78060571fd 100644 --- a/spec/active_relation/unit/relations/take_spec.rb +++ b/spec/arel/unit/relations/take_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Take do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb similarity index 98% rename from spec/active_relation/unit/relations/update_spec.rb rename to spec/arel/unit/relations/update_spec.rb index 29dd4e12dd544..f411781392cf1 100644 --- a/spec/active_relation/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Update do before do @relation = Table.new(:users) diff --git a/spec/active_relation/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb similarity index 98% rename from spec/active_relation/unit/session/session_spec.rb rename to spec/arel/unit/session/session_spec.rb index 5c3b668e1fb7d..c2eb9a45552ac 100644 --- a/spec/active_relation/unit/session/session_spec.rb +++ b/spec/arel/unit/session/session_spec.rb @@ -1,6 +1,6 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') -module ActiveRelation +module Arel describe Session do before do @relation = Table.new(:users) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6180f822bd4fc..bc117ec47dbf7 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,7 @@ require 'spec' require 'pp' require 'fileutils' -require 'active_relation' +require 'arel' [:matchers, :doubles].each do |helper| Dir["#{dir}/#{helper}/*"].each { |m| require "#{dir}/#{helper}/#{File.basename(m)}" } @@ -15,6 +15,6 @@ config.include(BeLikeMatcher, HashTheSameAsMatcher) config.mock_with :rr config.before do - ActiveRelation::Table.engine = ActiveRelation::Engine.new(Fake::Engine.new) + Arel::Table.engine = Arel::Engine.new(Fake::Engine.new) end end \ No newline at end of file From 2a9117d8546941b90126d1548b0bbff85fca145a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 18 Apr 2008 14:53:02 -0700 Subject: [PATCH 0132/1492] when ordering, the last order wins --- doc/TODO | 2 +- lib/arel/relations/order.rb | 12 +++--------- spec/arel/unit/relations/order_spec.rb | 15 ++------------- 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/doc/TODO b/doc/TODO index a51a730c90336..3aa7696952f84 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,4 @@ todo: -- rename Arel to arel - incorporate linq vocabularity - fix complex joining cases: - extract adapters @@ -57,6 +56,7 @@ done: - test relation, table reset - test Value, in particular bind. - test blank checks in relation.rb +- rename active_relation to arel icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/relations/order.rb b/lib/arel/relations/order.rb index 91526da02cfc3..b1454973c8619 100644 --- a/lib/arel/relations/order.rb +++ b/lib/arel/relations/order.rb @@ -1,21 +1,15 @@ module Arel class Order < Compound - attr_reader :ordering + attr_reader :orders def initialize(relation, *orders) - ordering = orders.pop - @relation = orders.empty?? relation : Order.new(relation, *orders) - @ordering = ordering.bind(@relation) + @relation, @orders = relation, orders.collect { |o| o.bind(relation) } end def ==(other) self.class == other.class and relation == other.relation and - ordering == other.ordering - end - - def orders - relation.orders + [ordering] + orders == other.orders end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb index 838a2f141e988..514612f047e07 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -7,17 +7,6 @@ module Arel @attribute = @relation[:id] end - describe '#initialize' do - before do - @another_attribtue = @relation[:name] - end - - it "manufactures nested Order relations if multiple predicates are provided" do - Order.new(@relation, @predicate, @another_attribute). \ - should == Order.new(Order.new(@relation, @another_attribute), @predicate) - end - end - describe '#to_sql' do describe "when given an attribute" do it "manufactures sql with an order clause populated by the attribute" do @@ -63,11 +52,11 @@ module Arel @another_attribute = @relation[:name] end - it "manufactures sql with an order clause populated by comma-separated attributes" do + it "manufactures sql with the order clause of the last ordering" do Order.new(@ordered_relation, @another_attribute).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`id`, `users`.`name` + ORDER BY `users`.`name` ") end end From caf89fe3415982fd0b593ffcda9a58a083aa7e78 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 18 Apr 2008 15:14:39 -0700 Subject: [PATCH 0133/1492] in fact, when doing subsequent orderings, we assume that the previous orderings have taken effect and therefore where the new ordering finds things equal, the previous ordering should take effect --- lib/arel/relations/order.rb | 14 +++++++++----- spec/arel/unit/relations/order_spec.rb | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/arel/relations/order.rb b/lib/arel/relations/order.rb index b1454973c8619..662d3740df02f 100644 --- a/lib/arel/relations/order.rb +++ b/lib/arel/relations/order.rb @@ -1,15 +1,19 @@ module Arel class Order < Compound - attr_reader :orders - - def initialize(relation, *orders) - @relation, @orders = relation, orders.collect { |o| o.bind(relation) } + attr_reader :orderings + + def initialize(relation, *orderings) + @relation, @orderings = relation, orderings.collect { |o| o.bind(relation) } end def ==(other) self.class == other.class and relation == other.relation and - orders == other.orders + orderings == other.orderings + end + + def orders + orderings + relation.orders end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb index 514612f047e07..d373a8ba126c5 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -52,11 +52,11 @@ module Arel @another_attribute = @relation[:name] end - it "manufactures sql with the order clause of the last ordering" do + it "manufactures sql with the order clause of the last ordering preceding the first ordering" do Order.new(@ordered_relation, @another_attribute).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`name` + ORDER BY `users`.`name`, `users`.`id` ") end end From 86885933c42a620026d6d5a9fab2a22bcfdc1f79 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 18 Apr 2008 19:00:56 -0700 Subject: [PATCH 0134/1492] todos --- doc/TODO | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/TODO b/doc/TODO index 3aa7696952f84..435684d77b682 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,9 @@ todo: -- incorporate linq vocabularity +- incorporate linq functionality/terminology + - then_by (ordering) + - reverse + - any/all + - where - fix complex joining cases: - extract adapters - cache expiry on write From 9567f8e4e87f95929f331a2d5eb35bce952eac86 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 19 Apr 2008 20:40:47 -0700 Subject: [PATCH 0135/1492] - new todo items - alias to_sql to to_s - added column_for to join (untested) --- doc/TODO | 7 ++++++- lib/arel/predicates.rb | 1 + lib/arel/relations/join.rb | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/TODO b/doc/TODO index 435684d77b682..fc18af28b607a 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,10 +1,14 @@ todo: +- active record query adapter +- audit active record quoting - incorporate linq functionality/terminology - then_by (ordering) - reverse - any/all - where -- fix complex joining cases: +- limit clauses with left outer joins ? + - see add_limited_ids_condition + - select_limited_ids_list - extract adapters - cache expiry on write - rewrite of arecord querycache test in light of this @@ -61,6 +65,7 @@ done: - test Value, in particular bind. - test blank checks in relation.rb - rename active_relation to arel +- fix complex joining cases: icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index ccaec1ad9374e..7faaebfc1768d 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -23,6 +23,7 @@ def bind(relation) def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end + alias_method :to_s, :to_sql end class Equality < Binary diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index fb51ea0260d5d..d5ec9d43bd98a 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -37,6 +37,11 @@ def prefix_for(attribute) end end + # TESTME: Not sure which scenario needs this method, was driven by failing tests in ActiveRecord + def column_for(attribute) + (relation1[attribute] || relation2[attribute]).column + end + def joins this_join = [ join_sql, From 4a6822d5e416f2e687d32a14ff98c7b5c815369c Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 27 Apr 2008 18:11:36 -0700 Subject: [PATCH 0136/1492] results of a select query are a hash indexed by attribute rather than string --- doc/TODO | 21 +++++++++++++++------ lib/arel/relations/relation.rb | 17 ++++++++++++----- lib/arel/relations/table.rb | 5 ----- spec/arel/unit/relations/relation_spec.rb | 2 +- spec/doubles/database.rb | 2 +- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/doc/TODO b/doc/TODO index fc18af28b607a..acd6ea7a1ea27 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,17 +1,25 @@ todo: -- active record query adapter +- lock + - SELECT suchandsuch FOR UPDATE +- anonymous table names +- rename select to where +- and/or w/ predicates - audit active record quoting -- incorporate linq functionality/terminology - - then_by (ordering) - - reverse - - any/all - - where - limit clauses with left outer joins ? - see add_limited_ids_condition - select_limited_ids_list +- count queries - extract adapters +- arbitrary sql relationships + - consider this code from has_many: + # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ + @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } + - can join with this as a subselect no problem right? it's' unclear what attributes it has, though. - cache expiry on write - rewrite of arecord querycache test in light of this +- linq functionality + - reverse + - any/all done: - mock out database @@ -66,6 +74,7 @@ done: - test blank checks in relation.rb - rename active_relation to arel - fix complex joining cases: +- active record query adapter icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 60fb7bd00ac64..c8602d22e3544 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -18,19 +18,19 @@ def first include Enumerable module Operations - def join(other = nil) + def join(other = nil, join_type = "INNER JOIN") case other when String Join.new(other, self) when Relation - JoinOperation.new("INNER JOIN", self, other) + JoinOperation.new(join_type, self, other) else self end end - def outer_join(other) - JoinOperation.new("LEFT OUTER JOIN", self, other) + def outer_join(other = nil) + join(other, "LEFT OUTER JOIN") end def [](index) @@ -39,6 +39,8 @@ def [](index) attribute_for_name(index) when Attribute, Expression attribute_for_attribute(index) + when Array + index.collect { |i| self[i] } end end @@ -123,7 +125,12 @@ def inclusion_predicate_sql end def call(connection = engine.connection) - connection.select_all(to_sql) + results = connection.execute(to_sql) + rows = [] + results.each do |row| + rows << attributes.zip(row).to_hash + end + rows end module AttributeAccessors diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index cdc03df623781..b627558cafbba 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -39,10 +39,5 @@ def reset def table_sql engine.quote_table_name(name) end - - private - def qualifications - attributes.zip(attributes.collect(&:qualified_name)).to_hash - end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index 46c3ee250d7c6..d6874a1554f90 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -207,7 +207,7 @@ module Arel describe '#call' do it 'executes a select_all on the connection' do - mock(connection = Object.new).select_all(@relation.to_sql) + mock(connection = Object.new).execute(@relation.to_sql) { [] } @relation.call(connection) end end diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb index cc445966908d6..c28e9b1a0bc5f 100644 --- a/spec/doubles/database.rb +++ b/spec/doubles/database.rb @@ -23,7 +23,7 @@ def columns(table_name, comment) }[table_name] end - def select_all(*args) + def execute(*args) [] end From 3ae7a601e962468468eac1399ebdfd7113730310 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 27 Apr 2008 20:40:20 -0700 Subject: [PATCH 0137/1492] attribute disambiguation --- doc/TODO | 1 - lib/arel/relations/join.rb | 14 +++--------- lib/arel/relations/relation.rb | 4 +++- spec/arel/unit/relations/join_spec.rb | 33 ++++++++++++++++++++------- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/doc/TODO b/doc/TODO index acd6ea7a1ea27..f9599646527e7 100644 --- a/doc/TODO +++ b/doc/TODO @@ -8,7 +8,6 @@ todo: - limit clauses with left outer joins ? - see add_limited_ids_condition - select_limited_ids_list -- count queries - extract adapters - arbitrary sql relationships - consider this code from has_many: diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index d5ec9d43bd98a..e5ca49c284836 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -24,17 +24,9 @@ def attributes end def prefix_for(attribute) - if relation1[attribute] && !relation2[attribute] - externalize(relation1).prefix_for(attribute) - elsif relation2[attribute] && !relation1[attribute] - externalize(relation2).prefix_for(attribute) - else - if (attribute % relation1[attribute]).size < (attribute % relation2[attribute]).size - externalize(relation1).prefix_for(attribute) - else - externalize(relation2).prefix_for(attribute) - end - end + externalize([relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| + (attribute % a1).size <=> (attribute % a2).size + end.relation).prefix_for(attribute) end # TESTME: Not sure which scenario needs this method, was driven by failing tests in ActiveRecord diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index c8602d22e3544..3bd40e8f6b450 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -139,7 +139,9 @@ def attribute_for_name(name) end def attribute_for_attribute(attribute) - attributes.detect { |a| a =~ attribute } + attributes.select { |a| a =~ attribute }.min do |a1, a2| + (attribute % a1).size <=> (attribute % a2).size + end end end include AttributeAccessors diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index f9d0d9561e5d5..12b7d7a5935ac 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -145,14 +145,31 @@ module Arel end describe 'when joining aliased relations' do - it 'aliases the table and attributes properly' do - aliased_relation = @relation1.as(:alias) - @relation1.join(aliased_relation).on(@relation1[:id].eq(aliased_relation[:id])).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `alias`.`id`, `alias`.`name` - FROM `users` - INNER JOIN `users` AS `alias` - ON `users`.`id` = `alias`.`id` - ") + before do + @aliased_relation = @relation1.as(:alias) + end + + describe '#to_sql' do + it 'aliases the table and attributes properly' do + @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `alias`.`id`, `alias`.`name` + FROM `users` + INNER JOIN `users` AS `alias` + ON `users`.`id` = `alias`.`id` + ") + end + end + + describe 'when joining the same relation to itself' do + describe '[]' do + describe 'when given an attribute belonging to both sub-relations' do + it '' do + relation = @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])) + relation[@relation1[:id]].ancestor.should == @relation1[:id] + relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] + end + end + end end end From 09b2406e829cee71e4543a75fc4fbe226157d35e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 28 Apr 2008 14:01:33 -0700 Subject: [PATCH 0138/1492] automatically aliasing tables --- lib/arel/primitives/attribute.rb | 10 +-- lib/arel/relations/grouping.rb | 4 + lib/arel/relations/join.rb | 48 ++++++----- lib/arel/relations/nil.rb | 4 +- lib/arel/relations/relation.rb | 6 +- lib/arel/relations/table.rb | 4 +- lib/arel/sql.rb | 16 ++-- spec/arel/unit/primitives/attribute_spec.rb | 17 ---- spec/arel/unit/relations/join_spec.rb | 89 ++++++++++----------- 9 files changed, 92 insertions(+), 106 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 280fc9f439015..797ebfd07b9ac 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -30,10 +30,6 @@ def to_attribute end include Transformations - def qualified_name - "#{prefix}.#{name}" - end - def column relation.column_for(self) end @@ -122,7 +118,7 @@ def average include Expressions def to_sql(formatter = Sql::WhereCondition.new(engine)) - formatter.attribute prefix, name, self.alias + formatter.attribute relation.prefix_for(self), name, self.alias end def format(object) @@ -133,9 +129,5 @@ def format(object) def formatter Sql::Attribute.new(self) end - - def prefix - relation.prefix_for(self) - end end end \ No newline at end of file diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index ccca600360206..41af4ba0f6c39 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -15,5 +15,9 @@ def ==(other) def aggregation? true end + + def name + relation.name + '_aggregation' + end end end \ No newline at end of file diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index e5ca49c284836..ce236d79d0078 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -24,9 +24,13 @@ def attributes end def prefix_for(attribute) - externalize([relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| + name_for(relation_for(attribute)) + end + + def relation_for(attribute) + [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| (attribute % a1).size <=> (attribute % a2).size - end.relation).prefix_for(attribute) + end.relation.relation_for(attribute) end # TESTME: Not sure which scenario needs this method, was driven by failing tests in ActiveRecord @@ -34,10 +38,10 @@ def column_for(attribute) (relation1[attribute] || relation2[attribute]).column end - def joins + def joins(formatter = Sql::TableReference.new(engine)) this_join = [ join_sql, - externalize(relation2).table_sql, + externalize(relation2).table_sql(formatter), ("ON" unless predicates.blank?), predicates.collect { |p| p.bind(self).to_sql }.join(' AND ') ].compact.join(" ") @@ -45,29 +49,35 @@ def joins end def selects - externalize(relation1).selects + externalize(relation2).selects + (externalize(relation1).selects + externalize(relation2).selects).collect { |s| s.bind(self) } end - def table_sql - externalize(relation1).table_sql + def table_sql(formatter = Sql::TableReference.new(engine)) + externalize(relation1).table_sql(formatter) + end + + def name_for(relation) + @used_names ||= Hash.new(0) + @relation_names ||= Hash.new do |h, k| + @used_names[k.name] += 1 + h[k] = k.name + (@used_names[k.name] > 1 ? "_#{@used_names[k.name]}" : '') + end + @relation_names[relation] end private def externalize(relation) - Externalizer.new(relation) + Externalizer.new(self, relation) end - Externalizer = Struct.new(:relation) do + Externalizer = Struct.new(:christener, :relation) do delegate :engine, :to => :relation - def table_sql - case - when relation.aggregation? - relation.to_sql(Sql::TableReference.new(engine)) - when relation.alias? - relation.table_sql + ' AS ' + engine.quote_table_name(relation.alias.to_s) + def table_sql(formatter = Sql::TableReference.new(engine)) + if relation.aggregation? + relation.to_sql(formatter) + ' AS ' + engine.quote_table_name(christener.name_for(relation)) else - relation.table_sql + relation.table_sql(formatter) + (relation.name != christener.name_for(relation) ? " AS " + engine.quote_table_name(christener.name_for(relation)) : '') end end @@ -78,12 +88,6 @@ def selects def attributes relation.aggregation?? relation.attributes.collect(&:to_attribute) : relation.attributes end - - def prefix_for(attribute) - if relation[attribute] - relation.alias?? relation.alias : relation.prefix_for(attribute) - end - end end end end \ No newline at end of file diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index 3c1d413953746..67eb2d3a627bf 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,7 +1,7 @@ module Arel class Nil < Relation - def table_sql; '' end - + def table_sql(formatter = nil); '' end + def name; '' end def to_s; '' end def ==(other) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 3bd40e8f6b450..0a5bf2ff24c85 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -103,6 +103,10 @@ def aggregation? def alias? false end + + def relation_for(attribute) + self[attribute] and self + end end include Externalizable @@ -116,7 +120,7 @@ def to_sql(formatter = Sql::SelectStatement.new(engine)) ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n"), self.alias + ].compact.join("\n") end alias_method :to_s, :to_sql diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index b627558cafbba..7637a471bf6a9 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -36,8 +36,8 @@ def reset @attributes = @columns = nil end - def table_sql - engine.quote_table_name(name) + def table_sql(formatter = Sql::TableReference.new(engine)) + formatter.table name end end end \ No newline at end of file diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb index b6d646c047101..3cb8d13680fd7 100644 --- a/lib/arel/sql.rb +++ b/lib/arel/sql.rb @@ -19,8 +19,8 @@ def attribute(relation_name, attribute_name, aliaz) "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") end - def select(select_sql, aliaz) - "(#{select_sql})" + (aliaz ? " AS #{quote(aliaz)}" : "") + def select(select_sql) + "(#{select_sql})" end def value(value) @@ -56,20 +56,24 @@ def scalar(value, column = nil) quote(value, column) end - def select(select_sql, aliaz) + def select(select_sql) "(#{select_sql})" end end class SelectStatement < Formatter - def select(select_sql, aliaz) + def select(select_sql) select_sql end end class TableReference < Formatter - def select(select_sql, aliaz) - "(#{select_sql}) AS #{quote_table_name(aliaz)}" + def select(select_sql) + "(#{select_sql})" + end + + def table(name) + quote_table_name(name) end end diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index ac9afa85c76bd..561c47da1646d 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -38,12 +38,6 @@ module Arel end end - describe '#qualified_name' do - it "manufactures an attribute name prefixed with the relation's name" do - @attribute.qualified_name.should == "#{@relation.prefix_for(@attribute)}.id" - end - end - describe '#engine' do it "delegates to its relation" do Attribute.new(@relation, :id).engine.should == @relation.engine @@ -77,17 +71,6 @@ module Arel @attribute.to_sql.should be_like("`users`.`id`") end end - - describe 'for an attribute in a join relation where the source relation is aliased' do - before do - another_relation = Table.new(:photos) - @join_with_alias = @relation.as(:alias).join(another_relation).on(@relation[:id].eq(another_relation[:user_id])) - end - - it "manufactures sql with an alias" do - @join_with_alias[@attribute].to_sql.should be_like("`alias`.`id`") - end - end end describe Attribute::Predications do diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 12b7d7a5935ac..15c00a4f24abd 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -31,31 +31,6 @@ module Arel .should hash_the_same_as(Join.new("INNER JOIN", @relation1, @relation2, @predicate)) end end - - describe '#prefix_for' do - describe 'when the joined relations are simple' do - it "returns the name of the relation containing the attribute" do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation1[:id]) \ - .should == @relation1.prefix_for(@relation1[:id]) - Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation2[:id]) \ - .should == @relation2.prefix_for(@relation2[:id]) - - end - end - - describe 'when one of the joined relations is an alias' do - before do - @aliased_relation = @relation1.as(:alias) - end - - it "returns the alias of the relation containing the attribute" do - Join.new("INNER JOIN", @aliased_relation, @relation2, @predicate).prefix_for(@aliased_relation[:id]) \ - .should == @aliased_relation.alias - Join.new("INNER JOIN", @aliased_relation, @relation2, @predicate).prefix_for(@relation2[:id]) \ - .should == @relation2.prefix_for(@relation2[:id]) - end - end - end describe '#engine' do it "delegates to a relation's engine" do @@ -71,6 +46,15 @@ module Arel (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } end end + + describe '#prefix_for' do + it "returns the name of the relation containing the attribute" do + Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation1[:id]) \ + .should == @relation1.prefix_for(@relation1[:id]) + Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation2[:id]) \ + .should == @relation2.prefix_for(@relation2[:id]) + end + end describe '#to_sql' do it 'manufactures sql joining the two tables on the predicate' do @@ -89,7 +73,7 @@ module Arel INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` WHERE `users`.`id` = 1 AND `photos`.`id` = 2 - ") + ") end end end @@ -99,7 +83,6 @@ module Arel @aggregation = @relation2 \ .group(@relation2[:user_id]) \ .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ - .as('photo_count') end describe '#attributes' do @@ -114,10 +97,10 @@ module Arel describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` + SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` - ON `users`.`id` = `photo_count`.`user_id` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` + ON `users`.`id` = `photos_aggregation`.`user_id` ") end end @@ -125,45 +108,57 @@ module Arel describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(" - SELECT `photo_count`.`user_id`, `photo_count`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photo_count` + SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` INNER JOIN `users` - ON `users`.`id` = `photo_count`.`user_id` + ON `users`.`id` = `photos_aggregation`.`user_id` ") end end it "keeps selects on the aggregation within the derived table" do Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photo_count`.`user_id`, `photo_count`.`cnt` + SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photo_count` - ON `users`.`id` = `photo_count`.`user_id` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` + ON `users`.`id` = `photos_aggregation`.`user_id` ") end end end - describe 'when joining aliased relations' do + describe 'when joining a relation to itself' do before do @aliased_relation = @relation1.as(:alias) - end + @predicate = @relation1[:id].eq(@aliased_relation[:id]) + end - describe '#to_sql' do - it 'aliases the table and attributes properly' do - @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `alias`.`id`, `alias`.`name` - FROM `users` - INNER JOIN `users` AS `alias` - ON `users`.`id` = `alias`.`id` - ") + describe '#prefix_for' do + it "returns the alias of the relation containing the attribute" do + relation = Join.new("INNER JOIN", @relation1, @aliased_relation, @predicate) + relation.prefix_for(@aliased_relation[:id]) \ + .should == @relation1.name + relation.prefix_for(@relation1[:id]) \ + .should == @relation1.name + '_2' end end describe 'when joining the same relation to itself' do + describe '#to_sql' do + it 'aliases the table and attributes properly in selects' + it 'aliases the table and attributes properly in the join predicate' do + @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + ") + end + end + describe '[]' do describe 'when given an attribute belonging to both sub-relations' do - it '' do + it 'disambiguates the ...' do relation = @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])) relation[@relation1[:id]].ancestor.should == @relation1[:id] relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] From 57d6bce28b07f864c97a7b58d758fd5621196b00 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 28 Apr 2008 14:03:36 -0700 Subject: [PATCH 0139/1492] improved messaging in test --- spec/arel/unit/relations/join_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 15c00a4f24abd..b14d951aaed22 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -145,8 +145,7 @@ module Arel describe 'when joining the same relation to itself' do describe '#to_sql' do - it 'aliases the table and attributes properly in selects' - it 'aliases the table and attributes properly in the join predicate' do + it 'aliases the table and attributes properly in the join predicate and the where clause' do @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` @@ -158,7 +157,7 @@ module Arel describe '[]' do describe 'when given an attribute belonging to both sub-relations' do - it 'disambiguates the ...' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do relation = @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])) relation[@relation1[:id]].ancestor.should == @relation1[:id] relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] From f48c642852b5bb6be62dbbc7502d34b64e53716b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 30 Apr 2008 23:42:26 -0700 Subject: [PATCH 0140/1492] the big obstacle --- lib/arel/relations/alias.rb | 12 +++--------- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/join.rb | 5 +++++ lib/arel/relations/relation.rb | 9 ++------- spec/arel/unit/relations/alias_spec.rb | 6 +++--- spec/arel/unit/relations/join_spec.rb | 11 +++++++++-- spec/arel/unit/relations/relation_spec.rb | 24 ++++++----------------- 7 files changed, 29 insertions(+), 40 deletions(-) diff --git a/lib/arel/relations/alias.rb b/lib/arel/relations/alias.rb index 2dab52515f32e..329f94638ea38 100644 --- a/lib/arel/relations/alias.rb +++ b/lib/arel/relations/alias.rb @@ -2,18 +2,12 @@ module Arel class Alias < Compound attr_reader :alias - def initialize(relation, aliaz) - @relation, @alias = relation, aliaz - end - - def alias? - true + def initialize(relation) + @relation = relation end def ==(other) - self.class == other.class and - relation == other.relation and - @alias == other.alias + self.equal? other end end end \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 4ffac6d1c3610..ae848433be221 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -5,7 +5,7 @@ class Compound < Relation hash_on :relation delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :taken, - :skipped, :name, :alias, :aggregation?, :alias?, :prefix_for, :column_for, + :skipped, :name, :alias, :aggregation?, :prefix_for, :column_for, :engine, :to => :relation diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index ce236d79d0078..6c12a0ea2679d 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -48,6 +48,11 @@ def joins(formatter = Sql::TableReference.new(engine)) [relation1.joins, relation2.joins, this_join].compact.join(" ") end + # FIXME + def name + 'user' + end + def selects (externalize(relation1).selects + externalize(relation2).selects).collect { |s| s.bind(self) } end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 0a5bf2ff24c85..3453b9adc6ce6 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -52,8 +52,8 @@ def project(*attributes) attributes.all?(&:blank?) ? self : Projection.new(self, *attributes) end - def as(aliaz = nil) - aliaz.blank?? self : Alias.new(self, aliaz) + def alias + Alias.new(self) end def order(*attributes) @@ -100,10 +100,6 @@ def aggregation? false end - def alias? - false - end - def relation_for(attribute) self[attribute] and self end @@ -166,6 +162,5 @@ def groupings; [] end def joins; nil end def taken; nil end def skipped; nil end - def alias; nil end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 420a91c80614f..25dbf70668701 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -4,12 +4,12 @@ module Arel describe Alias do before do @relation = Table.new(:users) - @alias_relation = Alias.new(@relation, :foo) end - describe '#alias' do + describe '==' do it "returns the alias" do - @alias_relation.alias.should == :foo + Alias.new(@relation).should_not == Alias.new(@relation) + (aliaz = Alias.new(@relation)).should == aliaz end end end diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index b14d951aaed22..c3f33e1ae78e3 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -129,7 +129,7 @@ module Arel describe 'when joining a relation to itself' do before do - @aliased_relation = @relation1.as(:alias) + @aliased_relation = @relation1.alias @predicate = @relation1[:id].eq(@aliased_relation[:id]) end @@ -145,6 +145,13 @@ module Arel describe 'when joining the same relation to itself' do describe '#to_sql' do + it '' do + @relation1 \ + .join(@relation1.alias.join(@relation1.alias).on(@relation1[:id].eq(1))) \ + .on(@relation1[:id].eq(1)) \ + .to_sql.should be_like("") + end + it 'aliases the table and attributes properly in the join predicate and the where clause' do @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` @@ -173,7 +180,7 @@ module Arel SELECT `users`.`id`, `users`.`name` FROM `users` INNER JOIN asdf ON fdsa - ") + ") end end end diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index d6874a1554f90..3b8be55c7d766 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -30,12 +30,6 @@ module Arel @relation.should_not be_aggregation end end - - describe '#alias?' do - it "returns false" do - @relation.should_not be_alias - end - end end describe Relation::Operations do @@ -86,31 +80,25 @@ module Arel end end - describe '#as' do + describe '#alias' do it "manufactures an alias relation" do - @relation.as(:paul).should == Alias.new(@relation, :paul) - end - - describe 'when given a blank alias' do - it 'returns self' do - @relation.as.should == @relation - end + @relation.alias.relation.should == Alias.new(@relation).relation end end - + describe '#select' do before do @predicate = Equality.new(@attribute1, @attribute2) end - + it "manufactures a selection relation" do @relation.select(@predicate).should == Selection.new(@relation, @predicate) end - + it "accepts arbitrary strings" do @relation.select("arbitrary").should == Selection.new(@relation, "arbitrary") end - + describe 'when given a blank predicate' do it 'returns self' do @relation.select.should == @relation From 3c52d91b5dc8b582e03d9ad84e3b97a85273110e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 30 Apr 2008 23:44:19 -0700 Subject: [PATCH 0141/1492] my failing test. this is really really hard --- spec/arel/unit/relations/join_spec.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index c3f33e1ae78e3..f74bd32ef8d9e 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -149,7 +149,14 @@ module Arel @relation1 \ .join(@relation1.alias.join(@relation1.alias).on(@relation1[:id].eq(1))) \ .on(@relation1[:id].eq(1)) \ - .to_sql.should be_like("") + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = 1 + INNER JOIN `users` AS `users_3` + ON `users`.`id` = 1 + ") end it 'aliases the table and attributes properly in the join predicate and the where clause' do From 6c61ebb4d677f9bc5e1a669e7351c1226cbc9582 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 1 May 2008 21:23:55 -0700 Subject: [PATCH 0142/1492] naming of aliased relations seemed to be solved; now aggregate relations are still broken --- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/grouping.rb | 6 +----- lib/arel/relations/join.rb | 18 +++++++++++------- lib/arel/relations/relation.rb | 14 +++++++++++--- lib/arel/relations/table.rb | 4 ---- lib/arel/sql.rb | 10 ++++++++-- spec/arel/unit/relations/join_spec.rb | 10 ++++++---- 7 files changed, 38 insertions(+), 26 deletions(-) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index ae848433be221..f4d6b199b58dd 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -4,7 +4,7 @@ class Compound < Relation hash_on :relation - delegate :joins, :selects, :orders, :groupings, :table_sql, :inserts, :taken, + delegate :joins, :selects, :orders, :groupings, :inserts, :taken, :skipped, :name, :alias, :aggregation?, :prefix_for, :column_for, :engine, :to => :relation diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index 41af4ba0f6c39..2815f62b7989a 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -1,6 +1,6 @@ module Arel class Grouping < Compound - attr_reader :expressions, :groupings + attr_reader :groupings def initialize(relation, *groupings) @relation, @groupings = relation, groupings.collect { |g| g.bind(relation) } @@ -15,9 +15,5 @@ def ==(other) def aggregation? true end - - def name - relation.name + '_aggregation' - end end end \ No newline at end of file diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 6c12a0ea2679d..1fb0055caaa7a 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -1,4 +1,6 @@ module Arel + # TODO Explicitly model recursive structural decomposition / polymorphism + # TODO Explicitly model the namer/externalizer using interpreter jargon class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates @@ -24,7 +26,7 @@ def attributes end def prefix_for(attribute) - name_for(relation_for(attribute)) + externalize(relation_for(attribute)).table_sql # externalize or something? end def relation_for(attribute) @@ -38,14 +40,14 @@ def column_for(attribute) (relation1[attribute] || relation2[attribute]).column end - def joins(formatter = Sql::TableReference.new(engine)) + def joins(formatter = Sql::TableReference.new(self)) this_join = [ join_sql, externalize(relation2).table_sql(formatter), ("ON" unless predicates.blank?), predicates.collect { |p| p.bind(self).to_sql }.join(' AND ') ].compact.join(" ") - [relation1.joins, relation2.joins, this_join].compact.join(" ") + [relation1.joins(formatter), relation2.joins(formatter), this_join].compact.join(" ") end # FIXME @@ -57,7 +59,7 @@ def selects (externalize(relation1).selects + externalize(relation2).selects).collect { |s| s.bind(self) } end - def table_sql(formatter = Sql::TableReference.new(engine)) + def table_sql(formatter = Sql::TableReference.new(self)) externalize(relation1).table_sql(formatter) end @@ -78,11 +80,13 @@ def externalize(relation) Externalizer = Struct.new(:christener, :relation) do delegate :engine, :to => :relation - def table_sql(formatter = Sql::TableReference.new(engine)) + def table_sql(formatter = Sql::TableReference.new(self)) if relation.aggregation? - relation.to_sql(formatter) + ' AS ' + engine.quote_table_name(christener.name_for(relation)) + relation.to_sql(formatter) + ' AS ' + engine.quote_table_name(christener.name_for(relation) + '_aggregation') else - relation.table_sql(formatter) + (relation.name != christener.name_for(relation) ? " AS " + engine.quote_table_name(christener.name_for(relation)) : '') + # not an aggregation + # all this can be is a join or a compound or a table + relation.table_sql(formatter) end end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 3453b9adc6ce6..02fc1c628478d 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -103,14 +103,22 @@ def aggregation? def relation_for(attribute) self[attribute] and self end + + def name_for(relation) + relation.name + end + + def table_sql(formatter = Sql::TableReference.new(self)) + formatter.table name, formatter.name_for(self) + end end include Externalizable def to_sql(formatter = Sql::SelectStatement.new(engine)) formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(engine)) }.join(', ')}", - "FROM #{table_sql}", - (joins unless joins.blank? ), + "FROM #{table_sql(Sql::TableReference.new(self))}", + (joins(Sql::TableReference.new(self)) unless joins.blank? ), ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(engine)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), @@ -159,7 +167,7 @@ def selects; [] end def orders; [] end def inserts; [] end def groupings; [] end - def joins; nil end + def joins(formatter = nil); nil end def taken; nil end def skipped; nil end end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 7637a471bf6a9..9c7d90d4fcf67 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -35,9 +35,5 @@ def columns def reset @attributes = @columns = nil end - - def table_sql(formatter = Sql::TableReference.new(engine)) - formatter.table name - end end end \ No newline at end of file diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb index 3cb8d13680fd7..34a730c5f3a9c 100644 --- a/lib/arel/sql.rb +++ b/lib/arel/sql.rb @@ -68,12 +68,18 @@ def select(select_sql) end class TableReference < Formatter + delegate :name_for, :to => :@christener + + def initialize(christener) + @christener, @engine = christener, christener.engine + end + def select(select_sql) "(#{select_sql})" end - def table(name) - quote_table_name(name) + def table(name, aliaz) + quote_table_name(name) + (name != aliaz ? " AS " + engine.quote_table_name(aliaz) : '') end end diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index f74bd32ef8d9e..c08ff68f3606d 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -146,16 +146,18 @@ module Arel describe 'when joining the same relation to itself' do describe '#to_sql' do it '' do + relation2 = @relation1.alias + relation3 = @relation1.alias @relation1 \ - .join(@relation1.alias.join(@relation1.alias).on(@relation1[:id].eq(1))) \ - .on(@relation1[:id].eq(1)) \ + .join(relation2.join(relation3).on(relation2[:id].eq(relation3[:id]))) \ + .on(@relation1[:id].eq(relation2[:id])) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` FROM `users` INNER JOIN `users` AS `users_2` - ON `users`.`id` = 1 + ON `users_2`.`id` = `users_3`.`id` INNER JOIN `users` AS `users_3` - ON `users`.`id` = 1 + ON `users_2`.`id` = `users_3`.`id` ") end From 85bc3b417dc4e1ecad76fa89b5d195e2db8f5ff5 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 1 May 2008 23:19:12 -0700 Subject: [PATCH 0143/1492] finally fixed table aliasing issues - the solution is currently ugly, but i have an idea how to clean it up --- doc/TODO | 22 +++++++---------- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/join.rb | 34 ++++++++++++--------------- lib/arel/relations/relation.rb | 5 ++-- lib/arel/sql.rb | 1 + spec/arel/unit/relations/join_spec.rb | 2 +- 6 files changed, 29 insertions(+), 37 deletions(-) diff --git a/doc/TODO b/doc/TODO index f9599646527e7..752579d2299ba 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,24 +1,14 @@ todo: +- Explicitly model recursive structural decomposition / polymorphism +- Explicitly model the namer/externalizer using interpreter jargon +- All Sql Strategies should be accumulations with the top-level relation? - lock - SELECT suchandsuch FOR UPDATE -- anonymous table names - rename select to where - and/or w/ predicates -- audit active record quoting -- limit clauses with left outer joins ? - - see add_limited_ids_condition - - select_limited_ids_list -- extract adapters -- arbitrary sql relationships - - consider this code from has_many: - # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ - @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } - - can join with this as a subselect no problem right? it's' unclear what attributes it has, though. - cache expiry on write - rewrite of arecord querycache test in light of this -- linq functionality - - reverse - - any/all +- scoped writes done: - mock out database @@ -74,6 +64,7 @@ done: - rename active_relation to arel - fix complex joining cases: - active record query adapter +- anonymous table names icebox: - #bind in Attribute and Expression should be doing a descend? @@ -83,3 +74,6 @@ icebox: - "unit" test sql strategies - use real world examples, so they should be like a tutorial. - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent +- consider this code from has_many: + # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ + @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index f4d6b199b58dd..735f58611419c 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -6,7 +6,7 @@ class Compound < Relation delegate :joins, :selects, :orders, :groupings, :inserts, :taken, :skipped, :name, :alias, :aggregation?, :prefix_for, :column_for, - :engine, + :engine, :name_for, :to => :relation def attributes diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 1fb0055caaa7a..cb24ab77170c5 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -1,6 +1,4 @@ module Arel - # TODO Explicitly model recursive structural decomposition / polymorphism - # TODO Explicitly model the namer/externalizer using interpreter jargon class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates @@ -26,13 +24,7 @@ def attributes end def prefix_for(attribute) - externalize(relation_for(attribute)).table_sql # externalize or something? - end - - def relation_for(attribute) - [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| - (attribute % a1).size <=> (attribute % a2).size - end.relation.relation_for(attribute) + externalize(relation_for(attribute)).prefix_for(attribute) end # TESTME: Not sure which scenario needs this method, was driven by failing tests in ActiveRecord @@ -45,14 +37,9 @@ def joins(formatter = Sql::TableReference.new(self)) join_sql, externalize(relation2).table_sql(formatter), ("ON" unless predicates.blank?), - predicates.collect { |p| p.bind(self).to_sql }.join(' AND ') + predicates.collect { |p| p.bind(formatter.christener).to_sql }.join(' AND ') ].compact.join(" ") - [relation1.joins(formatter), relation2.joins(formatter), this_join].compact.join(" ") - end - - # FIXME - def name - 'user' + [relation1.joins(formatter), this_join, relation2.joins(formatter)].compact.join(" ") end def selects @@ -72,6 +59,13 @@ def name_for(relation) @relation_names[relation] end + protected + def relation_for(attribute) + [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| + (attribute % a1).size <=> (attribute % a2).size + end.relation.relation_for(attribute) + end + private def externalize(relation) Externalizer.new(self, relation) @@ -82,10 +76,8 @@ def externalize(relation) def table_sql(formatter = Sql::TableReference.new(self)) if relation.aggregation? - relation.to_sql(formatter) + ' AS ' + engine.quote_table_name(christener.name_for(relation) + '_aggregation') + relation.to_sql(formatter) + ' AS ' + engine.quote_table_name(formatter.name_for(relation) + (relation.aggregation?? '_aggregation' : '')) else - # not an aggregation - # all this can be is a join or a compound or a table relation.table_sql(formatter) end end @@ -97,6 +89,10 @@ def selects def attributes relation.aggregation?? relation.attributes.collect(&:to_attribute) : relation.attributes end + + def prefix_for(attribute) + christener.name_for(relation) + (relation.aggregation?? '_aggregation' : '') + end end end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 02fc1c628478d..7b414b9768429 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -115,10 +115,11 @@ def table_sql(formatter = Sql::TableReference.new(self)) include Externalizable def to_sql(formatter = Sql::SelectStatement.new(engine)) + tr = Sql::TableReference.new(self) formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(engine)) }.join(', ')}", - "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(Sql::TableReference.new(self)) unless joins.blank? ), + "FROM #{table_sql(tr)}", + (joins(tr) unless joins.blank? ), ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(engine)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb index 34a730c5f3a9c..7a620009dbccf 100644 --- a/lib/arel/sql.rb +++ b/lib/arel/sql.rb @@ -68,6 +68,7 @@ def select(select_sql) end class TableReference < Formatter + attr_reader :christener delegate :name_for, :to => :@christener def initialize(christener) diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index c08ff68f3606d..0c2d1d771d855 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -155,7 +155,7 @@ module Arel SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` FROM `users` INNER JOIN `users` AS `users_2` - ON `users_2`.`id` = `users_3`.`id` + ON `users`.`id` = `users_2`.`id` INNER JOIN `users` AS `users_3` ON `users_2`.`id` = `users_3`.`id` ") From f413129f37bbbc4100317cb60179f43291e69f8e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 16:50:03 -0700 Subject: [PATCH 0144/1492] Table names seem to be disambiguated. - Code is a mess, about to undergo some refactoring --- lib/arel/primitives/attribute.rb | 13 +++++- lib/arel/primitives/value.rb | 4 +- lib/arel/relations/alias.rb | 12 +++-- lib/arel/relations/compound.rb | 4 +- lib/arel/relations/grouping.rb | 8 ++++ lib/arel/relations/join.rb | 42 ++++++++---------- lib/arel/relations/nil.rb | 1 + lib/arel/relations/relation.rb | 37 ++++++++++------ lib/arel/relations/table.rb | 12 +++-- lib/arel/sql.rb | 49 ++++++++++----------- spec/arel/unit/relations/grouping_spec.rb | 4 +- spec/arel/unit/relations/join_spec.rb | 22 ++------- spec/arel/unit/relations/projection_spec.rb | 11 ++++- spec/arel/unit/relations/table_spec.rb | 7 --- 14 files changed, 120 insertions(+), 106 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 797ebfd07b9ac..9215ea64a06dc 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -7,6 +7,7 @@ def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end + # INVESTIGATE def alias_or_name @alias || name end @@ -117,14 +118,22 @@ def average end include Expressions - def to_sql(formatter = Sql::WhereCondition.new(engine)) - formatter.attribute relation.prefix_for(self), name, self.alias + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self end def format(object) object.to_sql(formatter) end + def original_relation + relation.relation_for(self) + end + + def christener + relation.christener + end + private def formatter Sql::Attribute.new(self) diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 650557559a7b0..5142eb45ca83c 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -8,12 +8,12 @@ def initialize(value, relation) @value, @relation = value, relation end - def to_sql(formatter = Sql::WhereCondition.new(relation.engine)) + def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value end def format(object) - object.to_sql(Sql::Value.new(relation.engine)) + object.to_sql(Sql::Value.new(relation)) end def ==(other) diff --git a/lib/arel/relations/alias.rb b/lib/arel/relations/alias.rb index 329f94638ea38..b4e8965625bae 100644 --- a/lib/arel/relations/alias.rb +++ b/lib/arel/relations/alias.rb @@ -1,13 +1,19 @@ module Arel class Alias < Compound - attr_reader :alias - def initialize(relation) @relation = relation end def ==(other) - self.equal? other + equal? other + end + + def table + self + end + + def relation_for(attribute) + self[attribute] and self end end end \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 735f58611419c..7367e60a2db80 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -5,8 +5,8 @@ class Compound < Relation hash_on :relation delegate :joins, :selects, :orders, :groupings, :inserts, :taken, - :skipped, :name, :alias, :aggregation?, :prefix_for, :column_for, - :engine, :name_for, + :skipped, :name, :alias, :aggregation?, :column_for, + :engine, :name_for, :table, :relation_for, :to => :relation def attributes diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index 2815f62b7989a..e3686f7f282ff 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -15,5 +15,13 @@ def ==(other) def aggregation? true end + + def table_sql(formatter = Sql::TableReference.new(self)) + to_sql(formatter) + end + + def name + table.name + '_aggregation' + end end end \ No newline at end of file diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index cb24ab77170c5..20c19e0848ced 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -23,10 +23,6 @@ def attributes externalize(relation2).attributes).collect { |a| a.bind(self) } end - def prefix_for(attribute) - externalize(relation_for(attribute)).prefix_for(attribute) - end - # TESTME: Not sure which scenario needs this method, was driven by failing tests in ActiveRecord def column_for(attribute) (relation1[attribute] || relation2[attribute]).column @@ -35,7 +31,11 @@ def column_for(attribute) def joins(formatter = Sql::TableReference.new(self)) this_join = [ join_sql, - externalize(relation2).table_sql(formatter), + if relation2.aggregation? + relation2.to_sql(formatter) + else + relation2.table.table_sql(formatter) + end, ("ON" unless predicates.blank?), predicates.collect { |p| p.bind(formatter.christener).to_sql }.join(' AND ') ].compact.join(" ") @@ -46,10 +46,6 @@ def selects (externalize(relation1).selects + externalize(relation2).selects).collect { |s| s.bind(self) } end - def table_sql(formatter = Sql::TableReference.new(self)) - externalize(relation1).table_sql(formatter) - end - def name_for(relation) @used_names ||= Hash.new(0) @relation_names ||= Hash.new do |h, k| @@ -59,11 +55,21 @@ def name_for(relation) @relation_names[relation] end - protected + def table + relation1.aggregation?? relation1 : relation1.table + end + + delegate :name, :to => :relation1 + def relation_for(attribute) - [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| + x = [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| (attribute % a1).size <=> (attribute % a2).size - end.relation.relation_for(attribute) + end.relation + if x.aggregation? + x + else + x.relation_for(attribute) # FIXME @demeter + end end private @@ -74,14 +80,6 @@ def externalize(relation) Externalizer = Struct.new(:christener, :relation) do delegate :engine, :to => :relation - def table_sql(formatter = Sql::TableReference.new(self)) - if relation.aggregation? - relation.to_sql(formatter) + ' AS ' + engine.quote_table_name(formatter.name_for(relation) + (relation.aggregation?? '_aggregation' : '')) - else - relation.table_sql(formatter) - end - end - def selects relation.aggregation?? [] : relation.selects end @@ -89,10 +87,6 @@ def selects def attributes relation.aggregation?? relation.attributes.collect(&:to_attribute) : relation.attributes end - - def prefix_for(attribute) - christener.name_for(relation) + (relation.aggregation?? '_aggregation' : '') - end end end end \ No newline at end of file diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index 67eb2d3a627bf..258f60f478802 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,5 +1,6 @@ module Arel class Nil < Relation + def table; self end def table_sql(formatter = nil); '' end def name; '' end def to_s; '' end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 7b414b9768429..e08123eaf5179 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -99,36 +99,40 @@ module Externalizable def aggregation? false end - - def relation_for(attribute) - self[attribute] and self - end def name_for(relation) relation.name end def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table name, formatter.name_for(self) + formatter.table self end end include Externalizable - def to_sql(formatter = Sql::SelectStatement.new(engine)) - tr = Sql::TableReference.new(self) + def to_sql(formatter = Sql::SelectStatement.new(self)) formatter.select [ - "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(engine)) }.join(', ')}", - "FROM #{table_sql(tr)}", - (joins(tr) unless joins.blank? ), - ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(engine)) }.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(engine)) }.join(', ')}" unless orders.blank? ), + "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "FROM #{thing}", + (joins(Sql::TableReference.new(self)) unless joins.blank? ), + ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n") + ].compact.join("\n"), name end alias_method :to_s, :to_sql + # FIXME + def thing + if table.aggregation? + table.to_sql(Sql::TableReference.new(self)) + else + table.table_sql(Sql::TableReference.new(self)) + end + end + def inclusion_predicate_sql "IN" end @@ -159,8 +163,13 @@ def bind(relation) self end + # INVESTIGATE def format(object) - object.to_sql(Sql::WhereCondition.new(engine)) + object.to_sql(Sql::WhereCondition.new(self)) + end + + def christener + self end def attributes; [] end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 9c7d90d4fcf67..fcde94b5951c2 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -15,14 +15,18 @@ def attributes end end - def prefix_for(attribute) - self[attribute] and name - end - def column_for(attribute) self[attribute] and columns.detect { |c| c.name == attribute.name.to_s } end + def table + self + end + + def relation_for(attribute) + self[attribute] and self + end + def ==(other) self.class == other.class and name == other.name diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb index 7a620009dbccf..de0bece37264e 100644 --- a/lib/arel/sql.rb +++ b/lib/arel/sql.rb @@ -5,22 +5,23 @@ module Quoting end class Formatter - attr_reader :engine + attr_reader :engine, :christener include Quoting - def initialize(engine) - @engine = engine + def initialize(environment) + @christener, @engine = environment.christener, environment.engine end end class SelectClause < Formatter - def attribute(relation_name, attribute_name, aliaz) - "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + (aliaz ? " AS #{quote(aliaz.to_s)}" : "") + def attribute(attribute) + relation_name = @christener.name_for(attribute.original_relation) + "#{quote_table_name(relation_name)}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") end - def select(select_sql) - "(#{select_sql})" + def select(select_sql, name) + "(#{select_sql}) AS #{quote_table_name(name.to_s)}" end def value(value) @@ -37,15 +38,17 @@ def value(value) class WhereClause < PassThrough end - class OrderClause < PassThrough - def attribute(relation_name, attribute_name, aliaz) - "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + class OrderClause < PassThrough + def attribute(attribute) + relation_name = @christener.name_for(attribute.original_relation) + "#{quote_table_name(relation_name)}.#{quote_column_name(attribute.name)}" end end class WhereCondition < Formatter - def attribute(relation_name, attribute_name, aliaz) - "#{quote_table_name(relation_name)}.#{quote_column_name(attribute_name)}" + def attribute(attribute) + relation_name = @christener.name_for(attribute.original_relation) + "#{quote_table_name(relation_name)}.#{quote_column_name(attribute.name)}" end def value(value) @@ -56,37 +59,31 @@ def scalar(value, column = nil) quote(value, column) end - def select(select_sql) + def select(select_sql, name) "(#{select_sql})" end end class SelectStatement < Formatter - def select(select_sql) + def select(select_sql, name) select_sql end end class TableReference < Formatter - attr_reader :christener - delegate :name_for, :to => :@christener - - def initialize(christener) - @christener, @engine = christener, christener.engine - end - - def select(select_sql) - "(#{select_sql})" + def select(select_sql, name) + "(#{select_sql}) AS #{quote_table_name(name)}" end - def table(name, aliaz) - quote_table_name(name) + (name != aliaz ? " AS " + engine.quote_table_name(aliaz) : '') + def table(table) + aliaz = christener.name_for(table) + quote_table_name(table.name) + (table.name != aliaz ? " AS " + engine.quote_table_name(aliaz) : '') end end class Attribute < WhereCondition def initialize(attribute) - @attribute, @engine = attribute, attribute.engine + @attribute, @christener, @engine = attribute, attribute.christener, attribute.engine end def scalar(scalar) diff --git a/spec/arel/unit/relations/grouping_spec.rb b/spec/arel/unit/relations/grouping_spec.rb index bef356689654e..66205b8f951bc 100644 --- a/spec/arel/unit/relations/grouping_spec.rb +++ b/spec/arel/unit/relations/grouping_spec.rb @@ -6,7 +6,7 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do @@ -20,7 +20,7 @@ module Arel describe 'when given a string' do it "passes the string through to the where clause" do - pending 'it should not quote asdf' + pending 'it should not quote the group clause' Grouping.new(@relation, 'asdf').to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 0c2d1d771d855..52e1a93b8ebee 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -47,15 +47,6 @@ module Arel end end - describe '#prefix_for' do - it "returns the name of the relation containing the attribute" do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation1[:id]) \ - .should == @relation1.prefix_for(@relation1[:id]) - Join.new("INNER JOIN", @relation1, @relation2, @predicate).prefix_for(@relation2[:id]) \ - .should == @relation2.prefix_for(@relation2[:id]) - end - end - describe '#to_sql' do it 'manufactures sql joining the two tables on the predicate' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(" @@ -116,6 +107,7 @@ module Arel end end + # TESTME try other direction too! it "keeps selects on the aggregation within the derived table" do Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` @@ -133,16 +125,6 @@ module Arel @predicate = @relation1[:id].eq(@aliased_relation[:id]) end - describe '#prefix_for' do - it "returns the alias of the relation containing the attribute" do - relation = Join.new("INNER JOIN", @relation1, @aliased_relation, @predicate) - relation.prefix_for(@aliased_relation[:id]) \ - .should == @relation1.name - relation.prefix_for(@relation1[:id]) \ - .should == @relation1.name + '_2' - end - end - describe 'when joining the same relation to itself' do describe '#to_sql' do it '' do @@ -151,6 +133,7 @@ module Arel @relation1 \ .join(relation2.join(relation3).on(relation2[:id].eq(relation3[:id]))) \ .on(@relation1[:id].eq(relation2[:id])) \ + .select(@relation1[:id].eq(1)) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` FROM `users` @@ -158,6 +141,7 @@ module Arel ON `users`.`id` = `users_2`.`id` INNER JOIN `users` AS `users_3` ON `users_2`.`id` = `users_3`.`id` + WHERE `users`.`id` = 1 ") end diff --git a/spec/arel/unit/relations/projection_spec.rb b/spec/arel/unit/relations/projection_spec.rb index cd59d6c3834ea..eedcf77952013 100644 --- a/spec/arel/unit/relations/projection_spec.rb +++ b/spec/arel/unit/relations/projection_spec.rb @@ -47,7 +47,7 @@ module Arel it "manufactures sql with scalar selects" do Projection.new(@relation, @scalar_relation).to_sql.should be_like(" - SELECT (SELECT `users`.`name` FROM `users`) FROM `users` + SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` ") end end @@ -59,6 +59,15 @@ module Arel ") end end + + describe 'when given an expression' do + it 'manufactures sql with expressions' do + @relation.project(@attribute.count).to_sql.should be_like(" + SELECT COUNT(`users`.`id`) + FROM `users` + ") + end + end end describe Projection::Externalizable do diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index eb765ce7771cc..54520bf3b6df7 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -51,13 +51,6 @@ module Arel end end - describe '#prefix_for' do - it "returns the table name if the relation contains the attribute" do - @relation.prefix_for(@relation[:id]).should == 'users' - @relation.prefix_for(:does_not_exist).should be_nil - end - end - describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do @relation.attributes.should == [ From 9d8e661a1ad5e2f1904cef1d076355273aa6146e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 17:03:31 -0700 Subject: [PATCH 0145/1492] minor cleanup --- lib/arel/primitives/attribute.rb | 55 +++++++++++++++----------------- lib/arel/relations/alias.rb | 5 +++ lib/arel/relations/grouping.rb | 4 --- lib/arel/relations/join.rb | 7 +--- lib/arel/relations/relation.rb | 11 +++---- lib/arel/relations/table.rb | 4 +++ 6 files changed, 40 insertions(+), 46 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 9215ea64a06dc..14b8c18cb2a2c 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -1,13 +1,12 @@ module Arel class Attribute attr_reader :relation, :name, :alias, :ancestor - delegate :engine, :to => :relation + delegate :engine, :christener, :to => :relation def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end - # INVESTIGATE def alias_or_name @alias || name end @@ -16,6 +15,30 @@ def aggregation? false end + def column + original_relation.column_for(self) + end + + def original_relation + relation.relation_for(self) + end + + def format(object) + object.to_sql(formatter) + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self + end + + def ==(other) + self.class == other.class and + relation == other.relation and + name == other.name and + @alias == other.alias and + ancestor == other.ancestor + end + module Transformations def as(aliaz = nil) Attribute.new(relation, name, :alias => aliaz, :ancestor => self) @@ -31,18 +54,6 @@ def to_attribute end include Transformations - def column - relation.column_for(self) - end - - def ==(other) - self.class == other.class and - relation == other.relation and - name == other.name and - @alias == other.alias and - ancestor == other.ancestor - end - module Congruence def self.included(klass) klass.hash_on :name @@ -117,22 +128,6 @@ def average end end include Expressions - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - - def format(object) - object.to_sql(formatter) - end - - def original_relation - relation.relation_for(self) - end - - def christener - relation.christener - end private def formatter diff --git a/lib/arel/relations/alias.rb b/lib/arel/relations/alias.rb index b4e8965625bae..0099a794b4369 100644 --- a/lib/arel/relations/alias.rb +++ b/lib/arel/relations/alias.rb @@ -15,5 +15,10 @@ def table def relation_for(attribute) self[attribute] and self end + + def table_sql(formatter = Sql::TableReference.new(self)) + formatter.table self + end + end end \ No newline at end of file diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index e3686f7f282ff..3f0ea54407079 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -16,10 +16,6 @@ def aggregation? true end - def table_sql(formatter = Sql::TableReference.new(self)) - to_sql(formatter) - end - def name table.name + '_aggregation' end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 20c19e0848ced..1b37b3f225f32 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -23,11 +23,6 @@ def attributes externalize(relation2).attributes).collect { |a| a.bind(self) } end - # TESTME: Not sure which scenario needs this method, was driven by failing tests in ActiveRecord - def column_for(attribute) - (relation1[attribute] || relation2[attribute]).column - end - def joins(formatter = Sql::TableReference.new(self)) this_join = [ join_sql, @@ -58,7 +53,7 @@ def name_for(relation) def table relation1.aggregation?? relation1 : relation1.table end - + delegate :name, :to => :relation1 def relation_for(attribute) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index e08123eaf5179..62656773dd0f7 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -104,8 +104,8 @@ def name_for(relation) relation.name end - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self + def table + self end end include Externalizable @@ -113,7 +113,7 @@ def table_sql(formatter = Sql::TableReference.new(self)) def to_sql(formatter = Sql::SelectStatement.new(self)) formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", - "FROM #{thing}", + "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(Sql::TableReference.new(self)) unless joins.blank? ), ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), @@ -123,9 +123,8 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) ].compact.join("\n"), name end alias_method :to_s, :to_sql - - # FIXME - def thing + + def table_sql(formatter = Sql::TableReference.new(self)) if table.aggregation? table.to_sql(Sql::TableReference.new(self)) else diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index fcde94b5951c2..75593731e0232 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -27,6 +27,10 @@ def relation_for(attribute) self[attribute] and self end + def table_sql(formatter = Sql::TableReference.new(self)) + formatter.table self + end + def ==(other) self.class == other.class and name == other.name From 5e52a24e67dfedaf9b2a3bb6601f79f1f8e00c72 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 17:23:22 -0700 Subject: [PATCH 0146/1492] additional testing --- lib/arel/relations/relation.rb | 9 +-- spec/arel/unit/relations/join_spec.rb | 106 +++++++++++++++++++------- 2 files changed, 80 insertions(+), 35 deletions(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 62656773dd0f7..846594e7cd1f5 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -115,8 +115,8 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(Sql::TableReference.new(self)) unless joins.blank? ), - ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), + ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) @@ -162,11 +162,6 @@ def bind(relation) self end - # INVESTIGATE - def format(object) - object.to_sql(Sql::WhereCondition.new(self)) - end - def christener self end diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 52e1a93b8ebee..9cd7a13ed7479 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -107,14 +107,28 @@ module Arel end end - # TESTME try other direction too! - it "keeps selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` - ON `users`.`id` = `photos_aggregation`.`user_id` - ") + describe 'when the aggration has a selection' do + describe 'with the aggregation on the left' do + it "manufactures sql keeping selects on the aggregation within the derived table" do + Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` + ON `users`.`id` = `photos_aggregation`.`user_id` + ") + end + end + + describe 'with the aggregation on the right' do + it "manufactures sql keeping selects on the aggregation within the derived table" do + Join.new("INNER JOIN", @aggregation.select(@aggregation[:user_id].eq(1)), @relation1, @predicate).to_sql.should be_like(" + SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` + INNER JOIN `users` + ON `users`.`id` = `photos_aggregation`.`user_id` + ") + end + end end end end @@ -127,38 +141,74 @@ module Arel describe 'when joining the same relation to itself' do describe '#to_sql' do - it '' do - relation2 = @relation1.alias - relation3 = @relation1.alias - @relation1 \ - .join(relation2.join(relation3).on(relation2[:id].eq(relation3[:id]))) \ - .on(@relation1[:id].eq(relation2[:id])) \ - .select(@relation1[:id].eq(1)) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do + @relation1.join(@aliased_relation).on(@predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` INNER JOIN `users` AS `users_2` ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - WHERE `users`.`id` = 1 ") end - it 'aliases the table and attributes properly in the join predicate and the where clause' do - @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - ") + describe 'when joining with a selection on the same relation' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@aliased_relation.select(@aliased_relation[:id].eq(1))) \ + .on(@predicate) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + WHERE `users_2`.`id` = 1 + ") + end + end + + describe 'when joining the same relation to itself multiple times' do + before do + @relation2 = @relation1.alias + @relation3 = @relation1.alias + end + + describe 'when joining left-associatively' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@relation2.join(@relation3).on(@relation2[:id].eq(@relation3[:id]))) \ + .on(@relation1[:id].eq(@relation2[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + ") + end + end + + describe 'when joining right-associatively' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ + .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + ") + end + end end end describe '[]' do describe 'when given an attribute belonging to both sub-relations' do it 'disambiguates the relation that serves as the ancestor to the attribute' do - relation = @relation1.join(@aliased_relation).on(@relation1[:id].eq(@aliased_relation[:id])) + relation = @relation1.join(@aliased_relation).on(@predicate) relation[@relation1[:id]].ancestor.should == @relation1[:id] relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] end From 880efb9bd45a5d7134153a0f1d78cfa7f6cd8470 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 17:28:37 -0700 Subject: [PATCH 0147/1492] cleanup --- lib/arel/relations/join.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 1b37b3f225f32..048cb170e5282 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -1,9 +1,7 @@ module Arel class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates - delegate :engine, :to => :relation1 - hash_on :relation1 def initialize(join_sql, relation1, relation2 = Nil.new, *predicates) @@ -59,22 +57,20 @@ def table def relation_for(attribute) x = [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| (attribute % a1).size <=> (attribute % a2).size - end.relation - if x.aggregation? - x + end + if x.relation.aggregation? + x.relation else - x.relation_for(attribute) # FIXME @demeter + x.original_relation end end private def externalize(relation) - Externalizer.new(self, relation) + Externalizer.new(relation) end - Externalizer = Struct.new(:christener, :relation) do - delegate :engine, :to => :relation - + Externalizer = Struct.new(:relation) do def selects relation.aggregation?? [] : relation.selects end From f9876c67fb372817af2e69c36c5739879d1b238c Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 17:31:04 -0700 Subject: [PATCH 0148/1492] cleanup --- lib/arel/relations/join.rb | 8 ++++---- lib/arel/relations/relation.rb | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 048cb170e5282..0dec80af7925b 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -57,11 +57,11 @@ def table def relation_for(attribute) x = [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| (attribute % a1).size <=> (attribute % a2).size - end - if x.relation.aggregation? - x.relation + end.relation + if x.aggregation? + x else - x.original_relation + x.relation_for(attribute) end end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 846594e7cd1f5..336960f424490 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -103,10 +103,6 @@ def aggregation? def name_for(relation) relation.name end - - def table - self - end end include Externalizable From 8f87072b1fc2b92328aa45078e535e9575b0b6cf Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 17:34:01 -0700 Subject: [PATCH 0149/1492] cleanup --- lib/arel/sql.rb | 107 +----------------------------------------------- 1 file changed, 2 insertions(+), 105 deletions(-) diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb index de0bece37264e..7e7dd0a80fb93 100644 --- a/lib/arel/sql.rb +++ b/lib/arel/sql.rb @@ -1,105 +1,2 @@ -module Arel - module Sql - module Quoting - delegate :quote_table_name, :quote_column_name, :quote, :to => :engine - end - - class Formatter - attr_reader :engine, :christener - - include Quoting - - def initialize(environment) - @christener, @engine = environment.christener, environment.engine - end - end - - class SelectClause < Formatter - def attribute(attribute) - relation_name = @christener.name_for(attribute.original_relation) - "#{quote_table_name(relation_name)}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - end - - def select(select_sql, name) - "(#{select_sql}) AS #{quote_table_name(name.to_s)}" - end - - def value(value) - value - end - end - - class PassThrough < Formatter - def value(value) - value - end - end - - class WhereClause < PassThrough - end - - class OrderClause < PassThrough - def attribute(attribute) - relation_name = @christener.name_for(attribute.original_relation) - "#{quote_table_name(relation_name)}.#{quote_column_name(attribute.name)}" - end - end - - class WhereCondition < Formatter - def attribute(attribute) - relation_name = @christener.name_for(attribute.original_relation) - "#{quote_table_name(relation_name)}.#{quote_column_name(attribute.name)}" - end - - def value(value) - value.to_sql(self) - end - - def scalar(value, column = nil) - quote(value, column) - end - - def select(select_sql, name) - "(#{select_sql})" - end - end - - class SelectStatement < Formatter - def select(select_sql, name) - select_sql - end - end - - class TableReference < Formatter - def select(select_sql, name) - "(#{select_sql}) AS #{quote_table_name(name)}" - end - - def table(table) - aliaz = christener.name_for(table) - quote_table_name(table.name) + (table.name != aliaz ? " AS " + engine.quote_table_name(aliaz) : '') - end - end - - class Attribute < WhereCondition - def initialize(attribute) - @attribute, @christener, @engine = attribute, attribute.christener, attribute.engine - end - - def scalar(scalar) - quote(scalar, @attribute.column) - end - - def array(array) - "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" - end - - def range(left, right) - "#{left} AND #{right}" - end - end - - class Value < WhereCondition - end - end -end \ No newline at end of file +require 'arel/sql/formatters' +require 'arel/sql/christener' \ No newline at end of file From 6b28dcfa7e03909b69b922e26eb6d3ad8eb3f061 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 18:15:38 -0700 Subject: [PATCH 0150/1492] cleanup --- lib/arel/primitives/expression.rb | 6 +- lib/arel/relations/join.rb | 11 +-- lib/arel/relations/relation.rb | 2 +- lib/arel/sql/christener.rb | 14 ++++ lib/arel/sql/formatters.rb | 102 +++++++++++++++++++++++++ spec/arel/unit/relations/join_spec.rb | 104 +++++++++++++------------- 6 files changed, 171 insertions(+), 68 deletions(-) create mode 100644 lib/arel/sql/christener.rb create mode 100644 lib/arel/sql/formatters.rb diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index bf674cc9e1408..75bf1f2ef0292 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -1,7 +1,5 @@ module Arel class Expression < Attribute - include Sql::Quoting - attr_reader :attribute, :function_sql delegate :relation, :to => :attribute alias_method :name, :alias @@ -25,8 +23,8 @@ def to_attribute end include Transformations - def to_sql(formatter = nil) - "#{function_sql}(#{attribute.to_sql})" + (@alias ? " AS #{quote_column_name(@alias)}" : '') + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self end def aggregation? diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 0dec80af7925b..a30c179e4e5b6 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -30,7 +30,7 @@ def joins(formatter = Sql::TableReference.new(self)) relation2.table.table_sql(formatter) end, ("ON" unless predicates.blank?), - predicates.collect { |p| p.bind(formatter.christener).to_sql }.join(' AND ') + predicates.collect { |p| p.bind(formatter.environment).to_sql }.join(' AND ') ].compact.join(" ") [relation1.joins(formatter), this_join, relation2.joins(formatter)].compact.join(" ") end @@ -39,15 +39,6 @@ def selects (externalize(relation1).selects + externalize(relation2).selects).collect { |s| s.bind(self) } end - def name_for(relation) - @used_names ||= Hash.new(0) - @relation_names ||= Hash.new do |h, k| - @used_names[k.name] += 1 - h[k] = k.name + (@used_names[k.name] > 1 ? "_#{@used_names[k.name]}" : '') - end - @relation_names[relation] - end - def table relation1.aggregation?? relation1 : relation1.table end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 336960f424490..0b2098591460c 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -159,7 +159,7 @@ def bind(relation) end def christener - self + @christener ||= Sql::Christener.new end def attributes; [] end diff --git a/lib/arel/sql/christener.rb b/lib/arel/sql/christener.rb new file mode 100644 index 0000000000000..894f0303425c7 --- /dev/null +++ b/lib/arel/sql/christener.rb @@ -0,0 +1,14 @@ +module Arel + module Sql + class Christener + def name_for(relation) + @used_names ||= Hash.new(0) + @relation_names ||= Hash.new do |h, k| + @used_names[k.name] += 1 + h[k] = k.name + (@used_names[k.name] > 1 ? "_#{@used_names[k.name]}" : '') + end + @relation_names[relation] + end + end + end +end \ No newline at end of file diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb new file mode 100644 index 0000000000000..96bab2495c45a --- /dev/null +++ b/lib/arel/sql/formatters.rb @@ -0,0 +1,102 @@ +module Arel + module Sql + class Formatter + attr_reader :environment + delegate :christener, :engine, :to => :environment + delegate :name_for, :to => :christener + delegate :quote_table_name, :quote_column_name, :quote, :to => :engine + + def initialize(environment) + @environment = environment + end + end + + class SelectClause < Formatter + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") + end + + def expression(expression) + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + end + + def select(select_sql, name) + "(#{select_sql}) AS #{quote_table_name(name.to_s)}" + end + + def value(value) + value + end + end + + class PassThrough < Formatter + def value(value) + value + end + end + + class WhereClause < PassThrough + end + + class OrderClause < PassThrough + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + end + end + + class WhereCondition < Formatter + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + end + + def expression(expression) + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + end + + def value(value) + value.to_sql(self) + end + + def scalar(value, column = nil) + quote(value, column) + end + + def select(select_sql, name) + "(#{select_sql})" + end + end + + class SelectStatement < Formatter + def select(select_sql, name) + select_sql + end + end + + class TableReference < Formatter + def select(select_sql, name) + "(#{select_sql}) AS #{quote_table_name(name)}" + end + + def table(table) + quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + engine.quote_table_name(name_for(table)) : '') + end + end + + class Attribute < WhereCondition + def scalar(scalar) + quote(scalar, environment.column) + end + + def array(array) + "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" + end + + def range(left, right) + "#{left} AND #{right}" + end + end + + class Value < WhereCondition + end + end +end \ No newline at end of file diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 9cd7a13ed7479..d517da8c1fe28 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -139,79 +139,77 @@ module Arel @predicate = @relation1[:id].eq(@aliased_relation[:id]) end - describe 'when joining the same relation to itself' do - describe '#to_sql' do - it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do - @relation1.join(@aliased_relation).on(@predicate).to_sql.should be_like(" + describe '#to_sql' do + it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do + @relation1.join(@aliased_relation).on(@predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + ") + end + + describe 'when joining with a selection on the same relation' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@aliased_relation.select(@aliased_relation[:id].eq(1))) \ + .on(@predicate) \ + .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` INNER JOIN `users` AS `users_2` ON `users`.`id` = `users_2`.`id` + WHERE `users_2`.`id` = 1 ") end + end + + describe 'when joining the relation to itself multiple times' do + before do + @relation2 = @relation1.alias + @relation3 = @relation1.alias + end - describe 'when joining with a selection on the same relation' do + describe 'when joining left-associatively' do it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@aliased_relation.select(@aliased_relation[:id].eq(1))) \ - .on(@predicate) \ + @relation1 \ + .join(@relation2.join(@relation3).on(@relation2[:id].eq(@relation3[:id]))) \ + .on(@relation1[:id].eq(@relation2[:id])) \ .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` FROM `users` INNER JOIN `users` AS `users_2` ON `users`.`id` = `users_2`.`id` - WHERE `users_2`.`id` = 1 + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` ") end end - describe 'when joining the same relation to itself multiple times' do - before do - @relation2 = @relation1.alias - @relation3 = @relation1.alias - end - - describe 'when joining left-associatively' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2.join(@relation3).on(@relation2[:id].eq(@relation3[:id]))) \ - .on(@relation1[:id].eq(@relation2[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") - end - end - - describe 'when joining right-associatively' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ - .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") - end + describe 'when joining right-associatively' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ + .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + ") end end end + end - describe '[]' do - describe 'when given an attribute belonging to both sub-relations' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - relation = @relation1.join(@aliased_relation).on(@predicate) - relation[@relation1[:id]].ancestor.should == @relation1[:id] - relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] - end + describe '[]' do + describe 'when given an attribute belonging to both sub-relations' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + relation = @relation1.join(@aliased_relation).on(@predicate) + relation[@relation1[:id]].ancestor.should == @relation1[:id] + relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] end end end From 92c2fd2a2fe029ffe2597134496bdab7f1ed4de6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 18:18:28 -0700 Subject: [PATCH 0151/1492] introducing structural recursion --- lib/arel/relations.rb | 1 + lib/arel/relations/alias.rb | 15 ++------------- lib/arel/relations/table.rb | 14 ++------------ 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index 96aa8e9d358eb..6cd599ad5d7e1 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -1,3 +1,4 @@ +require 'arel/relations/recursion' require 'arel/relations/relation' require 'arel/relations/nil' require 'arel/relations/compound' diff --git a/lib/arel/relations/alias.rb b/lib/arel/relations/alias.rb index 0099a794b4369..08be02e862815 100644 --- a/lib/arel/relations/alias.rb +++ b/lib/arel/relations/alias.rb @@ -1,5 +1,7 @@ module Arel class Alias < Compound + include Recursion::BaseCase + def initialize(relation) @relation = relation end @@ -7,18 +9,5 @@ def initialize(relation) def ==(other) equal? other end - - def table - self - end - - def relation_for(attribute) - self[attribute] and self - end - - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self - end - end end \ No newline at end of file diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 75593731e0232..735159508e7ad 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -1,5 +1,7 @@ module Arel class Table < Relation + include Recursion::BaseCase + cattr_accessor :engine attr_reader :name, :engine @@ -19,18 +21,6 @@ def column_for(attribute) self[attribute] and columns.detect { |c| c.name == attribute.name.to_s } end - def table - self - end - - def relation_for(attribute) - self[attribute] and self - end - - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self - end - def ==(other) self.class == other.class and name == other.name From ce147912eedee3eee1b93dc89f5de3a01e9ac2f1 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 18:28:28 -0700 Subject: [PATCH 0152/1492] reorganization --- lib/arel/relations/compound.rb | 2 - lib/arel/relations/relation.rb | 158 ++++++++++---------- spec/arel/unit/relations/projection_spec.rb | 21 ++- spec/arel/unit/relations/relation_spec.rb | 14 +- 4 files changed, 91 insertions(+), 104 deletions(-) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 7367e60a2db80..1658efd6361a3 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -1,9 +1,7 @@ module Arel class Compound < Relation attr_reader :relation - hash_on :relation - delegate :joins, :selects, :orders, :groupings, :inserts, :taken, :skipped, :name, :alias, :aggregation?, :column_for, :engine, :name_for, :table, :relation_for, diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 0b2098591460c..440e6c9db652b 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -3,7 +3,58 @@ class Relation def session Session.new end + + def name_for(relation) + relation.name + end + + def to_sql(formatter = Sql::SelectStatement.new(self)) + formatter.select [ + "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "FROM #{table_sql(Sql::TableReference.new(self))}", + (joins(Sql::TableReference.new(self)) unless joins.blank? ), + ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), + ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) + ].compact.join("\n"), name + end + alias_method :to_s, :to_sql + def table_sql(formatter = Sql::TableReference.new(self)) + if table.aggregation? + table.to_sql(Sql::TableReference.new(self)) + else + table.table_sql(Sql::TableReference.new(self)) + end + end + + def inclusion_predicate_sql + "IN" + end + + def call(connection = engine.connection) + results = connection.execute(to_sql) + rows = [] + results.each do |row| + rows << attributes.zip(row).to_hash + end + rows + end + + def bind(relation) + self + end + + def christener + @christener ||= Sql::Christener.new + end + + def aggregation? + false + end + module Enumerable include ::Enumerable @@ -17,7 +68,7 @@ def first end include Enumerable - module Operations + module Operable def join(other = nil, join_type = "INNER JOIN") case other when String @@ -32,18 +83,7 @@ def join(other = nil, join_type = "INNER JOIN") def outer_join(other = nil) join(other, "LEFT OUTER JOIN") end - - def [](index) - case index - when Symbol, String - attribute_for_name(index) - when Attribute, Expression - attribute_for_attribute(index) - when Array - index.collect { |i| self[i] } - end - end - + def select(*predicates) predicates.all?(&:blank?) ? self : Selection.new(self, *predicates) end @@ -72,7 +112,7 @@ def group(*groupings) groupings.all?(&:blank?) ? self : Grouping.new(self, *groupings) end - module Writes + module Writable def insert(record) session.create Insertion.new(self, record); self end @@ -85,7 +125,7 @@ def delete session.delete Deletion.new(self); self end end - include Writes + include Writable JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do def on(*predicates) @@ -93,82 +133,42 @@ def on(*predicates) end end end - include Operations + include Operable - module Externalizable - def aggregation? - false + module AttributeAccessable + def [](index) + case index + when Symbol, String + attribute_for_name(index) + when Attribute, Expression + attribute_for_attribute(index) + when Array + index.collect { |i| self[i] } + end end - def name_for(relation) - relation.name - end - end - include Externalizable - - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select [ - "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", - "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(Sql::TableReference.new(self)) unless joins.blank? ), - ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n"), name - end - alias_method :to_s, :to_sql - - def table_sql(formatter = Sql::TableReference.new(self)) - if table.aggregation? - table.to_sql(Sql::TableReference.new(self)) - else - table.table_sql(Sql::TableReference.new(self)) - end - end - - def inclusion_predicate_sql - "IN" - end - - def call(connection = engine.connection) - results = connection.execute(to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash - end - rows - end - - module AttributeAccessors def attribute_for_name(name) attributes.detect { |a| a.alias_or_name.to_s == name.to_s } end - + def attribute_for_attribute(attribute) attributes.select { |a| a =~ attribute }.min do |a1, a2| (attribute % a1).size <=> (attribute % a2).size end end end - include AttributeAccessors - - def bind(relation) - self - end - - def christener - @christener ||= Sql::Christener.new - end + include AttributeAccessable - def attributes; [] end - def selects; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def joins(formatter = nil); nil end - def taken; nil end - def skipped; nil end + module DefaultOperations + def attributes; [] end + def selects; [] end + def orders; [] end + def inserts; [] end + def groupings; [] end + def joins(formatter = nil); nil end + def taken; nil end + def skipped; nil end + end + include DefaultOperations end end \ No newline at end of file diff --git a/spec/arel/unit/relations/projection_spec.rb b/spec/arel/unit/relations/projection_spec.rb index eedcf77952013..0008858e081ab 100644 --- a/spec/arel/unit/relations/projection_spec.rb +++ b/spec/arel/unit/relations/projection_spec.rb @@ -70,21 +70,18 @@ module Arel end end - describe Projection::Externalizable do - describe '#aggregation?' do - describe 'when the projections are attributes' do - it 'returns false' do - Projection.new(@relation, @attribute).should_not be_aggregation - end + describe '#aggregation?' do + describe 'when the projections are attributes' do + it 'returns false' do + Projection.new(@relation, @attribute).should_not be_aggregation end - - describe 'when the projections include an aggregation' do - it "obtains" do - Projection.new(@relation, @attribute.sum).should be_aggregation - end + end + + describe 'when the projections include an aggregation' do + it "obtains" do + Projection.new(@relation, @attribute.sum).should be_aggregation end end - end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index 3b8be55c7d766..d9ae8e0742a96 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -23,16 +23,8 @@ module Arel end end end - - describe Relation::Externalizable do - describe '#aggregation?' do - it "returns false" do - @relation.should_not be_aggregation - end - end - end - - describe Relation::Operations do + + describe Relation::Operable do describe 'joins' do before do @predicate = @relation[:id].eq(@relation[:id]) @@ -154,7 +146,7 @@ module Arel end end - describe Relation::Operations::Writes do + describe Relation::Operable::Writable do describe '#delete' do it 'manufactures a deletion relation' do Session.start do From 542a14c2580469eebdf1d281383096ea985ee11b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 18:52:42 -0700 Subject: [PATCH 0153/1492] cleanup --- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/join.rb | 53 +++++++++++++++++++--------------- lib/arel/relations/relation.rb | 21 +++++--------- lib/arel/relations/table.rb | 3 +- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 1658efd6361a3..f0a3392e097ac 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -4,7 +4,7 @@ class Compound < Relation hash_on :relation delegate :joins, :selects, :orders, :groupings, :inserts, :taken, :skipped, :name, :alias, :aggregation?, :column_for, - :engine, :name_for, :table, :relation_for, + :engine, :name_for, :table, :relation_for, :table_sql, :to => :relation def attributes diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index a30c179e4e5b6..01e7e36f37ac8 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -1,7 +1,7 @@ module Arel class Join < Relation attr_reader :join_sql, :relation1, :relation2, :predicates - delegate :engine, :to => :relation1 + delegate :engine, :name, :to => :relation1 hash_on :relation1 def initialize(join_sql, relation1, relation2 = Nil.new, *predicates) @@ -16,23 +16,19 @@ def ==(other) ) end - def attributes - (externalize(relation1).attributes + - externalize(relation2).attributes).collect { |a| a.bind(self) } - end - - def joins(formatter = Sql::TableReference.new(self)) + def joins(environment, formatter = Sql::TableReference.new(environment)) this_join = [ join_sql, - if relation2.aggregation? - relation2.to_sql(formatter) - else - relation2.table.table_sql(formatter) - end, + externalize(relation2).table_sql(formatter), ("ON" unless predicates.blank?), - predicates.collect { |p| p.bind(formatter.environment).to_sql }.join(' AND ') + predicates.collect { |p| p.bind(environment).to_sql }.join(' AND ') ].compact.join(" ") - [relation1.joins(formatter), this_join, relation2.joins(formatter)].compact.join(" ") + [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") + end + + def attributes + (externalize(relation1).attributes + + externalize(relation2).attributes).collect { |a| a.bind(self) } end def selects @@ -40,20 +36,17 @@ def selects end def table - relation1.aggregation?? relation1 : relation1.table + externalize(relation1).table + end + + def table_sql(formatter = Sql::TableReference.new(self)) + externalize(table).table_sql(formatter) end - - delegate :name, :to => :relation1 def relation_for(attribute) - x = [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| + externalize([relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| (attribute % a1).size <=> (attribute % a2).size - end.relation - if x.aggregation? - x - else - x.relation_for(attribute) - end + end.relation).relation_for(attribute) end private @@ -66,6 +59,18 @@ def selects relation.aggregation?? [] : relation.selects end + def table + relation.aggregation?? relation : relation.table + end + + def relation_for(attribute) + relation.aggregation?? relation : relation.relation_for(attribute) + end + + def table_sql(formatter = Sql::TableReference.new(relation)) + relation.aggregation?? relation.to_sql(formatter) : relation.table.table_sql(formatter) + end + def attributes relation.aggregation?? relation.attributes.collect(&:to_attribute) : relation.attributes end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 440e6c9db652b..14d2143a8bd6c 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -4,6 +4,7 @@ def session Session.new end + # INVESTIGATE def name_for(relation) relation.name end @@ -12,23 +13,15 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(Sql::TableReference.new(self)) unless joins.blank? ), - ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) + (joins(self) unless joins(self).blank? ), + ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), + ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n"), name end alias_method :to_s, :to_sql - - def table_sql(formatter = Sql::TableReference.new(self)) - if table.aggregation? - table.to_sql(Sql::TableReference.new(self)) - else - table.table_sql(Sql::TableReference.new(self)) - end - end def inclusion_predicate_sql "IN" diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 735159508e7ad..5c3ba6c57509b 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -3,8 +3,7 @@ class Table < Relation include Recursion::BaseCase cattr_accessor :engine - attr_reader :name, :engine - + attr_reader :name, :engine hash_on :name def initialize(name, engine = Table.engine) From 4a313bb478765cbc5007aac5097291dabd4628c7 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 18:52:48 -0700 Subject: [PATCH 0154/1492] missing file --- lib/arel/relations/recursion.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lib/arel/relations/recursion.rb diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb new file mode 100644 index 0000000000000..2c6024dc30302 --- /dev/null +++ b/lib/arel/relations/recursion.rb @@ -0,0 +1,17 @@ +module Arel + module Recursion + module BaseCase + def table + self + end + + def relation_for(attribute) + self[attribute] and self + end + + def table_sql(formatter = Sql::TableReference.new(self)) + formatter.table self + end + end + end +end \ No newline at end of file From cd428ee66498146d3dc14f58c6534d79ab124b45 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 4 May 2008 18:57:54 -0700 Subject: [PATCH 0155/1492] last of the cleanup -- FOR THE MOMENT --- lib/arel/relations.rb | 1 + lib/arel/relations/aggregation.rb | 21 +++++++++++++++++++++ lib/arel/relations/compound.rb | 2 +- lib/arel/relations/join.rb | 24 +----------------------- lib/arel/relations/relation.rb | 5 ----- 5 files changed, 24 insertions(+), 29 deletions(-) create mode 100644 lib/arel/relations/aggregation.rb diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index 6cd599ad5d7e1..1a216993e0413 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -4,6 +4,7 @@ require 'arel/relations/compound' require 'arel/relations/writing' require 'arel/relations/table' +require 'arel/relations/aggregation' require 'arel/relations/join' require 'arel/relations/grouping' require 'arel/relations/projection' diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb new file mode 100644 index 0000000000000..7a568341254c1 --- /dev/null +++ b/lib/arel/relations/aggregation.rb @@ -0,0 +1,21 @@ +Aggregation = Struct.new(:relation) do + def selects + [] + end + + def table + relation + end + + def relation_for(attribute) + relation + end + + def table_sql(formatter = Sql::TableReference.new(relation)) + relation.to_sql(formatter) + end + + def attributes + relation.attributes.collect(&:to_attribute) + end +end \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index f0a3392e097ac..7b6f3a46f8b48 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -4,7 +4,7 @@ class Compound < Relation hash_on :relation delegate :joins, :selects, :orders, :groupings, :inserts, :taken, :skipped, :name, :alias, :aggregation?, :column_for, - :engine, :name_for, :table, :relation_for, :table_sql, + :engine, :table, :relation_for, :table_sql, :to => :relation def attributes diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 01e7e36f37ac8..42697310925da 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -51,29 +51,7 @@ def relation_for(attribute) private def externalize(relation) - Externalizer.new(relation) - end - - Externalizer = Struct.new(:relation) do - def selects - relation.aggregation?? [] : relation.selects - end - - def table - relation.aggregation?? relation : relation.table - end - - def relation_for(attribute) - relation.aggregation?? relation : relation.relation_for(attribute) - end - - def table_sql(formatter = Sql::TableReference.new(relation)) - relation.aggregation?? relation.to_sql(formatter) : relation.table.table_sql(formatter) - end - - def attributes - relation.aggregation?? relation.attributes.collect(&:to_attribute) : relation.attributes - end + relation.aggregation?? Aggregation.new(relation) : relation end end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 14d2143a8bd6c..cc0f40ea17f19 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -4,11 +4,6 @@ def session Session.new end - # INVESTIGATE - def name_for(relation) - relation.name - end - def to_sql(formatter = Sql::SelectStatement.new(self)) formatter.select [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", From b9e90e4e55290172d7c5918319fd5fe35aa6a10e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 5 May 2008 11:22:48 -0700 Subject: [PATCH 0156/1492] better column disambiguation --- lib/arel/primitives/attribute.rb | 8 +++--- lib/arel/relations/join.rb | 9 ++++--- lib/arel/relations/nil.rb | 1 + lib/arel/relations/relation.rb | 4 +-- spec/arel/unit/primitives/attribute_spec.rb | 29 +++++++++++++++++++++ spec/arel/unit/relations/join_spec.rb | 17 ++++++++++++ 6 files changed, 60 insertions(+), 8 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 14b8c18cb2a2c..5895f7e9b91a0 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -1,3 +1,5 @@ +require 'set' + module Arel class Attribute attr_reader :relation, :name, :alias, :ancestor @@ -67,9 +69,9 @@ def =~(other) !(history & other.history).empty? end - def %(other) - if other then (history - other.history) + (other.history - history) - else history + def /(other) + if other then (history & other.history).size.to_f / Set.new(history + other.history).size + else 0 end end end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 42697310925da..5356e57394236 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -44,9 +44,12 @@ def table_sql(formatter = Sql::TableReference.new(self)) end def relation_for(attribute) - externalize([relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2| - (attribute % a1).size <=> (attribute % a2).size - end.relation).relation_for(attribute) + x = [externalize(relation1), externalize(relation2)].max do |r1, r2| + o1, o2 = r1.relation_for(attribute), r2.relation_for(attribute) + a1, a2 = o1 && o1[attribute], o2 && o2[attribute] + + attribute / a1 <=> attribute / a2 + end.relation_for(attribute) end private diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index 258f60f478802..b0d97dd174317 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -2,6 +2,7 @@ module Arel class Nil < Relation def table; self end def table_sql(formatter = nil); '' end + def relation_for(attribute); nil end def name; '' end def to_s; '' end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index cc0f40ea17f19..8c56a0cdcc29a 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -140,8 +140,8 @@ def attribute_for_name(name) end def attribute_for_attribute(attribute) - attributes.select { |a| a =~ attribute }.min do |a1, a2| - (attribute % a1).size <=> (attribute % a2).size + attributes.select { |a| a =~ attribute }.max do |a1, a2| + (attribute / a1) <=> (attribute / a2) end end end diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index 561c47da1646d..b253892b58e02 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -57,6 +57,35 @@ module Arel end end + describe '/' do + before do + @aliased_relation = @relation.alias + @doubly_aliased_relation = @aliased_relation.alias.alias.alias.alias + end + + describe 'when dividing two identical attributes' do + it "returns 1.0" do + (@relation[:id] / @relation[:id]).should == 1.0 + (@aliased_relation[:id] / @aliased_relation[:id]).should == 1.0 + end + end + + describe 'when dividing two unrelated attributes' do + it "returns 0.0" do + (@relation[:id] / @relation[:name]).should == 0.0 + end + end + + describe 'when dividing two similar attributes' do + it 'returns a the highest score for the most similar attributes' do + (@aliased_relation[:id] / @relation[:id]) \ + .should == (@aliased_relation[:id] / @relation[:id]) + (@aliased_relation[:id] / @relation[:id]) \ + .should < (@aliased_relation[:id] / @aliased_relation[:id]) + end + end + end + describe 'hashing' do it "implements hash equality" do Attribute.new(@relation, 'name').should hash_the_same_as(Attribute.new(@relation, 'name')) diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index d517da8c1fe28..a538c8af68caf 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -203,6 +203,23 @@ module Arel end end end + + describe 'something really really complex' do + it '' do + users = @relation1 + photos = @relation2 + users_2 = users.alias + photos_2 = photos.alias + r = users \ + .join(photos) \ + .on(photos[:user_id].eq users[:id]) \ + .join(users_2) \ + .on(users_2[:id].eq photos[:user_id]) \ + .join(photos_2) \ + .on(users_2[:id].eq photos_2[:user_id]) + r.relation_for(photos[:user_id]).should == photos + end + end describe '[]' do describe 'when given an attribute belonging to both sub-relations' do From 680e080bb4399312f63a699d2f103632b41be927 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 5 May 2008 13:00:50 -0700 Subject: [PATCH 0157/1492] string passthrough for "group by" --- lib/arel/relations/relation.rb | 2 +- lib/arel/sql/formatters.rb | 6 ++++++ spec/arel/unit/relations/grouping_spec.rb | 1 - spec/arel/unit/relations/join_spec.rb | 17 ----------------- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 8c56a0cdcc29a..cd58f0f15cc4f 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -11,7 +11,7 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) (joins(self) unless joins(self).blank? ), ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("GROUP BY #{groupings.collect(&:to_sql)}" unless groupings.blank? ), + ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n"), name diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index 96bab2495c45a..5eab65726e788 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -44,6 +44,12 @@ def attribute(attribute) end end + class GroupClause < PassThrough + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + end + end + class WhereCondition < Formatter def attribute(attribute) "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" diff --git a/spec/arel/unit/relations/grouping_spec.rb b/spec/arel/unit/relations/grouping_spec.rb index 66205b8f951bc..5f781727cfb5b 100644 --- a/spec/arel/unit/relations/grouping_spec.rb +++ b/spec/arel/unit/relations/grouping_spec.rb @@ -20,7 +20,6 @@ module Arel describe 'when given a string' do it "passes the string through to the where clause" do - pending 'it should not quote the group clause' Grouping.new(@relation, 'asdf').to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index a538c8af68caf..d517da8c1fe28 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -203,23 +203,6 @@ module Arel end end end - - describe 'something really really complex' do - it '' do - users = @relation1 - photos = @relation2 - users_2 = users.alias - photos_2 = photos.alias - r = users \ - .join(photos) \ - .on(photos[:user_id].eq users[:id]) \ - .join(users_2) \ - .on(users_2[:id].eq photos[:user_id]) \ - .join(photos_2) \ - .on(users_2[:id].eq photos_2[:user_id]) - r.relation_for(photos[:user_id]).should == photos - end - end describe '[]' do describe 'when given an attribute belonging to both sub-relations' do From f22ea4dd5b20c979dbacf8fd5768659e9e4d0706 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 5 May 2008 23:15:32 -0700 Subject: [PATCH 0158/1492] performance optimization --- lib/arel/extensions/class.rb | 8 -------- lib/arel/extensions/object.rb | 2 +- lib/arel/primitives/attribute.rb | 2 +- lib/arel/primitives/value.rb | 3 ++- lib/arel/relations/join.rb | 4 ++-- lib/arel/relations/relation.rb | 13 +++++++++++-- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/arel/extensions/class.rb b/lib/arel/extensions/class.rb index 0e5b728c26550..fed2ef79c7054 100644 --- a/lib/arel/extensions/class.rb +++ b/lib/arel/extensions/class.rb @@ -1,12 +1,4 @@ class Class - def abstract(*methods) - methods.each do |method| - define_method method do - raise NotImplementedError - end - end - end - def hash_on(delegatee) define_method :eql? do |other| self == other diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index 779098f7ea487..69ec6a5dce001 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -10,7 +10,7 @@ def to_sql(formatter = nil) def equality_predicate_sql '=' end - + def metaclass class << self self diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 5895f7e9b91a0..30c03839e2da0 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -35,9 +35,9 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) def ==(other) self.class == other.class and - relation == other.relation and name == other.name and @alias == other.alias and + relation == other.relation and ancestor == other.ancestor end diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 5142eb45ca83c..8ed3c4ce30af9 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -17,7 +17,8 @@ def format(object) end def ==(other) - value == other.value + self.class == other.class and + value == other.value end def bind(relation) diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 5356e57394236..c1c3150629182 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -44,10 +44,10 @@ def table_sql(formatter = Sql::TableReference.new(self)) end def relation_for(attribute) - x = [externalize(relation1), externalize(relation2)].max do |r1, r2| + [externalize(relation1), externalize(relation2)].max do |r1, r2| o1, o2 = r1.relation_for(attribute), r2.relation_for(attribute) a1, a2 = o1 && o1[attribute], o2 && o2[attribute] - + attribute / a1 <=> attribute / a2 end.relation_for(attribute) end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index cd58f0f15cc4f..fc47a129a0c03 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -138,12 +138,21 @@ def [](index) def attribute_for_name(name) attributes.detect { |a| a.alias_or_name.to_s == name.to_s } end - + + # TESTME - added relation_for(x)[x] because of AR def attribute_for_attribute(attribute) attributes.select { |a| a =~ attribute }.max do |a1, a2| - (attribute / a1) <=> (attribute / a2) + (attribute / relation_for(a1)[a1]) <=> (attribute / relation_for(a2)[a2]) + end + end + + def attribute_for_attribute_with_memoization(attribute) + @attribute_for_attribute ||= Hash.new do |h, a| + h[a] = attribute_for_attribute_without_memoization(a) end + @attribute_for_attribute[attribute] end + alias_method_chain :attribute_for_attribute, :memoization end include AttributeAccessable From 116b6f05b0e72ce35808cb42dfbe4c543d8504ea Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 7 May 2008 00:32:32 -0700 Subject: [PATCH 0159/1492] removing operator overloading --- lib/arel/primitives/attribute.rb | 2 +- lib/arel/relations/relation.rb | 2 +- spec/arel/unit/primitives/attribute_spec.rb | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 30c03839e2da0..78a519b35cbe4 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -65,7 +65,7 @@ def history [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) end - def =~(other) + def match?(other) !(history & other.history).empty? end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index fc47a129a0c03..250eb85222ccb 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -141,7 +141,7 @@ def attribute_for_name(name) # TESTME - added relation_for(x)[x] because of AR def attribute_for_attribute(attribute) - attributes.select { |a| a =~ attribute }.max do |a1, a2| + attributes.select { |a| a.match?(attribute) }.max do |a1, a2| (attribute / relation_for(a1)[a1]) <=> (attribute / relation_for(a2)[a2]) end end diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index b253892b58e02..e21a5902d51fe 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -45,15 +45,15 @@ module Arel end describe Attribute::Congruence do - describe '=~' do + describe 'match?' do it "obtains if the attributes are identical" do - Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name) + Attribute.new(@relation, :name).should be_match(Attribute.new(@relation, :name)) end it "obtains if the attributes have an overlapping history" do - Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)).should =~ Attribute.new(@relation, :name) - Attribute.new(@relation, :name).should =~ Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)) + Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)).should be_match(Attribute.new(@relation, :name)) + Attribute.new(@relation, :name).should be_match(Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name))) end end From ea111521b7eb7456934a283d96f6eb986322baf2 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 7 May 2008 00:36:37 -0700 Subject: [PATCH 0160/1492] renamed attribute_for_attribute to find_attribute_matching_attribute --- lib/arel/relations/relation.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 250eb85222ccb..4653323514a71 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -127,32 +127,33 @@ module AttributeAccessable def [](index) case index when Symbol, String - attribute_for_name(index) + find_attribute_matching_name(index) when Attribute, Expression - attribute_for_attribute(index) + find_attribute_matching_attribute(index) when Array index.collect { |i| self[i] } end end - def attribute_for_name(name) + def find_attribute_matching_name(name) attributes.detect { |a| a.alias_or_name.to_s == name.to_s } end # TESTME - added relation_for(x)[x] because of AR - def attribute_for_attribute(attribute) + def find_attribute_matching_attribute(attribute) attributes.select { |a| a.match?(attribute) }.max do |a1, a2| + # FIXME relation_for(a1)[a1] should be a1.original or something (attribute / relation_for(a1)[a1]) <=> (attribute / relation_for(a2)[a2]) end end - def attribute_for_attribute_with_memoization(attribute) + def find_attribute_matching_attribute_with_memoization(attribute) @attribute_for_attribute ||= Hash.new do |h, a| - h[a] = attribute_for_attribute_without_memoization(a) + h[a] = find_attribute_matching_attribute_without_memoization(a) end @attribute_for_attribute[attribute] end - alias_method_chain :attribute_for_attribute, :memoization + alias_method_chain :find_attribute_matching_attribute, :memoization end include AttributeAccessable From fff47a5a5e92eccf949785231d1f6953d6fdc640 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 12 May 2008 15:40:06 -0700 Subject: [PATCH 0161/1492] some memoizing and hash equality performance optimizations --- lib/arel/primitives/attribute.rb | 14 +++++++------- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/relation.rb | 2 +- spec/arel/unit/primitives/attribute_spec.rb | 20 ++++++-------------- spec/arel/unit/relations/insertion_spec.rb | 2 +- spec/arel/unit/relations/update_spec.rb | 2 +- 6 files changed, 17 insertions(+), 25 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 78a519b35cbe4..acc4d86a804bb 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -9,8 +9,8 @@ def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end - def alias_or_name - @alias || name + def named?(hypothetical_name) + (@alias || name).to_s == hypothetical_name.to_s end def aggregation? @@ -57,12 +57,12 @@ def to_attribute include Transformations module Congruence - def self.included(klass) - klass.hash_on :name - end - + # def self.included(klass) + # klass.hash_on :name + # end + # def history - [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) + @history ||= [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) end def match?(other) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 7b6f3a46f8b48..663711760c008 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -8,7 +8,7 @@ class Compound < Relation :to => :relation def attributes - relation.attributes.collect { |a| a.bind(self) } + @attributes ||= relation.attributes.collect { |a| a.bind(self) } end end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 4653323514a71..b2f811cea207f 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -136,7 +136,7 @@ def [](index) end def find_attribute_matching_name(name) - attributes.detect { |a| a.alias_or_name.to_s == name.to_s } + attributes.detect { |a| a.named?(name) } end # TESTME - added relation_for(x)[x] because of AR diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index e21a5902d51fe..7e0155f84d93b 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -4,7 +4,7 @@ module Arel describe Attribute do before do @relation = Table.new(:users) - @attribute = Attribute.new(@relation, :id) + @attribute = @relation[:id] end describe Attribute::Transformations do @@ -45,22 +45,21 @@ module Arel end describe Attribute::Congruence do - describe 'match?' do - + describe '#match?' do it "obtains if the attributes are identical" do - Attribute.new(@relation, :name).should be_match(Attribute.new(@relation, :name)) + @attribute.should be_match(@attribute) end it "obtains if the attributes have an overlapping history" do - Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name)).should be_match(Attribute.new(@relation, :name)) - Attribute.new(@relation, :name).should be_match(Attribute.new(@relation, :name, :ancestor => Attribute.new(@relation, :name))) + Attribute.new(@relation, :id, :ancestor => @attribute).should be_match(@attribute) + @attribute.should be_match(Attribute.new(@relation, :id, :ancestor => @attribute)) end end describe '/' do before do @aliased_relation = @relation.alias - @doubly_aliased_relation = @aliased_relation.alias.alias.alias.alias + @doubly_aliased_relation = @aliased_relation.alias end describe 'when dividing two identical attributes' do @@ -85,13 +84,6 @@ module Arel end end end - - describe 'hashing' do - it "implements hash equality" do - Attribute.new(@relation, 'name').should hash_the_same_as(Attribute.new(@relation, 'name')) - Attribute.new(@relation, 'name').should_not hash_the_same_as(Attribute.new(@relation, 'id')) - end - end end describe '#to_sql' do diff --git a/spec/arel/unit/relations/insertion_spec.rb b/spec/arel/unit/relations/insertion_spec.rb index 10b70a203693e..0667aa665eb0e 100644 --- a/spec/arel/unit/relations/insertion_spec.rb +++ b/spec/arel/unit/relations/insertion_spec.rb @@ -24,7 +24,7 @@ module Arel @insertion.to_sql.should be_like(" INSERT INTO `users` - (`users`.`id`, `users`.`name`) VALUES (1, 'nick') + (`users`.`name`, `users`.`id`) VALUES ('nick', 1) ") end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index f411781392cf1..976e88dddc613 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -10,7 +10,7 @@ module Arel it "manufactures sql updating attributes when given multiple attributes" do Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` - SET `users`.`id` = 1, `users`.`name` = 'nick' + SET `users`.`name` = 'nick', `users`.`id` = 1 ") end From 562a0bf634bd61f61ebb0145d7626fb484e13c53 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 12 May 2008 15:50:07 -0700 Subject: [PATCH 0162/1492] some slight performance improvements --- lib/arel/primitives/attribute.rb | 8 ++++---- lib/arel/relations/join.rb | 8 ++++---- lib/arel/relations/recursion.rb | 2 +- lib/arel/relations/relation.rb | 3 +-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index acc4d86a804bb..39de11be26690 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -24,6 +24,10 @@ def column def original_relation relation.relation_for(self) end + + def original_attribute + original_relation[self] + end def format(object) object.to_sql(formatter) @@ -57,10 +61,6 @@ def to_attribute include Transformations module Congruence - # def self.included(klass) - # klass.hash_on :name - # end - # def history @history ||= [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index c1c3150629182..b3452968e4f15 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -44,15 +44,15 @@ def table_sql(formatter = Sql::TableReference.new(self)) end def relation_for(attribute) - [externalize(relation1), externalize(relation2)].max do |r1, r2| - o1, o2 = r1.relation_for(attribute), r2.relation_for(attribute) - a1, a2 = o1 && o1[attribute], o2 && o2[attribute] + [externalize(relation1).relation_for(attribute), externalize(relation2).relation_for(attribute)].max do |r1, r2| + a1, a2 = r1 && r1[attribute], r2 && r2[attribute] attribute / a1 <=> attribute / a2 - end.relation_for(attribute) + end end private + # FIXME - make instance method def externalize(relation) relation.aggregation?? Aggregation.new(relation) : relation end diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index 2c6024dc30302..90976c702bab7 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -6,7 +6,7 @@ def table end def relation_for(attribute) - self[attribute] and self + self end def table_sql(formatter = Sql::TableReference.new(self)) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index b2f811cea207f..db7d746c79152 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -142,8 +142,7 @@ def find_attribute_matching_name(name) # TESTME - added relation_for(x)[x] because of AR def find_attribute_matching_attribute(attribute) attributes.select { |a| a.match?(attribute) }.max do |a1, a2| - # FIXME relation_for(a1)[a1] should be a1.original or something - (attribute / relation_for(a1)[a1]) <=> (attribute / relation_for(a2)[a2]) + (attribute / a1.original_attribute) <=> (attribute / a2.original_attribute) end end From 16730fdbd0ab630320aba225314aa6a1a3b450fe Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 13 May 2008 16:53:36 -0700 Subject: [PATCH 0163/1492] fixed defect in alias --- doc/TODO | 15 +++++++++------ lib/arel/primitives/attribute.rb | 8 ++++++++ lib/arel/relations/aggregation.rb | 2 +- lib/arel/relations/alias.rb | 5 +---- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/join.rb | 8 +++++--- lib/arel/relations/projection.rb | 2 +- lib/arel/relations/recursion.rb | 2 +- lib/arel/relations/relation.rb | 10 +--------- lib/arel/sessions/session.rb | 8 -------- lib/arel/sql/christener.rb | 6 +++--- spec/arel/unit/relations/alias_spec.rb | 11 ++++++++++- spec/arel/unit/relations/insertion_spec.rb | 2 +- spec/arel/unit/relations/update_spec.rb | 2 +- spec/arel/unit/session/session_spec.rb | 10 +--------- 15 files changed, 44 insertions(+), 49 deletions(-) diff --git a/doc/TODO b/doc/TODO index 752579d2299ba..00a8ce4e4d9c1 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,11 +1,9 @@ todo: -- Explicitly model recursive structural decomposition / polymorphism -- Explicitly model the namer/externalizer using interpreter jargon -- All Sql Strategies should be accumulations with the top-level relation? -- lock - - SELECT suchandsuch FOR UPDATE +- instance methodify externalize +- test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. - rename select to where - and/or w/ predicates +- blocks for joins - cache expiry on write - rewrite of arecord querycache test in light of this - scoped writes @@ -65,6 +63,9 @@ done: - fix complex joining cases: - active record query adapter - anonymous table names +- Explicitly model recursive structural decomposition / polymorphism +- Explicitly model the namer/externalizer using interpreter jargon +- All Sql Strategies should be accumulations with the top-level relation? icebox: - #bind in Attribute and Expression should be doing a descend? @@ -76,4 +77,6 @@ icebox: - rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent - consider this code from has_many: # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ - @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } \ No newline at end of file + @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } +- lock + - SELECT suchandsuch FOR UPDATE diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 39de11be26690..5f8618ddfcc71 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -46,6 +46,14 @@ def ==(other) end module Transformations + def self.included(klass) + alias_method :eql?, :== + end + + def hash + name.hash + history.size.hash + end + def as(aliaz = nil) Attribute.new(relation, name, :alias => aliaz, :ancestor => self) end diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index 7a568341254c1..955a71c0b0a8a 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -16,6 +16,6 @@ def table_sql(formatter = Sql::TableReference.new(relation)) end def attributes - relation.attributes.collect(&:to_attribute) + @attributes ||= relation.attributes.collect(&:to_attribute) end end \ No newline at end of file diff --git a/lib/arel/relations/alias.rb b/lib/arel/relations/alias.rb index 08be02e862815..d14a51f67ac9e 100644 --- a/lib/arel/relations/alias.rb +++ b/lib/arel/relations/alias.rb @@ -1,13 +1,10 @@ module Arel class Alias < Compound include Recursion::BaseCase + alias_method :==, :equal? def initialize(relation) @relation = relation end - - def ==(other) - equal? other - end end end \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 663711760c008..649d11e8b1fbd 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -3,7 +3,7 @@ class Compound < Relation attr_reader :relation hash_on :relation delegate :joins, :selects, :orders, :groupings, :inserts, :taken, - :skipped, :name, :alias, :aggregation?, :column_for, + :skipped, :name, :aggregation?, :column_for, :engine, :table, :relation_for, :table_sql, :to => :relation diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index b3452968e4f15..b7c5c3f39b3a6 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -27,7 +27,7 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) end def attributes - (externalize(relation1).attributes + + @attributes ||= (externalize(relation1).attributes + externalize(relation2).attributes).collect { |a| a.bind(self) } end @@ -44,9 +44,11 @@ def table_sql(formatter = Sql::TableReference.new(self)) end def relation_for(attribute) - [externalize(relation1).relation_for(attribute), externalize(relation2).relation_for(attribute)].max do |r1, r2| + [ + externalize(relation1).relation_for(attribute), + externalize(relation2).relation_for(attribute) + ].max do |r1, r2| a1, a2 = r1 && r1[attribute], r2 && r2[attribute] - attribute / a1 <=> attribute / a2 end end diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/projection.rb index f09d4f894bf77..8a08cda70c4ff 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -7,7 +7,7 @@ def initialize(relation, *projections) end def attributes - projections.collect { |p| p.bind(self) } + @attributes ||= projections.collect { |p| p.bind(self) } end def ==(other) diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index 90976c702bab7..2c6024dc30302 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -6,7 +6,7 @@ def table end def relation_for(attribute) - self + self[attribute] and self end def table_sql(formatter = Sql::TableReference.new(self)) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index db7d746c79152..c576033938979 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -139,20 +139,12 @@ def find_attribute_matching_name(name) attributes.detect { |a| a.named?(name) } end - # TESTME - added relation_for(x)[x] because of AR + # TESTME - added original_attribute because of AR def find_attribute_matching_attribute(attribute) attributes.select { |a| a.match?(attribute) }.max do |a1, a2| (attribute / a1.original_attribute) <=> (attribute / a2.original_attribute) end end - - def find_attribute_matching_attribute_with_memoization(attribute) - @attribute_for_attribute ||= Hash.new do |h, a| - h[a] = find_attribute_matching_attribute_without_memoization(a) - end - @attribute_for_attribute[attribute] - end - alias_method_chain :find_attribute_matching_attribute, :memoization end include AttributeAccessable diff --git a/lib/arel/sessions/session.rb b/lib/arel/sessions/session.rb index becf23b8b6a28..9c61d0cba1928 100644 --- a/lib/arel/sessions/session.rb +++ b/lib/arel/sessions/session.rb @@ -44,13 +44,5 @@ def delete(delete) end end include CRUD - - module Transactions - end - include Transactions - - module UnitOfWork - end - include UnitOfWork end end \ No newline at end of file diff --git a/lib/arel/sql/christener.rb b/lib/arel/sql/christener.rb index 894f0303425c7..26e1acab58bae 100644 --- a/lib/arel/sql/christener.rb +++ b/lib/arel/sql/christener.rb @@ -3,9 +3,9 @@ module Sql class Christener def name_for(relation) @used_names ||= Hash.new(0) - @relation_names ||= Hash.new do |h, k| - @used_names[k.name] += 1 - h[k] = k.name + (@used_names[k.name] > 1 ? "_#{@used_names[k.name]}" : '') + @relation_names ||= Hash.new do |hash, relation| + @used_names[name = relation.name] += 1 + hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') end @relation_names[relation] end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 25dbf70668701..85850b5e1ae29 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -7,10 +7,19 @@ module Arel end describe '==' do - it "returns the alias" do + it "obtains if the objects are the same" do Alias.new(@relation).should_not == Alias.new(@relation) (aliaz = Alias.new(@relation)).should == aliaz end + + it '' do + @relation.select(@relation[:id].eq(1)).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE + `users`.`id` = 1 + ") + end end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/insertion_spec.rb b/spec/arel/unit/relations/insertion_spec.rb index 0667aa665eb0e..10b70a203693e 100644 --- a/spec/arel/unit/relations/insertion_spec.rb +++ b/spec/arel/unit/relations/insertion_spec.rb @@ -24,7 +24,7 @@ module Arel @insertion.to_sql.should be_like(" INSERT INTO `users` - (`users`.`name`, `users`.`id`) VALUES ('nick', 1) + (`users`.`id`, `users`.`name`) VALUES (1, 'nick') ") end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index 976e88dddc613..f411781392cf1 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -10,7 +10,7 @@ module Arel it "manufactures sql updating attributes when given multiple attributes" do Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` - SET `users`.`name` = 'nick', `users`.`id` = 1 + SET `users`.`id` = 1, `users`.`name` = 'nick' ") end diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb index c2eb9a45552ac..fbb2b7791b874 100644 --- a/spec/arel/unit/session/session_spec.rb +++ b/spec/arel/unit/session/session_spec.rb @@ -73,20 +73,12 @@ module Arel end end - describe Session::Transactions do + describe 'Transactions' do describe '#begin' do end describe '#end' do end end - - describe Session::UnitOfWork do - describe '#flush' do - end - - describe '#clear' do - end - end end end \ No newline at end of file From 9376459a7186b794b29e11c55186135004e8f3b8 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 14 May 2008 20:33:23 -0700 Subject: [PATCH 0164/1492] fixed defect with select inside of alias joined to the same table (yikes) --- lib/arel/primitives/attribute.rb | 8 ++------ lib/arel/relations/join.rb | 4 ++-- lib/arel/relations/selection.rb | 2 +- spec/arel/unit/relations/join_spec.rb | 23 ++++++++++++++++++----- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 5f8618ddfcc71..22ee37524ee7d 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -47,11 +47,7 @@ def ==(other) module Transformations def self.included(klass) - alias_method :eql?, :== - end - - def hash - name.hash + history.size.hash + klass.hash_on :name end def as(aliaz = nil) @@ -70,7 +66,7 @@ def to_attribute module Congruence def history - @history ||= [self] + (ancestor ? [ancestor, ancestor.history].flatten : []) + @history ||= [self] + (ancestor ? ancestor.history : []) end def match?(other) diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index b7c5c3f39b3a6..14903cf01d97d 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -21,7 +21,7 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) join_sql, externalize(relation2).table_sql(formatter), ("ON" unless predicates.blank?), - predicates.collect { |p| p.bind(environment).to_sql }.join(' AND ') + (predicates + externalize(relation2).selects).collect { |p| p.bind(environment).to_sql }.join(' AND ') ].compact.join(" ") [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") end @@ -32,7 +32,7 @@ def attributes end def selects - (externalize(relation1).selects + externalize(relation2).selects).collect { |s| s.bind(self) } + (externalize(relation1).selects).collect { |s| s.bind(self) } end def table diff --git a/lib/arel/relations/selection.rb b/lib/arel/relations/selection.rb index 38a40e1b76916..0e7615a83ca27 100644 --- a/lib/arel/relations/selection.rb +++ b/lib/arel/relations/selection.rb @@ -15,7 +15,7 @@ def ==(other) end def selects - relation.selects + [predicate] + (relation.selects + [predicate]).collect { |p| p.bind(self) } end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index d517da8c1fe28..b5c5dc8e331d0 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -56,14 +56,13 @@ module Arel ") end - it 'manufactures sql joining the two tables, merging any selects' do + it 'manufactures sql joining the two tables, with selects from the right table in the ON clause' do Join.new("INNER JOIN", @relation1.select(@relation1[:id].eq(1)), @relation2.select(@relation2[:id].eq(2)), @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` + INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` AND `photos`.`id` = 2 WHERE `users`.`id` = 1 - AND `photos`.`id` = 2 ") end end @@ -158,10 +157,24 @@ module Arel SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - WHERE `users_2`.`id` = 1 + ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 ") end + + describe 'when the selection occurs before the alias' do + it 'manufactures sql aliasing the predicates properly' do + aliased_relation = @relation1.select(@relation1[:id].eq(1)).alias + @relation1 \ + .join(aliased_relation) \ + .on(aliased_relation[:id].eq(@relation1[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 + ") + end + end end describe 'when joining the relation to itself multiple times' do From 4b300befaffd0486eb4ffbc63d64f04c85cd0219 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 15 May 2008 18:42:16 -0700 Subject: [PATCH 0165/1492] experimenting with new binding stuff --- lib/arel/primitives/expression.rb | 3 ++- lib/arel/relations/aggregation.rb | 38 +++++++++++++++++-------------- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/join.rb | 12 ++++++---- lib/arel/relations/projection.rb | 4 ++++ lib/arel/relations/recursion.rb | 4 ---- lib/arel/sql/christener.rb | 2 +- 7 files changed, 36 insertions(+), 29 deletions(-) diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 75bf1f2ef0292..10e72f426e0fc 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -14,7 +14,8 @@ def as(aliaz) end def bind(new_relation) - new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + # new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + self end def to_attribute diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index 955a71c0b0a8a..55f24997cc793 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -1,21 +1,25 @@ -Aggregation = Struct.new(:relation) do - def selects - [] - end - - def table - relation - end +module Arel + class Aggregation < Compound + include Recursion::BaseCase + + def initialize(relation) + @relation = relation + end + + def selects + [] + end - def relation_for(attribute) - relation - end - - def table_sql(formatter = Sql::TableReference.new(relation)) - relation.to_sql(formatter) - end + def table_sql(formatter = Sql::TableReference.new(relation)) + relation.to_sql(formatter) + end - def attributes - @attributes ||= relation.attributes.collect(&:to_attribute) + def attributes + @attributes ||= relation.attributes.collect(&:to_attribute) + end + + def ==(other) + self.class == other.class and self.relation == other.relation + end end end \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 649d11e8b1fbd..ca192a6e8a27b 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -4,7 +4,7 @@ class Compound < Relation hash_on :relation delegate :joins, :selects, :orders, :groupings, :inserts, :taken, :skipped, :name, :aggregation?, :column_for, - :engine, :table, :relation_for, :table_sql, + :engine, :table, :table_sql, :to => :relation def attributes diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 14903cf01d97d..d42af5a499ae7 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -35,12 +35,8 @@ def selects (externalize(relation1).selects).collect { |s| s.bind(self) } end - def table - externalize(relation1).table - end - def table_sql(formatter = Sql::TableReference.new(self)) - externalize(table).table_sql(formatter) + externalize(relation1).table_sql(formatter) end def relation_for(attribute) @@ -59,4 +55,10 @@ def externalize(relation) relation.aggregation?? Aggregation.new(relation) : relation end end + + class Relation + def relation_for(attribute) + self[attribute] && self + end + end end \ No newline at end of file diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/projection.rb index 8a08cda70c4ff..66aa61f1d9b2f 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -19,5 +19,9 @@ def ==(other) def aggregation? attributes.any?(&:aggregation?) end + + def relation_for(attribute) + self[attribute] && self || relation.relation_for(attribute) + end end end \ No newline at end of file diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index 2c6024dc30302..848b059507b01 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -5,10 +5,6 @@ def table self end - def relation_for(attribute) - self[attribute] and self - end - def table_sql(formatter = Sql::TableReference.new(self)) formatter.table self end diff --git a/lib/arel/sql/christener.rb b/lib/arel/sql/christener.rb index 26e1acab58bae..d0dbf47eaf52c 100644 --- a/lib/arel/sql/christener.rb +++ b/lib/arel/sql/christener.rb @@ -7,7 +7,7 @@ def name_for(relation) @used_names[name = relation.name] += 1 hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') end - @relation_names[relation] + @relation_names[relation.table] end end end From fdffe2160a4b855d7d9e611c6326f4a509c7cb07 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 15 May 2008 19:26:18 -0700 Subject: [PATCH 0166/1492] thinks must get worse before they get better --- lib/arel/relations/compound.rb | 6 +++++- lib/arel/relations/join.rb | 14 ++++++++------ lib/arel/relations/nil.rb | 3 ++- lib/arel/relations/recursion.rb | 12 ++++++++++++ lib/arel/relations/relation.rb | 4 ---- spec/arel/unit/relations/join_spec.rb | 4 ++++ spec/arel/unit/relations/projection_spec.rb | 2 +- 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index ca192a6e8a27b..94616ff14f0f7 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation hash_on :relation - delegate :joins, :selects, :orders, :groupings, :inserts, :taken, + delegate :joins, :selects, :join?, :orders, :groupings, :inserts, :taken, :skipped, :name, :aggregation?, :column_for, :engine, :table, :table_sql, :to => :relation @@ -10,5 +10,9 @@ class Compound < Relation def attributes @attributes ||= relation.attributes.collect { |a| a.bind(self) } end + + def relation_for(attribute) + join? && relation.relation_for(attribute) || self[attribute] && self + end end end \ No newline at end of file diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index d42af5a499ae7..05ed6efc23df5 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -49,16 +49,18 @@ def relation_for(attribute) end end + def aggregation? + relation1.aggregation? or relation2.aggregation? + end + + def join? + true + end + private # FIXME - make instance method def externalize(relation) relation.aggregation?? Aggregation.new(relation) : relation end end - - class Relation - def relation_for(attribute) - self[attribute] && self - end - end end \ No newline at end of file diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index b0d97dd174317..34f9ea872277c 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,6 +1,7 @@ module Arel class Nil < Relation - def table; self end + include Recursion::BaseCase + def table_sql(formatter = nil); '' end def relation_for(attribute); nil end def name; '' end diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index 848b059507b01..c5ca171fd2e3e 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -8,6 +8,18 @@ def table def table_sql(formatter = Sql::TableReference.new(self)) formatter.table self end + + def relation_for(attribute) + self[attribute] && self + end + + def join? + false + end + + def aggregation? + false + end end end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index c576033938979..884b743f20e7f 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -39,10 +39,6 @@ def christener @christener ||= Sql::Christener.new end - def aggregation? - false - end - module Enumerable include ::Enumerable diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index b5c5dc8e331d0..46215b158b306 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -65,6 +65,10 @@ module Arel WHERE `users`.`id` = 1 ") end + + it '' do + p @relation1.select(@relation1[:id].eq(1)).join(@relation2).on(@predicate).select(@relation1[:id].eq(1)).to_sql + end end end diff --git a/spec/arel/unit/relations/projection_spec.rb b/spec/arel/unit/relations/projection_spec.rb index 0008858e081ab..cede58354b0fd 100644 --- a/spec/arel/unit/relations/projection_spec.rb +++ b/spec/arel/unit/relations/projection_spec.rb @@ -13,7 +13,7 @@ module Arel end it "manufactures attributes associated with the projection relation" do - @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } + # @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } end end From e4ee2a35c8dc62efed965bf0023a517c65f1c9e7 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Thu, 15 May 2008 19:44:06 -0700 Subject: [PATCH 0167/1492] worser --- lib/arel/relations/grouping.rb | 2 +- spec/arel/unit/relations/join_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index 3f0ea54407079..2c39d23b2daa0 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -17,7 +17,7 @@ def aggregation? end def name - table.name + '_aggregation' + relation.name + '_aggregation' end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 46215b158b306..b3cd28ac25491 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -69,6 +69,10 @@ module Arel it '' do p @relation1.select(@relation1[:id].eq(1)).join(@relation2).on(@predicate).select(@relation1[:id].eq(1)).to_sql end + + it '' do + p @relation1.join(@relation2).on(@predicate).group(@relation1[:id]).to_sql + end end end From 71bb593fb240f8e49931b3e3415a827900a032fd Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 12:12:30 -0700 Subject: [PATCH 0168/1492] reorganized integration join specs --- .../integration/joins/with_adjacency_spec.rb | 101 +++++++++ .../joins/with_aggregations_spec.rb | 75 +++++++ .../integration/joins/with_compounds_spec.rb | 49 +++++ spec/arel/unit/relations/join_spec.rb | 194 ++---------------- 4 files changed, 238 insertions(+), 181 deletions(-) create mode 100644 spec/arel/integration/joins/with_adjacency_spec.rb create mode 100644 spec/arel/integration/joins/with_aggregations_spec.rb create mode 100644 spec/arel/integration/joins/with_compounds_spec.rb diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb new file mode 100644 index 0000000000000..eaa0b6cdf5c86 --- /dev/null +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -0,0 +1,101 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table.new(:users) + @relation2 = @relation1.alias + @predicate = @relation1[:id].eq(@relation2[:id]) + end + + describe 'when joining a relation to itself' do + describe '#to_sql' do + it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do + @relation1.join(@relation2).on(@predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + ") + end + + describe 'when joining with a selection on the same relation' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@relation2.select(@relation2[:id].eq(1))) \ + .on(@predicate) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 + ") + end + + describe 'when the selection occurs before the alias' do + it 'manufactures sql aliasing the predicates properly' do + relation2 = @relation1.select(@relation1[:id].eq(1)).alias + @relation1 \ + .join(relation2) \ + .on(relation2[:id].eq(@relation1[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 + ") + end + end + end + + describe 'when joining the relation to itself multiple times' do + before do + @relation3 = @relation1.alias + end + + describe 'when joining left-associatively' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@relation2.join(@relation3).on(@relation2[:id].eq(@relation3[:id]))) \ + .on(@relation1[:id].eq(@relation2[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + ") + end + end + + describe 'when joining right-associatively' do + it 'manufactures sql aliasing the tables properly' do + @relation1 \ + .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ + .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + ") + end + end + end + end + + describe '[]' do + describe 'when given an attribute belonging to both sub-relations' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + relation = @relation1.join(@relation2).on(@predicate) + relation[@relation1[:id]].ancestor.should == @relation1[:id] + relation[@relation2[:id]].ancestor.should == @relation2[:id] + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb new file mode 100644 index 0000000000000..e6af920d32dd1 --- /dev/null +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -0,0 +1,75 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe 'when joining aggregated relations' do + before do + @aggregation = @relation2 \ + .group(@relation2[:user_id]) \ + .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ + end + + describe '#attributes' do + it 'it transforms aggregate expressions into attributes' do + join_with_aggregation = Join.new("INNER JOIN", @relation1, @aggregation, @predicate) + join_with_aggregation.attributes.should == + (@relation1.attributes + @aggregation.attributes).collect(&:to_attribute).collect { |a| a.bind(join_with_aggregation) } + end + end + + describe '#to_sql' do + describe 'with the aggregation on the right' do + it 'manufactures sql joining the left table to a derived table' do + Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` + ON `users`.`id` = `photos_aggregation`.`user_id` + ") + end + end + + describe 'with the aggregation on the left' do + it 'manufactures sql joining the right table to a derived table' do + Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(" + SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` + INNER JOIN `users` + ON `users`.`id` = `photos_aggregation`.`user_id` + ") + end + end + + describe 'when the aggration has a selection' do + describe 'with the aggregation on the left' do + it "manufactures sql keeping selects on the aggregation within the derived table" do + Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` + ON `users`.`id` = `photos_aggregation`.`user_id` + ") + end + end + + describe 'with the aggregation on the right' do + it "manufactures sql keeping selects on the aggregation within the derived table" do + Join.new("INNER JOIN", @aggregation.select(@aggregation[:user_id].eq(1)), @relation1, @predicate).to_sql.should be_like(" + SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` + INNER JOIN `users` + ON `users`.`id` = `photos_aggregation`.`user_id` + ") + end + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb new file mode 100644 index 0000000000000..49f013219034d --- /dev/null +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -0,0 +1,49 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe 'when a compound contains a join' do + describe '#to_sql' do + describe 'when the compound is a select' do + it 'manufactures sql disambiguating the tables' do + @relation1 \ + .select(@relation1[:id].eq(1)) \ + .join(@relation2) \ + .on(@predicate) \ + .select(@relation1[:id].eq(1)) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + WHERE `users`.`id` = 1 + AND `users`.`id` = 1 + ") + end + end + + describe 'when the compound is a group' do + it 'manufactures sql disambiguating the tables' do + @relation1 \ + .join(@relation2) \ + .on(@predicate) \ + .group(@relation1[:id]) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + GROUP BY `users`.`id` + ") + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index b3cd28ac25491..347566e6ea384 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -38,16 +38,16 @@ module Arel end end - describe 'when joining simple relations' do - describe '#attributes' do - it 'combines the attributes of the two relations' do - join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) - join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } - end + describe '#attributes' do + it 'combines the attributes of the two relations' do + join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) + join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } end + end - describe '#to_sql' do + describe '#to_sql' do + describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` @@ -65,184 +65,16 @@ module Arel WHERE `users`.`id` = 1 ") end - - it '' do - p @relation1.select(@relation1[:id].eq(1)).join(@relation2).on(@predicate).select(@relation1[:id].eq(1)).to_sql - end - - it '' do - p @relation1.join(@relation2).on(@predicate).group(@relation1[:id]).to_sql - end - end - end - - describe 'when joining aggregated relations' do - before do - @aggregation = @relation2 \ - .group(@relation2[:user_id]) \ - .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ - end - - describe '#attributes' do - it 'it transforms aggregate expressions into attributes' do - join_with_aggregation = Join.new("INNER JOIN", @relation1, @aggregation, @predicate) - join_with_aggregation.attributes.should == - (@relation1.attributes + @aggregation.attributes).collect(&:to_attribute).collect { |a| a.bind(join_with_aggregation) } - end end - describe '#to_sql' do - describe 'with the aggregation on the right' do - it 'manufactures sql joining the left table to a derived table' do - Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` - ON `users`.`id` = `photos_aggregation`.`user_id` - ") - end - end - - describe 'with the aggregation on the left' do - it 'manufactures sql joining the right table to a derived table' do - Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(" - SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` - INNER JOIN `users` - ON `users`.`id` = `photos_aggregation`.`user_id` - ") - end - end - - describe 'when the aggration has a selection' do - describe 'with the aggregation on the left' do - it "manufactures sql keeping selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` - ON `users`.`id` = `photos_aggregation`.`user_id` - ") - end - end - - describe 'with the aggregation on the right' do - it "manufactures sql keeping selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @aggregation.select(@aggregation[:user_id].eq(1)), @relation1, @predicate).to_sql.should be_like(" - SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` - INNER JOIN `users` - ON `users`.`id` = `photos_aggregation`.`user_id` - ") - end - end - end - end - end - - describe 'when joining a relation to itself' do - before do - @aliased_relation = @relation1.alias - @predicate = @relation1[:id].eq(@aliased_relation[:id]) - end - - describe '#to_sql' do - it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do - @relation1.join(@aliased_relation).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + describe 'when joining with a string' do + it "passes the string through to the where clause" do + Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name` FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` + INNER JOIN asdf ON fdsa ") end - - describe 'when joining with a selection on the same relation' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@aliased_relation.select(@aliased_relation[:id].eq(1))) \ - .on(@predicate) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 - ") - end - - describe 'when the selection occurs before the alias' do - it 'manufactures sql aliasing the predicates properly' do - aliased_relation = @relation1.select(@relation1[:id].eq(1)).alias - @relation1 \ - .join(aliased_relation) \ - .on(aliased_relation[:id].eq(@relation1[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 - ") - end - end - end - - describe 'when joining the relation to itself multiple times' do - before do - @relation2 = @relation1.alias - @relation3 = @relation1.alias - end - - describe 'when joining left-associatively' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2.join(@relation3).on(@relation2[:id].eq(@relation3[:id]))) \ - .on(@relation1[:id].eq(@relation2[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") - end - end - - describe 'when joining right-associatively' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ - .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") - end - end - end - end - - describe '[]' do - describe 'when given an attribute belonging to both sub-relations' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - relation = @relation1.join(@aliased_relation).on(@predicate) - relation[@relation1[:id]].ancestor.should == @relation1[:id] - relation[@aliased_relation[:id]].ancestor.should == @aliased_relation[:id] - end - end - end - end - - describe 'when joining with a string' do - it "passes the string through to the where clause" do - Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - INNER JOIN asdf ON fdsa - ") end end end From 6a0097468213e928f477f638ec53e9efa396febe Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 12:32:59 -0700 Subject: [PATCH 0169/1492] some cleanup, notes for further cleanup/investigation --- lib/arel/predicates.rb | 2 +- lib/arel/primitives/attribute.rb | 28 ++++++++-------- lib/arel/primitives/expression.rb | 32 +++++++++---------- lib/arel/relations/aggregation.rb | 6 ++++ lib/arel/relations/compound.rb | 1 + lib/arel/relations/join.rb | 31 ++++++++---------- lib/arel/relations/nil.rb | 1 + lib/arel/relations/projection.rb | 13 ++++---- lib/arel/relations/recursion.rb | 1 + lib/arel/relations/table.rb | 10 +++--- .../integration/joins/with_adjacency_spec.rb | 12 ++++--- 11 files changed, 72 insertions(+), 65 deletions(-) diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index 7faaebfc1768d..cad4969952582 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -55,7 +55,7 @@ def predicate_sql; '<' end end class Match < Binary - alias_method :regexp, :operand2 + def predicate_sql; 'LIKE' end end class In < Binary diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 22ee37524ee7d..9d5b98474f36f 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -20,17 +20,9 @@ def aggregation? def column original_relation.column_for(self) end - - def original_relation - relation.relation_for(self) - end - - def original_attribute - original_relation[self] - end - + def format(object) - object.to_sql(formatter) + object.to_sql(Sql::Attribute.new(self)) end def to_sql(formatter = Sql::WhereCondition.new(relation)) @@ -45,6 +37,17 @@ def ==(other) ancestor == other.ancestor end + module Origin + def original_relation + relation.relation_for(self) + end + + def original_attribute + original_relation[self] + end + end + include Origin + module Transformations def self.included(klass) klass.hash_on :name @@ -134,10 +137,5 @@ def average end end include Expressions - - private - def formatter - Sql::Attribute.new(self) - end end end \ No newline at end of file diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 10e72f426e0fc..3cde9d87249be 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -7,22 +7,6 @@ class Expression < Attribute def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor end - - module Transformations - def as(aliaz) - Expression.new(attribute, function_sql, aliaz, self) - end - - def bind(new_relation) - # new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) - self - end - - def to_attribute - Attribute.new(relation, @alias, :ancestor => self) - end - end - include Transformations def to_sql(formatter = Sql::SelectClause.new(relation)) formatter.expression self @@ -39,5 +23,21 @@ def ==(other) ancestor == other.ancestor and @alias == other.alias end + + module Transformations + def as(aliaz) + Expression.new(attribute, function_sql, aliaz, self) + end + + def bind(new_relation) + # new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + self + end + + def to_attribute + Attribute.new(relation, @alias, :ancestor => self) + end + end + include Transformations end end \ No newline at end of file diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index 55f24997cc793..4c4ef0dfed0f0 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -22,4 +22,10 @@ def ==(other) self.class == other.class and self.relation == other.relation end end + + class Relation + def externalize + aggregation?? Aggregation.new(self) : self + end + end end \ No newline at end of file diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 94616ff14f0f7..1459c163cfa86 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -11,6 +11,7 @@ def attributes @attributes ||= relation.attributes.collect { |a| a.bind(self) } end + # XXX def relation_for(attribute) join? && relation.relation_for(attribute) || self[attribute] && self end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 05ed6efc23df5..92bbbd56262e1 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -16,39 +16,42 @@ def ==(other) ) end + def table_sql(formatter = Sql::TableReference.new(self)) + relation1.externalize.table_sql(formatter) + end + def joins(environment, formatter = Sql::TableReference.new(environment)) this_join = [ join_sql, - externalize(relation2).table_sql(formatter), + relation2.externalize.table_sql(formatter), ("ON" unless predicates.blank?), - (predicates + externalize(relation2).selects).collect { |p| p.bind(environment).to_sql }.join(' AND ') + (predicates + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql }.join(' AND ') ].compact.join(" ") [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") end def attributes - @attributes ||= (externalize(relation1).attributes + - externalize(relation2).attributes).collect { |a| a.bind(self) } + @attributes ||= (relation1.externalize.attributes + + relation2.externalize.attributes).collect { |a| a.bind(self) } end + # XXX def selects - (externalize(relation1).selects).collect { |s| s.bind(self) } - end - - def table_sql(formatter = Sql::TableReference.new(self)) - externalize(relation1).table_sql(formatter) + (relation1.externalize.selects).collect { |s| s.bind(self) } end + # XXX def relation_for(attribute) [ - externalize(relation1).relation_for(attribute), - externalize(relation2).relation_for(attribute) + relation1.externalize.relation_for(attribute), + relation2.externalize.relation_for(attribute) ].max do |r1, r2| a1, a2 = r1 && r1[attribute], r2 && r2[attribute] attribute / a1 <=> attribute / a2 end end + # TESTME def aggregation? relation1.aggregation? or relation2.aggregation? end @@ -56,11 +59,5 @@ def aggregation? def join? true end - - private - # FIXME - make instance method - def externalize(relation) - relation.aggregation?? Aggregation.new(relation) : relation - end end end \ No newline at end of file diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index 34f9ea872277c..e78ebe6088b07 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,5 +1,6 @@ module Arel class Nil < Relation + # XXX include Recursion::BaseCase def table_sql(formatter = nil); '' end diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/projection.rb index 66aa61f1d9b2f..87b952d672c04 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -10,18 +10,19 @@ def attributes @attributes ||= projections.collect { |p| p.bind(self) } end - def ==(other) - self.class == other.class and - relation == other.relation and - projections == other.projections - end - def aggregation? attributes.any?(&:aggregation?) end + # XXX def relation_for(attribute) self[attribute] && self || relation.relation_for(attribute) end + + def ==(other) + self.class == other.class and + relation == other.relation and + projections == other.projections + end end end \ No newline at end of file diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index c5ca171fd2e3e..7507613a1200b 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -1,6 +1,7 @@ module Arel module Recursion module BaseCase + # XXX def table self end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 5c3ba6c57509b..b95e51a3070f4 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -20,11 +20,6 @@ def column_for(attribute) self[attribute] and columns.detect { |c| c.name == attribute.name.to_s } end - def ==(other) - self.class == other.class and - name == other.name - end - def columns @columns ||= engine.columns(name, "#{name} Columns") end @@ -32,5 +27,10 @@ def columns def reset @attributes = @columns = nil end + + def ==(other) + self.class == other.class and + name == other.name + end end end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index eaa0b6cdf5c86..74d461319c3ea 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -22,7 +22,7 @@ module Arel describe 'when joining with a selection on the same relation' do it 'manufactures sql aliasing the tables properly' do @relation1 \ - .join(@relation2.select(@relation2[:id].eq(1))) \ + .join(@relation2.select(@relation2[:id].eq(1))) \ .on(@predicate) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` @@ -35,8 +35,8 @@ module Arel describe 'when the selection occurs before the alias' do it 'manufactures sql aliasing the predicates properly' do relation2 = @relation1.select(@relation1[:id].eq(1)).alias - @relation1 \ - .join(relation2) \ + @relation1 \ + .join(relation2) \ .on(relation2[:id].eq(@relation1[:id])) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` @@ -55,8 +55,10 @@ module Arel describe 'when joining left-associatively' do it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2.join(@relation3).on(@relation2[:id].eq(@relation3[:id]))) \ + @relation1 \ + .join(@relation2 \ + .join(@relation3) \ + .on(@relation2[:id].eq(@relation3[:id]))) \ .on(@relation1[:id].eq(@relation2[:id])) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` From 0ff5607e1e6e150915543766ac42a292a69fcfd6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 13:06:23 -0700 Subject: [PATCH 0170/1492] cleaned up nil --- lib/arel/relations/aggregation.rb | 9 +++++++-- lib/arel/relations/join.rb | 9 +++++++-- lib/arel/relations/nil.rb | 7 +------ lib/arel/relations/recursion.rb | 8 -------- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index 4c4ef0dfed0f0..d18ef014fa205 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -19,13 +19,18 @@ def attributes end def ==(other) - self.class == other.class and self.relation == other.relation + self.class == other.class and + self.relation == other.relation end end class Relation def externalize - aggregation?? Aggregation.new(self) : self + @externalized ||= aggregation?? Aggregation.new(self) : self + end + + def aggregation? + false end end end \ No newline at end of file diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 92bbbd56262e1..2dd3555bac8f1 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -35,9 +35,8 @@ def attributes relation2.externalize.attributes).collect { |a| a.bind(self) } end - # XXX def selects - (relation1.externalize.selects).collect { |s| s.bind(self) } + relation1.externalize.selects end # XXX @@ -60,4 +59,10 @@ def join? true end end + + class Relation + def join? + false + end + end end \ No newline at end of file diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index e78ebe6088b07..714b11cc2af61 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,16 +1,11 @@ module Arel class Nil < Relation - # XXX - include Recursion::BaseCase - def table_sql(formatter = nil); '' end def relation_for(attribute); nil end def name; '' end - def to_s; '' end - + def ==(other) self.class == other.class end end - end \ No newline at end of file diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index 7507613a1200b..1333d7ff57ca9 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -13,14 +13,6 @@ def table_sql(formatter = Sql::TableReference.new(self)) def relation_for(attribute) self[attribute] && self end - - def join? - false - end - - def aggregation? - false - end end end end \ No newline at end of file From 6c173acf0a2ccc4907cf55709def5752f59d0167 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 13:14:11 -0700 Subject: [PATCH 0171/1492] cleanup --- lib/arel/relations/projection.rb | 5 ----- lib/arel/relations/recursion.rb | 1 - lib/arel/relations/selection.rb | 8 ++++---- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/projection.rb index 87b952d672c04..7c64726852e6a 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -14,11 +14,6 @@ def aggregation? attributes.any?(&:aggregation?) end - # XXX - def relation_for(attribute) - self[attribute] && self || relation.relation_for(attribute) - end - def ==(other) self.class == other.class and relation == other.relation and diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index 1333d7ff57ca9..fa4d9969c9ce4 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -1,7 +1,6 @@ module Arel module Recursion module BaseCase - # XXX def table self end diff --git a/lib/arel/relations/selection.rb b/lib/arel/relations/selection.rb index 0e7615a83ca27..a37f51c9ecd61 100644 --- a/lib/arel/relations/selection.rb +++ b/lib/arel/relations/selection.rb @@ -8,14 +8,14 @@ def initialize(relation, *predicates) @predicate = predicate.bind(@relation) end + def selects + (relation.selects + [predicate]).collect { |p| p.bind(self) } + end + def ==(other) self.class == other.class and relation == other.relation and predicate == other.predicate end - - def selects - (relation.selects + [predicate]).collect { |p| p.bind(self) } - end end end \ No newline at end of file From 6064001d642fdbd18cdfe2aafc1f17e8fb248bd1 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 14:43:27 -0700 Subject: [PATCH 0172/1492] additional test coverage for some random complex case --- lib/arel/primitives/attribute.rb | 23 ++++++++++------- lib/arel/relations/compound.rb | 4 +++ lib/arel/relations/recursion.rb | 10 ++++++++ lib/arel/relations/relation.rb | 2 +- .../integration/joins/with_adjacency_spec.rb | 25 +++++++++++++++++++ spec/arel/unit/primitives/expression_spec.rb | 1 + 6 files changed, 55 insertions(+), 10 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 9d5b98474f36f..9fb47d56cfdbd 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -37,16 +37,9 @@ def ==(other) ancestor == other.ancestor end - module Origin - def original_relation - relation.relation_for(self) - end - - def original_attribute - original_relation[self] - end + def original_relation + relation.relation_for(self) end - include Origin module Transformations def self.included(klass) @@ -76,6 +69,18 @@ def match?(other) !(history & other.history).empty? end + def descends_from?(other) + history.include?(other) + end + + def root? + relation.root? + end + + def root + @root ||= history.detect(&:root?) + end + def /(other) if other then (history & other.history).size.to_f / Set.new(history + other.history).size else 0 diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 1459c163cfa86..6f230c3f5778b 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -11,6 +11,10 @@ def attributes @attributes ||= relation.attributes.collect { |a| a.bind(self) } end + def selects + @selects ||= relation.selects.collect { |s| s.bind(self) } + end + # XXX def relation_for(attribute) join? && relation.relation_for(attribute) || self[attribute] && self diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index fa4d9969c9ce4..ea8109d87d2a5 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -9,9 +9,19 @@ def table_sql(formatter = Sql::TableReference.new(self)) formatter.table self end + def root? + true + end + def relation_for(attribute) self[attribute] && self end end end + + class Relation + def root? + false + end + end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 884b743f20e7f..25dc75e8eae1b 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -138,7 +138,7 @@ def find_attribute_matching_name(name) # TESTME - added original_attribute because of AR def find_attribute_matching_attribute(attribute) attributes.select { |a| a.match?(attribute) }.max do |a1, a2| - (attribute / a1.original_attribute) <=> (attribute / a2.original_attribute) + (attribute / a1.root) <=> (attribute / a2.root) end end end diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 74d461319c3ea..56ead0993ab25 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -96,6 +96,31 @@ module Arel relation[@relation1[:id]].ancestor.should == @relation1[:id] relation[@relation2[:id]].ancestor.should == @relation2[:id] end + + describe 'when the left relation is compound' do + it '' do + relation = @relation1 \ + .select(@predicate) \ + .select(@predicate) \ + .join(@relation2) \ + .on(@predicate) + relation[@relation1[:id]].should be_descends_from(@relation1[:id]) + relation[@relation1[:id]].should_not be_descends_from(@relation2[:id]) + end + end + + describe 'when the right relation is compound' do + it '' do + relation = @relation1 \ + .join( \ + @relation2 \ + .select(@predicate) \ + .select(@predicate) \ + .select(@predicate)) \ + .on(@predicate) + relation[@relation2[:id]].should be_descends_from(@relation2[:id]) + end + end end end end diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index 8a990231f6131..ace439b952f7e 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -14,6 +14,7 @@ module Arel describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do + pending derived_relation = @relation.select(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end From 131b106dc0c6b001a78f6f6656c52c49831b9c9d Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 14:47:34 -0700 Subject: [PATCH 0173/1492] better messaging --- spec/arel/integration/joins/with_adjacency_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 56ead0993ab25..e75ae3766e54f 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -98,7 +98,7 @@ module Arel end describe 'when the left relation is compound' do - it '' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do relation = @relation1 \ .select(@predicate) \ .select(@predicate) \ @@ -110,7 +110,7 @@ module Arel end describe 'when the right relation is compound' do - it '' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do relation = @relation1 \ .join( \ @relation2 \ From c96155c4fdd9a15eeca6e59ca3f35197d2ad3541 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 15:08:50 -0700 Subject: [PATCH 0174/1492] custom matcher --- .../integration/joins/with_adjacency_spec.rb | 40 +++++++++---------- spec/matchers/be_like.rb | 10 ++--- spec/matchers/hash_the_same_as.rb | 10 ++--- spec/spec_helper.rb | 2 +- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index e75ae3766e54f..4ffdf1f64f8b9 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -92,33 +92,33 @@ module Arel describe '[]' do describe 'when given an attribute belonging to both sub-relations' do it 'disambiguates the relation that serves as the ancestor to the attribute' do - relation = @relation1.join(@relation2).on(@predicate) - relation[@relation1[:id]].ancestor.should == @relation1[:id] - relation[@relation2[:id]].ancestor.should == @relation2[:id] + @relation1 \ + .join(@relation2) \ + .on(@predicate) \ + .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end - describe 'when the left relation is compound' do + describe 'when the left relation is extremely compound' do it 'disambiguates the relation that serves as the ancestor to the attribute' do - relation = @relation1 \ - .select(@predicate) \ - .select(@predicate) \ - .join(@relation2) \ - .on(@predicate) - relation[@relation1[:id]].should be_descends_from(@relation1[:id]) - relation[@relation1[:id]].should_not be_descends_from(@relation2[:id]) + @relation1 \ + .select(@predicate) \ + .select(@predicate) \ + .join(@relation2) \ + .on(@predicate) \ + .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end end - describe 'when the right relation is compound' do + describe 'when the right relation is extremely compound' do it 'disambiguates the relation that serves as the ancestor to the attribute' do - relation = @relation1 \ - .join( \ - @relation2 \ - .select(@predicate) \ - .select(@predicate) \ - .select(@predicate)) \ - .on(@predicate) - relation[@relation2[:id]].should be_descends_from(@relation2[:id]) + @relation1 \ + .join( \ + @relation2 \ + .select(@predicate) \ + .select(@predicate) \ + .select(@predicate)) \ + .on(@predicate) \ + .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end end end diff --git a/spec/matchers/be_like.rb b/spec/matchers/be_like.rb index cea3f3027b9f6..c1b1ffc3fd3fd 100644 --- a/spec/matchers/be_like.rb +++ b/spec/matchers/be_like.rb @@ -4,17 +4,17 @@ def initialize(expected) @expected = expected end - def matches?(target) - @target = target - @expected.gsub(/\s+/, ' ').strip == @target.gsub(/\s+/, ' ').strip + def matches?(actual) + @actual = actual + @expected.gsub(/\s+/, ' ').strip == @actual.gsub(/\s+/, ' ').strip end def failure_message - "expected #{@target} to be like #{@expected}" + "expected #{@actual} to be like #{@expected}" end def negative_failure_message - "expected #{@target} to be unlike #{@expected}" + "expected #{@actual} to be unlike #{@expected}" end end diff --git a/spec/matchers/hash_the_same_as.rb b/spec/matchers/hash_the_same_as.rb index 86e98f31a3dbb..c1903b62b4ba1 100644 --- a/spec/matchers/hash_the_same_as.rb +++ b/spec/matchers/hash_the_same_as.rb @@ -4,19 +4,19 @@ def initialize(expected) @expected = expected end - def matches?(target) - @target = target + def matches?(actual) + @actual = actual hash = {} hash[@expected] = :some_arbitrary_value - hash[@target] == :some_arbitrary_value + hash[@actual] == :some_arbitrary_value end def failure_message - "expected #{@target} to hash the same as #{@expected}; they must be `eql?` and have the same `#hash` value" + "expected #{@actual} to hash the same as #{@expected}; they must be `eql?` and have the same `#hash` value" end def negative_failure_message - "expected #{@target} to hash differently than #{@expected}; they must not be `eql?` or have a differing `#hash` values" + "expected #{@actual} to hash differently than #{@expected}; they must not be `eql?` or have a differing `#hash` values" end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index bc117ec47dbf7..eb87e2448cf76 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,7 +12,7 @@ end Spec::Runner.configure do |config| - config.include(BeLikeMatcher, HashTheSameAsMatcher) + config.include(BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher) config.mock_with :rr config.before do Arel::Table.engine = Arel::Engine.new(Fake::Engine.new) From b06d351b701906efab737894be674c66561ec524 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 17:10:35 -0700 Subject: [PATCH 0175/1492] this is as close as it's been --- lib/arel/primitives/attribute.rb | 6 ++++ lib/arel/relations/relation.rb | 3 +- .../integration/joins/with_adjacency_spec.rb | 7 +++++ spec/matchers/disambiguate_attributes.rb | 28 +++++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 spec/matchers/disambiguate_attributes.rb diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 9fb47d56cfdbd..1de2bf7cb0d21 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -39,6 +39,11 @@ def ==(other) def original_relation relation.relation_for(self) + # root.relation + end + + def original_attribute + original_relation[self] end module Transformations @@ -85,6 +90,7 @@ def /(other) if other then (history & other.history).size.to_f / Set.new(history + other.history).size else 0 end + # 1 / (history.index(other) || -1) end end include Congruence diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 25dc75e8eae1b..490f545637d00 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -135,10 +135,9 @@ def find_attribute_matching_name(name) attributes.detect { |a| a.named?(name) } end - # TESTME - added original_attribute because of AR def find_attribute_matching_attribute(attribute) attributes.select { |a| a.match?(attribute) }.max do |a1, a2| - (attribute / a1.root) <=> (attribute / a2.root) + (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) end end end diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 4ffdf1f64f8b9..ab63fecb4625d 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -107,6 +107,13 @@ module Arel .on(@predicate) \ .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end + + it '' do + r0 = @relation1.select(@predicate) + r1 = r0.alias + r = r0.join(r1).on(@predicate) + r.should disambiguate_attributes(r0[:id], r1[:id]) + end end describe 'when the right relation is extremely compound' do diff --git a/spec/matchers/disambiguate_attributes.rb b/spec/matchers/disambiguate_attributes.rb new file mode 100644 index 0000000000000..bee7d22b0cc07 --- /dev/null +++ b/spec/matchers/disambiguate_attributes.rb @@ -0,0 +1,28 @@ +module DisambiguateAttributesMatcher + class DisambiguateAttributes + def initialize(attributes) + @attributes = attributes + end + + def matches?(actual) + @actual = actual + attribute1, attribute2 = @attributes + @actual[attribute1].descends_from?(attribute1) && + !@actual[attribute1].descends_from?(attribute2) && + @actual[attribute2].descends_from?(attribute2) + end + + def failure_message + "" + # "expected #{@actual} to disambiguate its attributes" + end + + def negative_failure_message + "expected #{@actual} to not disambiguate its attributes" + end + end + + def disambiguate_attributes(*attributes) + DisambiguateAttributes.new(attributes) + end +end \ No newline at end of file From 732b222126bd6b37925a4fcdcda832de65858122 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Fri, 16 May 2008 17:38:15 -0700 Subject: [PATCH 0176/1492] fixed string escaping issue --- lib/arel/extensions/object.rb | 2 +- lib/arel/relations/join.rb | 2 +- lib/arel/relations/relation.rb | 4 ++-- .../integration/joins/with_compounds_spec.rb | 24 +++++++++++++++---- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index 69ec6a5dce001..0382ca802710a 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -3,7 +3,7 @@ def bind(relation) Arel::Value.new(self, relation) end - def to_sql(formatter = nil) + def to_sql(formatter) formatter.scalar self end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 2dd3555bac8f1..8e29f0492b25f 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -25,7 +25,7 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) join_sql, relation2.externalize.table_sql(formatter), ("ON" unless predicates.blank?), - (predicates + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql }.join(' AND ') + (predicates + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') ].compact.join(" ") [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 490f545637d00..920bcd2d8df5a 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -9,8 +9,8 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), - ("WHERE #{selects.collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), - ("ORDER BY #{orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), + ("WHERE #{selects .collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), + ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 49f013219034d..62d226acf2f1e 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -8,9 +8,25 @@ module Arel @predicate = @relation1[:id].eq(@relation2[:user_id]) end - describe 'when a compound contains a join' do - describe '#to_sql' do - describe 'when the compound is a select' do + describe '#to_sql' do + describe 'when the join contains a select' do + describe 'and the select is given a string' do + it 'does not escape the string' do + @relation1 \ + .join(@relation2.select("asdf")) \ + .on(@predicate) \ + .to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` AND asdf + ") + end + end + end + + describe 'when a compound contains a join' do + describe 'and the compound is a select' do it 'manufactures sql disambiguating the tables' do @relation1 \ .select(@relation1[:id].eq(1)) \ @@ -28,7 +44,7 @@ module Arel end end - describe 'when the compound is a group' do + describe 'and the compound is a group' do it 'manufactures sql disambiguating the tables' do @relation1 \ .join(@relation2) \ From 3f55d33e530da1b5c454e0cfe920462d497649c8 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 17 May 2008 11:59:03 -0700 Subject: [PATCH 0177/1492] simplificatin of attribute division --- lib/arel/primitives/attribute.rb | 18 +++--------------- lib/arel/relations/join.rb | 1 - lib/arel/relations/recursion.rb | 10 ---------- .../joins/with_aggregations_spec.rb | 4 ++++ spec/arel/unit/primitives/attribute_spec.rb | 9 +-------- 5 files changed, 8 insertions(+), 34 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 1de2bf7cb0d21..bb951638e431c 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -38,12 +38,11 @@ def ==(other) end def original_relation - relation.relation_for(self) - # root.relation + @original_relation ||= relation.relation_for(self) end def original_attribute - original_relation[self] + @original_attribute ||= original_relation[self] end module Transformations @@ -78,19 +77,8 @@ def descends_from?(other) history.include?(other) end - def root? - relation.root? - end - - def root - @root ||= history.detect(&:root?) - end - def /(other) - if other then (history & other.history).size.to_f / Set.new(history + other.history).size - else 0 - end - # 1 / (history.index(other) || -1) + other ? (history & other.history).size : 0 end end include Congruence diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 8e29f0492b25f..88d5f45b67e39 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -39,7 +39,6 @@ def selects relation1.externalize.selects end - # XXX def relation_for(attribute) [ relation1.externalize.relation_for(attribute), diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index ea8109d87d2a5..fa4d9969c9ce4 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -9,19 +9,9 @@ def table_sql(formatter = Sql::TableReference.new(self)) formatter.table self end - def root? - true - end - def relation_for(attribute) self[attribute] && self end end end - - class Relation - def root? - false - end - end end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index e6af920d32dd1..b9cb4acc314a3 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -16,6 +16,10 @@ module Arel end describe '#attributes' do + it '' do + @relation1.join(@aggregation).on(@predicate)[@relation2[:user_id]].should_not be_nil + end + it 'it transforms aggregate expressions into attributes' do join_with_aggregation = Join.new("INNER JOIN", @relation1, @aggregation, @predicate) join_with_aggregation.attributes.should == diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index 7e0155f84d93b..34665b5adf5eb 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -62,20 +62,13 @@ module Arel @doubly_aliased_relation = @aliased_relation.alias end - describe 'when dividing two identical attributes' do - it "returns 1.0" do - (@relation[:id] / @relation[:id]).should == 1.0 - (@aliased_relation[:id] / @aliased_relation[:id]).should == 1.0 - end - end - describe 'when dividing two unrelated attributes' do it "returns 0.0" do (@relation[:id] / @relation[:name]).should == 0.0 end end - describe 'when dividing two similar attributes' do + describe 'when dividing two matching attributes' do it 'returns a the highest score for the most similar attributes' do (@aliased_relation[:id] / @relation[:id]) \ .should == (@aliased_relation[:id] / @relation[:id]) From 2e252c4cc8003489185658db1b76bee69be4a010 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 17 May 2008 14:43:27 -0700 Subject: [PATCH 0178/1492] slight performance improvement --- lib/arel/extensions/class.rb | 6 ++- lib/arel/primitives/attribute.rb | 8 +++- lib/arel/relations/compound.rb | 7 +--- lib/arel/relations/order.rb | 8 ++-- lib/arel/relations/selection.rb | 2 +- lib/arel/sessions/session.rb | 5 +-- lib/arel/sql/christener.rb | 5 +-- .../integration/joins/with_adjacency_spec.rb | 37 +++++++++++++------ spec/matchers/be_like.rb | 4 +- 9 files changed, 49 insertions(+), 33 deletions(-) diff --git a/lib/arel/extensions/class.rb b/lib/arel/extensions/class.rb index fed2ef79c7054..48d07a45f9547 100644 --- a/lib/arel/extensions/class.rb +++ b/lib/arel/extensions/class.rb @@ -1,9 +1,11 @@ class Class - def hash_on(delegatee) + def hash_on(*delegatees) define_method :eql? do |other| self == other end - delegate :hash, :to => delegatee + define_method :hash do + @hash ||= delegatees.map(&:hash).sum + end end end \ No newline at end of file diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index bb951638e431c..f3291b18da55f 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -46,8 +46,14 @@ def original_attribute end module Transformations + delegate :size, :to => :history + def self.included(klass) - klass.hash_on :name + klass.send :alias_method, :eql?, :== + end + + def hash + @hash ||= history.size + name.hash + relation.hash end def as(aliaz = nil) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 6f230c3f5778b..55b2bc80c7300 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -10,12 +10,7 @@ class Compound < Relation def attributes @attributes ||= relation.attributes.collect { |a| a.bind(self) } end - - def selects - @selects ||= relation.selects.collect { |s| s.bind(self) } - end - - # XXX + def relation_for(attribute) join? && relation.relation_for(attribute) || self[attribute] && self end diff --git a/lib/arel/relations/order.rb b/lib/arel/relations/order.rb index 662d3740df02f..2d721277226ed 100644 --- a/lib/arel/relations/order.rb +++ b/lib/arel/relations/order.rb @@ -6,14 +6,14 @@ def initialize(relation, *orderings) @relation, @orderings = relation, orderings.collect { |o| o.bind(relation) } end + def orders + orderings + relation.orders + end + def ==(other) self.class == other.class and relation == other.relation and orderings == other.orderings end - - def orders - orderings + relation.orders - end end end \ No newline at end of file diff --git a/lib/arel/relations/selection.rb b/lib/arel/relations/selection.rb index a37f51c9ecd61..c50db1c88a5ec 100644 --- a/lib/arel/relations/selection.rb +++ b/lib/arel/relations/selection.rb @@ -9,7 +9,7 @@ def initialize(relation, *predicates) end def selects - (relation.selects + [predicate]).collect { |p| p.bind(self) } + @selects ||= (relation.selects + [predicate]).collect { |p| p.bind(self) } end def ==(other) diff --git a/lib/arel/sessions/session.rb b/lib/arel/sessions/session.rb index 9c61d0cba1928..8b72fd1fe69d6 100644 --- a/lib/arel/sessions/session.rb +++ b/lib/arel/sessions/session.rb @@ -29,10 +29,9 @@ def create(insert) end def read(select) - @read ||= Hash.new do |hash, select| + (@read ||= Hash.new do |hash, select| hash[select] = select.call(select.engine.connection) - end - @read[select] + end)[select] end def update(update) diff --git a/lib/arel/sql/christener.rb b/lib/arel/sql/christener.rb index d0dbf47eaf52c..5883a75f41346 100644 --- a/lib/arel/sql/christener.rb +++ b/lib/arel/sql/christener.rb @@ -3,11 +3,10 @@ module Sql class Christener def name_for(relation) @used_names ||= Hash.new(0) - @relation_names ||= Hash.new do |hash, relation| + (@relation_names ||= Hash.new do |hash, relation| @used_names[name = relation.name] += 1 hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') - end - @relation_names[relation.table] + end)[relation.table] end end end diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index ab63fecb4625d..79f6f6d425b5b 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -8,9 +8,9 @@ module Arel @predicate = @relation1[:id].eq(@relation2[:id]) end - describe 'when joining a relation to itself' do + describe 'when joining a relation to xitself' do describe '#to_sql' do - it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do + xit 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do @relation1.join(@relation2).on(@predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` @@ -20,7 +20,7 @@ module Arel end describe 'when joining with a selection on the same relation' do - it 'manufactures sql aliasing the tables properly' do + xit 'manufactures sql aliasing the tables properly' do @relation1 \ .join(@relation2.select(@relation2[:id].eq(1))) \ .on(@predicate) \ @@ -33,7 +33,7 @@ module Arel end describe 'when the selection occurs before the alias' do - it 'manufactures sql aliasing the predicates properly' do + xit 'manufactures sql aliasing the predicates properly' do relation2 = @relation1.select(@relation1[:id].eq(1)).alias @relation1 \ .join(relation2) \ @@ -45,16 +45,31 @@ module Arel ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 ") end + + it 'investigation' do + relation2 = @relation1.select(@relation1[:id].eq(1)).alias + a = relation2.selects.first.operand1 + + join = @relation1 \ + .join(relation2) \ + .on(relation2[:id].eq(@relation1[:id])) \ + + a = a.bind(join) + a.history # join, select, relation1 + relation2[:id].history # alias, select, relation + + p a.history[1].eql?(relation2[:id].history[1]) + end end end - describe 'when joining the relation to itself multiple times' do + describe 'when joining the relation to xitself multiple times' do before do @relation3 = @relation1.alias end describe 'when joining left-associatively' do - it 'manufactures sql aliasing the tables properly' do + xit 'manufactures sql aliasing the tables properly' do @relation1 \ .join(@relation2 \ .join(@relation3) \ @@ -72,7 +87,7 @@ module Arel end describe 'when joining right-associatively' do - it 'manufactures sql aliasing the tables properly' do + xit 'manufactures sql aliasing the tables properly' do @relation1 \ .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ @@ -91,7 +106,7 @@ module Arel describe '[]' do describe 'when given an attribute belonging to both sub-relations' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do + xit 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ .join(@relation2) \ .on(@predicate) \ @@ -99,7 +114,7 @@ module Arel end describe 'when the left relation is extremely compound' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do + xit 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ .select(@predicate) \ .select(@predicate) \ @@ -108,7 +123,7 @@ module Arel .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end - it '' do + xit '' do r0 = @relation1.select(@predicate) r1 = r0.alias r = r0.join(r1).on(@predicate) @@ -117,7 +132,7 @@ module Arel end describe 'when the right relation is extremely compound' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do + xit 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ .join( \ @relation2 \ diff --git a/spec/matchers/be_like.rb b/spec/matchers/be_like.rb index c1b1ffc3fd3fd..4ff5bc532fcfd 100644 --- a/spec/matchers/be_like.rb +++ b/spec/matchers/be_like.rb @@ -10,11 +10,11 @@ def matches?(actual) end def failure_message - "expected #{@actual} to be like #{@expected}" + "expected\n#{@actual}\nto be like\n#{@expected}" end def negative_failure_message - "expected #{@actual} to be unlike #{@expected}" + "expected\n#{@actual}\nto be unlike\n#{@expected}" end end From 2c5566dbdc239f4fc56dc19ca6e343e091e4d022 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 17 May 2008 14:44:02 -0700 Subject: [PATCH 0179/1492] cleanup --- .../integration/joins/with_adjacency_spec.rb | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 79f6f6d425b5b..ab63fecb4625d 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -8,9 +8,9 @@ module Arel @predicate = @relation1[:id].eq(@relation2[:id]) end - describe 'when joining a relation to xitself' do + describe 'when joining a relation to itself' do describe '#to_sql' do - xit 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do + it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do @relation1.join(@relation2).on(@predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` @@ -20,7 +20,7 @@ module Arel end describe 'when joining with a selection on the same relation' do - xit 'manufactures sql aliasing the tables properly' do + it 'manufactures sql aliasing the tables properly' do @relation1 \ .join(@relation2.select(@relation2[:id].eq(1))) \ .on(@predicate) \ @@ -33,7 +33,7 @@ module Arel end describe 'when the selection occurs before the alias' do - xit 'manufactures sql aliasing the predicates properly' do + it 'manufactures sql aliasing the predicates properly' do relation2 = @relation1.select(@relation1[:id].eq(1)).alias @relation1 \ .join(relation2) \ @@ -45,31 +45,16 @@ module Arel ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 ") end - - it 'investigation' do - relation2 = @relation1.select(@relation1[:id].eq(1)).alias - a = relation2.selects.first.operand1 - - join = @relation1 \ - .join(relation2) \ - .on(relation2[:id].eq(@relation1[:id])) \ - - a = a.bind(join) - a.history # join, select, relation1 - relation2[:id].history # alias, select, relation - - p a.history[1].eql?(relation2[:id].history[1]) - end end end - describe 'when joining the relation to xitself multiple times' do + describe 'when joining the relation to itself multiple times' do before do @relation3 = @relation1.alias end describe 'when joining left-associatively' do - xit 'manufactures sql aliasing the tables properly' do + it 'manufactures sql aliasing the tables properly' do @relation1 \ .join(@relation2 \ .join(@relation3) \ @@ -87,7 +72,7 @@ module Arel end describe 'when joining right-associatively' do - xit 'manufactures sql aliasing the tables properly' do + it 'manufactures sql aliasing the tables properly' do @relation1 \ .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ @@ -106,7 +91,7 @@ module Arel describe '[]' do describe 'when given an attribute belonging to both sub-relations' do - xit 'disambiguates the relation that serves as the ancestor to the attribute' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ .join(@relation2) \ .on(@predicate) \ @@ -114,7 +99,7 @@ module Arel end describe 'when the left relation is extremely compound' do - xit 'disambiguates the relation that serves as the ancestor to the attribute' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ .select(@predicate) \ .select(@predicate) \ @@ -123,7 +108,7 @@ module Arel .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end - xit '' do + it '' do r0 = @relation1.select(@predicate) r1 = r0.alias r = r0.join(r1).on(@predicate) @@ -132,7 +117,7 @@ module Arel end describe 'when the right relation is extremely compound' do - xit 'disambiguates the relation that serves as the ancestor to the attribute' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ .join( \ @relation2 \ From 724a2684139342eb4613f78bfae723ef00911ff7 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 17 May 2008 20:24:22 -0700 Subject: [PATCH 0180/1492] performance enhancing drugs --- doc/TODO | 4 ++-- lib/arel/extensions/class.rb | 4 ++-- lib/arel/predicates.rb | 2 +- lib/arel/primitives/attribute.rb | 12 ++++++++---- lib/arel/primitives/expression.rb | 3 ++- lib/arel/primitives/value.rb | 4 ++-- lib/arel/relations/aggregation.rb | 2 +- lib/arel/relations/compound.rb | 2 +- lib/arel/relations/deletion.rb | 2 +- lib/arel/relations/grouping.rb | 2 +- lib/arel/relations/insertion.rb | 2 +- lib/arel/relations/join.rb | 2 +- lib/arel/relations/nil.rb | 2 +- lib/arel/relations/order.rb | 2 +- lib/arel/relations/projection.rb | 2 +- lib/arel/relations/recursion.rb | 4 ++-- lib/arel/relations/relation.rb | 14 +++++++++++++- lib/arel/relations/selection.rb | 2 +- lib/arel/relations/skip.rb | 2 +- lib/arel/relations/table.rb | 4 ++-- lib/arel/relations/take.rb | 2 +- lib/arel/relations/update.rb | 2 +- 22 files changed, 47 insertions(+), 30 deletions(-) diff --git a/doc/TODO b/doc/TODO index 00a8ce4e4d9c1..95e05ece49b8f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,6 +1,4 @@ todo: -- instance methodify externalize -- test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. - rename select to where - and/or w/ predicates - blocks for joins @@ -66,6 +64,8 @@ done: - Explicitly model recursive structural decomposition / polymorphism - Explicitly model the namer/externalizer using interpreter jargon - All Sql Strategies should be accumulations with the top-level relation? +- instance methodify externalize +- test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/extensions/class.rb b/lib/arel/extensions/class.rb index 48d07a45f9547..09e6d86ed4be4 100644 --- a/lib/arel/extensions/class.rb +++ b/lib/arel/extensions/class.rb @@ -1,11 +1,11 @@ class Class - def hash_on(*delegatees) + def hash_on(delegatee) define_method :eql? do |other| self == other end define_method :hash do - @hash ||= delegatees.map(&:hash).sum + @hash ||= delegatee.hash end end end \ No newline at end of file diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index cad4969952582..93c7ed0099d7d 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -28,7 +28,7 @@ def to_sql(formatter = nil) class Equality < Binary def ==(other) - self.class == other.class and + Equality == other.class and ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index f3291b18da55f..5e769ac0eb47d 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -30,11 +30,11 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) end def ==(other) - self.class == other.class and + Attribute == other.class and name == other.name and @alias == other.alias and - relation == other.relation and - ancestor == other.ancestor + ancestor == other.ancestor and + relation == other.relation end def original_relation @@ -76,7 +76,11 @@ def history end def match?(other) - !(history & other.history).empty? + history.last == other.history.last + end + + def root + history.last end def descends_from?(other) diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 3cde9d87249be..76b76538c9ca3 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -17,7 +17,7 @@ def aggregation? end def ==(other) - self.class == other.class and + Expression == other.class and attribute == other.attribute and function_sql == other.function_sql and ancestor == other.ancestor and @@ -29,6 +29,7 @@ def as(aliaz) Expression.new(attribute, function_sql, aliaz, self) end + # FIXME def bind(new_relation) # new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) self diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 8ed3c4ce30af9..b4bddd0b0c8ec 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -17,8 +17,8 @@ def format(object) end def ==(other) - self.class == other.class and - value == other.value + Value == other.class and + value == other.value end def bind(relation) diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index d18ef014fa205..d409c34284525 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -19,7 +19,7 @@ def attributes end def ==(other) - self.class == other.class and + Aggregation == other.class and self.relation == other.relation end end diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 55b2bc80c7300..abc583880544d 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -12,7 +12,7 @@ def attributes end def relation_for(attribute) - join? && relation.relation_for(attribute) || self[attribute] && self + join? && relation.relation_for(attribute) || has_attribute?(attribute) && self end end end \ No newline at end of file diff --git a/lib/arel/relations/deletion.rb b/lib/arel/relations/deletion.rb index 6c802ba905403..8c9d873a02025 100644 --- a/lib/arel/relations/deletion.rb +++ b/lib/arel/relations/deletion.rb @@ -18,7 +18,7 @@ def call(connection = engine.connection) end def ==(other) - self.class == other.class and + Deletion == other.class and relation == other.relation end end diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index 2c39d23b2daa0..39b5942bcce3e 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -7,7 +7,7 @@ def initialize(relation, *groupings) end def ==(other) - self.class == other.class and + Grouping == other.class and relation == other.relation and groupings == other.groupings end diff --git a/lib/arel/relations/insertion.rb b/lib/arel/relations/insertion.rb index 37e7be87571fb..cc7fcb4fb0c7a 100644 --- a/lib/arel/relations/insertion.rb +++ b/lib/arel/relations/insertion.rb @@ -20,7 +20,7 @@ def call(connection = engine.connection) end def ==(other) - self.class == other.class and + Insertion == other.class and relation == other.relation and record == other.record end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 88d5f45b67e39..abd4eae4f63cf 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -9,7 +9,7 @@ def initialize(join_sql, relation1, relation2 = Nil.new, *predicates) end def ==(other) - self.class == other.class and + Join == other.class and predicates == other.predicates and ( (relation1 == other.relation1 and relation2 == other.relation2) or (relation2 == other.relation1 and relation1 == other.relation2) diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index 714b11cc2af61..e8d4cbc481515 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -5,7 +5,7 @@ def relation_for(attribute); nil end def name; '' end def ==(other) - self.class == other.class + Nil == other.class end end end \ No newline at end of file diff --git a/lib/arel/relations/order.rb b/lib/arel/relations/order.rb index 2d721277226ed..31032e871c103 100644 --- a/lib/arel/relations/order.rb +++ b/lib/arel/relations/order.rb @@ -11,7 +11,7 @@ def orders end def ==(other) - self.class == other.class and + Order == other.class and relation == other.relation and orderings == other.orderings end diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/projection.rb index 7c64726852e6a..7eea63d808b84 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -15,7 +15,7 @@ def aggregation? end def ==(other) - self.class == other.class and + Projection == other.class and relation == other.relation and projections == other.projections end diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index fa4d9969c9ce4..c2fcf1bd211c1 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -10,8 +10,8 @@ def table_sql(formatter = Sql::TableReference.new(self)) end def relation_for(attribute) - self[attribute] && self - end + has_attribute?(attribute) && self + end end end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 920bcd2d8df5a..3704eb9318e08 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -136,10 +136,22 @@ def find_attribute_matching_name(name) end def find_attribute_matching_attribute(attribute) - attributes.select { |a| a.match?(attribute) }.max do |a1, a2| + matching_attributes(attribute).max do |a1, a2| (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) end end + + private + def matching_attributes(attribute) + (@matching_attributes ||= attributes.inject({}) do |hash, a| + (hash[a.root] ||= []) << a + hash + end)[attribute.root] || [] + end + + def has_attribute?(attribute) + !matching_attributes(attribute).empty? + end end include AttributeAccessable diff --git a/lib/arel/relations/selection.rb b/lib/arel/relations/selection.rb index c50db1c88a5ec..0c5956d2fc2d6 100644 --- a/lib/arel/relations/selection.rb +++ b/lib/arel/relations/selection.rb @@ -13,7 +13,7 @@ def selects end def ==(other) - self.class == other.class and + Selection == other.class and relation == other.relation and predicate == other.predicate end diff --git a/lib/arel/relations/skip.rb b/lib/arel/relations/skip.rb index f17e439ebf8cf..4686e03177e55 100644 --- a/lib/arel/relations/skip.rb +++ b/lib/arel/relations/skip.rb @@ -7,7 +7,7 @@ def initialize(relation, skipped) end def ==(other) - self.class == other.class and + Skip == other.class and relation == other.relation and skipped == other.skipped end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index b95e51a3070f4..06625dd52a154 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -17,7 +17,7 @@ def attributes end def column_for(attribute) - self[attribute] and columns.detect { |c| c.name == attribute.name.to_s } + has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end def columns @@ -29,7 +29,7 @@ def reset end def ==(other) - self.class == other.class and + Table == other.class and name == other.name end end diff --git a/lib/arel/relations/take.rb b/lib/arel/relations/take.rb index d2743d7a6e380..80aa62a878bde 100644 --- a/lib/arel/relations/take.rb +++ b/lib/arel/relations/take.rb @@ -7,7 +7,7 @@ def initialize(relation, taken) end def ==(other) - self.class == other.class and + Take == other.class and relation == other.relation and taken == other.taken end diff --git a/lib/arel/relations/update.rb b/lib/arel/relations/update.rb index f1f6776f15dcc..486ad2ab1212e 100644 --- a/lib/arel/relations/update.rb +++ b/lib/arel/relations/update.rb @@ -22,7 +22,7 @@ def call(connection = engine.connection) end def ==(other) - self.class == other.class and + Update == other.class and relation == other.relation and assignments == other.assignments end From 6e1450a2a646e416aaea003eff19b7703c563bed Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 17 May 2008 23:03:56 -0700 Subject: [PATCH 0181/1492] performance enhancements --- lib/arel/predicates.rb | 2 +- lib/arel/primitives/attribute.rb | 12 ++++---- lib/arel/relations/aggregation.rb | 2 +- lib/arel/relations/compound.rb | 6 ++-- lib/arel/relations/join.rb | 28 ++++++++----------- lib/arel/relations/nil.rb | 1 - lib/arel/relations/recursion.rb | 4 --- .../joins/with_aggregations_spec.rb | 6 ---- spec/arel/unit/predicates/binary_spec.rb | 17 ++++++++--- spec/arel/unit/primitives/attribute_spec.rb | 11 -------- spec/arel/unit/relations/join_spec.rb | 10 ------- 11 files changed, 34 insertions(+), 65 deletions(-) diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index 93c7ed0099d7d..3d01d5872fff5 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -17,7 +17,7 @@ def ==(other) end def bind(relation) - self.class.new(operand1.bind(relation), operand2.bind(relation)) + self.class.new(relation[operand1] || operand1, relation[operand2] || operand2) end def to_sql(formatter = nil) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 5e769ac0eb47d..cb564c158733f 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -38,16 +38,14 @@ def ==(other) end def original_relation - @original_relation ||= relation.relation_for(self) + original_attribute.relation end def original_attribute - @original_attribute ||= original_relation[self] + @original_attribute ||= history.detect { |a| !a.join? } end - module Transformations - delegate :size, :to => :history - + module Transformations def self.included(klass) klass.send :alias_method, :eql?, :== end @@ -75,8 +73,8 @@ def history @history ||= [self] + (ancestor ? ancestor.history : []) end - def match?(other) - history.last == other.history.last + def join? + relation.join? end def root diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index d409c34284525..a6f40be786c33 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -15,7 +15,7 @@ def table_sql(formatter = Sql::TableReference.new(relation)) end def attributes - @attributes ||= relation.attributes.collect(&:to_attribute) + @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } end def ==(other) diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index abc583880544d..9921568157231 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -10,9 +10,9 @@ class Compound < Relation def attributes @attributes ||= relation.attributes.collect { |a| a.bind(self) } end - - def relation_for(attribute) - join? && relation.relation_for(attribute) || has_attribute?(attribute) && self + + def selects + @selects || relation.selects.collect { |s| s.bind(self) } end end end \ No newline at end of file diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index abd4eae4f63cf..9cc9f95c81b37 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -7,14 +7,6 @@ class Join < Relation def initialize(join_sql, relation1, relation2 = Nil.new, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end - - def ==(other) - Join == other.class and - predicates == other.predicates and ( - (relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2) - ) - end def table_sql(formatter = Sql::TableReference.new(self)) relation1.externalize.table_sql(formatter) @@ -25,7 +17,7 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) join_sql, relation2.externalize.table_sql(formatter), ("ON" unless predicates.blank?), - (predicates + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + (ons + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') ].compact.join(" ") [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") end @@ -39,14 +31,8 @@ def selects relation1.externalize.selects end - def relation_for(attribute) - [ - relation1.externalize.relation_for(attribute), - relation2.externalize.relation_for(attribute) - ].max do |r1, r2| - a1, a2 = r1 && r1[attribute], r2 && r2[attribute] - attribute / a1 <=> attribute / a2 - end + def ons + @ons ||= @predicates.collect { |p| p.bind(self) } end # TESTME @@ -57,6 +43,14 @@ def aggregation? def join? true end + + def ==(other) + Join == other.class and + predicates == other.predicates and ( + (relation1 == other.relation1 and relation2 == other.relation2) or + (relation2 == other.relation1 and relation1 == other.relation2) + ) + end end class Relation diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index e8d4cbc481515..c34fe71473cf4 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -1,7 +1,6 @@ module Arel class Nil < Relation def table_sql(formatter = nil); '' end - def relation_for(attribute); nil end def name; '' end def ==(other) diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/recursion.rb index c2fcf1bd211c1..848b059507b01 100644 --- a/lib/arel/relations/recursion.rb +++ b/lib/arel/relations/recursion.rb @@ -8,10 +8,6 @@ def table def table_sql(formatter = Sql::TableReference.new(self)) formatter.table self end - - def relation_for(attribute) - has_attribute?(attribute) && self - end end end end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index b9cb4acc314a3..655250f4f965e 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -19,12 +19,6 @@ module Arel it '' do @relation1.join(@aggregation).on(@predicate)[@relation2[:user_id]].should_not be_nil end - - it 'it transforms aggregate expressions into attributes' do - join_with_aggregation = Join.new("INNER JOIN", @relation1, @aggregation, @predicate) - join_with_aggregation.attributes.should == - (@relation1.attributes + @aggregation.attributes).collect(&:to_attribute).collect { |a| a.bind(join_with_aggregation) } - end end describe '#to_sql' do diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index f39b37d9138e0..2d6ef5d7e336b 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -59,12 +59,21 @@ def predicate_sql describe '#bind' do before do - @another_relation = Table.new(:photos) + @another_relation = @relation.alias end - it "descends" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.bind(@another_relation), @attribute2.bind(@another_relation)) + describe 'when both operands are attributes' do + it "manufactures an expression with the attributes bound to the relation" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) + end + end + + describe 'when an operand is a value' do + it "manufactures an expression with unmodified values" do + ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ + should == ConcreteBinary.new(@another_relation[@attribute1], "asdf") + end end end end diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index 34665b5adf5eb..890ac0e8138d1 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -45,17 +45,6 @@ module Arel end describe Attribute::Congruence do - describe '#match?' do - it "obtains if the attributes are identical" do - @attribute.should be_match(@attribute) - end - - it "obtains if the attributes have an overlapping history" do - Attribute.new(@relation, :id, :ancestor => @attribute).should be_match(@attribute) - @attribute.should be_match(Attribute.new(@relation, :id, :ancestor => @attribute)) - end - end - describe '/' do before do @aliased_relation = @relation.alias diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 347566e6ea384..d128dd0560648 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -55,16 +55,6 @@ module Arel INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` ") end - - it 'manufactures sql joining the two tables, with selects from the right table in the ON clause' do - Join.new("INNER JOIN", @relation1.select(@relation1[:id].eq(1)), - @relation2.select(@relation2[:id].eq(2)), @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` AND `photos`.`id` = 2 - WHERE `users`.`id` = 1 - ") - end end describe 'when joining with a string' do From 7a068384b74813b3ea9a309d237c6ce8e8fde5d6 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sat, 17 May 2008 23:35:51 -0700 Subject: [PATCH 0182/1492] still faster --- lib/arel/extensions/object.rb | 4 ++++ lib/arel/predicates.rb | 2 +- lib/arel/primitives/attribute.rb | 6 +++++- lib/arel/primitives/value.rb | 4 ++++ spec/arel/unit/predicates/binary_spec.rb | 2 +- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index 0382ca802710a..9b66fcac4ecb5 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -3,6 +3,10 @@ def bind(relation) Arel::Value.new(self, relation) end + def circle(relation) + bind(relation) + end + def to_sql(formatter) formatter.scalar self end diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index 3d01d5872fff5..48283e5d0916f 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -17,7 +17,7 @@ def ==(other) end def bind(relation) - self.class.new(relation[operand1] || operand1, relation[operand2] || operand2) + self.class.new(operand1.circle(relation), operand2.circle(relation)) end def to_sql(formatter = nil) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index cb564c158733f..eeea495b096fd 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -38,12 +38,16 @@ def ==(other) end def original_relation - original_attribute.relation + @original_relation ||= original_attribute.relation end def original_attribute @original_attribute ||= history.detect { |a| !a.join? } end + + def circle(relation) + relation[self] + end module Transformations def self.included(klass) diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index b4bddd0b0c8ec..7751390be6b62 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -24,5 +24,9 @@ def ==(other) def bind(relation) Value.new(value, relation) end + + def circle(relation) + bind(relation) + end end end \ No newline at end of file diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index 2d6ef5d7e336b..e5b30b787de01 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -72,7 +72,7 @@ def predicate_sql describe 'when an operand is a value' do it "manufactures an expression with unmodified values" do ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@another_relation[@attribute1], "asdf") + should == ConcreteBinary.new(@attribute1.circle(@another_relation), "asdf".circle(@another_relation)) end end end From 32ad530b825f4cdac51e579306548ca695471039 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 18 May 2008 16:11:08 -0700 Subject: [PATCH 0183/1492] rename refactor of circle --- lib/arel/extensions/object.rb | 2 +- lib/arel/predicates.rb | 2 +- lib/arel/primitives/attribute.rb | 2 +- lib/arel/primitives/expression.rb | 4 +--- lib/arel/primitives/value.rb | 4 ---- lib/arel/sql/formatters.rb | 14 ++++++------- .../integration/joins/with_adjacency_spec.rb | 18 ++++++++++------- .../joins/with_aggregations_spec.rb | 20 +++++++++---------- spec/arel/unit/predicates/binary_spec.rb | 2 +- spec/arel/unit/primitives/expression_spec.rb | 1 - spec/arel/unit/relations/alias_spec.rb | 9 --------- spec/arel/unit/relations/selection_spec.rb | 9 +++------ 12 files changed, 36 insertions(+), 51 deletions(-) diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index 9b66fcac4ecb5..ea73c336dc31d 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -3,7 +3,7 @@ def bind(relation) Arel::Value.new(self, relation) end - def circle(relation) + def find_correlate_in(relation) bind(relation) end diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index 48283e5d0916f..b375f37ff4545 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -17,7 +17,7 @@ def ==(other) end def bind(relation) - self.class.new(operand1.circle(relation), operand2.circle(relation)) + self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end def to_sql(formatter = nil) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index eeea495b096fd..011b751a1dd16 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -45,7 +45,7 @@ def original_attribute @original_attribute ||= history.detect { |a| !a.join? } end - def circle(relation) + def find_correlate_in(relation) relation[self] end diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 76b76538c9ca3..696e3521be8cd 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -29,10 +29,8 @@ def as(aliaz) Expression.new(attribute, function_sql, aliaz, self) end - # FIXME def bind(new_relation) - # new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) - self + new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) end def to_attribute diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 7751390be6b62..b4bddd0b0c8ec 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -24,9 +24,5 @@ def ==(other) def bind(relation) Value.new(value, relation) end - - def circle(relation) - bind(relation) - end end end \ No newline at end of file diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index 5eab65726e788..cc7a1fa7d5ab5 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -20,8 +20,8 @@ def expression(expression) "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') end - def select(select_sql, name) - "(#{select_sql}) AS #{quote_table_name(name.to_s)}" + def select(select_sql, table) + "(#{select_sql}) AS #{quote_table_name(table)}" end def value(value) @@ -67,24 +67,24 @@ def scalar(value, column = nil) quote(value, column) end - def select(select_sql, name) + def select(select_sql, table) "(#{select_sql})" end end class SelectStatement < Formatter - def select(select_sql, name) + def select(select_sql, table) select_sql end end class TableReference < Formatter - def select(select_sql, name) - "(#{select_sql}) AS #{quote_table_name(name)}" + def select(select_sql, table) + "(#{select_sql}) AS #{quote_table_name(table)}" end def table(table) - quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + engine.quote_table_name(name_for(table)) : '') + quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') end end diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index ab63fecb4625d..222303977f073 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -97,6 +97,17 @@ module Arel .on(@predicate) \ .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end + + describe 'when both relations are compound and only one is an alias' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + compound1 = @relation1.select(@predicate) + compound2 = compound1.alias + compound1 \ + .join(compound2) \ + .on(@predicate) \ + .should disambiguate_attributes(compound1[:id], compound2[:id]) + end + end describe 'when the left relation is extremely compound' do it 'disambiguates the relation that serves as the ancestor to the attribute' do @@ -107,13 +118,6 @@ module Arel .on(@predicate) \ .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end - - it '' do - r0 = @relation1.select(@predicate) - r1 = r0.alias - r = r0.join(r1).on(@predicate) - r.should disambiguate_attributes(r0[:id], r1[:id]) - end end describe 'when the right relation is extremely compound' do diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 655250f4f965e..db34bb1b46e4e 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -15,16 +15,10 @@ module Arel .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ end - describe '#attributes' do - it '' do - @relation1.join(@aggregation).on(@predicate)[@relation2[:user_id]].should_not be_nil - end - end - describe '#to_sql' do describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do - Join.new("INNER JOIN", @relation1, @aggregation, @predicate).to_sql.should be_like(" + @relation1.join(@aggregation).on(@predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` @@ -35,7 +29,7 @@ module Arel describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do - Join.new("INNER JOIN", @aggregation, @relation1, @predicate).to_sql.should be_like(" + @aggregation.join(@relation1).on(@predicate).to_sql.should be_like(" SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` INNER JOIN `users` @@ -43,11 +37,17 @@ module Arel ") end end + + describe 'with the aggregation on both sides' do + it '' do + @aggregation.join(@aggregation.alias).on(@predicate).to_sql.should == '' + end + end describe 'when the aggration has a selection' do describe 'with the aggregation on the left' do it "manufactures sql keeping selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @relation1, @aggregation.select(@aggregation[:user_id].eq(1)), @predicate).to_sql.should be_like(" + @relation1.join(@aggregation.select(@aggregation[:user_id].eq(1))).on(@predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` @@ -58,7 +58,7 @@ module Arel describe 'with the aggregation on the right' do it "manufactures sql keeping selects on the aggregation within the derived table" do - Join.new("INNER JOIN", @aggregation.select(@aggregation[:user_id].eq(1)), @relation1, @predicate).to_sql.should be_like(" + @aggregation.select(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` INNER JOIN `users` diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index e5b30b787de01..57b1f3a53468c 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -72,7 +72,7 @@ def predicate_sql describe 'when an operand is a value' do it "manufactures an expression with unmodified values" do ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.circle(@another_relation), "asdf".circle(@another_relation)) + should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) end end end diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index ace439b952f7e..8a990231f6131 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -14,7 +14,6 @@ module Arel describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do - pending derived_relation = @relation.select(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 85850b5e1ae29..96e06f48bc57b 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -11,15 +11,6 @@ module Arel Alias.new(@relation).should_not == Alias.new(@relation) (aliaz = Alias.new(@relation)).should == aliaz end - - it '' do - @relation.select(@relation[:id].eq(1)).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE - `users`.`id` = 1 - ") - end end end end \ No newline at end of file diff --git a/spec/arel/unit/relations/selection_spec.rb b/spec/arel/unit/relations/selection_spec.rb index 61d9787df2088..20807f952f083 100644 --- a/spec/arel/unit/relations/selection_spec.rb +++ b/spec/arel/unit/relations/selection_spec.rb @@ -8,13 +8,10 @@ module Arel end describe '#initialize' do - before do - @another_predicate = @relation[:name].lt(2) - end - it "manufactures nested selection relations if multiple predicates are provided" do - Selection.new(@relation, @predicate, @another_predicate). \ - should == Selection.new(Selection.new(@relation, @another_predicate), @predicate) + another_predicate = @relation[:name].lt(2) + Selection.new(@relation, @predicate, another_predicate). \ + should == Selection.new(Selection.new(@relation, another_predicate), @predicate) end end From 7feff4e7b52fbef356426d22257af161704315ad Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 18 May 2008 16:47:55 -0700 Subject: [PATCH 0184/1492] performance enhancements --- lib/arel/predicates.rb | 9 ++++---- lib/arel/primitives/attribute.rb | 10 ++++----- lib/arel/primitives/expression.rb | 10 ++++----- lib/arel/primitives/value.rb | 4 ++-- lib/arel/relations/aggregation.rb | 4 ++-- lib/arel/relations/deletion.rb | 4 ++-- lib/arel/relations/grouping.rb | 6 ++--- lib/arel/relations/insertion.rb | 2 +- lib/arel/relations/join.rb | 25 +++++++++++---------- lib/arel/relations/nil.rb | 2 +- lib/arel/relations/order.rb | 6 ++--- lib/arel/relations/projection.rb | 6 ++--- lib/arel/relations/selection.rb | 6 ++--- lib/arel/relations/skip.rb | 6 ++--- lib/arel/relations/table.rb | 4 ++-- lib/arel/relations/take.rb | 6 ++--- lib/arel/relations/update.rb | 6 ++--- spec/arel/unit/predicates/binary_spec.rb | 12 ---------- spec/arel/unit/relations/join_spec.rb | 17 -------------- spec/arel/unit/relations/projection_spec.rb | 15 +------------ 20 files changed, 59 insertions(+), 101 deletions(-) diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index b375f37ff4545..f21376d4c93a1 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -1,8 +1,5 @@ module Arel class Predicate - def ==(other) - self.class == other.class - end end class Binary < Predicate @@ -13,7 +10,9 @@ def initialize(operand1, operand2) end def ==(other) - super and @operand1 == other.operand1 and @operand2 == other.operand2 + self.class === other and + @operand1 == other.operand1 and + @operand2 == other.operand2 end def bind(relation) @@ -28,7 +27,7 @@ def to_sql(formatter = nil) class Equality < Binary def ==(other) - Equality == other.class and + Equality === other and ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 011b751a1dd16..ca1d31ffcf05c 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -30,11 +30,11 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) end def ==(other) - Attribute == other.class and - name == other.name and - @alias == other.alias and - ancestor == other.ancestor and - relation == other.relation + Attribute === other and + name == other.name and + @alias == other.alias and + ancestor == other.ancestor and + relation == other.relation end def original_relation diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 696e3521be8cd..9afafcce2fa49 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -17,11 +17,11 @@ def aggregation? end def ==(other) - Expression == other.class and - attribute == other.attribute and - function_sql == other.function_sql and - ancestor == other.ancestor and - @alias == other.alias + Expression === other and + attribute == other.attribute and + function_sql == other.function_sql and + ancestor == other.ancestor and + @alias == other.alias end module Transformations diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index b4bddd0b0c8ec..4509f13d17321 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -17,8 +17,8 @@ def format(object) end def ==(other) - Value == other.class and - value == other.value + Value === other and + value == other.value end def bind(relation) diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index a6f40be786c33..9a34ea5d89ea4 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -19,8 +19,8 @@ def attributes end def ==(other) - Aggregation == other.class and - self.relation == other.relation + Aggregation === other and + self.relation == other.relation end end diff --git a/lib/arel/relations/deletion.rb b/lib/arel/relations/deletion.rb index 8c9d873a02025..cd58771846459 100644 --- a/lib/arel/relations/deletion.rb +++ b/lib/arel/relations/deletion.rb @@ -18,8 +18,8 @@ def call(connection = engine.connection) end def ==(other) - Deletion == other.class and - relation == other.relation + Deletion === other and + relation == other.relation end end end \ No newline at end of file diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index 39b5942bcce3e..6d112990510b8 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -7,9 +7,9 @@ def initialize(relation, *groupings) end def ==(other) - Grouping == other.class and - relation == other.relation and - groupings == other.groupings + Grouping === other and + relation == other.relation and + groupings == other.groupings end def aggregation? diff --git a/lib/arel/relations/insertion.rb b/lib/arel/relations/insertion.rb index cc7fcb4fb0c7a..16eb9b75557bd 100644 --- a/lib/arel/relations/insertion.rb +++ b/lib/arel/relations/insertion.rb @@ -20,7 +20,7 @@ def call(connection = engine.connection) end def ==(other) - Insertion == other.class and + Insertion === other and relation == other.relation and record == other.record end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 9cc9f95c81b37..81a157dc102f6 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -13,13 +13,15 @@ def table_sql(formatter = Sql::TableReference.new(self)) end def joins(environment, formatter = Sql::TableReference.new(environment)) - this_join = [ - join_sql, - relation2.externalize.table_sql(formatter), - ("ON" unless predicates.blank?), - (ons + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') - ].compact.join(" ") - [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") + @joins ||= begin + this_join = [ + join_sql, + relation2.externalize.table_sql(formatter), + ("ON" unless predicates.blank?), + (ons + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + ].compact.join(" ") + [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") + end end def attributes @@ -45,11 +47,10 @@ def join? end def ==(other) - Join == other.class and - predicates == other.predicates and ( - (relation1 == other.relation1 and relation2 == other.relation2) or - (relation2 == other.relation1 and relation1 == other.relation2) - ) + Join === other and + predicates == other.predicates and + relation1 == other.relation1 and + relation2 == other.relation2 end end diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/nil.rb index c34fe71473cf4..2dcfb47233585 100644 --- a/lib/arel/relations/nil.rb +++ b/lib/arel/relations/nil.rb @@ -4,7 +4,7 @@ def table_sql(formatter = nil); '' end def name; '' end def ==(other) - Nil == other.class + Nil === other end end end \ No newline at end of file diff --git a/lib/arel/relations/order.rb b/lib/arel/relations/order.rb index 31032e871c103..ebb4dc0668414 100644 --- a/lib/arel/relations/order.rb +++ b/lib/arel/relations/order.rb @@ -11,9 +11,9 @@ def orders end def ==(other) - Order == other.class and - relation == other.relation and - orderings == other.orderings + Order === other and + relation == other.relation and + orderings == other.orderings end end end \ No newline at end of file diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/projection.rb index 7eea63d808b84..d74f111271c57 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/projection.rb @@ -15,9 +15,9 @@ def aggregation? end def ==(other) - Projection == other.class and - relation == other.relation and - projections == other.projections + Projection === other and + relation == other.relation and + projections == other.projections end end end \ No newline at end of file diff --git a/lib/arel/relations/selection.rb b/lib/arel/relations/selection.rb index 0c5956d2fc2d6..fc4e94621a9d3 100644 --- a/lib/arel/relations/selection.rb +++ b/lib/arel/relations/selection.rb @@ -13,9 +13,9 @@ def selects end def ==(other) - Selection == other.class and - relation == other.relation and - predicate == other.predicate + Selection === other and + relation == other.relation and + predicate == other.predicate end end end \ No newline at end of file diff --git a/lib/arel/relations/skip.rb b/lib/arel/relations/skip.rb index 4686e03177e55..01ac4c7204e3a 100644 --- a/lib/arel/relations/skip.rb +++ b/lib/arel/relations/skip.rb @@ -7,9 +7,9 @@ def initialize(relation, skipped) end def ==(other) - Skip == other.class and - relation == other.relation and - skipped == other.skipped + Skip === other and + relation == other.relation and + skipped == other.skipped end end end \ No newline at end of file diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 06625dd52a154..087028fb55965 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -29,8 +29,8 @@ def reset end def ==(other) - Table == other.class and - name == other.name + Table === other and + name == other.name end end end \ No newline at end of file diff --git a/lib/arel/relations/take.rb b/lib/arel/relations/take.rb index 80aa62a878bde..0a49891aee012 100644 --- a/lib/arel/relations/take.rb +++ b/lib/arel/relations/take.rb @@ -7,9 +7,9 @@ def initialize(relation, taken) end def ==(other) - Take == other.class and - relation == other.relation and - taken == other.taken + Take === other and + relation == other.relation and + taken == other.taken end end end \ No newline at end of file diff --git a/lib/arel/relations/update.rb b/lib/arel/relations/update.rb index 486ad2ab1212e..8306a83aac0d8 100644 --- a/lib/arel/relations/update.rb +++ b/lib/arel/relations/update.rb @@ -22,9 +22,9 @@ def call(connection = engine.connection) end def ==(other) - Update == other.class and - relation == other.relation and - assignments == other.assignments + Update === other and + relation == other.relation and + assignments == other.assignments end end end \ No newline at end of file diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index 57b1f3a53468c..5dee4833d4ca3 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -44,18 +44,6 @@ def predicate_sql end end end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) - Binary.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the predicates are identical" do - Binary.new(@attribute1, @attribute2).should == Binary.new(@attribute1, @attribute2) - Binary.new(@attribute1, @attribute2).should_not == ConcreteBinary.new(@attribute1, @attribute2) - end - end describe '#bind' do before do diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index d128dd0560648..1698bf9647a31 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -7,23 +7,6 @@ module Arel @relation2 = Table.new(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - - describe '==' do - before do - @another_predicate = @relation1[:id].eq(1) - @another_relation = Table.new(:cameras) - end - - it 'obtains if the two relations and the predicate are identical' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation1, @relation2, @predicate) - Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @another_relation, @predicate) - Join.new("INNER JOIN", @relation1, @relation2, @predicate).should_not == Join.new("INNER JOIN", @relation1, @relation2, @another_predicate) - end - - it 'is commutative on the relations' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).should == Join.new("INNER JOIN", @relation2, @relation1, @predicate) - end - end describe 'hashing' do it 'implements hash equality' do diff --git a/spec/arel/unit/relations/projection_spec.rb b/spec/arel/unit/relations/projection_spec.rb index cede58354b0fd..3c6a092db5859 100644 --- a/spec/arel/unit/relations/projection_spec.rb +++ b/spec/arel/unit/relations/projection_spec.rb @@ -13,20 +13,7 @@ module Arel end it "manufactures attributes associated with the projection relation" do - # @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } - end - end - - describe '==' do - before do - @another_relation = Table.new(:photos) - @another_attribute = @relation[:name] - end - - it "obtains if the relations and attributes are identical" do - Projection.new(@relation, @attribute).should == Projection.new(@relation, @attribute) - Projection.new(@relation, @attribute).should_not == Projection.new(@another_relation, @attribute) - Projection.new(@relation, @attribute).should_not == Projection.new(@relation, @another_attribute) + @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } end end From 14210279b23788d47a18f0615f5e20234550c8ac Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Sun, 18 May 2008 22:11:05 -0700 Subject: [PATCH 0185/1492] can't remember what i was working on --- README | 2 +- lib/arel/relations/aggregation.rb | 6 +++++- lib/arel/relations/compound.rb | 10 +++++++++- lib/arel/relations/grouping.rb | 4 ---- lib/arel/relations/relation.rb | 10 +++++++--- lib/arel/sql/formatters.rb | 4 ++-- .../joins/with_aggregations_spec.rb | 10 ++++++++-- spec/arel/unit/relations/alias_spec.rb | 20 +++++++++++++++++++ 8 files changed, 52 insertions(+), 14 deletions(-) diff --git a/README b/README index bb8c6eb71a497..efd379d7840c2 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ == Abstract == -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation of both the simplest and the most complex of SQL queries and it 2) transparently 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. +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 2) transparently 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. == A Gentle Introduction == diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index 9a34ea5d89ea4..7e9cdfe6125ce 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -11,13 +11,17 @@ def selects end def table_sql(formatter = Sql::TableReference.new(relation)) - relation.to_sql(formatter) + formatter.select relation.select_sql, self end def attributes @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } end + def name + relation.name + '_aggregation' + end + def ==(other) Aggregation === other and self.relation == other.relation diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index 9921568157231..f8af1906448a7 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -12,7 +12,15 @@ def attributes end def selects - @selects || relation.selects.collect { |s| s.bind(self) } + @selects ||= relation.selects.collect { |s| s.bind(self) } + end + + def groupings + @groupings ||= relation.groupings.collect { |g| g.bind(self) } + end + + def orders + @orders ||= relation.orders.collect { |o| o.bind(self) } end end end \ No newline at end of file diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/grouping.rb index 6d112990510b8..de8643278b884 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/grouping.rb @@ -15,9 +15,5 @@ def ==(other) def aggregation? true end - - def name - relation.name + '_aggregation' - end end end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 3704eb9318e08..9bf7e740aa513 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -5,7 +5,12 @@ def session end def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select [ + formatter.select select_sql, self + end + alias_method :to_s, :to_sql + + def select_sql + [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), @@ -14,9 +19,8 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n"), name + ].compact.join("\n") end - alias_method :to_s, :to_sql def inclusion_predicate_sql "IN" diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index cc7a1fa7d5ab5..068fb8d22d156 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -21,7 +21,7 @@ def expression(expression) end def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(table)}" + "(#{select_sql}) AS #{quote_table_name(name_for(table))}" end def value(value) @@ -80,7 +80,7 @@ def select(select_sql, table) class TableReference < Formatter def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(table)}" + "(#{select_sql}) AS #{quote_table_name(name_for(table))}" end def table(table) diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index db34bb1b46e4e..ab904d103d911 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -39,8 +39,14 @@ module Arel end describe 'with the aggregation on both sides' do - it '' do - @aggregation.join(@aggregation.alias).on(@predicate).to_sql.should == '' + it 'it properly aliases the aggregations' do + aggregation2 = @aggregation.alias + @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql.should be_like(" + SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `photos_aggregation_2`.`user_id`, `photos_aggregation_2`.`cnt` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation_2` + ON `photos_aggregation_2`.`user_id` = `photos_aggregation`.`user_id` + ") end end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 96e06f48bc57b..ce35debadf059 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -12,5 +12,25 @@ module Arel (aliaz = Alias.new(@relation)).should == aliaz end end + + describe '#to_sql' do + describe 'when there is no ambiguity' do + it 'does not alias table names anywhere a table name can appear' do + @relation \ + .select(@relation[:id].eq(1)) \ + .order(@relation[:id]) \ + .project(@relation[:id]) \ + .group(@relation[:id]) \ + .alias \ + .to_sql.should be_like(" + SELECT `users`.`id` + FROM `users` + WHERE `users`.`id` = 1 + ORDER BY `users`.`id` + GROUP BY `users`.`id` + ") + end + end + end end end \ No newline at end of file From 3eae3b08eef84237c201a2f7bfc5292dbbe6951c Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 13:49:43 -0700 Subject: [PATCH 0186/1492] renamed select operation to where --- README | 117 +++++++++++++----- doc/TODO | 3 +- lib/arel/relations.rb | 2 +- lib/arel/relations/aggregation.rb | 2 +- lib/arel/relations/compound.rb | 6 +- lib/arel/relations/deletion.rb | 2 +- lib/arel/relations/join.rb | 6 +- lib/arel/relations/relation.rb | 8 +- lib/arel/relations/selection.rb | 21 ---- lib/arel/relations/update.rb | 2 +- lib/arel/relations/where.rb | 21 ++++ .../integration/joins/with_adjacency_spec.rb | 20 +-- .../joins/with_aggregations_spec.rb | 10 +- .../integration/joins/with_compounds_spec.rb | 12 +- spec/arel/unit/primitives/attribute_spec.rb | 2 +- spec/arel/unit/primitives/expression_spec.rb | 2 +- spec/arel/unit/relations/alias_spec.rb | 2 +- spec/arel/unit/relations/deletion_spec.rb | 4 +- spec/arel/unit/relations/relation_spec.rb | 10 +- spec/arel/unit/relations/update_spec.rb | 6 +- .../{selection_spec.rb => where_spec.rb} | 12 +- 21 files changed, 165 insertions(+), 105 deletions(-) delete mode 100644 lib/arel/relations/selection.rb create mode 100644 lib/arel/relations/where.rb rename spec/arel/unit/relations/{selection_spec.rb => where_spec.rb} (66%) diff --git a/README b/README index efd379d7840c2..0e8f31ce13f49 100644 --- a/README +++ b/README @@ -1,8 +1,16 @@ -== Abstract == +## Abstract ## -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 2) transparently 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. +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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. -== A Gentle Introduction == +## Status ## + +Arel is alpha software, BEWARE. Nevertheless, at this point, many (most?) SELECT queries can be composed, including very very complicated ones. Writes are only experimental for now. + +For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. On the horizon is the use of DataObjects instead. + +The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc. + +## A Gentle Introduction ## Generating a query with ARel is simple. For example, in order to produce @@ -10,56 +18,107 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: - Arel::Table.new(:users).to_sql + users = Arel::Table.new(:users) + users.to_sql -In fact, you will probably never call `#to_sql`. Let `users = Arel::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: +In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: users.each { |user| ... } -In other words, Arel relations behave implement Ruby's Eunmerable interface. Let's have a look at a concrete example: +In other words, Arel relations implement Ruby's Enumerable interface. Let's have a look at a concrete example: - users.first # => {'id' => 10, 'name' => 'bob'} + users.first # => { users[:id] => 1, users[:name] => 'bob' } As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). -== Relational Algebra == +### More Sophisticated Queries Relations ### + +Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database. -Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. Arel::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: +First is the 'restriction' operator, `where`: - users.insert({users[:name] => 'amy'}) # => INSERT INTO users (users.name) VALUES ('amy') + 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 -To delete all 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.group(users[:name]) # => SELECT * FROM users GROUP BY name + +The best property of the Relational Algebra is its "composability", or closure under all operations. For example, to select 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.delete # => DELETE FROM users + users.where(users[:name].eq('bob')).where(users[:age].lt(25)) -To update: +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)) - users.update({users[:name] => 'carl'}) # => UPDATE users SET name = 'carl' +The `OR` operator is not yet supported. It will work like this: + + users.where(users[:name].eq('bob').or(users[:age].lt(25))) -As you can see, the `relation` named `users` does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate SQL queries to do the various CRUD operations. +The `AND` operator will behave similarly. -=== More Sophisticated Queries Relations === +### The Crazy Features ### -Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: +The examples above are fairly simple and other libraries match or come close to matching the expressiveness of Arel (e.g., `Sequel` in Ruby). - users.select(users[:name].eq('amy')) # => SELECT * FROM users WHERE users.name = 'amy' -What would, in SQL, be part of the `SELECT` clause is called here a `projection`: +#### Complex Joins #### - users.project(users[:id]) # => SELECT users.id FROM users +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) -Joins are fairly straightforward: +And this table has the following attributes: - users.join(photos).on(users[:id].eq(photos[:user_id])) => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id + comments.attributes # => [comments[:id], comments[:body], comments[:parent_id]] -The best property of the Relational is compositionality, or closure under all operations. For example, to select and project: +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: - users \ - .select(users[:name].eq('amy')) \ - .project(users[:id]) \ - # => SELECT users.id FROM users WHERE users.name = 'amy' + 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 + +Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Typically, the problem with automated table aliasing is that extracting data out of the result set when everything has a random name is quite hard. Arel makes this simple: to get just certain columns from the result set, treat a row like a hash: + + comments_with_replies.first[replies[:body]] + +This will return the first comment's reply's body. + +Arel can actually perform the aliasing automatically, without the need for the programmer to explicitly call `alias`. However, this makes it difficult to specify the join condition: + + comments.join(comments).on(comments[:parent_id].eq(comments[:id])) + # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id + +This does NOT have the same meaning as the previous query. As an alternative to aliasing, there is a convenient block form: + + comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } + +Of course, without the `alias`, you will have a harder time extracting `replies` data from a row. +#### Complex Aggregations #### -== Contributions == +My personal favorite feature of Arel, and certainly the most difficult to implement, is closure under joining even in the presence of aggregations. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. -I appreciate all contributions to Arel. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. \ No newline at end of file diff --git a/doc/TODO b/doc/TODO index 95e05ece49b8f..4b27d03c4ca4f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,7 +1,8 @@ todo: - rename select to where - and/or w/ predicates -- blocks for joins +- blocks for all operations +- result sets to attr correlation too - cache expiry on write - rewrite of arecord querycache test in light of this - scoped writes diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index 1a216993e0413..b606be3743bf2 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -8,7 +8,7 @@ require 'arel/relations/join' require 'arel/relations/grouping' require 'arel/relations/projection' -require 'arel/relations/selection' +require 'arel/relations/where' require 'arel/relations/order' require 'arel/relations/take' require 'arel/relations/skip' diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/aggregation.rb index 7e9cdfe6125ce..66150bff0a4a8 100644 --- a/lib/arel/relations/aggregation.rb +++ b/lib/arel/relations/aggregation.rb @@ -6,7 +6,7 @@ def initialize(relation) @relation = relation end - def selects + def wheres [] end diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/compound.rb index f8af1906448a7..a77099e0de1af 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation hash_on :relation - delegate :joins, :selects, :join?, :orders, :groupings, :inserts, :taken, + delegate :joins, :wheres, :join?, :inserts, :taken, :skipped, :name, :aggregation?, :column_for, :engine, :table, :table_sql, :to => :relation @@ -11,8 +11,8 @@ def attributes @attributes ||= relation.attributes.collect { |a| a.bind(self) } end - def selects - @selects ||= relation.selects.collect { |s| s.bind(self) } + def wheres + @wheres ||= relation.wheres.collect { |w| w.bind(self) } end def groupings diff --git a/lib/arel/relations/deletion.rb b/lib/arel/relations/deletion.rb index cd58771846459..7edc328e4acbd 100644 --- a/lib/arel/relations/deletion.rb +++ b/lib/arel/relations/deletion.rb @@ -8,7 +8,7 @@ def to_sql(formatter = nil) [ "DELETE", "FROM #{table_sql}", - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank? ), + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ].compact.join("\n") end diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/join.rb index 81a157dc102f6..acad75c81754d 100644 --- a/lib/arel/relations/join.rb +++ b/lib/arel/relations/join.rb @@ -18,7 +18,7 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) join_sql, relation2.externalize.table_sql(formatter), ("ON" unless predicates.blank?), - (ons + relation2.externalize.selects).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') ].compact.join(" ") [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") end @@ -29,8 +29,8 @@ def attributes relation2.externalize.attributes).collect { |a| a.bind(self) } end - def selects - relation1.externalize.selects + def wheres + relation1.externalize.wheres end def ons diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 9bf7e740aa513..1ef7874f39d3a 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -14,7 +14,7 @@ def select_sql "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), - ("WHERE #{selects .collect { |s| s.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless selects.blank? ), + ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), ("LIMIT #{taken}" unless taken.blank? ), @@ -72,8 +72,8 @@ def outer_join(other = nil) join(other, "LEFT OUTER JOIN") end - def select(*predicates) - predicates.all?(&:blank?) ? self : Selection.new(self, *predicates) + def where(*predicates) + predicates.all?(&:blank?) ? self : Where.new(self, *predicates) end def project(*attributes) @@ -161,7 +161,7 @@ def has_attribute?(attribute) module DefaultOperations def attributes; [] end - def selects; [] end + def wheres; [] end def orders; [] end def inserts; [] end def groupings; [] end diff --git a/lib/arel/relations/selection.rb b/lib/arel/relations/selection.rb deleted file mode 100644 index fc4e94621a9d3..0000000000000 --- a/lib/arel/relations/selection.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Arel - class Selection < Compound - attr_reader :predicate - - def initialize(relation, *predicates) - predicate = predicates.shift - @relation = predicates.empty?? relation : Selection.new(relation, *predicates) - @predicate = predicate.bind(@relation) - end - - def selects - @selects ||= (relation.selects + [predicate]).collect { |p| p.bind(self) } - end - - def ==(other) - Selection === other and - relation == other.relation and - predicate == other.predicate - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/update.rb b/lib/arel/relations/update.rb index 8306a83aac0d8..450f06af96223 100644 --- a/lib/arel/relations/update.rb +++ b/lib/arel/relations/update.rb @@ -12,7 +12,7 @@ def to_sql(formatter = nil) assignments.collect do |attribute, value| "#{value.format(attribute)} = #{attribute.format(value)}" end.join(",\n"), - ("WHERE #{selects.collect(&:to_sql).join('\n\tAND ')}" unless selects.blank? ), + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), ("LIMIT #{taken}" unless taken.blank? ) ].join("\n") end diff --git a/lib/arel/relations/where.rb b/lib/arel/relations/where.rb new file mode 100644 index 0000000000000..ba34846c041b3 --- /dev/null +++ b/lib/arel/relations/where.rb @@ -0,0 +1,21 @@ +module Arel + class Where < Compound + attr_reader :predicate + + def initialize(relation, *predicates) + predicate = predicates.shift + @relation = predicates.empty?? relation : Where.new(relation, *predicates) + @predicate = predicate.bind(@relation) + end + + def wheres + @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } + end + + def ==(other) + Where === other and + relation == other.relation and + predicate == other.predicate + end + end +end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 222303977f073..2fb5895a872bf 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -19,10 +19,10 @@ module Arel ") end - describe 'when joining with a selection on the same relation' do + describe 'when joining with a where on the same relation' do it 'manufactures sql aliasing the tables properly' do @relation1 \ - .join(@relation2.select(@relation2[:id].eq(1))) \ + .join(@relation2.where(@relation2[:id].eq(1))) \ .on(@predicate) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` @@ -32,9 +32,9 @@ module Arel ") end - describe 'when the selection occurs before the alias' do + describe 'when the where occurs before the alias' do it 'manufactures sql aliasing the predicates properly' do - relation2 = @relation1.select(@relation1[:id].eq(1)).alias + relation2 = @relation1.where(@relation1[:id].eq(1)).alias @relation1 \ .join(relation2) \ .on(relation2[:id].eq(@relation1[:id])) \ @@ -100,7 +100,7 @@ module Arel describe 'when both relations are compound and only one is an alias' do it 'disambiguates the relation that serves as the ancestor to the attribute' do - compound1 = @relation1.select(@predicate) + compound1 = @relation1.where(@predicate) compound2 = compound1.alias compound1 \ .join(compound2) \ @@ -112,8 +112,8 @@ module Arel describe 'when the left relation is extremely compound' do it 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ - .select(@predicate) \ - .select(@predicate) \ + .where(@predicate) \ + .where(@predicate) \ .join(@relation2) \ .on(@predicate) \ .should disambiguate_attributes(@relation1[:id], @relation2[:id]) @@ -125,9 +125,9 @@ module Arel @relation1 \ .join( \ @relation2 \ - .select(@predicate) \ - .select(@predicate) \ - .select(@predicate)) \ + .where(@predicate) \ + .where(@predicate) \ + .where(@predicate)) \ .on(@predicate) \ .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index ab904d103d911..b4861b0c5391a 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -50,10 +50,10 @@ module Arel end end - describe 'when the aggration has a selection' do + describe 'when the aggration has a where' do describe 'with the aggregation on the left' do - it "manufactures sql keeping selects on the aggregation within the derived table" do - @relation1.join(@aggregation.select(@aggregation[:user_id].eq(1))).on(@predicate).to_sql.should be_like(" + it "manufactures sql keeping wheres on the aggregation within the derived table" do + @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` FROM `users` INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` @@ -63,8 +63,8 @@ module Arel end describe 'with the aggregation on the right' do - it "manufactures sql keeping selects on the aggregation within the derived table" do - @aggregation.select(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" + it "manufactures sql keeping wheres on the aggregation within the derived table" do + @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` INNER JOIN `users` diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 62d226acf2f1e..3c17ab315da5e 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -9,11 +9,11 @@ module Arel end describe '#to_sql' do - describe 'when the join contains a select' do - describe 'and the select is given a string' do + describe 'when the join contains a where' do + describe 'and the where is given a string' do it 'does not escape the string' do @relation1 \ - .join(@relation2.select("asdf")) \ + .join(@relation2.where("asdf")) \ .on(@predicate) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` @@ -26,13 +26,13 @@ module Arel end describe 'when a compound contains a join' do - describe 'and the compound is a select' do + describe 'and the compound is a where' do it 'manufactures sql disambiguating the tables' do @relation1 \ - .select(@relation1[:id].eq(1)) \ + .where(@relation1[:id].eq(1)) \ .join(@relation2) \ .on(@predicate) \ - .select(@relation1[:id].eq(1)) \ + .where(@relation1[:id].eq(1)) \ .to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `users` diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index 890ac0e8138d1..b341c6f88e267 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -16,7 +16,7 @@ module Arel describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do - derived_relation = @relation.select(@relation[:id].eq(1)) + derived_relation = @relation.where(@relation[:id].eq(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index 8a990231f6131..d398805fe2642 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -14,7 +14,7 @@ module Arel describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do - derived_relation = @relation.select(@relation[:id].eq(1)) + derived_relation = @relation.where(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index ce35debadf059..5327154fa8370 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -17,7 +17,7 @@ module Arel describe 'when there is no ambiguity' do it 'does not alias table names anywhere a table name can appear' do @relation \ - .select(@relation[:id].eq(1)) \ + .where(@relation[:id].eq(1)) \ .order(@relation[:id]) \ .project(@relation[:id]) \ .group(@relation[:id]) \ diff --git a/spec/arel/unit/relations/deletion_spec.rb b/spec/arel/unit/relations/deletion_spec.rb index f975720d83a52..46c2ec9143183 100644 --- a/spec/arel/unit/relations/deletion_spec.rb +++ b/spec/arel/unit/relations/deletion_spec.rb @@ -14,8 +14,8 @@ module Arel ") end - it 'manufactures sql deleting a selection relation' do - Deletion.new(@relation.select(@relation[:id].eq(1))).to_sql.should be_like(" + it 'manufactures sql deleting a where relation' do + Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql.should be_like(" DELETE FROM `users` WHERE `users`.`id` = 1 diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index d9ae8e0742a96..78e391640e589 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -78,22 +78,22 @@ module Arel end end - describe '#select' do + describe '#where' do before do @predicate = Equality.new(@attribute1, @attribute2) end - it "manufactures a selection relation" do - @relation.select(@predicate).should == Selection.new(@relation, @predicate) + it "manufactures a where relation" do + @relation.where(@predicate).should == Where.new(@relation, @predicate) end it "accepts arbitrary strings" do - @relation.select("arbitrary").should == Selection.new(@relation, "arbitrary") + @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") end describe 'when given a blank predicate' do it 'returns self' do - @relation.select.should == @relation + @relation.where.should == @relation end end end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index f411781392cf1..08c6da7901ef3 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -48,15 +48,15 @@ module Arel end end - describe 'when the relation is a selection' do + describe 'when the relation is a where' do before do @update = Update.new( - @relation.select(@relation[:id].eq(1)), + @relation.where(@relation[:id].eq(1)), @relation[:name] => "nick" ) end - it 'manufactures sql updating a selection relation' do + it 'manufactures sql updating a where relation' do @update.to_sql.should be_like(" UPDATE `users` SET `users`.`name` = 'nick' diff --git a/spec/arel/unit/relations/selection_spec.rb b/spec/arel/unit/relations/where_spec.rb similarity index 66% rename from spec/arel/unit/relations/selection_spec.rb rename to spec/arel/unit/relations/where_spec.rb index 20807f952f083..aa14fd7bdcbec 100644 --- a/spec/arel/unit/relations/selection_spec.rb +++ b/spec/arel/unit/relations/where_spec.rb @@ -1,24 +1,24 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel - describe Selection do + describe Where do before do @relation = Table.new(:users) @predicate = @relation[:id].eq(1) end describe '#initialize' do - it "manufactures nested selection relations if multiple predicates are provided" do + it "manufactures nested where relations if multiple predicates are provided" do another_predicate = @relation[:name].lt(2) - Selection.new(@relation, @predicate, another_predicate). \ - should == Selection.new(Selection.new(@relation, another_predicate), @predicate) + Where.new(@relation, @predicate, another_predicate). \ + should == Where.new(Where.new(@relation, another_predicate), @predicate) end end describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - Selection.new(@relation, @predicate).to_sql.should be_like(" + Where.new(@relation, @predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` WHERE `users`.`id` = 1 @@ -28,7 +28,7 @@ module Arel describe 'when given a string' do it "passes the string through to the where clause" do - Selection.new(@relation, 'asdf').to_sql.should be_like(" + Where.new(@relation, 'asdf').to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` WHERE asdf From 518db17ca3dade07fc67b6044b63c826cefb1442 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 13:57:21 -0700 Subject: [PATCH 0187/1492] renamed ion classes --- doc/TODO | 5 +++-- lib/arel/relations.rb | 8 ++++---- lib/arel/relations/{deletion.rb => delete.rb} | 0 lib/arel/relations/{grouping.rb => group.rb} | 4 ++-- lib/arel/relations/{insertion.rb => insert.rb} | 4 ++-- lib/arel/relations/{projection.rb => project.rb} | 4 ++-- lib/arel/relations/relation.rb | 6 +++--- .../{deletion_spec.rb => delete_spec.rb} | 0 .../{grouping_spec.rb => group_spec.rb} | 6 +++--- .../{insertion_spec.rb => insert_spec.rb} | 12 ++++++------ .../{projection_spec.rb => project_spec.rb} | 16 ++++++++-------- spec/arel/unit/relations/relation_spec.rb | 6 +++--- spec/arel/unit/session/session_spec.rb | 2 +- 13 files changed, 37 insertions(+), 36 deletions(-) rename lib/arel/relations/{deletion.rb => delete.rb} (100%) rename lib/arel/relations/{grouping.rb => group.rb} (81%) rename lib/arel/relations/{insertion.rb => insert.rb} (89%) rename lib/arel/relations/{projection.rb => project.rb} (85%) rename spec/arel/unit/relations/{deletion_spec.rb => delete_spec.rb} (100%) rename spec/arel/unit/relations/{grouping_spec.rb => group_spec.rb} (81%) rename spec/arel/unit/relations/{insertion_spec.rb => insert_spec.rb} (78%) rename spec/arel/unit/relations/{projection_spec.rb => project_spec.rb} (75%) diff --git a/doc/TODO b/doc/TODO index 4b27d03c4ca4f..8d805d9f72688 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,4 @@ todo: -- rename select to where - and/or w/ predicates - blocks for all operations - result sets to attr correlation too @@ -18,7 +17,7 @@ done: . Attribute == Attribute -> EqualityPredicate . Attribute >= Attribute -> GreaterThanOrEqualToPredicate . Relation.include?(Column) -> Predicate -. Relation.project(*Column) -> ProjectionRelation +. Relation.project(*Column) -> ProjectRelation . Relation.select(*Predicate) -> SelectionRelation . Relation.order(*Column) -> OrderRelation . #to_sql @@ -67,6 +66,8 @@ done: - All Sql Strategies should be accumulations with the top-level relation? - instance methodify externalize - test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. +- rename select to where +- rename all ion classes icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index b606be3743bf2..364235fb4918b 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -6,14 +6,14 @@ require 'arel/relations/table' require 'arel/relations/aggregation' require 'arel/relations/join' -require 'arel/relations/grouping' -require 'arel/relations/projection' +require 'arel/relations/group' +require 'arel/relations/project' require 'arel/relations/where' require 'arel/relations/order' require 'arel/relations/take' require 'arel/relations/skip' -require 'arel/relations/deletion' -require 'arel/relations/insertion' +require 'arel/relations/delete' +require 'arel/relations/insert' require 'arel/relations/update' require 'arel/relations/alias' require 'arel/sessions/session' \ No newline at end of file diff --git a/lib/arel/relations/deletion.rb b/lib/arel/relations/delete.rb similarity index 100% rename from lib/arel/relations/deletion.rb rename to lib/arel/relations/delete.rb diff --git a/lib/arel/relations/grouping.rb b/lib/arel/relations/group.rb similarity index 81% rename from lib/arel/relations/grouping.rb rename to lib/arel/relations/group.rb index de8643278b884..bc3a7f3437910 100644 --- a/lib/arel/relations/grouping.rb +++ b/lib/arel/relations/group.rb @@ -1,5 +1,5 @@ module Arel - class Grouping < Compound + class Group < Compound attr_reader :groupings def initialize(relation, *groupings) @@ -7,7 +7,7 @@ def initialize(relation, *groupings) end def ==(other) - Grouping === other and + Group === other and relation == other.relation and groupings == other.groupings end diff --git a/lib/arel/relations/insertion.rb b/lib/arel/relations/insert.rb similarity index 89% rename from lib/arel/relations/insertion.rb rename to lib/arel/relations/insert.rb index 16eb9b75557bd..b190ccb2113b7 100644 --- a/lib/arel/relations/insertion.rb +++ b/lib/arel/relations/insert.rb @@ -1,5 +1,5 @@ module Arel - class Insertion < Writing + class Insert < Writing attr_reader :record def initialize(relation, record) @@ -20,7 +20,7 @@ def call(connection = engine.connection) end def ==(other) - Insertion === other and + Insert === other and relation == other.relation and record == other.record end diff --git a/lib/arel/relations/projection.rb b/lib/arel/relations/project.rb similarity index 85% rename from lib/arel/relations/projection.rb rename to lib/arel/relations/project.rb index d74f111271c57..0efc13bdb38e4 100644 --- a/lib/arel/relations/projection.rb +++ b/lib/arel/relations/project.rb @@ -1,5 +1,5 @@ module Arel - class Projection < Compound + class Project < Compound attr_reader :projections def initialize(relation, *projections) @@ -15,7 +15,7 @@ def aggregation? end def ==(other) - Projection === other and + Project === other and relation == other.relation and projections == other.projections end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 1ef7874f39d3a..4440fb1c1d93f 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -77,7 +77,7 @@ def where(*predicates) end def project(*attributes) - attributes.all?(&:blank?) ? self : Projection.new(self, *attributes) + attributes.all?(&:blank?) ? self : Project.new(self, *attributes) end def alias @@ -97,12 +97,12 @@ def skip(skipped = nil) end def group(*groupings) - groupings.all?(&:blank?) ? self : Grouping.new(self, *groupings) + groupings.all?(&:blank?) ? self : Group.new(self, *groupings) end module Writable def insert(record) - session.create Insertion.new(self, record); self + session.create Insert.new(self, record); self end def update(assignments) diff --git a/spec/arel/unit/relations/deletion_spec.rb b/spec/arel/unit/relations/delete_spec.rb similarity index 100% rename from spec/arel/unit/relations/deletion_spec.rb rename to spec/arel/unit/relations/delete_spec.rb diff --git a/spec/arel/unit/relations/grouping_spec.rb b/spec/arel/unit/relations/group_spec.rb similarity index 81% rename from spec/arel/unit/relations/grouping_spec.rb rename to spec/arel/unit/relations/group_spec.rb index 5f781727cfb5b..a0147b94160b4 100644 --- a/spec/arel/unit/relations/grouping_spec.rb +++ b/spec/arel/unit/relations/group_spec.rb @@ -1,7 +1,7 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel - describe Grouping do + describe Group do before do @relation = Table.new(:users) @attribute = @relation[:id] @@ -10,7 +10,7 @@ module Arel describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - Grouping.new(@relation, @attribute).to_sql.should be_like(" + Group.new(@relation, @attribute).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` GROUP BY `users`.`id` @@ -20,7 +20,7 @@ module Arel describe 'when given a string' do it "passes the string through to the where clause" do - Grouping.new(@relation, 'asdf').to_sql.should be_like(" + Group.new(@relation, 'asdf').to_sql.should be_like(" SELECT `users`.`id`, `users`.`name` FROM `users` GROUP BY asdf diff --git a/spec/arel/unit/relations/insertion_spec.rb b/spec/arel/unit/relations/insert_spec.rb similarity index 78% rename from spec/arel/unit/relations/insertion_spec.rb rename to spec/arel/unit/relations/insert_spec.rb index 10b70a203693e..b983e545a4b4c 100644 --- a/spec/arel/unit/relations/insertion_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -1,7 +1,7 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel - describe Insertion do + describe Insert do before do @relation = Table.new(:users) end @@ -9,7 +9,7 @@ module Arel describe '#to_sql' do it 'manufactures sql inserting data when given multiple rows' do pending 'it should insert multiple rows' - @insertion = Insertion.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) + @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) @insertion.to_sql.should be_like(" INSERT @@ -19,7 +19,7 @@ module Arel end it 'manufactures sql inserting data when given multiple values' do - @insertion = Insertion.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") + @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") @insertion.to_sql.should be_like(" INSERT @@ -30,7 +30,7 @@ module Arel describe 'when given values whose types correspond to the types of the attributes' do before do - @insertion = Insertion.new(@relation, @relation[:name] => "nick") + @insertion = Insert.new(@relation, @relation[:name] => "nick") end it 'manufactures sql inserting data' do @@ -44,7 +44,7 @@ module Arel describe 'when given values whose types differ from from the types of the attributes' do before do - @insertion = Insertion.new(@relation, @relation[:id] => '1-asdf') + @insertion = Insert.new(@relation, @relation[:id] => '1-asdf') end it 'manufactures sql inserting data' do @@ -59,7 +59,7 @@ module Arel describe '#call' do before do - @insertion = Insertion.new(@relation, @relation[:name] => "nick") + @insertion = Insert.new(@relation, @relation[:name] => "nick") end it 'executes an insert on the connection' do diff --git a/spec/arel/unit/relations/projection_spec.rb b/spec/arel/unit/relations/project_spec.rb similarity index 75% rename from spec/arel/unit/relations/projection_spec.rb rename to spec/arel/unit/relations/project_spec.rb index 3c6a092db5859..2a4b690dd8a33 100644 --- a/spec/arel/unit/relations/projection_spec.rb +++ b/spec/arel/unit/relations/project_spec.rb @@ -1,7 +1,7 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel - describe Projection do + describe Project do before do @relation = Table.new(:users) @attribute = @relation[:id] @@ -9,7 +9,7 @@ module Arel describe '#attributes' do before do - @projection = Projection.new(@relation, @attribute) + @projection = Project.new(@relation, @attribute) end it "manufactures attributes associated with the projection relation" do @@ -20,7 +20,7 @@ module Arel describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do - Projection.new(@relation, @attribute).to_sql.should be_like(" + Project.new(@relation, @attribute).to_sql.should be_like(" SELECT `users`.`id` FROM `users` ") @@ -29,11 +29,11 @@ module Arel describe 'when given a relation' do before do - @scalar_relation = Projection.new(@relation, @relation[:name]) + @scalar_relation = Project.new(@relation, @relation[:name]) end it "manufactures sql with scalar selects" do - Projection.new(@relation, @scalar_relation).to_sql.should be_like(" + Project.new(@relation, @scalar_relation).to_sql.should be_like(" SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` ") end @@ -41,7 +41,7 @@ module Arel describe 'when given a string' do it "passes the string through to the select clause" do - Projection.new(@relation, 'asdf').to_sql.should be_like(" + Project.new(@relation, 'asdf').to_sql.should be_like(" SELECT asdf FROM `users` ") end @@ -60,13 +60,13 @@ module Arel describe '#aggregation?' do describe 'when the projections are attributes' do it 'returns false' do - Projection.new(@relation, @attribute).should_not be_aggregation + Project.new(@relation, @attribute).should_not be_aggregation end end describe 'when the projections include an aggregation' do it "obtains" do - Projection.new(@relation, @attribute.sum).should be_aggregation + Project.new(@relation, @attribute.sum).should be_aggregation end end end diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index 78e391640e589..77a787b840e0c 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -62,7 +62,7 @@ module Arel describe '#project' do it "manufactures a projection relation" do @relation.project(@attribute1, @attribute2). \ - should == Projection.new(@relation, @attribute1, @attribute2) + should == Project.new(@relation, @attribute1, @attribute2) end describe "when given blank attributes" do @@ -136,7 +136,7 @@ module Arel describe '#group' do it 'manufactures a group relation' do - @relation.group(@attribute1, @attribute2).should == Grouping.new(@relation, @attribute1, @attribute2) + @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) end describe 'when given blank groupings' do @@ -160,7 +160,7 @@ module Arel it 'manufactures an insertion relation' do Session.start do record = {@relation[:name] => 'carl'} - mock(Session.new).create(Insertion.new(@relation, record)) + mock(Session.new).create(Insert.new(@relation, record)) @relation.insert(record).should == @relation end end diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb index fbb2b7791b874..7582aa35e1159 100644 --- a/spec/arel/unit/session/session_spec.rb +++ b/spec/arel/unit/session/session_spec.rb @@ -32,7 +32,7 @@ module Arel describe Session::CRUD do before do - @insert = Insertion.new(@relation, @relation[:name] => 'nick') + @insert = Insert.new(@relation, @relation[:name] => 'nick') @update = Update.new(@relation, @relation[:name] => 'nick') @delete = Deletion.new(@relation) @read = @relation From e8966bf9a86afb82c658cedd7e4baffa3a15a856 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 14:08:42 -0700 Subject: [PATCH 0188/1492] reorganized file structure --- lib/arel.rb | 3 +- lib/arel/{engines => }/engine.rb | 0 lib/arel/engines.rb | 1 - lib/arel/relations.rb | 23 ++++---------- lib/arel/relations/operations.rb | 8 +++++ lib/arel/relations/{ => operations}/alias.rb | 0 lib/arel/relations/{ => operations}/group.rb | 0 lib/arel/relations/{ => operations}/join.rb | 0 lib/arel/relations/{ => operations}/order.rb | 0 .../relations/{ => operations}/project.rb | 0 lib/arel/relations/{ => operations}/skip.rb | 0 lib/arel/relations/{ => operations}/take.rb | 0 lib/arel/relations/{ => operations}/where.rb | 0 lib/arel/relations/utilities.rb | 5 +++ .../relations/{ => utilities}/aggregation.rb | 0 .../relations/{ => utilities}/compound.rb | 0 lib/arel/relations/{ => utilities}/nil.rb | 0 .../relations/{ => utilities}/recursion.rb | 0 lib/arel/relations/writes.rb | 3 ++ lib/arel/relations/{ => writes}/delete.rb | 2 +- lib/arel/relations/{ => writes}/insert.rb | 2 +- lib/arel/relations/{ => writes}/update.rb | 2 +- lib/arel/relations/writing.rb | 4 --- lib/arel/{sessions => }/session.rb | 0 spec/arel/unit/relations/compound_spec.rb | 31 ------------------- 25 files changed, 27 insertions(+), 57 deletions(-) rename lib/arel/{engines => }/engine.rb (100%) delete mode 100644 lib/arel/engines.rb create mode 100644 lib/arel/relations/operations.rb rename lib/arel/relations/{ => operations}/alias.rb (100%) rename lib/arel/relations/{ => operations}/group.rb (100%) rename lib/arel/relations/{ => operations}/join.rb (100%) rename lib/arel/relations/{ => operations}/order.rb (100%) rename lib/arel/relations/{ => operations}/project.rb (100%) rename lib/arel/relations/{ => operations}/skip.rb (100%) rename lib/arel/relations/{ => operations}/take.rb (100%) rename lib/arel/relations/{ => operations}/where.rb (100%) create mode 100644 lib/arel/relations/utilities.rb rename lib/arel/relations/{ => utilities}/aggregation.rb (100%) rename lib/arel/relations/{ => utilities}/compound.rb (100%) rename lib/arel/relations/{ => utilities}/nil.rb (100%) rename lib/arel/relations/{ => utilities}/recursion.rb (100%) create mode 100644 lib/arel/relations/writes.rb rename lib/arel/relations/{ => writes}/delete.rb (94%) rename lib/arel/relations/{ => writes}/insert.rb (95%) rename lib/arel/relations/{ => writes}/update.rb (96%) delete mode 100644 lib/arel/relations/writing.rb rename lib/arel/{sessions => }/session.rb (100%) delete mode 100644 spec/arel/unit/relations/compound_spec.rb diff --git a/lib/arel.rb b/lib/arel.rb index 75489c9c6e5cc..b4fae65f738f0 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -8,5 +8,6 @@ require 'arel/sql' require 'arel/predicates' require 'arel/relations' -require 'arel/engines' +require 'arel/engine' +require 'arel/session' require 'arel/primitives' \ No newline at end of file diff --git a/lib/arel/engines/engine.rb b/lib/arel/engine.rb similarity index 100% rename from lib/arel/engines/engine.rb rename to lib/arel/engine.rb diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb deleted file mode 100644 index bb71537e9c890..0000000000000 --- a/lib/arel/engines.rb +++ /dev/null @@ -1 +0,0 @@ -require 'arel/engines/engine' \ No newline at end of file diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index 364235fb4918b..3394fac7cbcc4 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -1,19 +1,8 @@ -require 'arel/relations/recursion' require 'arel/relations/relation' -require 'arel/relations/nil' -require 'arel/relations/compound' -require 'arel/relations/writing' + +require 'arel/relations/utilities' + require 'arel/relations/table' -require 'arel/relations/aggregation' -require 'arel/relations/join' -require 'arel/relations/group' -require 'arel/relations/project' -require 'arel/relations/where' -require 'arel/relations/order' -require 'arel/relations/take' -require 'arel/relations/skip' -require 'arel/relations/delete' -require 'arel/relations/insert' -require 'arel/relations/update' -require 'arel/relations/alias' -require 'arel/sessions/session' \ No newline at end of file + +require 'arel/relations/writes' +require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/operations.rb b/lib/arel/relations/operations.rb new file mode 100644 index 0000000000000..c598c7fcc9ab9 --- /dev/null +++ b/lib/arel/relations/operations.rb @@ -0,0 +1,8 @@ +require 'arel/relations/operations/alias' +require 'arel/relations/operations/group' +require 'arel/relations/operations/join' +require 'arel/relations/operations/order' +require 'arel/relations/operations/project' +require 'arel/relations/operations/where' +require 'arel/relations/operations/skip' +require 'arel/relations/operations/take' \ No newline at end of file diff --git a/lib/arel/relations/alias.rb b/lib/arel/relations/operations/alias.rb similarity index 100% rename from lib/arel/relations/alias.rb rename to lib/arel/relations/operations/alias.rb diff --git a/lib/arel/relations/group.rb b/lib/arel/relations/operations/group.rb similarity index 100% rename from lib/arel/relations/group.rb rename to lib/arel/relations/operations/group.rb diff --git a/lib/arel/relations/join.rb b/lib/arel/relations/operations/join.rb similarity index 100% rename from lib/arel/relations/join.rb rename to lib/arel/relations/operations/join.rb diff --git a/lib/arel/relations/order.rb b/lib/arel/relations/operations/order.rb similarity index 100% rename from lib/arel/relations/order.rb rename to lib/arel/relations/operations/order.rb diff --git a/lib/arel/relations/project.rb b/lib/arel/relations/operations/project.rb similarity index 100% rename from lib/arel/relations/project.rb rename to lib/arel/relations/operations/project.rb diff --git a/lib/arel/relations/skip.rb b/lib/arel/relations/operations/skip.rb similarity index 100% rename from lib/arel/relations/skip.rb rename to lib/arel/relations/operations/skip.rb diff --git a/lib/arel/relations/take.rb b/lib/arel/relations/operations/take.rb similarity index 100% rename from lib/arel/relations/take.rb rename to lib/arel/relations/operations/take.rb diff --git a/lib/arel/relations/where.rb b/lib/arel/relations/operations/where.rb similarity index 100% rename from lib/arel/relations/where.rb rename to lib/arel/relations/operations/where.rb diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb new file mode 100644 index 0000000000000..02c2e0a952ce3 --- /dev/null +++ b/lib/arel/relations/utilities.rb @@ -0,0 +1,5 @@ +require 'arel/relations/utilities/compound' +require 'arel/relations/utilities/recursion' +require 'arel/relations/utilities/nil' +require 'arel/relations/utilities/aggregation' +require 'arel/relations/utilities/recursion' \ No newline at end of file diff --git a/lib/arel/relations/aggregation.rb b/lib/arel/relations/utilities/aggregation.rb similarity index 100% rename from lib/arel/relations/aggregation.rb rename to lib/arel/relations/utilities/aggregation.rb diff --git a/lib/arel/relations/compound.rb b/lib/arel/relations/utilities/compound.rb similarity index 100% rename from lib/arel/relations/compound.rb rename to lib/arel/relations/utilities/compound.rb diff --git a/lib/arel/relations/nil.rb b/lib/arel/relations/utilities/nil.rb similarity index 100% rename from lib/arel/relations/nil.rb rename to lib/arel/relations/utilities/nil.rb diff --git a/lib/arel/relations/recursion.rb b/lib/arel/relations/utilities/recursion.rb similarity index 100% rename from lib/arel/relations/recursion.rb rename to lib/arel/relations/utilities/recursion.rb diff --git a/lib/arel/relations/writes.rb b/lib/arel/relations/writes.rb new file mode 100644 index 0000000000000..1495d9c8575e0 --- /dev/null +++ b/lib/arel/relations/writes.rb @@ -0,0 +1,3 @@ +require 'arel/relations/writes/delete' +require 'arel/relations/writes/update' +require 'arel/relations/writes/insert' \ No newline at end of file diff --git a/lib/arel/relations/delete.rb b/lib/arel/relations/writes/delete.rb similarity index 94% rename from lib/arel/relations/delete.rb rename to lib/arel/relations/writes/delete.rb index 7edc328e4acbd..2eaad6d1da5f5 100644 --- a/lib/arel/relations/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -1,5 +1,5 @@ module Arel - class Deletion < Writing + class Deletion < Compound def initialize(relation) @relation = relation end diff --git a/lib/arel/relations/insert.rb b/lib/arel/relations/writes/insert.rb similarity index 95% rename from lib/arel/relations/insert.rb rename to lib/arel/relations/writes/insert.rb index b190ccb2113b7..a1c4c93de5e1c 100644 --- a/lib/arel/relations/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -1,5 +1,5 @@ module Arel - class Insert < Writing + class Insert < Compound attr_reader :record def initialize(relation, record) diff --git a/lib/arel/relations/update.rb b/lib/arel/relations/writes/update.rb similarity index 96% rename from lib/arel/relations/update.rb rename to lib/arel/relations/writes/update.rb index 450f06af96223..760f4e931fc3e 100644 --- a/lib/arel/relations/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -1,5 +1,5 @@ module Arel - class Update < Writing + class Update < Compound attr_reader :assignments def initialize(relation, assignments) diff --git a/lib/arel/relations/writing.rb b/lib/arel/relations/writing.rb deleted file mode 100644 index b871e5a520b3c..0000000000000 --- a/lib/arel/relations/writing.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Arel - class Writing < Compound - end -end \ No newline at end of file diff --git a/lib/arel/sessions/session.rb b/lib/arel/session.rb similarity index 100% rename from lib/arel/sessions/session.rb rename to lib/arel/session.rb diff --git a/spec/arel/unit/relations/compound_spec.rb b/spec/arel/unit/relations/compound_spec.rb deleted file mode 100644 index 763e447db3dd6..0000000000000 --- a/spec/arel/unit/relations/compound_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Compound do - before do - class ConcreteCompound < Compound - def initialize(relation) - @relation = relation - end - - def ==(other) - true - end - end - @relation = Table.new(:users) - @compound_relation = ConcreteCompound.new(@relation) - end - - describe '#attributes' do - it 'manufactures attributes associated with the compound relation' do - @compound_relation.attributes.should == @relation.attributes.collect { |a| a.bind(@compound_relation) } - end - end - - describe 'hashing' do - it 'implements hash equality' do - ConcreteCompound.new(@relation).should hash_the_same_as(ConcreteCompound.new(@relation)) - end - end - end -end \ No newline at end of file From 78b5b5783776f57a47e480db4bd83b15db988909 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 17:55:49 -0700 Subject: [PATCH 0189/1492] some convenience methods --- README | 2 +- doc/TODO | 1 + lib/arel.rb | 1 + lib/arel/arel.rb | 3 +++ lib/arel/relations/relation.rb | 20 +++++++++---------- .../integration/joins/with_adjacency_spec.rb | 2 +- .../joins/with_aggregations_spec.rb | 4 ++-- .../integration/joins/with_compounds_spec.rb | 4 ++-- 8 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 lib/arel/arel.rb diff --git a/README b/README index 0e8f31ce13f49..d870f066536ec 100644 --- a/README +++ b/README @@ -109,7 +109,7 @@ This will return the first comment's reply's body. Arel can actually perform the aliasing automatically, without the need for the programmer to explicitly call `alias`. However, this makes it difficult to specify the join condition: - comments.join(comments).on(comments[:parent_id].eq(comments[:id])) + comments.join(comments, comments[:parent_id].eq(comments[:id])) # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id This does NOT have the same meaning as the previous query. As an alternative to aliasing, there is a convenient block form: diff --git a/doc/TODO b/doc/TODO index 8d805d9f72688..d7dd75d62e1f3 100644 --- a/doc/TODO +++ b/doc/TODO @@ -4,6 +4,7 @@ todo: - result sets to attr correlation too - cache expiry on write - rewrite of arecord querycache test in light of this +- transactions - scoped writes done: diff --git a/lib/arel.rb b/lib/arel.rb index b4fae65f738f0..f56005c2ed4cb 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -4,6 +4,7 @@ require 'activesupport' require 'activerecord' +require 'arel/arel' require 'arel/extensions' require 'arel/sql' require 'arel/predicates' diff --git a/lib/arel/arel.rb b/lib/arel/arel.rb new file mode 100644 index 0000000000000..892be854ee9a0 --- /dev/null +++ b/lib/arel/arel.rb @@ -0,0 +1,3 @@ +def Arel(name, engine = Arel::Table.engine) + Arel::Table.new(name, engine) +end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 4440fb1c1d93f..6e0413232fef5 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -57,26 +57,26 @@ def first include Enumerable module Operable - def join(other = nil, join_type = "INNER JOIN") - case other + def join(other_relation = nil, join_type = "INNER JOIN") + case other_relation when String - Join.new(other, self) + Join.new(other_relation, self) when Relation - JoinOperation.new(join_type, self, other) + JoinOperation.new(join_type, self, other_relation) else self end end - def outer_join(other = nil) - join(other, "LEFT OUTER JOIN") + def outer_join(other_relation = nil) + join(other_relation, "LEFT OUTER JOIN") end - def where(*predicates) + def where(*predicates, &block) predicates.all?(&:blank?) ? self : Where.new(self, *predicates) end - def project(*attributes) + def project(*attributes, &block) attributes.all?(&:blank?) ? self : Project.new(self, *attributes) end @@ -84,7 +84,7 @@ def alias Alias.new(self) end - def order(*attributes) + def order(*attributes, &block) attributes.all?(&:blank?) ? self : Order.new(self, *attributes) end @@ -96,7 +96,7 @@ def skip(skipped = nil) skipped.blank?? self : Skip.new(self, skipped) end - def group(*groupings) + def group(*groupings, &block) groupings.all?(&:blank?) ? self : Group.new(self, *groupings) end diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 2fb5895a872bf..32109cc3543d1 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -3,7 +3,7 @@ module Arel describe Join do before do - @relation1 = Table.new(:users) + @relation1 = Arel(:users) @relation2 = @relation1.alias @predicate = @relation1[:id].eq(@relation2[:id]) end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index b4861b0c5391a..9e28237c3c779 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -3,8 +3,8 @@ module Arel describe Join do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) + @relation1 = Arel(:users) + @relation2 = Arel(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 3c17ab315da5e..acfe35b25e7e8 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -3,8 +3,8 @@ module Arel describe Join do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) + @relation1 = Arel(:users) + @relation2 = Arel(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end From 5a5501cde76bbba69bcea27d3d0efeaffa3e3bf5 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 18:13:23 -0700 Subject: [PATCH 0190/1492] drying up some of the code --- lib/arel/relations/relation.rb | 29 ++++++------------------ lib/arel/relations/utilities/compound.rb | 26 ++++++++------------- 2 files changed, 16 insertions(+), 39 deletions(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 6e0413232fef5..1e2ac9f2be18a 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -72,33 +72,18 @@ def outer_join(other_relation = nil) join(other_relation, "LEFT OUTER JOIN") end - def where(*predicates, &block) - predicates.all?(&:blank?) ? self : Where.new(self, *predicates) + [:where, :project, :order, :take, :skip, :group].each do |operation_name| + operation = <<-OPERATION + def #{operation_name}(*arguments, &block) + arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) + end + OPERATION + class_eval operation, __FILE__, __LINE__ end - def project(*attributes, &block) - attributes.all?(&:blank?) ? self : Project.new(self, *attributes) - end - def alias Alias.new(self) end - - def order(*attributes, &block) - attributes.all?(&:blank?) ? self : Order.new(self, *attributes) - end - - def take(taken = nil) - taken.blank?? self : Take.new(self, taken) - end - - def skip(skipped = nil) - skipped.blank?? self : Skip.new(self, skipped) - end - - def group(*groupings, &block) - groupings.all?(&:blank?) ? self : Group.new(self, *groupings) - end module Writable def insert(record) diff --git a/lib/arel/relations/utilities/compound.rb b/lib/arel/relations/utilities/compound.rb index a77099e0de1af..23a55d4b5b064 100644 --- a/lib/arel/relations/utilities/compound.rb +++ b/lib/arel/relations/utilities/compound.rb @@ -2,25 +2,17 @@ module Arel class Compound < Relation attr_reader :relation hash_on :relation - delegate :joins, :wheres, :join?, :inserts, :taken, - :skipped, :name, :aggregation?, :column_for, - :engine, :table, :table_sql, + delegate :joins, :join?, :inserts, :taken, :skipped, :name, :aggregation?, + :column_for, :engine, :table, :table_sql, :to => :relation - def attributes - @attributes ||= relation.attributes.collect { |a| a.bind(self) } - end - - def wheres - @wheres ||= relation.wheres.collect { |w| w.bind(self) } - end - - def groupings - @groupings ||= relation.groupings.collect { |g| g.bind(self) } - end - - def orders - @orders ||= relation.orders.collect { |o| o.bind(self) } + [:attributes, :wheres, :groupings, :orders].each do |operation_name| + operation = <<-OPERATION + def #{operation_name} + @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } + end + OPERATION + class_eval operation, __FILE__, __LINE__ end end end \ No newline at end of file From 9e5ee49ec55b9cb1c2b4444dee58f3dfaefc7c7e Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 19:27:48 -0700 Subject: [PATCH 0191/1492] some drying up of boiler plate initialization and equality code --- lib/arel/extensions/class.rb | 26 ++++++++++++++++++++++++ lib/arel/relations/operations/alias.rb | 6 ++---- lib/arel/relations/operations/group.rb | 14 +++++-------- lib/arel/relations/operations/join.rb | 10 ++------- lib/arel/relations/operations/order.rb | 17 +++++++--------- lib/arel/relations/operations/project.rb | 14 +++++-------- lib/arel/relations/operations/skip.rb | 13 ++---------- lib/arel/relations/operations/take.rb | 13 ++---------- lib/arel/relations/operations/where.rb | 13 ++++-------- 9 files changed, 55 insertions(+), 71 deletions(-) diff --git a/lib/arel/extensions/class.rb b/lib/arel/extensions/class.rb index 09e6d86ed4be4..f37898e7d7fea 100644 --- a/lib/arel/extensions/class.rb +++ b/lib/arel/extensions/class.rb @@ -1,4 +1,30 @@ class Class + def attributes(*attrs) + @attributes = attrs + attr_reader *attrs + end + + def deriving(*methods) + methods.each { |m| derive m } + end + + def derive(method_name) + methods = { + :initialize => " + def #{method_name}(#{@attributes.join(',')}) + #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} + end + ", + :== => " + def ==(other) + #{name} === other && + #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} + end + " + } + class_eval methods[method_name], __FILE__, __LINE__ + end + def hash_on(delegatee) define_method :eql? do |other| self == other diff --git a/lib/arel/relations/operations/alias.rb b/lib/arel/relations/operations/alias.rb index d14a51f67ac9e..8ed33fc5978cf 100644 --- a/lib/arel/relations/operations/alias.rb +++ b/lib/arel/relations/operations/alias.rb @@ -1,10 +1,8 @@ module Arel class Alias < Compound include Recursion::BaseCase + attributes :relation + deriving :initialize alias_method :==, :equal? - - def initialize(relation) - @relation = relation - end end end \ No newline at end of file diff --git a/lib/arel/relations/operations/group.rb b/lib/arel/relations/operations/group.rb index bc3a7f3437910..22af2734a66b9 100644 --- a/lib/arel/relations/operations/group.rb +++ b/lib/arel/relations/operations/group.rb @@ -1,15 +1,11 @@ module Arel class Group < Compound - attr_reader :groupings + attributes :relation, :groupings + deriving :== - def initialize(relation, *groupings) - @relation, @groupings = relation, groupings.collect { |g| g.bind(relation) } - end - - def ==(other) - Group === other and - relation == other.relation and - groupings == other.groupings + def initialize(relation, *groupings, &block) + @relation = relation + @groupings = (groupings + (block_given?? [yield(self)] : [])).collect { |g| g.bind(relation) } end def aggregation? diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index acad75c81754d..01fa6da255f3d 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -1,6 +1,7 @@ module Arel class Join < Relation - attr_reader :join_sql, :relation1, :relation2, :predicates + attributes :join_sql, :relation1, :relation2, :predicates + deriving :== delegate :engine, :name, :to => :relation1 hash_on :relation1 @@ -45,13 +46,6 @@ def aggregation? def join? true end - - def ==(other) - Join === other and - predicates == other.predicates and - relation1 == other.relation1 and - relation2 == other.relation2 - end end class Relation diff --git a/lib/arel/relations/operations/order.rb b/lib/arel/relations/operations/order.rb index ebb4dc0668414..82924806e2c5f 100644 --- a/lib/arel/relations/operations/order.rb +++ b/lib/arel/relations/operations/order.rb @@ -1,19 +1,16 @@ module Arel class Order < Compound - attr_reader :orderings + attributes :relation, :orderings + deriving :== - def initialize(relation, *orderings) - @relation, @orderings = relation, orderings.collect { |o| o.bind(relation) } + def initialize(relation, *orderings, &block) + @relation = relation + @orderings = (orderings + (block_given?? [yield(self)] : [])).collect { |o| o.bind(relation) } end + # TESTME def orders - orderings + relation.orders - end - - def ==(other) - Order === other and - relation == other.relation and - orderings == other.orderings + (orderings + relation.orders).collect { |o| o.bind(self) } end end end \ No newline at end of file diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/relations/operations/project.rb index 0efc13bdb38e4..2be87fe694687 100644 --- a/lib/arel/relations/operations/project.rb +++ b/lib/arel/relations/operations/project.rb @@ -1,9 +1,11 @@ module Arel class Project < Compound - attr_reader :projections + attributes :relation, :projections + deriving :== - def initialize(relation, *projections) - @relation, @projections = relation, projections + def initialize(relation, *projections, &block) + @relation = relation + @projections = (projections + (block_given?? [yield(self)] : [])).collect { |p| p.bind(relation) } end def attributes @@ -13,11 +15,5 @@ def attributes def aggregation? attributes.any?(&:aggregation?) end - - def ==(other) - Project === other and - relation == other.relation and - projections == other.projections - end end end \ No newline at end of file diff --git a/lib/arel/relations/operations/skip.rb b/lib/arel/relations/operations/skip.rb index 01ac4c7204e3a..ea5df21f532ba 100644 --- a/lib/arel/relations/operations/skip.rb +++ b/lib/arel/relations/operations/skip.rb @@ -1,15 +1,6 @@ module Arel class Skip < Compound - attr_reader :skipped - - def initialize(relation, skipped) - @relation, @skipped = relation, skipped - end - - def ==(other) - Skip === other and - relation == other.relation and - skipped == other.skipped - end + attributes :relation, :skipped + deriving :initialize, :== end end \ No newline at end of file diff --git a/lib/arel/relations/operations/take.rb b/lib/arel/relations/operations/take.rb index 0a49891aee012..095e4304175f7 100644 --- a/lib/arel/relations/operations/take.rb +++ b/lib/arel/relations/operations/take.rb @@ -1,15 +1,6 @@ module Arel class Take < Compound - attr_reader :taken - - def initialize(relation, taken) - @relation, @taken = relation, taken - end - - def ==(other) - Take === other and - relation == other.relation and - taken == other.taken - end + attributes :relation, :taken + deriving :initialize, :== end end \ No newline at end of file diff --git a/lib/arel/relations/operations/where.rb b/lib/arel/relations/operations/where.rb index ba34846c041b3..9acb8ae3c6b51 100644 --- a/lib/arel/relations/operations/where.rb +++ b/lib/arel/relations/operations/where.rb @@ -1,21 +1,16 @@ module Arel class Where < Compound - attr_reader :predicate + attributes :relation, :predicate + deriving :== - def initialize(relation, *predicates) - predicate = predicates.shift + def initialize(relation, *predicates, &block) + predicate = block_given?? yield(self) : predicates.shift @relation = predicates.empty?? relation : Where.new(relation, *predicates) @predicate = predicate.bind(@relation) end def wheres @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } - end - - def ==(other) - Where === other and - relation == other.relation and - predicate == other.predicate end end end \ No newline at end of file From 2d021c641ab8c9215df863531cfb0d8ff8b9554a Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 19 May 2008 19:38:36 -0700 Subject: [PATCH 0192/1492] removed more boiler-plate --- lib/arel/primitives/attribute.rb | 37 +++++++++------------ lib/arel/primitives/expression.rb | 11 ++---- lib/arel/primitives/value.rb | 12 ++----- lib/arel/relations/operations/join.rb | 2 +- lib/arel/relations/utilities/aggregation.rb | 11 ++---- lib/arel/relations/utilities/nil.rb | 6 ++-- lib/arel/relations/writes/delete.rb | 10 ++---- lib/arel/relations/writes/insert.rb | 9 ++--- lib/arel/relations/writes/update.rb | 11 ++---- 9 files changed, 31 insertions(+), 78 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index ca1d31ffcf05c..dffe24d1219da 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -2,7 +2,8 @@ module Arel class Attribute - attr_reader :relation, :name, :alias, :ancestor + attributes :relation, :name, :alias, :ancestor + deriving :== delegate :engine, :christener, :to => :relation def initialize(relation, name, options = {}) @@ -28,26 +29,6 @@ def format(object) def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.attribute self end - - def ==(other) - Attribute === other and - name == other.name and - @alias == other.alias and - ancestor == other.ancestor and - relation == other.relation - end - - def original_relation - @original_relation ||= original_attribute.relation - end - - def original_attribute - @original_attribute ||= history.detect { |a| !a.join? } - end - - def find_correlate_in(relation) - relation[self] - end module Transformations def self.included(klass) @@ -80,11 +61,23 @@ def history def join? relation.join? end - + def root history.last end + def original_relation + @original_relation ||= original_attribute.relation + end + + def original_attribute + @original_attribute ||= history.detect { |a| !a.join? } + end + + def find_correlate_in(relation) + relation[self] + end + def descends_from?(other) history.include?(other) end diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 9afafcce2fa49..26186ccad8b0f 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -1,6 +1,7 @@ module Arel class Expression < Attribute - attr_reader :attribute, :function_sql + attributes :attribute, :function_sql, :alias, :ancestor + deriving :== delegate :relation, :to => :attribute alias_method :name, :alias @@ -16,14 +17,6 @@ def aggregation? true end - def ==(other) - Expression === other and - attribute == other.attribute and - function_sql == other.function_sql and - ancestor == other.ancestor and - @alias == other.alias - end - module Transformations def as(aliaz) Expression.new(attribute, function_sql, aliaz, self) diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 4509f13d17321..809af7c206253 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -1,12 +1,9 @@ module Arel class Value - attr_reader :value, :relation - + attributes :value, :relation + deriving :initialize, :== delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value - def initialize(value, relation) - @value, @relation = value, relation - end def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value @@ -16,11 +13,6 @@ def format(object) object.to_sql(Sql::Value.new(relation)) end - def ==(other) - Value === other and - value == other.value - end - def bind(relation) Value.new(value, relation) end diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index 01fa6da255f3d..243a0289c7278 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -5,7 +5,7 @@ class Join < Relation delegate :engine, :name, :to => :relation1 hash_on :relation1 - def initialize(join_sql, relation1, relation2 = Nil.new, *predicates) + def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end diff --git a/lib/arel/relations/utilities/aggregation.rb b/lib/arel/relations/utilities/aggregation.rb index 66150bff0a4a8..9f5ead8f86c85 100644 --- a/lib/arel/relations/utilities/aggregation.rb +++ b/lib/arel/relations/utilities/aggregation.rb @@ -1,11 +1,9 @@ module Arel class Aggregation < Compound + attributes :relation + deriving :initialize, :== include Recursion::BaseCase - def initialize(relation) - @relation = relation - end - def wheres [] end @@ -21,11 +19,6 @@ def attributes def name relation.name + '_aggregation' end - - def ==(other) - Aggregation === other and - self.relation == other.relation - end end class Relation diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/relations/utilities/nil.rb index 2dcfb47233585..2b8dc570f844d 100644 --- a/lib/arel/relations/utilities/nil.rb +++ b/lib/arel/relations/utilities/nil.rb @@ -1,10 +1,8 @@ module Arel class Nil < Relation + include Singleton + def table_sql(formatter = nil); '' end def name; '' end - - def ==(other) - Nil === other - end end end \ No newline at end of file diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index 2eaad6d1da5f5..e72679c4d633f 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -1,8 +1,7 @@ module Arel class Deletion < Compound - def initialize(relation) - @relation = relation - end + attributes :relation + deriving :initialize, :== def to_sql(formatter = nil) [ @@ -16,10 +15,5 @@ def to_sql(formatter = nil) def call(connection = engine.connection) connection.delete(to_sql) end - - def ==(other) - Deletion === other and - relation == other.relation - end end end \ No newline at end of file diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb index a1c4c93de5e1c..0545d7faa3a07 100644 --- a/lib/arel/relations/writes/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -1,6 +1,7 @@ module Arel class Insert < Compound - attr_reader :record + attributes :relation, :record + deriving :== def initialize(relation, record) @relation, @record = relation, record.bind(relation) @@ -18,11 +19,5 @@ def to_sql(formatter = nil) def call(connection = engine.connection) connection.insert(to_sql) end - - def ==(other) - Insert === other and - relation == other.relation and - record == other.record - end end end \ No newline at end of file diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 760f4e931fc3e..18b7ad9de1087 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -1,7 +1,8 @@ module Arel class Update < Compound - attr_reader :assignments - + attributes :relation, :assignments + deriving :== + def initialize(relation, assignments) @relation, @assignments = relation, assignments.bind(relation) end @@ -20,11 +21,5 @@ def to_sql(formatter = nil) def call(connection = engine.connection) connection.update(to_sql) end - - def ==(other) - Update === other and - relation == other.relation and - assignments == other.assignments - end end end \ No newline at end of file From 41f80e494af3ce7c8f3d6aa34f8303524a48373b Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 20 May 2008 10:11:07 -0700 Subject: [PATCH 0193/1492] limits and offsets need to be externalized too. first draft --- README | 82 ++++++++++++++++--- lib/arel/predicates.rb | 7 +- lib/arel/relations/operations/group.rb | 2 +- lib/arel/relations/operations/join.rb | 4 +- lib/arel/relations/operations/project.rb | 4 +- lib/arel/relations/operations/skip.rb | 4 + lib/arel/relations/operations/take.rb | 4 + lib/arel/relations/utilities/aggregation.rb | 8 +- lib/arel/relations/utilities/compound.rb | 2 +- lib/arel/relations/writes/delete.rb | 2 +- lib/arel/relations/writes/update.rb | 2 +- .../joins/with_aggregations_spec.rb | 41 ++++++---- spec/arel/unit/relations/project_spec.rb | 6 +- 13 files changed, 121 insertions(+), 47 deletions(-) diff --git a/README b/README index d870f066536ec..e979dbc2a39d0 100644 --- a/README +++ b/README @@ -18,7 +18,7 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: - users = Arel::Table.new(:users) + users = Arel(:users) users.to_sql In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: @@ -79,16 +79,23 @@ The `OR` operator is not yet supported. It will work like this: The `AND` operator will behave similarly. +Finally, most operations take a block form. For example: + + Arel(:users) \ + .where { |u| u[:id].eq(1) } \ + .project { |u| u[:id] } + +This provides a (sometimes) convenient alternative syntax. + ### 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). - #### 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) + comments = Arel(:comments) And this table has the following attributes: @@ -101,24 +108,77 @@ The `parent_id` column is a foreign key from the `comments` table to itself. Now 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 -Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Typically, the problem with automated table aliasing is that extracting data out of the result set when everything has a random name is quite hard. Arel makes this simple: to get just certain columns from the result set, treat a row like a hash: +The call to `#alias` is actually optional: Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Explicit aliasing is more common, however. When you want to extract specific slices of data, aliased tables are a necessity. For example to get just certain columns from the row, treat a row like a hash: comments_with_replies.first[replies[:body]] This will return the first comment's reply's body. -Arel can actually perform the aliasing automatically, without the need for the programmer to explicitly call `alias`. However, this makes it difficult to specify the join condition: +If you don't need to extract the data later (for example, you're simply doing a join to find comments that have replies, you don't care what the content of the replies are), the block form may be preferable: - comments.join(comments, comments[:parent_id].eq(comments[:id])) - # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id + comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } + # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id -This does NOT have the same meaning as the previous query. As an alternative to aliasing, there is a convenient block form: +Note that you do NOT want to do something like: - comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } + comments.join(comments, comments[:parent_id].eq(comments[:id])) + # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id -Of course, without the `alias`, you will have a harder time extracting `replies` data from a row. +This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous. #### Complex Aggregations #### -My personal favorite feature of Arel, and certainly the most difficult to implement, is closure under joining even in the presence of aggregations. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. +My personal favorite feature of Arel, certainly the most difficult to implement, and possibly only of marginal value, is **closure under joining even in the presence of aggregations**. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. Think of this as a preview of the kind of radical functionality that is to come, stuff no other "ORM" is doing. + +The easiest way to introduce this is in SQL. Your task is to get all users and the **count** of their associated photos. Let's start from the inside out: + SELECT count(*) + FROM photos + GROUP BY user_id + +Now, we'd like to join this with the user table. Naively, you might try to do this: + + SELECT users.*, count(photos.id) + FROM users + LEFT OUTER JOIN photos + ON users.id = photos.id + GROUP BY photos.user_id + +Of course, this has a slightly different meaning than our intended query. This is actually a fairly advanced topic in SQL so let's see why this doesn't work *step by step*. Suppose we have these records in our `users` table: + + mysql> select * from users; + +------+--------+ + | id | name | + +------+--------+ + | 1 | hai | + | 2 | bai | + | 3 | dumpty | + +------+--------+ + +And these in the photos table: + + mysql> select * from photos; + +------+---------+-----------+ + | id | user_id | camera_id | + +------+---------+-----------+ + | 1 | 1 | 1 | + | 2 | 1 | 1 | + | 3 | 1 | 1 | + +------+---------+-----------+ + +If we perform the above, incorrect query, we get the following: + + mysql> select users.*, count(photos.id) from users left outer join photos on users.id = photos.user_id limit 3 group by user_id; + +------+------+------------------+ + | id | name | count(photos.id) | + +------+------+------------------+ + | 2 | bai | 0 | + | 1 | hai | 3 | + +------+------+------------------+ + +As you can see, we're completely missing data for user with id 3. `dumpty` has no photos, neither does `bai`. But strangely `bai` appeared and `dumpty` didn't! The reason is that the `GROUP BY` clause is aggregating on both tables, not just the `photos` table. All users without photos have a `photos.id` of `null` (thanks to the left outer join). These are rolled up together and an arbitrary user wins. In this case, `bai` not `dumpty`. + + SELECT users.*, photos_aggregation.cnt + FROM users + LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation + ON photos_aggregation.user_id = users.id \ No newline at end of file diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index f21376d4c93a1..a83bad3c22b8a 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -3,11 +3,8 @@ class Predicate end class Binary < Predicate - attr_reader :operand1, :operand2 - - def initialize(operand1, operand2) - @operand1, @operand2 = operand1, operand2 - end + attributes :operand1, :operand2 + deriving :initialize def ==(other) self.class === other and diff --git a/lib/arel/relations/operations/group.rb b/lib/arel/relations/operations/group.rb index 22af2734a66b9..253c4215b6263 100644 --- a/lib/arel/relations/operations/group.rb +++ b/lib/arel/relations/operations/group.rb @@ -8,7 +8,7 @@ def initialize(relation, *groupings, &block) @groupings = (groupings + (block_given?? [yield(self)] : [])).collect { |g| g.bind(relation) } end - def aggregation? + def externalizable? true end end diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index 243a0289c7278..8025db095e470 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -39,8 +39,8 @@ def ons end # TESTME - def aggregation? - relation1.aggregation? or relation2.aggregation? + def externalizable? + relation1.externalizable? or relation2.externalizable? end def join? diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/relations/operations/project.rb index 2be87fe694687..c92a9df5a594b 100644 --- a/lib/arel/relations/operations/project.rb +++ b/lib/arel/relations/operations/project.rb @@ -12,8 +12,8 @@ def attributes @attributes ||= projections.collect { |p| p.bind(self) } end - def aggregation? - attributes.any?(&:aggregation?) + def externalizable? + attributes.any?(&:aggregation?) or relation.externalizable? end end end \ No newline at end of file diff --git a/lib/arel/relations/operations/skip.rb b/lib/arel/relations/operations/skip.rb index ea5df21f532ba..930e4c94ea372 100644 --- a/lib/arel/relations/operations/skip.rb +++ b/lib/arel/relations/operations/skip.rb @@ -2,5 +2,9 @@ module Arel class Skip < Compound attributes :relation, :skipped deriving :initialize, :== + + def externalizable? + true + end end end \ No newline at end of file diff --git a/lib/arel/relations/operations/take.rb b/lib/arel/relations/operations/take.rb index 095e4304175f7..2fd3fdf63537c 100644 --- a/lib/arel/relations/operations/take.rb +++ b/lib/arel/relations/operations/take.rb @@ -2,5 +2,9 @@ module Arel class Take < Compound attributes :relation, :taken deriving :initialize, :== + + def externalizable? + true + end end end \ No newline at end of file diff --git a/lib/arel/relations/utilities/aggregation.rb b/lib/arel/relations/utilities/aggregation.rb index 9f5ead8f86c85..bdc7650a200db 100644 --- a/lib/arel/relations/utilities/aggregation.rb +++ b/lib/arel/relations/utilities/aggregation.rb @@ -1,5 +1,5 @@ module Arel - class Aggregation < Compound + class Externalization < Compound attributes :relation deriving :initialize, :== include Recursion::BaseCase @@ -17,16 +17,16 @@ def attributes end def name - relation.name + '_aggregation' + relation.name + '_external' end end class Relation def externalize - @externalized ||= aggregation?? Aggregation.new(self) : self + @externalized ||= externalizable?? Externalization.new(self) : self end - def aggregation? + def externalizable? false end end diff --git a/lib/arel/relations/utilities/compound.rb b/lib/arel/relations/utilities/compound.rb index 23a55d4b5b064..a91cec112723f 100644 --- a/lib/arel/relations/utilities/compound.rb +++ b/lib/arel/relations/utilities/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation hash_on :relation - delegate :joins, :join?, :inserts, :taken, :skipped, :name, :aggregation?, + delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, :column_for, :engine, :table, :table_sql, :to => :relation diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index e72679c4d633f..318a299b8b9b4 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -8,7 +8,7 @@ def to_sql(formatter = nil) "DELETE", "FROM #{table_sql}", ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), ].compact.join("\n") end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 18b7ad9de1087..720b9d697d3ab 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -14,7 +14,7 @@ def to_sql(formatter = nil) "#{value.format(attribute)} = #{attribute.format(value)}" end.join(",\n"), ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) + ("LIMIT #{taken}" unless taken.blank? ) ].join("\n") end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 9e28237c3c779..d4298060942df 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -16,13 +16,22 @@ module Arel end describe '#to_sql' do + it '' do + @relation1.join(@relation2.take(3)).on(@predicate).to_sql.should be_like(" + SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` + FROM `users` + INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + ") + end + describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do @relation1.join(@aggregation).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` - ON `users`.`id` = `photos_aggregation`.`user_id` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` ") end end @@ -30,10 +39,10 @@ module Arel describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do @aggregation.join(@relation1).on(@predicate).to_sql.should be_like(" - SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` INNER JOIN `users` - ON `users`.`id` = `photos_aggregation`.`user_id` + ON `users`.`id` = `photos_external`.`user_id` ") end end @@ -42,10 +51,10 @@ module Arel it 'it properly aliases the aggregations' do aggregation2 = @aggregation.alias @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql.should be_like(" - SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `photos_aggregation_2`.`user_id`, `photos_aggregation_2`.`cnt` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_aggregation_2` - ON `photos_aggregation_2`.`user_id` = `photos_aggregation`.`user_id` + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` + ON `photos_external_2`.`user_id` = `photos_external`.`user_id` ") end end @@ -54,10 +63,10 @@ module Arel describe 'with the aggregation on the left' do it "manufactures sql keeping wheres on the aggregation within the derived table" do @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt` + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` - ON `users`.`id` = `photos_aggregation`.`user_id` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` ") end end @@ -65,10 +74,10 @@ module Arel describe 'with the aggregation on the right' do it "manufactures sql keeping wheres on the aggregation within the derived table" do @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" - SELECT `photos_aggregation`.`user_id`, `photos_aggregation`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_aggregation` + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` INNER JOIN `users` - ON `users`.`id` = `photos_aggregation`.`user_id` + ON `users`.`id` = `photos_external`.`user_id` ") end end diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/unit/relations/project_spec.rb index 2a4b690dd8a33..93cbe5668acdb 100644 --- a/spec/arel/unit/relations/project_spec.rb +++ b/spec/arel/unit/relations/project_spec.rb @@ -57,16 +57,16 @@ module Arel end end - describe '#aggregation?' do + describe '#externalizable?' do describe 'when the projections are attributes' do it 'returns false' do - Project.new(@relation, @attribute).should_not be_aggregation + Project.new(@relation, @attribute).should_not be_externalizable end end describe 'when the projections include an aggregation' do it "obtains" do - Project.new(@relation, @attribute.sum).should be_aggregation + Project.new(@relation, @attribute.sum).should be_externalizable end end end From 191b2b7b7e6e2cf4fc5a24321bc9b1e593f96551 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Wed, 21 May 2008 00:23:32 -0700 Subject: [PATCH 0194/1492] externalization now includes limits --- doc/TODO | 15 +++++++++++++++ lib/arel/primitives/attribute.rb | 2 +- lib/arel/relations/operations/group.rb | 2 +- lib/arel/relations/operations/join.rb | 1 + lib/arel/relations/operations/order.rb | 2 +- lib/arel/relations/operations/project.rb | 2 +- lib/arel/relations/operations/where.rb | 2 +- lib/arel/relations/relation.rb | 4 ++++ lib/arel/relations/utilities.rb | 2 +- .../{aggregation.rb => externalization.rb} | 1 + .../integration/joins/with_aggregations_spec.rb | 1 + 11 files changed, 28 insertions(+), 6 deletions(-) rename lib/arel/relations/utilities/{aggregation.rb => externalization.rb} (97%) diff --git a/doc/TODO b/doc/TODO index d7dd75d62e1f3..0f688bc258749 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,4 +1,19 @@ todo: +- joining with LIMIT is like aggregations!! + +users.delete().where( + addresses.c.user_id== + select([users.c.id]). + where(users.c.name=='jack') + ) + + SELECT id, name, + (select count(*) FROM addresses WHERE + user_id=users.id) + FROM users + + SELECT users.*, (SELECT count(id) FROM addresses WHERE + addresses.user_id=users.id) FROM users - and/or w/ predicates - blocks for all operations - result sets to attr correlation too diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index dffe24d1219da..30885dd129795 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -75,7 +75,7 @@ def original_attribute end def find_correlate_in(relation) - relation[self] + relation[self] || self end def descends_from?(other) diff --git a/lib/arel/relations/operations/group.rb b/lib/arel/relations/operations/group.rb index 253c4215b6263..04fd9fea629b1 100644 --- a/lib/arel/relations/operations/group.rb +++ b/lib/arel/relations/operations/group.rb @@ -5,7 +5,7 @@ class Group < Compound def initialize(relation, *groupings, &block) @relation = relation - @groupings = (groupings + (block_given?? [yield(self)] : [])).collect { |g| g.bind(relation) } + @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) } end def externalizable? diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index 8025db095e470..a72030abf995f 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -31,6 +31,7 @@ def attributes end def wheres + # TESTME bind to self? relation1.externalize.wheres end diff --git a/lib/arel/relations/operations/order.rb b/lib/arel/relations/operations/order.rb index 82924806e2c5f..05af3fde4d125 100644 --- a/lib/arel/relations/operations/order.rb +++ b/lib/arel/relations/operations/order.rb @@ -5,7 +5,7 @@ class Order < Compound def initialize(relation, *orderings, &block) @relation = relation - @orderings = (orderings + (block_given?? [yield(self)] : [])).collect { |o| o.bind(relation) } + @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) } end # TESTME diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/relations/operations/project.rb index c92a9df5a594b..d7835edda4cb5 100644 --- a/lib/arel/relations/operations/project.rb +++ b/lib/arel/relations/operations/project.rb @@ -5,7 +5,7 @@ class Project < Compound def initialize(relation, *projections, &block) @relation = relation - @projections = (projections + (block_given?? [yield(self)] : [])).collect { |p| p.bind(relation) } + @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } end def attributes diff --git a/lib/arel/relations/operations/where.rb b/lib/arel/relations/operations/where.rb index 9acb8ae3c6b51..8882f36104a53 100644 --- a/lib/arel/relations/operations/where.rb +++ b/lib/arel/relations/operations/where.rb @@ -4,7 +4,7 @@ class Where < Compound deriving :== def initialize(relation, *predicates, &block) - predicate = block_given?? yield(self) : predicates.shift + predicate = block_given?? yield(relation) : predicates.shift @relation = predicates.empty?? relation : Where.new(relation, *predicates) @predicate = predicate.bind(@relation) end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 1e2ac9f2be18a..a2d8bba6ea7ce 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -39,6 +39,10 @@ def bind(relation) self end + def root + self + end + def christener @christener ||= Sql::Christener.new end diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb index 02c2e0a952ce3..454d455359156 100644 --- a/lib/arel/relations/utilities.rb +++ b/lib/arel/relations/utilities.rb @@ -1,5 +1,5 @@ require 'arel/relations/utilities/compound' require 'arel/relations/utilities/recursion' require 'arel/relations/utilities/nil' -require 'arel/relations/utilities/aggregation' +require 'arel/relations/utilities/externalization' require 'arel/relations/utilities/recursion' \ No newline at end of file diff --git a/lib/arel/relations/utilities/aggregation.rb b/lib/arel/relations/utilities/externalization.rb similarity index 97% rename from lib/arel/relations/utilities/aggregation.rb rename to lib/arel/relations/utilities/externalization.rb index bdc7650a200db..4e9139a78abf1 100644 --- a/lib/arel/relations/utilities/aggregation.rb +++ b/lib/arel/relations/utilities/externalization.rb @@ -16,6 +16,7 @@ def attributes @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } end + # REMOVEME def name relation.name + '_external' end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index d4298060942df..42248add0738c 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -16,6 +16,7 @@ module Arel end describe '#to_sql' do + # CLEANUP it '' do @relation1.join(@relation2.take(3)).on(@predicate).to_sql.should be_like(" SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` From aeb09afd73cf188c6aee22bf4dd0f1beb937ac22 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 May 2008 21:56:38 -0400 Subject: [PATCH 0195/1492] AND/OR support for predicates --- doc/TODO | 2 +- lib/arel/predicates.rb | 21 +++++++++++++ spec/arel/unit/predicates/binary_spec.rb | 27 ++++++++++++++++ spec/arel/unit/predicates/predicates_spec.rb | 33 ++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 spec/arel/unit/predicates/predicates_spec.rb diff --git a/doc/TODO b/doc/TODO index 0f688bc258749..65f9cfbca7ee4 100644 --- a/doc/TODO +++ b/doc/TODO @@ -14,7 +14,6 @@ users.delete().where( SELECT users.*, (SELECT count(id) FROM addresses WHERE addresses.user_id=users.id) FROM users -- and/or w/ predicates - blocks for all operations - result sets to attr correlation too - cache expiry on write @@ -23,6 +22,7 @@ users.delete().where( - scoped writes done: +- and/or w/ predicates - mock out database . Relation <=> Relation -> InnerJoinOperation . Relation << Relation -> LeftOuterJoinOperation diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index a83bad3c22b8a..051f8abdada89 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -1,5 +1,12 @@ module Arel class Predicate + def or(other_predicate) + Or.new(self, other_predicate) + end + + def and(other_predicate) + And.new(self, other_predicate) + end end class Binary < Predicate @@ -21,6 +28,20 @@ def to_sql(formatter = nil) end alias_method :to_s, :to_sql end + + class CompoundPredicate < Binary + def to_sql(formatter = nil) + "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + end + end + + class Or < CompoundPredicate + def predicate_sql; "OR" end + end + + class And < CompoundPredicate + def predicate_sql; "AND" end + end class Equality < Binary def ==(other) diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index 5dee4833d4ca3..56fcf2d8ad5dc 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -13,6 +13,33 @@ def predicate_sql end end + describe "with compound predicates" do + before do + @operand1 = ConcreteBinary.new(@attribute1, 1) + @operand2 = ConcreteBinary.new(@attribute2, "name") + end + + describe Or do + describe "#to_sql" do + it "manufactures sql with an OR operation" do + Or.new(@operand1, @operand2).to_sql.should be_like(" + (`users`.`id` <=> 1 OR `users`.`name` <=> 'name') + ") + end + end + end + + describe And do + describe "#to_sql" do + it "manufactures sql with an AND operation" do + And.new(@operand1, @operand2).to_sql.should be_like(" + (`users`.`id` <=> 1 AND `users`.`name` <=> 'name') + ") + end + end + end + end + describe '#to_sql' do describe 'when relating two attributes' do it 'manufactures sql with a binary operation' do diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb new file mode 100644 index 0000000000000..d11637cabe94e --- /dev/null +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -0,0 +1,33 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module Arel + describe Predicate do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + @operand1 = Equality.new(@attribute1, 1) + @operand2 = Equality.new(@attribute2, "name") + end + + describe "when being combined with another predicate with AND logic" do + describe "#to_sql" do + it "manufactures sql with an AND operation" do + @operand1.and(@operand2).to_sql.should be_like(" + (`users`.`id` = 1 AND `users`.`name` = 'name') + ") + end + end + end + + describe "when being combined with another predicate with OR logic" do + describe "#to_sql" do + it "manufactures sql with an OR operation" do + @operand1.or(@operand2).to_sql.should be_like(" + (`users`.`id` = 1 OR `users`.`name` = 'name') + ") + end + end + end + end +end \ No newline at end of file From e2661658a083a229975110dcdd03e60068d8851e Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 May 2008 21:59:18 -0400 Subject: [PATCH 0196/1492] Update TODO --- doc/TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/TODO b/doc/TODO index 65f9cfbca7ee4..740e5db5fe4e5 100644 --- a/doc/TODO +++ b/doc/TODO @@ -20,6 +20,7 @@ users.delete().where( - rewrite of arecord querycache test in light of this - transactions - scoped writes +- asc/desc for orderings done: - and/or w/ predicates From cc80d8df045b1b24e725a40f17002c6c50df5f14 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 23 Apr 2009 11:02:39 -0300 Subject: [PATCH 0197/1492] Quoting must be required --- spec/doubles/database.rb | 10 ++++++---- spec/spec_helper.rb | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb index c28e9b1a0bc5f..3be11a91649ae 100644 --- a/spec/doubles/database.rb +++ b/spec/doubles/database.rb @@ -1,3 +1,5 @@ +require 'active_record/connection_adapters/abstract/quoting' + module Fake class Engine def connection @@ -7,7 +9,7 @@ def connection class Connection include ActiveRecord::ConnectionAdapters::Quoting - + def columns(table_name, comment) { "users" => [ @@ -26,7 +28,7 @@ def columns(table_name, comment) def execute(*args) [] end - + def quote_column_name(column_name) "`#{column_name}`" end @@ -38,10 +40,10 @@ def quote_table_name(table_name) class Column attr_reader :name, :type - + def initialize(name, type) @name = name @type = type end end -end \ No newline at end of file +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index eb87e2448cf76..ce539b6ffa95f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,10 +11,10 @@ Dir["#{dir}/#{helper}/*"].each { |m| require "#{dir}/#{helper}/#{File.basename(m)}" } end -Spec::Runner.configure do |config| +Spec::Runner.configure do |config| config.include(BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher) config.mock_with :rr config.before do Arel::Table.engine = Arel::Engine.new(Fake::Engine.new) end -end \ No newline at end of file +end From b29268d5b64bbd7383bfcebc6fcc5e97a657885b Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 23 Apr 2009 11:52:48 -0300 Subject: [PATCH 0198/1492] Moved require to initializer --- lib/arel.rb | 3 ++- spec/arel/unit/relations/insert_spec.rb | 22 +++++++++++----------- spec/doubles/database.rb | 2 -- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index f56005c2ed4cb..00bfa1e2925c0 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -3,6 +3,7 @@ require 'rubygems' require 'activesupport' require 'activerecord' +require 'active_record/connection_adapters/abstract/quoting' require 'arel/arel' require 'arel/extensions' @@ -11,4 +12,4 @@ require 'arel/relations' require 'arel/engine' require 'arel/session' -require 'arel/primitives' \ No newline at end of file +require 'arel/primitives' diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb index b983e545a4b4c..4ef51fef9dcab 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -5,34 +5,34 @@ module Arel before do @relation = Table.new(:users) end - + describe '#to_sql' do it 'manufactures sql inserting data when given multiple rows' do pending 'it should insert multiple rows' @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) - + @insertion.to_sql.should be_like(" INSERT INTO `users` (`users`.`name`) VALUES ('nick'), ('bryan') ") end - + it 'manufactures sql inserting data when given multiple values' do @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") - + @insertion.to_sql.should be_like(" INSERT INTO `users` (`users`.`id`, `users`.`name`) VALUES (1, 'nick') ") end - + describe 'when given values whose types correspond to the types of the attributes' do before do @insertion = Insert.new(@relation, @relation[:name] => "nick") end - + it 'manufactures sql inserting data' do @insertion.to_sql.should be_like(" INSERT @@ -41,12 +41,12 @@ module Arel ") end end - + describe 'when given values whose types differ from from the types of the attributes' do before do @insertion = Insert.new(@relation, @relation[:id] => '1-asdf') end - + it 'manufactures sql inserting data' do @insertion.to_sql.should be_like(" INSERT @@ -56,16 +56,16 @@ module Arel end end end - + describe '#call' do before do @insertion = Insert.new(@relation, @relation[:name] => "nick") end - + it 'executes an insert on the connection' do mock(connection = Object.new).insert(@insertion.to_sql) @insertion.call(connection) end end end -end \ No newline at end of file +end diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb index 3be11a91649ae..7670958d7a165 100644 --- a/spec/doubles/database.rb +++ b/spec/doubles/database.rb @@ -1,5 +1,3 @@ -require 'active_record/connection_adapters/abstract/quoting' - module Fake class Engine def connection From 7978b69948c4fe38911932766d45026467f45e52 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 23 Apr 2009 13:01:18 -0300 Subject: [PATCH 0199/1492] Use the engine not the engine.connection, the engine may not even respond to connection --- lib/arel/arel.rb | 4 ++-- lib/arel/relations/table.rb | 12 +++++----- lib/arel/session.rb | 22 +++++++++--------- spec/arel/unit/session/session_spec.rb | 32 +++++++++++++------------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/arel/arel.rb b/lib/arel/arel.rb index 892be854ee9a0..7780d45e25d1b 100644 --- a/lib/arel/arel.rb +++ b/lib/arel/arel.rb @@ -1,3 +1,3 @@ -def Arel(name, engine = Arel::Table.engine) +def Arel(name, engine = (Arel::Table.engine || ActiveRecord::Base.connection)) Arel::Table.new(name, engine) -end \ No newline at end of file +end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb index 087028fb55965..0433abbbb24fb 100644 --- a/lib/arel/relations/table.rb +++ b/lib/arel/relations/table.rb @@ -3,9 +3,9 @@ class Table < Relation include Recursion::BaseCase cattr_accessor :engine - attr_reader :name, :engine + attr_reader :name, :engine hash_on :name - + def initialize(name, engine = Table.engine) @name, @engine = name.to_s, engine end @@ -19,18 +19,18 @@ def attributes def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end - + def columns @columns ||= engine.columns(name, "#{name} Columns") end - + def reset @attributes = @columns = nil end - + def ==(other) Table === other and name == other.name end end -end \ No newline at end of file +end diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 8b72fd1fe69d6..d9a6e4b5e4a48 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -1,11 +1,11 @@ require 'singleton' module Arel - class Session + class Session class << self attr_accessor :instance alias_method :manufacture, :new - + def start if @started yield @@ -22,26 +22,26 @@ def start end end end - + module CRUD def create(insert) - insert.call(insert.engine.connection) + insert.call(insert.engine) end - + def read(select) (@read ||= Hash.new do |hash, select| - hash[select] = select.call(select.engine.connection) + hash[select] = select.call(select.engine) end)[select] end - + def update(update) - update.call(update.engine.connection) + update.call(update.engine) end - + def delete(delete) - delete.call(delete.engine.connection) + delete.call(delete.engine) end end include CRUD end -end \ No newline at end of file +end diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb index 7582aa35e1159..6e73d74f2d6ec 100644 --- a/spec/arel/unit/session/session_spec.rb +++ b/spec/arel/unit/session/session_spec.rb @@ -6,7 +6,7 @@ module Arel @relation = Table.new(:users) @session = Session.new end - + describe '::start' do describe '::instance' do it "it is a singleton within the started session" do @@ -23,13 +23,13 @@ module Arel end end end - + it "manufactures new sessions outside of the started session" do Session.new.should_not == Session.new end end end - + describe Session::CRUD do before do @insert = Insert.new(@relation, @relation[:name] => 'nick') @@ -37,48 +37,48 @@ module Arel @delete = Deletion.new(@relation) @read = @relation end - + describe '#create' do it "executes an insertion on the connection" do - mock(@insert).call(@insert.engine.connection) + mock(@insert).call(@insert.engine) @session.create(@insert) end end - + describe '#read' do it "executes an selection on the connection" do - mock(@read).call(@read.engine.connection) + mock(@read).call(@read.engine) @session.read(@read) end - + it "is memoized" do - mock(@read).call(@read.engine.connection).once + mock(@read).call(@read.engine).once @session.read(@read) @session.read(@read) end end - + describe '#update' do it "executes an update on the connection" do - mock(@update).call(@update.engine.connection) + mock(@update).call(@update.engine) @session.update(@update) end end - + describe '#delete' do it "executes a delete on the connection" do - mock(@delete).call(@delete.engine.connection) + mock(@delete).call(@delete.engine) @session.delete(@delete) end end end - + describe 'Transactions' do describe '#begin' do end - + describe '#end' do end end end -end \ No newline at end of file +end From 318cf575eb2b7cf42cb133b3f24cd1aa5fa5e155 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 23 Apr 2009 13:51:10 -0300 Subject: [PATCH 0200/1492] Required singleton --- lib/arel/relations/utilities/nil.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/relations/utilities/nil.rb index 2b8dc570f844d..56cf395d2c473 100644 --- a/lib/arel/relations/utilities/nil.rb +++ b/lib/arel/relations/utilities/nil.rb @@ -1,8 +1,10 @@ +require 'singleton' + module Arel class Nil < Relation include Singleton - + def table_sql(formatter = nil); '' end def name; '' end end -end \ No newline at end of file +end From a454d45403cd0b8a24b05b7ff37021e307905825 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 23 Apr 2009 18:53:03 -0300 Subject: [PATCH 0201/1492] Fix insertion to work on SQLite3 --- lib/arel/extensions/object.rb | 12 +++---- lib/arel/predicates.rb | 16 ++++----- lib/arel/primitives/attribute.rb | 42 +++++++++++----------- lib/arel/primitives/expression.rb | 14 ++++---- lib/arel/relations/operations/where.rb | 2 +- lib/arel/relations/relation.rb | 40 +++++++++++---------- lib/arel/relations/writes/insert.rb | 10 +++--- lib/arel/sql/formatters.rb | 46 ++++++++++++------------- spec/arel/unit/relations/insert_spec.rb | 8 ++--- 9 files changed, 97 insertions(+), 93 deletions(-) diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index ea73c336dc31d..14e2f82ce52d1 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -1,23 +1,23 @@ -class Object +class Object def bind(relation) Arel::Value.new(self, relation) end - + def find_correlate_in(relation) bind(relation) end - + def to_sql(formatter) formatter.scalar self end - + def equality_predicate_sql '=' end - + def metaclass class << self self end end -end \ No newline at end of file +end diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index 051f8abdada89..b639022b4e1f3 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -3,7 +3,7 @@ class Predicate def or(other_predicate) Or.new(self, other_predicate) end - + def and(other_predicate) And.new(self, other_predicate) end @@ -18,27 +18,27 @@ def ==(other) @operand1 == other.operand1 and @operand2 == other.operand2 end - + def bind(relation) self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end - + def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end alias_method :to_s, :to_sql end - + class CompoundPredicate < Binary def to_sql(formatter = nil) "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" end end - + class Or < CompoundPredicate def predicate_sql; "OR" end end - + class And < CompoundPredicate def predicate_sql; "AND" end end @@ -74,8 +74,8 @@ def predicate_sql; '<' end class Match < Binary def predicate_sql; 'LIKE' end end - + class In < Binary def predicate_sql; operand2.inclusion_predicate_sql end end -end \ No newline at end of file +end diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 30885dd129795..7021e9f9ed1f9 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -9,11 +9,11 @@ class Attribute def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end - + def named?(hypothetical_name) (@alias || name).to_s == hypothetical_name.to_s end - + def aggregation? false end @@ -21,7 +21,7 @@ def aggregation? def column original_relation.column_for(self) end - + def format(object) object.to_sql(Sql::Attribute.new(self)) end @@ -30,19 +30,19 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.attribute self end - module Transformations + module Transformations def self.included(klass) klass.send :alias_method, :eql?, :== end - + def hash @hash ||= history.size + name.hash + relation.hash end - + def as(aliaz = nil) Attribute.new(relation, name, :alias => aliaz, :ancestor => self) end - + def bind(new_relation) relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) end @@ -52,20 +52,20 @@ def to_attribute end end include Transformations - + module Congruence def history @history ||= [self] + (ancestor ? ancestor.history : []) end - + def join? relation.join? end - + def root history.last end - + def original_relation @original_relation ||= original_attribute.relation end @@ -77,17 +77,17 @@ def original_attribute def find_correlate_in(relation) relation[self] || self end - + def descends_from?(other) history.include?(other) end - + def /(other) other ? (history & other.history).size : 0 end end include Congruence - + module Predications def eq(other) Equality.new(self, other) @@ -112,34 +112,34 @@ def gteq(other) def matches(regexp) Match.new(self, regexp) end - + def in(array) In.new(self, array) end end include Predications - + module Expressions def count Expression.new(self, "COUNT") end - + def sum Expression.new(self, "SUM") end - + def maximum Expression.new(self, "MAX") end - + def minimum Expression.new(self, "MIN") end - + def average Expression.new(self, "AVG") end end include Expressions end -end \ No newline at end of file +end diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 26186ccad8b0f..836f0147456ae 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -4,32 +4,32 @@ class Expression < Attribute deriving :== delegate :relation, :to => :attribute alias_method :name, :alias - + def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor end - + def to_sql(formatter = Sql::SelectClause.new(relation)) formatter.expression self end - + def aggregation? true end - + module Transformations def as(aliaz) Expression.new(attribute, function_sql, aliaz, self) end - + def bind(new_relation) new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) end - + def to_attribute Attribute.new(relation, @alias, :ancestor => self) end end include Transformations end -end \ No newline at end of file +end diff --git a/lib/arel/relations/operations/where.rb b/lib/arel/relations/operations/where.rb index 8882f36104a53..608aaeb4b7f7f 100644 --- a/lib/arel/relations/operations/where.rb +++ b/lib/arel/relations/operations/where.rb @@ -13,4 +13,4 @@ def wheres @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } end end -end \ No newline at end of file +end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index a2d8bba6ea7ce..d9ba9a108bf2b 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -3,12 +3,16 @@ class Relation def session Session.new end - + + def select_values + engine.select_values self.to_sql + end + def to_sql(formatter = Sql::SelectStatement.new(self)) formatter.select select_sql, self end alias_method :to_s, :to_sql - + def select_sql [ "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", @@ -21,12 +25,12 @@ def select_sql ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n") end - + def inclusion_predicate_sql "IN" end - - def call(connection = engine.connection) + + def call(connection = engine) results = connection.execute(to_sql) rows = [] results.each do |row| @@ -34,19 +38,19 @@ def call(connection = engine.connection) end rows end - + def bind(relation) self end - + def root self end - + def christener @christener ||= Sql::Christener.new end - + module Enumerable include ::Enumerable @@ -75,7 +79,7 @@ def join(other_relation = nil, join_type = "INNER JOIN") def outer_join(other_relation = nil) join(other_relation, "LEFT OUTER JOIN") end - + [:where, :project, :order, :take, :skip, :group].each do |operation_name| operation = <<-OPERATION def #{operation_name}(*arguments, &block) @@ -88,7 +92,7 @@ def #{operation_name}(*arguments, &block) def alias Alias.new(self) end - + module Writable def insert(record) session.create Insert.new(self, record); self @@ -103,7 +107,7 @@ def delete end end include Writable - + JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do def on(*predicates) Join.new(join_sql, relation1, relation2, *predicates) @@ -111,7 +115,7 @@ def on(*predicates) end end include Operable - + module AttributeAccessable def [](index) case index @@ -123,17 +127,17 @@ def [](index) index.collect { |i| self[i] } end end - + def find_attribute_matching_name(name) attributes.detect { |a| a.named?(name) } end - + def find_attribute_matching_attribute(attribute) matching_attributes(attribute).max do |a1, a2| (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) end end - + private def matching_attributes(attribute) (@matching_attributes ||= attributes.inject({}) do |hash, a| @@ -141,7 +145,7 @@ def matching_attributes(attribute) hash end)[attribute.root] || [] end - + def has_attribute?(attribute) !matching_attributes(attribute).empty? end @@ -160,4 +164,4 @@ def skipped; nil end end include DefaultOperations end -end \ No newline at end of file +end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb index 0545d7faa3a07..d579ad06d0bf5 100644 --- a/lib/arel/relations/writes/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -11,13 +11,13 @@ def to_sql(formatter = nil) [ "INSERT", "INTO #{table_sql}", - "(#{record.keys.collect(&:to_sql).join(', ')})", - "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + "(#{record.keys.map { |key| engine.quote_column_name(key.name) }.join(', ')})", + "VALUES (#{record.map { |key, value| key.format(value) }.join(', ')})" ].join("\n") end - - def call(connection = engine.connection) + + def call(connection = engine) connection.insert(to_sql) end end -end \ No newline at end of file +end diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index 068fb8d22d156..22a116117e4c8 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -5,104 +5,104 @@ class Formatter delegate :christener, :engine, :to => :environment delegate :name_for, :to => :christener delegate :quote_table_name, :quote_column_name, :quote, :to => :engine - + def initialize(environment) @environment = environment end end - + class SelectClause < Formatter def attribute(attribute) "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") end - + def expression(expression) "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') end - + def select(select_sql, table) "(#{select_sql}) AS #{quote_table_name(name_for(table))}" end - + def value(value) value end end - + class PassThrough < Formatter def value(value) value end end - + class WhereClause < PassThrough end - - class OrderClause < PassThrough + + class OrderClause < PassThrough def attribute(attribute) "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" end end - + class GroupClause < PassThrough def attribute(attribute) "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" end end - + class WhereCondition < Formatter def attribute(attribute) "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" end - + def expression(expression) "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" end - + def value(value) value.to_sql(self) end - + def scalar(value, column = nil) quote(value, column) end - + def select(select_sql, table) "(#{select_sql})" end end - + class SelectStatement < Formatter def select(select_sql, table) select_sql end end - + class TableReference < Formatter def select(select_sql, table) "(#{select_sql}) AS #{quote_table_name(name_for(table))}" end - + def table(table) quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') end end - + class Attribute < WhereCondition def scalar(scalar) quote(scalar, environment.column) end - + def array(array) "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" end - + def range(left, right) "#{left} AND #{right}" end end - + class Value < WhereCondition end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb index 4ef51fef9dcab..441c97b290463 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -14,7 +14,7 @@ module Arel @insertion.to_sql.should be_like(" INSERT INTO `users` - (`users`.`name`) VALUES ('nick'), ('bryan') + (`name`) VALUES ('nick'), ('bryan') ") end @@ -24,7 +24,7 @@ module Arel @insertion.to_sql.should be_like(" INSERT INTO `users` - (`users`.`id`, `users`.`name`) VALUES (1, 'nick') + (`id`, `name`) VALUES (1, 'nick') ") end @@ -37,7 +37,7 @@ module Arel @insertion.to_sql.should be_like(" INSERT INTO `users` - (`users`.`name`) VALUES ('nick') + (`name`) VALUES ('nick') ") end end @@ -51,7 +51,7 @@ module Arel @insertion.to_sql.should be_like(" INSERT INTO `users` - (`users`.`id`) VALUES (1) + (`id`) VALUES (1) ") end end From 1b1fc880bf7129a422901417bd6b9fede292aa7e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 24 Apr 2009 17:10:52 -0300 Subject: [PATCH 0202/1492] Removed table quotings to be SQLite3 compliant. Delete and update will returrn the size of modified records to prevent addional queries to be done. --- lib/arel/engine.rb | 6 +-- lib/arel/primitives/value.rb | 8 ++-- lib/arel/relations/relation.rb | 4 +- lib/arel/relations/writes/delete.rb | 6 +-- lib/arel/relations/writes/update.rb | 12 ++--- spec/arel/unit/relations/relation_spec.rb | 57 ++++++++--------------- spec/arel/unit/relations/update_spec.rb | 32 ++++++------- 7 files changed, 53 insertions(+), 72 deletions(-) diff --git a/lib/arel/engine.rb b/lib/arel/engine.rb index b0b7b4e95501f..5a5ef0687879c 100644 --- a/lib/arel/engine.rb +++ b/lib/arel/engine.rb @@ -6,13 +6,13 @@ class Engine def initialize(ar = nil) @ar = ar end - + def connection @ar.connection end - + def method_missing(method, *args, &block) @ar.connection.send(method, *args, &block) end end -end \ No newline at end of file +end diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 809af7c206253..74baa06e5b48b 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -3,8 +3,8 @@ class Value attributes :value, :relation deriving :initialize, :== delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value - - + + def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value end @@ -12,9 +12,9 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) def format(object) object.to_sql(Sql::Value.new(relation)) end - + def bind(relation) Value.new(value, relation) end end -end \ No newline at end of file +end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index d9ba9a108bf2b..50110c7416eb7 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -99,11 +99,11 @@ def insert(record) end def update(assignments) - session.update Update.new(self, assignments); self + session.update Update.new(self, assignments) end def delete - session.delete Deletion.new(self); self + session.delete Deletion.new(self) end end include Writable diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index 318a299b8b9b4..b1ff3bef278ba 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -11,9 +11,9 @@ def to_sql(formatter = nil) ("LIMIT #{taken}" unless taken.blank? ), ].compact.join("\n") end - - def call(connection = engine.connection) + + def call(connection = engine) connection.delete(to_sql) end end -end \ No newline at end of file +end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 720b9d697d3ab..3b43152ad69a2 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -2,7 +2,7 @@ module Arel class Update < Compound attributes :relation, :assignments deriving :== - + def initialize(relation, assignments) @relation, @assignments = relation, assignments.bind(relation) end @@ -11,15 +11,15 @@ def to_sql(formatter = nil) [ "UPDATE #{table_sql} SET", assignments.collect do |attribute, value| - "#{value.format(attribute)} = #{attribute.format(value)}" + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" end.join(",\n"), - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("WHERE #{wheres.map(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), ("LIMIT #{taken}" unless taken.blank? ) ].join("\n") end - - def call(connection = engine.connection) + + def call(connection = engine) connection.update(to_sql) end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index 77a787b840e0c..a3bfa673538ef 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -7,14 +7,14 @@ module Arel @attribute1 = @relation[:id] @attribute2 = @relation[:name] end - + describe '[]' do describe 'when given an', Attribute do it "return the attribute congruent to the provided attribute" do @relation[@attribute1].should == @attribute1 end end - + describe 'when given a', Symbol, String do it "returns the attribute with the same name, if it exists" do @relation[:id].should == @attribute1 @@ -23,13 +23,13 @@ module Arel end end end - + describe Relation::Operable do describe 'joins' do before do @predicate = @relation[:id].eq(@relation[:id]) end - + describe '#join' do describe 'when given a relation' do it "manufactures an inner join operation between those two relations" do @@ -37,13 +37,13 @@ module Arel should == Join.new("INNER JOIN", @relation, @relation, @predicate) end end - + describe "when given a string" do it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) end end - + describe "when given something blank" do it "returns self" do @relation.join.should == @relation @@ -64,7 +64,7 @@ module Arel @relation.project(@attribute1, @attribute2). \ should == Project.new(@relation, @attribute1, @attribute2) end - + describe "when given blank attributes" do it "returns self" do @relation.project.should == @relation @@ -97,36 +97,36 @@ module Arel end end end - + describe '#order' do it "manufactures an order relation" do @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) end - + describe 'when given a blank ordering' do it 'returns self' do @relation.order.should == @relation end end end - + describe '#take' do it "manufactures a take relation" do @relation.take(5).should == Take.new(@relation, 5) end - + describe 'when given a blank number of items' do it 'returns self' do @relation.take.should == @relation end end end - + describe '#skip' do it "manufactures a skip relation" do @relation.skip(4).should == Skip.new(@relation, 4) end - + describe 'when given a blank number of items' do it 'returns self' do @relation.skip.should == @relation @@ -138,24 +138,15 @@ module Arel it 'manufactures a group relation' do @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) end - + describe 'when given blank groupings' do it 'returns self' do @relation.group.should == @relation end end end - - describe Relation::Operable::Writable do - describe '#delete' do - it 'manufactures a deletion relation' do - Session.start do - mock(Session.new).delete(Deletion.new(@relation)) - @relation.delete.should == @relation - end - end - end + describe Relation::Operable::Writable do describe '#insert' do it 'manufactures an insertion relation' do Session.start do @@ -165,26 +156,16 @@ module Arel end end end - - describe '#update' do - it 'manufactures an update relation' do - Session.start do - assignments = {@relation[:name] => Value.new('bob', @relation)} - mock(Session.new).update(Update.new(@relation, assignments)) - @relation.update(assignments).should == @relation - end - end - end end end - + describe Relation::Enumerable do it "implements enumerable" do @relation.collect.should == @relation.session.read(@relation) @relation.first.should == @relation.session.read(@relation).first end end - + describe '#call' do it 'executes a select_all on the connection' do mock(connection = Object.new).execute(@relation.to_sql) { [] } @@ -192,4 +173,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index 08c6da7901ef3..b67369251f5ac 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -5,32 +5,32 @@ module Arel before do @relation = Table.new(:users) end - + describe '#to_sql' do it "manufactures sql updating attributes when given multiple attributes" do Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` - SET `users`.`id` = 1, `users`.`name` = 'nick' + SET `id` = 1, `name` = 'nick' ") end - + it "manufactures sql updating attributes when given a ranged relation" do Update.new(@relation.take(1), @relation[:name] => "nick").to_sql.should be_like(" UPDATE `users` - SET `users`.`name` = 'nick' + SET `name` = 'nick' LIMIT 1 ") end - + describe 'when given values whose types correspond to the types of the attributes' do before do @update = Update.new(@relation, @relation[:name] => "nick") end - + it 'manufactures sql updating attributes' do @update.to_sql.should be_like(" UPDATE `users` - SET `users`.`name` = 'nick' + SET `name` = 'nick' ") end end @@ -39,15 +39,15 @@ module Arel before do @update = Update.new(@relation, @relation[:id] => '1-asdf') end - + it 'manufactures sql updating attributes' do @update.to_sql.should be_like(" UPDATE `users` - SET `users`.`id` = 1 + SET `id` = 1 ") end end - + describe 'when the relation is a where' do before do @update = Update.new( @@ -55,27 +55,27 @@ module Arel @relation[:name] => "nick" ) end - + it 'manufactures sql updating a where relation' do @update.to_sql.should be_like(" UPDATE `users` - SET `users`.`name` = 'nick' + SET `name` = 'nick' WHERE `users`.`id` = 1 ") end end end - + describe '#call' do before do @update = Update.new(@relation, @relation[:name] => "nick") end - + it 'executes an update on the connection' do mock(connection = Object.new).update(@update.to_sql) @update.call(connection) end end - + end -end \ No newline at end of file +end From 45646ec54c4c4a3c7340b79deea9e3cf76554f0b Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 24 Apr 2009 21:48:00 -0300 Subject: [PATCH 0203/1492] Added aggregation and to_attribute methods to Value --- lib/arel/primitives/value.rb | 8 ++++++++ lib/arel/relations/operations/join.rb | 16 ++++++++-------- lib/arel/relations/utilities/externalization.rb | 12 ++++++------ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 74baa06e5b48b..36a7fb7c71462 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -16,5 +16,13 @@ def format(object) def bind(relation) Value.new(value, relation) end + + def aggregation? + false + end + + def to_attribute + value + end end end diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index a72030abf995f..8fe89358d84f2 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -8,11 +8,11 @@ class Join < Relation def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end - + def table_sql(formatter = Sql::TableReference.new(self)) relation1.externalize.table_sql(formatter) end - + def joins(environment, formatter = Sql::TableReference.new(environment)) @joins ||= begin this_join = [ @@ -29,29 +29,29 @@ def attributes @attributes ||= (relation1.externalize.attributes + relation2.externalize.attributes).collect { |a| a.bind(self) } end - + def wheres # TESTME bind to self? relation1.externalize.wheres end - + def ons @ons ||= @predicates.collect { |p| p.bind(self) } end - + # TESTME def externalizable? relation1.externalizable? or relation2.externalizable? end - + def join? true end end - + class Relation def join? false end end -end \ No newline at end of file +end diff --git a/lib/arel/relations/utilities/externalization.rb b/lib/arel/relations/utilities/externalization.rb index 4e9139a78abf1..3b9b2296dc2c2 100644 --- a/lib/arel/relations/utilities/externalization.rb +++ b/lib/arel/relations/utilities/externalization.rb @@ -7,28 +7,28 @@ class Externalization < Compound def wheres [] end - + def table_sql(formatter = Sql::TableReference.new(relation)) formatter.select relation.select_sql, self end - + def attributes @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } end - + # REMOVEME def name relation.name + '_external' end end - + class Relation def externalize @externalized ||= externalizable?? Externalization.new(self) : self end - + def externalizable? false end end -end \ No newline at end of file +end From 1dfae3a5a01b05bf14de88958b625b865748387b Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 28 Apr 2009 18:51:15 -0300 Subject: [PATCH 0204/1492] ORDER BY should be included after GROUP BY clause --- lib/arel/relations/relation.rb | 6 +++++- lib/arel/relations/utilities/compound.rb | 4 ++-- spec/arel/unit/relations/alias_spec.rb | 8 ++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 50110c7416eb7..986bc3fbebde9 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -4,6 +4,10 @@ def session Session.new end + def select_value + engine.select_value self.to_sql + end + def select_values engine.select_values self.to_sql end @@ -19,8 +23,8 @@ def select_sql "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), - ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), + ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n") diff --git a/lib/arel/relations/utilities/compound.rb b/lib/arel/relations/utilities/compound.rb index a91cec112723f..b1e8054d4d496 100644 --- a/lib/arel/relations/utilities/compound.rb +++ b/lib/arel/relations/utilities/compound.rb @@ -5,7 +5,7 @@ class Compound < Relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, :column_for, :engine, :table, :table_sql, :to => :relation - + [:attributes, :wheres, :groupings, :orders].each do |operation_name| operation = <<-OPERATION def #{operation_name} @@ -15,4 +15,4 @@ def #{operation_name} class_eval operation, __FILE__, __LINE__ end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 5327154fa8370..460a0ed0df20a 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -5,14 +5,14 @@ module Arel before do @relation = Table.new(:users) end - + describe '==' do it "obtains if the objects are the same" do Alias.new(@relation).should_not == Alias.new(@relation) (aliaz = Alias.new(@relation)).should == aliaz end end - + describe '#to_sql' do describe 'when there is no ambiguity' do it 'does not alias table names anywhere a table name can appear' do @@ -26,11 +26,11 @@ module Arel SELECT `users`.`id` FROM `users` WHERE `users`.`id` = 1 - ORDER BY `users`.`id` GROUP BY `users`.`id` + ORDER BY `users`.`id` ") end end end end -end \ No newline at end of file +end From 5e4bfb1ce4144785feaeffc6210740e3e4ce5770 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 28 Apr 2009 19:51:00 -0300 Subject: [PATCH 0205/1492] Workaround so quote_table_name is not included when not using a column name. For example: project('2 * amount') --- lib/arel/sql/formatters.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index 22a116117e4c8..f105fbea72a73 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -13,7 +13,12 @@ def initialize(environment) class SelectClause < Formatter def attribute(attribute) + # FIXME this should check that the column exists + if attribute.name.to_s =~ /^\w*$/ "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") + else + attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") + end end def expression(expression) From b4b73d9520a2ff27021b530ccd3dcd96973ce5fe Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 29 Apr 2009 19:38:39 -0300 Subject: [PATCH 0206/1492] Added DISTINCT support. Modified when to quote or not columns and tables. --- lib/arel/primitives/attribute.rb | 4 +-- lib/arel/primitives/value.rb | 6 ++++- lib/arel/relations/relation.rb | 9 ++++++- lib/arel/sql/formatters.rb | 14 +++++++--- spec/arel/unit/primitives/expression_spec.rb | 14 +++++----- spec/arel/unit/relations/project_spec.rb | 27 ++++++++++++-------- spec/doubles/database.rb | 4 +++ 7 files changed, 54 insertions(+), 24 deletions(-) diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 7021e9f9ed1f9..6cb558d8ce342 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -120,8 +120,8 @@ def in(array) include Predications module Expressions - def count - Expression.new(self, "COUNT") + def count(distinct = false) + distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT") end def sum diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 36a7fb7c71462..9c6e518a95764 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -6,7 +6,11 @@ class Value def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.value value + if value =~ /^\(.*\)$/ + value + else + formatter.value value + end end def format(object) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 986bc3fbebde9..50c46aa2ed257 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -1,5 +1,7 @@ module Arel class Relation + attr_reader :count + def session Session.new end @@ -12,6 +14,11 @@ def select_values engine.select_values self.to_sql end + def count + @count = "COUNT(*) AS count_all" + engine.select_value self.to_sql + end + def to_sql(formatter = Sql::SelectStatement.new(self)) formatter.select select_sql, self end @@ -19,7 +26,7 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) def select_sql [ - "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "SELECT #{@count} #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ') unless @count}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index f105fbea72a73..aa10952d04924 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -15,14 +15,18 @@ class SelectClause < Formatter def attribute(attribute) # FIXME this should check that the column exists if attribute.name.to_s =~ /^\w*$/ - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") else attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") end end def expression(expression) - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + if expression.function_sql == "DISTINCT" + "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + else + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + end end def select(select_sql, table) @@ -89,7 +93,11 @@ def select(select_sql, table) end def table(table) - quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') + if table.name =~ /^(\w|-)*$/ + quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') + else + table.name + (table.name != name_for(table) ? " AS " + (name_for(table)) : '') + end end end diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index d398805fe2642..4943f4ef33046 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -6,40 +6,40 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Expression::Transformations do before do @expression = Expression.new(@attribute, "COUNT") end - + describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) end - + it "returns self if the substituting to the same relation" do @expression.bind(@relation).should == @expression end end - + describe '#as' do it "manufactures an aliased expression" do @expression.as(:alias).should == Expression.new(@attribute, "COUNT", :alias, @expression) end end - + describe '#to_attribute' do it "manufactures an attribute with the expression as an ancestor" do @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) end end end - + describe '#to_sql' do it "manufactures sql with the expression and alias" do Expression.new(@attribute, "COUNT", :alias).to_sql.should == "COUNT(`users`.`id`) AS `alias`" end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/unit/relations/project_spec.rb index 93cbe5668acdb..7f531096f07d3 100644 --- a/spec/arel/unit/relations/project_spec.rb +++ b/spec/arel/unit/relations/project_spec.rb @@ -6,17 +6,17 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe '#attributes' do before do @projection = Project.new(@relation, @attribute) end - + it "manufactures attributes associated with the projection relation" do @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } end end - + describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do @@ -26,19 +26,19 @@ module Arel ") end end - + describe 'when given a relation' do before do @scalar_relation = Project.new(@relation, @relation[:name]) end - + it "manufactures sql with scalar selects" do Project.new(@relation, @scalar_relation).to_sql.should be_like(" SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` ") end end - + describe 'when given a string' do it "passes the string through to the select clause" do Project.new(@relation, 'asdf').to_sql.should be_like(" @@ -46,7 +46,7 @@ module Arel ") end end - + describe 'when given an expression' do it 'manufactures sql with expressions' do @relation.project(@attribute.count).to_sql.should be_like(" @@ -54,16 +54,23 @@ module Arel FROM `users` ") end + + it 'manufactures sql with distinct expressions' do + @relation.project(@attribute.count(true)).to_sql.should be_like(" + SELECT COUNT(DISTINCT `users`.`id`) + FROM `users` + ") + end end end - + describe '#externalizable?' do describe 'when the projections are attributes' do it 'returns false' do Project.new(@relation, @attribute).should_not be_externalizable end end - + describe 'when the projections include an aggregation' do it "obtains" do Project.new(@relation, @attribute.sum).should be_externalizable @@ -71,4 +78,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb index 7670958d7a165..f8a4b38e178ef 100644 --- a/spec/doubles/database.rb +++ b/spec/doubles/database.rb @@ -34,6 +34,10 @@ def quote_column_name(column_name) def quote_table_name(table_name) "`#{table_name}`" end + + def supports_count_distinct? + true + end end class Column From 092c2be685e8e359c161144ce58addac6caa5c44 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 30 Apr 2009 13:18:32 -0300 Subject: [PATCH 0207/1492] Don't bind, just assign. --- lib/arel/relations/writes/update.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 3b43152ad69a2..2e90de3a52fda 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -4,7 +4,7 @@ class Update < Compound deriving :== def initialize(relation, assignments) - @relation, @assignments = relation, assignments.bind(relation) + @relation, @assignments = relation, assignments end def to_sql(formatter = nil) From f44853a5aa7f4481d99a3af4585f3a51272bc7f7 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 2 May 2009 03:14:31 -0300 Subject: [PATCH 0208/1492] COUNT should return an integer --- lib/arel/relations/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 50c46aa2ed257..466ee66f64146 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -16,7 +16,7 @@ def select_values def count @count = "COUNT(*) AS count_all" - engine.select_value self.to_sql + engine.select_value(self.to_sql).to_i end def to_sql(formatter = Sql::SelectStatement.new(self)) From de843c86518e4ac871d4bb5b0873bb6c184ac304 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 4 May 2009 21:50:44 -0300 Subject: [PATCH 0209/1492] Fixes for PostgreSQL: always alias expresions and quote values. --- lib/arel/relations/operations/project.rb | 6 +++--- lib/arel/sql/formatters.rb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/relations/operations/project.rb index d7835edda4cb5..5507ea3163dc8 100644 --- a/lib/arel/relations/operations/project.rb +++ b/lib/arel/relations/operations/project.rb @@ -2,7 +2,7 @@ module Arel class Project < Compound attributes :relation, :projections deriving :== - + def initialize(relation, *projections, &block) @relation = relation @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } @@ -11,9 +11,9 @@ def initialize(relation, *projections, &block) def attributes @attributes ||= projections.collect { |p| p.bind(self) } end - + def externalizable? attributes.any?(&:aggregation?) or relation.externalizable? end end -end \ No newline at end of file +end diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index aa10952d04924..d8618ca2cca22 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -25,7 +25,7 @@ def expression(expression) if expression.function_sql == "DISTINCT" "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') else - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") end end @@ -69,7 +69,7 @@ def expression(expression) end def value(value) - value.to_sql(self) + quote value.to_sql(self) end def scalar(value, column = nil) From a7dea38204f3c40e4d0c3f29ebe17af818659697 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 6 May 2009 14:14:56 -0300 Subject: [PATCH 0210/1492] Don't depend engine select_value(s) method. Quoting should be performed by connection not ARel --- lib/arel/relations/relation.rb | 9 --------- lib/arel/sql/formatters.rb | 2 +- .../integration/joins/with_adjacency_spec.rb | 20 +++++++++---------- .../joins/with_aggregations_spec.rb | 12 +++++------ .../integration/joins/with_compounds_spec.rb | 8 ++++---- spec/arel/unit/primitives/value_spec.rb | 4 ++-- spec/arel/unit/relations/delete_spec.rb | 10 +++++----- spec/arel/unit/relations/project_spec.rb | 4 ++-- spec/arel/unit/relations/where_spec.rb | 10 +++++----- 9 files changed, 35 insertions(+), 44 deletions(-) diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 466ee66f64146..5d2c336a157c9 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -6,17 +6,8 @@ def session Session.new end - def select_value - engine.select_value self.to_sql - end - - def select_values - engine.select_values self.to_sql - end - def count @count = "COUNT(*) AS count_all" - engine.select_value(self.to_sql).to_i end def to_sql(formatter = Sql::SelectStatement.new(self)) diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb index d8618ca2cca22..f82ddf631fef0 100644 --- a/lib/arel/sql/formatters.rb +++ b/lib/arel/sql/formatters.rb @@ -69,7 +69,7 @@ def expression(expression) end def value(value) - quote value.to_sql(self) + value.to_sql(self) end def scalar(value, column = nil) diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 32109cc3543d1..559b5bbe1a824 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -7,7 +7,7 @@ module Arel @relation2 = @relation1.alias @predicate = @relation1[:id].eq(@relation2[:id]) end - + describe 'when joining a relation to itself' do describe '#to_sql' do it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do @@ -18,7 +18,7 @@ module Arel ON `users`.`id` = `users_2`.`id` ") end - + describe 'when joining with a where on the same relation' do it 'manufactures sql aliasing the tables properly' do @relation1 \ @@ -31,7 +31,7 @@ module Arel ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 ") end - + describe 'when the where occurs before the alias' do it 'manufactures sql aliasing the predicates properly' do relation2 = @relation1.where(@relation1[:id].eq(1)).alias @@ -47,12 +47,12 @@ module Arel end end end - + describe 'when joining the relation to itself multiple times' do before do @relation3 = @relation1.alias end - + describe 'when joining left-associatively' do it 'manufactures sql aliasing the tables properly' do @relation1 \ @@ -70,7 +70,7 @@ module Arel ") end end - + describe 'when joining right-associatively' do it 'manufactures sql aliasing the tables properly' do @relation1 \ @@ -88,7 +88,7 @@ module Arel end end end - + describe '[]' do describe 'when given an attribute belonging to both sub-relations' do it 'disambiguates the relation that serves as the ancestor to the attribute' do @@ -108,7 +108,7 @@ module Arel .should disambiguate_attributes(compound1[:id], compound2[:id]) end end - + describe 'when the left relation is extremely compound' do it 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ @@ -119,7 +119,7 @@ module Arel .should disambiguate_attributes(@relation1[:id], @relation2[:id]) end end - + describe 'when the right relation is extremely compound' do it 'disambiguates the relation that serves as the ancestor to the attribute' do @relation1 \ @@ -136,4 +136,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 42248add0738c..2b21dcaa1e8fe 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -7,14 +7,14 @@ module Arel @relation2 = Arel(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - + describe 'when joining aggregated relations' do before do @aggregation = @relation2 \ .group(@relation2[:user_id]) \ .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ end - + describe '#to_sql' do # CLEANUP it '' do @@ -25,7 +25,7 @@ module Arel ON `users`.`id` = `photos_external`.`user_id` ") end - + describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do @relation1.join(@aggregation).on(@predicate).to_sql.should be_like(" @@ -47,7 +47,7 @@ module Arel ") end end - + describe 'with the aggregation on both sides' do it 'it properly aliases the aggregations' do aggregation2 = @aggregation.alias @@ -71,7 +71,7 @@ module Arel ") end end - + describe 'with the aggregation on the right' do it "manufactures sql keeping wheres on the aggregation within the derived table" do @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" @@ -86,4 +86,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index acfe35b25e7e8..95fadc23d6ee4 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -7,7 +7,7 @@ module Arel @relation2 = Arel(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - + describe '#to_sql' do describe 'when the join contains a where' do describe 'and the where is given a string' do @@ -24,7 +24,7 @@ module Arel end end end - + describe 'when a compound contains a join' do describe 'and the compound is a where' do it 'manufactures sql disambiguating the tables' do @@ -43,7 +43,7 @@ module Arel ") end end - + describe 'and the compound is a group' do it 'manufactures sql disambiguating the tables' do @relation1 \ @@ -62,4 +62,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/primitives/value_spec.rb b/spec/arel/unit/primitives/value_spec.rb index 87425c780d6a1..ba9a80bb49101 100644 --- a/spec/arel/unit/primitives/value_spec.rb +++ b/spec/arel/unit/primitives/value_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '#to_sql' do it "appropriately quotes the value" do Value.new(1, @relation).to_sql.should be_like('1') @@ -25,4 +25,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/unit/relations/delete_spec.rb index 46c2ec9143183..fa887d20fdde3 100644 --- a/spec/arel/unit/relations/delete_spec.rb +++ b/spec/arel/unit/relations/delete_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '#to_sql' do it 'manufactures sql deleting a table relation' do Deletion.new(@relation).to_sql.should be_like(" @@ -13,7 +13,7 @@ module Arel FROM `users` ") end - + it 'manufactures sql deleting a where relation' do Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql.should be_like(" DELETE @@ -21,7 +21,7 @@ module Arel WHERE `users`.`id` = 1 ") end - + it "manufactures sql deleting a ranged relation" do Deletion.new(@relation.take(1)).to_sql.should be_like(" DELETE @@ -30,7 +30,7 @@ module Arel ") end end - + describe '#call' do it 'executes a delete on the connection' do deletion = Deletion.new(@relation) @@ -39,4 +39,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/unit/relations/project_spec.rb index 7f531096f07d3..f389b18c54cd9 100644 --- a/spec/arel/unit/relations/project_spec.rb +++ b/spec/arel/unit/relations/project_spec.rb @@ -50,14 +50,14 @@ module Arel describe 'when given an expression' do it 'manufactures sql with expressions' do @relation.project(@attribute.count).to_sql.should be_like(" - SELECT COUNT(`users`.`id`) + SELECT COUNT(`users`.`id`) AS count_id FROM `users` ") end it 'manufactures sql with distinct expressions' do @relation.project(@attribute.count(true)).to_sql.should be_like(" - SELECT COUNT(DISTINCT `users`.`id`) + SELECT COUNT(DISTINCT `users`.`id`) AS count_id FROM `users` ") end diff --git a/spec/arel/unit/relations/where_spec.rb b/spec/arel/unit/relations/where_spec.rb index aa14fd7bdcbec..8ef4d54b63a6d 100644 --- a/spec/arel/unit/relations/where_spec.rb +++ b/spec/arel/unit/relations/where_spec.rb @@ -6,15 +6,15 @@ module Arel @relation = Table.new(:users) @predicate = @relation[:id].eq(1) end - + describe '#initialize' do it "manufactures nested where relations if multiple predicates are provided" do - another_predicate = @relation[:name].lt(2) + another_predicate = @relation[:name].lt(2) Where.new(@relation, @predicate, another_predicate). \ should == Where.new(Where.new(@relation, another_predicate), @predicate) end end - + describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do @@ -25,7 +25,7 @@ module Arel ") end end - + describe 'when given a string' do it "passes the string through to the where clause" do Where.new(@relation, 'asdf').to_sql.should be_like(" @@ -37,4 +37,4 @@ module Arel end end end -end \ No newline at end of file +end From 5b87e3869e1da533d4d31da64703eac113495662 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 16 May 2009 23:09:59 -0400 Subject: [PATCH 0211/1492] Rename README -> README.markdown --- README => README.markdown | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.markdown (100%) diff --git a/README b/README.markdown similarity index 100% rename from README rename to README.markdown From 49d119ae84bbb7cd180ca855cf48997dc731554c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 16 May 2009 21:13:32 -0400 Subject: [PATCH 0212/1492] Adding spec:mysql and spec:sqlite3 tasks --- .gitignore | 1 + Rakefile | 24 ++- .../integration/joins/with_adjacency_spec.rb | 150 +++++++++++++----- .../joins/with_aggregations_spec.rb | 150 +++++++++++++----- .../integration/joins/with_compounds_spec.rb | 90 ++++++++--- spec/arel/unit/predicates/binary_spec.rb | 76 ++++++--- spec/arel/unit/predicates/equality_spec.rb | 38 +++-- spec/arel/unit/predicates/in_spec.rb | 68 +++++--- spec/arel/unit/predicates/predicates_spec.rb | 36 ++++- spec/arel/unit/primitives/attribute_spec.rb | 62 ++++---- spec/arel/unit/primitives/expression_spec.rb | 10 +- spec/arel/unit/relations/alias_spec.rb | 30 +++- spec/arel/unit/relations/delete_spec.rb | 57 +++++-- spec/arel/unit/relations/group_spec.rb | 48 ++++-- spec/arel/unit/relations/insert_spec.rb | 75 ++++++--- spec/arel/unit/relations/join_spec.rb | 52 ++++-- spec/arel/unit/relations/order_spec.rb | 101 ++++++++---- spec/arel/unit/relations/project_spec.rb | 89 ++++++++--- spec/arel/unit/relations/skip_spec.rb | 22 ++- spec/arel/unit/relations/table_spec.rb | 41 +++-- spec/arel/unit/relations/take_spec.rb | 22 ++- spec/arel/unit/relations/update_spec.rb | 95 ++++++++--- spec/arel/unit/relations/where_spec.rb | 44 +++-- spec/connections/mysql_connection.rb | 13 ++ spec/connections/sqlite3_connection.rb | 22 +++ spec/doubles/database.rb | 51 ------ spec/schemas/mysql_schema.rb | 18 +++ spec/schemas/sqlite3_schema.rb | 18 +++ spec/spec_helper.rb | 19 ++- 29 files changed, 1101 insertions(+), 421 deletions(-) create mode 100644 spec/connections/mysql_connection.rb create mode 100644 spec/connections/sqlite3_connection.rb delete mode 100644 spec/doubles/database.rb create mode 100644 spec/schemas/mysql_schema.rb create mode 100644 spec/schemas/sqlite3_schema.rb diff --git a/.gitignore b/.gitignore index 2bab52ab219aa..da2f440badc89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ coverage/* config/database.yml +spec/fixtures/*database* *.DS_Store diff --git a/Rakefile b/Rakefile index b1fc74a13c6fe..9292ac25339c9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,15 +1,31 @@ require 'rubygems' require 'spec/rake/spectask' -Spec::Rake::SpecTask.new do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] -end +spec_file_list = FileList['spec/**/*_spec.rb'] +desc "Run specs using RCov (uses mysql database adapter)" Spec::Rake::SpecTask.new(:coverage) do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] + t.spec_files = + ["spec/connections/mysql_connection.rb"] + + spec_file_list t.rcov = true t.rcov_opts = ['-x', 'spec,gems'] end +namespace :spec do + for adapter in %w[mysql sqlite3] + desc "Run specs with the #{adapter} database adapter" + Spec::Rake::SpecTask.new(adapter) do |t| + t.spec_files = + ["spec/connections/#{adapter}_connection.rb"] + + ["spec/schemas/#{adapter}_schema.rb"] + + spec_file_list + end + end +end + +desc "Run specs with mysql and sqlite3 database adapters (default)" +task :spec => ["spec:sqlite3", "spec:mysql"] + desc "Default task is to run specs" task :default => :spec \ No newline at end of file diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 559b5bbe1a824..fbac723e10cf8 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -11,39 +11,79 @@ module Arel describe 'when joining a relation to itself' do describe '#to_sql' do it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do - @relation1.join(@relation2).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - ") - end + sql = @relation1.join(@relation2).on(@predicate).to_sql - describe 'when joining with a where on the same relation' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2.where(@relation2[:id].eq(1))) \ - .on(@predicate) \ - .to_sql.should be_like(" + adapter_is :mysql do + sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 - ") + ON `users`.`id` = `users_2`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + }) + end + end + + describe 'when joining with a where on the same relation' do + it 'manufactures sql aliasing the tables properly' do + sql = @relation1 \ + .join(@relation2.where(@relation2[:id].eq(1))) \ + .on(@predicate) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1 + }) + end end describe 'when the where occurs before the alias' do it 'manufactures sql aliasing the predicates properly' do relation2 = @relation1.where(@relation1[:id].eq(1)).alias - @relation1 \ + + sql = @relation1 \ .join(relation2) \ .on(relation2[:id].eq(@relation1[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1 + }) + end end end end @@ -55,35 +95,65 @@ module Arel describe 'when joining left-associatively' do it 'manufactures sql aliasing the tables properly' do - @relation1 \ + sql = @relation1 \ .join(@relation2 \ .join(@relation3) \ .on(@relation2[:id].eq(@relation3[:id]))) \ .on(@relation1[:id].eq(@relation2[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + INNER JOIN "users" AS "users_3" + ON "users_2"."id" = "users_3"."id" + }) + end end end describe 'when joining right-associatively' do it 'manufactures sql aliasing the tables properly' do - @relation1 \ + sql = @relation1 \ .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + INNER JOIN "users" AS "users_3" + ON "users_2"."id" = "users_3"."id" + }) + end end end end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 2b21dcaa1e8fe..41978c0a5abaf 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -18,68 +18,146 @@ module Arel describe '#to_sql' do # CLEANUP it '' do - @relation1.join(@relation2.take(3)).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` - FROM `users` - INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @relation1.join(@relation2.take(3)).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` + FROM `users` + INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" + FROM "users" + INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end end describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do - @relation1.join(@aggregation).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @relation1.join(@aggregation).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" + FROM "users" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end end end describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do - @aggregation.join(@relation1).on(@predicate).to_sql.should be_like(" - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @aggregation.join(@relation1).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN `users` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN "users" + ON "users"."id" = "photos_external"."user_id" + }) + end end end describe 'with the aggregation on both sides' do it 'it properly aliases the aggregations' do aggregation2 = @aggregation.alias - @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql.should be_like(" - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` - ON `photos_external_2`.`user_id` = `photos_external`.`user_id` - ") + sql = @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` + ON `photos_external_2`.`user_id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external_2" + ON "photos_external_2"."user_id" = "photos_external"."user_id" + }) + end end end describe 'when the aggration has a where' do describe 'with the aggregation on the left' do it "manufactures sql keeping wheres on the aggregation within the derived table" do - @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" + FROM "users" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end end end describe 'with the aggregation on the right' do it "manufactures sql keeping wheres on the aggregation within the derived table" do - @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN `users` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN "users" + ON "users"."id" = "photos_external"."user_id" + }) + end end end end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 95fadc23d6ee4..7582c5fc83022 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -12,15 +12,28 @@ module Arel describe 'when the join contains a where' do describe 'and the where is given a string' do it 'does not escape the string' do - @relation1 \ + sql = @relation1 \ .join(@relation2.where("asdf")) \ .on(@predicate) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` AND asdf - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` AND asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" AND asdf + }) + end end end end @@ -28,35 +41,64 @@ module Arel describe 'when a compound contains a join' do describe 'and the compound is a where' do it 'manufactures sql disambiguating the tables' do - @relation1 \ + sql = @relation1 \ .where(@relation1[:id].eq(1)) \ .join(@relation2) \ .on(@predicate) \ .where(@relation1[:id].eq(1)) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - WHERE `users`.`id` = 1 - AND `users`.`id` = 1 - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + WHERE `users`.`id` = 1 + AND `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" + WHERE "users"."id" = 1 + AND "users"."id" = 1 + }) + end end end describe 'and the compound is a group' do it 'manufactures sql disambiguating the tables' do - @relation1 \ + sql = @relation1 \ .join(@relation2) \ .on(@predicate) \ .group(@relation1[:id]) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - GROUP BY `users`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + GROUP BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" + GROUP BY "users"."id" + }) + end end end end diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index 56fcf2d8ad5dc..2d0c67e006c3f 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -18,13 +18,19 @@ def predicate_sql @operand1 = ConcreteBinary.new(@attribute1, 1) @operand2 = ConcreteBinary.new(@attribute2, "name") end - + describe Or do describe "#to_sql" do it "manufactures sql with an OR operation" do - Or.new(@operand1, @operand2).to_sql.should be_like(" - (`users`.`id` <=> 1 OR `users`.`name` <=> 'name') - ") + sql = Or.new(@operand1, @operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) + end end end end @@ -32,58 +38,82 @@ def predicate_sql describe And do describe "#to_sql" do it "manufactures sql with an AND operation" do - And.new(@operand1, @operand2).to_sql.should be_like(" - (`users`.`id` <=> 1 AND `users`.`name` <=> 'name') - ") + sql = And.new(@operand1, @operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) + end end end end end - + describe '#to_sql' do describe 'when relating two attributes' do it 'manufactures sql with a binary operation' do - ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" - `users`.`id` <=> `users`.`name` - ") + sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> "users"."name"}) + end end end - + describe 'when relating an attribute and a value' do before do @value = "1-asdf" end - + describe 'when relating to an integer attribute' do it 'formats values as integers' do - ConcreteBinary.new(@attribute1, @value).to_sql.should be_like(" - `users`.`id` <=> 1 - ") + sql = ConcreteBinary.new(@attribute1, @value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> 1}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> 1}) + end end end - + describe 'when relating to a string attribute' do it 'formats values as strings' do - ConcreteBinary.new(@attribute2, @value).to_sql.should be_like(" - `users`.`name` <=> '1-asdf' - ") + sql = ConcreteBinary.new(@attribute2, @value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) + end end end end end - + describe '#bind' do before do @another_relation = @relation.alias end - + describe 'when both operands are attributes' do it "manufactures an expression with the attributes bound to the relation" do ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) end end - + describe 'when an operand is a value' do it "manufactures an expression with unmodified values" do ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ diff --git a/spec/arel/unit/predicates/equality_spec.rb b/spec/arel/unit/predicates/equality_spec.rb index 8a58ba30966ca..b595cdd247398 100644 --- a/spec/arel/unit/predicates/equality_spec.rb +++ b/spec/arel/unit/predicates/equality_spec.rb @@ -8,40 +8,52 @@ module Arel @attribute1 = @relation1[:id] @attribute2 = @relation2[:user_id] end - - describe '==' do + + describe '==' do it "obtains if attribute1 and attribute2 are identical" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) end - + it "obtains if the concrete type of the predicates are identical" do Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) end - + it "is commutative on the attributes" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) end end - + describe '#to_sql' do describe 'when relating to a non-nil value' do it "manufactures an equality predicate" do - Equality.new(@attribute1, @attribute2).to_sql.should be_like(" - `users`.`id` = `photos`.`user_id` - ") + sql = Equality.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) + end end end - + describe 'when relation to a nil value' do before do @nil = nil end - + it "manufactures an is null predicate" do - Equality.new(@attribute1, @nil).to_sql.should be_like(" - `users`.`id` IS NULL - ") + sql = Equality.new(@attribute1, @nil).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NULL}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IS NULL}) + end end end end diff --git a/spec/arel/unit/predicates/in_spec.rb b/spec/arel/unit/predicates/in_spec.rb index 797798a77fdf1..9107da9d4b19b 100644 --- a/spec/arel/unit/predicates/in_spec.rb +++ b/spec/arel/unit/predicates/in_spec.rb @@ -6,51 +6,79 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - - describe '#to_sql' do + + describe '#to_sql' do describe 'when relating to an array' do describe 'when the array\'s elements are the same type as the attribute' do before do @array = [1, 2, 3] end - + it 'manufactures sql with a comma separated list' do - In.new(@attribute, @array).to_sql.should be_like(" - `users`.`id` IN (1, 2, 3) - ") + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end end end - + describe 'when the array\'s elements are not same type as the attribute' do before do @array = ['1-asdf', 2, 3] end - + it 'formats values in the array as the type of the attribute' do - In.new(@attribute, @array).to_sql.should be_like(" - `users`.`id` IN (1, 2, 3) - ") + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end end end end - + describe 'when relating to a range' do before do @range = 1..2 end - + it 'manufactures sql with a between' do - In.new(@attribute, @range).to_sql.should be_like(" - `users`.`id` BETWEEN 1 AND 2 - ") + sql = In.new(@attribute, @range).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) + end end end - + describe 'when relating to a relation' do it 'manufactures sql with a subselect' do - In.new(@attribute, @relation).to_sql.should be_like(" - `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) - ") + sql = In.new(@attribute, @relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") + }) + end end end end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb index d11637cabe94e..8f9cec537627e 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -9,23 +9,43 @@ module Arel @operand1 = Equality.new(@attribute1, 1) @operand2 = Equality.new(@attribute2, "name") end - + describe "when being combined with another predicate with AND logic" do describe "#to_sql" do it "manufactures sql with an AND operation" do - @operand1.and(@operand2).to_sql.should be_like(" - (`users`.`id` = 1 AND `users`.`name` = 'name') - ") + sql = @operand1.and(@operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 AND `users`.`name` = 'name') + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = 'name') + }) + end end end end - + describe "when being combined with another predicate with OR logic" do describe "#to_sql" do it "manufactures sql with an OR operation" do - @operand1.or(@operand2).to_sql.should be_like(" - (`users`.`id` = 1 OR `users`.`name` = 'name') - ") + sql = @operand1.or(@operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 OR `users`.`name` = 'name') + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = 'name') + }) + end end end end diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index b341c6f88e267..6d0f146a39ccd 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -6,57 +6,57 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) end end - + describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end - + it "returns self if the substituting to the same relation" do @attribute.bind(@relation).should == @attribute end end - + describe '#to_attribute' do it "returns self" do @attribute.to_attribute.should == @attribute end end end - + describe '#column' do it "returns the corresponding column in the relation" do @attribute.column.should == @relation.column_for(@attribute) end end - + describe '#engine' do it "delegates to its relation" do Attribute.new(@relation, :id).engine.should == @relation.engine end end - + describe Attribute::Congruence do describe '/' do before do @aliased_relation = @relation.alias @doubly_aliased_relation = @aliased_relation.alias end - + describe 'when dividing two unrelated attributes' do it "returns 0.0" do (@relation[:id] / @relation[:name]).should == 0.0 end end - + describe 'when dividing two matching attributes' do it 'returns a the highest score for the most similar attributes' do (@aliased_relation[:id] / @relation[:id]) \ @@ -67,97 +67,105 @@ module Arel end end end - + describe '#to_sql' do describe 'for a simple attribute' do it "manufactures sql with an alias" do - @attribute.to_sql.should be_like("`users`.`id`") + sql = @attribute.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id"}) + end end end end - + describe Attribute::Predications do before do @attribute = Attribute.new(@relation, :name) end - + describe '#eq' do it "manufactures an equality predicate" do @attribute.eq('name').should == Equality.new(@attribute, 'name') end end - + describe '#lt' do it "manufactures a less-than predicate" do @attribute.lt(10).should == LessThan.new(@attribute, 10) end end - + describe '#lteq' do it "manufactures a less-than or equal-to predicate" do @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) end end - + describe '#gt' do it "manufactures a greater-than predicate" do @attribute.gt(10).should == GreaterThan.new(@attribute, 10) end end - + describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end - + describe '#matches' do it "manufactures a match predicate" do @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end - + describe '#in' do it "manufactures an in predicate" do @attribute.in(1..30).should == In.new(@attribute, (1..30)) end end end - + describe Attribute::Expressions do before do - @attribute = Attribute.new(@relation, :name) + @attribute = Attribute.new(@relation, :name) end - + describe '#count' do it "manufactures a count Expression" do @attribute.count.should == Expression.new(@attribute, "COUNT") end end - + describe '#sum' do it "manufactures a sum Expression" do @attribute.sum.should == Expression.new(@attribute, "SUM") end end - + describe '#maximum' do it "manufactures a maximum Expression" do @attribute.maximum.should == Expression.new(@attribute, "MAX") end end - + describe '#minimum' do it "manufactures a minimum Expression" do @attribute.minimum.should == Expression.new(@attribute, "MIN") end end - + describe '#average' do it "manufactures an average Expression" do @attribute.average.should == Expression.new(@attribute, "AVG") end - end + end end end end \ No newline at end of file diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index 4943f4ef33046..ebde55ff9064f 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -38,7 +38,15 @@ module Arel describe '#to_sql' do it "manufactures sql with the expression and alias" do - Expression.new(@attribute, "COUNT", :alias).to_sql.should == "COUNT(`users`.`id`) AS `alias`" + sql = Expression.new(@attribute, "COUNT", :alias).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{COUNT("users"."id") AS "alias"}) + end end end end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 460a0ed0df20a..570f3158926f3 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -16,19 +16,33 @@ module Arel describe '#to_sql' do describe 'when there is no ambiguity' do it 'does not alias table names anywhere a table name can appear' do - @relation \ + sql = @relation \ .where(@relation[:id].eq(1)) \ .order(@relation[:id]) \ .project(@relation[:id]) \ .group(@relation[:id]) \ .alias \ - .to_sql.should be_like(" - SELECT `users`.`id` - FROM `users` - WHERE `users`.`id` = 1 - GROUP BY `users`.`id` - ORDER BY `users`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id` + FROM `users` + WHERE `users`.`id` = 1 + GROUP BY `users`.`id` + ORDER BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + GROUP BY "users"."id" + ORDER BY "users"."id" + }) + end end end end diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/unit/relations/delete_spec.rb index fa887d20fdde3..3798178ccc7e1 100644 --- a/spec/arel/unit/relations/delete_spec.rb +++ b/spec/arel/unit/relations/delete_spec.rb @@ -8,26 +8,55 @@ module Arel describe '#to_sql' do it 'manufactures sql deleting a table relation' do - Deletion.new(@relation).to_sql.should be_like(" - DELETE - FROM `users` - ") + sql = Deletion.new(@relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{DELETE FROM `users`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{DELETE FROM "users"}) + end end it 'manufactures sql deleting a where relation' do - Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql.should be_like(" - DELETE - FROM `users` - WHERE `users`.`id` = 1 - ") + sql = Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + DELETE + FROM `users` + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + DELETE + FROM "users" + WHERE "users"."id" = 1 + }) + end end it "manufactures sql deleting a ranged relation" do - Deletion.new(@relation.take(1)).to_sql.should be_like(" - DELETE - FROM `users` - LIMIT 1 - ") + sql = Deletion.new(@relation.take(1)).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + DELETE + FROM `users` + LIMIT 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + DELETE + FROM "users" + LIMIT 1 + }) + end end end diff --git a/spec/arel/unit/relations/group_spec.rb b/spec/arel/unit/relations/group_spec.rb index a0147b94160b4..658c0ad406b28 100644 --- a/spec/arel/unit/relations/group_spec.rb +++ b/spec/arel/unit/relations/group_spec.rb @@ -6,25 +6,49 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - Group.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY `users`.`id` - ") + sql = Group.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + GROUP BY "users"."id" + }) + end end end - + describe 'when given a string' do it "passes the string through to the where clause" do - Group.new(@relation, 'asdf').to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY asdf - ") + sql = Group.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + GROUP BY asdf + }) + end end end end diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb index 441c97b290463..2fd07dd96c4d5 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -8,24 +8,35 @@ module Arel describe '#to_sql' do it 'manufactures sql inserting data when given multiple rows' do - pending 'it should insert multiple rows' - @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) + pending 'it should insert multiple rows' do + @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`name`) VALUES ('nick'), ('bryan') - ") + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`name`) VALUES ('nick'), ('bryan') + ") + end end it 'manufactures sql inserting data when given multiple values' do @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`id`, `name`) VALUES (1, 'nick') - ") + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`id`, `name`) VALUES (1, 'nick') + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id", "name") VALUES (1, 'nick') + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -34,11 +45,21 @@ module Arel end it 'manufactures sql inserting data' do - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`name`) VALUES ('nick') - ") + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`name`) VALUES ('nick') + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("name") VALUES ('nick') + }) + end end end @@ -48,11 +69,21 @@ module Arel end it 'manufactures sql inserting data' do - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`id`) VALUES (1) - ") + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`id`) VALUES (1) + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id") VALUES (1) + }) + end end end end diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 1698bf9647a31..fa6bbbe216224 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -7,20 +7,20 @@ module Arel @relation2 = Table.new(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - + describe 'hashing' do it 'implements hash equality' do Join.new("INNER JOIN", @relation1, @relation2, @predicate) \ .should hash_the_same_as(Join.new("INNER JOIN", @relation1, @relation2, @predicate)) end end - + describe '#engine' do it "delegates to a relation's engine" do Join.new("INNER JOIN", @relation1, @relation2, @predicate).engine.should == @relation1.engine end end - + describe '#attributes' do it 'combines the attributes of the two relations' do join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) @@ -32,21 +32,45 @@ module Arel describe '#to_sql' do describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` - ") + sql = Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" ON "users"."id" = "photos"."user_id" + }) + end end end - + describe 'when joining with a string' do it "passes the string through to the where clause" do - Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - INNER JOIN asdf ON fdsa - ") + sql = Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + INNER JOIN asdf ON fdsa + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + INNER JOIN asdf ON fdsa + }) + end end end end diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb index d373a8ba126c5..31014ddd39336 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -10,57 +10,104 @@ module Arel describe '#to_sql' do describe "when given an attribute" do it "manufactures sql with an order clause populated by the attribute" do - Order.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` - ") + sql = Order.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."id" + }) + end end end - + describe "when given multiple attributes" do before do @another_attribute = @relation[:name] end - + it "manufactures sql with an order clause populated by comma-separated attributes" do - Order.new(@relation, @attribute, @another_attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id`, `users`.`name` - ") + sql = Order.new(@relation, @attribute, @another_attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id`, `users`.`name` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."id", "users"."name" + }) + end end end - + describe "when given a string" do before do @string = "asdf" end - + it "passes the string through to the order clause" do - Order.new(@relation, @string).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY asdf - ") + sql = Order.new(@relation, @string).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY asdf + }) + end end end - + describe "when ordering an ordered relation" do before do @ordered_relation = Order.new(@relation, @attribute) @another_attribute = @relation[:name] end - + it "manufactures sql with the order clause of the last ordering preceding the first ordering" do - Order.new(@ordered_relation, @another_attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`name`, `users`.`id` - ") + sql = Order.new(@ordered_relation, @another_attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`name`, `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."name", "users"."id" + }) + end end end end end end - \ No newline at end of file diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/unit/relations/project_spec.rb index f389b18c54cd9..d2d1fb3873929 100644 --- a/spec/arel/unit/relations/project_spec.rb +++ b/spec/arel/unit/relations/project_spec.rb @@ -20,10 +20,21 @@ module Arel describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do - Project.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id` - FROM `users` - ") + sql = Project.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id" + FROM "users" + }) + end end end @@ -33,33 +44,75 @@ module Arel end it "manufactures sql with scalar selects" do - Project.new(@relation, @scalar_relation).to_sql.should be_like(" - SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` - ") + sql = Project.new(@relation, @scalar_relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users" + }) + end end end describe 'when given a string' do it "passes the string through to the select clause" do - Project.new(@relation, 'asdf').to_sql.should be_like(" - SELECT asdf FROM `users` - ") + sql = Project.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT asdf FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT asdf FROM "users" + }) + end end end describe 'when given an expression' do it 'manufactures sql with expressions' do - @relation.project(@attribute.count).to_sql.should be_like(" - SELECT COUNT(`users`.`id`) AS count_id - FROM `users` - ") + sql = @relation.project(@attribute.count).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(`users`.`id`) AS count_id + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT COUNT("users"."id") AS count_id + FROM "users" + }) + end end it 'manufactures sql with distinct expressions' do - @relation.project(@attribute.count(true)).to_sql.should be_like(" - SELECT COUNT(DISTINCT `users`.`id`) AS count_id - FROM `users` - ") + sql = @relation.project(@attribute.count(true)).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT `users`.`id`) AS count_id + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT "users"."id") AS count_id + FROM "users" + }) + end end end end diff --git a/spec/arel/unit/relations/skip_spec.rb b/spec/arel/unit/relations/skip_spec.rb index d83c969aa859f..0653d795b10f7 100644 --- a/spec/arel/unit/relations/skip_spec.rb +++ b/spec/arel/unit/relations/skip_spec.rb @@ -9,11 +9,23 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - Skip.new(@relation, @skipped).to_s.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - OFFSET #{@skipped} - ") + sql = Skip.new(@relation, @skipped).to_s + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + OFFSET 4 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + OFFSET 4 + }) + end end end end diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index 54520bf3b6df7..08486c7b6ce8b 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do @@ -18,39 +18,50 @@ module Arel it "returns the attribute if the attribute is within the relation" do @relation[@relation[:id]].should == @relation[:id] end - + it "returns nil if the attribtue is not within the relation" do another_relation = Table.new(:photos) @relation[another_relation[:id]].should be_nil end end - + describe 'when given an', Expression do before do @expression = @relation[:id].count end - + it "returns the Expression if the Expression is within the relation" do @relation[@expression].should be_nil end end end - + describe '#to_sql' do it "manufactures a simple select query" do - @relation.to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ") + sql = @relation.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + }) + end end end - + describe '#column_for' do it "returns the column corresponding to the attribute" do @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } end end - + describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do @relation.attributes.should == [ @@ -58,7 +69,7 @@ module Arel Attribute.new(@relation, :name) ] end - + describe '#reset' do it "reloads columns from the database" do lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } @@ -66,20 +77,20 @@ module Arel end end end - + describe 'hashing' do it "implements hash equality" do Table.new(:users).should hash_the_same_as(Table.new(:users)) Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) end end - + describe '#engine' do it "defaults to global engine" do Table.engine = engine = Engine.new Table.new(:users).engine.should == engine end - + it "can be specified" do Table.new(:users, engine = Engine.new).engine.should == engine end diff --git a/spec/arel/unit/relations/take_spec.rb b/spec/arel/unit/relations/take_spec.rb index dca78060571fd..911b84e01e7ad 100644 --- a/spec/arel/unit/relations/take_spec.rb +++ b/spec/arel/unit/relations/take_spec.rb @@ -9,11 +9,23 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - Take.new(@relation, @taken).to_s.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - LIMIT #{@taken} - ") + sql = Take.new(@relation, @taken).to_s + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + LIMIT 4 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + LIMIT 4 + }) + end end end end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index b67369251f5ac..0bbc9113c68f1 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -8,18 +8,41 @@ module Arel describe '#to_sql' do it "manufactures sql updating attributes when given multiple attributes" do - Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" - UPDATE `users` - SET `id` = 1, `name` = 'nick' - ") + sql = Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + UPDATE `users` + SET `id` = 1, `name` = 'nick' + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1, "name" = 'nick' + }) + end end it "manufactures sql updating attributes when given a ranged relation" do - Update.new(@relation.take(1), @relation[:name] => "nick").to_sql.should be_like(" - UPDATE `users` - SET `name` = 'nick' - LIMIT 1 - ") + sql = Update.new(@relation.take(1), @relation[:name] => "nick").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + LIMIT 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + LIMIT 1 + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -28,10 +51,19 @@ module Arel end it 'manufactures sql updating attributes' do - @update.to_sql.should be_like(" - UPDATE `users` - SET `name` = 'nick' - ") + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + }) + end end end @@ -41,10 +73,19 @@ module Arel end it 'manufactures sql updating attributes' do - @update.to_sql.should be_like(" - UPDATE `users` - SET `id` = 1 - ") + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `id` = 1 + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1 + }) + end end end @@ -57,11 +98,21 @@ module Arel end it 'manufactures sql updating a where relation' do - @update.to_sql.should be_like(" - UPDATE `users` - SET `name` = 'nick' - WHERE `users`.`id` = 1 - ") + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + WHERE "users"."id" = 1 + }) + end end end end diff --git a/spec/arel/unit/relations/where_spec.rb b/spec/arel/unit/relations/where_spec.rb index 8ef4d54b63a6d..64f97c8135fcf 100644 --- a/spec/arel/unit/relations/where_spec.rb +++ b/spec/arel/unit/relations/where_spec.rb @@ -18,21 +18,45 @@ module Arel describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - Where.new(@relation, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE `users`.`id` = 1 - ") + sql = Where.new(@relation, @predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + WHERE "users"."id" = 1 + }) + end end end describe 'when given a string' do it "passes the string through to the where clause" do - Where.new(@relation, 'asdf').to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE asdf - ") + sql = Where.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + WHERE asdf + }) + end end end end diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb new file mode 100644 index 0000000000000..789628b95d089 --- /dev/null +++ b/spec/connections/mysql_connection.rb @@ -0,0 +1,13 @@ +require "activerecord" +puts "Using native MySQL" + +ActiveRecord::Base.configurations = { + 'unit' => { + :adapter => 'mysql', + :username => 'rails', + :encoding => 'utf8', + :database => 'arel_unit', + } +} + +ActiveRecord::Base.establish_connection 'unit' \ No newline at end of file diff --git a/spec/connections/sqlite3_connection.rb b/spec/connections/sqlite3_connection.rb new file mode 100644 index 0000000000000..bae077711d9bf --- /dev/null +++ b/spec/connections/sqlite3_connection.rb @@ -0,0 +1,22 @@ +require "activerecord" +puts "Using native SQLite3" + +db_file = "spec/fixtures/fixture_database.sqlite3" + +ActiveRecord::Base.configurations = { + "unit" => { + :adapter => 'sqlite3', + :database => db_file, + :timeout => 5000 + } +} + +unless File.exist?(db_file) + puts "SQLite3 database not found at #{db_file}. Rebuilding it." + FileUtils.mkdir_p(File.dirname(db_file)) + sqlite_command = %Q{sqlite3 "#{db_file}" "create table a (a integer); drop table a;"} + puts "Executing '#{sqlite_command}'" + raise "Seems that there is no sqlite3 executable available" unless system(sqlite_command) +end + +ActiveRecord::Base.establish_connection("unit") diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb deleted file mode 100644 index f8a4b38e178ef..0000000000000 --- a/spec/doubles/database.rb +++ /dev/null @@ -1,51 +0,0 @@ -module Fake - class Engine - def connection - @conn ||= Connection.new - end - end - - class Connection - include ActiveRecord::ConnectionAdapters::Quoting - - def columns(table_name, comment) - { "users" => - [ - Column.new("id", :integer), - Column.new("name", :string) - ], - "photos" => - [ - Column.new("id", :integer), - Column.new("user_id", :integer), - Column.new("camera_id", :integer) - ] - }[table_name] - end - - def execute(*args) - [] - end - - def quote_column_name(column_name) - "`#{column_name}`" - end - - def quote_table_name(table_name) - "`#{table_name}`" - end - - def supports_count_distinct? - true - end - end - - class Column - attr_reader :name, :type - - def initialize(name, type) - @name = name - @type = type - end - end -end diff --git a/spec/schemas/mysql_schema.rb b/spec/schemas/mysql_schema.rb new file mode 100644 index 0000000000000..1123f4582e2fd --- /dev/null +++ b/spec/schemas/mysql_schema.rb @@ -0,0 +1,18 @@ +sql = <<-SQL + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL + ); + + DROP TABLE IF EXISTS photos; + CREATE TABLE photos ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + user_id INTEGER NOT NULL, + camera_id INTEGER NOT NULL + ); +SQL + +sql.split(/;/).select(&:present?).each do |sql_statement| + ActiveRecord::Base.connection.execute sql_statement +end \ No newline at end of file diff --git a/spec/schemas/sqlite3_schema.rb b/spec/schemas/sqlite3_schema.rb new file mode 100644 index 0000000000000..6c98a4f934966 --- /dev/null +++ b/spec/schemas/sqlite3_schema.rb @@ -0,0 +1,18 @@ +sql = <<-SQL + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(255) NOT NULL + ); + + DROP TABLE IF EXISTS photos; + CREATE TABLE photos ( + id INTEGER NOT NULL PRIMARY KEY, + user_id INTEGER NOT NULL, + camera_id INTEGER NOT NULL + ); +SQL + +sql.split(/;/).select(&:present?).each do |sql_statement| + ActiveRecord::Base.connection.execute sql_statement +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce539b6ffa95f..8d515d66f1a64 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,10 +11,25 @@ Dir["#{dir}/#{helper}/*"].each { |m| require "#{dir}/#{helper}/#{File.basename(m)}" } end +module AdapterGuards + def adapter_is(name) + yield if name.to_s == adapter_name + end + + def adapter_is_not(name) + yield if name.to_s != adapter_name + end + + def adapter_name + Arel::Table.engine.connection.class.name.underscore.split("/").last.gsub(/_adapter/, '') + end +end + Spec::Runner.configure do |config| - config.include(BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher) + config.include BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher + config.include AdapterGuards config.mock_with :rr config.before do - Arel::Table.engine = Arel::Engine.new(Fake::Engine.new) + Arel::Table.engine = Arel::Engine.new(ActiveRecord::Base) end end From 2bbf8ca9d2af3ea959a21c3729b4894bc31f088b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 13:58:29 -0400 Subject: [PATCH 0213/1492] reorganized call Conflicts: doc/TODO lib/arel/relations/relation.rb lib/arel/relations/writes/delete.rb lib/arel/relations/writes/insert.rb lib/arel/relations/writes/update.rb lib/arel/session.rb spec/arel/unit/relations/delete_spec.rb spec/arel/unit/relations/insert_spec.rb spec/arel/unit/relations/relation_spec.rb spec/arel/unit/relations/update_spec.rb spec/arel/unit/session/session_spec.rb --- doc/TODO | 16 ++++++-------- lib/arel/engine.rb | 24 ++++++++++++++++++++ lib/arel/relations.rb | 4 +--- lib/arel/relations/array.rb | 19 ++++++++++++++++ lib/arel/relations/relation.rb | 9 ++------ lib/arel/relations/writes/delete.rb | 4 ++-- lib/arel/relations/writes/insert.rb | 4 ++-- lib/arel/relations/writes/update.rb | 4 ++-- lib/arel/session.rb | 8 +++---- spec/arel/unit/relations/array_spec.rb | 27 +++++++++++++++++++++++ spec/arel/unit/relations/delete_spec.rb | 8 ------- spec/arel/unit/relations/insert_spec.rb | 11 --------- spec/arel/unit/relations/relation_spec.rb | 7 ------ spec/arel/unit/relations/update_spec.rb | 11 --------- spec/arel/unit/session/session_spec.rb | 10 ++++----- 15 files changed, 95 insertions(+), 71 deletions(-) create mode 100644 lib/arel/relations/array.rb create mode 100644 spec/arel/unit/relations/array_spec.rb diff --git a/doc/TODO b/doc/TODO index 740e5db5fe4e5..ad1264088106c 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,19 +1,16 @@ todo: -- joining with LIMIT is like aggregations!! +- refactor adapter pattern +- implement in memory adapter +- implement mnesia adapter +- joins become subselects in writes: users.delete().where( addresses.c.user_id== select([users.c.id]). where(users.c.name=='jack') ) - - SELECT id, name, - (select count(*) FROM addresses WHERE - user_id=users.id) - FROM users - - SELECT users.*, (SELECT count(id) FROM addresses WHERE - addresses.user_id=users.id) FROM users +- rename externalize to derived. +- and/or w/ predicates - blocks for all operations - result sets to attr correlation too - cache expiry on write @@ -85,6 +82,7 @@ done: - test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. - rename select to where - rename all ion classes +- joining with LIMIT is like aggregations!! icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/engine.rb b/lib/arel/engine.rb index 5a5ef0687879c..2bb4bbbd904cd 100644 --- a/lib/arel/engine.rb +++ b/lib/arel/engine.rb @@ -14,5 +14,29 @@ def connection def method_missing(method, *args, &block) @ar.connection.send(method, *args, &block) end + + module CRUD + def create(relation) + connection.insert(relation.to_sql) + end + + def read(relation) + results = connection.execute(relation.to_sql) + rows = [] + results.each do |row| + rows << attributes.zip(row).to_hash + end + rows + end + + def update(relation) + connection.update(relation.to_sql) + end + + def delete(relation) + connection.delete(relation.to_sql) + end + end + include CRUD end end diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index 3394fac7cbcc4..fd758ed15d9aa 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -1,8 +1,6 @@ require 'arel/relations/relation' - require 'arel/relations/utilities' - require 'arel/relations/table' - +require 'arel/relations/array' require 'arel/relations/writes' require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/array.rb b/lib/arel/relations/array.rb new file mode 100644 index 0000000000000..dac65abbc2228 --- /dev/null +++ b/lib/arel/relations/array.rb @@ -0,0 +1,19 @@ +module Arel + class Array < Relation + include Recursion::BaseCase + + def initialize(array, attribute_names) + @array, @attribute_names = array, attribute_names + end + + def attributes + @attributes ||= @attribute_names.collect do |name| + Attribute.new(self, name.to_sym) + end + end + + def call(connection = nil) + @array.collect { |row| attributes.zip(row).to_hash } + end + end +end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 5d2c336a157c9..ef295dfdd78ad 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -32,13 +32,8 @@ def inclusion_predicate_sql "IN" end - def call(connection = engine) - results = connection.execute(to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash - end - rows + def call + engine.read(self) end def bind(relation) diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index b1ff3bef278ba..0a04454e7f648 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -12,8 +12,8 @@ def to_sql(formatter = nil) ].compact.join("\n") end - def call(connection = engine) - connection.delete(to_sql) + def call + engine.delete(self) end end end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb index d579ad06d0bf5..d05bd9cdc821d 100644 --- a/lib/arel/relations/writes/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -16,8 +16,8 @@ def to_sql(formatter = nil) ].join("\n") end - def call(connection = engine) - connection.insert(to_sql) + def call + engine.create(self) end end end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 2e90de3a52fda..fd0aadb479a5d 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -18,8 +18,8 @@ def to_sql(formatter = nil) ].join("\n") end - def call(connection = engine) - connection.update(to_sql) + def call + engine.update(self) end end end diff --git a/lib/arel/session.rb b/lib/arel/session.rb index d9a6e4b5e4a48..9c2ddc535b2ba 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -25,21 +25,21 @@ def start module CRUD def create(insert) - insert.call(insert.engine) + insert.call end def read(select) (@read ||= Hash.new do |hash, select| - hash[select] = select.call(select.engine) + hash[select] = select.call end)[select] end def update(update) - update.call(update.engine) + update.call end def delete(delete) - delete.call(delete.engine) + delete.call end end include CRUD diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb new file mode 100644 index 0000000000000..1330f0f2055db --- /dev/null +++ b/spec/arel/unit/relations/array_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module Arel + describe Array do + before do + @relation = Array.new([[1], [2], [3]], [:id]) + end + + describe '#attributes' do + it 'manufactures attributes corresponding to the names given on construction' do + @relation.attributes.should == [ + Attribute.new(@relation, :id) + ] + end + end + + describe '#call' do + it "manufactures an array of hashes of attributes to values" do + @relation.call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 }, + { @relation[:id] => 3 } + ] + end + end + end +end \ No newline at end of file diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/unit/relations/delete_spec.rb index 3798178ccc7e1..23aca563f7c86 100644 --- a/spec/arel/unit/relations/delete_spec.rb +++ b/spec/arel/unit/relations/delete_spec.rb @@ -59,13 +59,5 @@ module Arel end end end - - describe '#call' do - it 'executes a delete on the connection' do - deletion = Deletion.new(@relation) - mock(connection = Object.new).delete(deletion.to_sql) - deletion.call(connection) - end - end end end diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb index 2fd07dd96c4d5..5ab3ef1299549 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -87,16 +87,5 @@ module Arel end end end - - describe '#call' do - before do - @insertion = Insert.new(@relation, @relation[:name] => "nick") - end - - it 'executes an insert on the connection' do - mock(connection = Object.new).insert(@insertion.to_sql) - @insertion.call(connection) - end - end end end diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index a3bfa673538ef..7df10be59cf6e 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -165,12 +165,5 @@ module Arel @relation.first.should == @relation.session.read(@relation).first end end - - describe '#call' do - it 'executes a select_all on the connection' do - mock(connection = Object.new).execute(@relation.to_sql) { [] } - @relation.call(connection) - end - end end end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index 0bbc9113c68f1..e0d7ddd2951cd 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -117,16 +117,5 @@ module Arel end end - describe '#call' do - before do - @update = Update.new(@relation, @relation[:name] => "nick") - end - - it 'executes an update on the connection' do - mock(connection = Object.new).update(@update.to_sql) - @update.call(connection) - end - end - end end diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb index 6e73d74f2d6ec..c30ba6195fa7f 100644 --- a/spec/arel/unit/session/session_spec.rb +++ b/spec/arel/unit/session/session_spec.rb @@ -40,19 +40,19 @@ module Arel describe '#create' do it "executes an insertion on the connection" do - mock(@insert).call(@insert.engine) + mock(@insert).call @session.create(@insert) end end describe '#read' do it "executes an selection on the connection" do - mock(@read).call(@read.engine) + mock(@read).call @session.read(@read) end it "is memoized" do - mock(@read).call(@read.engine).once + mock(@read).call.once @session.read(@read) @session.read(@read) end @@ -60,14 +60,14 @@ module Arel describe '#update' do it "executes an update on the connection" do - mock(@update).call(@update.engine) + mock(@update).call @session.update(@update) end end describe '#delete' do it "executes a delete on the connection" do - mock(@delete).call(@delete.engine) + mock(@delete).call @session.delete(@delete) end end From bdca9ed42ffea10aa6989ea3ecebedb424fa01ed Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:20:29 -0400 Subject: [PATCH 0214/1492] moved sql related code to its own engine area Conflicts: lib/arel/engine.rb lib/arel/extensions/object.rb lib/arel/predicates.rb lib/arel/primitives/attribute.rb lib/arel/primitives/expression.rb lib/arel/primitives/value.rb lib/arel/relations/operations/join.rb lib/arel/relations/relation.rb lib/arel/relations/utilities/externalization.rb lib/arel/relations/utilities/nil.rb lib/arel/relations/writes/delete.rb lib/arel/relations/writes/insert.rb lib/arel/relations/writes/update.rb spec/arel/unit/relations/skip_spec.rb spec/arel/unit/relations/take_spec.rb spec/spec_helper.rb --- doc/TODO | 2 +- lib/arel.rb | 3 +- lib/arel/engine.rb | 42 ------------------- lib/arel/engines.rb | 2 + lib/arel/engines/array/array.rb | 1 + .../{ => engines/array}/relations/array.rb | 0 lib/arel/{ => engines}/sql/christener.rb | 0 lib/arel/engines/sql/engine.rb | 41 ++++++++++++++++++ lib/arel/engines/sql/extensions.rb | 4 ++ lib/arel/engines/sql/extensions/array.rb | 9 ++++ .../{ => engines/sql}/extensions/nil_class.rb | 0 lib/arel/engines/sql/extensions/object.rb | 9 ++++ .../{ => engines/sql}/extensions/range.rb | 0 lib/arel/{ => engines}/sql/formatters.rb | 0 lib/arel/engines/sql/predicates.rb | 37 ++++++++++++++++ lib/arel/engines/sql/primitives.rb | 3 ++ lib/arel/engines/sql/primitives/attribute.rb | 17 ++++++++ lib/arel/engines/sql/primitives/expression.rb | 7 ++++ lib/arel/engines/sql/primitives/value.rb | 11 +++++ lib/arel/engines/sql/relations.rb | 5 +++ lib/arel/engines/sql/relations/operations.rb | 2 + .../engines/sql/relations/operations/alias.rb | 5 +++ .../engines/sql/relations/operations/join.rb | 19 +++++++++ lib/arel/engines/sql/relations/relation.rb | 28 +++++++++++++ lib/arel/{ => engines/sql}/relations/table.rb | 0 lib/arel/engines/sql/relations/utilities.rb | 3 ++ .../relations/utilities/externalization.rb | 14 +++++++ .../engines/sql/relations/utilities/nil.rb | 6 +++ .../sql}/relations/utilities/recursion.rb | 0 lib/arel/engines/sql/relations/writes.rb | 3 ++ .../engines/sql/relations/writes/delete.rb | 12 ++++++ .../engines/sql/relations/writes/insert.rb | 12 ++++++ .../engines/sql/relations/writes/update.rb | 14 +++++++ lib/arel/engines/sql/sql.rb | 7 ++++ lib/arel/extensions.rb | 2 - lib/arel/extensions/array.rb | 8 ---- lib/arel/extensions/object.rb | 8 ---- lib/arel/predicates.rb | 15 ------- lib/arel/primitives/attribute.rb | 12 ------ lib/arel/primitives/expression.rb | 4 -- lib/arel/primitives/value.rb | 13 ------ lib/arel/relations.rb | 2 - lib/arel/relations/operations/alias.rb | 1 - lib/arel/relations/operations/join.rb | 16 ------- lib/arel/relations/relation.rb | 32 +------------- lib/arel/relations/utilities.rb | 2 - .../relations/utilities/externalization.rb | 10 ----- lib/arel/relations/utilities/nil.rb | 3 -- lib/arel/relations/writes/delete.rb | 9 ---- lib/arel/relations/writes/insert.rb | 9 ---- lib/arel/relations/writes/update.rb | 11 ----- lib/arel/sql.rb | 2 - spec/arel/unit/relations/skip_spec.rb | 2 +- spec/arel/unit/relations/table_spec.rb | 4 +- spec/arel/unit/relations/take_spec.rb | 2 +- spec/spec_helper.rb | 2 +- 56 files changed, 279 insertions(+), 208 deletions(-) delete mode 100644 lib/arel/engine.rb create mode 100644 lib/arel/engines.rb create mode 100644 lib/arel/engines/array/array.rb rename lib/arel/{ => engines/array}/relations/array.rb (100%) rename lib/arel/{ => engines}/sql/christener.rb (100%) create mode 100644 lib/arel/engines/sql/engine.rb create mode 100644 lib/arel/engines/sql/extensions.rb create mode 100644 lib/arel/engines/sql/extensions/array.rb rename lib/arel/{ => engines/sql}/extensions/nil_class.rb (100%) create mode 100644 lib/arel/engines/sql/extensions/object.rb rename lib/arel/{ => engines/sql}/extensions/range.rb (100%) rename lib/arel/{ => engines}/sql/formatters.rb (100%) create mode 100644 lib/arel/engines/sql/predicates.rb create mode 100644 lib/arel/engines/sql/primitives.rb create mode 100644 lib/arel/engines/sql/primitives/attribute.rb create mode 100644 lib/arel/engines/sql/primitives/expression.rb create mode 100644 lib/arel/engines/sql/primitives/value.rb create mode 100644 lib/arel/engines/sql/relations.rb create mode 100644 lib/arel/engines/sql/relations/operations.rb create mode 100644 lib/arel/engines/sql/relations/operations/alias.rb create mode 100644 lib/arel/engines/sql/relations/operations/join.rb create mode 100644 lib/arel/engines/sql/relations/relation.rb rename lib/arel/{ => engines/sql}/relations/table.rb (100%) create mode 100644 lib/arel/engines/sql/relations/utilities.rb create mode 100644 lib/arel/engines/sql/relations/utilities/externalization.rb create mode 100644 lib/arel/engines/sql/relations/utilities/nil.rb rename lib/arel/{ => engines/sql}/relations/utilities/recursion.rb (100%) create mode 100644 lib/arel/engines/sql/relations/writes.rb create mode 100644 lib/arel/engines/sql/relations/writes/delete.rb create mode 100644 lib/arel/engines/sql/relations/writes/insert.rb create mode 100644 lib/arel/engines/sql/relations/writes/update.rb create mode 100644 lib/arel/engines/sql/sql.rb delete mode 100644 lib/arel/sql.rb diff --git a/doc/TODO b/doc/TODO index ad1264088106c..8a8dcf5380794 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,5 @@ todo: - +- expressions should be class-based, and joins too, anything _sql should be renamed - refactor adapter pattern - implement in memory adapter - implement mnesia adapter diff --git a/lib/arel.rb b/lib/arel.rb index 00bfa1e2925c0..f22287fcc5ae2 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -7,9 +7,8 @@ require 'arel/arel' require 'arel/extensions' -require 'arel/sql' require 'arel/predicates' require 'arel/relations' -require 'arel/engine' +require 'arel/engines' require 'arel/session' require 'arel/primitives' diff --git a/lib/arel/engine.rb b/lib/arel/engine.rb deleted file mode 100644 index 2bb4bbbd904cd..0000000000000 --- a/lib/arel/engine.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Arel - # this file is currently just a hack to adapt between activerecord::base which holds the connection specification - # and active relation. ultimately, this file should be in effect what the connection specification is in active record; - # that is: a spec of the database (url, password, etc.), a quoting adapter layer, and a connection pool. - class Engine - def initialize(ar = nil) - @ar = ar - end - - def connection - @ar.connection - end - - def method_missing(method, *args, &block) - @ar.connection.send(method, *args, &block) - end - - module CRUD - def create(relation) - connection.insert(relation.to_sql) - end - - def read(relation) - results = connection.execute(relation.to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash - end - rows - end - - def update(relation) - connection.update(relation.to_sql) - end - - def delete(relation) - connection.delete(relation.to_sql) - end - end - include CRUD - end -end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb new file mode 100644 index 0000000000000..63a929528f6c5 --- /dev/null +++ b/lib/arel/engines.rb @@ -0,0 +1,2 @@ +require 'arel/engines/sql/sql' +require 'arel/engines/array/array' \ No newline at end of file diff --git a/lib/arel/engines/array/array.rb b/lib/arel/engines/array/array.rb new file mode 100644 index 0000000000000..3a3a47308a96c --- /dev/null +++ b/lib/arel/engines/array/array.rb @@ -0,0 +1 @@ +require 'arel/engines/array/relations/array' \ No newline at end of file diff --git a/lib/arel/relations/array.rb b/lib/arel/engines/array/relations/array.rb similarity index 100% rename from lib/arel/relations/array.rb rename to lib/arel/engines/array/relations/array.rb diff --git a/lib/arel/sql/christener.rb b/lib/arel/engines/sql/christener.rb similarity index 100% rename from lib/arel/sql/christener.rb rename to lib/arel/engines/sql/christener.rb diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb new file mode 100644 index 0000000000000..e5d1a8b0cad92 --- /dev/null +++ b/lib/arel/engines/sql/engine.rb @@ -0,0 +1,41 @@ +module Arel + module Sql + class Engine + def initialize(ar = nil) + @ar = ar + end + + def connection + @ar.connection + end + + def method_missing(method, *args, &block) + @ar.connection.send(method, *args, &block) + end + + module CRUD + def create(relation) + connection.insert(relation.to_sql) + end + + def read(relation) + results = connection.execute(relation.to_sql) + rows = [] + results.each do |row| + rows << attributes.zip(row).to_hash + end + rows + end + + def update(relation) + connection.update(relation.to_sql) + end + + def delete(relation) + connection.delete(relation.to_sql) + end + end + include CRUD + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions.rb b/lib/arel/engines/sql/extensions.rb new file mode 100644 index 0000000000000..6f4ad321485b2 --- /dev/null +++ b/lib/arel/engines/sql/extensions.rb @@ -0,0 +1,4 @@ +require 'arel/engines/sql/extensions/object' +require 'arel/engines/sql/extensions/array' +require 'arel/engines/sql/extensions/range' +require 'arel/engines/sql/extensions/nil_class' \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb new file mode 100644 index 0000000000000..1daa5abca7eeb --- /dev/null +++ b/lib/arel/engines/sql/extensions/array.rb @@ -0,0 +1,9 @@ +class Array + def to_sql(formatter = nil) + "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" + end + + def inclusion_predicate_sql + "IN" + end +end \ No newline at end of file diff --git a/lib/arel/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb similarity index 100% rename from lib/arel/extensions/nil_class.rb rename to lib/arel/engines/sql/extensions/nil_class.rb diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb new file mode 100644 index 0000000000000..ef990eee2f6a2 --- /dev/null +++ b/lib/arel/engines/sql/extensions/object.rb @@ -0,0 +1,9 @@ +class Object + def to_sql(formatter) + formatter.scalar self + end + + def equality_predicate_sql + '=' + end +end \ No newline at end of file diff --git a/lib/arel/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb similarity index 100% rename from lib/arel/extensions/range.rb rename to lib/arel/engines/sql/extensions/range.rb diff --git a/lib/arel/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb similarity index 100% rename from lib/arel/sql/formatters.rb rename to lib/arel/engines/sql/formatters.rb diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb new file mode 100644 index 0000000000000..dfeddb2de1fba --- /dev/null +++ b/lib/arel/engines/sql/predicates.rb @@ -0,0 +1,37 @@ +module Arel + class Binary < Predicate + def to_sql(formatter = nil) + "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" + end + end + + class Equality < Binary + def predicate_sql + operand2.equality_predicate_sql + end + end + + class GreaterThanOrEqualTo < Binary + def predicate_sql; '>=' end + end + + class GreaterThan < Binary + def predicate_sql; '>' end + end + + class LessThanOrEqualTo < Binary + def predicate_sql; '<=' end + end + + class LessThan < Binary + def predicate_sql; '<' end + end + + class Match < Binary + def predicate_sql; 'LIKE' end + end + + class In < Binary + def predicate_sql; operand2.inclusion_predicate_sql end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb new file mode 100644 index 0000000000000..405b1ca8038bb --- /dev/null +++ b/lib/arel/engines/sql/primitives.rb @@ -0,0 +1,3 @@ +require 'arel/engines/sql/primitives/attribute' +require 'arel/engines/sql/primitives/value' +require 'arel/engines/sql/primitives/expression' \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/attribute.rb b/lib/arel/engines/sql/primitives/attribute.rb new file mode 100644 index 0000000000000..48de690b6f868 --- /dev/null +++ b/lib/arel/engines/sql/primitives/attribute.rb @@ -0,0 +1,17 @@ +require 'set' + +module Arel + class Attribute + def column + original_relation.column_for(self) + end + + def format(object) + object.to_sql(Sql::Attribute.new(self)) + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/expression.rb b/lib/arel/engines/sql/primitives/expression.rb new file mode 100644 index 0000000000000..24f6879848492 --- /dev/null +++ b/lib/arel/engines/sql/primitives/expression.rb @@ -0,0 +1,7 @@ +module Arel + class Expression < Attribute + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/value.rb b/lib/arel/engines/sql/primitives/value.rb new file mode 100644 index 0000000000000..a44acc26e040d --- /dev/null +++ b/lib/arel/engines/sql/primitives/value.rb @@ -0,0 +1,11 @@ +module Arel + class Value + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.value value + end + + def format(object) + object.to_sql(Sql::Value.new(relation)) + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb new file mode 100644 index 0000000000000..4de01b2691274 --- /dev/null +++ b/lib/arel/engines/sql/relations.rb @@ -0,0 +1,5 @@ +require 'arel/engines/sql/relations/utilities' +require 'arel/engines/sql/relations/relation' +require 'arel/engines/sql/relations/operations' +require 'arel/engines/sql/relations/writes' +require 'arel/engines/sql/relations/table' \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/operations.rb b/lib/arel/engines/sql/relations/operations.rb new file mode 100644 index 0000000000000..ff33fc6bc3f97 --- /dev/null +++ b/lib/arel/engines/sql/relations/operations.rb @@ -0,0 +1,2 @@ +require 'arel/engines/sql/relations/operations/alias' +require 'arel/engines/sql/relations/operations/join' diff --git a/lib/arel/engines/sql/relations/operations/alias.rb b/lib/arel/engines/sql/relations/operations/alias.rb new file mode 100644 index 0000000000000..32c9911a69221 --- /dev/null +++ b/lib/arel/engines/sql/relations/operations/alias.rb @@ -0,0 +1,5 @@ +module Arel + class Alias < Compound + include Recursion::BaseCase + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb new file mode 100644 index 0000000000000..be21119bc95f5 --- /dev/null +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -0,0 +1,19 @@ +module Arel + class Join < Relation + def table_sql(formatter = Sql::TableReference.new(self)) + relation1.externalize.table_sql(formatter) + end + + def joins(environment, formatter = Sql::TableReference.new(environment)) + @joins ||= begin + this_join = [ + join_sql, + relation2.externalize.table_sql(formatter), + ("ON" unless predicates.blank?), + (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + ].compact.join(" ") + [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") + end + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb new file mode 100644 index 0000000000000..5fd4121176c29 --- /dev/null +++ b/lib/arel/engines/sql/relations/relation.rb @@ -0,0 +1,28 @@ +module Arel + class Relation + def to_sql(formatter = Sql::SelectStatement.new(self)) + formatter.select select_sql, self + end + + def select_sql + [ + "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "FROM #{table_sql(Sql::TableReference.new(self))}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), + ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), + ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) + ].compact.join("\n") + end + + def inclusion_predicate_sql + "IN" + end + + def christener + @christener ||= Sql::Christener.new + end + end +end \ No newline at end of file diff --git a/lib/arel/relations/table.rb b/lib/arel/engines/sql/relations/table.rb similarity index 100% rename from lib/arel/relations/table.rb rename to lib/arel/engines/sql/relations/table.rb diff --git a/lib/arel/engines/sql/relations/utilities.rb b/lib/arel/engines/sql/relations/utilities.rb new file mode 100644 index 0000000000000..a1451ed4488a9 --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities.rb @@ -0,0 +1,3 @@ +require 'arel/engines/sql/relations/utilities/recursion' +require 'arel/engines/sql/relations/utilities/externalization' +require 'arel/engines/sql/relations/utilities/nil' diff --git a/lib/arel/engines/sql/relations/utilities/externalization.rb b/lib/arel/engines/sql/relations/utilities/externalization.rb new file mode 100644 index 0000000000000..1ac6f2de8ebfd --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/externalization.rb @@ -0,0 +1,14 @@ +module Arel + class Externalization < Compound + include Recursion::BaseCase + + def table_sql(formatter = Sql::TableReference.new(relation)) + formatter.select relation.select_sql, self + end + + # REMOVEME + def name + relation.name + '_external' + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/utilities/nil.rb b/lib/arel/engines/sql/relations/utilities/nil.rb new file mode 100644 index 0000000000000..77534b25ade1c --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/nil.rb @@ -0,0 +1,6 @@ +module Arel + class Nil < Relation + def table_sql(formatter = nil); '' end + def name; '' end + end +end \ No newline at end of file diff --git a/lib/arel/relations/utilities/recursion.rb b/lib/arel/engines/sql/relations/utilities/recursion.rb similarity index 100% rename from lib/arel/relations/utilities/recursion.rb rename to lib/arel/engines/sql/relations/utilities/recursion.rb diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb new file mode 100644 index 0000000000000..dcadc326d92f9 --- /dev/null +++ b/lib/arel/engines/sql/relations/writes.rb @@ -0,0 +1,3 @@ +require 'arel/engines/sql/relations/writes/delete' +require 'arel/engines/sql/relations/writes/insert' +require 'arel/engines/sql/relations/writes/update' diff --git a/lib/arel/engines/sql/relations/writes/delete.rb b/lib/arel/engines/sql/relations/writes/delete.rb new file mode 100644 index 0000000000000..b22ee51e24e6c --- /dev/null +++ b/lib/arel/engines/sql/relations/writes/delete.rb @@ -0,0 +1,12 @@ +module Arel + class Deletion < Compound + def to_sql(formatter = nil) + [ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ].compact.join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/insert.rb b/lib/arel/engines/sql/relations/writes/insert.rb new file mode 100644 index 0000000000000..aac9c87a5bb6a --- /dev/null +++ b/lib/arel/engines/sql/relations/writes/insert.rb @@ -0,0 +1,12 @@ +module Arel + class Insert < Compound + def to_sql(formatter = nil) + [ + "INSERT", + "INTO #{table_sql}", + "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", + "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + ].join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/update.rb b/lib/arel/engines/sql/relations/writes/update.rb new file mode 100644 index 0000000000000..3e35a0d5cce57 --- /dev/null +++ b/lib/arel/engines/sql/relations/writes/update.rb @@ -0,0 +1,14 @@ +module Arel + class Update < Compound + def to_sql(formatter = nil) + [ + "UPDATE #{table_sql} SET", + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n"), + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) + ].join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/sql.rb b/lib/arel/engines/sql/sql.rb new file mode 100644 index 0000000000000..aed1fd861e2dd --- /dev/null +++ b/lib/arel/engines/sql/sql.rb @@ -0,0 +1,7 @@ +require 'arel/engines/sql/engine' +require 'arel/engines/sql/relations' +require 'arel/engines/sql/primitives' +require 'arel/engines/sql/predicates' +require 'arel/engines/sql/formatters' +require 'arel/engines/sql/extensions' +require 'arel/engines/sql/christener' \ No newline at end of file diff --git a/lib/arel/extensions.rb b/lib/arel/extensions.rb index 160cf36e5b379..299ba0631ca87 100644 --- a/lib/arel/extensions.rb +++ b/lib/arel/extensions.rb @@ -2,5 +2,3 @@ require 'arel/extensions/class' require 'arel/extensions/array' require 'arel/extensions/hash' -require 'arel/extensions/range' -require 'arel/extensions/nil_class' \ No newline at end of file diff --git a/lib/arel/extensions/array.rb b/lib/arel/extensions/array.rb index 793c06aad8d7c..5b6d6d6abd537 100644 --- a/lib/arel/extensions/array.rb +++ b/lib/arel/extensions/array.rb @@ -2,12 +2,4 @@ class Array def to_hash Hash[*flatten] end - - def to_sql(formatter = nil) - "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" - end - - def inclusion_predicate_sql - "IN" - end end \ No newline at end of file diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index 14e2f82ce52d1..d626407dcb801 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -7,14 +7,6 @@ def find_correlate_in(relation) bind(relation) end - def to_sql(formatter) - formatter.scalar self - end - - def equality_predicate_sql - '=' - end - def metaclass class << self self diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index b639022b4e1f3..aa206d4e9643c 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -22,11 +22,6 @@ def ==(other) def bind(relation) self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end - - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" - end - alias_method :to_s, :to_sql end class CompoundPredicate < Binary @@ -49,33 +44,23 @@ def ==(other) ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end - - def predicate_sql - operand2.equality_predicate_sql - end end class GreaterThanOrEqualTo < Binary - def predicate_sql; '>=' end end class GreaterThan < Binary - def predicate_sql; '>' end end class LessThanOrEqualTo < Binary - def predicate_sql; '<=' end end class LessThan < Binary - def predicate_sql; '<' end end class Match < Binary - def predicate_sql; 'LIKE' end end class In < Binary - def predicate_sql; operand2.inclusion_predicate_sql end end end diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 6cb558d8ce342..5e216770e4b5f 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -18,18 +18,6 @@ def aggregation? false end - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - module Transformations def self.included(klass) klass.send :alias_method, :eql?, :== diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 836f0147456ae..b67a5e1f8efbf 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -9,10 +9,6 @@ def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor end - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - def aggregation? true end diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 9c6e518a95764..91c4045507084 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -4,19 +4,6 @@ class Value deriving :initialize, :== delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - if value =~ /^\(.*\)$/ - value - else - formatter.value value - end - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - def bind(relation) Value.new(value, relation) end diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index fd758ed15d9aa..f97c35e56e26b 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -1,6 +1,4 @@ require 'arel/relations/relation' require 'arel/relations/utilities' -require 'arel/relations/table' -require 'arel/relations/array' require 'arel/relations/writes' require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/operations/alias.rb b/lib/arel/relations/operations/alias.rb index 8ed33fc5978cf..67837f6a7544d 100644 --- a/lib/arel/relations/operations/alias.rb +++ b/lib/arel/relations/operations/alias.rb @@ -1,6 +1,5 @@ module Arel class Alias < Compound - include Recursion::BaseCase attributes :relation deriving :initialize alias_method :==, :equal? diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index 8fe89358d84f2..8e19254378b2c 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -9,22 +9,6 @@ def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end - def table_sql(formatter = Sql::TableReference.new(self)) - relation1.externalize.table_sql(formatter) - end - - def joins(environment, formatter = Sql::TableReference.new(environment)) - @joins ||= begin - this_join = [ - join_sql, - relation2.externalize.table_sql(formatter), - ("ON" unless predicates.blank?), - (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') - ].compact.join(" ") - [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") - end - end - def attributes @attributes ||= (relation1.externalize.attributes + relation2.externalize.attributes).collect { |a| a.bind(self) } diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index ef295dfdd78ad..20badaf165be4 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -6,32 +6,6 @@ def session Session.new end - def count - @count = "COUNT(*) AS count_all" - end - - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select select_sql, self - end - alias_method :to_s, :to_sql - - def select_sql - [ - "SELECT #{@count} #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ') unless @count}", - "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), - ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n") - end - - def inclusion_predicate_sql - "IN" - end - def call engine.read(self) end @@ -44,10 +18,6 @@ def root self end - def christener - @christener ||= Sql::Christener.new - end - module Enumerable include ::Enumerable @@ -155,7 +125,7 @@ def wheres; [] end def orders; [] end def inserts; [] end def groupings; [] end - def joins(formatter = nil); nil end + def joins(formatter = nil); nil end # FIXME def taken; nil end def skipped; nil end end diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb index 454d455359156..fbd949ef0c8d3 100644 --- a/lib/arel/relations/utilities.rb +++ b/lib/arel/relations/utilities.rb @@ -1,5 +1,3 @@ require 'arel/relations/utilities/compound' -require 'arel/relations/utilities/recursion' require 'arel/relations/utilities/nil' require 'arel/relations/utilities/externalization' -require 'arel/relations/utilities/recursion' \ No newline at end of file diff --git a/lib/arel/relations/utilities/externalization.rb b/lib/arel/relations/utilities/externalization.rb index 3b9b2296dc2c2..bd067f230441a 100644 --- a/lib/arel/relations/utilities/externalization.rb +++ b/lib/arel/relations/utilities/externalization.rb @@ -2,24 +2,14 @@ module Arel class Externalization < Compound attributes :relation deriving :initialize, :== - include Recursion::BaseCase def wheres [] end - def table_sql(formatter = Sql::TableReference.new(relation)) - formatter.select relation.select_sql, self - end - def attributes @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } end - - # REMOVEME - def name - relation.name + '_external' - end end class Relation diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/relations/utilities/nil.rb index 56cf395d2c473..6a9d678c45de4 100644 --- a/lib/arel/relations/utilities/nil.rb +++ b/lib/arel/relations/utilities/nil.rb @@ -3,8 +3,5 @@ module Arel class Nil < Relation include Singleton - - def table_sql(formatter = nil); '' end - def name; '' end end end diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index 0a04454e7f648..a94067c7fab01 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -3,15 +3,6 @@ class Deletion < Compound attributes :relation deriving :initialize, :== - def to_sql(formatter = nil) - [ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") - end - def call engine.delete(self) end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb index d05bd9cdc821d..6d85e9769a08d 100644 --- a/lib/arel/relations/writes/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -7,15 +7,6 @@ def initialize(relation, record) @relation, @record = relation, record.bind(relation) end - def to_sql(formatter = nil) - [ - "INSERT", - "INTO #{table_sql}", - "(#{record.keys.map { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.map { |key, value| key.format(value) }.join(', ')})" - ].join("\n") - end - def call engine.create(self) end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index fd0aadb479a5d..e647218a80556 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -7,17 +7,6 @@ def initialize(relation, assignments) @relation, @assignments = relation, assignments end - def to_sql(formatter = nil) - [ - "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), - ("WHERE #{wheres.map(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") - end - def call engine.update(self) end diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb deleted file mode 100644 index 7e7dd0a80fb93..0000000000000 --- a/lib/arel/sql.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/sql/formatters' -require 'arel/sql/christener' \ No newline at end of file diff --git a/spec/arel/unit/relations/skip_spec.rb b/spec/arel/unit/relations/skip_spec.rb index 0653d795b10f7..2c8f6ccadb613 100644 --- a/spec/arel/unit/relations/skip_spec.rb +++ b/spec/arel/unit/relations/skip_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - sql = Skip.new(@relation, @skipped).to_s + sql = Skip.new(@relation, @skipped).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index 08486c7b6ce8b..211e6921f81d8 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -87,12 +87,12 @@ module Arel describe '#engine' do it "defaults to global engine" do - Table.engine = engine = Engine.new + Table.engine = engine = Sql::Engine.new Table.new(:users).engine.should == engine end it "can be specified" do - Table.new(:users, engine = Engine.new).engine.should == engine + Table.new(:users, engine = Sql::Engine.new).engine.should == engine end end end diff --git a/spec/arel/unit/relations/take_spec.rb b/spec/arel/unit/relations/take_spec.rb index 911b84e01e7ad..d6442fc9d1458 100644 --- a/spec/arel/unit/relations/take_spec.rb +++ b/spec/arel/unit/relations/take_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - sql = Take.new(@relation, @taken).to_s + sql = Take.new(@relation, @taken).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8d515d66f1a64..6a9a2ef23c8ce 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,6 +30,6 @@ def adapter_name config.include AdapterGuards config.mock_with :rr config.before do - Arel::Table.engine = Arel::Engine.new(ActiveRecord::Base) + Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) end end From 7032a50297fce4d7724d1735e81e5df5fd919e71 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:31:04 -0400 Subject: [PATCH 0215/1492] reorganized file structures Conflicts: lib/arel.rb lib/arel/arel.rb lib/arel/engines/memory/predicates.rb lib/arel/engines/memory/relations/array.rb lib/arel/engines/sql/relations/table.rb --- README.markdown | 6 +-- lib/arel.rb | 6 +-- lib/arel/algebra.rb | 4 ++ lib/arel/algebra/extensions.rb | 4 ++ lib/arel/{ => algebra}/extensions/array.rb | 0 lib/arel/{ => algebra}/extensions/class.rb | 0 lib/arel/{ => algebra}/extensions/hash.rb | 0 lib/arel/{ => algebra}/extensions/object.rb | 0 lib/arel/algebra/extensions/pathname.rb | 5 +++ lib/arel/algebra/predicates.rb | 45 +++++++++++++++++++ lib/arel/algebra/primitives.rb | 4 ++ .../{ => algebra}/primitives/attribute.rb | 0 .../{ => algebra}/primitives/expression.rb | 0 lib/arel/{ => algebra}/primitives/value.rb | 0 lib/arel/algebra/relations.rb | 15 +++++++ .../relations/operations/alias.rb | 0 .../relations/operations/group.rb | 0 .../relations/operations/join.rb | 0 .../relations/operations/order.rb | 0 .../relations/operations/project.rb | 0 .../relations/operations/skip.rb | 0 .../relations/operations/take.rb | 0 .../relations/operations/where.rb | 0 lib/arel/{ => algebra}/relations/relation.rb | 0 .../relations/utilities/compound.rb | 2 +- .../relations/utilities/externalization.rb | 0 .../{ => algebra}/relations/utilities/nil.rb | 0 .../{ => algebra}/relations/writes/delete.rb | 0 .../{ => algebra}/relations/writes/insert.rb | 0 .../{ => algebra}/relations/writes/update.rb | 0 lib/arel/arel.rb | 3 -- lib/arel/engines.rb | 4 +- lib/arel/engines/array/array.rb | 1 - lib/arel/engines/memory.rb | 4 ++ lib/arel/engines/memory/engine.rb | 12 +++++ lib/arel/{ => engines/memory}/predicates.rb | 14 ++---- lib/arel/engines/memory/primitives.rb | 2 + .../engines/memory/primitives/attribute.rb | 7 +++ lib/arel/engines/memory/primitives/value.rb | 7 +++ lib/arel/engines/memory/relations.rb | 2 + .../{array => memory}/relations/array.rb | 10 +++-- .../memory/relations/operations/where.rb | 7 +++ lib/arel/engines/{sql => }/sql.rb | 0 lib/arel/engines/sql/primitives/attribute.rb | 2 - lib/arel/engines/sql/relations.rb | 13 ++++-- lib/arel/engines/sql/relations/operations.rb | 2 - lib/arel/engines/sql/relations/table.rb | 5 +++ lib/arel/engines/sql/relations/utilities.rb | 3 -- lib/arel/engines/sql/relations/writes.rb | 3 -- lib/arel/extensions.rb | 4 -- lib/arel/primitives.rb | 4 -- lib/arel/relations.rb | 4 -- lib/arel/relations/operations.rb | 8 ---- lib/arel/relations/utilities.rb | 3 -- lib/arel/relations/writes.rb | 3 -- lib/arel/session.rb | 2 - .../integration/joins/with_adjacency_spec.rb | 2 +- .../joins/with_aggregations_spec.rb | 4 +- .../integration/joins/with_compounds_spec.rb | 4 +- spec/arel/unit/relations/array_spec.rb | 7 +++ 60 files changed, 160 insertions(+), 77 deletions(-) create mode 100644 lib/arel/algebra.rb create mode 100644 lib/arel/algebra/extensions.rb rename lib/arel/{ => algebra}/extensions/array.rb (100%) rename lib/arel/{ => algebra}/extensions/class.rb (100%) rename lib/arel/{ => algebra}/extensions/hash.rb (100%) rename lib/arel/{ => algebra}/extensions/object.rb (100%) create mode 100644 lib/arel/algebra/extensions/pathname.rb create mode 100644 lib/arel/algebra/predicates.rb create mode 100644 lib/arel/algebra/primitives.rb rename lib/arel/{ => algebra}/primitives/attribute.rb (100%) rename lib/arel/{ => algebra}/primitives/expression.rb (100%) rename lib/arel/{ => algebra}/primitives/value.rb (100%) create mode 100644 lib/arel/algebra/relations.rb rename lib/arel/{ => algebra}/relations/operations/alias.rb (100%) rename lib/arel/{ => algebra}/relations/operations/group.rb (100%) rename lib/arel/{ => algebra}/relations/operations/join.rb (100%) rename lib/arel/{ => algebra}/relations/operations/order.rb (100%) rename lib/arel/{ => algebra}/relations/operations/project.rb (100%) rename lib/arel/{ => algebra}/relations/operations/skip.rb (100%) rename lib/arel/{ => algebra}/relations/operations/take.rb (100%) rename lib/arel/{ => algebra}/relations/operations/where.rb (100%) rename lib/arel/{ => algebra}/relations/relation.rb (100%) rename lib/arel/{ => algebra}/relations/utilities/compound.rb (89%) rename lib/arel/{ => algebra}/relations/utilities/externalization.rb (100%) rename lib/arel/{ => algebra}/relations/utilities/nil.rb (100%) rename lib/arel/{ => algebra}/relations/writes/delete.rb (100%) rename lib/arel/{ => algebra}/relations/writes/insert.rb (100%) rename lib/arel/{ => algebra}/relations/writes/update.rb (100%) delete mode 100644 lib/arel/arel.rb delete mode 100644 lib/arel/engines/array/array.rb create mode 100644 lib/arel/engines/memory.rb create mode 100644 lib/arel/engines/memory/engine.rb rename lib/arel/{ => engines/memory}/predicates.rb (75%) create mode 100644 lib/arel/engines/memory/primitives.rb create mode 100644 lib/arel/engines/memory/primitives/attribute.rb create mode 100644 lib/arel/engines/memory/primitives/value.rb create mode 100644 lib/arel/engines/memory/relations.rb rename lib/arel/engines/{array => memory}/relations/array.rb (67%) create mode 100644 lib/arel/engines/memory/relations/operations/where.rb rename lib/arel/engines/{sql => }/sql.rb (100%) delete mode 100644 lib/arel/engines/sql/relations/operations.rb delete mode 100644 lib/arel/engines/sql/relations/utilities.rb delete mode 100644 lib/arel/engines/sql/relations/writes.rb delete mode 100644 lib/arel/extensions.rb delete mode 100644 lib/arel/primitives.rb delete mode 100644 lib/arel/relations.rb delete mode 100644 lib/arel/relations/operations.rb delete mode 100644 lib/arel/relations/utilities.rb delete mode 100644 lib/arel/relations/writes.rb diff --git a/README.markdown b/README.markdown index e979dbc2a39d0..4d95234423454 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: - users = Arel(:users) + users = Table(:users) users.to_sql In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: @@ -81,7 +81,7 @@ The `AND` operator will behave similarly. Finally, most operations take a block form. For example: - Arel(:users) \ + Table(:users) \ .where { |u| u[:id].eq(1) } \ .project { |u| u[:id] } @@ -95,7 +95,7 @@ The examples above are fairly simple and other libraries match or come close to 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(:comments) + comments = Table(:comments) And this table has the following attributes: diff --git a/lib/arel.rb b/lib/arel.rb index f22287fcc5ae2..fcca60758ed7b 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -5,10 +5,6 @@ require 'activerecord' require 'active_record/connection_adapters/abstract/quoting' -require 'arel/arel' -require 'arel/extensions' -require 'arel/predicates' -require 'arel/relations' +require 'arel/algebra' require 'arel/engines' require 'arel/session' -require 'arel/primitives' diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb new file mode 100644 index 0000000000000..f27882a343df0 --- /dev/null +++ b/lib/arel/algebra.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/extensions' +require 'arel/algebra/predicates' +require 'arel/algebra/relations' +require 'arel/algebra/primitives' \ No newline at end of file diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb new file mode 100644 index 0000000000000..5338fee989dd0 --- /dev/null +++ b/lib/arel/algebra/extensions.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/extensions/object' +require 'arel/algebra/extensions/class' +require 'arel/algebra/extensions/array' +require 'arel/algebra/extensions/hash' diff --git a/lib/arel/extensions/array.rb b/lib/arel/algebra/extensions/array.rb similarity index 100% rename from lib/arel/extensions/array.rb rename to lib/arel/algebra/extensions/array.rb diff --git a/lib/arel/extensions/class.rb b/lib/arel/algebra/extensions/class.rb similarity index 100% rename from lib/arel/extensions/class.rb rename to lib/arel/algebra/extensions/class.rb diff --git a/lib/arel/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb similarity index 100% rename from lib/arel/extensions/hash.rb rename to lib/arel/algebra/extensions/hash.rb diff --git a/lib/arel/extensions/object.rb b/lib/arel/algebra/extensions/object.rb similarity index 100% rename from lib/arel/extensions/object.rb rename to lib/arel/algebra/extensions/object.rb diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb new file mode 100644 index 0000000000000..2f7e2733e74fa --- /dev/null +++ b/lib/arel/algebra/extensions/pathname.rb @@ -0,0 +1,5 @@ +class Pathname + def /(path) + (self + path).expand_path + end +end \ No newline at end of file diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb new file mode 100644 index 0000000000000..f83101306ef2c --- /dev/null +++ b/lib/arel/algebra/predicates.rb @@ -0,0 +1,45 @@ +module Arel + class Predicate + end + + class Binary < Predicate + attributes :operand1, :operand2 + deriving :initialize + + def ==(other) + self.class === other and + @operand1 == other.operand1 and + @operand2 == other.operand2 + end + + def bind(relation) + self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) + end + end + + class Equality < Binary + def ==(other) + Equality === other and + ((operand1 == other.operand1 and operand2 == other.operand2) or + (operand1 == other.operand2 and operand2 == other.operand1)) + end + end + + class GreaterThanOrEqualTo < Binary + end + + class GreaterThan < Binary + end + + class LessThanOrEqualTo < Binary + end + + class LessThan < Binary + end + + class Match < Binary + end + + class In < Binary + end +end \ No newline at end of file diff --git a/lib/arel/algebra/primitives.rb b/lib/arel/algebra/primitives.rb new file mode 100644 index 0000000000000..a4c3169e0b9a0 --- /dev/null +++ b/lib/arel/algebra/primitives.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/primitives/attribute' +require 'arel/algebra/primitives/value' +require 'arel/algebra/primitives/expression' + diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb similarity index 100% rename from lib/arel/primitives/attribute.rb rename to lib/arel/algebra/primitives/attribute.rb diff --git a/lib/arel/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb similarity index 100% rename from lib/arel/primitives/expression.rb rename to lib/arel/algebra/primitives/expression.rb diff --git a/lib/arel/primitives/value.rb b/lib/arel/algebra/primitives/value.rb similarity index 100% rename from lib/arel/primitives/value.rb rename to lib/arel/algebra/primitives/value.rb diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb new file mode 100644 index 0000000000000..03f04d2459350 --- /dev/null +++ b/lib/arel/algebra/relations.rb @@ -0,0 +1,15 @@ +require 'arel/algebra/relations/relation' +require 'arel/algebra/relations/utilities/compound' +require 'arel/algebra/relations/utilities/nil' +require 'arel/algebra/relations/utilities/externalization' +require 'arel/algebra/relations/writes/delete' +require 'arel/algebra/relations/writes/update' +require 'arel/algebra/relations/writes/insert' +require 'arel/algebra/relations/operations/alias' +require 'arel/algebra/relations/operations/group' +require 'arel/algebra/relations/operations/join' +require 'arel/algebra/relations/operations/order' +require 'arel/algebra/relations/operations/project' +require 'arel/algebra/relations/operations/where' +require 'arel/algebra/relations/operations/skip' +require 'arel/algebra/relations/operations/take' \ No newline at end of file diff --git a/lib/arel/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb similarity index 100% rename from lib/arel/relations/operations/alias.rb rename to lib/arel/algebra/relations/operations/alias.rb diff --git a/lib/arel/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb similarity index 100% rename from lib/arel/relations/operations/group.rb rename to lib/arel/algebra/relations/operations/group.rb diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb similarity index 100% rename from lib/arel/relations/operations/join.rb rename to lib/arel/algebra/relations/operations/join.rb diff --git a/lib/arel/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb similarity index 100% rename from lib/arel/relations/operations/order.rb rename to lib/arel/algebra/relations/operations/order.rb diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb similarity index 100% rename from lib/arel/relations/operations/project.rb rename to lib/arel/algebra/relations/operations/project.rb diff --git a/lib/arel/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb similarity index 100% rename from lib/arel/relations/operations/skip.rb rename to lib/arel/algebra/relations/operations/skip.rb diff --git a/lib/arel/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb similarity index 100% rename from lib/arel/relations/operations/take.rb rename to lib/arel/algebra/relations/operations/take.rb diff --git a/lib/arel/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb similarity index 100% rename from lib/arel/relations/operations/where.rb rename to lib/arel/algebra/relations/operations/where.rb diff --git a/lib/arel/relations/relation.rb b/lib/arel/algebra/relations/relation.rb similarity index 100% rename from lib/arel/relations/relation.rb rename to lib/arel/algebra/relations/relation.rb diff --git a/lib/arel/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb similarity index 89% rename from lib/arel/relations/utilities/compound.rb rename to lib/arel/algebra/relations/utilities/compound.rb index b1e8054d4d496..e33b8dbf141b0 100644 --- a/lib/arel/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -3,7 +3,7 @@ class Compound < Relation attr_reader :relation hash_on :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :table, :table_sql, + :column_for, :engine, :table, :table_sql, :array, :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| diff --git a/lib/arel/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb similarity index 100% rename from lib/arel/relations/utilities/externalization.rb rename to lib/arel/algebra/relations/utilities/externalization.rb diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/algebra/relations/utilities/nil.rb similarity index 100% rename from lib/arel/relations/utilities/nil.rb rename to lib/arel/algebra/relations/utilities/nil.rb diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/algebra/relations/writes/delete.rb similarity index 100% rename from lib/arel/relations/writes/delete.rb rename to lib/arel/algebra/relations/writes/delete.rb diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/algebra/relations/writes/insert.rb similarity index 100% rename from lib/arel/relations/writes/insert.rb rename to lib/arel/algebra/relations/writes/insert.rb diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/algebra/relations/writes/update.rb similarity index 100% rename from lib/arel/relations/writes/update.rb rename to lib/arel/algebra/relations/writes/update.rb diff --git a/lib/arel/arel.rb b/lib/arel/arel.rb deleted file mode 100644 index 7780d45e25d1b..0000000000000 --- a/lib/arel/arel.rb +++ /dev/null @@ -1,3 +0,0 @@ -def Arel(name, engine = (Arel::Table.engine || ActiveRecord::Base.connection)) - Arel::Table.new(name, engine) -end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb index 63a929528f6c5..3f854edf90073 100644 --- a/lib/arel/engines.rb +++ b/lib/arel/engines.rb @@ -1,2 +1,2 @@ -require 'arel/engines/sql/sql' -require 'arel/engines/array/array' \ No newline at end of file +require 'arel/engines/sql' +require 'arel/engines/memory' \ No newline at end of file diff --git a/lib/arel/engines/array/array.rb b/lib/arel/engines/array/array.rb deleted file mode 100644 index 3a3a47308a96c..0000000000000 --- a/lib/arel/engines/array/array.rb +++ /dev/null @@ -1 +0,0 @@ -require 'arel/engines/array/relations/array' \ No newline at end of file diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb new file mode 100644 index 0000000000000..df6f6f3d4813a --- /dev/null +++ b/lib/arel/engines/memory.rb @@ -0,0 +1,4 @@ +require 'arel/engines/memory/relations' +require 'arel/engines/memory/primitives' +require 'arel/engines/memory/engine' +require 'arel/engines/memory/predicates' \ No newline at end of file diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb new file mode 100644 index 0000000000000..67a084f2cdeba --- /dev/null +++ b/lib/arel/engines/memory/engine.rb @@ -0,0 +1,12 @@ +module Arel + module Memory + class Engine + module CRUD + def read(relation) + relation.eval + end + end + include CRUD + end + end +end \ No newline at end of file diff --git a/lib/arel/predicates.rb b/lib/arel/engines/memory/predicates.rb similarity index 75% rename from lib/arel/predicates.rb rename to lib/arel/engines/memory/predicates.rb index aa206d4e9643c..3522ea3ffafc8 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -10,17 +10,8 @@ def and(other_predicate) end class Binary < Predicate - attributes :operand1, :operand2 - deriving :initialize - - def ==(other) - self.class === other and - @operand1 == other.operand1 and - @operand2 == other.operand2 - end - - def bind(relation) - self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) + def eval(row) + operand1.eval(row).send(operator, operand2.eval(row)) end end @@ -56,6 +47,7 @@ class LessThanOrEqualTo < Binary end class LessThan < Binary + def operator; :< end end class Match < Binary diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb new file mode 100644 index 0000000000000..4d5c76e956acb --- /dev/null +++ b/lib/arel/engines/memory/primitives.rb @@ -0,0 +1,2 @@ +require 'arel/engines/memory/primitives/attribute' +require 'arel/engines/memory/primitives/value' diff --git a/lib/arel/engines/memory/primitives/attribute.rb b/lib/arel/engines/memory/primitives/attribute.rb new file mode 100644 index 0000000000000..9864feadc2ff1 --- /dev/null +++ b/lib/arel/engines/memory/primitives/attribute.rb @@ -0,0 +1,7 @@ +module Arel + class Attribute + def eval(row) + row[self] + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives/value.rb b/lib/arel/engines/memory/primitives/value.rb new file mode 100644 index 0000000000000..b83cd02e57dc0 --- /dev/null +++ b/lib/arel/engines/memory/primitives/value.rb @@ -0,0 +1,7 @@ +module Arel + class Value + def eval(row) + value + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb new file mode 100644 index 0000000000000..6361d7c9d7d2d --- /dev/null +++ b/lib/arel/engines/memory/relations.rb @@ -0,0 +1,2 @@ +require 'arel/engines/memory/relations/array' +require 'arel/engines/memory/relations/operations/where' diff --git a/lib/arel/engines/array/relations/array.rb b/lib/arel/engines/memory/relations/array.rb similarity index 67% rename from lib/arel/engines/array/relations/array.rb rename to lib/arel/engines/memory/relations/array.rb index dac65abbc2228..c02c62891b25c 100644 --- a/lib/arel/engines/array/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -1,9 +1,11 @@ module Arel class Array < Relation + attributes :array, :attribute_names + deriving :initialize include Recursion::BaseCase - - def initialize(array, attribute_names) - @array, @attribute_names = array, attribute_names + + def engine + @engine ||= Memory::Engine.new end def attributes @@ -12,7 +14,7 @@ def attributes end end - def call(connection = nil) + def eval @array.collect { |row| attributes.zip(row).to_hash } end end diff --git a/lib/arel/engines/memory/relations/operations/where.rb b/lib/arel/engines/memory/relations/operations/where.rb new file mode 100644 index 0000000000000..eb11fb55fd0f6 --- /dev/null +++ b/lib/arel/engines/memory/relations/operations/where.rb @@ -0,0 +1,7 @@ +module Arel + class Where < Compound + def eval + relation.eval.select { |row| predicate.eval(row) } + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/sql.rb b/lib/arel/engines/sql.rb similarity index 100% rename from lib/arel/engines/sql/sql.rb rename to lib/arel/engines/sql.rb diff --git a/lib/arel/engines/sql/primitives/attribute.rb b/lib/arel/engines/sql/primitives/attribute.rb index 48de690b6f868..ad78a9ec5b590 100644 --- a/lib/arel/engines/sql/primitives/attribute.rb +++ b/lib/arel/engines/sql/primitives/attribute.rb @@ -1,5 +1,3 @@ -require 'set' - module Arel class Attribute def column diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 4de01b2691274..39ef8852a1dba 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -1,5 +1,10 @@ -require 'arel/engines/sql/relations/utilities' +require 'arel/engines/sql/relations/utilities/recursion' +require 'arel/engines/sql/relations/utilities/externalization' +require 'arel/engines/sql/relations/utilities/nil' require 'arel/engines/sql/relations/relation' -require 'arel/engines/sql/relations/operations' -require 'arel/engines/sql/relations/writes' -require 'arel/engines/sql/relations/table' \ No newline at end of file +require 'arel/engines/sql/relations/table' +require 'arel/engines/sql/relations/operations/join' +require 'arel/engines/sql/relations/operations/alias' +require 'arel/engines/sql/relations/writes/delete' +require 'arel/engines/sql/relations/writes/insert' +require 'arel/engines/sql/relations/writes/update' \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/operations.rb b/lib/arel/engines/sql/relations/operations.rb deleted file mode 100644 index ff33fc6bc3f97..0000000000000 --- a/lib/arel/engines/sql/relations/operations.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/engines/sql/relations/operations/alias' -require 'arel/engines/sql/relations/operations/join' diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 0433abbbb24fb..2653744149ab9 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -34,3 +34,8 @@ def ==(other) end end end + +def Table(name, engine = Arel::Table.engine) + Arel::Table.new(name, engine) +end + diff --git a/lib/arel/engines/sql/relations/utilities.rb b/lib/arel/engines/sql/relations/utilities.rb deleted file mode 100644 index a1451ed4488a9..0000000000000 --- a/lib/arel/engines/sql/relations/utilities.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/engines/sql/relations/utilities/recursion' -require 'arel/engines/sql/relations/utilities/externalization' -require 'arel/engines/sql/relations/utilities/nil' diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb deleted file mode 100644 index dcadc326d92f9..0000000000000 --- a/lib/arel/engines/sql/relations/writes.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/engines/sql/relations/writes/delete' -require 'arel/engines/sql/relations/writes/insert' -require 'arel/engines/sql/relations/writes/update' diff --git a/lib/arel/extensions.rb b/lib/arel/extensions.rb deleted file mode 100644 index 299ba0631ca87..0000000000000 --- a/lib/arel/extensions.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/extensions/object' -require 'arel/extensions/class' -require 'arel/extensions/array' -require 'arel/extensions/hash' diff --git a/lib/arel/primitives.rb b/lib/arel/primitives.rb deleted file mode 100644 index d84713d3d51d0..0000000000000 --- a/lib/arel/primitives.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/primitives/attribute' -require 'arel/primitives/value' -require 'arel/primitives/expression' - diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb deleted file mode 100644 index f97c35e56e26b..0000000000000 --- a/lib/arel/relations.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/relations/relation' -require 'arel/relations/utilities' -require 'arel/relations/writes' -require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/operations.rb b/lib/arel/relations/operations.rb deleted file mode 100644 index c598c7fcc9ab9..0000000000000 --- a/lib/arel/relations/operations.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'arel/relations/operations/alias' -require 'arel/relations/operations/group' -require 'arel/relations/operations/join' -require 'arel/relations/operations/order' -require 'arel/relations/operations/project' -require 'arel/relations/operations/where' -require 'arel/relations/operations/skip' -require 'arel/relations/operations/take' \ No newline at end of file diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb deleted file mode 100644 index fbd949ef0c8d3..0000000000000 --- a/lib/arel/relations/utilities.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/relations/utilities/compound' -require 'arel/relations/utilities/nil' -require 'arel/relations/utilities/externalization' diff --git a/lib/arel/relations/writes.rb b/lib/arel/relations/writes.rb deleted file mode 100644 index 1495d9c8575e0..0000000000000 --- a/lib/arel/relations/writes.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/relations/writes/delete' -require 'arel/relations/writes/update' -require 'arel/relations/writes/insert' \ No newline at end of file diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 9c2ddc535b2ba..cf04e8a93a61d 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -1,5 +1,3 @@ -require 'singleton' - module Arel class Session class << self diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index fbac723e10cf8..ffd6498749f88 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -3,7 +3,7 @@ module Arel describe Join do before do - @relation1 = Arel(:users) + @relation1 = Table(:users) @relation2 = @relation1.alias @predicate = @relation1[:id].eq(@relation2[:id]) end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 41978c0a5abaf..4aba005d5185d 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -3,8 +3,8 @@ module Arel describe Join do before do - @relation1 = Arel(:users) - @relation2 = Arel(:photos) + @relation1 = Table(:users) + @relation2 = Table(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 7582c5fc83022..41f04349b8bb1 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -3,8 +3,8 @@ module Arel describe Join do before do - @relation1 = Arel(:users) - @relation2 = Arel(:photos) + @relation1 = Table(:users) + @relation2 = Table(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb index 1330f0f2055db..c90843cd7d8b4 100644 --- a/spec/arel/unit/relations/array_spec.rb +++ b/spec/arel/unit/relations/array_spec.rb @@ -22,6 +22,13 @@ module Arel { @relation[:id] => 3 } ] end + + it '' do + @relation.where(@relation[:id].lt(3)).call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 } + ] + end end end end \ No newline at end of file From b0a45d52fdb7d8ce564f4dc2013bc790f98f1da3 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:38:09 -0400 Subject: [PATCH 0216/1492] consolidated files Conflicts: lib/arel/algebra/predicates.rb lib/arel/algebra/relations/writes/delete.rb lib/arel/algebra/relations/writes/insert.rb lib/arel/algebra/relations/writes/update.rb lib/arel/engines/memory/predicates.rb lib/arel/engines/memory/relations.rb lib/arel/engines/sql/primitives/attribute.rb lib/arel/engines/sql/relations/writes/insert.rb lib/arel/engines/sql/relations/writes/update.rb --- lib/arel/algebra/predicates.rb | 30 +++++++--------- lib/arel/algebra/relations.rb | 4 +-- lib/arel/algebra/relations/writes.rb | 36 +++++++++++++++++++ lib/arel/algebra/relations/writes/delete.rb | 10 ------ lib/arel/algebra/relations/writes/insert.rb | 14 -------- lib/arel/algebra/relations/writes/update.rb | 14 -------- lib/arel/engines/memory/predicates.rb | 14 -------- lib/arel/engines/memory/primitives.rb | 15 ++++++-- .../engines/memory/primitives/attribute.rb | 7 ---- lib/arel/engines/memory/primitives/value.rb | 7 ---- lib/arel/engines/memory/relations.rb | 3 +- .../{operations/where.rb => operations.rb} | 0 lib/arel/engines/sql/primitives.rb | 34 ++++++++++++++++-- lib/arel/engines/sql/primitives/attribute.rb | 15 -------- lib/arel/engines/sql/primitives/expression.rb | 7 ---- lib/arel/engines/sql/primitives/value.rb | 11 ------ lib/arel/engines/sql/relations.rb | 4 +-- lib/arel/engines/sql/relations/writes.rb | 36 +++++++++++++++++++ .../engines/sql/relations/writes/delete.rb | 12 ------- .../engines/sql/relations/writes/insert.rb | 12 ------- .../engines/sql/relations/writes/update.rb | 14 -------- spec/arel/unit/relations/table_spec.rb | 4 +-- 22 files changed, 135 insertions(+), 168 deletions(-) create mode 100644 lib/arel/algebra/relations/writes.rb delete mode 100644 lib/arel/algebra/relations/writes/delete.rb delete mode 100644 lib/arel/algebra/relations/writes/insert.rb delete mode 100644 lib/arel/algebra/relations/writes/update.rb delete mode 100644 lib/arel/engines/memory/primitives/attribute.rb delete mode 100644 lib/arel/engines/memory/primitives/value.rb rename lib/arel/engines/memory/relations/{operations/where.rb => operations.rb} (100%) delete mode 100644 lib/arel/engines/sql/primitives/attribute.rb delete mode 100644 lib/arel/engines/sql/primitives/expression.rb delete mode 100644 lib/arel/engines/sql/primitives/value.rb create mode 100644 lib/arel/engines/sql/relations/writes.rb delete mode 100644 lib/arel/engines/sql/relations/writes/delete.rb delete mode 100644 lib/arel/engines/sql/relations/writes/insert.rb delete mode 100644 lib/arel/engines/sql/relations/writes/update.rb diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index f83101306ef2c..7f093ded6db76 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -1,5 +1,12 @@ module Arel class Predicate + def or(other_predicate) + Or.new(self, other_predicate) + end + + def and(other_predicate) + And.new(self, other_predicate) + end end class Binary < Predicate @@ -25,21 +32,10 @@ def ==(other) end end - class GreaterThanOrEqualTo < Binary - end - - class GreaterThan < Binary - end - - class LessThanOrEqualTo < Binary - end - - class LessThan < Binary - end - - class Match < Binary - end - - class In < Binary - end + class GreaterThanOrEqualTo < Binary; end + class GreaterThan < Binary; end + class LessThanOrEqualTo < Binary; end + class LessThan < Binary; end + class Match < Binary; end + class In < Binary; end end \ No newline at end of file diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index 03f04d2459350..b75a31e5e3360 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -2,9 +2,7 @@ require 'arel/algebra/relations/utilities/compound' require 'arel/algebra/relations/utilities/nil' require 'arel/algebra/relations/utilities/externalization' -require 'arel/algebra/relations/writes/delete' -require 'arel/algebra/relations/writes/update' -require 'arel/algebra/relations/writes/insert' +require 'arel/algebra/relations/writes' require 'arel/algebra/relations/operations/alias' require 'arel/algebra/relations/operations/group' require 'arel/algebra/relations/operations/join' diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb new file mode 100644 index 0000000000000..352f7bc7e5d09 --- /dev/null +++ b/lib/arel/algebra/relations/writes.rb @@ -0,0 +1,36 @@ +module Arel + class Deletion < Compound + attributes :relation + deriving :initialize, :== + + def call + engine.delete(self) + end + end + + class Insert < Compound + attributes :relation, :record + deriving :== + + def initialize(relation, record) + @relation, @record = relation, record.bind(relation) + end + + def call + engine.create(self) + end + end + + class Update < Compound + attributes :relation, :assignments + deriving :== + + def initialize(relation, assignments) + @relation, @assignments = relation, assignments.bind(relation) + end + + def call + engine.update(self) + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/writes/delete.rb b/lib/arel/algebra/relations/writes/delete.rb deleted file mode 100644 index a94067c7fab01..0000000000000 --- a/lib/arel/algebra/relations/writes/delete.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Deletion < Compound - attributes :relation - deriving :initialize, :== - - def call - engine.delete(self) - end - end -end diff --git a/lib/arel/algebra/relations/writes/insert.rb b/lib/arel/algebra/relations/writes/insert.rb deleted file mode 100644 index 6d85e9769a08d..0000000000000 --- a/lib/arel/algebra/relations/writes/insert.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Insert < Compound - attributes :relation, :record - deriving :== - - def initialize(relation, record) - @relation, @record = relation, record.bind(relation) - end - - def call - engine.create(self) - end - end -end diff --git a/lib/arel/algebra/relations/writes/update.rb b/lib/arel/algebra/relations/writes/update.rb deleted file mode 100644 index e647218a80556..0000000000000 --- a/lib/arel/algebra/relations/writes/update.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Update < Compound - attributes :relation, :assignments - deriving :== - - def initialize(relation, assignments) - @relation, @assignments = relation, assignments - end - - def call - engine.update(self) - end - end -end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index 3522ea3ffafc8..bbf39ba794c09 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -1,13 +1,4 @@ module Arel - class Predicate - def or(other_predicate) - Or.new(self, other_predicate) - end - - def and(other_predicate) - And.new(self, other_predicate) - end - end class Binary < Predicate def eval(row) @@ -30,11 +21,6 @@ def predicate_sql; "AND" end end class Equality < Binary - def ==(other) - Equality === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) - end end class GreaterThanOrEqualTo < Binary diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index 4d5c76e956acb..77d4c1a52c2fc 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -1,2 +1,13 @@ -require 'arel/engines/memory/primitives/attribute' -require 'arel/engines/memory/primitives/value' +module Arel + class Attribute + def eval(row) + row[self] + end + end + + class Value + def eval(row) + value + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives/attribute.rb b/lib/arel/engines/memory/primitives/attribute.rb deleted file mode 100644 index 9864feadc2ff1..0000000000000 --- a/lib/arel/engines/memory/primitives/attribute.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Attribute - def eval(row) - row[self] - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives/value.rb b/lib/arel/engines/memory/primitives/value.rb deleted file mode 100644 index b83cd02e57dc0..0000000000000 --- a/lib/arel/engines/memory/primitives/value.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Value - def eval(row) - value - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 6361d7c9d7d2d..9f8264c439619 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,2 +1,3 @@ require 'arel/engines/memory/relations/array' -require 'arel/engines/memory/relations/operations/where' +require 'arel/engines/memory/relations/operations' + diff --git a/lib/arel/engines/memory/relations/operations/where.rb b/lib/arel/engines/memory/relations/operations.rb similarity index 100% rename from lib/arel/engines/memory/relations/operations/where.rb rename to lib/arel/engines/memory/relations/operations.rb diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 405b1ca8038bb..5544d63710ca9 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -1,3 +1,31 @@ -require 'arel/engines/sql/primitives/attribute' -require 'arel/engines/sql/primitives/value' -require 'arel/engines/sql/primitives/expression' \ No newline at end of file +module Arel + class Attribute + def column + original_relation.column_for(self) + end + + def format(object) + object.to_sql(Sql::Attribute.new(self)) + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self + end + end + + class Expression < Attribute + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + end + + class Value + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.value value + end + + def format(object) + object.to_sql(Sql::Value.new(relation)) + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/attribute.rb b/lib/arel/engines/sql/primitives/attribute.rb deleted file mode 100644 index ad78a9ec5b590..0000000000000 --- a/lib/arel/engines/sql/primitives/attribute.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Arel - class Attribute - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/expression.rb b/lib/arel/engines/sql/primitives/expression.rb deleted file mode 100644 index 24f6879848492..0000000000000 --- a/lib/arel/engines/sql/primitives/expression.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Expression < Attribute - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/value.rb b/lib/arel/engines/sql/primitives/value.rb deleted file mode 100644 index a44acc26e040d..0000000000000 --- a/lib/arel/engines/sql/primitives/value.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Arel - class Value - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.value value - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 39ef8852a1dba..d6e4d295ba5ae 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -5,6 +5,4 @@ require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' require 'arel/engines/sql/relations/operations/alias' -require 'arel/engines/sql/relations/writes/delete' -require 'arel/engines/sql/relations/writes/insert' -require 'arel/engines/sql/relations/writes/update' \ No newline at end of file +require 'arel/engines/sql/relations/writes' \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb new file mode 100644 index 0000000000000..edfd9f72332fe --- /dev/null +++ b/lib/arel/engines/sql/relations/writes.rb @@ -0,0 +1,36 @@ +module Arel + class Deletion < Compound + def to_sql(formatter = nil) + [ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ].compact.join("\n") + end + end + + class Insert < Compound + def to_sql(formatter = nil) + [ + "INSERT", + "INTO #{table_sql}", + "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", + "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + ].join("\n") + end + end + + class Update < Compound + def to_sql(formatter = nil) + [ + "UPDATE #{table_sql} SET", + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n"), + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) + ].join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/delete.rb b/lib/arel/engines/sql/relations/writes/delete.rb deleted file mode 100644 index b22ee51e24e6c..0000000000000 --- a/lib/arel/engines/sql/relations/writes/delete.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Arel - class Deletion < Compound - def to_sql(formatter = nil) - [ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/insert.rb b/lib/arel/engines/sql/relations/writes/insert.rb deleted file mode 100644 index aac9c87a5bb6a..0000000000000 --- a/lib/arel/engines/sql/relations/writes/insert.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Arel - class Insert < Compound - def to_sql(formatter = nil) - [ - "INSERT", - "INTO #{table_sql}", - "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" - ].join("\n") - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/update.rb b/lib/arel/engines/sql/relations/writes/update.rb deleted file mode 100644 index 3e35a0d5cce57..0000000000000 --- a/lib/arel/engines/sql/relations/writes/update.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Update < Compound - def to_sql(formatter = nil) - [ - "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index 211e6921f81d8..2779c0fe5dfd1 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -73,14 +73,14 @@ module Arel describe '#reset' do it "reloads columns from the database" do lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } - lambda { @relation.reset }.should change { @relation.attributes } + lambda { @relation.reset }.should change { @relation.attributes } end end end describe 'hashing' do it "implements hash equality" do - Table.new(:users).should hash_the_same_as(Table.new(:users)) + Table.new(:users).should hash_the_same_as(Table.new(:users)) Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) end end From 892337509b2bd269920dc567bc48c6a28c7222d2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:46:08 -0400 Subject: [PATCH 0217/1492] removed function_sql in favor of polymorphism Conflicts: lib/arel/algebra/primitives/attribute.rb lib/arel/algebra/primitives/expression.rb spec/arel/unit/primitives/expression_spec.rb --- doc/TODO | 10 ++++-- lib/arel/algebra/primitives/attribute.rb | 10 +++--- lib/arel/algebra/primitives/expression.rb | 18 +++++++--- lib/arel/engines/sql/primitives.rb | 36 ++++++++++++++++---- spec/arel/unit/primitives/attribute_spec.rb | 10 +++--- spec/arel/unit/primitives/expression_spec.rb | 8 ++--- 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/doc/TODO b/doc/TODO index 8a8dcf5380794..ebc469ad70606 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,6 +1,13 @@ todo: - expressions should be class-based, and joins too, anything _sql should be renamed - refactor adapter pattern +- clean up block_given stuff +- reorganize sql tests +- audit unit coverage of algebra +- break out adapters into sep modules +- data objects +- remove all explicit aliasing +- blocks for joins - implement in memory adapter - implement mnesia adapter - joins become subselects in writes: @@ -11,10 +18,8 @@ users.delete().where( ) - rename externalize to derived. - and/or w/ predicates -- blocks for all operations - result sets to attr correlation too - cache expiry on write - - rewrite of arecord querycache test in light of this - transactions - scoped writes - asc/desc for orderings @@ -83,6 +88,7 @@ done: - rename select to where - rename all ion classes - joining with LIMIT is like aggregations!! +- blocks for non-joins icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 5e216770e4b5f..943c5b030e87e 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -109,23 +109,23 @@ def in(array) module Expressions def count(distinct = false) - distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT") + distinct ? Distinct.new(self).count : Count.new(self) end def sum - Expression.new(self, "SUM") + Sum.new(self) end def maximum - Expression.new(self, "MAX") + Maximum.new(self) end def minimum - Expression.new(self, "MIN") + Minimum.new(self) end def average - Expression.new(self, "AVG") + Average.new(self) end end include Expressions diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb index b67a5e1f8efbf..989397720cb12 100644 --- a/lib/arel/algebra/primitives/expression.rb +++ b/lib/arel/algebra/primitives/expression.rb @@ -1,12 +1,12 @@ module Arel class Expression < Attribute - attributes :attribute, :function_sql, :alias, :ancestor + attributes :attribute, :alias, :ancestor deriving :== delegate :relation, :to => :attribute alias_method :name, :alias - def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) - @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor + def initialize(attribute, aliaz = nil, ancestor = nil) + @attribute, @alias, @ancestor = attribute, aliaz, ancestor end def aggregation? @@ -15,11 +15,11 @@ def aggregation? module Transformations def as(aliaz) - Expression.new(attribute, function_sql, aliaz, self) + self.class.new(attribute, aliaz, self) end def bind(new_relation) - new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) end def to_attribute @@ -28,4 +28,12 @@ def to_attribute end include Transformations end + + class Count < Expression; end + class Distinct < Expression; end + class Sum < Expression; end + class Maximum < Expression; end + class Minimum < Expression; end + class Average < Expression; end end + diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 5544d63710ca9..c4968558a2135 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -13,12 +13,6 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) end end - class Expression < Attribute - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - end - class Value def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value @@ -28,4 +22,34 @@ def format(object) object.to_sql(Sql::Value.new(relation)) end end + + class Expression < Attribute + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + end + + class Count < Expression + def function_sql; 'COUNT' end + end + + class Distinct < Expression + def function_sql; 'DISTINCT' end + end + + class Sum < Expression + def function_sql; 'SUM' end + end + + class Maximum < Expression + def function_sql; 'MAX' end + end + + class Minimum < Expression + def function_sql; 'MIN' end + end + + class Average < Expression + def function_sql; 'AVG' end + end end \ No newline at end of file diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index 6d0f146a39ccd..e512b40ebf505 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -139,31 +139,31 @@ module Arel describe '#count' do it "manufactures a count Expression" do - @attribute.count.should == Expression.new(@attribute, "COUNT") + @attribute.count.should == Count.new(@attribute) end end describe '#sum' do it "manufactures a sum Expression" do - @attribute.sum.should == Expression.new(@attribute, "SUM") + @attribute.sum.should == Sum.new(@attribute) end end describe '#maximum' do it "manufactures a maximum Expression" do - @attribute.maximum.should == Expression.new(@attribute, "MAX") + @attribute.maximum.should == Maximum.new(@attribute) end end describe '#minimum' do it "manufactures a minimum Expression" do - @attribute.minimum.should == Expression.new(@attribute, "MIN") + @attribute.minimum.should == Minimum.new(@attribute) end end describe '#average' do it "manufactures an average Expression" do - @attribute.average.should == Expression.new(@attribute, "AVG") + @attribute.average.should == Average.new(@attribute) end end end diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index ebde55ff9064f..92f300c4ee405 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -9,13 +9,13 @@ module Arel describe Expression::Transformations do before do - @expression = Expression.new(@attribute, "COUNT") + @expression = Count.new(@attribute) end describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) - @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) + @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) end it "returns self if the substituting to the same relation" do @@ -25,7 +25,7 @@ module Arel describe '#as' do it "manufactures an aliased expression" do - @expression.as(:alias).should == Expression.new(@attribute, "COUNT", :alias, @expression) + @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) end end @@ -38,7 +38,7 @@ module Arel describe '#to_sql' do it "manufactures sql with the expression and alias" do - sql = Expression.new(@attribute, "COUNT", :alias).to_sql + sql = Count.new(@attribute, :alias).to_sql adapter_is :mysql do sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) From 3a6e8e5a3f99841691b70b89b0a10f836e6ec071 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:49:56 -0400 Subject: [PATCH 0218/1492] join sql stuff moved into sql adapter Conflicts: lib/arel/algebra/primitives/value.rb lib/arel/algebra/relations/operations/join.rb lib/arel/algebra/relations/relation.rb spec/arel/unit/relations/join_spec.rb --- lib/arel/algebra/primitives/value.rb | 1 - lib/arel/algebra/relations/operations/join.rb | 14 +++++++++++--- lib/arel/algebra/relations/relation.rb | 15 +++++++-------- .../algebra/relations/utilities/compound.rb | 3 +-- lib/arel/engines/sql/primitives.rb | 18 ++++++++++-------- .../engines/sql/relations/operations/join.rb | 14 ++++++++++++++ spec/arel/unit/relations/join_spec.rb | 12 ++++++------ spec/arel/unit/relations/relation_spec.rb | 4 ++-- 8 files changed, 51 insertions(+), 30 deletions(-) diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/primitives/value.rb index 91c4045507084..76c82890d0c81 100644 --- a/lib/arel/algebra/primitives/value.rb +++ b/lib/arel/algebra/primitives/value.rb @@ -2,7 +2,6 @@ module Arel class Value attributes :value, :relation deriving :initialize, :== - delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value def bind(relation) Value.new(value, relation) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 8e19254378b2c..695f360b517f9 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -1,12 +1,12 @@ module Arel class Join < Relation - attributes :join_sql, :relation1, :relation2, :predicates + attributes :relation1, :relation2, :predicates deriving :== delegate :engine, :name, :to => :relation1 hash_on :relation1 - def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + def initialize(relation1, relation2 = Nil.instance, *predicates) + @relation1, @relation2, @predicates = relation1, relation2, predicates end def attributes @@ -33,6 +33,14 @@ def join? end end + class InnerJoin < Join; end + class OuterJoin < Join; end + class StringJoin < Join + def attributes + relation1.externalize.attributes + end + end + class Relation def join? false diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 20badaf165be4..6d76e66638c9a 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -32,28 +32,27 @@ def first include Enumerable module Operable - def join(other_relation = nil, join_type = "INNER JOIN") + def join(other_relation = nil, join_class = InnerJoin) case other_relation when String - Join.new(other_relation, self) + StringJoin.new(other_relation, self) when Relation - JoinOperation.new(join_type, self, other_relation) + JoinOperation.new(join_class, self, other_relation) else self end end def outer_join(other_relation = nil) - join(other_relation, "LEFT OUTER JOIN") + join(other_relation, OuterJoin) end [:where, :project, :order, :take, :skip, :group].each do |operation_name| - operation = <<-OPERATION + class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments, &block) arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) end OPERATION - class_eval operation, __FILE__, __LINE__ end def alias @@ -75,9 +74,9 @@ def delete end include Writable - JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do + JoinOperation = Struct.new(:join_class, :relation1, :relation2) do def on(*predicates) - Join.new(join_sql, relation1, relation2, *predicates) + join_class.new(relation1, relation2, *predicates) end end end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index e33b8dbf141b0..fbff36a868ee9 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -7,12 +7,11 @@ class Compound < Relation :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| - operation = <<-OPERATION + class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } end OPERATION - class_eval operation, __FILE__, __LINE__ end end end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index c4968558a2135..6f89723afe9aa 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -3,7 +3,7 @@ class Attribute def column original_relation.column_for(self) end - + def format(object) object.to_sql(Sql::Attribute.new(self)) end @@ -14,6 +14,8 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) end class Value + delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value + def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value end @@ -22,33 +24,33 @@ def format(object) object.to_sql(Sql::Value.new(relation)) end end - + class Expression < Attribute def to_sql(formatter = Sql::SelectClause.new(relation)) formatter.expression self end end - + class Count < Expression def function_sql; 'COUNT' end end - + class Distinct < Expression def function_sql; 'DISTINCT' end end - + class Sum < Expression def function_sql; 'SUM' end end - + class Maximum < Expression def function_sql; 'MAX' end end - + class Minimum < Expression def function_sql; 'MIN' end end - + class Average < Expression def function_sql; 'AVG' end end diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index be21119bc95f5..2f5e23644e95b 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -16,4 +16,18 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) end end end + + class InnerJoin < Join + def join_sql; "INNER JOIN" end + end + + class OuterJoin < Join + def join_sql; "OUTER JOIN" end + end + + class StringJoin < Join + def joins(_, __ = nil) + relation2 + end + end end \ No newline at end of file diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index fa6bbbe216224..0e3e6ef16b9a6 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -10,20 +10,20 @@ module Arel describe 'hashing' do it 'implements hash equality' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate) \ - .should hash_the_same_as(Join.new("INNER JOIN", @relation1, @relation2, @predicate)) + InnerJoin.new(@relation1, @relation2, @predicate) \ + .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) end end describe '#engine' do it "delegates to a relation's engine" do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).engine.should == @relation1.engine + InnerJoin.new(@relation1, @relation2, @predicate).engine.should == @relation1.engine end end describe '#attributes' do it 'combines the attributes of the two relations' do - join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) + join = InnerJoin.new(@relation1, @relation2, @predicate) join.attributes.should == (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } end @@ -32,7 +32,7 @@ module Arel describe '#to_sql' do describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do - sql = Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql + sql = InnerJoin.new(@relation1, @relation2, @predicate).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -54,7 +54,7 @@ module Arel describe 'when joining with a string' do it "passes the string through to the where clause" do - sql = Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql + sql = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa").to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index 7df10be59cf6e..6a61f39966731 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -34,7 +34,7 @@ module Arel describe 'when given a relation' do it "manufactures an inner join operation between those two relations" do @relation.join(@relation).on(@predicate). \ - should == Join.new("INNER JOIN", @relation, @relation, @predicate) + should == InnerJoin.new(@relation, @relation, @predicate) end end @@ -54,7 +54,7 @@ module Arel describe '#outer_join' do it "manufactures a left outer join operation between those two relations" do @relation.outer_join(@relation).on(@predicate). \ - should == Join.new("LEFT OUTER JOIN", @relation, @relation, @predicate) + should == OuterJoin.new(@relation, @relation, @predicate) end end end From 437429764510338bdc5f4915286425f07565a573 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 26 May 2008 14:30:51 -0700 Subject: [PATCH 0219/1492] moved table-related stuff into sql engine --- lib/arel/algebra/relations/utilities/compound.rb | 2 +- lib/arel/engines/sql/relations.rb | 1 + lib/arel/engines/sql/relations/utilities/compound.rb | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 lib/arel/engines/sql/relations/utilities/compound.rb diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index fbff36a868ee9..4d7cece812561 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -3,7 +3,7 @@ class Compound < Relation attr_reader :relation hash_on :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :table, :table_sql, :array, + :column_for, :engine, :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index d6e4d295ba5ae..0eb1303ec9ab5 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -1,3 +1,4 @@ +require 'arel/engines/sql/relations/utilities/compound' require 'arel/engines/sql/relations/utilities/recursion' require 'arel/engines/sql/relations/utilities/externalization' require 'arel/engines/sql/relations/utilities/nil' diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb new file mode 100644 index 0000000000000..502bf8b01e008 --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -0,0 +1,6 @@ +module Arel + class Compound < Relation + delegate :table, :table_sql, :array, :to => :relation + end +end + \ No newline at end of file From 4e3c9a01307339916f6b947d24f19b0f442afd78 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:58:46 -0400 Subject: [PATCH 0220/1492] most in memory operations save join and group Conflicts: lib/arel/algebra/extensions/object.rb lib/arel/algebra/primitives/value.rb lib/arel/engines/memory/relations.rb lib/arel/engines/sql/formatters.rb lib/arel/engines/sql/primitives.rb spec/arel/unit/relations/alias_spec.rb spec/arel/unit/relations/array_spec.rb spec/arel/unit/relations/order_spec.rb --- doc/TODO | 8 +- lib/arel/algebra/extensions/array.rb | 7 ++ lib/arel/algebra/extensions/hash.rb | 7 ++ lib/arel/algebra/extensions/object.rb | 5 ++ lib/arel/algebra/primitives.rb | 1 + lib/arel/algebra/primitives/attribute.rb | 17 +++++ lib/arel/algebra/primitives/ordering.rb | 18 +++++ lib/arel/algebra/primitives/value.rb | 8 +- .../algebra/relations/operations/order.rb | 3 +- lib/arel/engines/memory/primitives.rb | 14 ++++ lib/arel/engines/memory/relations.rb | 1 + lib/arel/engines/memory/relations/compound.rb | 5 ++ .../engines/memory/relations/operations.rb | 33 ++++++++ lib/arel/engines/sql/formatters.rb | 6 +- lib/arel/engines/sql/primitives.rb | 14 ++++ .../sql/relations/utilities/compound.rb | 2 +- spec/arel/unit/relations/alias_spec.rb | 4 +- spec/arel/unit/relations/array_spec.rb | 75 ++++++++++++++++--- spec/arel/unit/relations/order_spec.rb | 12 +-- 19 files changed, 208 insertions(+), 32 deletions(-) create mode 100644 lib/arel/algebra/primitives/ordering.rb create mode 100644 lib/arel/engines/memory/relations/compound.rb diff --git a/doc/TODO b/doc/TODO index ebc469ad70606..dfbf09de9deaf 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,6 +1,9 @@ todo: -- expressions should be class-based, and joins too, anything _sql should be renamed +- projection is by definition distincting +- union/intersection - refactor adapter pattern +- result sets to attr correlation too + - result sets should be array relations - clean up block_given stuff - reorganize sql tests - audit unit coverage of algebra @@ -10,6 +13,7 @@ todo: - blocks for joins - implement in memory adapter - implement mnesia adapter +- test ordering - joins become subselects in writes: users.delete().where( addresses.c.user_id== @@ -18,7 +22,6 @@ users.delete().where( ) - rename externalize to derived. - and/or w/ predicates -- result sets to attr correlation too - cache expiry on write - transactions - scoped writes @@ -89,6 +92,7 @@ done: - rename all ion classes - joining with LIMIT is like aggregations!! - blocks for non-joins +- expressions should be class-based, and joins too, anything _sql should be renamed icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb index 5b6d6d6abd537..935569a07b7b8 100644 --- a/lib/arel/algebra/extensions/array.rb +++ b/lib/arel/algebra/extensions/array.rb @@ -2,4 +2,11 @@ class Array def to_hash Hash[*flatten] end + + def group_by + inject({}) do |groups, element| + (groups[yield(element)] ||= []) << element + groups + end + end end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 7472b5aa731ad..bc97785e62de7 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -4,4 +4,11 @@ def bind(relation) bound.merge(key.bind(relation) => value.bind(relation)) end end + + def slice(*attributes) + inject({}) do |cheese, (key, value)| + cheese[key] = value if attributes.include?(key) + cheese + end + end end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index d626407dcb801..efdbbf525fde6 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -12,4 +12,9 @@ class << self self end end + + def let + yield(self) + end end + diff --git a/lib/arel/algebra/primitives.rb b/lib/arel/algebra/primitives.rb index a4c3169e0b9a0..df8d16a5d58e5 100644 --- a/lib/arel/algebra/primitives.rb +++ b/lib/arel/algebra/primitives.rb @@ -1,4 +1,5 @@ require 'arel/algebra/primitives/attribute' +require 'arel/algebra/primitives/ordering' require 'arel/algebra/primitives/value' require 'arel/algebra/primitives/expression' diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 943c5b030e87e..7a4411e248add 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -17,6 +17,10 @@ def named?(hypothetical_name) def aggregation? false end + + def inspect + "" + end module Transformations def self.included(klass) @@ -129,5 +133,18 @@ def average end end include Expressions + + module Orderings + def asc + Ascending.new(self) + end + + def desc + Descending.new(self) + end + + alias_method :to_ordering, :asc + end + include Orderings end end diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb new file mode 100644 index 0000000000000..e8d8f971884f5 --- /dev/null +++ b/lib/arel/algebra/primitives/ordering.rb @@ -0,0 +1,18 @@ +module Arel + class Ordering + attributes :attribute + deriving :initialize, :== + delegate :relation, :to => :attribute + + def bind(relation) + self.class.new(attribute.bind(relation)) + end + + def to_ordering + self + end + end + + class Ascending < Ordering; end + class Descending < Ordering; end +end \ No newline at end of file diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/primitives/value.rb index 76c82890d0c81..e3638051402a8 100644 --- a/lib/arel/algebra/primitives/value.rb +++ b/lib/arel/algebra/primitives/value.rb @@ -7,12 +7,8 @@ def bind(relation) Value.new(value, relation) end - def aggregation? - false - end - - def to_attribute - value + def to_ordering + self end end end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 05af3fde4d125..eccd8bcda0978 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -10,7 +10,8 @@ def initialize(relation, *orderings, &block) # TESTME def orders - (orderings + relation.orders).collect { |o| o.bind(self) } + # QUESTION - do we still need relation.orders ? + (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } end end end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index 77d4c1a52c2fc..f8bbcedb556d8 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -10,4 +10,18 @@ def eval(row) value end end + + class Ordering + def eval(row1, row2) + (attribute.eval(row1) <=> attribute.eval(row2)) * direction + end + end + + class Descending < Ordering + def direction; -1 end + end + + class Ascending < Ordering + def direction; 1 end + end end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 9f8264c439619..1b009537b9bad 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,3 +1,4 @@ require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' +require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb new file mode 100644 index 0000000000000..b029082d57400 --- /dev/null +++ b/lib/arel/engines/memory/relations/compound.rb @@ -0,0 +1,5 @@ +module Arel + class Compound < Relation + delegate :array, :to => :relation + end +end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index eb11fb55fd0f6..115df054df2a7 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -4,4 +4,37 @@ def eval relation.eval.select { |row| predicate.eval(row) } end end + + class Order < Compound + def eval + relation.eval.sort do |row1, row2| + ordering = orderings.detect { |o| o.eval(row1, row2) != 0 } || orderings.last + ordering.eval(row1, row2) + end + end + end + + class Project < Compound + def eval + relation.eval.collect { |r| r.slice(*projections) } + end + end + + class Take < Compound + def eval + relation.eval[0, taken] + end + end + + class Skip < Compound + def eval + relation.eval[skipped..-1] + end + end + + class Group < Compound + def eval + raise NotImplementedError + end + end end \ No newline at end of file diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index f82ddf631fef0..bc5f0f7c64ba0 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -47,9 +47,9 @@ def value(value) class WhereClause < PassThrough end - class OrderClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + class OrderClause < PassThrough + def ordering(ordering) + "#{quote_table_name(name_for(ordering.attribute.original_relation))}.#{quote_column_name(ordering.attribute.name)} #{ordering.direction_sql}" end end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 6f89723afe9aa..9e9143ac0f268 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -24,6 +24,20 @@ def format(object) object.to_sql(Sql::Value.new(relation)) end end + + class Ordering + def to_sql(formatter = Sql::OrderClause.new(relation)) + formatter.ordering self + end + end + + class Ascending < Ordering + def direction_sql; 'ASC' end + end + + class Descending < Ordering + def direction_sql; 'DESC' end + end class Expression < Attribute def to_sql(formatter = Sql::SelectClause.new(relation)) diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index 502bf8b01e008..61df196d6e2e1 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -1,6 +1,6 @@ module Arel class Compound < Relation - delegate :table, :table_sql, :array, :to => :relation + delegate :table, :table_sql, :to => :relation end end \ No newline at end of file diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 570f3158926f3..63c15cfeffef1 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -30,7 +30,7 @@ module Arel FROM `users` WHERE `users`.`id` = 1 GROUP BY `users`.`id` - ORDER BY `users`.`id` + ORDER BY `users`.`id` ASC }) end @@ -40,7 +40,7 @@ module Arel FROM "users" WHERE "users"."id" = 1 GROUP BY "users"."id" - ORDER BY "users"."id" + ORDER BY "users"."id" ASC }) end end diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb index c90843cd7d8b4..d1c65c60a99b2 100644 --- a/spec/arel/unit/relations/array_spec.rb +++ b/spec/arel/unit/relations/array_spec.rb @@ -3,13 +3,18 @@ module Arel describe Array do before do - @relation = Array.new([[1], [2], [3]], [:id]) + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) end describe '#attributes' do it 'manufactures attributes corresponding to the names given on construction' do @relation.attributes.should == [ - Attribute.new(@relation, :id) + Attribute.new(@relation, :id), + Attribute.new(@relation, :name) ] end end @@ -17,17 +22,65 @@ module Arel describe '#call' do it "manufactures an array of hashes of attributes to values" do @relation.call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 }, - { @relation[:id] => 3 } + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } ] end - - it '' do - @relation.where(@relation[:id].lt(3)).call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 } - ] + + describe 'where' do + it 'filters the relation with the provided predicate' do + @relation.where(@relation[:id].lt(3)).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'group' do + it 'sorts the relation with the provided ordering' do + end + end + + describe 'order' do + it 'sorts the relation with the provided ordering' do + @relation.order(@relation[:id].desc).call.should == [ + { @relation[:id] => 3, @relation[:name] => 'goose' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 1, @relation[:name] => 'duck' } + ] + end + end + + describe 'project' do + it 'projects' do + @relation.project(@relation[:id]).call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 }, + { @relation[:id] => 3 } + ] + end + end + + describe 'skip' do + it 'slices' do + @relation.skip(1).call.should == [ + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } + ] + end + end + + describe 'take' do + it 'dices' do + @relation.take(2).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'join' do end end end diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb index 31014ddd39336..cb0f1de84cee8 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -16,7 +16,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`id` + ORDER BY `users`.`id` ASC }) end @@ -24,7 +24,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" - ORDER BY "users"."id" + ORDER BY "users"."id" ASC }) end end @@ -42,7 +42,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`id`, `users`.`name` + ORDER BY `users`.`id` ASC, `users`.`name` ASC }) end @@ -50,7 +50,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" - ORDER BY "users"."id", "users"."name" + ORDER BY "users"."id" ASC, "users"."name" ASC }) end end @@ -95,7 +95,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`name`, `users`.`id` + ORDER BY `users`.`name` ASC, `users`.`id` ASC }) end @@ -103,7 +103,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" - ORDER BY "users"."name", "users"."id" + ORDER BY "users"."name" ASC, "users"."id" ASC }) end end From 2753d8f5768ce0b5f91a96cf81c6ba1d747aeea9 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:59:06 -0400 Subject: [PATCH 0221/1492] Add rake whitespace --- Rakefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 9292ac25339c9..545993653e65d 100644 --- a/Rakefile +++ b/Rakefile @@ -28,4 +28,9 @@ desc "Run specs with mysql and sqlite3 database adapters (default)" task :spec => ["spec:sqlite3", "spec:mysql"] desc "Default task is to run specs" -task :default => :spec \ No newline at end of file +task :default => :spec + +desc 'Removes trailing whitespace' +task :whitespace do + sh %{find . -name '*.rb' -exec sed -i '' 's/ *$//g' {} \\;} +end From 9d77c08cf8a75636b058c1b85af52ef96e07cee5 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:00:10 -0400 Subject: [PATCH 0222/1492] made block stuff read nicer Conflicts: doc/TODO --- doc/TODO | 30 +++++++++---------- .../algebra/relations/operations/group.rb | 3 +- .../algebra/relations/operations/order.rb | 3 +- .../algebra/relations/operations/project.rb | 3 +- .../algebra/relations/utilities/compound.rb | 5 ++++ 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/doc/TODO b/doc/TODO index dfbf09de9deaf..d7e3bb280d014 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,31 +1,24 @@ todo: -- projection is by definition distincting -- union/intersection -- refactor adapter pattern - result sets to attr correlation too - result sets should be array relations +- fix AR - clean up block_given stuff - reorganize sql tests - audit unit coverage of algebra -- break out adapters into sep modules +- implement mnesia adapter - data objects - remove all explicit aliasing - blocks for joins -- implement in memory adapter -- implement mnesia adapter -- test ordering -- joins become subselects in writes: -users.delete().where( - addresses.c.user_id== - select([users.c.id]). - where(users.c.name=='jack') - ) - rename externalize to derived. - and/or w/ predicates +- scoped writes +- refactor adapter pattern +- break out adapters into sep modules +- projection is by definition distincting? +- union/intersection +- test ordering - cache expiry on write - transactions -- scoped writes -- asc/desc for orderings done: - and/or w/ predicates @@ -93,6 +86,7 @@ done: - joining with LIMIT is like aggregations!! - blocks for non-joins - expressions should be class-based, and joins too, anything _sql should be renamed +- implement in memory adapter icebox: - #bind in Attribute and Expression should be doing a descend? @@ -107,3 +101,9 @@ icebox: @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } - lock - SELECT suchandsuch FOR UPDATE +- joins become subselects in writes: +users.delete().where( + addresses.c.user_id== + select([users.c.id]). + where(users.c.name=='jack') + ) \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 04fd9fea629b1..879f2352c5010 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -5,7 +5,8 @@ class Group < Compound def initialize(relation, *groupings, &block) @relation = relation - @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) } + @groupings = (groupings + arguments_from_block(relation, &block)) \ + .collect { |g| g.bind(relation) } end def externalizable? diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index eccd8bcda0978..4e7133f5a87b1 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -5,7 +5,8 @@ class Order < Compound def initialize(relation, *orderings, &block) @relation = relation - @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) } + @orderings = (orderings + arguments_from_block(relation, &block)) \ + .collect { |o| o.bind(relation) } end # TESTME diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 5507ea3163dc8..223d320e22ffa 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -5,7 +5,8 @@ class Project < Compound def initialize(relation, *projections, &block) @relation = relation - @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } + @projections = (projections + arguments_from_block(relation, &block)) \ + .collect { |p| p.bind(relation) } end def attributes diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 4d7cece812561..99c3d02748c75 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -13,5 +13,10 @@ def #{operation_name} end OPERATION end + + private + def arguments_from_block(relation, &block) + block_given?? [yield(relation)] : [] + end end end From a7aacd29460aa137c3b06ee214ff8ffdff8ee365 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 26 May 2008 21:02:23 -0700 Subject: [PATCH 0223/1492] reorganizing tests --- doc/TODO | 21 +- .../algebra/unit/predicates/binary_spec.rb | 33 +++ .../algebra/unit/predicates/equality_spec.rb | 27 +++ spec/arel/algebra/unit/predicates/in_spec.rb | 10 + .../algebra/unit/primitives/attribute_spec.rb | 169 ++++++++++++++++ .../unit/primitives/expression_spec.rb | 39 ++++ .../algebra/unit/primitives/value_spec.rb | 15 ++ .../arel/algebra/unit/relations/alias_spec.rb | 16 ++ .../algebra/unit/relations/delete_spec.rb | 9 + .../arel/algebra/unit/relations/group_spec.rb | 10 + .../algebra/unit/relations/insert_spec.rb | 9 + spec/arel/algebra/unit/relations/join_spec.rb | 26 +++ .../arel/algebra/unit/relations/order_spec.rb | 11 + .../algebra/unit/relations/project_spec.rb | 34 ++++ .../algebra/unit/relations/relation_spec.rb | 188 ++++++++++++++++++ spec/arel/algebra/unit/relations/skip_spec.rb | 10 + .../arel/algebra/unit/relations/table_spec.rb | 39 ++++ spec/arel/algebra/unit/relations/take_spec.rb | 10 + .../algebra/unit/relations/update_spec.rb | 9 + .../arel/algebra/unit/relations/where_spec.rb | 18 ++ .../arel/algebra/unit/session/session_spec.rb | 84 ++++++++ .../integration/joins/with_adjacency_spec.rb | 2 +- .../joins/with_aggregations_spec.rb | 2 +- .../integration/joins/with_compounds_spec.rb | 2 +- .../sql}/unit/predicates/binary_spec.rb | 2 +- .../sql}/unit/predicates/equality_spec.rb | 2 +- .../sql}/unit/predicates/in_spec.rb | 2 +- .../sql}/unit/primitives/attribute_spec.rb | 2 +- .../sql}/unit/primitives/expression_spec.rb | 2 +- .../sql}/unit/primitives/value_spec.rb | 2 +- .../sql}/unit/relations/alias_spec.rb | 2 +- .../sql}/unit/relations/array_spec.rb | 2 +- .../sql}/unit/relations/delete_spec.rb | 2 +- .../sql}/unit/relations/group_spec.rb | 2 +- .../sql}/unit/relations/insert_spec.rb | 2 +- .../sql}/unit/relations/join_spec.rb | 2 +- .../sql}/unit/relations/order_spec.rb | 2 +- .../sql}/unit/relations/project_spec.rb | 2 +- .../sql}/unit/relations/relation_spec.rb | 2 +- .../sql}/unit/relations/skip_spec.rb | 2 +- .../sql}/unit/relations/table_spec.rb | 2 +- .../sql}/unit/relations/take_spec.rb | 2 +- .../sql}/unit/relations/update_spec.rb | 2 +- .../sql}/unit/relations/where_spec.rb | 2 +- .../sql}/unit/session/session_spec.rb | 2 +- 45 files changed, 803 insertions(+), 32 deletions(-) create mode 100644 spec/arel/algebra/unit/predicates/binary_spec.rb create mode 100644 spec/arel/algebra/unit/predicates/equality_spec.rb create mode 100644 spec/arel/algebra/unit/predicates/in_spec.rb create mode 100644 spec/arel/algebra/unit/primitives/attribute_spec.rb create mode 100644 spec/arel/algebra/unit/primitives/expression_spec.rb create mode 100644 spec/arel/algebra/unit/primitives/value_spec.rb create mode 100644 spec/arel/algebra/unit/relations/alias_spec.rb create mode 100644 spec/arel/algebra/unit/relations/delete_spec.rb create mode 100644 spec/arel/algebra/unit/relations/group_spec.rb create mode 100644 spec/arel/algebra/unit/relations/insert_spec.rb create mode 100644 spec/arel/algebra/unit/relations/join_spec.rb create mode 100644 spec/arel/algebra/unit/relations/order_spec.rb create mode 100644 spec/arel/algebra/unit/relations/project_spec.rb create mode 100644 spec/arel/algebra/unit/relations/relation_spec.rb create mode 100644 spec/arel/algebra/unit/relations/skip_spec.rb create mode 100644 spec/arel/algebra/unit/relations/table_spec.rb create mode 100644 spec/arel/algebra/unit/relations/take_spec.rb create mode 100644 spec/arel/algebra/unit/relations/update_spec.rb create mode 100644 spec/arel/algebra/unit/relations/where_spec.rb create mode 100644 spec/arel/algebra/unit/session/session_spec.rb rename spec/arel/{ => engines/sql}/integration/joins/with_adjacency_spec.rb (98%) rename spec/arel/{ => engines/sql}/integration/joins/with_aggregations_spec.rb (98%) rename spec/arel/{ => engines/sql}/integration/joins/with_compounds_spec.rb (97%) rename spec/arel/{ => engines/sql}/unit/predicates/binary_spec.rb (97%) rename spec/arel/{ => engines/sql}/unit/predicates/equality_spec.rb (95%) rename spec/arel/{ => engines/sql}/unit/predicates/in_spec.rb (96%) rename spec/arel/{ => engines/sql}/unit/primitives/attribute_spec.rb (98%) rename spec/arel/{ => engines/sql}/unit/primitives/expression_spec.rb (94%) rename spec/arel/{ => engines/sql}/unit/primitives/value_spec.rb (89%) rename spec/arel/{ => engines/sql}/unit/relations/alias_spec.rb (93%) rename spec/arel/{ => engines/sql}/unit/relations/array_spec.rb (96%) rename spec/arel/{ => engines/sql}/unit/relations/delete_spec.rb (93%) rename spec/arel/{ => engines/sql}/unit/relations/group_spec.rb (93%) rename spec/arel/{ => engines/sql}/unit/relations/insert_spec.rb (96%) rename spec/arel/{ => engines/sql}/unit/relations/join_spec.rb (96%) rename spec/arel/{ => engines/sql}/unit/relations/order_spec.rb (97%) rename spec/arel/{ => engines/sql}/unit/relations/project_spec.rb (97%) rename spec/arel/{ => engines/sql}/unit/relations/relation_spec.rb (98%) rename spec/arel/{ => engines/sql}/unit/relations/skip_spec.rb (87%) rename spec/arel/{ => engines/sql}/unit/relations/table_spec.rb (96%) rename spec/arel/{ => engines/sql}/unit/relations/take_spec.rb (87%) rename spec/arel/{ => engines/sql}/unit/relations/update_spec.rb (97%) rename spec/arel/{ => engines/sql}/unit/relations/where_spec.rb (95%) rename spec/arel/{ => engines/sql}/unit/session/session_spec.rb (95%) diff --git a/doc/TODO b/doc/TODO index d7e3bb280d014..f97e74ef17c4e 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,22 +1,26 @@ todo: -- result sets to attr correlation too - - result sets should be array relations -- fix AR -- clean up block_given stuff - reorganize sql tests -- audit unit coverage of algebra +- reorganize memory tests +- blocks for joins +- implement joins in memory +- recursive memory operations +- result sets should be array relations +- cross-engine joins +- fix grouping - implement mnesia adapter +- fix AR +- rename externalize to derived. + +- result sets to attr correlation too +- audit unit coverage of algebra - data objects - remove all explicit aliasing -- blocks for joins -- rename externalize to derived. - and/or w/ predicates - scoped writes - refactor adapter pattern - break out adapters into sep modules - projection is by definition distincting? - union/intersection -- test ordering - cache expiry on write - transactions @@ -87,6 +91,7 @@ done: - blocks for non-joins - expressions should be class-based, and joins too, anything _sql should be renamed - implement in memory adapter +- clean up block_given stuff icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb new file mode 100644 index 0000000000000..9022a543d18f5 --- /dev/null +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -0,0 +1,33 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Binary do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + class ConcreteBinary < Binary + end + end + + describe '#bind' do + before do + @another_relation = @relation.alias + end + + describe 'when both operands are attributes' do + it "manufactures an expression with the attributes bound to the relation" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) + end + end + + describe 'when an operand is a value' do + it "manufactures an expression with unmodified values" do + ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ + should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb new file mode 100644 index 0000000000000..9a56ed5eafa1d --- /dev/null +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Equality do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) + Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) + end + + it "is commutative on the attributes" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/arel/algebra/unit/predicates/in_spec.rb new file mode 100644 index 0000000000000..91c154763caa3 --- /dev/null +++ b/spec/arel/algebra/unit/predicates/in_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe In do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb new file mode 100644 index 0000000000000..bab9fad3d5104 --- /dev/null +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -0,0 +1,169 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Attribute do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Attribute::Transformations do + describe '#as' do + it "manufactures an aliased attributed" do + @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) + end + end + + describe '#bind' do + it "manufactures an attribute with the relation bound and self as an ancestor" do + derived_relation = @relation.where(@relation[:id].eq(1)) + @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) + end + + it "returns self if the substituting to the same relation" do + @attribute.bind(@relation).should == @attribute + end + end + + describe '#to_attribute' do + it "returns self" do + @attribute.to_attribute.should == @attribute + end + end + end + + describe '#column' do + it "returns the corresponding column in the relation" do + @attribute.column.should == @relation.column_for(@attribute) + end + end + + describe '#engine' do + it "delegates to its relation" do + Attribute.new(@relation, :id).engine.should == @relation.engine + end + end + + describe Attribute::Congruence do + describe '/' do + before do + @aliased_relation = @relation.alias + @doubly_aliased_relation = @aliased_relation.alias + end + + describe 'when dividing two unrelated attributes' do + it "returns 0.0" do + (@relation[:id] / @relation[:name]).should == 0.0 + end + end + + describe 'when dividing two matching attributes' do + it 'returns a the highest score for the most similar attributes' do + (@aliased_relation[:id] / @relation[:id]) \ + .should == (@aliased_relation[:id] / @relation[:id]) + (@aliased_relation[:id] / @relation[:id]) \ + .should < (@aliased_relation[:id] / @aliased_relation[:id]) + end + end + end + end + + describe Attribute::Predications do + before do + @attribute = Attribute.new(@relation, :name) + end + + describe '#eq' do + it "manufactures an equality predicate" do + @attribute.eq('name').should == Equality.new(@attribute, 'name') + end + end + + describe '#lt' do + it "manufactures a less-than predicate" do + @attribute.lt(10).should == LessThan.new(@attribute, 10) + end + end + + describe '#lteq' do + it "manufactures a less-than or equal-to predicate" do + @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) + end + end + + describe '#gt' do + it "manufactures a greater-than predicate" do + @attribute.gt(10).should == GreaterThan.new(@attribute, 10) + end + end + + describe '#gteq' do + it "manufactures a greater-than or equal-to predicate" do + @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) + end + end + + describe '#matches' do + it "manufactures a match predicate" do + @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) + end + end + + describe '#in' do + it "manufactures an in predicate" do + @attribute.in(1..30).should == In.new(@attribute, (1..30)) + end + end + end + + describe Attribute::Expressions do + before do + @attribute = Attribute.new(@relation, :name) + end + + describe '#count' do + it "manufactures a count Expression" do + @attribute.count.should == Count.new(@attribute) + end + end + + describe '#sum' do + it "manufactures a sum Expression" do + @attribute.sum.should == Sum.new(@attribute) + end + end + + describe '#maximum' do + it "manufactures a maximum Expression" do + @attribute.maximum.should == Maximum.new(@attribute) + end + end + + describe '#minimum' do + it "manufactures a minimum Expression" do + @attribute.minimum.should == Minimum.new(@attribute) + end + end + + describe '#average' do + it "manufactures an average Expression" do + @attribute.average.should == Average.new(@attribute) + end + end + end + + describe Attribute::Orderings do + describe '#asc' do + it 'manufactures an ascending ordering' do + pending + end + end + + describe '#desc' do + it 'manufactures a descending ordering' do + pending + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb new file mode 100644 index 0000000000000..10bdb56302f12 --- /dev/null +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Expression do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Expression::Transformations do + before do + @expression = Count.new(@attribute) + end + + describe '#bind' do + it "manufactures an attribute with a rebound relation and self as the ancestor" do + derived_relation = @relation.where(@relation[:id].eq(1)) + @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) + end + + it "returns self if the substituting to the same relation" do + @expression.bind(@relation).should == @expression + end + end + + describe '#as' do + it "manufactures an aliased expression" do + @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) + end + end + + describe '#to_attribute' do + it "manufactures an attribute with the expression as an ancestor" do + @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/primitives/value_spec.rb b/spec/arel/algebra/unit/primitives/value_spec.rb new file mode 100644 index 0000000000000..8774ca78c5ba4 --- /dev/null +++ b/spec/arel/algebra/unit/primitives/value_spec.rb @@ -0,0 +1,15 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Value do + before do + @relation = Table.new(:users) + end + + describe '#bind' do + it "manufactures a new value whose relation is the provided relation" do + Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/arel/algebra/unit/relations/alias_spec.rb new file mode 100644 index 0000000000000..c87a0ca2dd8f3 --- /dev/null +++ b/spec/arel/algebra/unit/relations/alias_spec.rb @@ -0,0 +1,16 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Alias do + before do + @relation = Table.new(:users) + end + + describe '==' do + it "obtains if the objects are the same" do + Alias.new(@relation).should_not == Alias.new(@relation) + (aliaz = Alias.new(@relation)).should == aliaz + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/delete_spec.rb b/spec/arel/algebra/unit/relations/delete_spec.rb new file mode 100644 index 0000000000000..075e59e7240a2 --- /dev/null +++ b/spec/arel/algebra/unit/relations/delete_spec.rb @@ -0,0 +1,9 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Deletion do + before do + @relation = Table.new(:users) + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/group_spec.rb b/spec/arel/algebra/unit/relations/group_spec.rb new file mode 100644 index 0000000000000..050de2993d56e --- /dev/null +++ b/spec/arel/algebra/unit/relations/group_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Group do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/insert_spec.rb b/spec/arel/algebra/unit/relations/insert_spec.rb new file mode 100644 index 0000000000000..184cd2a926093 --- /dev/null +++ b/spec/arel/algebra/unit/relations/insert_spec.rb @@ -0,0 +1,9 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Insert do + before do + @relation = Table.new(:users) + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/join_spec.rb b/spec/arel/algebra/unit/relations/join_spec.rb new file mode 100644 index 0000000000000..5b512cc7f6438 --- /dev/null +++ b/spec/arel/algebra/unit/relations/join_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe 'hashing' do + it 'implements hash equality' do + InnerJoin.new(@relation1, @relation2, @predicate) \ + .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) + end + end + + describe '#attributes' do + it 'combines the attributes of the two relations' do + join = InnerJoin.new(@relation1, @relation2, @predicate) + join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb new file mode 100644 index 0000000000000..0e1b1a0e546db --- /dev/null +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -0,0 +1,11 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Order do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + end +end + \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/project_spec.rb b/spec/arel/algebra/unit/relations/project_spec.rb new file mode 100644 index 0000000000000..b71acf5e9193c --- /dev/null +++ b/spec/arel/algebra/unit/relations/project_spec.rb @@ -0,0 +1,34 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Project do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#attributes' do + before do + @projection = Project.new(@relation, @attribute) + end + + it "manufactures attributes associated with the projection relation" do + @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } + end + end + + describe '#externalizable?' do + describe 'when the projections are attributes' do + it 'returns false' do + Project.new(@relation, @attribute).should_not be_externalizable + end + end + + describe 'when the projections include an aggregation' do + it "obtains" do + Project.new(@relation, @attribute.sum).should be_externalizable + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb new file mode 100644 index 0000000000000..3286f373f51fb --- /dev/null +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -0,0 +1,188 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Relation do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + end + + describe '[]' do + describe 'when given an', Attribute do + it "return the attribute congruent to the provided attribute" do + @relation[@attribute1].should == @attribute1 + end + end + + describe 'when given a', Symbol, String do + it "returns the attribute with the same name, if it exists" do + @relation[:id].should == @attribute1 + @relation['id'].should == @attribute1 + @relation[:does_not_exist].should be_nil + end + end + end + + describe Relation::Operable do + describe 'joins' do + before do + @predicate = @relation[:id].eq(@relation[:id]) + end + + describe '#join' do + describe 'when given a relation' do + it "manufactures an inner join operation between those two relations" do + @relation.join(@relation).on(@predicate). \ + should == InnerJoin.new(@relation, @relation, @predicate) + end + end + + describe "when given a string" do + it "manufactures a join operation with the string passed through" do + @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + end + end + + describe "when given something blank" do + it "returns self" do + @relation.join.should == @relation + end + end + end + + describe '#outer_join' do + it "manufactures a left outer join operation between those two relations" do + @relation.outer_join(@relation).on(@predicate). \ + should == OuterJoin.new(@relation, @relation, @predicate) + end + end + end + + describe '#project' do + it "manufactures a projection relation" do + @relation.project(@attribute1, @attribute2). \ + should == Project.new(@relation, @attribute1, @attribute2) + end + + describe "when given blank attributes" do + it "returns self" do + @relation.project.should == @relation + end + end + end + + describe '#alias' do + it "manufactures an alias relation" do + @relation.alias.relation.should == Alias.new(@relation).relation + end + end + + describe '#where' do + before do + @predicate = Equality.new(@attribute1, @attribute2) + end + + it "manufactures a where relation" do + @relation.where(@predicate).should == Where.new(@relation, @predicate) + end + + it "accepts arbitrary strings" do + @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") + end + + describe 'when given a blank predicate' do + it 'returns self' do + @relation.where.should == @relation + end + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) + end + + describe 'when given a blank ordering' do + it 'returns self' do + @relation.order.should == @relation + end + end + end + + describe '#take' do + it "manufactures a take relation" do + @relation.take(5).should == Take.new(@relation, 5) + end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.take.should == @relation + end + end + end + + describe '#skip' do + it "manufactures a skip relation" do + @relation.skip(4).should == Skip.new(@relation, 4) + end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.skip.should == @relation + end + end + end + + describe '#group' do + it 'manufactures a group relation' do + @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) + end + + describe 'when given blank groupings' do + it 'returns self' do + @relation.group.should == @relation + end + end + end + + describe Relation::Operable::Writable do + describe '#delete' do + it 'manufactures a deletion relation' do + Session.start do + mock(Session.new).delete(Deletion.new(@relation)) + @relation.delete + end + end + end + + describe '#insert' do + it 'manufactures an insertion relation' do + Session.start do + record = {@relation[:name] => 'carl'} + mock(Session.new).create(Insert.new(@relation, record)) + @relation.insert(record) + end + end + end + + describe '#update' do + it 'manufactures an update relation' do + Session.start do + assignments = {@relation[:name] => Value.new('bob', @relation)} + mock(Session.new).update(Update.new(@relation, assignments)) + @relation.update(assignments) + end + end + end + end + end + + describe Relation::Enumerable do + it "implements enumerable" do + @relation.collect.should == @relation.session.read(@relation) + @relation.first.should == @relation.session.read(@relation).first + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/skip_spec.rb b/spec/arel/algebra/unit/relations/skip_spec.rb new file mode 100644 index 0000000000000..ff57e03d1c11a --- /dev/null +++ b/spec/arel/algebra/unit/relations/skip_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Skip do + before do + @relation = Table.new(:users) + @skipped = 4 + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb new file mode 100644 index 0000000000000..4821d92299deb --- /dev/null +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Table do + before do + @relation = Table.new(:users) + end + + describe '[]' do + describe 'when given a', Symbol do + it "manufactures an attribute if the symbol names an attribute within the relation" do + @relation[:id].should == Attribute.new(@relation, :id) + @relation[:does_not_exist].should be_nil + end + end + + describe 'when given an', Attribute do + it "returns the attribute if the attribute is within the relation" do + @relation[@relation[:id]].should == @relation[:id] + end + + it "returns nil if the attribtue is not within the relation" do + another_relation = Table.new(:photos) + @relation[another_relation[:id]].should be_nil + end + end + + describe 'when given an', Expression do + before do + @expression = @relation[:id].count + end + + it "returns the Expression if the Expression is within the relation" do + @relation[@expression].should be_nil + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/take_spec.rb b/spec/arel/algebra/unit/relations/take_spec.rb new file mode 100644 index 0000000000000..6f8b4fd36e01d --- /dev/null +++ b/spec/arel/algebra/unit/relations/take_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Take do + before do + @relation = Table.new(:users) + @taken = 4 + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/update_spec.rb b/spec/arel/algebra/unit/relations/update_spec.rb new file mode 100644 index 0000000000000..c27afb48b2007 --- /dev/null +++ b/spec/arel/algebra/unit/relations/update_spec.rb @@ -0,0 +1,9 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Update do + before do + @relation = Table.new(:users) + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/where_spec.rb b/spec/arel/algebra/unit/relations/where_spec.rb new file mode 100644 index 0000000000000..3f37b531382e5 --- /dev/null +++ b/spec/arel/algebra/unit/relations/where_spec.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Where do + before do + @relation = Table.new(:users) + @predicate = @relation[:id].eq(1) + end + + describe '#initialize' do + it "manufactures nested where relations if multiple predicates are provided" do + another_predicate = @relation[:name].lt(2) + Where.new(@relation, @predicate, another_predicate). \ + should == Where.new(Where.new(@relation, another_predicate), @predicate) + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/arel/algebra/unit/session/session_spec.rb new file mode 100644 index 0000000000000..e17b5d638a8a8 --- /dev/null +++ b/spec/arel/algebra/unit/session/session_spec.rb @@ -0,0 +1,84 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Session do + before do + @relation = Table.new(:users) + @session = Session.new + end + + describe '::start' do + describe '::instance' do + it "it is a singleton within the started session" do + Session.start do + Session.new.should == Session.new + end + end + + it "is a singleton across nested sessions" do + Session.start do + outside = Session.new + Session.start do + Session.new.should == outside + end + end + end + + it "manufactures new sessions outside of the started session" do + Session.new.should_not == Session.new + end + end + end + + describe Session::CRUD do + before do + @insert = Insert.new(@relation, @relation[:name] => 'nick') + @update = Update.new(@relation, @relation[:name] => 'nick') + @delete = Deletion.new(@relation) + @read = @relation + end + + describe '#create' do + it "executes an insertion on the connection" do + mock(@insert).call + @session.create(@insert) + end + end + + describe '#read' do + it "executes an selection on the connection" do + mock(@read).call + @session.read(@read) + end + + it "is memoized" do + mock(@read).call.once + @session.read(@read) + @session.read(@read) + end + end + + describe '#update' do + it "executes an update on the connection" do + mock(@update).call + @session.update(@update) + end + end + + describe '#delete' do + it "executes a delete on the connection" do + mock(@delete).call + @session.delete(@delete) + end + end + end + + describe 'Transactions' do + describe '#begin' do + end + + describe '#end' do + end + end + end +end \ No newline at end of file diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb similarity index 98% rename from spec/arel/integration/joins/with_adjacency_spec.rb rename to spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb index ffd6498749f88..50b090844155b 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Join do diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb similarity index 98% rename from spec/arel/integration/joins/with_aggregations_spec.rb rename to spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb index 4aba005d5185d..709ae9f8d1973 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Join do diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb similarity index 97% rename from spec/arel/integration/joins/with_compounds_spec.rb rename to spec/arel/engines/sql/integration/joins/with_compounds_spec.rb index 41f04349b8bb1..4bceef4975533 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Join do diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb similarity index 97% rename from spec/arel/unit/predicates/binary_spec.rb rename to spec/arel/engines/sql/unit/predicates/binary_spec.rb index 2d0c67e006c3f..03574225c2cc0 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Binary do diff --git a/spec/arel/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb similarity index 95% rename from spec/arel/unit/predicates/equality_spec.rb rename to spec/arel/engines/sql/unit/predicates/equality_spec.rb index b595cdd247398..2ab79d702809e 100644 --- a/spec/arel/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Equality do diff --git a/spec/arel/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb similarity index 96% rename from spec/arel/unit/predicates/in_spec.rb rename to spec/arel/engines/sql/unit/predicates/in_spec.rb index 9107da9d4b19b..d977937e4e3a0 100644 --- a/spec/arel/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe In do diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb similarity index 98% rename from spec/arel/unit/primitives/attribute_spec.rb rename to spec/arel/engines/sql/unit/primitives/attribute_spec.rb index e512b40ebf505..f37cd14370c4d 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Attribute do diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/engines/sql/unit/primitives/expression_spec.rb similarity index 94% rename from spec/arel/unit/primitives/expression_spec.rb rename to spec/arel/engines/sql/unit/primitives/expression_spec.rb index 92f300c4ee405..0869d9e40335e 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/expression_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Expression do diff --git a/spec/arel/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb similarity index 89% rename from spec/arel/unit/primitives/value_spec.rb rename to spec/arel/engines/sql/unit/primitives/value_spec.rb index ba9a80bb49101..f76323f32b02a 100644 --- a/spec/arel/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Value do diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/engines/sql/unit/relations/alias_spec.rb similarity index 93% rename from spec/arel/unit/relations/alias_spec.rb rename to spec/arel/engines/sql/unit/relations/alias_spec.rb index 63c15cfeffef1..83b9113f6dfb7 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/engines/sql/unit/relations/alias_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Alias do diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/engines/sql/unit/relations/array_spec.rb similarity index 96% rename from spec/arel/unit/relations/array_spec.rb rename to spec/arel/engines/sql/unit/relations/array_spec.rb index d1c65c60a99b2..8d40858c5f3d5 100644 --- a/spec/arel/unit/relations/array_spec.rb +++ b/spec/arel/engines/sql/unit/relations/array_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Array do diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/engines/sql/unit/relations/delete_spec.rb similarity index 93% rename from spec/arel/unit/relations/delete_spec.rb rename to spec/arel/engines/sql/unit/relations/delete_spec.rb index 23aca563f7c86..7a5e2b00884b5 100644 --- a/spec/arel/unit/relations/delete_spec.rb +++ b/spec/arel/engines/sql/unit/relations/delete_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Deletion do diff --git a/spec/arel/unit/relations/group_spec.rb b/spec/arel/engines/sql/unit/relations/group_spec.rb similarity index 93% rename from spec/arel/unit/relations/group_spec.rb rename to spec/arel/engines/sql/unit/relations/group_spec.rb index 658c0ad406b28..b7279a23d9ab8 100644 --- a/spec/arel/unit/relations/group_spec.rb +++ b/spec/arel/engines/sql/unit/relations/group_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Group do diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb similarity index 96% rename from spec/arel/unit/relations/insert_spec.rb rename to spec/arel/engines/sql/unit/relations/insert_spec.rb index 5ab3ef1299549..dd1995cced17f 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Insert do diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb similarity index 96% rename from spec/arel/unit/relations/join_spec.rb rename to spec/arel/engines/sql/unit/relations/join_spec.rb index 0e3e6ef16b9a6..ea17f8106f8c5 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Join do diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/engines/sql/unit/relations/order_spec.rb similarity index 97% rename from spec/arel/unit/relations/order_spec.rb rename to spec/arel/engines/sql/unit/relations/order_spec.rb index cb0f1de84cee8..ce97a4dd5e1e2 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/engines/sql/unit/relations/order_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Order do diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/engines/sql/unit/relations/project_spec.rb similarity index 97% rename from spec/arel/unit/relations/project_spec.rb rename to spec/arel/engines/sql/unit/relations/project_spec.rb index d2d1fb3873929..9d6b9fab06b04 100644 --- a/spec/arel/unit/relations/project_spec.rb +++ b/spec/arel/engines/sql/unit/relations/project_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Project do diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/engines/sql/unit/relations/relation_spec.rb similarity index 98% rename from spec/arel/unit/relations/relation_spec.rb rename to spec/arel/engines/sql/unit/relations/relation_spec.rb index 6a61f39966731..9a5cfbff4114c 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/engines/sql/unit/relations/relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Relation do diff --git a/spec/arel/unit/relations/skip_spec.rb b/spec/arel/engines/sql/unit/relations/skip_spec.rb similarity index 87% rename from spec/arel/unit/relations/skip_spec.rb rename to spec/arel/engines/sql/unit/relations/skip_spec.rb index 2c8f6ccadb613..f8e5ceaad3658 100644 --- a/spec/arel/unit/relations/skip_spec.rb +++ b/spec/arel/engines/sql/unit/relations/skip_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Skip do diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb similarity index 96% rename from spec/arel/unit/relations/table_spec.rb rename to spec/arel/engines/sql/unit/relations/table_spec.rb index 2779c0fe5dfd1..6de49a91571fb 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Table do diff --git a/spec/arel/unit/relations/take_spec.rb b/spec/arel/engines/sql/unit/relations/take_spec.rb similarity index 87% rename from spec/arel/unit/relations/take_spec.rb rename to spec/arel/engines/sql/unit/relations/take_spec.rb index d6442fc9d1458..1263ed4795906 100644 --- a/spec/arel/unit/relations/take_spec.rb +++ b/spec/arel/engines/sql/unit/relations/take_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Take do diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb similarity index 97% rename from spec/arel/unit/relations/update_spec.rb rename to spec/arel/engines/sql/unit/relations/update_spec.rb index e0d7ddd2951cd..f553490ef584d 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Update do diff --git a/spec/arel/unit/relations/where_spec.rb b/spec/arel/engines/sql/unit/relations/where_spec.rb similarity index 95% rename from spec/arel/unit/relations/where_spec.rb rename to spec/arel/engines/sql/unit/relations/where_spec.rb index 64f97c8135fcf..5870b6b79361a 100644 --- a/spec/arel/unit/relations/where_spec.rb +++ b/spec/arel/engines/sql/unit/relations/where_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Where do diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/engines/sql/unit/session/session_spec.rb similarity index 95% rename from spec/arel/unit/session/session_spec.rb rename to spec/arel/engines/sql/unit/session/session_spec.rb index c30ba6195fa7f..c489984a612c9 100644 --- a/spec/arel/unit/session/session_spec.rb +++ b/spec/arel/engines/sql/unit/session/session_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Session do From 4c71e3b2ea4b8da574954cbd8a26d12f2cc640d0 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:41:49 -0400 Subject: [PATCH 0224/1492] removed duplicates from sql tests Conflicts: spec/arel/engines/sql/unit/predicates/binary_spec.rb spec/arel/engines/sql/unit/predicates/equality_spec.rb spec/arel/engines/sql/unit/primitives/attribute_spec.rb spec/arel/engines/sql/unit/primitives/expression_spec.rb spec/arel/engines/sql/unit/relations/alias_spec.rb spec/arel/engines/sql/unit/relations/join_spec.rb spec/arel/engines/sql/unit/relations/project_spec.rb spec/arel/engines/sql/unit/relations/relation_spec.rb spec/arel/engines/sql/unit/relations/table_spec.rb spec/arel/engines/sql/unit/relations/where_spec.rb spec/arel/engines/sql/unit/session/session_spec.rb --- .../unit/relations/array_spec.rb | 0 .../sql/unit/predicates/binary_spec.rb | 20 --- .../sql/unit/predicates/equality_spec.rb | 15 -- .../sql/unit/primitives/attribute_spec.rb | 141 +-------------- .../sql/unit/primitives/expression_spec.rb | 29 --- .../engines/sql/unit/primitives/value_spec.rb | 6 - .../engines/sql/unit/relations/alias_spec.rb | 7 - .../engines/sql/unit/relations/join_spec.rb | 21 --- .../sql/unit/relations/project_spec.rb | 24 --- .../sql/unit/relations/relation_spec.rb | 169 ------------------ .../engines/sql/unit/relations/table_spec.rb | 30 ---- .../engines/sql/unit/relations/where_spec.rb | 8 - .../engines/sql/unit/session/session_spec.rb | 84 --------- 13 files changed, 1 insertion(+), 553 deletions(-) rename spec/arel/engines/{sql => memory}/unit/relations/array_spec.rb (100%) delete mode 100644 spec/arel/engines/sql/unit/relations/relation_spec.rb delete mode 100644 spec/arel/engines/sql/unit/session/session_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/array_spec.rb rename to spec/arel/engines/memory/unit/relations/array_spec.rb diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 03574225c2cc0..679147067ec6c 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -101,25 +101,5 @@ def predicate_sql end end end - - describe '#bind' do - before do - @another_relation = @relation.alias - end - - describe 'when both operands are attributes' do - it "manufactures an expression with the attributes bound to the relation" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ - should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) - end - end - - describe 'when an operand is a value' do - it "manufactures an expression with unmodified values" do - ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) - end - end - end end end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index 2ab79d702809e..e8c8c4267593a 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -9,21 +9,6 @@ module Arel @attribute2 = @relation2[:user_id] end - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) - Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the predicates are identical" do - Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) - end - - it "is commutative on the attributes" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) - end - end - describe '#to_sql' do describe 'when relating to a non-nil value' do it "manufactures an equality predicate" do diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index f37cd14370c4d..e71ab949f1076 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -7,67 +7,12 @@ module Arel @attribute = @relation[:id] end - describe Attribute::Transformations do - describe '#as' do - it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) - end - end - - describe '#bind' do - it "manufactures an attribute with the relation bound and self as an ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) - end - - it "returns self if the substituting to the same relation" do - @attribute.bind(@relation).should == @attribute - end - end - - describe '#to_attribute' do - it "returns self" do - @attribute.to_attribute.should == @attribute - end - end - end - describe '#column' do it "returns the corresponding column in the relation" do @attribute.column.should == @relation.column_for(@attribute) end end - - describe '#engine' do - it "delegates to its relation" do - Attribute.new(@relation, :id).engine.should == @relation.engine - end - end - - describe Attribute::Congruence do - describe '/' do - before do - @aliased_relation = @relation.alias - @doubly_aliased_relation = @aliased_relation.alias - end - - describe 'when dividing two unrelated attributes' do - it "returns 0.0" do - (@relation[:id] / @relation[:name]).should == 0.0 - end - end - - describe 'when dividing two matching attributes' do - it 'returns a the highest score for the most similar attributes' do - (@aliased_relation[:id] / @relation[:id]) \ - .should == (@aliased_relation[:id] / @relation[:id]) - (@aliased_relation[:id] / @relation[:id]) \ - .should < (@aliased_relation[:id] / @aliased_relation[:id]) - end - end - end - end - + describe '#to_sql' do describe 'for a simple attribute' do it "manufactures sql with an alias" do @@ -83,89 +28,5 @@ module Arel end end end - - describe Attribute::Predications do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#eq' do - it "manufactures an equality predicate" do - @attribute.eq('name').should == Equality.new(@attribute, 'name') - end - end - - describe '#lt' do - it "manufactures a less-than predicate" do - @attribute.lt(10).should == LessThan.new(@attribute, 10) - end - end - - describe '#lteq' do - it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#gt' do - it "manufactures a greater-than predicate" do - @attribute.gt(10).should == GreaterThan.new(@attribute, 10) - end - end - - describe '#gteq' do - it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#matches' do - it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) - end - end - - describe '#in' do - it "manufactures an in predicate" do - @attribute.in(1..30).should == In.new(@attribute, (1..30)) - end - end - end - - describe Attribute::Expressions do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#count' do - it "manufactures a count Expression" do - @attribute.count.should == Count.new(@attribute) - end - end - - describe '#sum' do - it "manufactures a sum Expression" do - @attribute.sum.should == Sum.new(@attribute) - end - end - - describe '#maximum' do - it "manufactures a maximum Expression" do - @attribute.maximum.should == Maximum.new(@attribute) - end - end - - describe '#minimum' do - it "manufactures a minimum Expression" do - @attribute.minimum.should == Minimum.new(@attribute) - end - end - - describe '#average' do - it "manufactures an average Expression" do - @attribute.average.should == Average.new(@attribute) - end - end - end end end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/primitives/expression_spec.rb b/spec/arel/engines/sql/unit/primitives/expression_spec.rb index 0869d9e40335e..ee7f2c1461750 100644 --- a/spec/arel/engines/sql/unit/primitives/expression_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/expression_spec.rb @@ -7,35 +7,6 @@ module Arel @attribute = @relation[:id] end - describe Expression::Transformations do - before do - @expression = Count.new(@attribute) - end - - describe '#bind' do - it "manufactures an attribute with a rebound relation and self as the ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) - end - - it "returns self if the substituting to the same relation" do - @expression.bind(@relation).should == @expression - end - end - - describe '#as' do - it "manufactures an aliased expression" do - @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) - end - end - - describe '#to_attribute' do - it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) - end - end - end - describe '#to_sql' do it "manufactures sql with the expression and alias" do sql = Count.new(@attribute, :alias).to_sql diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb index f76323f32b02a..da5a163d3bafd 100644 --- a/spec/arel/engines/sql/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -18,11 +18,5 @@ module Arel Value.new(1, @relation).format(@relation[:id]).should == @relation[:id].to_sql end end - - describe '#bind' do - it "manufactures a new value whose relation is the provided relation" do - Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) - end - end end end diff --git a/spec/arel/engines/sql/unit/relations/alias_spec.rb b/spec/arel/engines/sql/unit/relations/alias_spec.rb index 83b9113f6dfb7..b67a0bbc89333 100644 --- a/spec/arel/engines/sql/unit/relations/alias_spec.rb +++ b/spec/arel/engines/sql/unit/relations/alias_spec.rb @@ -6,13 +6,6 @@ module Arel @relation = Table.new(:users) end - describe '==' do - it "obtains if the objects are the same" do - Alias.new(@relation).should_not == Alias.new(@relation) - (aliaz = Alias.new(@relation)).should == aliaz - end - end - describe '#to_sql' do describe 'when there is no ambiguity' do it 'does not alias table names anywhere a table name can appear' do diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index ea17f8106f8c5..1f4310113353a 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -8,27 +8,6 @@ module Arel @predicate = @relation1[:id].eq(@relation2[:user_id]) end - describe 'hashing' do - it 'implements hash equality' do - InnerJoin.new(@relation1, @relation2, @predicate) \ - .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) - end - end - - describe '#engine' do - it "delegates to a relation's engine" do - InnerJoin.new(@relation1, @relation2, @predicate).engine.should == @relation1.engine - end - end - - describe '#attributes' do - it 'combines the attributes of the two relations' do - join = InnerJoin.new(@relation1, @relation2, @predicate) - join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } - end - end - describe '#to_sql' do describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do diff --git a/spec/arel/engines/sql/unit/relations/project_spec.rb b/spec/arel/engines/sql/unit/relations/project_spec.rb index 9d6b9fab06b04..5e29124cfa0dd 100644 --- a/spec/arel/engines/sql/unit/relations/project_spec.rb +++ b/spec/arel/engines/sql/unit/relations/project_spec.rb @@ -7,16 +7,6 @@ module Arel @attribute = @relation[:id] end - describe '#attributes' do - before do - @projection = Project.new(@relation, @attribute) - end - - it "manufactures attributes associated with the projection relation" do - @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } - end - end - describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do @@ -116,19 +106,5 @@ module Arel end end end - - describe '#externalizable?' do - describe 'when the projections are attributes' do - it 'returns false' do - Project.new(@relation, @attribute).should_not be_externalizable - end - end - - describe 'when the projections include an aggregation' do - it "obtains" do - Project.new(@relation, @attribute.sum).should be_externalizable - end - end - end end end diff --git a/spec/arel/engines/sql/unit/relations/relation_spec.rb b/spec/arel/engines/sql/unit/relations/relation_spec.rb deleted file mode 100644 index 9a5cfbff4114c..0000000000000 --- a/spec/arel/engines/sql/unit/relations/relation_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') - -module Arel - describe Relation do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - end - - describe '[]' do - describe 'when given an', Attribute do - it "return the attribute congruent to the provided attribute" do - @relation[@attribute1].should == @attribute1 - end - end - - describe 'when given a', Symbol, String do - it "returns the attribute with the same name, if it exists" do - @relation[:id].should == @attribute1 - @relation['id'].should == @attribute1 - @relation[:does_not_exist].should be_nil - end - end - end - - describe Relation::Operable do - describe 'joins' do - before do - @predicate = @relation[:id].eq(@relation[:id]) - end - - describe '#join' do - describe 'when given a relation' do - it "manufactures an inner join operation between those two relations" do - @relation.join(@relation).on(@predicate). \ - should == InnerJoin.new(@relation, @relation, @predicate) - end - end - - describe "when given a string" do - it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) - end - end - - describe "when given something blank" do - it "returns self" do - @relation.join.should == @relation - end - end - end - - describe '#outer_join' do - it "manufactures a left outer join operation between those two relations" do - @relation.outer_join(@relation).on(@predicate). \ - should == OuterJoin.new(@relation, @relation, @predicate) - end - end - end - - describe '#project' do - it "manufactures a projection relation" do - @relation.project(@attribute1, @attribute2). \ - should == Project.new(@relation, @attribute1, @attribute2) - end - - describe "when given blank attributes" do - it "returns self" do - @relation.project.should == @relation - end - end - end - - describe '#alias' do - it "manufactures an alias relation" do - @relation.alias.relation.should == Alias.new(@relation).relation - end - end - - describe '#where' do - before do - @predicate = Equality.new(@attribute1, @attribute2) - end - - it "manufactures a where relation" do - @relation.where(@predicate).should == Where.new(@relation, @predicate) - end - - it "accepts arbitrary strings" do - @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") - end - - describe 'when given a blank predicate' do - it 'returns self' do - @relation.where.should == @relation - end - end - end - - describe '#order' do - it "manufactures an order relation" do - @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) - end - - describe 'when given a blank ordering' do - it 'returns self' do - @relation.order.should == @relation - end - end - end - - describe '#take' do - it "manufactures a take relation" do - @relation.take(5).should == Take.new(@relation, 5) - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.take.should == @relation - end - end - end - - describe '#skip' do - it "manufactures a skip relation" do - @relation.skip(4).should == Skip.new(@relation, 4) - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.skip.should == @relation - end - end - end - - describe '#group' do - it 'manufactures a group relation' do - @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) - end - - describe 'when given blank groupings' do - it 'returns self' do - @relation.group.should == @relation - end - end - end - - describe Relation::Operable::Writable do - describe '#insert' do - it 'manufactures an insertion relation' do - Session.start do - record = {@relation[:name] => 'carl'} - mock(Session.new).create(Insert.new(@relation, record)) - @relation.insert(record).should == @relation - end - end - end - end - end - - describe Relation::Enumerable do - it "implements enumerable" do - @relation.collect.should == @relation.session.read(@relation) - @relation.first.should == @relation.session.read(@relation).first - end - end - end -end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 6de49a91571fb..3f5a5ac248a6f 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -6,36 +6,6 @@ module Arel @relation = Table.new(:users) end - describe '[]' do - describe 'when given a', Symbol do - it "manufactures an attribute if the symbol names an attribute within the relation" do - @relation[:id].should == Attribute.new(@relation, :id) - @relation[:does_not_exist].should be_nil - end - end - - describe 'when given an', Attribute do - it "returns the attribute if the attribute is within the relation" do - @relation[@relation[:id]].should == @relation[:id] - end - - it "returns nil if the attribtue is not within the relation" do - another_relation = Table.new(:photos) - @relation[another_relation[:id]].should be_nil - end - end - - describe 'when given an', Expression do - before do - @expression = @relation[:id].count - end - - it "returns the Expression if the Expression is within the relation" do - @relation[@expression].should be_nil - end - end - end - describe '#to_sql' do it "manufactures a simple select query" do sql = @relation.to_sql diff --git a/spec/arel/engines/sql/unit/relations/where_spec.rb b/spec/arel/engines/sql/unit/relations/where_spec.rb index 5870b6b79361a..4f0cce1e019bf 100644 --- a/spec/arel/engines/sql/unit/relations/where_spec.rb +++ b/spec/arel/engines/sql/unit/relations/where_spec.rb @@ -7,14 +7,6 @@ module Arel @predicate = @relation[:id].eq(1) end - describe '#initialize' do - it "manufactures nested where relations if multiple predicates are provided" do - another_predicate = @relation[:name].lt(2) - Where.new(@relation, @predicate, another_predicate). \ - should == Where.new(Where.new(@relation, another_predicate), @predicate) - end - end - describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do diff --git a/spec/arel/engines/sql/unit/session/session_spec.rb b/spec/arel/engines/sql/unit/session/session_spec.rb deleted file mode 100644 index c489984a612c9..0000000000000 --- a/spec/arel/engines/sql/unit/session/session_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') - -module Arel - describe Session do - before do - @relation = Table.new(:users) - @session = Session.new - end - - describe '::start' do - describe '::instance' do - it "it is a singleton within the started session" do - Session.start do - Session.new.should == Session.new - end - end - - it "is a singleton across nested sessions" do - Session.start do - outside = Session.new - Session.start do - Session.new.should == outside - end - end - end - - it "manufactures new sessions outside of the started session" do - Session.new.should_not == Session.new - end - end - end - - describe Session::CRUD do - before do - @insert = Insert.new(@relation, @relation[:name] => 'nick') - @update = Update.new(@relation, @relation[:name] => 'nick') - @delete = Deletion.new(@relation) - @read = @relation - end - - describe '#create' do - it "executes an insertion on the connection" do - mock(@insert).call - @session.create(@insert) - end - end - - describe '#read' do - it "executes an selection on the connection" do - mock(@read).call - @session.read(@read) - end - - it "is memoized" do - mock(@read).call.once - @session.read(@read) - @session.read(@read) - end - end - - describe '#update' do - it "executes an update on the connection" do - mock(@update).call - @session.update(@update) - end - end - - describe '#delete' do - it "executes a delete on the connection" do - mock(@delete).call - @session.delete(@delete) - end - end - end - - describe 'Transactions' do - describe '#begin' do - end - - describe '#end' do - end - end - end -end From 8339f024c7663133a78c4d0a8824b5b6fafaf239 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:42:42 -0400 Subject: [PATCH 0225/1492] recursive memory operations now possible Conflicts: lib/arel/algebra/relations/relation.rb --- doc/TODO | 7 +- lib/arel/algebra/extensions/hash.rb | 7 -- lib/arel/algebra/relations.rb | 1 + lib/arel/algebra/relations/relation.rb | 4 - lib/arel/algebra/relations/row.rb | 21 +++++ lib/arel/engines/memory/predicates.rb | 6 ++ lib/arel/engines/memory/relations.rb | 1 + lib/arel/engines/memory/relations/array.rb | 2 +- lib/arel/engines/memory/relations/compound.rb | 4 + .../engines/memory/relations/operations.rb | 10 +-- lib/arel/engines/memory/relations/relation.rb | 7 ++ .../memory/unit/relations/array_spec.rb | 83 +++++++++++++------ 12 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 lib/arel/algebra/relations/row.rb create mode 100644 lib/arel/engines/memory/relations/relation.rb diff --git a/doc/TODO b/doc/TODO index f97e74ef17c4e..7af8db6bdf73d 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,11 +1,11 @@ todo: -- reorganize sql tests +- recursive memory operations - reorganize memory tests -- blocks for joins +- deal with table tests in algebra - implement joins in memory -- recursive memory operations - result sets should be array relations - cross-engine joins +- blocks for joins - fix grouping - implement mnesia adapter - fix AR @@ -92,6 +92,7 @@ done: - expressions should be class-based, and joins too, anything _sql should be renamed - implement in memory adapter - clean up block_given stuff +- reorganize sql tests icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index bc97785e62de7..7472b5aa731ad 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -4,11 +4,4 @@ def bind(relation) bound.merge(key.bind(relation) => value.bind(relation)) end end - - def slice(*attributes) - inject({}) do |cheese, (key, value)| - cheese[key] = value if attributes.include?(key) - cheese - end - end end \ No newline at end of file diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index b75a31e5e3360..94df5938fecec 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -2,6 +2,7 @@ require 'arel/algebra/relations/utilities/compound' require 'arel/algebra/relations/utilities/nil' require 'arel/algebra/relations/utilities/externalization' +require 'arel/algebra/relations/row' require 'arel/algebra/relations/writes' require 'arel/algebra/relations/operations/alias' require 'arel/algebra/relations/operations/group' diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 6d76e66638c9a..fe8cab4b024a1 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -14,10 +14,6 @@ def bind(relation) self end - def root - self - end - module Enumerable include ::Enumerable diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb new file mode 100644 index 0000000000000..2d634984522bc --- /dev/null +++ b/lib/arel/algebra/relations/row.rb @@ -0,0 +1,21 @@ +module Arel + class Row + attributes :relation, :tuple + deriving :==, :initialize + + def [](attribute) + tuple[relation.position_of(attribute)] + end + + def slice(*attributes) + Row.new(relation, attributes.inject([]) do |cheese, attribute| + cheese << self[attribute] + cheese + end) + end + + def bind(relation) + Row.new(relation, tuple) + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index bbf39ba794c09..e233f3ba39037 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -21,15 +21,19 @@ def predicate_sql; "AND" end end class Equality < Binary + def operator; :== end end class GreaterThanOrEqualTo < Binary + def operator; :>= end end class GreaterThan < Binary + def operator; :> end end class LessThanOrEqualTo < Binary + def operator; :<= end end class LessThan < Binary @@ -37,8 +41,10 @@ def operator; :< end end class Match < Binary + def operator; :=~ end end class In < Binary + def operator; :include? end end end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 1b009537b9bad..820b0af4b2760 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,3 +1,4 @@ +require 'arel/engines/memory/relations/relation' require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index c02c62891b25c..ea0b5af5ba5a2 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -15,7 +15,7 @@ def attributes end def eval - @array.collect { |row| attributes.zip(row).to_hash } + @array.collect { |r| Row.new(self, r) } end end end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index b029082d57400..3791fa4622943 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -1,5 +1,9 @@ module Arel class Compound < Relation delegate :array, :to => :relation + + def unoperated_rows + relation.eval.collect { |row| row.bind(self) } + end end end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 115df054df2a7..8e03aca7b1495 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -1,13 +1,13 @@ module Arel class Where < Compound def eval - relation.eval.select { |row| predicate.eval(row) } + unoperated_rows.select { |row| predicate.eval(row) } end end class Order < Compound def eval - relation.eval.sort do |row1, row2| + unoperated_rows.sort do |row1, row2| ordering = orderings.detect { |o| o.eval(row1, row2) != 0 } || orderings.last ordering.eval(row1, row2) end @@ -16,19 +16,19 @@ def eval class Project < Compound def eval - relation.eval.collect { |r| r.slice(*projections) } + unoperated_rows.collect { |r| r.slice(*projections) } end end class Take < Compound def eval - relation.eval[0, taken] + unoperated_rows[0, taken] end end class Skip < Compound def eval - relation.eval[skipped..-1] + unoperated_rows[skipped..-1] end end diff --git a/lib/arel/engines/memory/relations/relation.rb b/lib/arel/engines/memory/relations/relation.rb new file mode 100644 index 0000000000000..abfb8bb37fb30 --- /dev/null +++ b/lib/arel/engines/memory/relations/relation.rb @@ -0,0 +1,7 @@ +module Arel + class Relation + def position_of(attribute) + attributes.index(self[attribute]) + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 8d40858c5f3d5..22cddf7156341 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -22,61 +22,92 @@ module Arel describe '#call' do it "manufactures an array of hashes of attributes to values" do @relation.call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } + Row.new(@relation, [1, 'duck']), + Row.new(@relation, [2, 'duck']), + Row.new(@relation, [3, 'goose']) ] end describe 'where' do + xit 'filters the relation with the provided predicate' do + @relation \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end + end + it 'filters the relation with the provided predicate' do - @relation.where(@relation[:id].lt(3)).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] + @relation \ + .where(@relation[:id].gt(1)) \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']) + ] + end end end describe 'group' do - it 'sorts the relation with the provided ordering' do + xit 'sorts the relation with the provided ordering' do end end describe 'order' do it 'sorts the relation with the provided ordering' do - @relation.order(@relation[:id].desc).call.should == [ - { @relation[:id] => 3, @relation[:name] => 'goose' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 1, @relation[:name] => 'duck' } - ] + @relation \ + .order(@relation[:id].desc) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [3, 'goose']), + Row.new(relation, [2, 'duck']), + Row.new(relation, [1, 'duck']) + ] + end end end describe 'project' do it 'projects' do - @relation.project(@relation[:id]).call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 }, - { @relation[:id] => 3 } - ] + @relation \ + .project(@relation[:id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1]), + Row.new(relation, [2]), + Row.new(relation, [3]) + ] + end end end describe 'skip' do it 'slices' do - @relation.skip(1).call.should == [ - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } - ] + @relation \ + .skip(1) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + ] + end end end describe 'take' do it 'dices' do - @relation.take(2).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] + @relation \ + .take(2) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end end end From b7f58db57a535806e0cfc3057fbab80ca43b1a53 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:44:03 -0400 Subject: [PATCH 0226/1492] better test ordering Conflicts: doc/TODO --- doc/TODO | 9 +- .../memory/unit/relations/array_spec.rb | 86 ------------------- .../memory/unit/relations/order_spec.rb | 27 ++++++ .../memory/unit/relations/project_spec.rb | 27 ++++++ .../memory/unit/relations/skip_spec.rb | 26 ++++++ .../memory/unit/relations/take_spec.rb | 26 ++++++ .../memory/unit/relations/where_spec.rb | 39 +++++++++ 7 files changed, 149 insertions(+), 91 deletions(-) create mode 100644 spec/arel/engines/memory/unit/relations/order_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/project_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/skip_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/take_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/where_spec.rb diff --git a/doc/TODO b/doc/TODO index 7af8db6bdf73d..2070a26efc984 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,13 +1,12 @@ todo: -- recursive memory operations - reorganize memory tests -- deal with table tests in algebra - implement joins in memory - result sets should be array relations +- deal with table tests in algebra - cross-engine joins - blocks for joins -- fix grouping - implement mnesia adapter +- fix grouping - fix AR - rename externalize to derived. @@ -15,7 +14,6 @@ todo: - audit unit coverage of algebra - data objects - remove all explicit aliasing -- and/or w/ predicates - scoped writes - refactor adapter pattern - break out adapters into sep modules @@ -26,7 +24,6 @@ todo: done: - and/or w/ predicates -- mock out database . Relation <=> Relation -> InnerJoinOperation . Relation << Relation -> LeftOuterJoinOperation . InnerJoinOperation.on(*Predicate) -> InnerJoinRelation @@ -77,6 +74,7 @@ done: - test Value, in particular bind. - test blank checks in relation.rb - rename active_relation to arel +- mock out database - fix complex joining cases: - active record query adapter - anonymous table names @@ -93,6 +91,7 @@ done: - implement in memory adapter - clean up block_given stuff - reorganize sql tests +- recursive memory operations icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 22cddf7156341..4fe24c77fac5a 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -27,92 +27,6 @@ module Arel Row.new(@relation, [3, 'goose']) ] end - - describe 'where' do - xit 'filters the relation with the provided predicate' do - @relation \ - .where(@relation[:id].lt(3)) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - ] - end - end - - it 'filters the relation with the provided predicate' do - @relation \ - .where(@relation[:id].gt(1)) \ - .where(@relation[:id].lt(3)) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [2, 'duck']) - ] - end - end - end - - describe 'group' do - xit 'sorts the relation with the provided ordering' do - end - end - - describe 'order' do - it 'sorts the relation with the provided ordering' do - @relation \ - .order(@relation[:id].desc) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [3, 'goose']), - Row.new(relation, [2, 'duck']), - Row.new(relation, [1, 'duck']) - ] - end - end - end - - describe 'project' do - it 'projects' do - @relation \ - .project(@relation[:id]) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1]), - Row.new(relation, [2]), - Row.new(relation, [3]) - ] - end - end - end - - describe 'skip' do - it 'slices' do - @relation \ - .skip(1) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [2, 'duck']), - Row.new(relation, [3, 'goose']), - ] - end - end - end - - describe 'take' do - it 'dices' do - @relation \ - .take(2) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - ] - end - end - end - - describe 'join' do - end end end end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/arel/engines/memory/unit/relations/order_spec.rb new file mode 100644 index 0000000000000..3ecb31068bb32 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/order_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Order do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'sorts the relation with the provided ordering' do + @relation \ + .order(@relation[:id].desc) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [3, 'goose']), + Row.new(relation, [2, 'duck' ]), + Row.new(relation, [1, 'duck' ]) + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/arel/engines/memory/unit/relations/project_spec.rb new file mode 100644 index 0000000000000..1d1224cfdcd24 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/project_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Project do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'retains only the attributes that are provided' do + @relation \ + .project(@relation[:id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1]), + Row.new(relation, [2]), + Row.new(relation, [3]) + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/arel/engines/memory/unit/relations/skip_spec.rb new file mode 100644 index 0000000000000..86db45ef611e4 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/skip_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Skip do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'removes the first n rows' do + @relation \ + .skip(1) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/arel/engines/memory/unit/relations/take_spec.rb new file mode 100644 index 0000000000000..8b774987e05c7 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/take_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Take do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'removes the rows after the first n' do + @relation \ + .take(2) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/arel/engines/memory/unit/relations/where_spec.rb new file mode 100644 index 0000000000000..d75ee5dcbe450 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/where_spec.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Where do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'filters the relation with the provided predicate' do + @relation \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end + end + + describe 'when filtering a where relation' do + it 'further filters the already-filtered relation with the provided predicate' do + @relation \ + .where(@relation[:id].gt(1)) \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']) + ] + end + end + end + end + end +end \ No newline at end of file From 2fe585328d6a24df310d3e60059c9c7b05b64bac Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 27 May 2008 14:19:59 -0700 Subject: [PATCH 0227/1492] performing in memory joins --- doc/TODO | 8 ++--- lib/arel/algebra/relations/row.rb | 4 +++ .../engines/memory/relations/operations.rb | 21 ++++++++++++ .../memory/unit/relations/join_spec.rb | 32 +++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 spec/arel/engines/memory/unit/relations/join_spec.rb diff --git a/doc/TODO b/doc/TODO index 2070a26efc984..3f8c34f66068f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,16 +1,13 @@ todo: -- reorganize memory tests -- implement joins in memory - result sets should be array relations - deal with table tests in algebra - cross-engine joins - blocks for joins - implement mnesia adapter -- fix grouping - fix AR - rename externalize to derived. -- result sets to attr correlation too +- fix grouping - audit unit coverage of algebra - data objects - remove all explicit aliasing @@ -92,6 +89,9 @@ done: - clean up block_given stuff - reorganize sql tests - recursive memory operations +- reorganize memory tests +- result sets to attr correlation too +- implement joins in memory icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index 2d634984522bc..3731dd96962ac 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -17,5 +17,9 @@ def slice(*attributes) def bind(relation) Row.new(relation, tuple) end + + def combine(other, relation) + Row.new(relation, tuple + other.tuple) + end end end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 8e03aca7b1495..e35fbe3234cc2 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -37,4 +37,25 @@ def eval raise NotImplementedError end end + + class Alias < Compound + def eval + unoperated_rows + end + end + + class Join < Relation + def eval + result = [] + relation1.eval.each do |row1| + relation2.eval.each do |row2| + combined_row = row1.combine(row2, self) + if predicates.all? { |p| p.eval(combined_row) } + result << combined_row + end + end + end + result + end + end end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb new file mode 100644 index 0000000000000..920cc55d0a4cb --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -0,0 +1,32 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + @relation2 = @relation1.alias + @relation3 = @relation1.alias + end + + describe InnerJoin do + describe '#call' do + it 'combines the two tables where the predicate obtains' do + @relation1 \ + .join(@relation2) \ + .on(@relation1[:id].eq(@relation2[:id])) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck', 1, 'duck' ]), + Row.new(relation, [2, 'duck', 2, 'duck' ]), + Row.new(relation, [3, 'goose', 3, 'goose']) + ] + end + end + end + end + end +end \ No newline at end of file From 20b28b441b651d0404d64049253898c061a039be Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 27 May 2008 14:37:11 -0700 Subject: [PATCH 0228/1492] using in memory relations as results from sql relation Conflicts: lib/arel/algebra/primitives/expression.rb lib/arel/algebra/relations/relation.rb --- doc/TODO | 6 +++--- lib/arel/algebra/extensions.rb | 1 + lib/arel/algebra/extensions/symbol.rb | 5 +++++ lib/arel/algebra/primitives/attribute.rb | 4 ++-- lib/arel/algebra/primitives/expression.rb | 2 +- lib/arel/algebra/relations/relation.rb | 11 +++++++++-- .../algebra/relations/utilities/externalization.rb | 2 +- lib/arel/engines/memory/relations.rb | 1 - lib/arel/engines/memory/relations/array.rb | 4 ++-- lib/arel/engines/memory/relations/relation.rb | 7 ------- lib/arel/engines/sql/engine.rb | 10 +++++----- lib/arel/engines/sql/relations/operations/join.rb | 2 +- spec/arel/algebra/unit/primitives/attribute_spec.rb | 12 ++++++++++-- spec/arel/algebra/unit/primitives/expression_spec.rb | 2 +- spec/arel/algebra/unit/relations/relation_spec.rb | 10 +++++----- 15 files changed, 46 insertions(+), 33 deletions(-) create mode 100644 lib/arel/algebra/extensions/symbol.rb delete mode 100644 lib/arel/engines/memory/relations/relation.rb diff --git a/doc/TODO b/doc/TODO index 3f8c34f66068f..7e7028d39f7d1 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,10 +1,9 @@ todo: -- result sets should be array relations -- deal with table tests in algebra +- fix AR - cross-engine joins - blocks for joins +- deal with table tests in algebra - implement mnesia adapter -- fix AR - rename externalize to derived. - fix grouping @@ -92,6 +91,7 @@ done: - reorganize memory tests - result sets to attr correlation too - implement joins in memory +- result sets should be array relations icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb index 5338fee989dd0..694dc60a2a391 100644 --- a/lib/arel/algebra/extensions.rb +++ b/lib/arel/algebra/extensions.rb @@ -1,4 +1,5 @@ require 'arel/algebra/extensions/object' require 'arel/algebra/extensions/class' require 'arel/algebra/extensions/array' +require 'arel/algebra/extensions/symbol' require 'arel/algebra/extensions/hash' diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb new file mode 100644 index 0000000000000..787867bdc3feb --- /dev/null +++ b/lib/arel/algebra/extensions/symbol.rb @@ -0,0 +1,5 @@ +class Symbol + def to_attribute(relation) + Arel::Attribute.new(relation, self) + end +end \ No newline at end of file diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 7a4411e248add..aa1f2ae00cf32 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -39,8 +39,8 @@ def bind(new_relation) relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) end - def to_attribute - self + def to_attribute(relation) + bind(relation) end end include Transformations diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb index 989397720cb12..5566e2d0b79e3 100644 --- a/lib/arel/algebra/primitives/expression.rb +++ b/lib/arel/algebra/primitives/expression.rb @@ -22,7 +22,7 @@ def bind(new_relation) new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) end - def to_attribute + def to_attribute(relation) Attribute.new(relation, @alias, :ancestor => self) end end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index fe8cab4b024a1..c38ab0e9c578f 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -31,7 +31,7 @@ module Operable def join(other_relation = nil, join_class = InnerJoin) case other_relation when String - StringJoin.new(other_relation, self) + StringJoin.new(self, other_relation) when Relation JoinOperation.new(join_class, self, other_relation) else @@ -85,7 +85,8 @@ def [](index) find_attribute_matching_name(index) when Attribute, Expression find_attribute_matching_attribute(index) - when Array + when ::Array + # TESTME index.collect { |i| self[i] } end end @@ -100,6 +101,12 @@ def find_attribute_matching_attribute(attribute) end end + def position_of(attribute) + (@position_of ||= Hash.new do |h, attribute| + h[attribute] = attributes.index(self[attribute]) + end)[attribute] + end + private def matching_attributes(attribute) (@matching_attributes ||= attributes.inject({}) do |hash, a| diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index bd067f230441a..13758ccec9802 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -8,7 +8,7 @@ def wheres end def attributes - @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } + @attributes ||= relation.attributes.collect { |a| a.to_attribute(self) } end end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 820b0af4b2760..1b009537b9bad 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,4 +1,3 @@ -require 'arel/engines/memory/relations/relation' require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index ea0b5af5ba5a2..15a3e95e1b5ea 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -1,8 +1,8 @@ module Arel class Array < Relation attributes :array, :attribute_names - deriving :initialize include Recursion::BaseCase + deriving :==, :initialize def engine @engine ||= Memory::Engine.new @@ -10,7 +10,7 @@ def engine def attributes @attributes ||= @attribute_names.collect do |name| - Attribute.new(self, name.to_sym) + name.to_attribute(self) end end diff --git a/lib/arel/engines/memory/relations/relation.rb b/lib/arel/engines/memory/relations/relation.rb deleted file mode 100644 index abfb8bb37fb30..0000000000000 --- a/lib/arel/engines/memory/relations/relation.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Relation - def position_of(attribute) - attributes.index(self[attribute]) - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index e5d1a8b0cad92..0700ae9733e25 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -19,12 +19,12 @@ def create(relation) end def read(relation) - results = connection.execute(relation.to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash + # FIXME + class << rows = connection.execute(relation.to_sql) + include Enumerable end - rows + + Array.new(rows, relation.attributes) end def update(relation) diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index 2f5e23644e95b..f848fd326892a 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -22,7 +22,7 @@ def join_sql; "INNER JOIN" end end class OuterJoin < Join - def join_sql; "OUTER JOIN" end + def join_sql; "LEFT OUTER JOIN" end end class StringJoin < Join diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index bab9fad3d5104..dcac5abf65b20 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -26,8 +26,16 @@ module Arel end describe '#to_attribute' do - it "returns self" do - @attribute.to_attribute.should == @attribute + describe 'when the given relation is the same as the attributes relation' do + it "returns self" do + @attribute.to_attribute(@relation).should == @attribute + end + end + + describe 'when the given relation differs from the attributes relation' do + it 'binds to the new relation' do + @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation) + end end end end diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index 10bdb56302f12..dfd2100048367 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -31,7 +31,7 @@ module Arel describe '#to_attribute' do it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) + @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression) end end end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 3286f373f51fb..9707f2887ceaa 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -40,7 +40,7 @@ module Arel describe "when given a string" do it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) end end @@ -159,7 +159,7 @@ module Arel describe '#insert' do it 'manufactures an insertion relation' do Session.start do - record = {@relation[:name] => 'carl'} + record = { @relation[:name] => 'carl' } mock(Session.new).create(Insert.new(@relation, record)) @relation.insert(record) end @@ -169,7 +169,7 @@ module Arel describe '#update' do it 'manufactures an update relation' do Session.start do - assignments = {@relation[:name] => Value.new('bob', @relation)} + assignments = { @relation[:name] => Value.new('bob', @relation) } mock(Session.new).update(Update.new(@relation, assignments)) @relation.update(assignments) end @@ -180,8 +180,8 @@ module Arel describe Relation::Enumerable do it "implements enumerable" do - @relation.collect.should == @relation.session.read(@relation) - @relation.first.should == @relation.session.read(@relation).first + @relation.collect.should == @relation.session.read(@relation).collect + @relation.first.should == @relation.session.read(@relation).first end end end From 07833d39c2885a5cddf38eeb860d79353c0f447b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:47:10 -0400 Subject: [PATCH 0229/1492] basic implementation of in memory insertions Conflicts: lib/arel/engines/memory/relations.rb --- doc/TODO | 8 ++++-- lib/arel/algebra/relations/relation.rb | 2 +- lib/arel/engines/memory/engine.rb | 4 +++ lib/arel/engines/memory/relations.rb | 1 + lib/arel/engines/memory/relations/writes.rb | 7 +++++ lib/arel/session.rb | 3 ++ .../memory/unit/relations/insert_spec.rb | 28 +++++++++++++++++++ 7 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 lib/arel/engines/memory/relations/writes.rb create mode 100644 spec/arel/engines/memory/unit/relations/insert_spec.rb diff --git a/doc/TODO b/doc/TODO index 7e7028d39f7d1..5e3a7ee3abd5e 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,11 +1,12 @@ todo: -- fix AR +- insertions for in memory - cross-engine joins - blocks for joins -- deal with table tests in algebra +- test sql insertions - implement mnesia adapter -- rename externalize to derived. +- rename externalize to derived. +- deal with table tests in algebra - fix grouping - audit unit coverage of algebra - data objects @@ -92,6 +93,7 @@ done: - result sets to attr correlation too - implement joins in memory - result sets should be array relations +- fix AR icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index c38ab0e9c578f..9fdac265288a0 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -57,7 +57,7 @@ def alias module Writable def insert(record) - session.create Insert.new(self, record); self + session.create Insert.new(self, record) end def update(assignments) diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb index 67a084f2cdeba..c8f79c9d5776b 100644 --- a/lib/arel/engines/memory/engine.rb +++ b/lib/arel/engines/memory/engine.rb @@ -5,6 +5,10 @@ module CRUD def read(relation) relation.eval end + + def create(relation) + relation.eval + end end include CRUD end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 1b009537b9bad..c67af2d63ba61 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,4 +1,5 @@ require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' +require 'arel/engines/memory/relations/writes' require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/writes.rb b/lib/arel/engines/memory/relations/writes.rb new file mode 100644 index 0000000000000..fa8b84a32c516 --- /dev/null +++ b/lib/arel/engines/memory/relations/writes.rb @@ -0,0 +1,7 @@ +module Arel + class Insert < Compound + def eval + unoperated_rows + [Row.new(self, record.values.collect(&:value))] + end + end +end \ No newline at end of file diff --git a/lib/arel/session.rb b/lib/arel/session.rb index cf04e8a93a61d..921ad0a7ac83c 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -24,6 +24,7 @@ def start module CRUD def create(insert) insert.call + insert end def read(select) @@ -34,10 +35,12 @@ def read(select) def update(update) update.call + update end def delete(delete) delete.call + delete end end include CRUD diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb new file mode 100644 index 0000000000000..4b5e8833a0099 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -0,0 +1,28 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Insert do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it "manufactures an array of hashes of attributes to values" do + @relation \ + .insert(@relation[:id] => 4, @relation[:name] => 'guinea fowl') \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + Row.new(relation, [4, 'guinea fowl']) + ] + end + end + end + end +end \ No newline at end of file From 7a51983efc50c8f9092785b1b586f8884dedc01a Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:02:10 -0400 Subject: [PATCH 0230/1492] initial implementation of cross-engine join Conflicts: lib/arel/engines/memory/relations/array.rb lib/arel/engines/sql/primitives.rb --- doc/TODO | 4 +-- lib/arel/algebra/relations/row.rb | 5 +-- lib/arel/engines/memory/relations/array.rb | 4 +++ lib/arel/engines/memory/relations/compound.rb | 2 +- .../engines/memory/relations/operations.rb | 4 +-- lib/arel/engines/sql/engine.rb | 4 ++- lib/arel/engines/sql/primitives.rb | 4 +++ lib/arel/engines/sql/relations/table.rb | 4 +++ .../integration/joins/cross_engine_spec.rb | 31 +++++++++++++++++++ 9 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 spec/arel/engines/memory/integration/joins/cross_engine_spec.rb diff --git a/doc/TODO b/doc/TODO index 5e3a7ee3abd5e..901d6ab13fa87 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,8 +1,7 @@ todo: -- insertions for in memory - cross-engine joins - blocks for joins -- test sql insertions +- fix sql insertions - implement mnesia adapter - rename externalize to derived. @@ -94,6 +93,7 @@ done: - implement joins in memory - result sets should be array relations - fix AR +- insertions for in memory icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index 3731dd96962ac..e8484944bd8b6 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -4,12 +4,13 @@ class Row deriving :==, :initialize def [](attribute) - tuple[relation.position_of(attribute)] + attribute.type_cast(tuple[relation.position_of(attribute)]) end def slice(*attributes) Row.new(relation, attributes.inject([]) do |cheese, attribute| - cheese << self[attribute] + # FIXME TESTME method chaining + cheese << tuple[relation.relation.position_of(attribute)] cheese end) end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 15a3e95e1b5ea..6e2dc292523b8 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -14,6 +14,10 @@ def attributes end end + def format(attribute, value) + value + end + def eval @array.collect { |r| Row.new(self, r) } end diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index 3791fa4622943..9e7827dfb3622 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -3,7 +3,7 @@ class Compound < Relation delegate :array, :to => :relation def unoperated_rows - relation.eval.collect { |row| row.bind(self) } + relation.call.collect { |row| row.bind(self) } end end end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index e35fbe3234cc2..e0fd2824b3c55 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -47,8 +47,8 @@ def eval class Join < Relation def eval result = [] - relation1.eval.each do |row1| - relation2.eval.each do |row2| + relation1.call.each do |row1| + relation2.call.each do |row2| combined_row = row1.combine(row2, self) if predicates.all? { |p| p.eval(combined_row) } result << combined_row diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 0700ae9733e25..d27d93a5dc8e5 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -20,7 +20,9 @@ def create(relation) def read(relation) # FIXME - class << rows = connection.execute(relation.to_sql) + rows = connection.select_rows(relation.to_sql) + + class << rows include Enumerable end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 9e9143ac0f268..22ee19dcf0bfd 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -4,6 +4,10 @@ def column original_relation.column_for(self) end + def type_cast(value) + root.relation.format(self, value) + end + def format(object) object.to_sql(Sql::Attribute.new(self)) end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 2653744149ab9..e842f85ed1a0c 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -16,6 +16,10 @@ def attributes end end + def format(attribute, value) + attribute.column.type_cast(value) + end + def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb new file mode 100644 index 0000000000000..dd923ee6ebf81 --- /dev/null +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -0,0 +1,31 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @users = Array.new([ + [1, 'bryan' ], + [2, 'emilio' ], + [3, 'nick'] + ], [:id, :name]) + @photos = Table.new(:photos) + @photos.delete + @photos \ + .insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) \ + .insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) + end + + it 'joins across engines' do + @users \ + .join(@photos) \ + .on(@users[:id].eq(@photos[:user_id])) \ + .project(@users[:name], @photos[:camera_id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, ['bryan', '6']), + Row.new(relation, ['emilio', '42']) + ] + end + end + end +end \ No newline at end of file From 44743bed5568b3065e4f9da7972e3ea1d0d9e728 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:14:28 -0400 Subject: [PATCH 0231/1492] joining across engines in either direction Conflicts: spec/arel/engines/memory/integration/joins/cross_engine_spec.rb --- doc/TODO | 4 +- lib/arel/algebra/relations/operations/join.rb | 10 ++++- .../integration/joins/cross_engine_spec.rb | 39 +++++++++++++------ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/TODO b/doc/TODO index 901d6ab13fa87..61ff24f4a0188 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,9 +1,10 @@ todo: -- cross-engine joins +- fix AR again - blocks for joins - fix sql insertions - implement mnesia adapter +- CLEANUP!!!!! - rename externalize to derived. - deal with table tests in algebra - fix grouping @@ -94,6 +95,7 @@ done: - result sets should be array relations - fix AR - insertions for in memory +- cross-engine joins icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 695f360b517f9..02a8fa629d965 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -2,7 +2,7 @@ module Arel class Join < Relation attributes :relation1, :relation2, :predicates deriving :== - delegate :engine, :name, :to => :relation1 + delegate :name, :to => :relation1 hash_on :relation1 def initialize(relation1, relation2 = Nil.instance, *predicates) @@ -31,6 +31,10 @@ def externalizable? def join? true end + + def engine + relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine + end end class InnerJoin < Join; end @@ -39,6 +43,10 @@ class StringJoin < Join def attributes relation1.externalize.attributes end + + def engine + relation1.engine + end end class Relation diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index dd923ee6ebf81..486230005209f 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -14,17 +14,34 @@ module Arel .insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) \ .insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) end - - it 'joins across engines' do - @users \ - .join(@photos) \ - .on(@users[:id].eq(@photos[:user_id])) \ - .project(@users[:name], @photos[:camera_id]) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, ['bryan', '6']), - Row.new(relation, ['emilio', '42']) - ] + + describe 'when the in memory relation is on the left' do + it 'joins across engines' do + @users \ + .join(@photos) \ + .on(@users[:id].eq(@photos[:user_id])) \ + .project(@users[:name], @photos[:camera_id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, ['bryan', '6']), + Row.new(relation, ['emilio', '42']) + ] + end + end + end + + describe 'when the in memory relation is on the right' do + it 'joins across engines' do + @photos \ + .join(@users) \ + .on(@users[:id].eq(@photos[:user_id])) \ + .project(@users[:name], @photos[:camera_id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, ['bryan', '6']), + Row.new(relation, ['emilio', '42']) + ] + end end end end From 19b2af181009acfcb24d156ca350c148630e6787 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:20:25 -0400 Subject: [PATCH 0232/1492] Improve coverage output --- Rakefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 545993653e65d..cfae22260a6a2 100644 --- a/Rakefile +++ b/Rakefile @@ -8,8 +8,12 @@ Spec::Rake::SpecTask.new(:coverage) do |t| t.spec_files = ["spec/connections/mysql_connection.rb"] + spec_file_list + t.rcov = true - t.rcov_opts = ['-x', 'spec,gems'] + t.rcov_opts << '--exclude' << "spec,gems" + t.rcov_opts << '--text-summary' + t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse' + t.rcov_opts << '--only-uncovered' end namespace :spec do From dc7b51883b1cc8ad7e525b7315fb575ae77a5b3d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:20:40 -0400 Subject: [PATCH 0233/1492] Whitespace --- lib/arel/algebra.rb | 2 +- lib/arel/algebra/extensions/array.rb | 4 +- lib/arel/algebra/extensions/class.rb | 10 ++-- lib/arel/algebra/extensions/hash.rb | 2 +- lib/arel/algebra/extensions/pathname.rb | 2 +- lib/arel/algebra/extensions/symbol.rb | 2 +- lib/arel/algebra/predicates.rb | 2 +- lib/arel/algebra/primitives/attribute.rb | 8 +-- lib/arel/algebra/primitives/ordering.rb | 8 +-- lib/arel/algebra/relations.rb | 2 +- .../algebra/relations/operations/alias.rb | 2 +- .../algebra/relations/operations/group.rb | 2 +- lib/arel/algebra/relations/operations/join.rb | 4 +- .../algebra/relations/operations/order.rb | 4 +- lib/arel/algebra/relations/operations/skip.rb | 4 +- lib/arel/algebra/relations/operations/take.rb | 4 +- lib/arel/algebra/relations/row.rb | 10 ++-- .../algebra/relations/utilities/compound.rb | 2 +- lib/arel/algebra/relations/writes.rb | 10 ++-- lib/arel/engines.rb | 2 +- lib/arel/engines/memory.rb | 2 +- lib/arel/engines/memory/engine.rb | 4 +- lib/arel/engines/memory/primitives.rb | 10 ++-- lib/arel/engines/memory/relations/array.rb | 6 +- lib/arel/engines/memory/relations/compound.rb | 2 +- .../engines/memory/relations/operations.rb | 16 ++--- lib/arel/engines/memory/relations/writes.rb | 4 +- lib/arel/engines/sql.rb | 2 +- lib/arel/engines/sql/christener.rb | 2 +- lib/arel/engines/sql/engine.rb | 6 +- lib/arel/engines/sql/extensions.rb | 2 +- lib/arel/engines/sql/extensions/array.rb | 2 +- lib/arel/engines/sql/extensions/nil_class.rb | 2 +- lib/arel/engines/sql/extensions/object.rb | 2 +- lib/arel/engines/sql/extensions/range.rb | 4 +- lib/arel/engines/sql/formatters.rb | 2 +- lib/arel/engines/sql/predicates.rb | 2 +- lib/arel/engines/sql/primitives.rb | 10 ++-- lib/arel/engines/sql/relations.rb | 2 +- .../engines/sql/relations/operations/alias.rb | 2 +- .../engines/sql/relations/operations/join.rb | 2 +- lib/arel/engines/sql/relations/relation.rb | 2 +- lib/arel/engines/sql/relations/table.rb | 2 +- .../sql/relations/utilities/compound.rb | 2 +- .../relations/utilities/externalization.rb | 2 +- .../engines/sql/relations/utilities/nil.rb | 2 +- .../sql/relations/utilities/recursion.rb | 2 +- lib/arel/engines/sql/relations/writes.rb | 2 +- .../algebra/unit/predicates/binary_spec.rb | 8 +-- .../algebra/unit/predicates/equality_spec.rb | 10 ++-- spec/arel/algebra/unit/predicates/in_spec.rb | 2 +- .../algebra/unit/primitives/attribute_spec.rb | 58 +++++++++---------- .../unit/primitives/expression_spec.rb | 12 ++-- .../algebra/unit/primitives/value_spec.rb | 2 +- .../arel/algebra/unit/relations/alias_spec.rb | 4 +- .../algebra/unit/relations/delete_spec.rb | 2 +- .../arel/algebra/unit/relations/group_spec.rb | 2 +- .../algebra/unit/relations/insert_spec.rb | 2 +- spec/arel/algebra/unit/relations/join_spec.rb | 6 +- .../arel/algebra/unit/relations/order_spec.rb | 2 +- .../algebra/unit/relations/project_spec.rb | 10 ++-- .../algebra/unit/relations/relation_spec.rb | 36 ++++++------ spec/arel/algebra/unit/relations/skip_spec.rb | 2 +- .../arel/algebra/unit/relations/table_spec.rb | 10 ++-- spec/arel/algebra/unit/relations/take_spec.rb | 2 +- .../algebra/unit/relations/update_spec.rb | 2 +- .../arel/algebra/unit/relations/where_spec.rb | 6 +- .../arel/algebra/unit/session/session_spec.rb | 22 +++---- .../integration/joins/cross_engine_spec.rb | 2 +- .../memory/unit/relations/array_spec.rb | 2 +- .../memory/unit/relations/insert_spec.rb | 4 +- .../memory/unit/relations/join_spec.rb | 4 +- .../memory/unit/relations/order_spec.rb | 4 +- .../memory/unit/relations/project_spec.rb | 4 +- .../memory/unit/relations/skip_spec.rb | 4 +- .../memory/unit/relations/take_spec.rb | 4 +- .../memory/unit/relations/where_spec.rb | 6 +- .../sql/unit/predicates/binary_spec.rb | 2 +- .../sql/unit/predicates/equality_spec.rb | 2 +- .../engines/sql/unit/predicates/in_spec.rb | 2 +- .../sql/unit/primitives/attribute_spec.rb | 4 +- .../engines/sql/unit/relations/group_spec.rb | 2 +- .../engines/sql/unit/relations/join_spec.rb | 2 +- .../engines/sql/unit/relations/skip_spec.rb | 2 +- .../engines/sql/unit/relations/table_spec.rb | 2 +- .../engines/sql/unit/relations/take_spec.rb | 2 +- spec/arel/unit/predicates/predicates_spec.rb | 2 +- spec/connections/mysql_connection.rb | 2 +- spec/doubles/hash.rb | 8 +-- spec/matchers/be_like.rb | 10 ++-- spec/matchers/disambiguate_attributes.rb | 10 ++-- spec/matchers/hash_the_same_as.rb | 10 ++-- spec/schemas/mysql_schema.rb | 2 +- spec/schemas/sqlite3_schema.rb | 2 +- 94 files changed, 243 insertions(+), 243 deletions(-) diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index f27882a343df0..c206fea0b0339 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,4 +1,4 @@ require 'arel/algebra/extensions' require 'arel/algebra/predicates' require 'arel/algebra/relations' -require 'arel/algebra/primitives' \ No newline at end of file +require 'arel/algebra/primitives' diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb index 935569a07b7b8..48541a395ee91 100644 --- a/lib/arel/algebra/extensions/array.rb +++ b/lib/arel/algebra/extensions/array.rb @@ -2,11 +2,11 @@ class Array def to_hash Hash[*flatten] end - + def group_by inject({}) do |groups, element| (groups[yield(element)] ||= []) << element groups end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index f37898e7d7fea..0a729d82558a5 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -3,11 +3,11 @@ def attributes(*attrs) @attributes = attrs attr_reader *attrs end - + def deriving(*methods) methods.each { |m| derive m } end - + def derive(method_name) methods = { :initialize => " @@ -24,14 +24,14 @@ def ==(other) } class_eval methods[method_name], __FILE__, __LINE__ end - + def hash_on(delegatee) define_method :eql? do |other| self == other end - + define_method :hash do @hash ||= delegatee.hash end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 7472b5aa731ad..82cd5e11d3372 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -4,4 +4,4 @@ def bind(relation) bound.merge(key.bind(relation) => value.bind(relation)) end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb index 2f7e2733e74fa..45f1a5f6b31ec 100644 --- a/lib/arel/algebra/extensions/pathname.rb +++ b/lib/arel/algebra/extensions/pathname.rb @@ -2,4 +2,4 @@ class Pathname def /(path) (self + path).expand_path end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb index 787867bdc3feb..8d324a801cb1b 100644 --- a/lib/arel/algebra/extensions/symbol.rb +++ b/lib/arel/algebra/extensions/symbol.rb @@ -2,4 +2,4 @@ class Symbol def to_attribute(relation) Arel::Attribute.new(relation, self) end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 7f093ded6db76..72167c2b27bb6 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -38,4 +38,4 @@ class LessThanOrEqualTo < Binary; end class LessThan < Binary; end class Match < Binary; end class In < Binary; end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index aa1f2ae00cf32..44a2f4173305b 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -17,7 +17,7 @@ def named?(hypothetical_name) def aggregation? false end - + def inspect "" end @@ -133,16 +133,16 @@ def average end end include Expressions - + module Orderings def asc Ascending.new(self) end - + def desc Descending.new(self) end - + alias_method :to_ordering, :asc end include Orderings diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb index e8d8f971884f5..a60d794f27ae9 100644 --- a/lib/arel/algebra/primitives/ordering.rb +++ b/lib/arel/algebra/primitives/ordering.rb @@ -3,16 +3,16 @@ class Ordering attributes :attribute deriving :initialize, :== delegate :relation, :to => :attribute - + def bind(relation) self.class.new(attribute.bind(relation)) end - + def to_ordering self end end - + class Ascending < Ordering; end class Descending < Ordering; end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index 94df5938fecec..f9fa24ba25463 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -11,4 +11,4 @@ require 'arel/algebra/relations/operations/project' require 'arel/algebra/relations/operations/where' require 'arel/algebra/relations/operations/skip' -require 'arel/algebra/relations/operations/take' \ No newline at end of file +require 'arel/algebra/relations/operations/take' diff --git a/lib/arel/algebra/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb index 67837f6a7544d..0331d98b8544f 100644 --- a/lib/arel/algebra/relations/operations/alias.rb +++ b/lib/arel/algebra/relations/operations/alias.rb @@ -4,4 +4,4 @@ class Alias < Compound deriving :initialize alias_method :==, :equal? end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 879f2352c5010..b8975ed3d6fb6 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -13,4 +13,4 @@ def externalizable? true end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 02a8fa629d965..e47d9fa9e0131 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -31,7 +31,7 @@ def externalizable? def join? true end - + def engine relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine end @@ -43,7 +43,7 @@ class StringJoin < Join def attributes relation1.externalize.attributes end - + def engine relation1.engine end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 4e7133f5a87b1..a589b56997637 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -2,7 +2,7 @@ module Arel class Order < Compound attributes :relation, :orderings deriving :== - + def initialize(relation, *orderings, &block) @relation = relation @orderings = (orderings + arguments_from_block(relation, &block)) \ @@ -15,4 +15,4 @@ def orders (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 930e4c94ea372..2dda191c35ee6 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -2,9 +2,9 @@ module Arel class Skip < Compound attributes :relation, :skipped deriving :initialize, :== - + def externalizable? true end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index 2fd3fdf63537c..eb32ec492e345 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -2,9 +2,9 @@ module Arel class Take < Compound attributes :relation, :taken deriving :initialize, :== - + def externalizable? true end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index e8484944bd8b6..31585574485a7 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -2,11 +2,11 @@ module Arel class Row attributes :relation, :tuple deriving :==, :initialize - + def [](attribute) attribute.type_cast(tuple[relation.position_of(attribute)]) end - + def slice(*attributes) Row.new(relation, attributes.inject([]) do |cheese, attribute| # FIXME TESTME method chaining @@ -14,13 +14,13 @@ def slice(*attributes) cheese end) end - + def bind(relation) Row.new(relation, tuple) end - + def combine(other, relation) Row.new(relation, tuple + other.tuple) end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 99c3d02748c75..676d80a737109 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -13,7 +13,7 @@ def #{operation_name} end OPERATION end - + private def arguments_from_block(relation, &block) block_given?? [yield(relation)] : [] diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb index 352f7bc7e5d09..d344987915aa9 100644 --- a/lib/arel/algebra/relations/writes.rb +++ b/lib/arel/algebra/relations/writes.rb @@ -2,7 +2,7 @@ module Arel class Deletion < Compound attributes :relation deriving :initialize, :== - + def call engine.delete(self) end @@ -15,7 +15,7 @@ class Insert < Compound def initialize(relation, record) @relation, @record = relation, record.bind(relation) end - + def call engine.create(self) end @@ -24,13 +24,13 @@ def call class Update < Compound attributes :relation, :assignments deriving :== - + def initialize(relation, assignments) @relation, @assignments = relation, assignments.bind(relation) end - + def call engine.update(self) end end -end \ No newline at end of file +end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb index 3f854edf90073..cd848d83e2331 100644 --- a/lib/arel/engines.rb +++ b/lib/arel/engines.rb @@ -1,2 +1,2 @@ require 'arel/engines/sql' -require 'arel/engines/memory' \ No newline at end of file +require 'arel/engines/memory' diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb index df6f6f3d4813a..9e7193ef1353c 100644 --- a/lib/arel/engines/memory.rb +++ b/lib/arel/engines/memory.rb @@ -1,4 +1,4 @@ require 'arel/engines/memory/relations' require 'arel/engines/memory/primitives' require 'arel/engines/memory/engine' -require 'arel/engines/memory/predicates' \ No newline at end of file +require 'arel/engines/memory/predicates' diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb index c8f79c9d5776b..c7ac9422d42ea 100644 --- a/lib/arel/engines/memory/engine.rb +++ b/lib/arel/engines/memory/engine.rb @@ -5,7 +5,7 @@ module CRUD def read(relation) relation.eval end - + def create(relation) relation.eval end @@ -13,4 +13,4 @@ def create(relation) include CRUD end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index f8bbcedb556d8..935b34f5ee490 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -4,24 +4,24 @@ def eval(row) row[self] end end - + class Value def eval(row) value end end - + class Ordering def eval(row1, row2) (attribute.eval(row1) <=> attribute.eval(row2)) * direction end end - + class Descending < Ordering def direction; -1 end end - + class Ascending < Ordering def direction; 1 end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 6e2dc292523b8..5e7c0a4ab1203 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -3,7 +3,7 @@ class Array < Relation attributes :array, :attribute_names include Recursion::BaseCase deriving :==, :initialize - + def engine @engine ||= Memory::Engine.new end @@ -17,9 +17,9 @@ def attributes def format(attribute, value) value end - + def eval @array.collect { |r| Row.new(self, r) } end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index 9e7827dfb3622..6dda92a6a1242 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -1,7 +1,7 @@ module Arel class Compound < Relation delegate :array, :to => :relation - + def unoperated_rows relation.call.collect { |row| row.bind(self) } end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index e0fd2824b3c55..8e019383603a0 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -4,7 +4,7 @@ def eval unoperated_rows.select { |row| predicate.eval(row) } end end - + class Order < Compound def eval unoperated_rows.sort do |row1, row2| @@ -13,37 +13,37 @@ def eval end end end - + class Project < Compound def eval unoperated_rows.collect { |r| r.slice(*projections) } end end - + class Take < Compound def eval unoperated_rows[0, taken] end end - + class Skip < Compound def eval unoperated_rows[skipped..-1] end end - + class Group < Compound def eval raise NotImplementedError end end - + class Alias < Compound def eval unoperated_rows end end - + class Join < Relation def eval result = [] @@ -58,4 +58,4 @@ def eval result end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/relations/writes.rb b/lib/arel/engines/memory/relations/writes.rb index fa8b84a32c516..12c4f36c0d970 100644 --- a/lib/arel/engines/memory/relations/writes.rb +++ b/lib/arel/engines/memory/relations/writes.rb @@ -1,7 +1,7 @@ module Arel class Insert < Compound def eval - unoperated_rows + [Row.new(self, record.values.collect(&:value))] + unoperated_rows + [Row.new(self, record.values.collect(&:value))] end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index aed1fd861e2dd..f31cfc7dacda6 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -4,4 +4,4 @@ require 'arel/engines/sql/predicates' require 'arel/engines/sql/formatters' require 'arel/engines/sql/extensions' -require 'arel/engines/sql/christener' \ No newline at end of file +require 'arel/engines/sql/christener' diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index 5883a75f41346..c1c9325208b19 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -10,4 +10,4 @@ def name_for(relation) end end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index d27d93a5dc8e5..5a8c9f16c5864 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -21,11 +21,11 @@ def create(relation) def read(relation) # FIXME rows = connection.select_rows(relation.to_sql) - + class << rows include Enumerable end - + Array.new(rows, relation.attributes) end @@ -40,4 +40,4 @@ def delete(relation) include CRUD end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions.rb b/lib/arel/engines/sql/extensions.rb index 6f4ad321485b2..1ea31bc140801 100644 --- a/lib/arel/engines/sql/extensions.rb +++ b/lib/arel/engines/sql/extensions.rb @@ -1,4 +1,4 @@ require 'arel/engines/sql/extensions/object' require 'arel/engines/sql/extensions/array' require 'arel/engines/sql/extensions/range' -require 'arel/engines/sql/extensions/nil_class' \ No newline at end of file +require 'arel/engines/sql/extensions/nil_class' diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb index 1daa5abca7eeb..d97dd1aa25279 100644 --- a/lib/arel/engines/sql/extensions/array.rb +++ b/lib/arel/engines/sql/extensions/array.rb @@ -6,4 +6,4 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "IN" end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb index 729c4cada7b5e..6f38ecdf3ab77 100644 --- a/lib/arel/engines/sql/extensions/nil_class.rb +++ b/lib/arel/engines/sql/extensions/nil_class.rb @@ -2,4 +2,4 @@ class NilClass def equality_predicate_sql 'IS' end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb index ef990eee2f6a2..65270ee3de072 100644 --- a/lib/arel/engines/sql/extensions/object.rb +++ b/lib/arel/engines/sql/extensions/object.rb @@ -6,4 +6,4 @@ def to_sql(formatter) def equality_predicate_sql '=' end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb index d7329efe344a2..946dbc26330e9 100644 --- a/lib/arel/engines/sql/extensions/range.rb +++ b/lib/arel/engines/sql/extensions/range.rb @@ -2,8 +2,8 @@ class Range def to_sql(formatter = nil) formatter.range self.begin, self.end end - + def inclusion_predicate_sql "BETWEEN" end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index bc5f0f7c64ba0..08a32843c9f94 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -47,7 +47,7 @@ def value(value) class WhereClause < PassThrough end - class OrderClause < PassThrough + class OrderClause < PassThrough def ordering(ordering) "#{quote_table_name(name_for(ordering.attribute.original_relation))}.#{quote_column_name(ordering.attribute.name)} #{ordering.direction_sql}" end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index dfeddb2de1fba..7e195c26051a8 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -34,4 +34,4 @@ def predicate_sql; 'LIKE' end class In < Binary def predicate_sql; operand2.inclusion_predicate_sql end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 22ee19dcf0bfd..f2e8e8dabea5a 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -7,7 +7,7 @@ def column def type_cast(value) root.relation.format(self, value) end - + def format(object) object.to_sql(Sql::Attribute.new(self)) end @@ -28,17 +28,17 @@ def format(object) object.to_sql(Sql::Value.new(relation)) end end - + class Ordering def to_sql(formatter = Sql::OrderClause.new(relation)) formatter.ordering self end end - + class Ascending < Ordering def direction_sql; 'ASC' end end - + class Descending < Ordering def direction_sql; 'DESC' end end @@ -72,4 +72,4 @@ def function_sql; 'MIN' end class Average < Expression def function_sql; 'AVG' end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 0eb1303ec9ab5..8360a1f80685d 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -6,4 +6,4 @@ require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' require 'arel/engines/sql/relations/operations/alias' -require 'arel/engines/sql/relations/writes' \ No newline at end of file +require 'arel/engines/sql/relations/writes' diff --git a/lib/arel/engines/sql/relations/operations/alias.rb b/lib/arel/engines/sql/relations/operations/alias.rb index 32c9911a69221..9b6a484463764 100644 --- a/lib/arel/engines/sql/relations/operations/alias.rb +++ b/lib/arel/engines/sql/relations/operations/alias.rb @@ -2,4 +2,4 @@ module Arel class Alias < Compound include Recursion::BaseCase end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index f848fd326892a..7c5e13510a23b 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -30,4 +30,4 @@ def joins(_, __ = nil) relation2 end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 5fd4121176c29..93c146352c12a 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -25,4 +25,4 @@ def christener @christener ||= Sql::Christener.new end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index e842f85ed1a0c..0b6574eedc3ae 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -19,7 +19,7 @@ def attributes def format(attribute, value) attribute.column.type_cast(value) end - + def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index 61df196d6e2e1..b63a829c6738d 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -3,4 +3,4 @@ class Compound < Relation delegate :table, :table_sql, :to => :relation end end - \ No newline at end of file + diff --git a/lib/arel/engines/sql/relations/utilities/externalization.rb b/lib/arel/engines/sql/relations/utilities/externalization.rb index 1ac6f2de8ebfd..7f937e84231c3 100644 --- a/lib/arel/engines/sql/relations/utilities/externalization.rb +++ b/lib/arel/engines/sql/relations/utilities/externalization.rb @@ -11,4 +11,4 @@ def name relation.name + '_external' end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/utilities/nil.rb b/lib/arel/engines/sql/relations/utilities/nil.rb index 77534b25ade1c..519ea8acf1b6e 100644 --- a/lib/arel/engines/sql/relations/utilities/nil.rb +++ b/lib/arel/engines/sql/relations/utilities/nil.rb @@ -3,4 +3,4 @@ class Nil < Relation def table_sql(formatter = nil); '' end def name; '' end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/utilities/recursion.rb b/lib/arel/engines/sql/relations/utilities/recursion.rb index 848b059507b01..84a526f57c7dd 100644 --- a/lib/arel/engines/sql/relations/utilities/recursion.rb +++ b/lib/arel/engines/sql/relations/utilities/recursion.rb @@ -10,4 +10,4 @@ def table_sql(formatter = Sql::TableReference.new(self)) end end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index edfd9f72332fe..4d753f5fcab77 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -33,4 +33,4 @@ def to_sql(formatter = nil) ].join("\n") end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb index 9022a543d18f5..14fd7ab21b2fb 100644 --- a/spec/arel/algebra/unit/predicates/binary_spec.rb +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -9,19 +9,19 @@ module Arel class ConcreteBinary < Binary end end - + describe '#bind' do before do @another_relation = @relation.alias end - + describe 'when both operands are attributes' do it "manufactures an expression with the attributes bound to the relation" do ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) end end - + describe 'when an operand is a value' do it "manufactures an expression with unmodified values" do ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ @@ -30,4 +30,4 @@ class ConcreteBinary < Binary end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb index 9a56ed5eafa1d..af91f8b51bcda 100644 --- a/spec/arel/algebra/unit/predicates/equality_spec.rb +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -8,20 +8,20 @@ module Arel @attribute1 = @relation1[:id] @attribute2 = @relation2[:user_id] end - - describe '==' do + + describe '==' do it "obtains if attribute1 and attribute2 are identical" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) end - + it "obtains if the concrete type of the predicates are identical" do Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) end - + it "is commutative on the attributes" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/arel/algebra/unit/predicates/in_spec.rb index 91c154763caa3..a8a15ce4e38bf 100644 --- a/spec/arel/algebra/unit/predicates/in_spec.rb +++ b/spec/arel/algebra/unit/predicates/in_spec.rb @@ -7,4 +7,4 @@ module Arel @attribute = @relation[:id] end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index dcac5abf65b20..89e338e377229 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -6,32 +6,32 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) end end - + describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end - + it "returns self if the substituting to the same relation" do @attribute.bind(@relation).should == @attribute end end - + describe '#to_attribute' do describe 'when the given relation is the same as the attributes relation' do it "returns self" do @attribute.to_attribute(@relation).should == @attribute end end - + describe 'when the given relation differs from the attributes relation' do it 'binds to the new relation' do @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation) @@ -39,32 +39,32 @@ module Arel end end end - + describe '#column' do it "returns the corresponding column in the relation" do @attribute.column.should == @relation.column_for(@attribute) end end - + describe '#engine' do it "delegates to its relation" do Attribute.new(@relation, :id).engine.should == @relation.engine end end - + describe Attribute::Congruence do describe '/' do before do @aliased_relation = @relation.alias @doubly_aliased_relation = @aliased_relation.alias end - + describe 'when dividing two unrelated attributes' do it "returns 0.0" do (@relation[:id] / @relation[:name]).should == 0.0 end end - + describe 'when dividing two matching attributes' do it 'returns a the highest score for the most similar attributes' do (@aliased_relation[:id] / @relation[:id]) \ @@ -75,98 +75,98 @@ module Arel end end end - + describe Attribute::Predications do before do @attribute = Attribute.new(@relation, :name) end - + describe '#eq' do it "manufactures an equality predicate" do @attribute.eq('name').should == Equality.new(@attribute, 'name') end end - + describe '#lt' do it "manufactures a less-than predicate" do @attribute.lt(10).should == LessThan.new(@attribute, 10) end end - + describe '#lteq' do it "manufactures a less-than or equal-to predicate" do @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) end end - + describe '#gt' do it "manufactures a greater-than predicate" do @attribute.gt(10).should == GreaterThan.new(@attribute, 10) end end - + describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end - + describe '#matches' do it "manufactures a match predicate" do @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end - + describe '#in' do it "manufactures an in predicate" do @attribute.in(1..30).should == In.new(@attribute, (1..30)) end end end - + describe Attribute::Expressions do before do - @attribute = Attribute.new(@relation, :name) + @attribute = Attribute.new(@relation, :name) end - + describe '#count' do it "manufactures a count Expression" do @attribute.count.should == Count.new(@attribute) end end - + describe '#sum' do it "manufactures a sum Expression" do @attribute.sum.should == Sum.new(@attribute) end end - + describe '#maximum' do it "manufactures a maximum Expression" do @attribute.maximum.should == Maximum.new(@attribute) end end - + describe '#minimum' do it "manufactures a minimum Expression" do @attribute.minimum.should == Minimum.new(@attribute) end end - + describe '#average' do it "manufactures an average Expression" do @attribute.average.should == Average.new(@attribute) end - end + end end - + describe Attribute::Orderings do describe '#asc' do it 'manufactures an ascending ordering' do pending end end - + describe '#desc' do it 'manufactures a descending ordering' do pending @@ -174,4 +174,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index dfd2100048367..82d12d53f9383 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -6,29 +6,29 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Expression::Transformations do before do @expression = Count.new(@attribute) end - + describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) end - + it "returns self if the substituting to the same relation" do @expression.bind(@relation).should == @expression end end - + describe '#as' do it "manufactures an aliased expression" do @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) end end - + describe '#to_attribute' do it "manufactures an attribute with the expression as an ancestor" do @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression) @@ -36,4 +36,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/primitives/value_spec.rb b/spec/arel/algebra/unit/primitives/value_spec.rb index 8774ca78c5ba4..45208e6c5df03 100644 --- a/spec/arel/algebra/unit/primitives/value_spec.rb +++ b/spec/arel/algebra/unit/primitives/value_spec.rb @@ -12,4 +12,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/arel/algebra/unit/relations/alias_spec.rb index c87a0ca2dd8f3..a5d716a638797 100644 --- a/spec/arel/algebra/unit/relations/alias_spec.rb +++ b/spec/arel/algebra/unit/relations/alias_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '==' do it "obtains if the objects are the same" do Alias.new(@relation).should_not == Alias.new(@relation) @@ -13,4 +13,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/delete_spec.rb b/spec/arel/algebra/unit/relations/delete_spec.rb index 075e59e7240a2..7578e12a3ee84 100644 --- a/spec/arel/algebra/unit/relations/delete_spec.rb +++ b/spec/arel/algebra/unit/relations/delete_spec.rb @@ -6,4 +6,4 @@ module Arel @relation = Table.new(:users) end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/group_spec.rb b/spec/arel/algebra/unit/relations/group_spec.rb index 050de2993d56e..58f9252356302 100644 --- a/spec/arel/algebra/unit/relations/group_spec.rb +++ b/spec/arel/algebra/unit/relations/group_spec.rb @@ -7,4 +7,4 @@ module Arel @attribute = @relation[:id] end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/insert_spec.rb b/spec/arel/algebra/unit/relations/insert_spec.rb index 184cd2a926093..feb1a5eae40a4 100644 --- a/spec/arel/algebra/unit/relations/insert_spec.rb +++ b/spec/arel/algebra/unit/relations/insert_spec.rb @@ -6,4 +6,4 @@ module Arel @relation = Table.new(:users) end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/join_spec.rb b/spec/arel/algebra/unit/relations/join_spec.rb index 5b512cc7f6438..f5a8bd32aa4af 100644 --- a/spec/arel/algebra/unit/relations/join_spec.rb +++ b/spec/arel/algebra/unit/relations/join_spec.rb @@ -7,14 +7,14 @@ module Arel @relation2 = Table.new(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - + describe 'hashing' do it 'implements hash equality' do InnerJoin.new(@relation1, @relation2, @predicate) \ .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) end end - + describe '#attributes' do it 'combines the attributes of the two relations' do join = InnerJoin.new(@relation1, @relation2, @predicate) @@ -23,4 +23,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb index 0e1b1a0e546db..4f163894c851c 100644 --- a/spec/arel/algebra/unit/relations/order_spec.rb +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -8,4 +8,4 @@ module Arel end end end - \ No newline at end of file + diff --git a/spec/arel/algebra/unit/relations/project_spec.rb b/spec/arel/algebra/unit/relations/project_spec.rb index b71acf5e9193c..9f4358ea54960 100644 --- a/spec/arel/algebra/unit/relations/project_spec.rb +++ b/spec/arel/algebra/unit/relations/project_spec.rb @@ -6,24 +6,24 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe '#attributes' do before do @projection = Project.new(@relation, @attribute) end - + it "manufactures attributes associated with the projection relation" do @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } end end - + describe '#externalizable?' do describe 'when the projections are attributes' do it 'returns false' do Project.new(@relation, @attribute).should_not be_externalizable end end - + describe 'when the projections include an aggregation' do it "obtains" do Project.new(@relation, @attribute.sum).should be_externalizable @@ -31,4 +31,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 9707f2887ceaa..adf82847ac5a8 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -7,14 +7,14 @@ module Arel @attribute1 = @relation[:id] @attribute2 = @relation[:name] end - + describe '[]' do describe 'when given an', Attribute do it "return the attribute congruent to the provided attribute" do @relation[@attribute1].should == @attribute1 end end - + describe 'when given a', Symbol, String do it "returns the attribute with the same name, if it exists" do @relation[:id].should == @attribute1 @@ -23,13 +23,13 @@ module Arel end end end - + describe Relation::Operable do describe 'joins' do before do @predicate = @relation[:id].eq(@relation[:id]) end - + describe '#join' do describe 'when given a relation' do it "manufactures an inner join operation between those two relations" do @@ -37,13 +37,13 @@ module Arel should == InnerJoin.new(@relation, @relation, @predicate) end end - + describe "when given a string" do it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) + @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) end end - + describe "when given something blank" do it "returns self" do @relation.join.should == @relation @@ -64,7 +64,7 @@ module Arel @relation.project(@attribute1, @attribute2). \ should == Project.new(@relation, @attribute1, @attribute2) end - + describe "when given blank attributes" do it "returns self" do @relation.project.should == @relation @@ -97,36 +97,36 @@ module Arel end end end - + describe '#order' do it "manufactures an order relation" do @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) end - + describe 'when given a blank ordering' do it 'returns self' do @relation.order.should == @relation end end end - + describe '#take' do it "manufactures a take relation" do @relation.take(5).should == Take.new(@relation, 5) end - + describe 'when given a blank number of items' do it 'returns self' do @relation.take.should == @relation end end end - + describe '#skip' do it "manufactures a skip relation" do @relation.skip(4).should == Skip.new(@relation, 4) end - + describe 'when given a blank number of items' do it 'returns self' do @relation.skip.should == @relation @@ -138,14 +138,14 @@ module Arel it 'manufactures a group relation' do @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) end - + describe 'when given blank groupings' do it 'returns self' do @relation.group.should == @relation end end end - + describe Relation::Operable::Writable do describe '#delete' do it 'manufactures a deletion relation' do @@ -177,7 +177,7 @@ module Arel end end end - + describe Relation::Enumerable do it "implements enumerable" do @relation.collect.should == @relation.session.read(@relation).collect @@ -185,4 +185,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/skip_spec.rb b/spec/arel/algebra/unit/relations/skip_spec.rb index ff57e03d1c11a..a41913436e0e5 100644 --- a/spec/arel/algebra/unit/relations/skip_spec.rb +++ b/spec/arel/algebra/unit/relations/skip_spec.rb @@ -7,4 +7,4 @@ module Arel @skipped = 4 end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb index 4821d92299deb..dfe457043caad 100644 --- a/spec/arel/algebra/unit/relations/table_spec.rb +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do @@ -18,22 +18,22 @@ module Arel it "returns the attribute if the attribute is within the relation" do @relation[@relation[:id]].should == @relation[:id] end - + it "returns nil if the attribtue is not within the relation" do another_relation = Table.new(:photos) @relation[another_relation[:id]].should be_nil end end - + describe 'when given an', Expression do before do @expression = @relation[:id].count end - + it "returns the Expression if the Expression is within the relation" do @relation[@expression].should be_nil end end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/take_spec.rb b/spec/arel/algebra/unit/relations/take_spec.rb index 6f8b4fd36e01d..2bc17db5a1607 100644 --- a/spec/arel/algebra/unit/relations/take_spec.rb +++ b/spec/arel/algebra/unit/relations/take_spec.rb @@ -7,4 +7,4 @@ module Arel @taken = 4 end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/update_spec.rb b/spec/arel/algebra/unit/relations/update_spec.rb index c27afb48b2007..e9642ffc99acc 100644 --- a/spec/arel/algebra/unit/relations/update_spec.rb +++ b/spec/arel/algebra/unit/relations/update_spec.rb @@ -6,4 +6,4 @@ module Arel @relation = Table.new(:users) end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/where_spec.rb b/spec/arel/algebra/unit/relations/where_spec.rb index 3f37b531382e5..6c3074a3a55bd 100644 --- a/spec/arel/algebra/unit/relations/where_spec.rb +++ b/spec/arel/algebra/unit/relations/where_spec.rb @@ -6,13 +6,13 @@ module Arel @relation = Table.new(:users) @predicate = @relation[:id].eq(1) end - + describe '#initialize' do it "manufactures nested where relations if multiple predicates are provided" do - another_predicate = @relation[:name].lt(2) + another_predicate = @relation[:name].lt(2) Where.new(@relation, @predicate, another_predicate). \ should == Where.new(Where.new(@relation, another_predicate), @predicate) end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/arel/algebra/unit/session/session_spec.rb index e17b5d638a8a8..ca0a43f278b95 100644 --- a/spec/arel/algebra/unit/session/session_spec.rb +++ b/spec/arel/algebra/unit/session/session_spec.rb @@ -6,7 +6,7 @@ module Arel @relation = Table.new(:users) @session = Session.new end - + describe '::start' do describe '::instance' do it "it is a singleton within the started session" do @@ -23,13 +23,13 @@ module Arel end end end - + it "manufactures new sessions outside of the started session" do Session.new.should_not == Session.new end end end - + describe Session::CRUD do before do @insert = Insert.new(@relation, @relation[:name] => 'nick') @@ -37,34 +37,34 @@ module Arel @delete = Deletion.new(@relation) @read = @relation end - + describe '#create' do it "executes an insertion on the connection" do mock(@insert).call @session.create(@insert) end end - + describe '#read' do it "executes an selection on the connection" do mock(@read).call @session.read(@read) end - + it "is memoized" do mock(@read).call.once @session.read(@read) @session.read(@read) end end - + describe '#update' do it "executes an update on the connection" do mock(@update).call @session.update(@update) end end - + describe '#delete' do it "executes a delete on the connection" do mock(@delete).call @@ -72,13 +72,13 @@ module Arel end end end - + describe 'Transactions' do describe '#begin' do end - + describe '#end' do end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index 486230005209f..bffecc918214f 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -45,4 +45,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 4fe24c77fac5a..dd9da41569b8b 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb index 4b5e8833a0099..59e43328a32ef 100644 --- a/spec/arel/engines/memory/unit/relations/insert_spec.rb +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it "manufactures an array of hashes of attributes to values" do @relation \ @@ -25,4 +25,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb index 920cc55d0a4cb..df08fd4a96a06 100644 --- a/spec/arel/engines/memory/unit/relations/join_spec.rb +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -11,7 +11,7 @@ module Arel @relation2 = @relation1.alias @relation3 = @relation1.alias end - + describe InnerJoin do describe '#call' do it 'combines the two tables where the predicate obtains' do @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/arel/engines/memory/unit/relations/order_spec.rb index 3ecb31068bb32..1e9690bbbf42f 100644 --- a/spec/arel/engines/memory/unit/relations/order_spec.rb +++ b/spec/arel/engines/memory/unit/relations/order_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'sorts the relation with the provided ordering' do @relation \ @@ -24,4 +24,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/arel/engines/memory/unit/relations/project_spec.rb index 1d1224cfdcd24..169091002687e 100644 --- a/spec/arel/engines/memory/unit/relations/project_spec.rb +++ b/spec/arel/engines/memory/unit/relations/project_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'retains only the attributes that are provided' do @relation \ @@ -24,4 +24,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/arel/engines/memory/unit/relations/skip_spec.rb index 86db45ef611e4..3411c5493b916 100644 --- a/spec/arel/engines/memory/unit/relations/skip_spec.rb +++ b/spec/arel/engines/memory/unit/relations/skip_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'removes the first n rows' do @relation \ @@ -23,4 +23,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/arel/engines/memory/unit/relations/take_spec.rb index 8b774987e05c7..5e7c4fb46276b 100644 --- a/spec/arel/engines/memory/unit/relations/take_spec.rb +++ b/spec/arel/engines/memory/unit/relations/take_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'removes the rows after the first n' do @relation \ @@ -23,4 +23,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/arel/engines/memory/unit/relations/where_spec.rb index d75ee5dcbe450..1d2c2eb39c666 100644 --- a/spec/arel/engines/memory/unit/relations/where_spec.rb +++ b/spec/arel/engines/memory/unit/relations/where_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'filters the relation with the provided predicate' do @relation \ @@ -21,7 +21,7 @@ module Arel ] end end - + describe 'when filtering a where relation' do it 'further filters the already-filtered relation with the provided predicate' do @relation \ @@ -36,4 +36,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 679147067ec6c..befd2878d9549 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -102,4 +102,4 @@ def predicate_sql end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index e8c8c4267593a..688a6a20beeb5 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -43,4 +43,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index d977937e4e3a0..d3e75cfb84caa 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -83,4 +83,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index e71ab949f1076..6cb72f3c194bf 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -12,7 +12,7 @@ module Arel @attribute.column.should == @relation.column_for(@attribute) end end - + describe '#to_sql' do describe 'for a simple attribute' do it "manufactures sql with an alias" do @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/group_spec.rb b/spec/arel/engines/sql/unit/relations/group_spec.rb index b7279a23d9ab8..5e0c675c8b357 100644 --- a/spec/arel/engines/sql/unit/relations/group_spec.rb +++ b/spec/arel/engines/sql/unit/relations/group_spec.rb @@ -53,4 +53,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index 1f4310113353a..f904b6187049b 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -54,4 +54,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/skip_spec.rb b/spec/arel/engines/sql/unit/relations/skip_spec.rb index f8e5ceaad3658..c14bd1ce95e79 100644 --- a/spec/arel/engines/sql/unit/relations/skip_spec.rb +++ b/spec/arel/engines/sql/unit/relations/skip_spec.rb @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 3f5a5ac248a6f..9797b388227c8 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -66,4 +66,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/take_spec.rb b/spec/arel/engines/sql/unit/relations/take_spec.rb index 1263ed4795906..8f1240fc17ef6 100644 --- a/spec/arel/engines/sql/unit/relations/take_spec.rb +++ b/spec/arel/engines/sql/unit/relations/take_spec.rb @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb index 8f9cec537627e..ac842998af82d 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -50,4 +50,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index 789628b95d089..b4e27f238099a 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -10,4 +10,4 @@ } } -ActiveRecord::Base.establish_connection 'unit' \ No newline at end of file +ActiveRecord::Base.establish_connection 'unit' diff --git a/spec/doubles/hash.rb b/spec/doubles/hash.rb index 97d25742cbabd..32c5b98058265 100644 --- a/spec/doubles/hash.rb +++ b/spec/doubles/hash.rb @@ -2,19 +2,19 @@ class Hash def ordered_array to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash } end - + def keys ordered_array.collect(&:first) end - + def values ordered_array.collect { |_, v| v } end - + def each(&block) ordered_array.each(&block) end - + def shift returning to_a.first do |k, v| delete(k) diff --git a/spec/matchers/be_like.rb b/spec/matchers/be_like.rb index 4ff5bc532fcfd..c9d4d4b979235 100644 --- a/spec/matchers/be_like.rb +++ b/spec/matchers/be_like.rb @@ -3,22 +3,22 @@ class BeLike def initialize(expected) @expected = expected end - + def matches?(actual) @actual = actual @expected.gsub(/\s+/, ' ').strip == @actual.gsub(/\s+/, ' ').strip end - + def failure_message "expected\n#{@actual}\nto be like\n#{@expected}" end - + def negative_failure_message "expected\n#{@actual}\nto be unlike\n#{@expected}" end end - + def be_like(expected) BeLike.new(expected) end -end \ No newline at end of file +end diff --git a/spec/matchers/disambiguate_attributes.rb b/spec/matchers/disambiguate_attributes.rb index bee7d22b0cc07..bc4a5215d4c9d 100644 --- a/spec/matchers/disambiguate_attributes.rb +++ b/spec/matchers/disambiguate_attributes.rb @@ -3,7 +3,7 @@ class DisambiguateAttributes def initialize(attributes) @attributes = attributes end - + def matches?(actual) @actual = actual attribute1, attribute2 = @attributes @@ -11,18 +11,18 @@ def matches?(actual) !@actual[attribute1].descends_from?(attribute2) && @actual[attribute2].descends_from?(attribute2) end - + def failure_message "" # "expected #{@actual} to disambiguate its attributes" end - + def negative_failure_message "expected #{@actual} to not disambiguate its attributes" end end - + def disambiguate_attributes(*attributes) DisambiguateAttributes.new(attributes) end -end \ No newline at end of file +end diff --git a/spec/matchers/hash_the_same_as.rb b/spec/matchers/hash_the_same_as.rb index c1903b62b4ba1..03e955a0cb5b0 100644 --- a/spec/matchers/hash_the_same_as.rb +++ b/spec/matchers/hash_the_same_as.rb @@ -3,24 +3,24 @@ class HashTheSameAs def initialize(expected) @expected = expected end - + def matches?(actual) @actual = actual hash = {} hash[@expected] = :some_arbitrary_value hash[@actual] == :some_arbitrary_value end - + def failure_message "expected #{@actual} to hash the same as #{@expected}; they must be `eql?` and have the same `#hash` value" end - + def negative_failure_message "expected #{@actual} to hash differently than #{@expected}; they must not be `eql?` or have a differing `#hash` values" end end - + def hash_the_same_as(expected) HashTheSameAs.new(expected) end -end \ No newline at end of file +end diff --git a/spec/schemas/mysql_schema.rb b/spec/schemas/mysql_schema.rb index 1123f4582e2fd..dc2558fd6af8f 100644 --- a/spec/schemas/mysql_schema.rb +++ b/spec/schemas/mysql_schema.rb @@ -15,4 +15,4 @@ sql.split(/;/).select(&:present?).each do |sql_statement| ActiveRecord::Base.connection.execute sql_statement -end \ No newline at end of file +end diff --git a/spec/schemas/sqlite3_schema.rb b/spec/schemas/sqlite3_schema.rb index 6c98a4f934966..94d224520e299 100644 --- a/spec/schemas/sqlite3_schema.rb +++ b/spec/schemas/sqlite3_schema.rb @@ -15,4 +15,4 @@ sql.split(/;/).select(&:present?).each do |sql_statement| ActiveRecord::Base.connection.execute sql_statement -end \ No newline at end of file +end From 0352d28a56de36946e691a0df390cfdfa7b1de7c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:31:16 -0400 Subject: [PATCH 0234/1492] Moving a few stray SQL references in the memory engine code --- lib/arel/engines/memory/predicates.rb | 15 --------------- lib/arel/engines/sql/predicates.rb | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index e233f3ba39037..03d4f25b0aa99 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -1,25 +1,10 @@ module Arel - class Binary < Predicate def eval(row) operand1.eval(row).send(operator, operand2.eval(row)) end end - class CompoundPredicate < Binary - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" - end - end - - class Or < CompoundPredicate - def predicate_sql; "OR" end - end - - class And < CompoundPredicate - def predicate_sql; "AND" end - end - class Equality < Binary def operator; :== end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 7e195c26051a8..b84c183c1dcc0 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -5,6 +5,20 @@ def to_sql(formatter = nil) end end + class CompoundPredicate < Binary + def to_sql(formatter = nil) + "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + end + end + + class Or < CompoundPredicate + def predicate_sql; "OR" end + end + + class And < CompoundPredicate + def predicate_sql; "AND" end + end + class Equality < Binary def predicate_sql operand2.equality_predicate_sql From ed8e0f9c02c291a51f93a2123e099d07756d75bb Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:42:17 -0400 Subject: [PATCH 0235/1492] Include modules to extend core classes to improve inspectability --- lib/arel/algebra/extensions/array.rb | 21 ++++--- lib/arel/algebra/extensions/class.rb | 65 +++++++++++--------- lib/arel/algebra/extensions/hash.rb | 12 ++-- lib/arel/algebra/extensions/object.rb | 31 +++++----- lib/arel/algebra/extensions/pathname.rb | 12 ++-- lib/arel/algebra/extensions/symbol.rb | 10 ++- lib/arel/engines/sql/extensions/array.rb | 19 ++++-- lib/arel/engines/sql/extensions/nil_class.rb | 12 +++- lib/arel/engines/sql/extensions/object.rb | 18 ++++-- lib/arel/engines/sql/extensions/range.rb | 18 ++++-- 10 files changed, 134 insertions(+), 84 deletions(-) diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb index 48541a395ee91..e7e44ae9091ac 100644 --- a/lib/arel/algebra/extensions/array.rb +++ b/lib/arel/algebra/extensions/array.rb @@ -1,12 +1,17 @@ -class Array - def to_hash - Hash[*flatten] - end +module Arel + module ArrayExtensions + def to_hash + Hash[*flatten] + end - def group_by - inject({}) do |groups, element| - (groups[yield(element)] ||= []) << element - groups + def group_by + inject({}) do |groups, element| + (groups[yield(element)] ||= []) << element + groups + end end + + Array.send(:include, self) end end + diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index 0a729d82558a5..d005814f91a32 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -1,37 +1,42 @@ -class Class - def attributes(*attrs) - @attributes = attrs - attr_reader *attrs - end - - def deriving(*methods) - methods.each { |m| derive m } - end +module Arel + module ClassExtensions + def attributes(*attrs) + @attributes = attrs + attr_reader *attrs + end - def derive(method_name) - methods = { - :initialize => " - def #{method_name}(#{@attributes.join(',')}) - #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} - end - ", - :== => " - def ==(other) - #{name} === other && - #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} - end - " - } - class_eval methods[method_name], __FILE__, __LINE__ - end + def deriving(*methods) + methods.each { |m| derive m } + end - def hash_on(delegatee) - define_method :eql? do |other| - self == other + def derive(method_name) + methods = { + :initialize => " + def #{method_name}(#{@attributes.join(',')}) + #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} + end + ", + :== => " + def ==(other) + #{name} === other && + #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} + end + " + } + class_eval methods[method_name], __FILE__, __LINE__ end - define_method :hash do - @hash ||= delegatee.hash + def hash_on(delegatee) + define_method :eql? do |other| + self == other + end + + define_method :hash do + @hash ||= delegatee.hash + end end + + Class.send(:include, self) end end + diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 82cd5e11d3372..05c15e7ebe62a 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -1,7 +1,11 @@ -class Hash - def bind(relation) - inject({}) do |bound, (key, value)| - bound.merge(key.bind(relation) => value.bind(relation)) +module Arel + module HashExtensions + def bind(relation) + inject({}) do |bound, (key, value)| + bound.merge(key.bind(relation) => value.bind(relation)) + end end + + Hash.send(:include, self) end end diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index efdbbf525fde6..80d68df177dae 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -1,20 +1,23 @@ -class Object - def bind(relation) - Arel::Value.new(self, relation) - end +module Arel + module ObjectExtensions + def bind(relation) + Arel::Value.new(self, relation) + end - def find_correlate_in(relation) - bind(relation) - end + def find_correlate_in(relation) + bind(relation) + end - def metaclass - class << self - self + def metaclass + class << self + self + end end - end - def let - yield(self) + def let + yield(self) + end + + Object.send(:include, self) end end - diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb index 45f1a5f6b31ec..829f692d79800 100644 --- a/lib/arel/algebra/extensions/pathname.rb +++ b/lib/arel/algebra/extensions/pathname.rb @@ -1,5 +1,9 @@ -class Pathname - def /(path) - (self + path).expand_path +module Arel + module PathnameExtensions + def /(path) + (self + path).expand_path + end + + Pathname.send(:include, self) end -end +end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb index 8d324a801cb1b..9bb47ef7abf94 100644 --- a/lib/arel/algebra/extensions/symbol.rb +++ b/lib/arel/algebra/extensions/symbol.rb @@ -1,5 +1,9 @@ -class Symbol - def to_attribute(relation) - Arel::Attribute.new(relation, self) +module Arel + module SymbolExtensions + def to_attribute(relation) + Arel::Attribute.new(relation, self) + end + + Symbol.send(:include, self) end end diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb index d97dd1aa25279..7f15179721261 100644 --- a/lib/arel/engines/sql/extensions/array.rb +++ b/lib/arel/engines/sql/extensions/array.rb @@ -1,9 +1,16 @@ -class Array - def to_sql(formatter = nil) - "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" - end +module Arel + module Sql + module ArrayExtensions + def to_sql(formatter = nil) + "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" + end - def inclusion_predicate_sql - "IN" + def inclusion_predicate_sql + "IN" + end + + Array.send(:include, self) + end end end + diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb index 6f38ecdf3ab77..8c335f904ae6c 100644 --- a/lib/arel/engines/sql/extensions/nil_class.rb +++ b/lib/arel/engines/sql/extensions/nil_class.rb @@ -1,5 +1,11 @@ -class NilClass - def equality_predicate_sql - 'IS' +module Arel + module Sql + module NilClassExtensions + def equality_predicate_sql + 'IS' + end + + NilClass.send(:include, self) + end end end diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb index 65270ee3de072..8fe63dba2faec 100644 --- a/lib/arel/engines/sql/extensions/object.rb +++ b/lib/arel/engines/sql/extensions/object.rb @@ -1,9 +1,15 @@ -class Object - def to_sql(formatter) - formatter.scalar self - end +module Arel + module Sql + module ObjectExtensions + def to_sql(formatter) + formatter.scalar self + end - def equality_predicate_sql - '=' + def equality_predicate_sql + '=' + end + + Object.send(:include, self) + end end end diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb index 946dbc26330e9..25bf1d01daaf0 100644 --- a/lib/arel/engines/sql/extensions/range.rb +++ b/lib/arel/engines/sql/extensions/range.rb @@ -1,9 +1,15 @@ -class Range - def to_sql(formatter = nil) - formatter.range self.begin, self.end - end +module Arel + module Sql + module RangeExtensions + def to_sql(formatter = nil) + formatter.range self.begin, self.end + end - def inclusion_predicate_sql - "BETWEEN" + def inclusion_predicate_sql + "BETWEEN" + end + + Range.send(:include, self) + end end end From 16707d1b96365ab569e7a5e47a3d694c14d4132c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:44:38 -0400 Subject: [PATCH 0236/1492] Add spec for Attribute#inspect --- spec/arel/algebra/unit/primitives/attribute_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index 89e338e377229..afcf1237e0dd2 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -7,6 +7,12 @@ module Arel @attribute = @relation[:id] end + describe "#inspect" do + it "returns a simple, short inspect string" do + @attribute.inspect.should == "" + end + end + describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do From 605973614add20b504489e6fac086565717db14b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:48:04 -0400 Subject: [PATCH 0237/1492] Removing unused array extensions --- lib/arel/algebra/extensions.rb | 1 - lib/arel/algebra/extensions/array.rb | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 lib/arel/algebra/extensions/array.rb diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb index 694dc60a2a391..bc8edd32741d8 100644 --- a/lib/arel/algebra/extensions.rb +++ b/lib/arel/algebra/extensions.rb @@ -1,5 +1,4 @@ require 'arel/algebra/extensions/object' require 'arel/algebra/extensions/class' -require 'arel/algebra/extensions/array' require 'arel/algebra/extensions/symbol' require 'arel/algebra/extensions/hash' diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb deleted file mode 100644 index e7e44ae9091ac..0000000000000 --- a/lib/arel/algebra/extensions/array.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Arel - module ArrayExtensions - def to_hash - Hash[*flatten] - end - - def group_by - inject({}) do |groups, element| - (groups[yield(element)] ||= []) << element - groups - end - end - - Array.send(:include, self) - end -end - From 7fc820501ce7b997da43c47ec189aaa0d40645e1 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:49:15 -0400 Subject: [PATCH 0238/1492] Removing two unused externalizable? methods --- lib/arel/algebra/relations/operations/group.rb | 4 ---- lib/arel/algebra/relations/operations/skip.rb | 4 ---- 2 files changed, 8 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index b8975ed3d6fb6..2bfc42214bb88 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -8,9 +8,5 @@ def initialize(relation, *groupings, &block) @groupings = (groupings + arguments_from_block(relation, &block)) \ .collect { |g| g.bind(relation) } end - - def externalizable? - true - end end end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 2dda191c35ee6..689e06e1c3ed8 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -2,9 +2,5 @@ module Arel class Skip < Compound attributes :relation, :skipped deriving :initialize, :== - - def externalizable? - true - end end end From d2988420fc6dd91ca751d96ed648fd1ed52ce342 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 17:53:40 -0400 Subject: [PATCH 0239/1492] Added PostgreSQL to build --- Rakefile | 4 +- .../sql/unit/predicates/binary_spec.rb | 18 +++++++-- .../engines/sql/unit/primitives/value_spec.rb | 9 ++++- .../engines/sql/unit/relations/insert_spec.rb | 20 +++++++++- .../engines/sql/unit/relations/update_spec.rb | 38 +++++++++++++++++-- spec/arel/unit/predicates/predicates_spec.rb | 16 +++++++- spec/connections/postgresql_connection.rb | 12 ++++++ spec/schemas/postgresql_schema.rb | 18 +++++++++ spec/spec_helper.rb | 14 ++++++- 9 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 spec/connections/postgresql_connection.rb create mode 100644 spec/schemas/postgresql_schema.rb diff --git a/Rakefile b/Rakefile index cfae22260a6a2..17a6f8d35d07d 100644 --- a/Rakefile +++ b/Rakefile @@ -17,7 +17,7 @@ Spec::Rake::SpecTask.new(:coverage) do |t| end namespace :spec do - for adapter in %w[mysql sqlite3] + for adapter in %w[mysql sqlite3 postgresql] desc "Run specs with the #{adapter} database adapter" Spec::Rake::SpecTask.new(adapter) do |t| t.spec_files = @@ -29,7 +29,7 @@ namespace :spec do end desc "Run specs with mysql and sqlite3 database adapters (default)" -task :spec => ["spec:sqlite3", "spec:mysql"] +task :spec => ["spec:sqlite3", "spec:mysql", "spec:postgresql"] desc "Default task is to run specs" task :default => :spec diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index befd2878d9549..b1400e2588ca5 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -28,7 +28,11 @@ def predicate_sql sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) end - adapter_is_not :mysql do + adapter_is :postgresql do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> E'name')}) + end + + adapter_is :sqlite3 do sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) end end @@ -44,9 +48,13 @@ def predicate_sql sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) end + + adapter_is :postgresql do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> E'name')}) + end end end end @@ -94,9 +102,13 @@ def predicate_sql sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) end + + adapter_is :postgresql do + sql.should be_like(%Q{"users"."name" <=> E'1-asdf'}) + end end end end diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb index da5a163d3bafd..ff3533f6ef532 100644 --- a/spec/arel/engines/sql/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -9,7 +9,14 @@ module Arel describe '#to_sql' do it "appropriately quotes the value" do Value.new(1, @relation).to_sql.should be_like('1') - Value.new('asdf', @relation).to_sql.should be_like("'asdf'") + + adapter_is_not :postgresql do + Value.new('asdf', @relation).to_sql.should be_like("'asdf'") + end + + adapter_is :postgresql do + Value.new('asdf', @relation).to_sql.should be_like("E'asdf'") + end end end diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb index dd1995cced17f..29a5e0bf4235c 100644 --- a/spec/arel/engines/sql/unit/relations/insert_spec.rb +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -30,13 +30,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @insertion.to_sql.should be_like(%Q{ INSERT INTO "users" ("id", "name") VALUES (1, 'nick') }) end + + adapter_is :postgresql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id", "name") VALUES (1, E'nick') + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -53,13 +61,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @insertion.to_sql.should be_like(%Q{ INSERT INTO "users" ("name") VALUES ('nick') }) end + + adapter_is :postgresql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("name") VALUES (E'nick') + }) + end end end diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb index f553490ef584d..4d728eb241387 100644 --- a/spec/arel/engines/sql/unit/relations/update_spec.rb +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -17,12 +17,19 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ UPDATE "users" SET "id" = 1, "name" = 'nick' }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1, "name" = E'nick' + }) + end end it "manufactures sql updating attributes when given a ranged relation" do @@ -36,13 +43,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ UPDATE "users" SET "name" = 'nick' LIMIT 1 }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + UPDATE "users" + SET "name" = E'nick' + LIMIT 1 + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -58,12 +73,19 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @update.to_sql.should be_like(%Q{ UPDATE "users" SET "name" = 'nick' }) end + + adapter_is :postgresql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = E'nick' + }) + end end end @@ -106,13 +128,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @update.to_sql.should be_like(%Q{ UPDATE "users" SET "name" = 'nick' WHERE "users"."id" = 1 }) end + + adapter_is :postgresql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = E'nick' + WHERE "users"."id" = 1 + }) + end end end end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb index ac842998af82d..8e7e0b1d9fd82 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -21,11 +21,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ ("users"."id" = 1 AND "users"."name" = 'name') }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = E'name') + }) + end end end end @@ -41,11 +47,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ ("users"."id" = 1 OR "users"."name" = 'name') }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = E'name') + }) + end end end end diff --git a/spec/connections/postgresql_connection.rb b/spec/connections/postgresql_connection.rb new file mode 100644 index 0000000000000..505dcdd1ef587 --- /dev/null +++ b/spec/connections/postgresql_connection.rb @@ -0,0 +1,12 @@ +require "activerecord" +puts "Using native PostgreSQL" + +ActiveRecord::Base.configurations = { + 'unit' => { + :adapter => 'postgresql', + :encoding => 'utf8', + :database => 'arel_unit', + } +} + +ActiveRecord::Base.establish_connection 'unit' diff --git a/spec/schemas/postgresql_schema.rb b/spec/schemas/postgresql_schema.rb new file mode 100644 index 0000000000000..30fa665902308 --- /dev/null +++ b/spec/schemas/postgresql_schema.rb @@ -0,0 +1,18 @@ +sql = <<-SQL + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255) NOT NULL + ); + + DROP TABLE IF EXISTS photos; + CREATE TABLE photos ( + id SERIAL PRIMARY KEY NOT NULL, + user_id INTEGER NOT NULL, + camera_id INTEGER NOT NULL + ); +SQL + +sql.split(/;/).select(&:present?).each do |sql_statement| + ActiveRecord::Base.connection.execute sql_statement +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6a9a2ef23c8ce..beb634fbd326a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -13,15 +13,27 @@ module AdapterGuards def adapter_is(name) + verify_adapter_name(name) yield if name.to_s == adapter_name end def adapter_is_not(name) + verify_adapter_name(name) yield if name.to_s != adapter_name end def adapter_name - Arel::Table.engine.connection.class.name.underscore.split("/").last.gsub(/_adapter/, '') + name = ActiveRecord::Base.configurations["unit"][:adapter] + verify_adapter_name(name) + name + end + + def verify_adapter_name(name) + raise "Invalid adapter name: #{name}" unless valid_adapters.include?(name.to_s) + end + + def valid_adapters + %w[mysql postgresql sqlite3] end end From c106c1ef59527331c9945f5f95e6b4e27194ac06 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:08:13 -0400 Subject: [PATCH 0240/1492] Moving SQL predicates spec to correct dir --- spec/arel/{ => engines/sql}/unit/predicates/predicates_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename spec/arel/{ => engines/sql}/unit/predicates/predicates_spec.rb (95%) diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb similarity index 95% rename from spec/arel/unit/predicates/predicates_spec.rb rename to spec/arel/engines/sql/unit/predicates/predicates_spec.rb index 8e7e0b1d9fd82..d55e178e432f2 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') module Arel describe Predicate do From 10c4b42c35f61145ac6ebb8d36f504344eef47cd Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:21:56 -0400 Subject: [PATCH 0241/1492] Fix bug in Order equality where Descending.new(attribute) was == Ascending.new(attribute) --- lib/arel/algebra/primitives/ordering.rb | 13 +++++++++---- spec/arel/algebra/unit/primitives/attribute_spec.rb | 4 ++-- spec/arel/algebra/unit/relations/order_spec.rb | 10 ++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb index a60d794f27ae9..3efb4c6280e36 100644 --- a/lib/arel/algebra/primitives/ordering.rb +++ b/lib/arel/algebra/primitives/ordering.rb @@ -1,7 +1,5 @@ module Arel class Ordering - attributes :attribute - deriving :initialize, :== delegate :relation, :to => :attribute def bind(relation) @@ -13,6 +11,13 @@ def to_ordering end end - class Ascending < Ordering; end - class Descending < Ordering; end + class Ascending < Ordering + attributes :attribute + deriving :initialize, :== + end + + class Descending < Ordering + attributes :attribute + deriving :initialize, :== + end end diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index afcf1237e0dd2..2ca63ba48eddb 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -169,13 +169,13 @@ module Arel describe Attribute::Orderings do describe '#asc' do it 'manufactures an ascending ordering' do - pending + @attribute.asc.should == Ascending.new(@attribute) end end describe '#desc' do it 'manufactures a descending ordering' do - pending + @attribute.desc.should == Descending.new(@attribute) end end end diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb index 4f163894c851c..8b3c932fb9c7c 100644 --- a/spec/arel/algebra/unit/relations/order_spec.rb +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -6,6 +6,16 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end + + describe "#==" do + it "returns true when the Orders are for the same attribute and direction" do + Ascending.new(@attribute).should == Ascending.new(@attribute) + end + + it "returns false when the Orders are for a diferent direction" do + Ascending.new(@attribute).should_not == Descending.new(@attribute) + end + end end end From a842aa572af1e8fac48f8a73a2e2985fbe39e046 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:35:45 -0400 Subject: [PATCH 0242/1492] Removing Object#metaclass definition (it's already in ActiveSupport) --- lib/arel/algebra/extensions/object.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index 80d68df177dae..d8c60b5dd5be7 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -8,12 +8,6 @@ def find_correlate_in(relation) bind(relation) end - def metaclass - class << self - self - end - end - def let yield(self) end From 9560650fa79212b33d6ab349ff83b4f617d395b7 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:36:08 -0400 Subject: [PATCH 0243/1492] Adding skeleton of spec for CRUD operations in Sql::Engine --- spec/arel/engines/sql/unit/engine_spec.rb | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 spec/arel/engines/sql/unit/engine_spec.rb diff --git a/spec/arel/engines/sql/unit/engine_spec.rb b/spec/arel/engines/sql/unit/engine_spec.rb new file mode 100644 index 0000000000000..67a5d62320761 --- /dev/null +++ b/spec/arel/engines/sql/unit/engine_spec.rb @@ -0,0 +1,36 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Sql::Engine do + before do + @relation = Table.new(:users) + end + + describe "CRUD" do + describe "#create" do + it "inserts into the relation" do + @relation.insert @relation[:name] => "Bryan" + end + end + + describe "#read" do + it "reads from the relation" do + @relation.each do |row| + end + end + end + + describe "#update" do + it "updates the relation" do + @relation.update @relation[:name] => "Bryan" + end + end + + describe "#delete" do + it "deletes from the relation" do + @relation.delete + end + end + end + end +end From 982f100d49095614df320d449f66f69aa827a763 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:40:24 -0400 Subject: [PATCH 0244/1492] Refactor #select_sql. Extract methods to generate clauses --- lib/arel/engines/sql/relations/relation.rb | 34 +++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 93c146352c12a..c8a4d952fe639 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -6,17 +6,18 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) def select_sql [ - "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "SELECT #{select_clauses.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), - ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n") end + def inclusion_predicate_sql "IN" end @@ -24,5 +25,24 @@ def inclusion_predicate_sql def christener @christener ||= Sql::Christener.new end + + protected + + def select_clauses + attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } + end + + def where_clauses + wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } + end + + def group_clauses + groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } + end + + def order_clauses + orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } + end + end end From 2e6fbf4f75c8e33380623b52e86ca8b90037712f Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:47:45 -0400 Subject: [PATCH 0245/1492] Extracting #build_query method for creating SQL from parts --- lib/arel/engines/sql/relations/relation.rb | 8 +++-- .../sql/relations/utilities/compound.rb | 4 +++ lib/arel/engines/sql/relations/writes.rb | 29 ++++++++++--------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index c8a4d952fe639..4cfb83a6017cd 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -5,7 +5,7 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) end def select_sql - [ + build_query \ "SELECT #{select_clauses.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), @@ -14,10 +14,8 @@ def select_sql ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n") end - def inclusion_predicate_sql "IN" end @@ -28,6 +26,10 @@ def christener protected + def build_query(*parts) + parts.compact.join("\n") + end + def select_clauses attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } end diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index b63a829c6738d..f8ce4033fd122 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -1,6 +1,10 @@ module Arel class Compound < Relation delegate :table, :table_sql, :to => :relation + + def build_query(*parts) + parts.compact.join("\n") + end end end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 4d753f5fcab77..f1a9bfd2ac561 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -1,36 +1,39 @@ module Arel class Deletion < Compound def to_sql(formatter = nil) - [ + build_query \ "DELETE", "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) end end class Insert < Compound def to_sql(formatter = nil) - [ + build_query \ "INSERT", "INTO #{table_sql}", "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" - ].join("\n") end end class Update < Compound def to_sql(formatter = nil) - [ + build_query \ "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") + assignment_sql, + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) + end + + protected + + def assignment_sql + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n") end end end From d3c343c6afdc65ca959beaeb20d71dd9f2fcf93f Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 00:59:01 -0400 Subject: [PATCH 0246/1492] Remvoing unused variable from spec --- spec/arel/engines/memory/unit/relations/join_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb index df08fd4a96a06..110fdb03b7cb9 100644 --- a/spec/arel/engines/memory/unit/relations/join_spec.rb +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -9,7 +9,6 @@ module Arel [3, 'goose'] ], [:id, :name]) @relation2 = @relation1.alias - @relation3 = @relation1.alias end describe InnerJoin do From 1234c926cce2a979ec967a8c5bc6ba58cda1ce71 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 00:59:08 -0400 Subject: [PATCH 0247/1492] Cleaning up Sql::Engine#read --- lib/arel/engines/sql/engine.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 5a8c9f16c5864..7d2926040c0d7 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -19,13 +19,7 @@ def create(relation) end def read(relation) - # FIXME rows = connection.select_rows(relation.to_sql) - - class << rows - include Enumerable - end - Array.new(rows, relation.attributes) end From 930c9f90a03729bdc380ab84882a118d8c17e54d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:11:40 -0400 Subject: [PATCH 0248/1492] Cleanup Sql formatters a bit --- lib/arel/engines/sql/formatters.rb | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 08a32843c9f94..ae80feb18e9d3 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -14,18 +14,17 @@ def initialize(environment) class SelectClause < Formatter def attribute(attribute) # FIXME this should check that the column exists - if attribute.name.to_s =~ /^\w*$/ - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - else - attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - end + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") end def expression(expression) if expression.function_sql == "DISTINCT" - "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') else - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") end end @@ -93,11 +92,8 @@ def select(select_sql, table) end def table(table) - if table.name =~ /^(\w|-)*$/ - quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') - else - table.name + (table.name != name_for(table) ? " AS " + (name_for(table)) : '') - end + quote_table_name(table.name) + + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') end end @@ -106,10 +102,6 @@ def scalar(scalar) quote(scalar, environment.column) end - def array(array) - "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" - end - def range(left, right) "#{left} AND #{right}" end From 65e419c172217f9747e2e56b36fcc4b6089a0d6d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:25:09 -0400 Subject: [PATCH 0249/1492] Expand usages of #hash_on. The #hash definition it produces looks broken, but leaving it for now --- lib/arel/algebra/extensions/class.rb | 10 ---------- lib/arel/algebra/relations/operations/join.rb | 9 ++++++++- lib/arel/algebra/relations/utilities/compound.rb | 12 ++++++++++-- lib/arel/engines/sql/relations/table.rb | 9 ++++++++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index d005814f91a32..520111b90f38e 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -25,16 +25,6 @@ def ==(other) } class_eval methods[method_name], __FILE__, __LINE__ end - - def hash_on(delegatee) - define_method :eql? do |other| - self == other - end - - define_method :hash do - @hash ||= delegatee.hash - end - end Class.send(:include, self) end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index e47d9fa9e0131..e9320f28e1a89 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -3,12 +3,19 @@ class Join < Relation attributes :relation1, :relation2, :predicates deriving :== delegate :name, :to => :relation1 - hash_on :relation1 def initialize(relation1, relation2 = Nil.instance, *predicates) @relation1, @relation2, @predicates = relation1, relation2, predicates end + def hash + @hash ||= :relation1.hash + end + + def eql?(other) + self == other + end + def attributes @attributes ||= (relation1.externalize.attributes + relation2.externalize.attributes).collect { |a| a.bind(self) } diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 676d80a737109..5e775618f1492 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -1,7 +1,6 @@ module Arel class Compound < Relation attr_reader :relation - hash_on :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, :column_for, :engine, :to => :relation @@ -14,7 +13,16 @@ def #{operation_name} OPERATION end - private + def hash + @hash ||= :relation.hash + end + + def eql?(other) + self == other + end + + private + def arguments_from_block(relation, &block) block_given?? [yield(relation)] : [] end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 0b6574eedc3ae..dd22f442264b1 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -4,7 +4,6 @@ class Table < Relation cattr_accessor :engine attr_reader :name, :engine - hash_on :name def initialize(name, engine = Table.engine) @name, @engine = name.to_s, engine @@ -16,6 +15,14 @@ def attributes end end + def eql?(other) + self == other + end + + def hash + @hash ||= :name.hash + end + def format(attribute, value) attribute.column.type_cast(value) end From fbfbf1adcb2252c326aa869a6f94bd3269565ba2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:36:12 -0400 Subject: [PATCH 0250/1492] Removing unused Pathname extension --- lib/arel/algebra/extensions/pathname.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 lib/arel/algebra/extensions/pathname.rb diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb deleted file mode 100644 index 829f692d79800..0000000000000 --- a/lib/arel/algebra/extensions/pathname.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - module PathnameExtensions - def /(path) - (self + path).expand_path - end - - Pathname.send(:include, self) - end -end \ No newline at end of file From 8feb358bd00cea30eb677e32f10995f5eddc167a Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:47:42 -0400 Subject: [PATCH 0251/1492] Ignore debug.log --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index da2f440badc89..c6dd721751c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ coverage/* config/database.yml spec/fixtures/*database* *.DS_Store +debug.log From 082079169caab2a00f62d9de9c4bdb5dcbc591aa Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:49:50 -0400 Subject: [PATCH 0252/1492] Better inspect output for Expressions --- lib/arel/algebra/primitives/expression.rb | 4 ++++ spec/arel/algebra/unit/primitives/expression_spec.rb | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb index 5566e2d0b79e3..875498c28282e 100644 --- a/lib/arel/algebra/primitives/expression.rb +++ b/lib/arel/algebra/primitives/expression.rb @@ -13,6 +13,10 @@ def aggregation? true end + def inspect + "<#{self.class.name} #{attribute.inspect}>" + end + module Transformations def as(aliaz) self.class.new(attribute, aliaz, self) diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index 82d12d53f9383..768bb492a768a 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -7,6 +7,12 @@ module Arel @attribute = @relation[:id] end + describe "#inspect" do + it "returns a simple, short inspect string" do + @attribute.count.inspect.should == ">" + end + end + describe Expression::Transformations do before do @expression = Count.new(@attribute) From eede6962a8c1ee86b49907c1937fb0e3a38cf819 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:50:39 -0400 Subject: [PATCH 0253/1492] Log queries to debug.log when running specs --- spec/connections/mysql_connection.rb | 2 ++ spec/connections/postgresql_connection.rb | 2 ++ spec/connections/sqlite3_connection.rb | 2 ++ 3 files changed, 6 insertions(+) diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index b4e27f238099a..a58ddc35efd5e 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -1,6 +1,8 @@ require "activerecord" puts "Using native MySQL" +ActiveRecord::Base.logger = Logger.new("debug.log") + ActiveRecord::Base.configurations = { 'unit' => { :adapter => 'mysql', diff --git a/spec/connections/postgresql_connection.rb b/spec/connections/postgresql_connection.rb index 505dcdd1ef587..e376d33ec647d 100644 --- a/spec/connections/postgresql_connection.rb +++ b/spec/connections/postgresql_connection.rb @@ -1,6 +1,8 @@ require "activerecord" puts "Using native PostgreSQL" +ActiveRecord::Base.logger = Logger.new("debug.log") + ActiveRecord::Base.configurations = { 'unit' => { :adapter => 'postgresql', diff --git a/spec/connections/sqlite3_connection.rb b/spec/connections/sqlite3_connection.rb index bae077711d9bf..649492f804e08 100644 --- a/spec/connections/sqlite3_connection.rb +++ b/spec/connections/sqlite3_connection.rb @@ -1,6 +1,8 @@ require "activerecord" puts "Using native SQLite3" +ActiveRecord::Base.logger = Logger.new("debug.log") + db_file = "spec/fixtures/fixture_database.sqlite3" ActiveRecord::Base.configurations = { From 976fb01a5dd812bcb50cc7b576941c76657908f9 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:50:50 -0400 Subject: [PATCH 0254/1492] Expand sql engine CRUD specs --- spec/arel/engines/sql/unit/engine_spec.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/spec/arel/engines/sql/unit/engine_spec.rb b/spec/arel/engines/sql/unit/engine_spec.rb index 67a5d62320761..c607abcfa17f2 100644 --- a/spec/arel/engines/sql/unit/engine_spec.rb +++ b/spec/arel/engines/sql/unit/engine_spec.rb @@ -3,32 +3,41 @@ module Arel describe Sql::Engine do before do - @relation = Table.new(:users) + @users = Table.new(:users) + @users.delete end describe "CRUD" do describe "#create" do it "inserts into the relation" do - @relation.insert @relation[:name] => "Bryan" + @users.insert @users[:name] => "Bryan" + @users.first[@users[:name]].should == "Bryan" end end describe "#read" do it "reads from the relation" do - @relation.each do |row| + @users.insert @users[:name] => "Bryan" + + @users.each do |row| + row[@users[:name]].should == "Bryan" end end end describe "#update" do it "updates the relation" do - @relation.update @relation[:name] => "Bryan" + @users.insert @users[:name] => "Nick" + @users.update @users[:name] => "Bryan" + @users.first[@users[:name]].should == "Bryan" end end describe "#delete" do it "deletes from the relation" do - @relation.delete + @users.insert @users[:name] => "Bryan" + @users.delete + @users.first.should == nil end end end From b522778a61670825948e2fbd4a3353583c1c7223 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 18 May 2009 19:59:47 -0300 Subject: [PATCH 0255/1492] Require active_support/core_ext since ActiveRecord don't require it any more --- lib/arel.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 00bfa1e2925c0..0240e23959635 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,7 +1,8 @@ $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'rubygems' -require 'activesupport' +require 'active_support' +require 'active_support/core_ext' require 'activerecord' require 'active_record/connection_adapters/abstract/quoting' From 4b8526dddd6a906a1879ec786401070b3545d7f4 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 18 May 2009 20:00:38 -0300 Subject: [PATCH 0256/1492] Don't quote columns when they are not an attribute --- lib/arel/relations/writes/update.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 2e90de3a52fda..52ca6ecf05f46 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -10,9 +10,7 @@ def initialize(relation, assignments) def to_sql(formatter = nil) [ "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), + map_assignments, ("WHERE #{wheres.map(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), ("LIMIT #{taken}" unless taken.blank? ) ].join("\n") @@ -21,5 +19,12 @@ def to_sql(formatter = nil) def call(connection = engine) connection.update(to_sql) end + + def map_assignments + assignments.collect do |attribute, value| + attribute.respond_to?(:name) ? + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" : attribute + end.join(",\n") + end end end From 86364591af807ed3fa4a7304f53e6f3458cb4961 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 19 May 2009 21:36:34 -0400 Subject: [PATCH 0257/1492] Adding SqlLiteral with spec for counts --- lib/arel/engines/sql/primitives.rb | 10 ++++++++ .../sql/unit/primitives/literal_spec.rb | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 spec/arel/engines/sql/unit/primitives/literal_spec.rb diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index f2e8e8dabea5a..bb3bed78e6075 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -1,4 +1,14 @@ module Arel + class SqlLiteral < String + def relation + nil + end + + def to_sql(formatter = nil) + self + end + end + class Attribute def column original_relation.column_for(self) diff --git a/spec/arel/engines/sql/unit/primitives/literal_spec.rb b/spec/arel/engines/sql/unit/primitives/literal_spec.rb new file mode 100644 index 0000000000000..c7ff1cf879a32 --- /dev/null +++ b/spec/arel/engines/sql/unit/primitives/literal_spec.rb @@ -0,0 +1,23 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe SqlLiteral do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "manufactures sql with a literal SQL fragment" do + sql = @relation.project(Count.new(SqlLiteral.new("*"))).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM `users`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "users"}) + end + end + end + end +end From ae1e0ac5e98a7e5a2894d0a431f8c34af6575cae Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 26 May 2009 12:12:19 -0300 Subject: [PATCH 0258/1492] Removed lib to avoid any conflict in merge --- lib/arel.rb | 16 -- lib/arel/.DS_Store | Bin 6148 -> 0 bytes lib/arel/arel.rb | 3 - lib/arel/engine.rb | 18 -- lib/arel/extensions.rb | 6 - lib/arel/extensions/array.rb | 13 -- lib/arel/extensions/class.rb | 37 ---- lib/arel/extensions/hash.rb | 7 - lib/arel/extensions/nil_class.rb | 5 - lib/arel/extensions/object.rb | 23 --- lib/arel/extensions/range.rb | 9 - lib/arel/predicates.rb | 81 --------- lib/arel/primitives.rb | 4 - lib/arel/primitives/attribute.rb | 145 --------------- lib/arel/primitives/expression.rb | 35 ---- lib/arel/primitives/value.rb | 32 ---- lib/arel/relations.rb | 8 - lib/arel/relations/operations.rb | 8 - lib/arel/relations/operations/alias.rb | 8 - lib/arel/relations/operations/group.rb | 15 -- lib/arel/relations/operations/join.rb | 57 ------ lib/arel/relations/operations/order.rb | 16 -- lib/arel/relations/operations/project.rb | 19 -- lib/arel/relations/operations/skip.rb | 10 -- lib/arel/relations/operations/take.rb | 10 -- lib/arel/relations/operations/where.rb | 16 -- lib/arel/relations/relation.rb | 169 ------------------ lib/arel/relations/table.rb | 36 ---- lib/arel/relations/utilities.rb | 5 - lib/arel/relations/utilities/compound.rb | 18 -- .../relations/utilities/externalization.rb | 34 ---- lib/arel/relations/utilities/nil.rb | 10 -- lib/arel/relations/utilities/recursion.rb | 13 -- lib/arel/relations/writes.rb | 3 - lib/arel/relations/writes/delete.rb | 19 -- lib/arel/relations/writes/insert.rb | 23 --- lib/arel/relations/writes/update.rb | 30 ---- lib/arel/session.rb | 47 ----- lib/arel/sql.rb | 2 - lib/arel/sql/christener.rb | 13 -- lib/arel/sql/formatters.rb | 121 ------------- 41 files changed, 1144 deletions(-) delete mode 100644 lib/arel.rb delete mode 100644 lib/arel/.DS_Store delete mode 100644 lib/arel/arel.rb delete mode 100644 lib/arel/engine.rb delete mode 100644 lib/arel/extensions.rb delete mode 100644 lib/arel/extensions/array.rb delete mode 100644 lib/arel/extensions/class.rb delete mode 100644 lib/arel/extensions/hash.rb delete mode 100644 lib/arel/extensions/nil_class.rb delete mode 100644 lib/arel/extensions/object.rb delete mode 100644 lib/arel/extensions/range.rb delete mode 100644 lib/arel/predicates.rb delete mode 100644 lib/arel/primitives.rb delete mode 100644 lib/arel/primitives/attribute.rb delete mode 100644 lib/arel/primitives/expression.rb delete mode 100644 lib/arel/primitives/value.rb delete mode 100644 lib/arel/relations.rb delete mode 100644 lib/arel/relations/operations.rb delete mode 100644 lib/arel/relations/operations/alias.rb delete mode 100644 lib/arel/relations/operations/group.rb delete mode 100644 lib/arel/relations/operations/join.rb delete mode 100644 lib/arel/relations/operations/order.rb delete mode 100644 lib/arel/relations/operations/project.rb delete mode 100644 lib/arel/relations/operations/skip.rb delete mode 100644 lib/arel/relations/operations/take.rb delete mode 100644 lib/arel/relations/operations/where.rb delete mode 100644 lib/arel/relations/relation.rb delete mode 100644 lib/arel/relations/table.rb delete mode 100644 lib/arel/relations/utilities.rb delete mode 100644 lib/arel/relations/utilities/compound.rb delete mode 100644 lib/arel/relations/utilities/externalization.rb delete mode 100644 lib/arel/relations/utilities/nil.rb delete mode 100644 lib/arel/relations/utilities/recursion.rb delete mode 100644 lib/arel/relations/writes.rb delete mode 100644 lib/arel/relations/writes/delete.rb delete mode 100644 lib/arel/relations/writes/insert.rb delete mode 100644 lib/arel/relations/writes/update.rb delete mode 100644 lib/arel/session.rb delete mode 100644 lib/arel/sql.rb delete mode 100644 lib/arel/sql/christener.rb delete mode 100644 lib/arel/sql/formatters.rb diff --git a/lib/arel.rb b/lib/arel.rb deleted file mode 100644 index 0240e23959635..0000000000000 --- a/lib/arel.rb +++ /dev/null @@ -1,16 +0,0 @@ -$LOAD_PATH.unshift(File.dirname(__FILE__)) - -require 'rubygems' -require 'active_support' -require 'active_support/core_ext' -require 'activerecord' -require 'active_record/connection_adapters/abstract/quoting' - -require 'arel/arel' -require 'arel/extensions' -require 'arel/sql' -require 'arel/predicates' -require 'arel/relations' -require 'arel/engine' -require 'arel/session' -require 'arel/primitives' diff --git a/lib/arel/.DS_Store b/lib/arel/.DS_Store deleted file mode 100644 index 9918127870d102c50de66d07fd25f40e6f54037c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRWu5S?j*RLZ7Hmf5m{8(3920T+PqYosWV8faOD4dN&qlQ$nwBhoIBpfl3= z*`8107sX=}5zn9RE{JACG=U1TbOuDG2Tdb)J_54lsHvrr8WQ{)BJVz>dwQWKv|I20 zuqn@rswrR>a#YIOdMzu3?1*VMRZ~C0{ti8+6>?T|gWS$aFY5;vqqD5s$~qYFo%3y1 z&h@fgHY " - def #{method_name}(#{@attributes.join(',')}) - #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} - end - ", - :== => " - def ==(other) - #{name} === other && - #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} - end - " - } - class_eval methods[method_name], __FILE__, __LINE__ - end - - def hash_on(delegatee) - define_method :eql? do |other| - self == other - end - - define_method :hash do - @hash ||= delegatee.hash - end - end -end \ No newline at end of file diff --git a/lib/arel/extensions/hash.rb b/lib/arel/extensions/hash.rb deleted file mode 100644 index 7472b5aa731ad..0000000000000 --- a/lib/arel/extensions/hash.rb +++ /dev/null @@ -1,7 +0,0 @@ -class Hash - def bind(relation) - inject({}) do |bound, (key, value)| - bound.merge(key.bind(relation) => value.bind(relation)) - end - end -end \ No newline at end of file diff --git a/lib/arel/extensions/nil_class.rb b/lib/arel/extensions/nil_class.rb deleted file mode 100644 index 729c4cada7b5e..0000000000000 --- a/lib/arel/extensions/nil_class.rb +++ /dev/null @@ -1,5 +0,0 @@ -class NilClass - def equality_predicate_sql - 'IS' - end -end \ No newline at end of file diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb deleted file mode 100644 index 14e2f82ce52d1..0000000000000 --- a/lib/arel/extensions/object.rb +++ /dev/null @@ -1,23 +0,0 @@ -class Object - def bind(relation) - Arel::Value.new(self, relation) - end - - def find_correlate_in(relation) - bind(relation) - end - - def to_sql(formatter) - formatter.scalar self - end - - def equality_predicate_sql - '=' - end - - def metaclass - class << self - self - end - end -end diff --git a/lib/arel/extensions/range.rb b/lib/arel/extensions/range.rb deleted file mode 100644 index d7329efe344a2..0000000000000 --- a/lib/arel/extensions/range.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Range - def to_sql(formatter = nil) - formatter.range self.begin, self.end - end - - def inclusion_predicate_sql - "BETWEEN" - end -end \ No newline at end of file diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb deleted file mode 100644 index b639022b4e1f3..0000000000000 --- a/lib/arel/predicates.rb +++ /dev/null @@ -1,81 +0,0 @@ -module Arel - class Predicate - def or(other_predicate) - Or.new(self, other_predicate) - end - - def and(other_predicate) - And.new(self, other_predicate) - end - end - - class Binary < Predicate - attributes :operand1, :operand2 - deriving :initialize - - def ==(other) - self.class === other and - @operand1 == other.operand1 and - @operand2 == other.operand2 - end - - def bind(relation) - self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) - end - - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" - end - alias_method :to_s, :to_sql - end - - class CompoundPredicate < Binary - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" - end - end - - class Or < CompoundPredicate - def predicate_sql; "OR" end - end - - class And < CompoundPredicate - def predicate_sql; "AND" end - end - - class Equality < Binary - def ==(other) - Equality === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) - end - - def predicate_sql - operand2.equality_predicate_sql - end - end - - class GreaterThanOrEqualTo < Binary - def predicate_sql; '>=' end - end - - class GreaterThan < Binary - def predicate_sql; '>' end - end - - class LessThanOrEqualTo < Binary - def predicate_sql; '<=' end - end - - class LessThan < Binary - def predicate_sql; '<' end - end - - class Match < Binary - def predicate_sql; 'LIKE' end - end - - class In < Binary - def predicate_sql; operand2.inclusion_predicate_sql end - end -end diff --git a/lib/arel/primitives.rb b/lib/arel/primitives.rb deleted file mode 100644 index d84713d3d51d0..0000000000000 --- a/lib/arel/primitives.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/primitives/attribute' -require 'arel/primitives/value' -require 'arel/primitives/expression' - diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb deleted file mode 100644 index 6cb558d8ce342..0000000000000 --- a/lib/arel/primitives/attribute.rb +++ /dev/null @@ -1,145 +0,0 @@ -require 'set' - -module Arel - class Attribute - attributes :relation, :name, :alias, :ancestor - deriving :== - delegate :engine, :christener, :to => :relation - - def initialize(relation, name, options = {}) - @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] - end - - def named?(hypothetical_name) - (@alias || name).to_s == hypothetical_name.to_s - end - - def aggregation? - false - end - - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - - module Transformations - def self.included(klass) - klass.send :alias_method, :eql?, :== - end - - def hash - @hash ||= history.size + name.hash + relation.hash - end - - def as(aliaz = nil) - Attribute.new(relation, name, :alias => aliaz, :ancestor => self) - end - - def bind(new_relation) - relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) - end - - def to_attribute - self - end - end - include Transformations - - module Congruence - def history - @history ||= [self] + (ancestor ? ancestor.history : []) - end - - def join? - relation.join? - end - - def root - history.last - end - - def original_relation - @original_relation ||= original_attribute.relation - end - - def original_attribute - @original_attribute ||= history.detect { |a| !a.join? } - end - - def find_correlate_in(relation) - relation[self] || self - end - - def descends_from?(other) - history.include?(other) - end - - def /(other) - other ? (history & other.history).size : 0 - end - end - include Congruence - - module Predications - def eq(other) - Equality.new(self, other) - end - - def lt(other) - LessThan.new(self, other) - end - - def lteq(other) - LessThanOrEqualTo.new(self, other) - end - - def gt(other) - GreaterThan.new(self, other) - end - - def gteq(other) - GreaterThanOrEqualTo.new(self, other) - end - - def matches(regexp) - Match.new(self, regexp) - end - - def in(array) - In.new(self, array) - end - end - include Predications - - module Expressions - def count(distinct = false) - distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT") - end - - def sum - Expression.new(self, "SUM") - end - - def maximum - Expression.new(self, "MAX") - end - - def minimum - Expression.new(self, "MIN") - end - - def average - Expression.new(self, "AVG") - end - end - include Expressions - end -end diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb deleted file mode 100644 index 836f0147456ae..0000000000000 --- a/lib/arel/primitives/expression.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Arel - class Expression < Attribute - attributes :attribute, :function_sql, :alias, :ancestor - deriving :== - delegate :relation, :to => :attribute - alias_method :name, :alias - - def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) - @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor - end - - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - - def aggregation? - true - end - - module Transformations - def as(aliaz) - Expression.new(attribute, function_sql, aliaz, self) - end - - def bind(new_relation) - new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) - end - - def to_attribute - Attribute.new(relation, @alias, :ancestor => self) - end - end - include Transformations - end -end diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb deleted file mode 100644 index 9c6e518a95764..0000000000000 --- a/lib/arel/primitives/value.rb +++ /dev/null @@ -1,32 +0,0 @@ -module Arel - class Value - attributes :value, :relation - deriving :initialize, :== - delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value - - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - if value =~ /^\(.*\)$/ - value - else - formatter.value value - end - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - - def bind(relation) - Value.new(value, relation) - end - - def aggregation? - false - end - - def to_attribute - value - end - end -end diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb deleted file mode 100644 index 3394fac7cbcc4..0000000000000 --- a/lib/arel/relations.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'arel/relations/relation' - -require 'arel/relations/utilities' - -require 'arel/relations/table' - -require 'arel/relations/writes' -require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/operations.rb b/lib/arel/relations/operations.rb deleted file mode 100644 index c598c7fcc9ab9..0000000000000 --- a/lib/arel/relations/operations.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'arel/relations/operations/alias' -require 'arel/relations/operations/group' -require 'arel/relations/operations/join' -require 'arel/relations/operations/order' -require 'arel/relations/operations/project' -require 'arel/relations/operations/where' -require 'arel/relations/operations/skip' -require 'arel/relations/operations/take' \ No newline at end of file diff --git a/lib/arel/relations/operations/alias.rb b/lib/arel/relations/operations/alias.rb deleted file mode 100644 index 8ed33fc5978cf..0000000000000 --- a/lib/arel/relations/operations/alias.rb +++ /dev/null @@ -1,8 +0,0 @@ -module Arel - class Alias < Compound - include Recursion::BaseCase - attributes :relation - deriving :initialize - alias_method :==, :equal? - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/group.rb b/lib/arel/relations/operations/group.rb deleted file mode 100644 index 04fd9fea629b1..0000000000000 --- a/lib/arel/relations/operations/group.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Arel - class Group < Compound - attributes :relation, :groupings - deriving :== - - def initialize(relation, *groupings, &block) - @relation = relation - @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) } - end - - def externalizable? - true - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb deleted file mode 100644 index 8fe89358d84f2..0000000000000 --- a/lib/arel/relations/operations/join.rb +++ /dev/null @@ -1,57 +0,0 @@ -module Arel - class Join < Relation - attributes :join_sql, :relation1, :relation2, :predicates - deriving :== - delegate :engine, :name, :to => :relation1 - hash_on :relation1 - - def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates - end - - def table_sql(formatter = Sql::TableReference.new(self)) - relation1.externalize.table_sql(formatter) - end - - def joins(environment, formatter = Sql::TableReference.new(environment)) - @joins ||= begin - this_join = [ - join_sql, - relation2.externalize.table_sql(formatter), - ("ON" unless predicates.blank?), - (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') - ].compact.join(" ") - [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") - end - end - - def attributes - @attributes ||= (relation1.externalize.attributes + - relation2.externalize.attributes).collect { |a| a.bind(self) } - end - - def wheres - # TESTME bind to self? - relation1.externalize.wheres - end - - def ons - @ons ||= @predicates.collect { |p| p.bind(self) } - end - - # TESTME - def externalizable? - relation1.externalizable? or relation2.externalizable? - end - - def join? - true - end - end - - class Relation - def join? - false - end - end -end diff --git a/lib/arel/relations/operations/order.rb b/lib/arel/relations/operations/order.rb deleted file mode 100644 index 05af3fde4d125..0000000000000 --- a/lib/arel/relations/operations/order.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Arel - class Order < Compound - attributes :relation, :orderings - deriving :== - - def initialize(relation, *orderings, &block) - @relation = relation - @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) } - end - - # TESTME - def orders - (orderings + relation.orders).collect { |o| o.bind(self) } - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/relations/operations/project.rb deleted file mode 100644 index 5507ea3163dc8..0000000000000 --- a/lib/arel/relations/operations/project.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Project < Compound - attributes :relation, :projections - deriving :== - - def initialize(relation, *projections, &block) - @relation = relation - @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } - end - - def attributes - @attributes ||= projections.collect { |p| p.bind(self) } - end - - def externalizable? - attributes.any?(&:aggregation?) or relation.externalizable? - end - end -end diff --git a/lib/arel/relations/operations/skip.rb b/lib/arel/relations/operations/skip.rb deleted file mode 100644 index 930e4c94ea372..0000000000000 --- a/lib/arel/relations/operations/skip.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Skip < Compound - attributes :relation, :skipped - deriving :initialize, :== - - def externalizable? - true - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/take.rb b/lib/arel/relations/operations/take.rb deleted file mode 100644 index 2fd3fdf63537c..0000000000000 --- a/lib/arel/relations/operations/take.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Take < Compound - attributes :relation, :taken - deriving :initialize, :== - - def externalizable? - true - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/where.rb b/lib/arel/relations/operations/where.rb deleted file mode 100644 index 608aaeb4b7f7f..0000000000000 --- a/lib/arel/relations/operations/where.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Arel - class Where < Compound - attributes :relation, :predicate - deriving :== - - def initialize(relation, *predicates, &block) - predicate = block_given?? yield(relation) : predicates.shift - @relation = predicates.empty?? relation : Where.new(relation, *predicates) - @predicate = predicate.bind(@relation) - end - - def wheres - @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } - end - end -end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb deleted file mode 100644 index 5d2c336a157c9..0000000000000 --- a/lib/arel/relations/relation.rb +++ /dev/null @@ -1,169 +0,0 @@ -module Arel - class Relation - attr_reader :count - - def session - Session.new - end - - def count - @count = "COUNT(*) AS count_all" - end - - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select select_sql, self - end - alias_method :to_s, :to_sql - - def select_sql - [ - "SELECT #{@count} #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ') unless @count}", - "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), - ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n") - end - - def inclusion_predicate_sql - "IN" - end - - def call(connection = engine) - results = connection.execute(to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash - end - rows - end - - def bind(relation) - self - end - - def root - self - end - - def christener - @christener ||= Sql::Christener.new - end - - module Enumerable - include ::Enumerable - - def each(&block) - session.read(self).each(&block) - end - - def first - session.read(self).first - end - end - include Enumerable - - module Operable - def join(other_relation = nil, join_type = "INNER JOIN") - case other_relation - when String - Join.new(other_relation, self) - when Relation - JoinOperation.new(join_type, self, other_relation) - else - self - end - end - - def outer_join(other_relation = nil) - join(other_relation, "LEFT OUTER JOIN") - end - - [:where, :project, :order, :take, :skip, :group].each do |operation_name| - operation = <<-OPERATION - def #{operation_name}(*arguments, &block) - arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) - end - OPERATION - class_eval operation, __FILE__, __LINE__ - end - - def alias - Alias.new(self) - end - - module Writable - def insert(record) - session.create Insert.new(self, record); self - end - - def update(assignments) - session.update Update.new(self, assignments) - end - - def delete - session.delete Deletion.new(self) - end - end - include Writable - - JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do - def on(*predicates) - Join.new(join_sql, relation1, relation2, *predicates) - end - end - end - include Operable - - module AttributeAccessable - def [](index) - case index - when Symbol, String - find_attribute_matching_name(index) - when Attribute, Expression - find_attribute_matching_attribute(index) - when Array - index.collect { |i| self[i] } - end - end - - def find_attribute_matching_name(name) - attributes.detect { |a| a.named?(name) } - end - - def find_attribute_matching_attribute(attribute) - matching_attributes(attribute).max do |a1, a2| - (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) - end - end - - private - def matching_attributes(attribute) - (@matching_attributes ||= attributes.inject({}) do |hash, a| - (hash[a.root] ||= []) << a - hash - end)[attribute.root] || [] - end - - def has_attribute?(attribute) - !matching_attributes(attribute).empty? - end - end - include AttributeAccessable - - module DefaultOperations - def attributes; [] end - def wheres; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def joins(formatter = nil); nil end - def taken; nil end - def skipped; nil end - end - include DefaultOperations - end -end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb deleted file mode 100644 index 0433abbbb24fb..0000000000000 --- a/lib/arel/relations/table.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Arel - class Table < Relation - include Recursion::BaseCase - - cattr_accessor :engine - attr_reader :name, :engine - hash_on :name - - def initialize(name, engine = Table.engine) - @name, @engine = name.to_s, engine - end - - def attributes - @attributes ||= columns.collect do |column| - Attribute.new(self, column.name.to_sym) - end - end - - def column_for(attribute) - has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } - end - - def columns - @columns ||= engine.columns(name, "#{name} Columns") - end - - def reset - @attributes = @columns = nil - end - - def ==(other) - Table === other and - name == other.name - end - end -end diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb deleted file mode 100644 index 454d455359156..0000000000000 --- a/lib/arel/relations/utilities.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'arel/relations/utilities/compound' -require 'arel/relations/utilities/recursion' -require 'arel/relations/utilities/nil' -require 'arel/relations/utilities/externalization' -require 'arel/relations/utilities/recursion' \ No newline at end of file diff --git a/lib/arel/relations/utilities/compound.rb b/lib/arel/relations/utilities/compound.rb deleted file mode 100644 index b1e8054d4d496..0000000000000 --- a/lib/arel/relations/utilities/compound.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Arel - class Compound < Relation - attr_reader :relation - hash_on :relation - delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :table, :table_sql, - :to => :relation - - [:attributes, :wheres, :groupings, :orders].each do |operation_name| - operation = <<-OPERATION - def #{operation_name} - @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } - end - OPERATION - class_eval operation, __FILE__, __LINE__ - end - end -end diff --git a/lib/arel/relations/utilities/externalization.rb b/lib/arel/relations/utilities/externalization.rb deleted file mode 100644 index 3b9b2296dc2c2..0000000000000 --- a/lib/arel/relations/utilities/externalization.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Arel - class Externalization < Compound - attributes :relation - deriving :initialize, :== - include Recursion::BaseCase - - def wheres - [] - end - - def table_sql(formatter = Sql::TableReference.new(relation)) - formatter.select relation.select_sql, self - end - - def attributes - @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } - end - - # REMOVEME - def name - relation.name + '_external' - end - end - - class Relation - def externalize - @externalized ||= externalizable?? Externalization.new(self) : self - end - - def externalizable? - false - end - end -end diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/relations/utilities/nil.rb deleted file mode 100644 index 56cf395d2c473..0000000000000 --- a/lib/arel/relations/utilities/nil.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'singleton' - -module Arel - class Nil < Relation - include Singleton - - def table_sql(formatter = nil); '' end - def name; '' end - end -end diff --git a/lib/arel/relations/utilities/recursion.rb b/lib/arel/relations/utilities/recursion.rb deleted file mode 100644 index 848b059507b01..0000000000000 --- a/lib/arel/relations/utilities/recursion.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Recursion - module BaseCase - def table - self - end - - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self - end - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/writes.rb b/lib/arel/relations/writes.rb deleted file mode 100644 index 1495d9c8575e0..0000000000000 --- a/lib/arel/relations/writes.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/relations/writes/delete' -require 'arel/relations/writes/update' -require 'arel/relations/writes/insert' \ No newline at end of file diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb deleted file mode 100644 index b1ff3bef278ba..0000000000000 --- a/lib/arel/relations/writes/delete.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Deletion < Compound - attributes :relation - deriving :initialize, :== - - def to_sql(formatter = nil) - [ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") - end - - def call(connection = engine) - connection.delete(to_sql) - end - end -end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb deleted file mode 100644 index d579ad06d0bf5..0000000000000 --- a/lib/arel/relations/writes/insert.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Arel - class Insert < Compound - attributes :relation, :record - deriving :== - - def initialize(relation, record) - @relation, @record = relation, record.bind(relation) - end - - def to_sql(formatter = nil) - [ - "INSERT", - "INTO #{table_sql}", - "(#{record.keys.map { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.map { |key, value| key.format(value) }.join(', ')})" - ].join("\n") - end - - def call(connection = engine) - connection.insert(to_sql) - end - end -end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb deleted file mode 100644 index 52ca6ecf05f46..0000000000000 --- a/lib/arel/relations/writes/update.rb +++ /dev/null @@ -1,30 +0,0 @@ -module Arel - class Update < Compound - attributes :relation, :assignments - deriving :== - - def initialize(relation, assignments) - @relation, @assignments = relation, assignments - end - - def to_sql(formatter = nil) - [ - "UPDATE #{table_sql} SET", - map_assignments, - ("WHERE #{wheres.map(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") - end - - def call(connection = engine) - connection.update(to_sql) - end - - def map_assignments - assignments.collect do |attribute, value| - attribute.respond_to?(:name) ? - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" : attribute - end.join(",\n") - end - end -end diff --git a/lib/arel/session.rb b/lib/arel/session.rb deleted file mode 100644 index d9a6e4b5e4a48..0000000000000 --- a/lib/arel/session.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'singleton' - -module Arel - class Session - class << self - attr_accessor :instance - alias_method :manufacture, :new - - def start - if @started - yield - else - begin - @started = true - @instance = manufacture - metaclass.send :alias_method, :new, :instance - yield - ensure - metaclass.send :alias_method, :new, :manufacture - @started = false - end - end - end - end - - module CRUD - def create(insert) - insert.call(insert.engine) - end - - def read(select) - (@read ||= Hash.new do |hash, select| - hash[select] = select.call(select.engine) - end)[select] - end - - def update(update) - update.call(update.engine) - end - - def delete(delete) - delete.call(delete.engine) - end - end - include CRUD - end -end diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb deleted file mode 100644 index 7e7dd0a80fb93..0000000000000 --- a/lib/arel/sql.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/sql/formatters' -require 'arel/sql/christener' \ No newline at end of file diff --git a/lib/arel/sql/christener.rb b/lib/arel/sql/christener.rb deleted file mode 100644 index 5883a75f41346..0000000000000 --- a/lib/arel/sql/christener.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Sql - class Christener - def name_for(relation) - @used_names ||= Hash.new(0) - (@relation_names ||= Hash.new do |hash, relation| - @used_names[name = relation.name] += 1 - hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') - end)[relation.table] - end - end - end -end \ No newline at end of file diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb deleted file mode 100644 index f82ddf631fef0..0000000000000 --- a/lib/arel/sql/formatters.rb +++ /dev/null @@ -1,121 +0,0 @@ -module Arel - module Sql - class Formatter - attr_reader :environment - delegate :christener, :engine, :to => :environment - delegate :name_for, :to => :christener - delegate :quote_table_name, :quote_column_name, :quote, :to => :engine - - def initialize(environment) - @environment = environment - end - end - - class SelectClause < Formatter - def attribute(attribute) - # FIXME this should check that the column exists - if attribute.name.to_s =~ /^\w*$/ - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - else - attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - end - end - - def expression(expression) - if expression.function_sql == "DISTINCT" - "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') - else - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") - end - end - - def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(name_for(table))}" - end - - def value(value) - value - end - end - - class PassThrough < Formatter - def value(value) - value - end - end - - class WhereClause < PassThrough - end - - class OrderClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - end - - class GroupClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - end - - class WhereCondition < Formatter - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - - def expression(expression) - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" - end - - def value(value) - value.to_sql(self) - end - - def scalar(value, column = nil) - quote(value, column) - end - - def select(select_sql, table) - "(#{select_sql})" - end - end - - class SelectStatement < Formatter - def select(select_sql, table) - select_sql - end - end - - class TableReference < Formatter - def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(name_for(table))}" - end - - def table(table) - if table.name =~ /^(\w|-)*$/ - quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') - else - table.name + (table.name != name_for(table) ? " AS " + (name_for(table)) : '') - end - end - end - - class Attribute < WhereCondition - def scalar(scalar) - quote(scalar, environment.column) - end - - def array(array) - "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" - end - - def range(left, right) - "#{left} AND #{right}" - end - end - - class Value < WhereCondition - end - end -end From 054b0103a8a833e643c954fb31b9a5d88e29968e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 28 May 2009 18:08:48 -0300 Subject: [PATCH 0259/1492] This should be performed by the engine, if it does not exists, then create SQLLiteral not Attribute. --- lib/arel/engines/sql/formatters.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index ae80feb18e9d3..22935ebff1465 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -13,7 +13,6 @@ def initialize(environment) class SelectClause < Formatter def attribute(attribute) - # FIXME this should check that the column exists "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") end From dc09a633c37ca0b214e4d1dd1572cdb9070fc38d Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 28 May 2009 18:24:40 -0300 Subject: [PATCH 0260/1492] Don't quote the table if it isn't a table name. By doing this Arel supports using custom SQL FROM like: edges USE INDEX(unique_edge_index) --- lib/arel/engines/sql/formatters.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 22935ebff1465..626803a887214 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -91,8 +91,12 @@ def select(select_sql, table) end def table(table) - quote_table_name(table.name) + - (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') + if table.name =~ /\s/ + table.name + else + quote_table_name(table.name) + + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') + end end end From c55226bac0cfac67081b01860baa61f3acbb2ca9 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 28 May 2009 18:41:20 -0300 Subject: [PATCH 0261/1492] Allow expressions on literal SQL fragments --- lib/arel/engines/sql/primitives.rb | 4 +++- .../arel/engines/sql/unit/primitives/literal_spec.rb | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index bb3bed78e6075..a08ca11c12063 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -3,10 +3,12 @@ class SqlLiteral < String def relation nil end - + def to_sql(formatter = nil) self end + + include Attribute::Expressions end class Attribute diff --git a/spec/arel/engines/sql/unit/primitives/literal_spec.rb b/spec/arel/engines/sql/unit/primitives/literal_spec.rb index c7ff1cf879a32..ed8bea339baec 100644 --- a/spec/arel/engines/sql/unit/primitives/literal_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/literal_spec.rb @@ -18,6 +18,18 @@ module Arel sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "users"}) end end + + it "manufactures expressions on literal SQL fragment" do + sql = @relation.project(SqlLiteral.new("2 * credit_limit").sum).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM `users`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM "users"}) + end + end end end end From 324f265c1de98212f59f42c287d441b85b2350b7 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 2 Jun 2009 12:33:33 -0300 Subject: [PATCH 0262/1492] Return delete result instead Arel object --- lib/arel/session.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 921ad0a7ac83c..abef5c543b1b6 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -35,12 +35,10 @@ def read(select) def update(update) update.call - update end def delete(delete) delete.call - delete end end include CRUD From 3e6ad6e5838d20c946d7a286cb34be12aae177ff Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 10 Jun 2009 19:53:51 -0300 Subject: [PATCH 0263/1492] Allow strings as update assignments --- lib/arel/engines/sql/relations/writes.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index f1a9bfd2ac561..f7073654e94c3 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -31,9 +31,13 @@ def to_sql(formatter = nil) protected def assignment_sql - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n") + if assignments.respond_to?(:collect) + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n") + else + assignments.value + end end end end From ae0c58fed1cd3aca1edd75a249fa99bc9571a8a3 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 23 Jun 2009 17:18:37 -0300 Subject: [PATCH 0264/1492] Build valid SQL query for SQLite3 and PostgreSQL when updating records with limited conditions --- lib/arel/engines/sql/relations/writes.rb | 20 +++++++++++++++++-- .../engines/sql/unit/relations/update_spec.rb | 18 +++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index f7073654e94c3..471fceabd8a9e 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -24,8 +24,7 @@ def to_sql(formatter = nil) build_query \ "UPDATE #{table_sql} SET", assignment_sql, - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) + build_update_conditions_sql end protected @@ -39,5 +38,22 @@ def assignment_sql assignments.value end end + + def build_update_conditions_sql + conditions = "" + conditions << " WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? + conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? + + unless taken.blank? + conditions << " LIMIT #{taken}" + + if engine.adapter_name != "MySQL" + quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key) + conditions = "WHERE #{quote_primary_key} IN (SELECT #{quote_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" + end + end + + conditions + end end end diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb index 4d728eb241387..4b1d824ce54ff 100644 --- a/spec/arel/engines/sql/unit/relations/update_spec.rb +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -1,5 +1,11 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +class User + def self.primary_key + "id" + end +end + module Arel describe Update do before do @@ -45,17 +51,17 @@ module Arel adapter_is :sqlite3 do sql.should be_like(%Q{ - UPDATE "users" - SET "name" = 'nick' - LIMIT 1 + UPDATE "users" SET + "name" = 'nick' + WHERE "id" IN (SELECT "id" FROM "users" LIMIT 1) }) end adapter_is :postgresql do sql.should be_like(%Q{ - UPDATE "users" - SET "name" = E'nick' - LIMIT 1 + UPDATE "users" SET + "name" = E'nick' + WHERE "id" IN (SELECT "id" FROM "users" LIMIT 1) }) end end From a9486193c8c6250d56bfb0258be50025f7f62f5e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 23 Jun 2009 17:37:10 -0300 Subject: [PATCH 0265/1492] Build valid SQL query when using PostreSQL with given order and DISTINCT ON clause. TODO: refactoring to clean up components. --- lib/arel/engines/sql/relations/relation.rb | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 4cfb83a6017cd..ed7f19ddbd344 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -5,6 +5,26 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) end def select_sql + if engine.adapter_name == "PostgreSQL" && !orders.blank? && using_distinct_on? + # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this + # by wrapping the +sql+ string as a sub-select and ordering in that query. + order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?) + order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') + + query = build_query \ + "SELECT #{select_clauses.to_s}", + "FROM #{table_sql(Sql::TableReference.new(self))}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ) + + build_query \ + "SELECT * FROM (#{query}) AS id_list", + "ORDER BY #{order}", + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) + + else build_query \ "SELECT #{select_clauses.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", @@ -14,6 +34,7 @@ def select_sql ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) + end end def inclusion_predicate_sql @@ -46,5 +67,8 @@ def order_clauses orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } end + def using_distinct_on? + select_clauses.any? { |x| x =~ /DISTINCT ON/ } + end end end From 97811698ab0e68b33fbf3067c3764e385dd75d53 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 23 Jun 2009 19:45:14 -0300 Subject: [PATCH 0266/1492] If the class or method isn't defined use "id" as primary_key. --- lib/arel/engines/sql/relations/writes.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 471fceabd8a9e..b90d380c6467f 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -48,7 +48,12 @@ def build_update_conditions_sql conditions << " LIMIT #{taken}" if engine.adapter_name != "MySQL" - quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key) + begin + quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key) + rescue NameError + quote_primary_key = engine.quote_column_name("id") + end + conditions = "WHERE #{quote_primary_key} IN (SELECT #{quote_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" end end From 808b9e90a38c6c19e109da8eb5f2a264fd780d9a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 1 Jul 2009 20:29:33 -0300 Subject: [PATCH 0267/1492] Allow SQL strings to insert query. Insert should better return engine's result. --- lib/arel/engines/sql/relations/writes.rb | 11 ++++++++--- lib/arel/session.rb | 1 - .../memory/integration/joins/cross_engine_spec.rb | 5 ++--- .../engines/memory/unit/relations/insert_spec.rb | 14 +++++++------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index b90d380c6467f..d648a54d91833 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -11,11 +11,17 @@ def to_sql(formatter = nil) class Insert < Compound def to_sql(formatter = nil) + insertion_attributes_values_sql = if record.is_a?(Value) + record.value + else + build_query "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", + "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + end + build_query \ "INSERT", "INTO #{table_sql}", - "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + insertion_attributes_values_sql end end @@ -28,7 +34,6 @@ def to_sql(formatter = nil) end protected - def assignment_sql if assignments.respond_to?(:collect) assignments.collect do |attribute, value| diff --git a/lib/arel/session.rb b/lib/arel/session.rb index abef5c543b1b6..cf04e8a93a61d 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -24,7 +24,6 @@ def start module CRUD def create(insert) insert.call - insert end def read(select) diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index bffecc918214f..07228bb0f75c8 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -10,9 +10,8 @@ module Arel ], [:id, :name]) @photos = Table.new(:photos) @photos.delete - @photos \ - .insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) \ - .insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) + @photos.insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) + @photos.insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) end describe 'when the in memory relation is on the left' do diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb index 59e43328a32ef..873737e3b5592 100644 --- a/spec/arel/engines/memory/unit/relations/insert_spec.rb +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -14,13 +14,13 @@ module Arel it "manufactures an array of hashes of attributes to values" do @relation \ .insert(@relation[:id] => 4, @relation[:name] => 'guinea fowl') \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - Row.new(relation, [3, 'goose']), - Row.new(relation, [4, 'guinea fowl']) - ] + do |relation| + relation.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + Row.new(relation, [4, 'guinea fowl']) + ] end end end From 53054c0032f46028280cd037ef31744bb54cc15f Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Thu, 6 Aug 2009 18:22:10 -0400 Subject: [PATCH 0268/1492] Adding jeweler for gem management --- .gitignore | 1 + Rakefile | 32 ++- VERSION | 1 + arel.gemspec | 231 ++++++++++++++++++++++ spec/connections/mysql_connection.rb | 1 + spec/connections/postgresql_connection.rb | 1 + spec/connections/sqlite3_connection.rb | 1 + 7 files changed, 262 insertions(+), 6 deletions(-) create mode 100644 VERSION create mode 100644 arel.gemspec diff --git a/.gitignore b/.gitignore index c6dd721751c6c..39cbb3948b811 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ config/database.yml spec/fixtures/*database* *.DS_Store debug.log +pkg diff --git a/Rakefile b/Rakefile index 17a6f8d35d07d..c1ae3fcbbd12a 100644 --- a/Rakefile +++ b/Rakefile @@ -1,13 +1,33 @@ -require 'rubygems' -require 'spec/rake/spectask' +require "rubygems" +require "spec/rake/spectask" -spec_file_list = FileList['spec/**/*_spec.rb'] +$LOAD_PATH.unshift "lib" +require "arel" + +begin + require 'jeweler' + + Jeweler::Tasks.new do |s| + s.name = "arel" + s.authors = ["Bryan Helmkamp", "Nick Kallen"] + s.email = "bryan" + "@" + "brynary.com" + s.homepage = "http://github.com/brynary/arel" + s.summary = "Arel is a relational algebra engine for Ruby" + # s.description = "TODO" + s.rubyforge_project = "arel" + s.extra_rdoc_files = %w(README.markdown) + end + + Jeweler::RubyforgeTasks.new +rescue LoadError + puts "Jeweler not available. Install it with: gem install jeweler" +end desc "Run specs using RCov (uses mysql database adapter)" Spec::Rake::SpecTask.new(:coverage) do |t| t.spec_files = ["spec/connections/mysql_connection.rb"] + - spec_file_list + FileList['spec/**/*_spec.rb'] t.rcov = true t.rcov_opts << '--exclude' << "spec,gems" @@ -23,13 +43,13 @@ namespace :spec do t.spec_files = ["spec/connections/#{adapter}_connection.rb"] + ["spec/schemas/#{adapter}_schema.rb"] + - spec_file_list + FileList['spec/**/*_spec.rb'] end end end desc "Run specs with mysql and sqlite3 database adapters (default)" -task :spec => ["spec:sqlite3", "spec:mysql", "spec:postgresql"] +task :spec => ["check_dependencies", "spec:sqlite3", "spec:mysql", "spec:postgresql"] desc "Default task is to run specs" task :default => :spec diff --git a/VERSION b/VERSION new file mode 100644 index 0000000000000..6c6aa7cb0918d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file diff --git a/arel.gemspec b/arel.gemspec new file mode 100644 index 0000000000000..76b98c79f0104 --- /dev/null +++ b/arel.gemspec @@ -0,0 +1,231 @@ +# Generated by jeweler +# DO NOT EDIT THIS FILE +# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec` +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = %q{arel} + s.version = "0.1.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Bryan Helmkamp", "Nick Kallen"] + s.date = %q{2009-08-06} + s.email = %q{bryan@brynary.com} + s.extra_rdoc_files = [ + "README.markdown" + ] + s.files = [ + ".gitignore", + "README.markdown", + "Rakefile", + "doc/CONVENTIONS", + "doc/TODO", + "lib/arel.rb", + "lib/arel/.DS_Store", + "lib/arel/algebra.rb", + "lib/arel/algebra/extensions.rb", + "lib/arel/algebra/extensions/class.rb", + "lib/arel/algebra/extensions/hash.rb", + "lib/arel/algebra/extensions/object.rb", + "lib/arel/algebra/extensions/symbol.rb", + "lib/arel/algebra/predicates.rb", + "lib/arel/algebra/primitives.rb", + "lib/arel/algebra/primitives/attribute.rb", + "lib/arel/algebra/primitives/expression.rb", + "lib/arel/algebra/primitives/ordering.rb", + "lib/arel/algebra/primitives/value.rb", + "lib/arel/algebra/relations.rb", + "lib/arel/algebra/relations/operations/alias.rb", + "lib/arel/algebra/relations/operations/group.rb", + "lib/arel/algebra/relations/operations/join.rb", + "lib/arel/algebra/relations/operations/order.rb", + "lib/arel/algebra/relations/operations/project.rb", + "lib/arel/algebra/relations/operations/skip.rb", + "lib/arel/algebra/relations/operations/take.rb", + "lib/arel/algebra/relations/operations/where.rb", + "lib/arel/algebra/relations/relation.rb", + "lib/arel/algebra/relations/row.rb", + "lib/arel/algebra/relations/utilities/compound.rb", + "lib/arel/algebra/relations/utilities/externalization.rb", + "lib/arel/algebra/relations/utilities/nil.rb", + "lib/arel/algebra/relations/writes.rb", + "lib/arel/engines.rb", + "lib/arel/engines/memory.rb", + "lib/arel/engines/memory/engine.rb", + "lib/arel/engines/memory/predicates.rb", + "lib/arel/engines/memory/primitives.rb", + "lib/arel/engines/memory/relations.rb", + "lib/arel/engines/memory/relations/array.rb", + "lib/arel/engines/memory/relations/compound.rb", + "lib/arel/engines/memory/relations/operations.rb", + "lib/arel/engines/memory/relations/writes.rb", + "lib/arel/engines/sql.rb", + "lib/arel/engines/sql/christener.rb", + "lib/arel/engines/sql/engine.rb", + "lib/arel/engines/sql/extensions.rb", + "lib/arel/engines/sql/extensions/array.rb", + "lib/arel/engines/sql/extensions/nil_class.rb", + "lib/arel/engines/sql/extensions/object.rb", + "lib/arel/engines/sql/extensions/range.rb", + "lib/arel/engines/sql/formatters.rb", + "lib/arel/engines/sql/predicates.rb", + "lib/arel/engines/sql/primitives.rb", + "lib/arel/engines/sql/relations.rb", + "lib/arel/engines/sql/relations/operations/alias.rb", + "lib/arel/engines/sql/relations/operations/join.rb", + "lib/arel/engines/sql/relations/relation.rb", + "lib/arel/engines/sql/relations/table.rb", + "lib/arel/engines/sql/relations/utilities/compound.rb", + "lib/arel/engines/sql/relations/utilities/externalization.rb", + "lib/arel/engines/sql/relations/utilities/nil.rb", + "lib/arel/engines/sql/relations/utilities/recursion.rb", + "lib/arel/engines/sql/relations/writes.rb", + "lib/arel/session.rb", + "spec/arel/algebra/unit/predicates/binary_spec.rb", + "spec/arel/algebra/unit/predicates/equality_spec.rb", + "spec/arel/algebra/unit/predicates/in_spec.rb", + "spec/arel/algebra/unit/primitives/attribute_spec.rb", + "spec/arel/algebra/unit/primitives/expression_spec.rb", + "spec/arel/algebra/unit/primitives/value_spec.rb", + "spec/arel/algebra/unit/relations/alias_spec.rb", + "spec/arel/algebra/unit/relations/delete_spec.rb", + "spec/arel/algebra/unit/relations/group_spec.rb", + "spec/arel/algebra/unit/relations/insert_spec.rb", + "spec/arel/algebra/unit/relations/join_spec.rb", + "spec/arel/algebra/unit/relations/order_spec.rb", + "spec/arel/algebra/unit/relations/project_spec.rb", + "spec/arel/algebra/unit/relations/relation_spec.rb", + "spec/arel/algebra/unit/relations/skip_spec.rb", + "spec/arel/algebra/unit/relations/table_spec.rb", + "spec/arel/algebra/unit/relations/take_spec.rb", + "spec/arel/algebra/unit/relations/update_spec.rb", + "spec/arel/algebra/unit/relations/where_spec.rb", + "spec/arel/algebra/unit/session/session_spec.rb", + "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", + "spec/arel/engines/memory/unit/relations/array_spec.rb", + "spec/arel/engines/memory/unit/relations/insert_spec.rb", + "spec/arel/engines/memory/unit/relations/join_spec.rb", + "spec/arel/engines/memory/unit/relations/order_spec.rb", + "spec/arel/engines/memory/unit/relations/project_spec.rb", + "spec/arel/engines/memory/unit/relations/skip_spec.rb", + "spec/arel/engines/memory/unit/relations/take_spec.rb", + "spec/arel/engines/memory/unit/relations/where_spec.rb", + "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", + "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", + "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", + "spec/arel/engines/sql/unit/engine_spec.rb", + "spec/arel/engines/sql/unit/predicates/binary_spec.rb", + "spec/arel/engines/sql/unit/predicates/equality_spec.rb", + "spec/arel/engines/sql/unit/predicates/in_spec.rb", + "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", + "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", + "spec/arel/engines/sql/unit/primitives/expression_spec.rb", + "spec/arel/engines/sql/unit/primitives/literal_spec.rb", + "spec/arel/engines/sql/unit/primitives/value_spec.rb", + "spec/arel/engines/sql/unit/relations/alias_spec.rb", + "spec/arel/engines/sql/unit/relations/delete_spec.rb", + "spec/arel/engines/sql/unit/relations/group_spec.rb", + "spec/arel/engines/sql/unit/relations/insert_spec.rb", + "spec/arel/engines/sql/unit/relations/join_spec.rb", + "spec/arel/engines/sql/unit/relations/order_spec.rb", + "spec/arel/engines/sql/unit/relations/project_spec.rb", + "spec/arel/engines/sql/unit/relations/skip_spec.rb", + "spec/arel/engines/sql/unit/relations/table_spec.rb", + "spec/arel/engines/sql/unit/relations/take_spec.rb", + "spec/arel/engines/sql/unit/relations/update_spec.rb", + "spec/arel/engines/sql/unit/relations/where_spec.rb", + "spec/connections/mysql_connection.rb", + "spec/connections/postgresql_connection.rb", + "spec/connections/sqlite3_connection.rb", + "spec/doubles/hash.rb", + "spec/matchers/be_like.rb", + "spec/matchers/disambiguate_attributes.rb", + "spec/matchers/hash_the_same_as.rb", + "spec/schemas/mysql_schema.rb", + "spec/schemas/postgresql_schema.rb", + "spec/schemas/sqlite3_schema.rb", + "spec/spec_helper.rb" + ] + s.homepage = %q{http://github.com/brynary/arel} + s.rdoc_options = ["--charset=UTF-8"] + s.require_paths = ["lib"] + s.rubyforge_project = %q{arel} + s.rubygems_version = %q{1.3.4} + s.summary = %q{Arel is a relational algebra engine for Ruby} + s.test_files = [ + "spec/arel/algebra/unit/predicates/binary_spec.rb", + "spec/arel/algebra/unit/predicates/equality_spec.rb", + "spec/arel/algebra/unit/predicates/in_spec.rb", + "spec/arel/algebra/unit/primitives/attribute_spec.rb", + "spec/arel/algebra/unit/primitives/expression_spec.rb", + "spec/arel/algebra/unit/primitives/value_spec.rb", + "spec/arel/algebra/unit/relations/alias_spec.rb", + "spec/arel/algebra/unit/relations/delete_spec.rb", + "spec/arel/algebra/unit/relations/group_spec.rb", + "spec/arel/algebra/unit/relations/insert_spec.rb", + "spec/arel/algebra/unit/relations/join_spec.rb", + "spec/arel/algebra/unit/relations/order_spec.rb", + "spec/arel/algebra/unit/relations/project_spec.rb", + "spec/arel/algebra/unit/relations/relation_spec.rb", + "spec/arel/algebra/unit/relations/skip_spec.rb", + "spec/arel/algebra/unit/relations/table_spec.rb", + "spec/arel/algebra/unit/relations/take_spec.rb", + "spec/arel/algebra/unit/relations/update_spec.rb", + "spec/arel/algebra/unit/relations/where_spec.rb", + "spec/arel/algebra/unit/session/session_spec.rb", + "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", + "spec/arel/engines/memory/unit/relations/array_spec.rb", + "spec/arel/engines/memory/unit/relations/insert_spec.rb", + "spec/arel/engines/memory/unit/relations/join_spec.rb", + "spec/arel/engines/memory/unit/relations/order_spec.rb", + "spec/arel/engines/memory/unit/relations/project_spec.rb", + "spec/arel/engines/memory/unit/relations/skip_spec.rb", + "spec/arel/engines/memory/unit/relations/take_spec.rb", + "spec/arel/engines/memory/unit/relations/where_spec.rb", + "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", + "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", + "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", + "spec/arel/engines/sql/unit/engine_spec.rb", + "spec/arel/engines/sql/unit/predicates/binary_spec.rb", + "spec/arel/engines/sql/unit/predicates/equality_spec.rb", + "spec/arel/engines/sql/unit/predicates/in_spec.rb", + "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", + "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", + "spec/arel/engines/sql/unit/primitives/expression_spec.rb", + "spec/arel/engines/sql/unit/primitives/literal_spec.rb", + "spec/arel/engines/sql/unit/primitives/value_spec.rb", + "spec/arel/engines/sql/unit/relations/alias_spec.rb", + "spec/arel/engines/sql/unit/relations/delete_spec.rb", + "spec/arel/engines/sql/unit/relations/group_spec.rb", + "spec/arel/engines/sql/unit/relations/insert_spec.rb", + "spec/arel/engines/sql/unit/relations/join_spec.rb", + "spec/arel/engines/sql/unit/relations/order_spec.rb", + "spec/arel/engines/sql/unit/relations/project_spec.rb", + "spec/arel/engines/sql/unit/relations/skip_spec.rb", + "spec/arel/engines/sql/unit/relations/table_spec.rb", + "spec/arel/engines/sql/unit/relations/take_spec.rb", + "spec/arel/engines/sql/unit/relations/update_spec.rb", + "spec/arel/engines/sql/unit/relations/where_spec.rb", + "spec/connections/mysql_connection.rb", + "spec/connections/postgresql_connection.rb", + "spec/connections/sqlite3_connection.rb", + "spec/doubles/hash.rb", + "spec/matchers/be_like.rb", + "spec/matchers/disambiguate_attributes.rb", + "spec/matchers/hash_the_same_as.rb", + "spec/schemas/mysql_schema.rb", + "spec/schemas/postgresql_schema.rb", + "spec/schemas/sqlite3_schema.rb", + "spec/spec_helper.rb" + ] + + if s.respond_to? :specification_version then + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION + s.specification_version = 3 + + if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + else + end + else + end +end diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index a58ddc35efd5e..6e2950f7dc677 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -1,3 +1,4 @@ +require "rubygems" require "activerecord" puts "Using native MySQL" diff --git a/spec/connections/postgresql_connection.rb b/spec/connections/postgresql_connection.rb index e376d33ec647d..01d65f09dccd9 100644 --- a/spec/connections/postgresql_connection.rb +++ b/spec/connections/postgresql_connection.rb @@ -1,3 +1,4 @@ +require "rubygems" require "activerecord" puts "Using native PostgreSQL" diff --git a/spec/connections/sqlite3_connection.rb b/spec/connections/sqlite3_connection.rb index 649492f804e08..9e9503e0caeca 100644 --- a/spec/connections/sqlite3_connection.rb +++ b/spec/connections/sqlite3_connection.rb @@ -1,3 +1,4 @@ +require "rubygems" require "activerecord" puts "Using native SQLite3" From 019f35a266c8e27e6dcf443b3c4d92648b96ce89 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Thu, 6 Aug 2009 18:22:24 -0400 Subject: [PATCH 0269/1492] Regenerated gemspec for version 0.1.0 --- arel.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arel.gemspec b/arel.gemspec index 76b98c79f0104..003a38073ad1a 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -18,6 +18,8 @@ Gem::Specification.new do |s| ".gitignore", "README.markdown", "Rakefile", + "VERSION", + "arel.gemspec", "doc/CONVENTIONS", "doc/TODO", "lib/arel.rb", From 724b48620c5cf21920717d66eea6e7cd4148b535 Mon Sep 17 00:00:00 2001 From: Lee Bankewitz Date: Mon, 10 Aug 2009 14:51:54 -0400 Subject: [PATCH 0270/1492] Bug fix: Don't use #delegate to declare delegations when intentionally delegating to nil This accounts for a behavior change after Rails 2.3 --- lib/arel/engines/sql/primitives.rb | 10 ++++++++-- .../engines/sql/unit/predicates/equality_spec.rb | 15 +++++++++++++++ spec/connections/mysql_connection.rb | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index bb3bed78e6075..16e1abdf59ddc 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -3,7 +3,7 @@ class SqlLiteral < String def relation nil end - + def to_sql(formatter = nil) self end @@ -28,7 +28,13 @@ def to_sql(formatter = Sql::WhereCondition.new(relation)) end class Value - delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value + def inclusion_predicate_sql + value.inclusion_predicate_sql + end + + def equality_predicate_sql + value.equality_predicate_sql + end def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index 688a6a20beeb5..e874d07bf392f 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -41,6 +41,21 @@ module Arel end end end + + describe "when relating to a nil Value" do + it "manufactures an IS NULL predicate" do + value = nil.bind(@relation1) + sql = Equality.new(@attribute1, value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NULL}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IS NULL}) + end + end + end end end end diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index 6e2950f7dc677..bcba2b3843b51 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -7,7 +7,7 @@ ActiveRecord::Base.configurations = { 'unit' => { :adapter => 'mysql', - :username => 'rails', + :username => 'root', :encoding => 'utf8', :database => 'arel_unit', } From 5dcbca25cef8e8f5809913977cfeb4366c8b44d0 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 14 Aug 2009 10:49:15 -0300 Subject: [PATCH 0271/1492] Allow joining a StringJoin with another join relation. --- lib/arel/engines/sql/relations/operations/join.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index 7c5e13510a23b..a3aaaa163ba1e 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -26,8 +26,8 @@ def join_sql; "LEFT OUTER JOIN" end end class StringJoin < Join - def joins(_, __ = nil) - relation2 + def joins(environment, formatter = Sql::TableReference.new(environment)) + [relation1.joins(environment), relation2].compact.join(" ") end end end From 3d747a56b76ae97645dd265cc75e73e5f7827193 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 14 Aug 2009 10:49:50 -0300 Subject: [PATCH 0272/1492] Accept Arel::Value in hash values and treat them properly. --- lib/arel/algebra/relations/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9fdac265288a0..5403e40faeca1 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -110,7 +110,7 @@ def position_of(attribute) private def matching_attributes(attribute) (@matching_attributes ||= attributes.inject({}) do |hash, a| - (hash[a.root] ||= []) << a + (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a hash end)[attribute.root] || [] end From 755a7ced2f98b0bb246089c80cdfa04cd918fa89 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 23 Aug 2009 17:24:59 -0300 Subject: [PATCH 0273/1492] REAME updated: remove whitespaces, fix invalid join in query output. --- README.markdown | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/README.markdown b/README.markdown index 4d95234423454..20d6e62b448b0 100644 --- a/README.markdown +++ b/README.markdown @@ -15,20 +15,20 @@ The long term goal, following both LINQ and DataMapper, is to have Arel adapt to 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 = Table(:users) users.to_sql - + In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: users.each { |user| ... } - + In other words, Arel relations implement Ruby's Enumerable interface. Let's have a look at a concrete example: users.first # => { users[:id] => 1, users[:name] => 'bob' } - + As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). ### More Sophisticated Queries Relations ### @@ -43,7 +43,7 @@ First is the 'restriction' operator, `where`: 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])) @@ -53,7 +53,7 @@ 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.group(users[:name]) # => SELECT * FROM users GROUP BY name @@ -68,7 +68,7 @@ The best property of the Relational Algebra is its "composability", or closure u 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)) @@ -76,7 +76,7 @@ Of course, many of the operators take multiple arguments, so the last example ca The `OR` operator is not yet supported. It will work like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) - + The `AND` operator will behave similarly. Finally, most operations take a block form. For example: @@ -96,7 +96,7 @@ The examples above are fairly simple and other libraries match or come close to 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 = Table(:comments) - + And this table has the following attributes: comments.attributes # => [comments[:id], comments[:body], comments[:parent_id]] @@ -107,23 +107,23 @@ The `parent_id` column is a foreign key from the `comments` table to itself. Now 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 - + The call to `#alias` is actually optional: Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Explicit aliasing is more common, however. When you want to extract specific slices of data, aliased tables are a necessity. For example to get just certain columns from the row, treat a row like a hash: comments_with_replies.first[replies[:body]] - + This will return the first comment's reply's body. If you don't need to extract the data later (for example, you're simply doing a join to find comments that have replies, you don't care what the content of the replies are), the block form may be preferable: comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id - + Note that you do NOT want to do something like: comments.join(comments, comments[:parent_id].eq(comments[:id])) # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id - + This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous. #### Complex Aggregations #### @@ -135,24 +135,24 @@ The easiest way to introduce this is in SQL. Your task is to get all users and t SELECT count(*) FROM photos GROUP BY user_id - + Now, we'd like to join this with the user table. Naively, you might try to do this: SELECT users.*, count(photos.id) FROM users LEFT OUTER JOIN photos - ON users.id = photos.id + ON users.id = photos.user_id GROUP BY photos.user_id - + Of course, this has a slightly different meaning than our intended query. This is actually a fairly advanced topic in SQL so let's see why this doesn't work *step by step*. Suppose we have these records in our `users` table: mysql> select * from users; +------+--------+ | id | name | +------+--------+ - | 1 | hai | - | 2 | bai | - | 3 | dumpty | + | 1 | hai | + | 2 | bai | + | 3 | dumpty | +------+--------+ And these in the photos table: @@ -161,19 +161,19 @@ And these in the photos table: +------+---------+-----------+ | id | user_id | camera_id | +------+---------+-----------+ - | 1 | 1 | 1 | - | 2 | 1 | 1 | - | 3 | 1 | 1 | + | 1 | 1 | 1 | + | 2 | 1 | 1 | + | 3 | 1 | 1 | +------+---------+-----------+ - + If we perform the above, incorrect query, we get the following: mysql> select users.*, count(photos.id) from users left outer join photos on users.id = photos.user_id limit 3 group by user_id; +------+------+------------------+ | id | name | count(photos.id) | +------+------+------------------+ - | 2 | bai | 0 | - | 1 | hai | 3 | + | 2 | bai | 0 | + | 1 | hai | 3 | +------+------+------------------+ As you can see, we're completely missing data for user with id 3. `dumpty` has no photos, neither does `bai`. But strangely `bai` appeared and `dumpty` didn't! The reason is that the `GROUP BY` clause is aggregating on both tables, not just the `photos` table. All users without photos have a `photos.id` of `null` (thanks to the left outer join). These are rolled up together and an arbitrary user wins. In this case, `bai` not `dumpty`. @@ -181,4 +181,4 @@ As you can see, we're completely missing data for user with id 3. `dumpty` has n SELECT users.*, photos_aggregation.cnt FROM users LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation - ON photos_aggregation.user_id = users.id \ No newline at end of file + ON photos_aggregation.user_id = users.id From 32af162414f2e092afa004b74a0be64fa53e7834 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 14 Sep 2009 02:50:12 -0700 Subject: [PATCH 0274/1492] Require active_support and active_record by name in LOAD_PATH instead of gem name (deprecated) --- lib/arel.rb | 4 ++-- spec/connections/mysql_connection.rb | 3 ++- spec/connections/postgresql_connection.rb | 3 ++- spec/connections/sqlite3_connection.rb | 5 +++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index 54a31b6ed0dde..b67186a308f97 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,11 +1,11 @@ $LOAD_PATH.unshift(File.dirname(__FILE__)) require 'rubygems' -require 'activesupport' +require 'active_support' require 'active_support/dependencies' require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/module/delegation' -require 'activerecord' +require 'active_record' require 'active_record/connection_adapters/abstract/quoting' require 'arel/algebra' diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index a58ddc35efd5e..dbece8646f12d 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -1,5 +1,6 @@ -require "activerecord" puts "Using native MySQL" +require "active_record" +require 'logger' ActiveRecord::Base.logger = Logger.new("debug.log") diff --git a/spec/connections/postgresql_connection.rb b/spec/connections/postgresql_connection.rb index e376d33ec647d..0fb6dfe065282 100644 --- a/spec/connections/postgresql_connection.rb +++ b/spec/connections/postgresql_connection.rb @@ -1,5 +1,6 @@ -require "activerecord" puts "Using native PostgreSQL" +require "active_record" +require 'logger' ActiveRecord::Base.logger = Logger.new("debug.log") diff --git a/spec/connections/sqlite3_connection.rb b/spec/connections/sqlite3_connection.rb index 9e9503e0caeca..e8eeee17d0801 100644 --- a/spec/connections/sqlite3_connection.rb +++ b/spec/connections/sqlite3_connection.rb @@ -1,6 +1,6 @@ -require "rubygems" -require "activerecord" puts "Using native SQLite3" +require "active_record" +require 'logger' ActiveRecord::Base.logger = Logger.new("debug.log") @@ -16,6 +16,7 @@ unless File.exist?(db_file) puts "SQLite3 database not found at #{db_file}. Rebuilding it." + require 'fileutils' FileUtils.mkdir_p(File.dirname(db_file)) sqlite_command = %Q{sqlite3 "#{db_file}" "create table a (a integer); drop table a;"} puts "Executing '#{sqlite_command}'" From a727cef713c75875941f56fc1e3779216c93d539 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 14 Sep 2009 03:12:54 -0700 Subject: [PATCH 0275/1492] Remove explicit rubygems require. Use Active Support provided by Active Record. Add self to load path after requiring Active Record. --- lib/arel.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index b67186a308f97..c5fa5ba9030d5 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,13 +1,7 @@ -$LOAD_PATH.unshift(File.dirname(__FILE__)) - -require 'rubygems' -require 'active_support' -require 'active_support/dependencies' -require 'active_support/core_ext/class/attribute_accessors' -require 'active_support/core_ext/module/delegation' require 'active_record' require 'active_record/connection_adapters/abstract/quoting' +$LOAD_PATH.unshift(File.dirname(__FILE__)) require 'arel/algebra' require 'arel/engines' require 'arel/session' From bad67f8a4a480a41adb9541ddc11d1dce08990f4 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 14 Sep 2009 03:14:53 -0700 Subject: [PATCH 0276/1492] Submodule rails master rather than rely on gems --- .gitmodules | 3 +++ Rakefile | 1 + vendor/rails | 1 + 3 files changed, 5 insertions(+) create mode 100644 .gitmodules create mode 160000 vendor/rails diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000..5f43dd3ae55a2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/rails"] + path = vendor/rails + url = git://github.com/rails/rails.git diff --git a/Rakefile b/Rakefile index 17a6f8d35d07d..cc5249c2c530b 100644 --- a/Rakefile +++ b/Rakefile @@ -20,6 +20,7 @@ namespace :spec do for adapter in %w[mysql sqlite3 postgresql] desc "Run specs with the #{adapter} database adapter" Spec::Rake::SpecTask.new(adapter) do |t| + t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" t.spec_files = ["spec/connections/#{adapter}_connection.rb"] + ["spec/schemas/#{adapter}_schema.rb"] + diff --git a/vendor/rails b/vendor/rails new file mode 160000 index 0000000000000..181cd109d9812 --- /dev/null +++ b/vendor/rails @@ -0,0 +1 @@ +Subproject commit 181cd109d9812d371e2d554a4846f0b2b25b1690 From 7a7ee72ec1cb5a0b31d0ed9cd5c58a018876b65d Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 14 Sep 2009 03:21:24 -0700 Subject: [PATCH 0277/1492] Use load path rather than relative path for spec_helper requires. Also fixes specs on Ruby 1.9 since . is no longer in the load path. --- Rakefile | 1 + spec/arel/algebra/unit/predicates/binary_spec.rb | 2 +- spec/arel/algebra/unit/predicates/equality_spec.rb | 2 +- spec/arel/algebra/unit/predicates/in_spec.rb | 2 +- spec/arel/algebra/unit/primitives/attribute_spec.rb | 2 +- spec/arel/algebra/unit/primitives/expression_spec.rb | 2 +- spec/arel/algebra/unit/primitives/value_spec.rb | 2 +- spec/arel/algebra/unit/relations/alias_spec.rb | 2 +- spec/arel/algebra/unit/relations/delete_spec.rb | 2 +- spec/arel/algebra/unit/relations/group_spec.rb | 2 +- spec/arel/algebra/unit/relations/insert_spec.rb | 2 +- spec/arel/algebra/unit/relations/join_spec.rb | 2 +- spec/arel/algebra/unit/relations/order_spec.rb | 2 +- spec/arel/algebra/unit/relations/project_spec.rb | 2 +- spec/arel/algebra/unit/relations/relation_spec.rb | 2 +- spec/arel/algebra/unit/relations/skip_spec.rb | 2 +- spec/arel/algebra/unit/relations/table_spec.rb | 2 +- spec/arel/algebra/unit/relations/take_spec.rb | 2 +- spec/arel/algebra/unit/relations/update_spec.rb | 2 +- spec/arel/algebra/unit/relations/where_spec.rb | 2 +- spec/arel/algebra/unit/session/session_spec.rb | 2 +- spec/arel/engines/memory/integration/joins/cross_engine_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/array_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/insert_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/join_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/order_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/project_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/skip_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/take_spec.rb | 2 +- spec/arel/engines/memory/unit/relations/where_spec.rb | 2 +- spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb | 2 +- .../engines/sql/integration/joins/with_aggregations_spec.rb | 2 +- spec/arel/engines/sql/integration/joins/with_compounds_spec.rb | 2 +- spec/arel/engines/sql/unit/engine_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/binary_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/equality_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/in_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/predicates_spec.rb | 2 +- spec/arel/engines/sql/unit/primitives/attribute_spec.rb | 2 +- spec/arel/engines/sql/unit/primitives/expression_spec.rb | 2 +- spec/arel/engines/sql/unit/primitives/literal_spec.rb | 2 +- spec/arel/engines/sql/unit/primitives/value_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/alias_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/delete_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/group_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/insert_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/join_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/order_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/project_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/skip_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/table_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/take_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/update_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/where_spec.rb | 2 +- 54 files changed, 54 insertions(+), 53 deletions(-) diff --git a/Rakefile b/Rakefile index cc5249c2c530b..47474e4b7ba7e 100644 --- a/Rakefile +++ b/Rakefile @@ -21,6 +21,7 @@ namespace :spec do desc "Run specs with the #{adapter} database adapter" Spec::Rake::SpecTask.new(adapter) do |t| t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" + t.libs << "#{File.dirname(__FILE__)}/spec" t.spec_files = ["spec/connections/#{adapter}_connection.rb"] + ["spec/schemas/#{adapter}_schema.rb"] + diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb index 14fd7ab21b2fb..97ef098e0e86e 100644 --- a/spec/arel/algebra/unit/predicates/binary_spec.rb +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Binary do diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb index af91f8b51bcda..c91752015866b 100644 --- a/spec/arel/algebra/unit/predicates/equality_spec.rb +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Equality do diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/arel/algebra/unit/predicates/in_spec.rb index a8a15ce4e38bf..54a6d6c7da459 100644 --- a/spec/arel/algebra/unit/predicates/in_spec.rb +++ b/spec/arel/algebra/unit/predicates/in_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe In do diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index 2ca63ba48eddb..cd484007e1aa2 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Attribute do diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index 768bb492a768a..ac932ed13989a 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Expression do diff --git a/spec/arel/algebra/unit/primitives/value_spec.rb b/spec/arel/algebra/unit/primitives/value_spec.rb index 45208e6c5df03..8fed752d664b6 100644 --- a/spec/arel/algebra/unit/primitives/value_spec.rb +++ b/spec/arel/algebra/unit/primitives/value_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Value do diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/arel/algebra/unit/relations/alias_spec.rb index a5d716a638797..2aa4d52d99855 100644 --- a/spec/arel/algebra/unit/relations/alias_spec.rb +++ b/spec/arel/algebra/unit/relations/alias_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Alias do diff --git a/spec/arel/algebra/unit/relations/delete_spec.rb b/spec/arel/algebra/unit/relations/delete_spec.rb index 7578e12a3ee84..c244be863151a 100644 --- a/spec/arel/algebra/unit/relations/delete_spec.rb +++ b/spec/arel/algebra/unit/relations/delete_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Deletion do diff --git a/spec/arel/algebra/unit/relations/group_spec.rb b/spec/arel/algebra/unit/relations/group_spec.rb index 58f9252356302..48fc818682579 100644 --- a/spec/arel/algebra/unit/relations/group_spec.rb +++ b/spec/arel/algebra/unit/relations/group_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Group do diff --git a/spec/arel/algebra/unit/relations/insert_spec.rb b/spec/arel/algebra/unit/relations/insert_spec.rb index feb1a5eae40a4..3141fa2fc4e5c 100644 --- a/spec/arel/algebra/unit/relations/insert_spec.rb +++ b/spec/arel/algebra/unit/relations/insert_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Insert do diff --git a/spec/arel/algebra/unit/relations/join_spec.rb b/spec/arel/algebra/unit/relations/join_spec.rb index f5a8bd32aa4af..9c1422c57182e 100644 --- a/spec/arel/algebra/unit/relations/join_spec.rb +++ b/spec/arel/algebra/unit/relations/join_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb index 8b3c932fb9c7c..419090102431e 100644 --- a/spec/arel/algebra/unit/relations/order_spec.rb +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Order do diff --git a/spec/arel/algebra/unit/relations/project_spec.rb b/spec/arel/algebra/unit/relations/project_spec.rb index 9f4358ea54960..8886e65a2eee5 100644 --- a/spec/arel/algebra/unit/relations/project_spec.rb +++ b/spec/arel/algebra/unit/relations/project_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Project do diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index adf82847ac5a8..0a08deffb874a 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Relation do diff --git a/spec/arel/algebra/unit/relations/skip_spec.rb b/spec/arel/algebra/unit/relations/skip_spec.rb index a41913436e0e5..e7dea6c1cf45b 100644 --- a/spec/arel/algebra/unit/relations/skip_spec.rb +++ b/spec/arel/algebra/unit/relations/skip_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Skip do diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb index dfe457043caad..e4c4e58b75381 100644 --- a/spec/arel/algebra/unit/relations/table_spec.rb +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Table do diff --git a/spec/arel/algebra/unit/relations/take_spec.rb b/spec/arel/algebra/unit/relations/take_spec.rb index 2bc17db5a1607..3ad8d269f15f5 100644 --- a/spec/arel/algebra/unit/relations/take_spec.rb +++ b/spec/arel/algebra/unit/relations/take_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Take do diff --git a/spec/arel/algebra/unit/relations/update_spec.rb b/spec/arel/algebra/unit/relations/update_spec.rb index e9642ffc99acc..9ed20a446b904 100644 --- a/spec/arel/algebra/unit/relations/update_spec.rb +++ b/spec/arel/algebra/unit/relations/update_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Update do diff --git a/spec/arel/algebra/unit/relations/where_spec.rb b/spec/arel/algebra/unit/relations/where_spec.rb index 6c3074a3a55bd..96b95b58238c5 100644 --- a/spec/arel/algebra/unit/relations/where_spec.rb +++ b/spec/arel/algebra/unit/relations/where_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Where do diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/arel/algebra/unit/session/session_spec.rb index ca0a43f278b95..03aab6a03fbad 100644 --- a/spec/arel/algebra/unit/session/session_spec.rb +++ b/spec/arel/algebra/unit/session/session_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Session do diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index 07228bb0f75c8..db754d9cec57c 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index dd9da41569b8b..9a834148b1596 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Array do diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb index 873737e3b5592..222e525c7bd0d 100644 --- a/spec/arel/engines/memory/unit/relations/insert_spec.rb +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Insert do diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb index 110fdb03b7cb9..112434ae1d008 100644 --- a/spec/arel/engines/memory/unit/relations/join_spec.rb +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/arel/engines/memory/unit/relations/order_spec.rb index 1e9690bbbf42f..21d77a2a24829 100644 --- a/spec/arel/engines/memory/unit/relations/order_spec.rb +++ b/spec/arel/engines/memory/unit/relations/order_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Order do diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/arel/engines/memory/unit/relations/project_spec.rb index 169091002687e..e688b93a392c5 100644 --- a/spec/arel/engines/memory/unit/relations/project_spec.rb +++ b/spec/arel/engines/memory/unit/relations/project_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Project do diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/arel/engines/memory/unit/relations/skip_spec.rb index 3411c5493b916..0c2077db80a9b 100644 --- a/spec/arel/engines/memory/unit/relations/skip_spec.rb +++ b/spec/arel/engines/memory/unit/relations/skip_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Skip do diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/arel/engines/memory/unit/relations/take_spec.rb index 5e7c4fb46276b..4b08a63d227a1 100644 --- a/spec/arel/engines/memory/unit/relations/take_spec.rb +++ b/spec/arel/engines/memory/unit/relations/take_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Take do diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/arel/engines/memory/unit/relations/where_spec.rb index 1d2c2eb39c666..8d0af4b52deb1 100644 --- a/spec/arel/engines/memory/unit/relations/where_spec.rb +++ b/spec/arel/engines/memory/unit/relations/where_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Where do diff --git a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb index 50b090844155b..37afb1a8f2728 100644 --- a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb index 709ae9f8d1973..5ed530508ad58 100644 --- a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb index 4bceef4975533..5909716542353 100644 --- a/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/engines/sql/unit/engine_spec.rb b/spec/arel/engines/sql/unit/engine_spec.rb index c607abcfa17f2..f782f56938f35 100644 --- a/spec/arel/engines/sql/unit/engine_spec.rb +++ b/spec/arel/engines/sql/unit/engine_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Sql::Engine do diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index b1400e2588ca5..ccf9d4ef73814 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Binary do diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index 688a6a20beeb5..3588604062a44 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Equality do diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index d3e75cfb84caa..4a3eff79ec492 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe In do diff --git a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb index d55e178e432f2..fe0010a8cb24b 100644 --- a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Predicate do diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index 6cb72f3c194bf..d24b6a9d13c8c 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Attribute do diff --git a/spec/arel/engines/sql/unit/primitives/expression_spec.rb b/spec/arel/engines/sql/unit/primitives/expression_spec.rb index ee7f2c1461750..d4df4f8d5a798 100644 --- a/spec/arel/engines/sql/unit/primitives/expression_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/expression_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Expression do diff --git a/spec/arel/engines/sql/unit/primitives/literal_spec.rb b/spec/arel/engines/sql/unit/primitives/literal_spec.rb index ed8bea339baec..cf66a60be9f91 100644 --- a/spec/arel/engines/sql/unit/primitives/literal_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/literal_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe SqlLiteral do diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb index ff3533f6ef532..c8f03fc270296 100644 --- a/spec/arel/engines/sql/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Value do diff --git a/spec/arel/engines/sql/unit/relations/alias_spec.rb b/spec/arel/engines/sql/unit/relations/alias_spec.rb index b67a0bbc89333..55d5a9b671387 100644 --- a/spec/arel/engines/sql/unit/relations/alias_spec.rb +++ b/spec/arel/engines/sql/unit/relations/alias_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Alias do diff --git a/spec/arel/engines/sql/unit/relations/delete_spec.rb b/spec/arel/engines/sql/unit/relations/delete_spec.rb index 7a5e2b00884b5..0b1e2329b63d4 100644 --- a/spec/arel/engines/sql/unit/relations/delete_spec.rb +++ b/spec/arel/engines/sql/unit/relations/delete_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Deletion do diff --git a/spec/arel/engines/sql/unit/relations/group_spec.rb b/spec/arel/engines/sql/unit/relations/group_spec.rb index 5e0c675c8b357..703dc35be5e14 100644 --- a/spec/arel/engines/sql/unit/relations/group_spec.rb +++ b/spec/arel/engines/sql/unit/relations/group_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Group do diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb index 29a5e0bf4235c..1884e32a3db03 100644 --- a/spec/arel/engines/sql/unit/relations/insert_spec.rb +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Insert do diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index f904b6187049b..2820763a66a89 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Join do diff --git a/spec/arel/engines/sql/unit/relations/order_spec.rb b/spec/arel/engines/sql/unit/relations/order_spec.rb index ce97a4dd5e1e2..575e617021fe7 100644 --- a/spec/arel/engines/sql/unit/relations/order_spec.rb +++ b/spec/arel/engines/sql/unit/relations/order_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Order do diff --git a/spec/arel/engines/sql/unit/relations/project_spec.rb b/spec/arel/engines/sql/unit/relations/project_spec.rb index 5e29124cfa0dd..70f2dff70a4ae 100644 --- a/spec/arel/engines/sql/unit/relations/project_spec.rb +++ b/spec/arel/engines/sql/unit/relations/project_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Project do diff --git a/spec/arel/engines/sql/unit/relations/skip_spec.rb b/spec/arel/engines/sql/unit/relations/skip_spec.rb index c14bd1ce95e79..2d606359ee4dd 100644 --- a/spec/arel/engines/sql/unit/relations/skip_spec.rb +++ b/spec/arel/engines/sql/unit/relations/skip_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Skip do diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 9797b388227c8..26b9364929822 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Table do diff --git a/spec/arel/engines/sql/unit/relations/take_spec.rb b/spec/arel/engines/sql/unit/relations/take_spec.rb index 8f1240fc17ef6..2a8aea3d9de3d 100644 --- a/spec/arel/engines/sql/unit/relations/take_spec.rb +++ b/spec/arel/engines/sql/unit/relations/take_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Take do diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb index 4b1d824ce54ff..fd444e27a8329 100644 --- a/spec/arel/engines/sql/unit/relations/update_spec.rb +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' class User def self.primary_key diff --git a/spec/arel/engines/sql/unit/relations/where_spec.rb b/spec/arel/engines/sql/unit/relations/where_spec.rb index 4f0cce1e019bf..8f9a8db4c7094 100644 --- a/spec/arel/engines/sql/unit/relations/where_spec.rb +++ b/spec/arel/engines/sql/unit/relations/where_spec.rb @@ -1,4 +1,4 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') +require 'spec_helper' module Arel describe Where do From 8852db7087a8f4f98e5fd26fa33bac14a5400979 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 14 Sep 2009 17:36:41 -0300 Subject: [PATCH 0278/1492] Cherry pick AS extensions. --- lib/arel.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel.rb b/lib/arel.rb index c5fa5ba9030d5..c4069aa78e585 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,3 +1,7 @@ +require 'active_support/inflector' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/class/attribute_accessors' + require 'active_record' require 'active_record/connection_adapters/abstract/quoting' From 72df9660c3a1a80d38ac504db86e9d5a476b62db Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:01:32 -0400 Subject: [PATCH 0279/1492] Whitespace --- lib/arel/algebra/extensions/class.rb | 2 +- lib/arel/algebra/extensions/hash.rb | 2 +- lib/arel/algebra/extensions/object.rb | 2 +- lib/arel/algebra/extensions/symbol.rb | 2 +- lib/arel/algebra/primitives/ordering.rb | 2 +- lib/arel/engines/sql/extensions/array.rb | 2 +- lib/arel/engines/sql/extensions/nil_class.rb | 2 +- lib/arel/engines/sql/extensions/object.rb | 2 +- lib/arel/engines/sql/extensions/range.rb | 2 +- spec/arel/algebra/unit/relations/order_spec.rb | 2 +- spec/arel/engines/sql/unit/primitives/value_spec.rb | 4 ++-- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index 520111b90f38e..56cad3aaa8a16 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -25,7 +25,7 @@ def ==(other) } class_eval methods[method_name], __FILE__, __LINE__ end - + Class.send(:include, self) end end diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 05c15e7ebe62a..c64225f68536e 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -5,7 +5,7 @@ def bind(relation) bound.merge(key.bind(relation) => value.bind(relation)) end end - + Hash.send(:include, self) end end diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index d8c60b5dd5be7..85a4d951a4f23 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -11,7 +11,7 @@ def find_correlate_in(relation) def let yield(self) end - + Object.send(:include, self) end end diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb index 9bb47ef7abf94..f575ad533abcc 100644 --- a/lib/arel/algebra/extensions/symbol.rb +++ b/lib/arel/algebra/extensions/symbol.rb @@ -3,7 +3,7 @@ module SymbolExtensions def to_attribute(relation) Arel::Attribute.new(relation, self) end - + Symbol.send(:include, self) end end diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb index 3efb4c6280e36..8439e937a94ce 100644 --- a/lib/arel/algebra/primitives/ordering.rb +++ b/lib/arel/algebra/primitives/ordering.rb @@ -15,7 +15,7 @@ class Ascending < Ordering attributes :attribute deriving :initialize, :== end - + class Descending < Ordering attributes :attribute deriving :initialize, :== diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb index 7f15179721261..80041cb5f34bf 100644 --- a/lib/arel/engines/sql/extensions/array.rb +++ b/lib/arel/engines/sql/extensions/array.rb @@ -8,7 +8,7 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "IN" end - + Array.send(:include, self) end end diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb index 8c335f904ae6c..c3dbc8cd76f75 100644 --- a/lib/arel/engines/sql/extensions/nil_class.rb +++ b/lib/arel/engines/sql/extensions/nil_class.rb @@ -4,7 +4,7 @@ module NilClassExtensions def equality_predicate_sql 'IS' end - + NilClass.send(:include, self) end end diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb index 8fe63dba2faec..9f15dff7715bd 100644 --- a/lib/arel/engines/sql/extensions/object.rb +++ b/lib/arel/engines/sql/extensions/object.rb @@ -8,7 +8,7 @@ def to_sql(formatter) def equality_predicate_sql '=' end - + Object.send(:include, self) end end diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb index 25bf1d01daaf0..46124f8865486 100644 --- a/lib/arel/engines/sql/extensions/range.rb +++ b/lib/arel/engines/sql/extensions/range.rb @@ -8,7 +8,7 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "BETWEEN" end - + Range.send(:include, self) end end diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb index 419090102431e..9fcdffe340981 100644 --- a/spec/arel/algebra/unit/relations/order_spec.rb +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -6,7 +6,7 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe "#==" do it "returns true when the Orders are for the same attribute and direction" do Ascending.new(@attribute).should == Ascending.new(@attribute) diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb index c8f03fc270296..807090e31a193 100644 --- a/spec/arel/engines/sql/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -9,11 +9,11 @@ module Arel describe '#to_sql' do it "appropriately quotes the value" do Value.new(1, @relation).to_sql.should be_like('1') - + adapter_is_not :postgresql do Value.new('asdf', @relation).to_sql.should be_like("'asdf'") end - + adapter_is :postgresql do Value.new('asdf', @relation).to_sql.should be_like("E'asdf'") end From d343fdd8f836f27f38b69d0d7d26591eb7d325f6 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:08:36 -0400 Subject: [PATCH 0280/1492] When Arel is loaded the $LOAD_PATH should already be set properly, so don't modify it --- lib/arel.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index c4069aa78e585..abdadda6b4b13 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -5,7 +5,6 @@ require 'active_record' require 'active_record/connection_adapters/abstract/quoting' -$LOAD_PATH.unshift(File.dirname(__FILE__)) require 'arel/algebra' require 'arel/engines' require 'arel/session' From 55ab59efdc6c8fb16ad4db09e015883833f95ae3 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:10:16 -0400 Subject: [PATCH 0281/1492] Remove unnecessary code from Rakefile --- Rakefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Rakefile b/Rakefile index 53ff3a5b7df09..d92d4c371b1ad 100644 --- a/Rakefile +++ b/Rakefile @@ -1,9 +1,6 @@ require "rubygems" require "spec/rake/spectask" -$LOAD_PATH.unshift "lib" -require "arel" - begin require 'jeweler' From dbb2dcf42fea6bb57d7ca6b089cdae58e6c9e102 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:12:55 -0400 Subject: [PATCH 0282/1492] Gracefully handle case where RSpec is not installed in Rakefile --- Rakefile | 71 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/Rakefile b/Rakefile index d92d4c371b1ad..471e6195ad590 100644 --- a/Rakefile +++ b/Rakefile @@ -1,9 +1,13 @@ require "rubygems" -require "spec/rake/spectask" begin require 'jeweler' - +rescue LoadError + desc "Install gem using sudo" + task(:install) do + $stderr.puts "Jeweler not available. `gem install jeweler` to install this gem" + end +else Jeweler::Tasks.new do |s| s.name = "arel" s.authors = ["Bryan Helmkamp", "Nick Kallen"] @@ -16,42 +20,47 @@ begin end Jeweler::RubyforgeTasks.new -rescue LoadError - puts "Jeweler not available. Install it with: gem install jeweler" end -desc "Run specs using RCov (uses mysql database adapter)" -Spec::Rake::SpecTask.new(:coverage) do |t| - t.spec_files = - ["spec/connections/mysql_connection.rb"] + - FileList['spec/**/*_spec.rb'] - - t.rcov = true - t.rcov_opts << '--exclude' << "spec,gems" - t.rcov_opts << '--text-summary' - t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse' - t.rcov_opts << '--only-uncovered' -end +begin + require "spec/rake/spectask" +rescue LoadError + desc "Run specs" + task(:spec) { $stderr.puts '`gem install rspec` to run specs' } +else + desc "Run specs using RCov (uses mysql database adapter)" + Spec::Rake::SpecTask.new(:coverage) do |t| + t.spec_files = + ["spec/connections/mysql_connection.rb"] + + FileList['spec/**/*_spec.rb'] + + t.rcov = true + t.rcov_opts << '--exclude' << "spec,gems" + t.rcov_opts << '--text-summary' + t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse' + t.rcov_opts << '--only-uncovered' + end -namespace :spec do - for adapter in %w[mysql sqlite3 postgresql] - desc "Run specs with the #{adapter} database adapter" - Spec::Rake::SpecTask.new(adapter) do |t| - t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" - t.libs << "#{File.dirname(__FILE__)}/spec" - t.spec_files = - ["spec/connections/#{adapter}_connection.rb"] + - ["spec/schemas/#{adapter}_schema.rb"] + - FileList['spec/**/*_spec.rb'] + namespace :spec do + for adapter in %w[mysql sqlite3 postgresql] + desc "Run specs with the #{adapter} database adapter" + Spec::Rake::SpecTask.new(adapter) do |t| + t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" + t.libs << "#{File.dirname(__FILE__)}/spec" + t.spec_files = + ["spec/connections/#{adapter}_connection.rb"] + + ["spec/schemas/#{adapter}_schema.rb"] + + FileList['spec/**/*_spec.rb'] + end end end -end -desc "Run specs with mysql and sqlite3 database adapters (default)" -task :spec => ["check_dependencies", "spec:sqlite3", "spec:mysql", "spec:postgresql"] + desc "Run specs with mysql and sqlite3 database adapters (default)" + task :spec => ["check_dependencies", "spec:sqlite3", "spec:mysql", "spec:postgresql"] -desc "Default task is to run specs" -task :default => :spec + desc "Default task is to run specs" + task :default => :spec +end desc 'Removes trailing whitespace' task :whitespace do From 7e3fe3114bd8464b95ecff98bc452c9410bf4895 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:15:58 -0400 Subject: [PATCH 0283/1492] Declare dependencies on ActiveRecord and ActiveSupport in Rakefile --- Rakefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Rakefile b/Rakefile index 471e6195ad590..940530cacc73d 100644 --- a/Rakefile +++ b/Rakefile @@ -17,6 +17,9 @@ else # s.description = "TODO" s.rubyforge_project = "arel" s.extra_rdoc_files = %w(README.markdown) + + s.add_dependency "activerecord", ">= 3.0pre" + s.add_dependency "activesupport", ">= 3.0pre" end Jeweler::RubyforgeTasks.new From 41ddc9d013cd8aa76954c486ae45de01bbe7b6f4 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:18:31 -0400 Subject: [PATCH 0284/1492] Add description to Rakefile --- Rakefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 940530cacc73d..eac3b54f61703 100644 --- a/Rakefile +++ b/Rakefile @@ -14,7 +14,13 @@ else s.email = "bryan" + "@" + "brynary.com" s.homepage = "http://github.com/brynary/arel" s.summary = "Arel is a relational algebra engine for Ruby" - # s.description = "TODO" + s.description = <<-EOS.strip +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex +of SQL queries and it 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. +EOS s.rubyforge_project = "arel" s.extra_rdoc_files = %w(README.markdown) From 6690e3c007f65a39797a92462aaabf564bc709b4 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:19:02 -0400 Subject: [PATCH 0285/1492] Turn on Ruby warnings when running specs --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index eac3b54f61703..91170a65f9fb0 100644 --- a/Rakefile +++ b/Rakefile @@ -56,6 +56,7 @@ else Spec::Rake::SpecTask.new(adapter) do |t| t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" t.libs << "#{File.dirname(__FILE__)}/spec" + t.warning = true t.spec_files = ["spec/connections/#{adapter}_connection.rb"] + ["spec/schemas/#{adapter}_schema.rb"] + From 927d8b8cde930244a16215c57896c8e45f616d0f Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 20 Sep 2009 12:59:32 -0400 Subject: [PATCH 0286/1492] Fix almost all Ruby warnings during spec suite --- lib/arel/algebra/extensions/class.rb | 2 +- lib/arel/session.rb | 12 +++++++++--- spec/arel/algebra/unit/predicates/equality_spec.rb | 2 +- spec/arel/algebra/unit/primitives/attribute_spec.rb | 6 ++---- spec/arel/algebra/unit/relations/alias_spec.rb | 2 +- spec/arel/algebra/unit/relations/relation_spec.rb | 6 +++--- spec/arel/algebra/unit/relations/table_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/binary_spec.rb | 11 ++++++----- spec/doubles/hash.rb | 4 ++++ spec/spec_helper.rb | 8 ++++++++ 10 files changed, 36 insertions(+), 19 deletions(-) diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index 56cad3aaa8a16..d0894931dae51 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -2,7 +2,7 @@ module Arel module ClassExtensions def attributes(*attrs) @attributes = attrs - attr_reader *attrs + attr_reader(*attrs) end def deriving(*methods) diff --git a/lib/arel/session.rb b/lib/arel/session.rb index cf04e8a93a61d..d844cd7423c55 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -5,16 +5,22 @@ class << self alias_method :manufacture, :new def start - if @started + if defined?(@started) && @started yield else begin @started = true @instance = manufacture - metaclass.send :alias_method, :new, :instance + metaclass.class_eval do + undef :new + alias_method :new, :instance + end yield ensure - metaclass.send :alias_method, :new, :manufacture + metaclass.class_eval do + undef :new + alias_method :new, :manufacture + end @started = false end end diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb index c91752015866b..01917842f629d 100644 --- a/spec/arel/algebra/unit/predicates/equality_spec.rb +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -11,7 +11,7 @@ module Arel describe '==' do it "obtains if attribute1 and attribute2 are identical" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) + check Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) end diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index cd484007e1aa2..93b661c6fc5c7 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -73,10 +73,8 @@ module Arel describe 'when dividing two matching attributes' do it 'returns a the highest score for the most similar attributes' do - (@aliased_relation[:id] / @relation[:id]) \ - .should == (@aliased_relation[:id] / @relation[:id]) - (@aliased_relation[:id] / @relation[:id]) \ - .should < (@aliased_relation[:id] / @aliased_relation[:id]) + check((@aliased_relation[:id] / @relation[:id]).should == (@aliased_relation[:id] / @relation[:id])) + (@aliased_relation[:id] / @relation[:id]).should < (@aliased_relation[:id] / @aliased_relation[:id]) end end end diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/arel/algebra/unit/relations/alias_spec.rb index 2aa4d52d99855..eaf31652b9ca9 100644 --- a/spec/arel/algebra/unit/relations/alias_spec.rb +++ b/spec/arel/algebra/unit/relations/alias_spec.rb @@ -8,7 +8,7 @@ module Arel describe '==' do it "obtains if the objects are the same" do - Alias.new(@relation).should_not == Alias.new(@relation) + check Alias.new(@relation).should_not == Alias.new(@relation) (aliaz = Alias.new(@relation)).should == aliaz end end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 0a08deffb874a..2688ece4a5eef 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -17,8 +17,8 @@ module Arel describe 'when given a', Symbol, String do it "returns the attribute with the same name, if it exists" do - @relation[:id].should == @attribute1 - @relation['id'].should == @attribute1 + check @relation[:id].should == @attribute1 + check @relation['id'].should == @attribute1 @relation[:does_not_exist].should be_nil end end @@ -180,7 +180,7 @@ module Arel describe Relation::Enumerable do it "implements enumerable" do - @relation.collect.should == @relation.session.read(@relation).collect + check @relation.collect.should == @relation.session.read(@relation).collect @relation.first.should == @relation.session.read(@relation).first end end diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb index e4c4e58b75381..19c1ba2bea8cd 100644 --- a/spec/arel/algebra/unit/relations/table_spec.rb +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -9,7 +9,7 @@ module Arel describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do - @relation[:id].should == Attribute.new(@relation, :id) + check @relation[:id].should == Attribute.new(@relation, :id) @relation[:does_not_exist].should be_nil end end diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index ccf9d4ef73814..783e6c6a7b67d 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -2,15 +2,16 @@ module Arel describe Binary do + class ConcreteBinary < Binary + def predicate_sql + "<=>" + end + end + before do @relation = Table.new(:users) @attribute1 = @relation[:id] @attribute2 = @relation[:name] - class ConcreteBinary < Binary - def predicate_sql - "<=>" - end - end end describe "with compound predicates" do diff --git a/spec/doubles/hash.rb b/spec/doubles/hash.rb index 32c5b98058265..fd9edd34adfb1 100644 --- a/spec/doubles/hash.rb +++ b/spec/doubles/hash.rb @@ -3,18 +3,22 @@ def ordered_array to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash } end + undef :keys def keys ordered_array.collect(&:first) end + undef :values def values ordered_array.collect { |_, v| v } end + undef :each def each(&block) ordered_array.each(&block) end + undef :shift def shift returning to_a.first do |k, v| delete(k) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index beb634fbd326a..7d61fc9120e0f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -37,9 +37,17 @@ def valid_adapters end end +module Check + # This is used to eliminate Ruby warnings on some RSpec assertion lines + # See: https://rspec.lighthouseapp.com/projects/5645/tickets/504 + def check(*args) + end +end + Spec::Runner.configure do |config| config.include BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher config.include AdapterGuards + config.include Check config.mock_with :rr config.before do Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) From 836a57732c6ddd3842f1bf50e687049a098f7383 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 30 Sep 2009 23:21:42 -0400 Subject: [PATCH 0287/1492] Autoload Arel::Session --- lib/arel.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index abdadda6b4b13..a9413b0f1b8d1 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -5,6 +5,8 @@ require 'active_record' require 'active_record/connection_adapters/abstract/quoting' -require 'arel/algebra' -require 'arel/engines' -require 'arel/session' +module Arel + require 'arel/algebra' + require 'arel/engines' + autoload :Session, 'arel/session' +end \ No newline at end of file From 52e8aff146c162986566d3e03852395729d7c24d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 30 Sep 2009 23:23:46 -0400 Subject: [PATCH 0288/1492] Move extensions directories to core_extensions --- lib/arel/algebra.rb | 2 +- lib/arel/algebra/core_extensions.rb | 4 ++++ lib/arel/algebra/{extensions => core_extensions}/class.rb | 0 lib/arel/algebra/{extensions => core_extensions}/hash.rb | 0 lib/arel/algebra/{extensions => core_extensions}/object.rb | 0 lib/arel/algebra/{extensions => core_extensions}/symbol.rb | 0 lib/arel/algebra/extensions.rb | 4 ---- lib/arel/engines/sql.rb | 2 +- lib/arel/engines/sql/core_extensions.rb | 4 ++++ lib/arel/engines/sql/{extensions => core_extensions}/array.rb | 0 .../engines/sql/{extensions => core_extensions}/nil_class.rb | 0 .../engines/sql/{extensions => core_extensions}/object.rb | 0 lib/arel/engines/sql/{extensions => core_extensions}/range.rb | 0 lib/arel/engines/sql/extensions.rb | 4 ---- 14 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 lib/arel/algebra/core_extensions.rb rename lib/arel/algebra/{extensions => core_extensions}/class.rb (100%) rename lib/arel/algebra/{extensions => core_extensions}/hash.rb (100%) rename lib/arel/algebra/{extensions => core_extensions}/object.rb (100%) rename lib/arel/algebra/{extensions => core_extensions}/symbol.rb (100%) delete mode 100644 lib/arel/algebra/extensions.rb create mode 100644 lib/arel/engines/sql/core_extensions.rb rename lib/arel/engines/sql/{extensions => core_extensions}/array.rb (100%) rename lib/arel/engines/sql/{extensions => core_extensions}/nil_class.rb (100%) rename lib/arel/engines/sql/{extensions => core_extensions}/object.rb (100%) rename lib/arel/engines/sql/{extensions => core_extensions}/range.rb (100%) delete mode 100644 lib/arel/engines/sql/extensions.rb diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index c206fea0b0339..319f8fc242ec6 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,4 +1,4 @@ -require 'arel/algebra/extensions' +require 'arel/algebra/core_extensions' require 'arel/algebra/predicates' require 'arel/algebra/relations' require 'arel/algebra/primitives' diff --git a/lib/arel/algebra/core_extensions.rb b/lib/arel/algebra/core_extensions.rb new file mode 100644 index 0000000000000..bce86d04ba140 --- /dev/null +++ b/lib/arel/algebra/core_extensions.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/core_extensions/object' +require 'arel/algebra/core_extensions/class' +require 'arel/algebra/core_extensions/symbol' +require 'arel/algebra/core_extensions/hash' diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/core_extensions/class.rb similarity index 100% rename from lib/arel/algebra/extensions/class.rb rename to lib/arel/algebra/core_extensions/class.rb diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/core_extensions/hash.rb similarity index 100% rename from lib/arel/algebra/extensions/hash.rb rename to lib/arel/algebra/core_extensions/hash.rb diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/core_extensions/object.rb similarity index 100% rename from lib/arel/algebra/extensions/object.rb rename to lib/arel/algebra/core_extensions/object.rb diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/core_extensions/symbol.rb similarity index 100% rename from lib/arel/algebra/extensions/symbol.rb rename to lib/arel/algebra/core_extensions/symbol.rb diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb deleted file mode 100644 index bc8edd32741d8..0000000000000 --- a/lib/arel/algebra/extensions.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/algebra/extensions/object' -require 'arel/algebra/extensions/class' -require 'arel/algebra/extensions/symbol' -require 'arel/algebra/extensions/hash' diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index f31cfc7dacda6..dc40428b777e4 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -3,5 +3,5 @@ require 'arel/engines/sql/primitives' require 'arel/engines/sql/predicates' require 'arel/engines/sql/formatters' -require 'arel/engines/sql/extensions' +require 'arel/engines/sql/core_extensions' require 'arel/engines/sql/christener' diff --git a/lib/arel/engines/sql/core_extensions.rb b/lib/arel/engines/sql/core_extensions.rb new file mode 100644 index 0000000000000..c8d9ec239eacd --- /dev/null +++ b/lib/arel/engines/sql/core_extensions.rb @@ -0,0 +1,4 @@ +require 'arel/engines/sql/core_extensions/object' +require 'arel/engines/sql/core_extensions/array' +require 'arel/engines/sql/core_extensions/range' +require 'arel/engines/sql/core_extensions/nil_class' diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/core_extensions/array.rb similarity index 100% rename from lib/arel/engines/sql/extensions/array.rb rename to lib/arel/engines/sql/core_extensions/array.rb diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/core_extensions/nil_class.rb similarity index 100% rename from lib/arel/engines/sql/extensions/nil_class.rb rename to lib/arel/engines/sql/core_extensions/nil_class.rb diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/core_extensions/object.rb similarity index 100% rename from lib/arel/engines/sql/extensions/object.rb rename to lib/arel/engines/sql/core_extensions/object.rb diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/core_extensions/range.rb similarity index 100% rename from lib/arel/engines/sql/extensions/range.rb rename to lib/arel/engines/sql/core_extensions/range.rb diff --git a/lib/arel/engines/sql/extensions.rb b/lib/arel/engines/sql/extensions.rb deleted file mode 100644 index 1ea31bc140801..0000000000000 --- a/lib/arel/engines/sql/extensions.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/engines/sql/extensions/object' -require 'arel/engines/sql/extensions/array' -require 'arel/engines/sql/extensions/range' -require 'arel/engines/sql/extensions/nil_class' From bcd8ffa2183a1ca98417fb39bbd83e8f69c984c8 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 30 Sep 2009 23:32:05 -0400 Subject: [PATCH 0289/1492] Create Predicates module to match directory structure --- lib/arel/algebra/predicates.rb | 62 ++++---- lib/arel/algebra/primitives/attribute.rb | 14 +- lib/arel/engines/memory/predicates.rb | 50 +++--- lib/arel/engines/sql/predicates.rb | 72 +++++---- .../algebra/unit/predicates/binary_spec.rb | 42 ++--- .../algebra/unit/predicates/equality_spec.rb | 36 +++-- spec/arel/algebra/unit/predicates/in_spec.rb | 10 +- .../algebra/unit/primitives/attribute_spec.rb | 14 +- .../algebra/unit/relations/relation_spec.rb | 2 +- .../sql/unit/predicates/binary_spec.rb | 150 +++++++++--------- .../sql/unit/predicates/equality_spec.rb | 78 ++++----- .../engines/sql/unit/predicates/in_spec.rb | 110 ++++++------- .../sql/unit/predicates/predicates_spec.rb | 92 +++++------ 13 files changed, 376 insertions(+), 356 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 72167c2b27bb6..8a0b41fa18f5e 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -1,41 +1,43 @@ module Arel - class Predicate - def or(other_predicate) - Or.new(self, other_predicate) - end + module Predicates + class Predicate + def or(other_predicate) + Or.new(self, other_predicate) + end - def and(other_predicate) - And.new(self, other_predicate) + def and(other_predicate) + And.new(self, other_predicate) + end end - end - class Binary < Predicate - attributes :operand1, :operand2 - deriving :initialize + class Binary < Predicate + attributes :operand1, :operand2 + deriving :initialize - def ==(other) - self.class === other and - @operand1 == other.operand1 and - @operand2 == other.operand2 - end + def ==(other) + self.class === other and + @operand1 == other.operand1 and + @operand2 == other.operand2 + end - def bind(relation) - self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) + def bind(relation) + self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) + end end - end - class Equality < Binary - def ==(other) - Equality === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) + class Equality < Binary + def ==(other) + Equality === other and + ((operand1 == other.operand1 and operand2 == other.operand2) or + (operand1 == other.operand2 and operand2 == other.operand1)) + end end - end - class GreaterThanOrEqualTo < Binary; end - class GreaterThan < Binary; end - class LessThanOrEqualTo < Binary; end - class LessThan < Binary; end - class Match < Binary; end - class In < Binary; end + class GreaterThanOrEqualTo < Binary; end + class GreaterThan < Binary; end + class LessThanOrEqualTo < Binary; end + class LessThan < Binary; end + class Match < Binary; end + class In < Binary; end + end end diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 44a2f4173305b..40a7d61a53fc7 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -82,31 +82,31 @@ def /(other) module Predications def eq(other) - Equality.new(self, other) + Predicates::Equality.new(self, other) end def lt(other) - LessThan.new(self, other) + Predicates::LessThan.new(self, other) end def lteq(other) - LessThanOrEqualTo.new(self, other) + Predicates::LessThanOrEqualTo.new(self, other) end def gt(other) - GreaterThan.new(self, other) + Predicates::GreaterThan.new(self, other) end def gteq(other) - GreaterThanOrEqualTo.new(self, other) + Predicates::GreaterThanOrEqualTo.new(self, other) end def matches(regexp) - Match.new(self, regexp) + Predicates::Match.new(self, regexp) end def in(array) - In.new(self, array) + Predicates::In.new(self, array) end end include Predications diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index 03d4f25b0aa99..dd2559c70f088 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -1,35 +1,37 @@ module Arel - class Binary < Predicate - def eval(row) - operand1.eval(row).send(operator, operand2.eval(row)) + module Predicates + class Binary < Predicate + def eval(row) + operand1.eval(row).send(operator, operand2.eval(row)) + end end - end - class Equality < Binary - def operator; :== end - end + class Equality < Binary + def operator; :== end + end - class GreaterThanOrEqualTo < Binary - def operator; :>= end - end + class GreaterThanOrEqualTo < Binary + def operator; :>= end + end - class GreaterThan < Binary - def operator; :> end - end + class GreaterThan < Binary + def operator; :> end + end - class LessThanOrEqualTo < Binary - def operator; :<= end - end + class LessThanOrEqualTo < Binary + def operator; :<= end + end - class LessThan < Binary - def operator; :< end - end + class LessThan < Binary + def operator; :< end + end - class Match < Binary - def operator; :=~ end - end + class Match < Binary + def operator; :=~ end + end - class In < Binary - def operator; :include? end + class In < Binary + def operator; :include? end + end end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index b84c183c1dcc0..e563a9ba3e2e7 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -1,51 +1,53 @@ module Arel - class Binary < Predicate - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" + module Predicates + class Binary < Predicate + def to_sql(formatter = nil) + "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" + end end - end - class CompoundPredicate < Binary - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + class CompoundPredicate < Binary + def to_sql(formatter = nil) + "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + end end - end - class Or < CompoundPredicate - def predicate_sql; "OR" end - end + class Or < CompoundPredicate + def predicate_sql; "OR" end + end - class And < CompoundPredicate - def predicate_sql; "AND" end - end + class And < CompoundPredicate + def predicate_sql; "AND" end + end - class Equality < Binary - def predicate_sql - operand2.equality_predicate_sql + class Equality < Binary + def predicate_sql + operand2.equality_predicate_sql + end end - end - class GreaterThanOrEqualTo < Binary - def predicate_sql; '>=' end - end + class GreaterThanOrEqualTo < Binary + def predicate_sql; '>=' end + end - class GreaterThan < Binary - def predicate_sql; '>' end - end + class GreaterThan < Binary + def predicate_sql; '>' end + end - class LessThanOrEqualTo < Binary - def predicate_sql; '<=' end - end + class LessThanOrEqualTo < Binary + def predicate_sql; '<=' end + end - class LessThan < Binary - def predicate_sql; '<' end - end + class LessThan < Binary + def predicate_sql; '<' end + end - class Match < Binary - def predicate_sql; 'LIKE' end - end + class Match < Binary + def predicate_sql; 'LIKE' end + end - class In < Binary - def predicate_sql; operand2.inclusion_predicate_sql end + class In < Binary + def predicate_sql; operand2.inclusion_predicate_sql end + end end end diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb index 97ef098e0e86e..be4c1ac738ab9 100644 --- a/spec/arel/algebra/unit/predicates/binary_spec.rb +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -1,31 +1,33 @@ require 'spec_helper' module Arel - describe Binary do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - class ConcreteBinary < Binary - end - end - - describe '#bind' do + module Predicates + describe Binary do before do - @another_relation = @relation.alias + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + class ConcreteBinary < Binary + end end - describe 'when both operands are attributes' do - it "manufactures an expression with the attributes bound to the relation" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ - should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) + describe '#bind' do + before do + @another_relation = @relation.alias + end + + describe 'when both operands are attributes' do + it "manufactures an expression with the attributes bound to the relation" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) + end end - end - describe 'when an operand is a value' do - it "manufactures an expression with unmodified values" do - ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) + describe 'when an operand is a value' do + it "manufactures an expression with unmodified values" do + ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ + should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) + end end end end diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb index 01917842f629d..cfd04cd90c80a 100644 --- a/spec/arel/algebra/unit/predicates/equality_spec.rb +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -1,26 +1,28 @@ require 'spec_helper' module Arel - describe Equality do - before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:user_id] - end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - check Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) - Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) + module Predicates + describe Equality do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] end - it "obtains if the concrete type of the predicates are identical" do - Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) - end + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + check Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) + Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) + end - it "is commutative on the attributes" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) + it "is commutative on the attributes" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) + end end end end diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/arel/algebra/unit/predicates/in_spec.rb index 54a6d6c7da459..b9e15d63a4a24 100644 --- a/spec/arel/algebra/unit/predicates/in_spec.rb +++ b/spec/arel/algebra/unit/predicates/in_spec.rb @@ -1,10 +1,12 @@ require 'spec_helper' module Arel - describe In do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] + module Predicates + describe In do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end end end end diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index 93b661c6fc5c7..f734cc9c38a11 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -87,43 +87,43 @@ module Arel describe '#eq' do it "manufactures an equality predicate" do - @attribute.eq('name').should == Equality.new(@attribute, 'name') + @attribute.eq('name').should == Predicates::Equality.new(@attribute, 'name') end end describe '#lt' do it "manufactures a less-than predicate" do - @attribute.lt(10).should == LessThan.new(@attribute, 10) + @attribute.lt(10).should == Predicates::LessThan.new(@attribute, 10) end end describe '#lteq' do it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) + @attribute.lteq(10).should == Predicates::LessThanOrEqualTo.new(@attribute, 10) end end describe '#gt' do it "manufactures a greater-than predicate" do - @attribute.gt(10).should == GreaterThan.new(@attribute, 10) + @attribute.gt(10).should == Predicates::GreaterThan.new(@attribute, 10) end end describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) + @attribute.gteq(10).should == Predicates::GreaterThanOrEqualTo.new(@attribute, 10) end end describe '#matches' do it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) + @attribute.matches(/.*/).should == Predicates::Match.new(@attribute, /.*/) end end describe '#in' do it "manufactures an in predicate" do - @attribute.in(1..30).should == In.new(@attribute, (1..30)) + @attribute.in(1..30).should == Predicates::In.new(@attribute, (1..30)) end end end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 2688ece4a5eef..35ce8bf1fb7c2 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -80,7 +80,7 @@ module Arel describe '#where' do before do - @predicate = Equality.new(@attribute1, @attribute2) + @predicate = Predicates::Equality.new(@attribute1, @attribute2) end it "manufactures a where relation" do diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 783e6c6a7b67d..23bce5479231b 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -1,114 +1,116 @@ require 'spec_helper' module Arel - describe Binary do - class ConcreteBinary < Binary - def predicate_sql - "<=>" + module Predicates + describe Binary do + class ConcreteBinary < Binary + def predicate_sql + "<=>" + end end - end - - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - end - describe "with compound predicates" do before do - @operand1 = ConcreteBinary.new(@attribute1, 1) - @operand2 = ConcreteBinary.new(@attribute2, "name") + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] end - describe Or do - describe "#to_sql" do - it "manufactures sql with an OR operation" do - sql = Or.new(@operand1, @operand2).to_sql + describe "with compound predicates" do + before do + @operand1 = ConcreteBinary.new(@attribute1, 1) + @operand2 = ConcreteBinary.new(@attribute2, "name") + end - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) - end + describe Or do + describe "#to_sql" do + it "manufactures sql with an OR operation" do + sql = Or.new(@operand1, @operand2).to_sql - adapter_is :postgresql do - sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> E'name')}) - end + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) + end + + adapter_is :postgresql do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> E'name')}) + end - adapter_is :sqlite3 do - sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) + adapter_is :sqlite3 do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) + end end end end - end - describe And do - describe "#to_sql" do - it "manufactures sql with an AND operation" do - sql = And.new(@operand1, @operand2).to_sql + describe And do + describe "#to_sql" do + it "manufactures sql with an AND operation" do + sql = And.new(@operand1, @operand2).to_sql - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) - end + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) + end - adapter_is :sqlite3 do - sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) - end + adapter_is :sqlite3 do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) + end - adapter_is :postgresql do - sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> E'name')}) + adapter_is :postgresql do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> E'name')}) + end end end end end - end - describe '#to_sql' do - describe 'when relating two attributes' do - it 'manufactures sql with a binary operation' do - sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql + describe '#to_sql' do + describe 'when relating two attributes' do + it 'manufactures sql with a binary operation' do + sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) - end + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) + end - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" <=> "users"."name"}) + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> "users"."name"}) + end end end - end - describe 'when relating an attribute and a value' do - before do - @value = "1-asdf" - end + describe 'when relating an attribute and a value' do + before do + @value = "1-asdf" + end - describe 'when relating to an integer attribute' do - it 'formats values as integers' do - sql = ConcreteBinary.new(@attribute1, @value).to_sql + describe 'when relating to an integer attribute' do + it 'formats values as integers' do + sql = ConcreteBinary.new(@attribute1, @value).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` <=> 1}) - end + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> 1}) + end - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" <=> 1}) + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> 1}) + end end end - end - describe 'when relating to a string attribute' do - it 'formats values as strings' do - sql = ConcreteBinary.new(@attribute2, @value).to_sql + describe 'when relating to a string attribute' do + it 'formats values as strings' do + sql = ConcreteBinary.new(@attribute2, @value).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) - end + adapter_is :mysql do + sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) + end - adapter_is :sqlite3 do - sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) - end + adapter_is :sqlite3 do + sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) + end - adapter_is :postgresql do - sql.should be_like(%Q{"users"."name" <=> E'1-asdf'}) + adapter_is :postgresql do + sql.should be_like(%Q{"users"."name" <=> E'1-asdf'}) + end end end end diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index c4dd2c0c310e9..4004bb58813cb 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -1,58 +1,60 @@ require 'spec_helper' module Arel - describe Equality do - before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:user_id] - end + module Predicates + describe Equality do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] + end - describe '#to_sql' do - describe 'when relating to a non-nil value' do - it "manufactures an equality predicate" do - sql = Equality.new(@attribute1, @attribute2).to_sql + describe '#to_sql' do + describe 'when relating to a non-nil value' do + it "manufactures an equality predicate" do + sql = Equality.new(@attribute1, @attribute2).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) - end + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) + end - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) + end end end - end - describe 'when relation to a nil value' do - before do - @nil = nil - end + describe 'when relation to a nil value' do + before do + @nil = nil + end - it "manufactures an is null predicate" do - sql = Equality.new(@attribute1, @nil).to_sql + it "manufactures an is null predicate" do + sql = Equality.new(@attribute1, @nil).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NULL}) - end + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NULL}) + end - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IS NULL}) + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IS NULL}) + end end end - end - describe "when relating to a nil Value" do - it "manufactures an IS NULL predicate" do - value = nil.bind(@relation1) - sql = Equality.new(@attribute1, value).to_sql + describe "when relating to a nil Value" do + it "manufactures an IS NULL predicate" do + value = nil.bind(@relation1) + sql = Equality.new(@attribute1, value).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NULL}) - end + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NULL}) + end - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IS NULL}) + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IS NULL}) + end end end end diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index 4a3eff79ec492..bb00733e6070f 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -1,83 +1,85 @@ require 'spec_helper' module Arel - describe In do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end + module Predicates + describe In do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end - describe '#to_sql' do - describe 'when relating to an array' do - describe 'when the array\'s elements are the same type as the attribute' do - before do - @array = [1, 2, 3] - end + describe '#to_sql' do + describe 'when relating to an array' do + describe 'when the array\'s elements are the same type as the attribute' do + before do + @array = [1, 2, 3] + end - it 'manufactures sql with a comma separated list' do - sql = In.new(@attribute, @array).to_sql + it 'manufactures sql with a comma separated list' do + sql = In.new(@attribute, @array).to_sql - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end end + end - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + describe 'when the array\'s elements are not same type as the attribute' do + before do + @array = ['1-asdf', 2, 3] + end + + it 'formats values in the array as the type of the attribute' do + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end end end end - describe 'when the array\'s elements are not same type as the attribute' do + describe 'when relating to a range' do before do - @array = ['1-asdf', 2, 3] + @range = 1..2 end - it 'formats values in the array as the type of the attribute' do - sql = In.new(@attribute, @array).to_sql + it 'manufactures sql with a between' do + sql = In.new(@attribute, @range).to_sql adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) end adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) end end end - end - - describe 'when relating to a range' do - before do - @range = 1..2 - end - - it 'manufactures sql with a between' do - sql = In.new(@attribute, @range).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) - end - end - end - describe 'when relating to a relation' do - it 'manufactures sql with a subselect' do - sql = In.new(@attribute, @relation).to_sql + describe 'when relating to a relation' do + it 'manufactures sql with a subselect' do + sql = In.new(@attribute, @relation).to_sql - adapter_is :mysql do - sql.should be_like(%Q{ - `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) - }) - end + adapter_is :mysql do + sql.should be_like(%Q{ + `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) + }) + end - adapter_is_not :mysql do - sql.should be_like(%Q{ - "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") - }) + adapter_is_not :mysql do + sql.should be_like(%Q{ + "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") + }) + end end end end diff --git a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb index fe0010a8cb24b..7d533515469e7 100644 --- a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb @@ -1,62 +1,64 @@ require 'spec_helper' module Arel - describe Predicate do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - @operand1 = Equality.new(@attribute1, 1) - @operand2 = Equality.new(@attribute2, "name") - end + module Predicates + describe Predicate do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + @operand1 = Equality.new(@attribute1, 1) + @operand2 = Equality.new(@attribute2, "name") + end - describe "when being combined with another predicate with AND logic" do - describe "#to_sql" do - it "manufactures sql with an AND operation" do - sql = @operand1.and(@operand2).to_sql + describe "when being combined with another predicate with AND logic" do + describe "#to_sql" do + it "manufactures sql with an AND operation" do + sql = @operand1.and(@operand2).to_sql - adapter_is :mysql do - sql.should be_like(%Q{ - (`users`.`id` = 1 AND `users`.`name` = 'name') - }) - end + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 AND `users`.`name` = 'name') + }) + end - adapter_is :sqlite3 do - sql.should be_like(%Q{ - ("users"."id" = 1 AND "users"."name" = 'name') - }) - end + adapter_is :sqlite3 do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = 'name') + }) + end - adapter_is :postgresql do - sql.should be_like(%Q{ - ("users"."id" = 1 AND "users"."name" = E'name') - }) + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = E'name') + }) + end end end end - end - describe "when being combined with another predicate with OR logic" do - describe "#to_sql" do - it "manufactures sql with an OR operation" do - sql = @operand1.or(@operand2).to_sql + describe "when being combined with another predicate with OR logic" do + describe "#to_sql" do + it "manufactures sql with an OR operation" do + sql = @operand1.or(@operand2).to_sql - adapter_is :mysql do - sql.should be_like(%Q{ - (`users`.`id` = 1 OR `users`.`name` = 'name') - }) - end + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 OR `users`.`name` = 'name') + }) + end - adapter_is :sqlite3 do - sql.should be_like(%Q{ - ("users"."id" = 1 OR "users"."name" = 'name') - }) - end + adapter_is :sqlite3 do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = 'name') + }) + end - adapter_is :postgresql do - sql.should be_like(%Q{ - ("users"."id" = 1 OR "users"."name" = E'name') - }) + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = E'name') + }) + end end end end From 71d65b7571d5ff01e0de3c08a9396dc1e1386118 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 30 Sep 2009 23:35:23 -0400 Subject: [PATCH 0290/1492] Pull primitives up one level --- lib/arel/algebra.rb | 7 ++++++- lib/arel/algebra/{primitives => }/attribute.rb | 0 lib/arel/algebra/{primitives => }/expression.rb | 0 lib/arel/algebra/{primitives => }/ordering.rb | 0 lib/arel/algebra/primitives.rb | 5 ----- lib/arel/algebra/{primitives => }/value.rb | 0 6 files changed, 6 insertions(+), 6 deletions(-) rename lib/arel/algebra/{primitives => }/attribute.rb (100%) rename lib/arel/algebra/{primitives => }/expression.rb (100%) rename lib/arel/algebra/{primitives => }/ordering.rb (100%) delete mode 100644 lib/arel/algebra/primitives.rb rename lib/arel/algebra/{primitives => }/value.rb (100%) diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index 319f8fc242ec6..980c558918e01 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,4 +1,9 @@ require 'arel/algebra/core_extensions' + +require 'arel/algebra/attribute' +require 'arel/algebra/expression' +require 'arel/algebra/ordering' require 'arel/algebra/predicates' require 'arel/algebra/relations' -require 'arel/algebra/primitives' +require 'arel/algebra/value' + diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/attribute.rb similarity index 100% rename from lib/arel/algebra/primitives/attribute.rb rename to lib/arel/algebra/attribute.rb diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/expression.rb similarity index 100% rename from lib/arel/algebra/primitives/expression.rb rename to lib/arel/algebra/expression.rb diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/ordering.rb similarity index 100% rename from lib/arel/algebra/primitives/ordering.rb rename to lib/arel/algebra/ordering.rb diff --git a/lib/arel/algebra/primitives.rb b/lib/arel/algebra/primitives.rb deleted file mode 100644 index df8d16a5d58e5..0000000000000 --- a/lib/arel/algebra/primitives.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'arel/algebra/primitives/attribute' -require 'arel/algebra/primitives/ordering' -require 'arel/algebra/primitives/value' -require 'arel/algebra/primitives/expression' - diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/value.rb similarity index 100% rename from lib/arel/algebra/primitives/value.rb rename to lib/arel/algebra/value.rb From 2824d7c2ad958679ec018cf15c06cc8008d7f193 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 30 Sep 2009 23:36:06 -0400 Subject: [PATCH 0291/1492] Whitespace --- lib/arel/engines/sql/relations/relation.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index ed7f19ddbd344..2edbe6a5f7597 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -25,15 +25,15 @@ def select_sql ("OFFSET #{skipped}" unless skipped.blank? ) else - build_query \ - "SELECT #{select_clauses.join(', ')}", - "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) + build_query \ + "SELECT #{select_clauses.join(', ')}", + "FROM #{table_sql(Sql::TableReference.new(self))}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) end end From 0da3bbe9a48d0fe2cd2c4cb2dd1590725ee6ad8c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Thu, 1 Oct 2009 00:13:56 -0400 Subject: [PATCH 0292/1492] Adding spec.opts --- Rakefile | 1 + spec/spec.opts | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 spec/spec.opts diff --git a/Rakefile b/Rakefile index 91170a65f9fb0..0564da23ca0c4 100644 --- a/Rakefile +++ b/Rakefile @@ -54,6 +54,7 @@ else for adapter in %w[mysql sqlite3 postgresql] desc "Run specs with the #{adapter} database adapter" Spec::Rake::SpecTask.new(adapter) do |t| + t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" t.libs << "#{File.dirname(__FILE__)}/spec" t.warning = true diff --git a/spec/spec.opts b/spec/spec.opts new file mode 100644 index 0000000000000..ef88ff877b1fd --- /dev/null +++ b/spec/spec.opts @@ -0,0 +1,3 @@ +--backtrace +--diff +--color \ No newline at end of file From 6d093fb719f4f080d47c8aeadb72201979c604d7 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Thu, 1 Oct 2009 00:14:15 -0400 Subject: [PATCH 0293/1492] Removing unused params from #to_sql methods on writes --- lib/arel/engines/sql/relations/writes.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index d648a54d91833..42496ef73587f 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -1,6 +1,6 @@ module Arel class Deletion < Compound - def to_sql(formatter = nil) + def to_sql build_query \ "DELETE", "FROM #{table_sql}", @@ -10,7 +10,7 @@ def to_sql(formatter = nil) end class Insert < Compound - def to_sql(formatter = nil) + def to_sql insertion_attributes_values_sql = if record.is_a?(Value) record.value else @@ -26,7 +26,7 @@ def to_sql(formatter = nil) end class Update < Compound - def to_sql(formatter = nil) + def to_sql build_query \ "UPDATE #{table_sql} SET", assignment_sql, @@ -34,6 +34,7 @@ def to_sql(formatter = nil) end protected + def assignment_sql if assignments.respond_to?(:collect) assignments.collect do |attribute, value| From b99b4e15d56af74c704c0595636f94af1d063dd2 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 14 Oct 2009 16:44:16 -0700 Subject: [PATCH 0294/1492] remove lib/arel/.DS_Store from gemspec --- arel.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 003a38073ad1a..69d4ce1c1a31f 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -23,7 +23,6 @@ Gem::Specification.new do |s| "doc/CONVENTIONS", "doc/TODO", "lib/arel.rb", - "lib/arel/.DS_Store", "lib/arel/algebra.rb", "lib/arel/algebra/extensions.rb", "lib/arel/algebra/extensions/class.rb", From 35acdc90ec31d386c49b29a5db9c867db137e6ea Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 Oct 2009 18:26:15 -0700 Subject: [PATCH 0295/1492] Bump version 0.1.0 -> 0.1.1 to distinguish from older, already-released gem --- VERSION | 2 +- arel.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 6c6aa7cb0918d..17e51c385ea38 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 \ No newline at end of file +0.1.1 diff --git a/arel.gemspec b/arel.gemspec index 69d4ce1c1a31f..6801267b63892 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -5,7 +5,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.1.0" + s.version = "0.1.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen"] From efc167dc07e61cf18cfae8ccac23134d87299cc1 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 Oct 2009 20:17:21 -0400 Subject: [PATCH 0296/1492] Dropping Jeweler in favor of some simple Thor tasks (for Gemcutter) --- Rakefile | 31 -------------- Thorfile | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ VERSION | 1 - lib/arel.rb | 2 + 4 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 Thorfile delete mode 100644 VERSION diff --git a/Rakefile b/Rakefile index 0564da23ca0c4..e1557bda70088 100644 --- a/Rakefile +++ b/Rakefile @@ -1,36 +1,5 @@ require "rubygems" -begin - require 'jeweler' -rescue LoadError - desc "Install gem using sudo" - task(:install) do - $stderr.puts "Jeweler not available. `gem install jeweler` to install this gem" - end -else - Jeweler::Tasks.new do |s| - s.name = "arel" - s.authors = ["Bryan Helmkamp", "Nick Kallen"] - s.email = "bryan" + "@" + "brynary.com" - s.homepage = "http://github.com/brynary/arel" - s.summary = "Arel is a relational algebra engine for Ruby" - s.description = <<-EOS.strip -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex -of SQL queries and it 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. -EOS - s.rubyforge_project = "arel" - s.extra_rdoc_files = %w(README.markdown) - - s.add_dependency "activerecord", ">= 3.0pre" - s.add_dependency "activesupport", ">= 3.0pre" - end - - Jeweler::RubyforgeTasks.new -end - begin require "spec/rake/spectask" rescue LoadError diff --git a/Thorfile b/Thorfile new file mode 100644 index 0000000000000..edc39a16b0de7 --- /dev/null +++ b/Thorfile @@ -0,0 +1,116 @@ +module GemHelpers + + def generate_gemspec + $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib"))) + require "arel" + + Gem::Specification.new do |s| + s.name = "arel" + s.version = Arel::VERSION + s.authors = ["Bryan Helmkamp", "Nick Kallen"] + s.email = "bryan@brynary.com" + s.homepage = "http://github.com/brynary/arel" + s.summary = "Arel is a relational algebra engine for Ruby" + s.description = <<-EOS.strip +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex +of SQL queries and it 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. + EOS + s.rubyforge_project = "arel" + + require "git" + repo = Git.open(".") + + s.files = normalize_files(repo.ls_files.keys - repo.lib.ignored_files) + s.test_files = normalize_files(Dir['spec/**/*.rb'] - repo.lib.ignored_files) + + s.has_rdoc = true + s.extra_rdoc_files = %w[README.markdown] + + s.add_dependency "activerecord", ">= 3.0pre" + s.add_dependency "activesupport", ">= 3.0pre" + end + end + + def normalize_files(array) + # only keep files, no directories, and sort + array.select do |path| + File.file?(path) + end.sort + end + + # Adds extra space when outputting an array. This helps create better version + # control diffs, because otherwise it is all on the same line. + def prettyify_array(gemspec_ruby, array_name) + gemspec_ruby.gsub(/s\.#{array_name.to_s} = \[.+?\]/) do |match| + leadin, files = match[0..-2].split("[") + leadin + "[\n #{files.split(",").join(",\n ")}\n ]" + end + end + + def read_gemspec + @read_gemspec ||= eval(File.read("arel.gemspec")) + end + + def sh(command) + puts command + system command + end +end + +class Default < Thor + include GemHelpers + + desc "gemspec", "Regenerate arel.gemspec" + def gemspec + File.open("arel.gemspec", "w") do |file| + gemspec_ruby = generate_gemspec.to_ruby + gemspec_ruby = prettyify_array(gemspec_ruby, :files) + gemspec_ruby = prettyify_array(gemspec_ruby, :test_files) + gemspec_ruby = prettyify_array(gemspec_ruby, :extra_rdoc_files) + + file.write gemspec_ruby + end + + puts "Wrote gemspec to arel.gemspec" + read_gemspec.validate + end + + desc "build", "Build a arel gem" + def build + sh "gem build arel.gemspec" + FileUtils.mkdir_p "pkg" + FileUtils.mv read_gemspec.file_name, "pkg" + end + + desc "install", "Install the latest built gem" + def install + sh "gem install --local pkg/#{read_gemspec.file_name}" + end + + desc "release", "Release the current branch to GitHub and Gemcutter" + def release + gemspec + build + Release.new.tag + Release.new.gem + end +end + +class Release < Thor + include GemHelpers + + desc "tag", "Tag the gem on the origin server" + def tag + release_tag = "v#{read_gemspec.version}" + sh "git tag -a #{release_tag} -m 'Tagging #{release_tag}'" + sh "git push origin #{release_tag}" + end + + desc "gem", "Push the gem to Gemcutter" + def gem + sh "gem push pkg/#{read_gemspec.file_name}" + end +end \ No newline at end of file diff --git a/VERSION b/VERSION deleted file mode 100644 index 17e51c385ea38..0000000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1.1 diff --git a/lib/arel.rb b/lib/arel.rb index a9413b0f1b8d1..a9fe15c8247a0 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -9,4 +9,6 @@ module Arel require 'arel/algebra' require 'arel/engines' autoload :Session, 'arel/session' + + VERSION = "0.1.2" end \ No newline at end of file From 492f96e83947b38e21bdde22caedb992cb1e4083 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 Oct 2009 20:19:20 -0400 Subject: [PATCH 0297/1492] Generating newly formatted gemspec --- arel.gemspec | 408 ++++++++++++++++++++++++++------------------------- 1 file changed, 208 insertions(+), 200 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 6801267b63892..a7dbeca51de7b 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,223 +1,225 @@ -# Generated by jeweler -# DO NOT EDIT THIS FILE -# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec` # -*- encoding: utf-8 -*- Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.1.1" + s.version = "0.1.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen"] - s.date = %q{2009-08-06} + s.date = %q{2009-10-27} + s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex +of SQL queries and it 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.} s.email = %q{bryan@brynary.com} s.extra_rdoc_files = [ "README.markdown" ] s.files = [ ".gitignore", - "README.markdown", - "Rakefile", - "VERSION", - "arel.gemspec", - "doc/CONVENTIONS", - "doc/TODO", - "lib/arel.rb", - "lib/arel/algebra.rb", - "lib/arel/algebra/extensions.rb", - "lib/arel/algebra/extensions/class.rb", - "lib/arel/algebra/extensions/hash.rb", - "lib/arel/algebra/extensions/object.rb", - "lib/arel/algebra/extensions/symbol.rb", - "lib/arel/algebra/predicates.rb", - "lib/arel/algebra/primitives.rb", - "lib/arel/algebra/primitives/attribute.rb", - "lib/arel/algebra/primitives/expression.rb", - "lib/arel/algebra/primitives/ordering.rb", - "lib/arel/algebra/primitives/value.rb", - "lib/arel/algebra/relations.rb", - "lib/arel/algebra/relations/operations/alias.rb", - "lib/arel/algebra/relations/operations/group.rb", - "lib/arel/algebra/relations/operations/join.rb", - "lib/arel/algebra/relations/operations/order.rb", - "lib/arel/algebra/relations/operations/project.rb", - "lib/arel/algebra/relations/operations/skip.rb", - "lib/arel/algebra/relations/operations/take.rb", - "lib/arel/algebra/relations/operations/where.rb", - "lib/arel/algebra/relations/relation.rb", - "lib/arel/algebra/relations/row.rb", - "lib/arel/algebra/relations/utilities/compound.rb", - "lib/arel/algebra/relations/utilities/externalization.rb", - "lib/arel/algebra/relations/utilities/nil.rb", - "lib/arel/algebra/relations/writes.rb", - "lib/arel/engines.rb", - "lib/arel/engines/memory.rb", - "lib/arel/engines/memory/engine.rb", - "lib/arel/engines/memory/predicates.rb", - "lib/arel/engines/memory/primitives.rb", - "lib/arel/engines/memory/relations.rb", - "lib/arel/engines/memory/relations/array.rb", - "lib/arel/engines/memory/relations/compound.rb", - "lib/arel/engines/memory/relations/operations.rb", - "lib/arel/engines/memory/relations/writes.rb", - "lib/arel/engines/sql.rb", - "lib/arel/engines/sql/christener.rb", - "lib/arel/engines/sql/engine.rb", - "lib/arel/engines/sql/extensions.rb", - "lib/arel/engines/sql/extensions/array.rb", - "lib/arel/engines/sql/extensions/nil_class.rb", - "lib/arel/engines/sql/extensions/object.rb", - "lib/arel/engines/sql/extensions/range.rb", - "lib/arel/engines/sql/formatters.rb", - "lib/arel/engines/sql/predicates.rb", - "lib/arel/engines/sql/primitives.rb", - "lib/arel/engines/sql/relations.rb", - "lib/arel/engines/sql/relations/operations/alias.rb", - "lib/arel/engines/sql/relations/operations/join.rb", - "lib/arel/engines/sql/relations/relation.rb", - "lib/arel/engines/sql/relations/table.rb", - "lib/arel/engines/sql/relations/utilities/compound.rb", - "lib/arel/engines/sql/relations/utilities/externalization.rb", - "lib/arel/engines/sql/relations/utilities/nil.rb", - "lib/arel/engines/sql/relations/utilities/recursion.rb", - "lib/arel/engines/sql/relations/writes.rb", - "lib/arel/session.rb", - "spec/arel/algebra/unit/predicates/binary_spec.rb", - "spec/arel/algebra/unit/predicates/equality_spec.rb", - "spec/arel/algebra/unit/predicates/in_spec.rb", - "spec/arel/algebra/unit/primitives/attribute_spec.rb", - "spec/arel/algebra/unit/primitives/expression_spec.rb", - "spec/arel/algebra/unit/primitives/value_spec.rb", - "spec/arel/algebra/unit/relations/alias_spec.rb", - "spec/arel/algebra/unit/relations/delete_spec.rb", - "spec/arel/algebra/unit/relations/group_spec.rb", - "spec/arel/algebra/unit/relations/insert_spec.rb", - "spec/arel/algebra/unit/relations/join_spec.rb", - "spec/arel/algebra/unit/relations/order_spec.rb", - "spec/arel/algebra/unit/relations/project_spec.rb", - "spec/arel/algebra/unit/relations/relation_spec.rb", - "spec/arel/algebra/unit/relations/skip_spec.rb", - "spec/arel/algebra/unit/relations/table_spec.rb", - "spec/arel/algebra/unit/relations/take_spec.rb", - "spec/arel/algebra/unit/relations/update_spec.rb", - "spec/arel/algebra/unit/relations/where_spec.rb", - "spec/arel/algebra/unit/session/session_spec.rb", - "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", - "spec/arel/engines/memory/unit/relations/array_spec.rb", - "spec/arel/engines/memory/unit/relations/insert_spec.rb", - "spec/arel/engines/memory/unit/relations/join_spec.rb", - "spec/arel/engines/memory/unit/relations/order_spec.rb", - "spec/arel/engines/memory/unit/relations/project_spec.rb", - "spec/arel/engines/memory/unit/relations/skip_spec.rb", - "spec/arel/engines/memory/unit/relations/take_spec.rb", - "spec/arel/engines/memory/unit/relations/where_spec.rb", - "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", - "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", - "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", - "spec/arel/engines/sql/unit/engine_spec.rb", - "spec/arel/engines/sql/unit/predicates/binary_spec.rb", - "spec/arel/engines/sql/unit/predicates/equality_spec.rb", - "spec/arel/engines/sql/unit/predicates/in_spec.rb", - "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", - "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", - "spec/arel/engines/sql/unit/primitives/expression_spec.rb", - "spec/arel/engines/sql/unit/primitives/literal_spec.rb", - "spec/arel/engines/sql/unit/primitives/value_spec.rb", - "spec/arel/engines/sql/unit/relations/alias_spec.rb", - "spec/arel/engines/sql/unit/relations/delete_spec.rb", - "spec/arel/engines/sql/unit/relations/group_spec.rb", - "spec/arel/engines/sql/unit/relations/insert_spec.rb", - "spec/arel/engines/sql/unit/relations/join_spec.rb", - "spec/arel/engines/sql/unit/relations/order_spec.rb", - "spec/arel/engines/sql/unit/relations/project_spec.rb", - "spec/arel/engines/sql/unit/relations/skip_spec.rb", - "spec/arel/engines/sql/unit/relations/table_spec.rb", - "spec/arel/engines/sql/unit/relations/take_spec.rb", - "spec/arel/engines/sql/unit/relations/update_spec.rb", - "spec/arel/engines/sql/unit/relations/where_spec.rb", - "spec/connections/mysql_connection.rb", - "spec/connections/postgresql_connection.rb", - "spec/connections/sqlite3_connection.rb", - "spec/doubles/hash.rb", - "spec/matchers/be_like.rb", - "spec/matchers/disambiguate_attributes.rb", - "spec/matchers/hash_the_same_as.rb", - "spec/schemas/mysql_schema.rb", - "spec/schemas/postgresql_schema.rb", - "spec/schemas/sqlite3_schema.rb", - "spec/spec_helper.rb" + ".gitmodules", + "README.markdown", + "Rakefile", + "Thorfile", + "arel.gemspec", + "doc/CONVENTIONS", + "doc/TODO", + "lib/arel.rb", + "lib/arel/algebra.rb", + "lib/arel/algebra/attribute.rb", + "lib/arel/algebra/core_extensions.rb", + "lib/arel/algebra/core_extensions/class.rb", + "lib/arel/algebra/core_extensions/hash.rb", + "lib/arel/algebra/core_extensions/object.rb", + "lib/arel/algebra/core_extensions/symbol.rb", + "lib/arel/algebra/expression.rb", + "lib/arel/algebra/ordering.rb", + "lib/arel/algebra/predicates.rb", + "lib/arel/algebra/relations.rb", + "lib/arel/algebra/relations/operations/alias.rb", + "lib/arel/algebra/relations/operations/group.rb", + "lib/arel/algebra/relations/operations/join.rb", + "lib/arel/algebra/relations/operations/order.rb", + "lib/arel/algebra/relations/operations/project.rb", + "lib/arel/algebra/relations/operations/skip.rb", + "lib/arel/algebra/relations/operations/take.rb", + "lib/arel/algebra/relations/operations/where.rb", + "lib/arel/algebra/relations/relation.rb", + "lib/arel/algebra/relations/row.rb", + "lib/arel/algebra/relations/utilities/compound.rb", + "lib/arel/algebra/relations/utilities/externalization.rb", + "lib/arel/algebra/relations/utilities/nil.rb", + "lib/arel/algebra/relations/writes.rb", + "lib/arel/algebra/value.rb", + "lib/arel/engines.rb", + "lib/arel/engines/memory.rb", + "lib/arel/engines/memory/engine.rb", + "lib/arel/engines/memory/predicates.rb", + "lib/arel/engines/memory/primitives.rb", + "lib/arel/engines/memory/relations.rb", + "lib/arel/engines/memory/relations/array.rb", + "lib/arel/engines/memory/relations/compound.rb", + "lib/arel/engines/memory/relations/operations.rb", + "lib/arel/engines/memory/relations/writes.rb", + "lib/arel/engines/sql.rb", + "lib/arel/engines/sql/christener.rb", + "lib/arel/engines/sql/core_extensions.rb", + "lib/arel/engines/sql/core_extensions/array.rb", + "lib/arel/engines/sql/core_extensions/nil_class.rb", + "lib/arel/engines/sql/core_extensions/object.rb", + "lib/arel/engines/sql/core_extensions/range.rb", + "lib/arel/engines/sql/engine.rb", + "lib/arel/engines/sql/formatters.rb", + "lib/arel/engines/sql/predicates.rb", + "lib/arel/engines/sql/primitives.rb", + "lib/arel/engines/sql/relations.rb", + "lib/arel/engines/sql/relations/operations/alias.rb", + "lib/arel/engines/sql/relations/operations/join.rb", + "lib/arel/engines/sql/relations/relation.rb", + "lib/arel/engines/sql/relations/table.rb", + "lib/arel/engines/sql/relations/utilities/compound.rb", + "lib/arel/engines/sql/relations/utilities/externalization.rb", + "lib/arel/engines/sql/relations/utilities/nil.rb", + "lib/arel/engines/sql/relations/utilities/recursion.rb", + "lib/arel/engines/sql/relations/writes.rb", + "lib/arel/session.rb", + "spec/arel/algebra/unit/predicates/binary_spec.rb", + "spec/arel/algebra/unit/predicates/equality_spec.rb", + "spec/arel/algebra/unit/predicates/in_spec.rb", + "spec/arel/algebra/unit/primitives/attribute_spec.rb", + "spec/arel/algebra/unit/primitives/expression_spec.rb", + "spec/arel/algebra/unit/primitives/value_spec.rb", + "spec/arel/algebra/unit/relations/alias_spec.rb", + "spec/arel/algebra/unit/relations/delete_spec.rb", + "spec/arel/algebra/unit/relations/group_spec.rb", + "spec/arel/algebra/unit/relations/insert_spec.rb", + "spec/arel/algebra/unit/relations/join_spec.rb", + "spec/arel/algebra/unit/relations/order_spec.rb", + "spec/arel/algebra/unit/relations/project_spec.rb", + "spec/arel/algebra/unit/relations/relation_spec.rb", + "spec/arel/algebra/unit/relations/skip_spec.rb", + "spec/arel/algebra/unit/relations/table_spec.rb", + "spec/arel/algebra/unit/relations/take_spec.rb", + "spec/arel/algebra/unit/relations/update_spec.rb", + "spec/arel/algebra/unit/relations/where_spec.rb", + "spec/arel/algebra/unit/session/session_spec.rb", + "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", + "spec/arel/engines/memory/unit/relations/array_spec.rb", + "spec/arel/engines/memory/unit/relations/insert_spec.rb", + "spec/arel/engines/memory/unit/relations/join_spec.rb", + "spec/arel/engines/memory/unit/relations/order_spec.rb", + "spec/arel/engines/memory/unit/relations/project_spec.rb", + "spec/arel/engines/memory/unit/relations/skip_spec.rb", + "spec/arel/engines/memory/unit/relations/take_spec.rb", + "spec/arel/engines/memory/unit/relations/where_spec.rb", + "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", + "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", + "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", + "spec/arel/engines/sql/unit/engine_spec.rb", + "spec/arel/engines/sql/unit/predicates/binary_spec.rb", + "spec/arel/engines/sql/unit/predicates/equality_spec.rb", + "spec/arel/engines/sql/unit/predicates/in_spec.rb", + "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", + "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", + "spec/arel/engines/sql/unit/primitives/expression_spec.rb", + "spec/arel/engines/sql/unit/primitives/literal_spec.rb", + "spec/arel/engines/sql/unit/primitives/value_spec.rb", + "spec/arel/engines/sql/unit/relations/alias_spec.rb", + "spec/arel/engines/sql/unit/relations/delete_spec.rb", + "spec/arel/engines/sql/unit/relations/group_spec.rb", + "spec/arel/engines/sql/unit/relations/insert_spec.rb", + "spec/arel/engines/sql/unit/relations/join_spec.rb", + "spec/arel/engines/sql/unit/relations/order_spec.rb", + "spec/arel/engines/sql/unit/relations/project_spec.rb", + "spec/arel/engines/sql/unit/relations/skip_spec.rb", + "spec/arel/engines/sql/unit/relations/table_spec.rb", + "spec/arel/engines/sql/unit/relations/take_spec.rb", + "spec/arel/engines/sql/unit/relations/update_spec.rb", + "spec/arel/engines/sql/unit/relations/where_spec.rb", + "spec/connections/mysql_connection.rb", + "spec/connections/postgresql_connection.rb", + "spec/connections/sqlite3_connection.rb", + "spec/doubles/hash.rb", + "spec/matchers/be_like.rb", + "spec/matchers/disambiguate_attributes.rb", + "spec/matchers/hash_the_same_as.rb", + "spec/schemas/mysql_schema.rb", + "spec/schemas/postgresql_schema.rb", + "spec/schemas/sqlite3_schema.rb", + "spec/spec.opts", + "spec/spec_helper.rb" ] s.homepage = %q{http://github.com/brynary/arel} - s.rdoc_options = ["--charset=UTF-8"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.3.4} + s.rubygems_version = %q{1.3.5} s.summary = %q{Arel is a relational algebra engine for Ruby} s.test_files = [ "spec/arel/algebra/unit/predicates/binary_spec.rb", - "spec/arel/algebra/unit/predicates/equality_spec.rb", - "spec/arel/algebra/unit/predicates/in_spec.rb", - "spec/arel/algebra/unit/primitives/attribute_spec.rb", - "spec/arel/algebra/unit/primitives/expression_spec.rb", - "spec/arel/algebra/unit/primitives/value_spec.rb", - "spec/arel/algebra/unit/relations/alias_spec.rb", - "spec/arel/algebra/unit/relations/delete_spec.rb", - "spec/arel/algebra/unit/relations/group_spec.rb", - "spec/arel/algebra/unit/relations/insert_spec.rb", - "spec/arel/algebra/unit/relations/join_spec.rb", - "spec/arel/algebra/unit/relations/order_spec.rb", - "spec/arel/algebra/unit/relations/project_spec.rb", - "spec/arel/algebra/unit/relations/relation_spec.rb", - "spec/arel/algebra/unit/relations/skip_spec.rb", - "spec/arel/algebra/unit/relations/table_spec.rb", - "spec/arel/algebra/unit/relations/take_spec.rb", - "spec/arel/algebra/unit/relations/update_spec.rb", - "spec/arel/algebra/unit/relations/where_spec.rb", - "spec/arel/algebra/unit/session/session_spec.rb", - "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", - "spec/arel/engines/memory/unit/relations/array_spec.rb", - "spec/arel/engines/memory/unit/relations/insert_spec.rb", - "spec/arel/engines/memory/unit/relations/join_spec.rb", - "spec/arel/engines/memory/unit/relations/order_spec.rb", - "spec/arel/engines/memory/unit/relations/project_spec.rb", - "spec/arel/engines/memory/unit/relations/skip_spec.rb", - "spec/arel/engines/memory/unit/relations/take_spec.rb", - "spec/arel/engines/memory/unit/relations/where_spec.rb", - "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", - "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", - "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", - "spec/arel/engines/sql/unit/engine_spec.rb", - "spec/arel/engines/sql/unit/predicates/binary_spec.rb", - "spec/arel/engines/sql/unit/predicates/equality_spec.rb", - "spec/arel/engines/sql/unit/predicates/in_spec.rb", - "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", - "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", - "spec/arel/engines/sql/unit/primitives/expression_spec.rb", - "spec/arel/engines/sql/unit/primitives/literal_spec.rb", - "spec/arel/engines/sql/unit/primitives/value_spec.rb", - "spec/arel/engines/sql/unit/relations/alias_spec.rb", - "spec/arel/engines/sql/unit/relations/delete_spec.rb", - "spec/arel/engines/sql/unit/relations/group_spec.rb", - "spec/arel/engines/sql/unit/relations/insert_spec.rb", - "spec/arel/engines/sql/unit/relations/join_spec.rb", - "spec/arel/engines/sql/unit/relations/order_spec.rb", - "spec/arel/engines/sql/unit/relations/project_spec.rb", - "spec/arel/engines/sql/unit/relations/skip_spec.rb", - "spec/arel/engines/sql/unit/relations/table_spec.rb", - "spec/arel/engines/sql/unit/relations/take_spec.rb", - "spec/arel/engines/sql/unit/relations/update_spec.rb", - "spec/arel/engines/sql/unit/relations/where_spec.rb", - "spec/connections/mysql_connection.rb", - "spec/connections/postgresql_connection.rb", - "spec/connections/sqlite3_connection.rb", - "spec/doubles/hash.rb", - "spec/matchers/be_like.rb", - "spec/matchers/disambiguate_attributes.rb", - "spec/matchers/hash_the_same_as.rb", - "spec/schemas/mysql_schema.rb", - "spec/schemas/postgresql_schema.rb", - "spec/schemas/sqlite3_schema.rb", - "spec/spec_helper.rb" + "spec/arel/algebra/unit/predicates/equality_spec.rb", + "spec/arel/algebra/unit/predicates/in_spec.rb", + "spec/arel/algebra/unit/primitives/attribute_spec.rb", + "spec/arel/algebra/unit/primitives/expression_spec.rb", + "spec/arel/algebra/unit/primitives/value_spec.rb", + "spec/arel/algebra/unit/relations/alias_spec.rb", + "spec/arel/algebra/unit/relations/delete_spec.rb", + "spec/arel/algebra/unit/relations/group_spec.rb", + "spec/arel/algebra/unit/relations/insert_spec.rb", + "spec/arel/algebra/unit/relations/join_spec.rb", + "spec/arel/algebra/unit/relations/order_spec.rb", + "spec/arel/algebra/unit/relations/project_spec.rb", + "spec/arel/algebra/unit/relations/relation_spec.rb", + "spec/arel/algebra/unit/relations/skip_spec.rb", + "spec/arel/algebra/unit/relations/table_spec.rb", + "spec/arel/algebra/unit/relations/take_spec.rb", + "spec/arel/algebra/unit/relations/update_spec.rb", + "spec/arel/algebra/unit/relations/where_spec.rb", + "spec/arel/algebra/unit/session/session_spec.rb", + "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", + "spec/arel/engines/memory/unit/relations/array_spec.rb", + "spec/arel/engines/memory/unit/relations/insert_spec.rb", + "spec/arel/engines/memory/unit/relations/join_spec.rb", + "spec/arel/engines/memory/unit/relations/order_spec.rb", + "spec/arel/engines/memory/unit/relations/project_spec.rb", + "spec/arel/engines/memory/unit/relations/skip_spec.rb", + "spec/arel/engines/memory/unit/relations/take_spec.rb", + "spec/arel/engines/memory/unit/relations/where_spec.rb", + "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", + "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", + "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", + "spec/arel/engines/sql/unit/engine_spec.rb", + "spec/arel/engines/sql/unit/predicates/binary_spec.rb", + "spec/arel/engines/sql/unit/predicates/equality_spec.rb", + "spec/arel/engines/sql/unit/predicates/in_spec.rb", + "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", + "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", + "spec/arel/engines/sql/unit/primitives/expression_spec.rb", + "spec/arel/engines/sql/unit/primitives/literal_spec.rb", + "spec/arel/engines/sql/unit/primitives/value_spec.rb", + "spec/arel/engines/sql/unit/relations/alias_spec.rb", + "spec/arel/engines/sql/unit/relations/delete_spec.rb", + "spec/arel/engines/sql/unit/relations/group_spec.rb", + "spec/arel/engines/sql/unit/relations/insert_spec.rb", + "spec/arel/engines/sql/unit/relations/join_spec.rb", + "spec/arel/engines/sql/unit/relations/order_spec.rb", + "spec/arel/engines/sql/unit/relations/project_spec.rb", + "spec/arel/engines/sql/unit/relations/skip_spec.rb", + "spec/arel/engines/sql/unit/relations/table_spec.rb", + "spec/arel/engines/sql/unit/relations/take_spec.rb", + "spec/arel/engines/sql/unit/relations/update_spec.rb", + "spec/arel/engines/sql/unit/relations/where_spec.rb", + "spec/connections/mysql_connection.rb", + "spec/connections/postgresql_connection.rb", + "spec/connections/sqlite3_connection.rb", + "spec/doubles/hash.rb", + "spec/matchers/be_like.rb", + "spec/matchers/disambiguate_attributes.rb", + "spec/matchers/hash_the_same_as.rb", + "spec/schemas/mysql_schema.rb", + "spec/schemas/postgresql_schema.rb", + "spec/schemas/sqlite3_schema.rb", + "spec/spec_helper.rb" ] if s.respond_to? :specification_version then @@ -225,8 +227,14 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q, [">= 3.0pre"]) + s.add_runtime_dependency(%q, [">= 3.0pre"]) else + s.add_dependency(%q, [">= 3.0pre"]) + s.add_dependency(%q, [">= 3.0pre"]) end else + s.add_dependency(%q, [">= 3.0pre"]) + s.add_dependency(%q, [">= 3.0pre"]) end end From 42aa39bf7127a554e44091b1b86e549c8515b843 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 Oct 2009 20:19:41 -0400 Subject: [PATCH 0298/1492] Don't declare ActiveRecord gem dependency for now --- Thorfile | 5 ++++- arel.gemspec | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Thorfile b/Thorfile index edc39a16b0de7..982a959e828f6 100644 --- a/Thorfile +++ b/Thorfile @@ -29,7 +29,10 @@ and query generation. s.has_rdoc = true s.extra_rdoc_files = %w[README.markdown] - s.add_dependency "activerecord", ">= 3.0pre" + # Arel required ActiveRecord, but we're not declaring it to avoid a + # circular dependency chain. The solution is for ActiveRecord to release + # the connection adapters which Arel uses in a separate gem + # s.add_dependency "activerecord", ">= 3.0pre" s.add_dependency "activesupport", ">= 3.0pre" end end diff --git a/arel.gemspec b/arel.gemspec index a7dbeca51de7b..9bd483938df20 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -227,14 +227,11 @@ and query generation.} s.specification_version = 3 if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 3.0pre"]) s.add_runtime_dependency(%q, [">= 3.0pre"]) else - s.add_dependency(%q, [">= 3.0pre"]) s.add_dependency(%q, [">= 3.0pre"]) end else - s.add_dependency(%q, [">= 3.0pre"]) s.add_dependency(%q, [">= 3.0pre"]) end end From a923cf7fed1e477638d29aa870bef83bb180ad29 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 Oct 2009 20:22:36 -0400 Subject: [PATCH 0299/1492] Correct version number for prerelease Rails components. Note the additional period --- Thorfile | 4 ++-- arel.gemspec | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Thorfile b/Thorfile index 982a959e828f6..ac6f5a0cb2c68 100644 --- a/Thorfile +++ b/Thorfile @@ -32,8 +32,8 @@ and query generation. # Arel required ActiveRecord, but we're not declaring it to avoid a # circular dependency chain. The solution is for ActiveRecord to release # the connection adapters which Arel uses in a separate gem - # s.add_dependency "activerecord", ">= 3.0pre" - s.add_dependency "activesupport", ">= 3.0pre" + # s.add_dependency "activerecord", ">= 3.0.pre" + s.add_dependency "activesupport", ">= 3.0.pre" end end diff --git a/arel.gemspec b/arel.gemspec index 9bd483938df20..cd45224218ce0 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -227,11 +227,11 @@ and query generation.} s.specification_version = 3 if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 3.0pre"]) + s.add_runtime_dependency(%q, [">= 3.0.pre"]) else - s.add_dependency(%q, [">= 3.0pre"]) + s.add_dependency(%q, [">= 3.0.pre"]) end else - s.add_dependency(%q, [">= 3.0pre"]) + s.add_dependency(%q, [">= 3.0.pre"]) end end From 19d7ee3661a395b69d8ea233096da33bde166b62 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 Oct 2009 20:32:10 -0400 Subject: [PATCH 0300/1492] Need to add Rails components to $LOAD_PATH to require "arel" reliably --- Thorfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Thorfile b/Thorfile index ac6f5a0cb2c68..0ef929847fa57 100644 --- a/Thorfile +++ b/Thorfile @@ -1,6 +1,9 @@ module GemHelpers def generate_gemspec + $LOAD_PATH << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" + $LOAD_PATH << "#{File.dirname(__FILE__)}/vendor/rails/activesupport/lib" + $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib"))) require "arel" From 567a14205d5a17e7cffc012bcc8c1132da99124c Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Tue, 3 Nov 2009 00:21:51 -0800 Subject: [PATCH 0301/1492] Spoof a version bump to work around Bundler using gem instead of git checkout --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index cd45224218ce0..8fedc9a25f7ac 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.1.2" + s.version = "0.1.3" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen"] From 976999cb980eb47ac5f297de043e2ed55248c2a5 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 9 Nov 2009 19:24:40 -0500 Subject: [PATCH 0302/1492] Ruby 1.9: the constants must be qualified --- spec/arel/algebra/unit/predicates/binary_spec.rb | 2 +- spec/arel/algebra/unit/predicates/equality_spec.rb | 4 ++-- spec/arel/engines/sql/unit/predicates/binary_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/equality_spec.rb | 4 ++-- spec/arel/engines/sql/unit/predicates/in_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/predicates_spec.rb | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb index be4c1ac738ab9..051aeeeb6e0c6 100644 --- a/spec/arel/algebra/unit/predicates/binary_spec.rb +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -4,7 +4,7 @@ module Arel module Predicates describe Binary do before do - @relation = Table.new(:users) + @relation = Arel::Table.new(:users) @attribute1 = @relation[:id] @attribute2 = @relation[:name] class ConcreteBinary < Binary diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb index cfd04cd90c80a..7d1d79ff35475 100644 --- a/spec/arel/algebra/unit/predicates/equality_spec.rb +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -4,8 +4,8 @@ module Arel module Predicates describe Equality do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) + @relation1 = Arel::Table.new(:users) + @relation2 = Arel::Table.new(:photos) @attribute1 = @relation1[:id] @attribute2 = @relation2[:user_id] end diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 23bce5479231b..08f3310f8e01e 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -10,7 +10,7 @@ def predicate_sql end before do - @relation = Table.new(:users) + @relation = Arel::Table.new(:users) @attribute1 = @relation[:id] @attribute2 = @relation[:name] end diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index 4004bb58813cb..7a5cb42c85de6 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -4,8 +4,8 @@ module Arel module Predicates describe Equality do before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) + @relation1 = Arel::Table.new(:users) + @relation2 = Arel::Table.new(:photos) @attribute1 = @relation1[:id] @attribute2 = @relation2[:user_id] end diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index bb00733e6070f..691abcb2d2188 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -4,7 +4,7 @@ module Arel module Predicates describe In do before do - @relation = Table.new(:users) + @relation = Arel::Table.new(:users) @attribute = @relation[:id] end diff --git a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb index 7d533515469e7..81c348357ce38 100644 --- a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb @@ -4,11 +4,11 @@ module Arel module Predicates describe Predicate do before do - @relation = Table.new(:users) + @relation = Arel::Table.new(:users) @attribute1 = @relation[:id] @attribute2 = @relation[:name] - @operand1 = Equality.new(@attribute1, 1) - @operand2 = Equality.new(@attribute2, "name") + @operand1 = Arel::Predicates::Equality.new(@attribute1, 1) + @operand2 = Arel::Predicates::Equality.new(@attribute2, "name") end describe "when being combined with another predicate with AND logic" do From 130188e67ce76e4ced60dc0331d2ac5bba6cdb74 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 9 Nov 2009 19:31:53 -0500 Subject: [PATCH 0303/1492] Switch from rr to RSpec mocks. rr has issues on 1.9.2pre --- spec/arel/algebra/unit/relations/relation_spec.rb | 6 +++--- spec/arel/algebra/unit/session/session_spec.rb | 10 +++++----- spec/arel/engines/sql/unit/relations/table_spec.rb | 4 ++-- spec/spec_helper.rb | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 35ce8bf1fb7c2..6bd7970e3f6c2 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -150,7 +150,7 @@ module Arel describe '#delete' do it 'manufactures a deletion relation' do Session.start do - mock(Session.new).delete(Deletion.new(@relation)) + Session.new.should_receive(:delete).with(Deletion.new(@relation)) @relation.delete end end @@ -160,7 +160,7 @@ module Arel it 'manufactures an insertion relation' do Session.start do record = { @relation[:name] => 'carl' } - mock(Session.new).create(Insert.new(@relation, record)) + Session.new.should_receive(:create).with(Insert.new(@relation, record)) @relation.insert(record) end end @@ -170,7 +170,7 @@ module Arel it 'manufactures an update relation' do Session.start do assignments = { @relation[:name] => Value.new('bob', @relation) } - mock(Session.new).update(Update.new(@relation, assignments)) + Session.new.should_receive(:update).with(Update.new(@relation, assignments)) @relation.update(assignments) end end diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/arel/algebra/unit/session/session_spec.rb index 03aab6a03fbad..0553a140ecfe2 100644 --- a/spec/arel/algebra/unit/session/session_spec.rb +++ b/spec/arel/algebra/unit/session/session_spec.rb @@ -40,19 +40,19 @@ module Arel describe '#create' do it "executes an insertion on the connection" do - mock(@insert).call + @insert.should_receive(:call) @session.create(@insert) end end describe '#read' do it "executes an selection on the connection" do - mock(@read).call + @read.should_receive(:call) @session.read(@read) end it "is memoized" do - mock(@read).call.once + @read.should_receive(:call).once @session.read(@read) @session.read(@read) end @@ -60,14 +60,14 @@ module Arel describe '#update' do it "executes an update on the connection" do - mock(@update).call + @update.should_receive(:call) @session.update(@update) end end describe '#delete' do it "executes a delete on the connection" do - mock(@delete).call + @delete.should_receive(:call) @session.delete(@delete) end end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 26b9364929822..92e45490289a1 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -42,8 +42,8 @@ module Arel describe '#reset' do it "reloads columns from the database" do - lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } - lambda { @relation.reset }.should change { @relation.attributes } + lambda { @relation.engine.stub!(:columns => []) }.should_not change { @relation.attributes } + lambda { @relation.reset }.should change { @relation.attributes } end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7d61fc9120e0f..6d99fa40385b6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,7 +48,7 @@ def check(*args) config.include BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher config.include AdapterGuards config.include Check - config.mock_with :rr + config.before do Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) end From 2eea340b2269aab85cead2a5e024d6ff9abd6c91 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 9 Nov 2009 19:37:00 -0500 Subject: [PATCH 0304/1492] Ruby 1.9: Improve the way we spec this --- spec/arel/algebra/unit/relations/relation_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 6bd7970e3f6c2..cf6509fe6aa35 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -180,8 +180,8 @@ module Arel describe Relation::Enumerable do it "implements enumerable" do - check @relation.collect.should == @relation.session.read(@relation).collect - @relation.first.should == @relation.session.read(@relation).first + @relation.map { |value| value }.should == + @relation.session.read(@relation).map { |value| value } end end end From 34e35c7cbc9f378564bf1dd0d6d29553dc59534e Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 9 Nov 2009 19:38:44 -0500 Subject: [PATCH 0305/1492] Rake check_dependencies is dead. Don't try to run it --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index e1557bda70088..fba44e620f6af 100644 --- a/Rakefile +++ b/Rakefile @@ -36,7 +36,7 @@ else end desc "Run specs with mysql and sqlite3 database adapters (default)" - task :spec => ["check_dependencies", "spec:sqlite3", "spec:mysql", "spec:postgresql"] + task :spec => ["spec:sqlite3", "spec:mysql", "spec:postgresql"] desc "Default task is to run specs" task :default => :spec From 4dcfe6786e5fe72c27cadc5c0ee18aa6a67ba2bd Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 9 Nov 2009 19:49:51 -0500 Subject: [PATCH 0306/1492] Ruby 1.9: Sort attributes deterministically so specs always pass --- lib/arel/engines/sql/relations/writes.rb | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 42496ef73587f..50fcb8e07e58d 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -14,8 +14,19 @@ def to_sql insertion_attributes_values_sql = if record.is_a?(Value) record.value else - build_query "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + attributes = record.keys.sort_by do |attribute| + attribute.name.to_s + end + + first = attributes.collect do |key| + engine.quote_column_name(key.name) + end.join(', ') + + second = attributes.collect do |key| + key.format(record[key]) + end.join(', ') + + build_query "(#{first})", "VALUES (#{second})" end build_query \ @@ -37,7 +48,12 @@ def to_sql def assignment_sql if assignments.respond_to?(:collect) - assignments.collect do |attribute, value| + attributes = assignments.keys.sort_by do |attribute| + attribute.name.to_s + end + + attributes.map do |attribute| + value = assignments[attribute] "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" end.join(",\n") else From 9544bb6c8cadd02cf7d7fa845a7682f4efbec89c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 10 Nov 2009 15:02:57 -0500 Subject: [PATCH 0307/1492] History --- History.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 History.txt diff --git a/History.txt b/History.txt new file mode 100644 index 0000000000000..acfff6c6065e8 --- /dev/null +++ b/History.txt @@ -0,0 +1,11 @@ +== Git + +* 1 major enhancement + + * Ruby 1.9 compatibility + +== 0.1.0 / 2009-08-06 + +* 1 major enhancement + + * Birthday! From 627bce9740531ca107d16ac62273b4acdfab7fbf Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 10 Nov 2009 15:04:24 -0500 Subject: [PATCH 0308/1492] This is 0.2.pre now --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index a9fe15c8247a0..30b2741eae8d0 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -10,5 +10,5 @@ module Arel require 'arel/engines' autoload :Session, 'arel/session' - VERSION = "0.1.2" + VERSION = "0.2.pre" end \ No newline at end of file From 3dbdaa399f1a15b5f6e770057342164a6deb9040 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 10 Nov 2009 15:04:54 -0500 Subject: [PATCH 0309/1492] Add History.txt to RDoc --- Thorfile | 2 +- arel.gemspec | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Thorfile b/Thorfile index 0ef929847fa57..a3cce295417a7 100644 --- a/Thorfile +++ b/Thorfile @@ -30,7 +30,7 @@ and query generation. s.test_files = normalize_files(Dir['spec/**/*.rb'] - repo.lib.ignored_files) s.has_rdoc = true - s.extra_rdoc_files = %w[README.markdown] + s.extra_rdoc_files = %w[History.txt README.markdown] # Arel required ActiveRecord, but we're not declaring it to avoid a # circular dependency chain. The solution is for ActiveRecord to release diff --git a/arel.gemspec b/arel.gemspec index 8fedc9a25f7ac..44128adc6388b 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.1.3" + s.version = "0.2.pre" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen"] - s.date = %q{2009-10-27} + s.date = %q{2009-11-10} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 @@ -14,11 +14,13 @@ innovative object and collection modeling as opposed to database compatibility and query generation.} s.email = %q{bryan@brynary.com} s.extra_rdoc_files = [ + "History.txt", "README.markdown" ] s.files = [ ".gitignore", ".gitmodules", + "History.txt", "README.markdown", "Rakefile", "Thorfile", From 0faeb5047407348533db952d9cf93ea59d2526dc Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 10 Nov 2009 15:23:54 -0500 Subject: [PATCH 0310/1492] Ruby 1.9: Array#to_s behaves like inspect now, so we don't want to use it here (needs spec!) --- lib/arel/engines/sql/relations/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 2edbe6a5f7597..b8f384a4c10d5 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -12,7 +12,7 @@ def select_sql order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') query = build_query \ - "SELECT #{select_clauses.to_s}", + "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), From a5e3ac2c2d20ea1335a1aa48e6813272a39bc3d3 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 26 Dec 2009 16:42:57 -0300 Subject: [PATCH 0311/1492] Don't split sql logging across multiple lines. --- lib/arel/engines/sql/relations/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index b8f384a4c10d5..deca9b19cbf75 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -48,7 +48,7 @@ def christener protected def build_query(*parts) - parts.compact.join("\n") + parts.compact.join(" ") end def select_clauses From 49a8c7bd5168ca84897166527f5c0d90126dc402 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 27 Dec 2009 16:38:32 -0300 Subject: [PATCH 0312/1492] Added "from" method, allowing to specify custom from clauses. --- lib/arel/algebra/relations.rb | 1 + lib/arel/algebra/relations/operations/from.rb | 6 +++ lib/arel/algebra/relations/relation.rb | 3 +- .../algebra/relations/utilities/compound.rb | 2 +- .../engines/memory/relations/operations.rb | 6 +++ lib/arel/engines/sql/formatters.rb | 4 ++ lib/arel/engines/sql/relations/relation.rb | 8 ++- .../engines/sql/unit/relations/from_spec.rb | 50 +++++++++++++++++++ 8 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 lib/arel/algebra/relations/operations/from.rb create mode 100644 spec/arel/engines/sql/unit/relations/from_spec.rb diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index f9fa24ba25463..cee308299b59f 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -5,6 +5,7 @@ require 'arel/algebra/relations/row' require 'arel/algebra/relations/writes' require 'arel/algebra/relations/operations/alias' +require 'arel/algebra/relations/operations/from' require 'arel/algebra/relations/operations/group' require 'arel/algebra/relations/operations/join' require 'arel/algebra/relations/operations/order' diff --git a/lib/arel/algebra/relations/operations/from.rb b/lib/arel/algebra/relations/operations/from.rb new file mode 100644 index 0000000000000..6bfd68dfc9665 --- /dev/null +++ b/lib/arel/algebra/relations/operations/from.rb @@ -0,0 +1,6 @@ +module Arel + class From < Compound + attributes :relation, :sources + deriving :initialize, :== + end +end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 5403e40faeca1..2ce3fdcce8711 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -43,7 +43,7 @@ def outer_join(other_relation = nil) join(other_relation, OuterJoin) end - [:where, :project, :order, :take, :skip, :group].each do |operation_name| + [:where, :project, :order, :take, :skip, :group, :from].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments, &block) arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) @@ -130,6 +130,7 @@ def groupings; [] end def joins(formatter = nil); nil end # FIXME def taken; nil end def skipped; nil end + def sources; [] end end include DefaultOperations end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 5e775618f1492..06bfce4ac0c6c 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, + :column_for, :engine, :sources, :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 8e019383603a0..a5082715a1aff 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -32,6 +32,12 @@ def eval end end + class From < Compound + def eval + unoperated_rows[sources..-1] + end + end + class Group < Compound def eval raise NotImplementedError diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 626803a887214..a13e11f24fbd8 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -98,6 +98,10 @@ def table(table) (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') end end + + def attribute(attribute) + attribute + end end class Attribute < WhereCondition diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index deca9b19cbf75..448cf7951da8f 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -13,7 +13,7 @@ def select_sql query = build_query \ "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", - "FROM #{table_sql(Sql::TableReference.new(self))}", + "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ) @@ -27,7 +27,7 @@ def select_sql else build_query \ "SELECT #{select_clauses.join(', ')}", - "FROM #{table_sql(Sql::TableReference.new(self))}", + "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), @@ -51,6 +51,10 @@ def build_query(*parts) parts.compact.join(" ") end + def from_clauses + sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources + end + def select_clauses attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } end diff --git a/spec/arel/engines/sql/unit/relations/from_spec.rb b/spec/arel/engines/sql/unit/relations/from_spec.rb new file mode 100644 index 0000000000000..a611cd65f440e --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/from_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +module Arel + describe Table do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "manufactures a simple select query" do + sql = @relation.from("workers").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM workers + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM workers + }) + end + end + end + + describe '#to_sql' do + it "overrides and use last from clause given " do + sql = @relation.from("workers").from("users").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM users + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM users + }) + end + end + end + + end +end From 82a519d623faf7cfb137b7ed079dc8ae872e2a7e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 27 Dec 2009 17:03:27 -0300 Subject: [PATCH 0313/1492] Removed useless attribute definition from TableReference. --- lib/arel/engines/sql/formatters.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index a13e11f24fbd8..626803a887214 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -98,10 +98,6 @@ def table(table) (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') end end - - def attribute(attribute) - attribute - end end class Attribute < WhereCondition From 3ea68bc6bde539f4391cc1b96999e16c25ca0801 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 27 Dec 2009 17:30:27 -0300 Subject: [PATCH 0314/1492] Don't split sql logging across multiple lines. --- lib/arel/engines/sql/relations/utilities/compound.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index f8ce4033fd122..b8b0e7d2691af 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -3,7 +3,7 @@ class Compound < Relation delegate :table, :table_sql, :to => :relation def build_query(*parts) - parts.compact.join("\n") + parts.compact.join(" ") end end end From b339caca2f3c7306c3944c5fc5d8dde17ae2deb8 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sun, 27 Dec 2009 18:04:35 -0300 Subject: [PATCH 0315/1492] Added lock to Arel, allowing a locking read if required. --- lib/arel/algebra/relations.rb | 1 + lib/arel/algebra/relations/operations/lock.rb | 12 +++++ lib/arel/algebra/relations/relation.rb | 5 ++ .../algebra/relations/utilities/compound.rb | 2 +- lib/arel/engines/sql/relations/relation.rb | 6 ++- .../engines/sql/unit/relations/lock_spec.rb | 47 +++++++++++++++++++ 6 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 lib/arel/algebra/relations/operations/lock.rb create mode 100644 spec/arel/engines/sql/unit/relations/lock_spec.rb diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index cee308299b59f..951b69d9702b4 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -13,3 +13,4 @@ require 'arel/algebra/relations/operations/where' require 'arel/algebra/relations/operations/skip' require 'arel/algebra/relations/operations/take' +require 'arel/algebra/relations/operations/lock' diff --git a/lib/arel/algebra/relations/operations/lock.rb b/lib/arel/algebra/relations/operations/lock.rb new file mode 100644 index 0000000000000..0d6c12e65bcc5 --- /dev/null +++ b/lib/arel/algebra/relations/operations/lock.rb @@ -0,0 +1,12 @@ +module Arel + class Lock < Compound + attributes :relation, :locked + deriving :initialize, :== + + def initialize(relation, locked, &block) + @relation = relation + @locked = locked.blank? ? " FOR UPDATE" : locked + end + end +end + diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 2ce3fdcce8711..b24e7c24d0dc2 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -51,6 +51,10 @@ def #{operation_name}(*arguments, &block) OPERATION end + def lock(locking = nil) + Lock.new(self, locking) + end + def alias Alias.new(self) end @@ -131,6 +135,7 @@ def joins(formatter = nil); nil end # FIXME def taken; nil end def skipped; nil end def sources; [] end + def locked; [] end end include DefaultOperations end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 06bfce4ac0c6c..9967472d88986 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :sources, + :column_for, :engine, :sources, :locked, :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 448cf7951da8f..8b71aa8c0459c 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -16,7 +16,8 @@ def select_sql "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ) + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("#{locked}" unless locked.blank? ) build_query \ "SELECT * FROM (#{query}) AS id_list", @@ -33,7 +34,8 @@ def select_sql ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) + ("OFFSET #{skipped}" unless skipped.blank? ), + ("#{locked}" unless locked.blank? ) end end diff --git a/spec/arel/engines/sql/unit/relations/lock_spec.rb b/spec/arel/engines/sql/unit/relations/lock_spec.rb new file mode 100644 index 0000000000000..27239eb1a8b1b --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/lock_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +module Arel + describe Lock do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "manufactures a simple select query lock" do + sql = @relation.lock.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` FOR UPDATE + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" FOR UPDATE + }) + end + end + + it "manufactures a select query locking with a given lock" do + sql = @relation.lock("LOCK IN SHARE MODE").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` LOCK IN SHARE MODE + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" LOCK IN SHARE MODE + }) + end + end + end + end +end From 4fe6bdf195336d54b082ca26b96c5294d8aae3d1 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 28 Dec 2009 10:45:11 -0300 Subject: [PATCH 0316/1492] Don't try to lock reads when using any SQLite adapter, it's redundant and may generate an invalid query. --- lib/arel/engines/sql/relations/relation.rb | 2 +- .../engines/sql/unit/relations/lock_spec.rb | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 8b71aa8c0459c..12b328151fc5f 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -35,7 +35,7 @@ def select_sql ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ), - ("#{locked}" unless locked.blank? ) + ("#{locked}" unless engine.adapter_name =~ /SQLite/ || locked.blank?) end end diff --git a/spec/arel/engines/sql/unit/relations/lock_spec.rb b/spec/arel/engines/sql/unit/relations/lock_spec.rb index 27239eb1a8b1b..23f8a9f577a8b 100644 --- a/spec/arel/engines/sql/unit/relations/lock_spec.rb +++ b/spec/arel/engines/sql/unit/relations/lock_spec.rb @@ -17,12 +17,19 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :postgresql do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" FOR UPDATE }) end + + adapter_is :sqlite3 do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + }) + end end it "manufactures a select query locking with a given lock" do @@ -35,12 +42,19 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :postgresql do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" LOCK IN SHARE MODE }) end + + adapter_is :sqlite3 do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + }) + end end end end From bd00a461e042a77aef48822040897467c544cd1a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 28 Dec 2009 12:58:30 -0300 Subject: [PATCH 0317/1492] Added having to use in combination with group to filter records. --- lib/arel/algebra/relations.rb | 1 + .../algebra/relations/operations/having.rb | 13 +++++++ lib/arel/algebra/relations/relation.rb | 3 +- .../algebra/relations/utilities/compound.rb | 2 +- lib/arel/engines/sql/formatters.rb | 6 ++++ lib/arel/engines/sql/relations/relation.rb | 6 ++++ .../engines/sql/unit/relations/having_spec.rb | 36 +++++++++++++++++++ spec/schemas/mysql_schema.rb | 7 ++++ spec/schemas/postgresql_schema.rb | 7 ++++ spec/schemas/sqlite3_schema.rb | 7 ++++ 10 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 lib/arel/algebra/relations/operations/having.rb create mode 100644 spec/arel/engines/sql/unit/relations/having_spec.rb diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index 951b69d9702b4..9481554667d64 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -7,6 +7,7 @@ require 'arel/algebra/relations/operations/alias' require 'arel/algebra/relations/operations/from' require 'arel/algebra/relations/operations/group' +require 'arel/algebra/relations/operations/having' require 'arel/algebra/relations/operations/join' require 'arel/algebra/relations/operations/order' require 'arel/algebra/relations/operations/project' diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb new file mode 100644 index 0000000000000..cd1653560954f --- /dev/null +++ b/lib/arel/algebra/relations/operations/having.rb @@ -0,0 +1,13 @@ +module Arel + class Having < Compound + attributes :relation, :havings + deriving :== + + def initialize(relation, *havings, &block) + @relation = relation + @havings = (havings + arguments_from_block(relation, &block)) \ + .collect { |g| g.bind(relation) } + end + end +end + diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index b24e7c24d0dc2..e848c8aa1c473 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -43,7 +43,7 @@ def outer_join(other_relation = nil) join(other_relation, OuterJoin) end - [:where, :project, :order, :take, :skip, :group, :from].each do |operation_name| + [:where, :project, :order, :take, :skip, :group, :from, :having].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments, &block) arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) @@ -131,6 +131,7 @@ def wheres; [] end def orders; [] end def inserts; [] end def groupings; [] end + def havings; [] end def joins(formatter = nil); nil end # FIXME def taken; nil end def skipped; nil end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 9967472d88986..1acf92fef8ec3 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -5,7 +5,7 @@ class Compound < Relation :column_for, :engine, :sources, :locked, :to => :relation - [:attributes, :wheres, :groupings, :orders].each do |operation_name| + [:attributes, :wheres, :groupings, :orders, :havings].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 626803a887214..e05dc3eb9359f 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -57,6 +57,12 @@ def attribute(attribute) end end + class HavingClause < PassThrough + def attribute(attribute) + attribute + end + end + class WhereCondition < Formatter def attribute(attribute) "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 12b328151fc5f..940f985358e09 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -17,6 +17,7 @@ def select_sql (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), ("#{locked}" unless locked.blank? ) build_query \ @@ -32,6 +33,7 @@ def select_sql (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ), @@ -69,6 +71,10 @@ def group_clauses groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } end + def having_clauses + havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } + end + def order_clauses orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } end diff --git a/spec/arel/engines/sql/unit/relations/having_spec.rb b/spec/arel/engines/sql/unit/relations/having_spec.rb new file mode 100644 index 0000000000000..dd170a256f8e9 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/having_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +module Arel + describe Having do + before do + @relation = Table.new(:developers) + end + + describe '#to_sql' do + describe 'when given a predicate' do + it "manufactures sql with where clause conditions" do + sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department` + FROM `developers` + GROUP BY `developers`.`department` + HAVING MIN(salary) > 1000 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department" + FROM "developers" + GROUP BY "developers"."department" + HAVING MIN(salary) > 1000 + }) + end + end + end + end + end +end + diff --git a/spec/schemas/mysql_schema.rb b/spec/schemas/mysql_schema.rb index dc2558fd6af8f..cb4c746776d6d 100644 --- a/spec/schemas/mysql_schema.rb +++ b/spec/schemas/mysql_schema.rb @@ -11,6 +11,13 @@ user_id INTEGER NOT NULL, camera_id INTEGER NOT NULL ); + DROP TABLE IF EXISTS developers; + CREATE TABLE developers ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + salary INTEGER NOT NULL, + department VARCHAR(255) NOT NULL + ); SQL sql.split(/;/).select(&:present?).each do |sql_statement| diff --git a/spec/schemas/postgresql_schema.rb b/spec/schemas/postgresql_schema.rb index 30fa665902308..8b7dac1c41bd1 100644 --- a/spec/schemas/postgresql_schema.rb +++ b/spec/schemas/postgresql_schema.rb @@ -11,6 +11,13 @@ user_id INTEGER NOT NULL, camera_id INTEGER NOT NULL ); + DROP TABLE IF EXISTS developers; + CREATE TABLE developers ( + id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255) NOT NULL, + salary INTEGER NOT NULL, + department VARCHAR(255) NOT NULL + ); SQL sql.split(/;/).select(&:present?).each do |sql_statement| diff --git a/spec/schemas/sqlite3_schema.rb b/spec/schemas/sqlite3_schema.rb index 94d224520e299..9dbb62428ec44 100644 --- a/spec/schemas/sqlite3_schema.rb +++ b/spec/schemas/sqlite3_schema.rb @@ -11,6 +11,13 @@ user_id INTEGER NOT NULL, camera_id INTEGER NOT NULL ); + DROP TABLE IF EXISTS developers; + CREATE TABLE developers ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + salary INTEGER NOT NULL, + department VARCHAR(255) NOT NULL + ); SQL sql.split(/;/).select(&:present?).each do |sql_statement| From 818f019711d448a62ee11569f5ca1ba0ddfb3c2c Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 29 Dec 2009 10:26:51 -0300 Subject: [PATCH 0318/1492] Attributes may be an Arel value which doesn't respond to aggregation?, don't test them. --- lib/arel/algebra/relations/operations/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 223d320e22ffa..a1140e91c184e 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -14,7 +14,7 @@ def attributes end def externalizable? - attributes.any?(&:aggregation?) or relation.externalizable? + attributes.any? { |a| a.respond_to?(:aggregation?) && a.aggregation? } || relation.externalizable? end end end From 333106ebe335294773b41999c79068d56e9867d7 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 29 Dec 2009 14:04:34 -0500 Subject: [PATCH 0319/1492] Update Gemspec --- arel.gemspec | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 44128adc6388b..a7ae71bd1d5df 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen"] - s.date = %q{2009-11-10} + s.date = %q{2009-12-29} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 @@ -40,8 +40,11 @@ and query generation.} "lib/arel/algebra/predicates.rb", "lib/arel/algebra/relations.rb", "lib/arel/algebra/relations/operations/alias.rb", + "lib/arel/algebra/relations/operations/from.rb", "lib/arel/algebra/relations/operations/group.rb", + "lib/arel/algebra/relations/operations/having.rb", "lib/arel/algebra/relations/operations/join.rb", + "lib/arel/algebra/relations/operations/lock.rb", "lib/arel/algebra/relations/operations/order.rb", "lib/arel/algebra/relations/operations/project.rb", "lib/arel/algebra/relations/operations/skip.rb", @@ -129,9 +132,12 @@ and query generation.} "spec/arel/engines/sql/unit/primitives/value_spec.rb", "spec/arel/engines/sql/unit/relations/alias_spec.rb", "spec/arel/engines/sql/unit/relations/delete_spec.rb", + "spec/arel/engines/sql/unit/relations/from_spec.rb", "spec/arel/engines/sql/unit/relations/group_spec.rb", + "spec/arel/engines/sql/unit/relations/having_spec.rb", "spec/arel/engines/sql/unit/relations/insert_spec.rb", "spec/arel/engines/sql/unit/relations/join_spec.rb", + "spec/arel/engines/sql/unit/relations/lock_spec.rb", "spec/arel/engines/sql/unit/relations/order_spec.rb", "spec/arel/engines/sql/unit/relations/project_spec.rb", "spec/arel/engines/sql/unit/relations/skip_spec.rb", @@ -201,9 +207,12 @@ and query generation.} "spec/arel/engines/sql/unit/primitives/value_spec.rb", "spec/arel/engines/sql/unit/relations/alias_spec.rb", "spec/arel/engines/sql/unit/relations/delete_spec.rb", + "spec/arel/engines/sql/unit/relations/from_spec.rb", "spec/arel/engines/sql/unit/relations/group_spec.rb", + "spec/arel/engines/sql/unit/relations/having_spec.rb", "spec/arel/engines/sql/unit/relations/insert_spec.rb", "spec/arel/engines/sql/unit/relations/join_spec.rb", + "spec/arel/engines/sql/unit/relations/lock_spec.rb", "spec/arel/engines/sql/unit/relations/order_spec.rb", "spec/arel/engines/sql/unit/relations/project_spec.rb", "spec/arel/engines/sql/unit/relations/skip_spec.rb", From 5f23dad4e5b14e14f09068c1993d8cc0c0780ad8 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 31 Dec 2009 09:59:38 -0300 Subject: [PATCH 0320/1492] Remove every new line when generating queries, this may build invalid queries on SQLite. --- lib/arel/engines/sql/relations/relation.rb | 4 ++-- lib/arel/engines/sql/relations/writes.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 940f985358e09..78508595fd4f4 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -15,7 +15,7 @@ def select_sql "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), + ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), ("#{locked}" unless locked.blank? ) @@ -31,7 +31,7 @@ def select_sql "SELECT #{select_clauses.join(', ')}", "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), + ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 50fcb8e07e58d..83c5fbad42e26 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -4,7 +4,7 @@ def to_sql build_query \ "DELETE", "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ), ("LIMIT #{taken}" unless taken.blank? ) end end @@ -55,7 +55,7 @@ def assignment_sql attributes.map do |attribute| value = assignments[attribute] "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n") + end.join(", ") else assignments.value end @@ -63,7 +63,7 @@ def assignment_sql def build_update_conditions_sql conditions = "" - conditions << " WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? + conditions << " WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? unless taken.blank? From 752813016ed227ecfbe0bf69c92de2e2c3e7a988 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Fri, 1 Jan 2010 22:54:23 +0530 Subject: [PATCH 0321/1492] Add support for table aliasing Example : users = Table(:users, :as => :accounts) users.to_sql => SELECT `accounts`.`id`, `accounts`.`name` FROM `users` AS `accounts` --- .../algebra/relations/utilities/compound.rb | 2 +- lib/arel/engines/sql/christener.rb | 3 +- lib/arel/engines/sql/relations/table.rb | 18 +++++- .../engines/sql/unit/relations/join_spec.rb | 56 ++++++++++++++++++- .../engines/sql/unit/relations/table_spec.rb | 20 +++++++ 5 files changed, 92 insertions(+), 7 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 1acf92fef8ec3..9eca02c8c4e5e 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :sources, :locked, + :column_for, :engine, :sources, :locked, :table_alias, :to => :relation [:attributes, :wheres, :groupings, :orders, :havings].each do |operation_name| diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index c1c9325208b19..a2a2da799a9dc 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -4,7 +4,8 @@ class Christener def name_for(relation) @used_names ||= Hash.new(0) (@relation_names ||= Hash.new do |hash, relation| - @used_names[name = relation.name] += 1 + name = relation.table_alias ? relation.table_alias : relation.name + @used_names[name] += 1 hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') end)[relation.table] end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index dd22f442264b1..6ad294dc6c319 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -3,10 +3,22 @@ class Table < Relation include Recursion::BaseCase cattr_accessor :engine - attr_reader :name, :engine + attr_reader :name, :engine, :table_alias, :options - def initialize(name, engine = Table.engine) - @name, @engine = name.to_s, engine + def initialize(name, options = {}) + @name = name.to_s + + if options.is_a?(Hash) + @options = options + @engine = options[:engine] || Table.engine + @table_alias = options[:as].to_s if options[:as].present? + else + @engine = options # Table.new('foo', engine) + end + end + + def as(table_alias) + Table.new(name, options.merge(:as => table_alias)) end def attributes diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index 2820763a66a89..e2fc4bab3d20c 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -5,13 +5,20 @@ module Arel before do @relation1 = Table.new(:users) @relation2 = Table.new(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) + @predicate1 = @relation1[:id].eq(@relation2[:user_id]) + + @relation3 = Table.new(:users, :as => :super_users) + @relation4 = Table.new(:photos, :as => :super_photos) + + @predicate2 = @relation3[:id].eq(@relation2[:user_id]) + @predicate3 = @relation3[:id].eq(@relation4[:user_id]) end describe '#to_sql' do + describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do - sql = InnerJoin.new(@relation1, @relation2, @predicate).to_sql + sql = InnerJoin.new(@relation1, @relation2, @predicate1).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -29,6 +36,51 @@ module Arel }) end end + + describe 'when joining with another relation with an aliased table' do + it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do + sql = InnerJoin.new(@relation3, @relation2, @predicate2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `super_users`.`id`, `super_users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` AS `super_users` + INNER JOIN `photos` ON `super_users`.`id` = `photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "super_users"."id", "super_users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" AS "super_users" + INNER JOIN "photos" ON "super_users"."id" = "photos"."user_id" + }) + end + end + end + + describe 'when joining with two relations with aliased tables' do + it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do + sql = InnerJoin.new(@relation3, @relation4, @predicate3).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `super_users`.`id`, `super_users`.`name`, `super_photos`.`id`, `super_photos`.`user_id`, `super_photos`.`camera_id` + FROM `users` AS `super_users` + INNER JOIN `photos` AS `super_photos` ON `super_users`.`id` = `super_photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "super_users"."id", "super_users"."name", "super_photos"."id", "super_photos"."user_id", "super_photos"."camera_id" + FROM "users" AS "super_users" + INNER JOIN "photos" AS "super_photos" ON "super_users"."id" = "super_photos"."user_id" + }) + end + end + end + end describe 'when joining with a string' do diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 92e45490289a1..977eb343e34b7 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -26,6 +26,26 @@ module Arel end end + describe '#as' do + it "manufactures a simple select query using aliases" do + sql = @relation.as(:super_users).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `super_users`.`id`, `super_users`.`name` + FROM `users` AS `super_users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "super_users"."id", "super_users"."name" + FROM "users" AS "super_users" + }) + end + end + end + describe '#column_for' do it "returns the column corresponding to the attribute" do @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } From 26a0fefc6d87107161a0d3a171d852f6cd2b4888 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 9 Jan 2010 03:43:17 +0530 Subject: [PATCH 0322/1492] Dont require activerecord --- lib/arel.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index 30b2741eae8d0..706c5af93b264 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -2,9 +2,6 @@ require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/class/attribute_accessors' -require 'active_record' -require 'active_record/connection_adapters/abstract/quoting' - module Arel require 'arel/algebra' require 'arel/engines' From 7286f0f4c8117e2210834070d30378ffb12dba23 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 12 Jan 2010 21:40:38 +0530 Subject: [PATCH 0323/1492] Make sure not to use alias if it's same as the table name --- lib/arel/engines/sql/relations/table.rb | 2 +- .../engines/sql/unit/relations/table_spec.rb | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 6ad294dc6c319..0634436280935 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -11,7 +11,7 @@ def initialize(name, options = {}) if options.is_a?(Hash) @options = options @engine = options[:engine] || Table.engine - @table_alias = options[:as].to_s if options[:as].present? + @table_alias = options[:as].to_s if options[:as].present? && options[:as].to_s != @name else @engine = options # Table.new('foo', engine) end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 977eb343e34b7..d8584ccaeceed 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -44,6 +44,25 @@ module Arel }) end end + + it "does not apply alias if it's same as the table name" do + sql = @relation.as(:users).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + }) + end + end + end describe '#column_for' do From 182c5a0e1f6a2268557ca43ed953d23b32e0483f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Tue, 12 Jan 2010 21:43:55 +0530 Subject: [PATCH 0324/1492] Table alias should be considered when checking for equality --- lib/arel/engines/sql/relations/table.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 0634436280935..a409d8223f016 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -52,8 +52,9 @@ def reset end def ==(other) - Table === other and - name == other.name + Table === other and + name == other.name and + table_alias == other.table_alias end end end From 83592292768de6c093eea06289470154761f3825 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 13 Jan 2010 13:08:42 +0530 Subject: [PATCH 0325/1492] Make sure string join relations can be chained --- lib/arel/algebra/relations/operations/join.rb | 4 +++ .../engines/sql/unit/relations/join_spec.rb | 31 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index e9320f28e1a89..df457686ccef3 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -47,6 +47,10 @@ def engine class InnerJoin < Join; end class OuterJoin < Join; end class StringJoin < Join + def externalizable? + relation1.externalizable? + end + def attributes relation1.externalize.attributes end diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index e2fc4bab3d20c..b926c2aaabaaa 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -103,7 +103,36 @@ module Arel }) end end - end + + it "passes the string when there are multiple string joins" do + relation = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa") + relation = StringJoin.new(relation, "INNER JOIN lifo ON fifo") + sql = StringJoin.new(relation, "INNER JOIN hatful ON hallow").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + INNER JOIN asdf ON fdsa + INNER JOIN lifo ON fifo + INNER JOIN hatful ON hallow + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + INNER JOIN asdf ON fdsa + INNER JOIN lifo ON fifo + INNER JOIN hatful ON hallow + }) + end + end + + end + + end end end From e2dad56caae7ed7697f8d9b4e9d6a62faa308046 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 21 Jan 2010 14:29:30 +0530 Subject: [PATCH 0326/1492] Cache adapter_name in Sql::Engine --- lib/arel/engines/sql/engine.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 7d2926040c0d7..eb9dd85602f7c 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -9,6 +9,10 @@ def connection @ar.connection end + def adapter_name + @adapter_name ||= connection.adapter_name + end + def method_missing(method, *args, &block) @ar.connection.send(method, *args, &block) end From 11dc44ac339199680704b52402fd53f2e3c0ee07 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Sat, 30 Jan 2010 19:31:31 +0000 Subject: [PATCH 0327/1492] Fix the generated SQL when In predicate is supplied an empty Array --- lib/arel/engines/sql/core_extensions/array.rb | 6 +++++- .../engines/sql/unit/predicates/in_spec.rb | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/core_extensions/array.rb b/lib/arel/engines/sql/core_extensions/array.rb index 80041cb5f34bf..72f579b7ebfbe 100644 --- a/lib/arel/engines/sql/core_extensions/array.rb +++ b/lib/arel/engines/sql/core_extensions/array.rb @@ -2,7 +2,11 @@ module Arel module Sql module ArrayExtensions def to_sql(formatter = nil) - "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" + if any? + "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" + else + "(NULL)" + end end def inclusion_predicate_sql diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index 691abcb2d2188..76e5fc58df7f7 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -45,6 +45,25 @@ module Predicates end end end + + describe 'when the array is empty' do + before do + @array = [] + end + + it 'manufactures sql with a comma separated list' do + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (NULL)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (NULL)}) + end + end + end + end describe 'when relating to a range' do From 7ba3758665906599013e892515620431d6494030 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 31 Jan 2010 21:27:16 -0500 Subject: [PATCH 0328/1492] Release v0.2.0 --- History.txt | 6 +++--- Thorfile | 2 ++ arel.gemspec | 6 +++--- lib/arel.rb | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/History.txt b/History.txt index acfff6c6065e8..8267acb031c95 100644 --- a/History.txt +++ b/History.txt @@ -1,8 +1,8 @@ -== Git - -* 1 major enhancement +== 0.2.0 / 2010-01-31 * Ruby 1.9 compatibility + * Many improvements to support the Arel integration into ActiveRecord (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 diff --git a/Thorfile b/Thorfile index a3cce295417a7..11a3d510be70c 100644 --- a/Thorfile +++ b/Thorfile @@ -1,3 +1,5 @@ +require "active_support" + module GemHelpers def generate_gemspec diff --git a/arel.gemspec b/arel.gemspec index a7ae71bd1d5df..77c5d181efcbc 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.2.pre" + s.version = "0.2.0" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen"] - s.date = %q{2009-12-29} + s.date = %q{2010-01-31} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 diff --git a/lib/arel.rb b/lib/arel.rb index 706c5af93b264..286c7a1ed8eab 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -7,5 +7,5 @@ module Arel require 'arel/engines' autoload :Session, 'arel/session' - VERSION = "0.2.pre" + VERSION = "0.2.0" end \ No newline at end of file From e74bbd6830f5ca5f0ab1fe9f2f645674f6333a29 Mon Sep 17 00:00:00 2001 From: Eugene Pimenov Date: Sat, 30 Jan 2010 13:16:59 +0300 Subject: [PATCH 0329/1492] Quoting every part of a Range. Calling .to_s is not enough for Range with two Time objects. --- lib/arel/engines/sql/formatters.rb | 2 +- .../engines/sql/unit/predicates/in_spec.rb | 24 +++++++++++++++++++ .../engines/sql/unit/relations/having_spec.rb | 4 ++-- spec/schemas/mysql_schema.rb | 3 ++- spec/schemas/postgresql_schema.rb | 3 ++- spec/schemas/sqlite3_schema.rb | 3 ++- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index e05dc3eb9359f..8da362ef3bcd0 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -112,7 +112,7 @@ def scalar(scalar) end def range(left, right) - "#{left} AND #{right}" + "#{scalar(left)} AND #{scalar(right)}" end end diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index 76e5fc58df7f7..a8ae9e4b5f489 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -84,6 +84,30 @@ module Predicates end end + describe 'when relating to a time range' do + before do + @relation = Arel::Table.new(:developers) + @attribute = @relation[:created_at] + @range = Time.mktime(2010, 01, 01)..Time.mktime(2010, 02, 01) + end + + it 'manufactures sql with a between' do + sql = In.new(@attribute, @range).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`developers`.`created_at` BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'}) + end + + adapter_is :sqlite3 do + sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'}) + end + + adapter_is :postgresql do + sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00.000000' AND '2010-02-01 00:00:00.000000'}) + end + end + end + describe 'when relating to a relation' do it 'manufactures sql with a subselect' do sql = In.new(@attribute, @relation).to_sql diff --git a/spec/arel/engines/sql/unit/relations/having_spec.rb b/spec/arel/engines/sql/unit/relations/having_spec.rb index dd170a256f8e9..915ee3af0887f 100644 --- a/spec/arel/engines/sql/unit/relations/having_spec.rb +++ b/spec/arel/engines/sql/unit/relations/having_spec.rb @@ -13,7 +13,7 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ - SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department` + SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department`, `developers`.`created_at` FROM `developers` GROUP BY `developers`.`department` HAVING MIN(salary) > 1000 @@ -22,7 +22,7 @@ module Arel adapter_is_not :mysql do sql.should be_like(%Q{ - SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department" + SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department", "developers"."created_at" FROM "developers" GROUP BY "developers"."department" HAVING MIN(salary) > 1000 diff --git a/spec/schemas/mysql_schema.rb b/spec/schemas/mysql_schema.rb index cb4c746776d6d..a2e913d756fd1 100644 --- a/spec/schemas/mysql_schema.rb +++ b/spec/schemas/mysql_schema.rb @@ -16,7 +16,8 @@ id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, salary INTEGER NOT NULL, - department VARCHAR(255) NOT NULL + department VARCHAR(255) NOT NULL, + created_at TIMESTAMP NOT NULL ); SQL diff --git a/spec/schemas/postgresql_schema.rb b/spec/schemas/postgresql_schema.rb index 8b7dac1c41bd1..23a48f5ad8ea4 100644 --- a/spec/schemas/postgresql_schema.rb +++ b/spec/schemas/postgresql_schema.rb @@ -16,7 +16,8 @@ id SERIAL PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL, salary INTEGER NOT NULL, - department VARCHAR(255) NOT NULL + department VARCHAR(255) NOT NULL, + created_at TIMESTAMP NOT NULL ); SQL diff --git a/spec/schemas/sqlite3_schema.rb b/spec/schemas/sqlite3_schema.rb index 9dbb62428ec44..c1fed70859fe2 100644 --- a/spec/schemas/sqlite3_schema.rb +++ b/spec/schemas/sqlite3_schema.rb @@ -16,7 +16,8 @@ id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(255) NOT NULL, salary INTEGER NOT NULL, - department VARCHAR(255) NOT NULL + department VARCHAR(255) NOT NULL, + created_at TIMESTAMP NOT NULL ); SQL From 91663d1e3a1ed45ad4bf54129a1d633161133667 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 1 Feb 2010 12:39:57 -0500 Subject: [PATCH 0330/1492] Add Emilio Tagua as a maintainer --- Thorfile | 2 +- arel.gemspec | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Thorfile b/Thorfile index 11a3d510be70c..eebb58254f361 100644 --- a/Thorfile +++ b/Thorfile @@ -12,7 +12,7 @@ module GemHelpers Gem::Specification.new do |s| s.name = "arel" s.version = Arel::VERSION - s.authors = ["Bryan Helmkamp", "Nick Kallen"] + s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] s.email = "bryan@brynary.com" s.homepage = "http://github.com/brynary/arel" s.summary = "Arel is a relational algebra engine for Ruby" diff --git a/arel.gemspec b/arel.gemspec index 77c5d181efcbc..465dcb7567be9 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -5,8 +5,8 @@ Gem::Specification.new do |s| s.version = "0.2.0" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Bryan Helmkamp", "Nick Kallen"] - s.date = %q{2010-01-31} + s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] + s.date = %q{2010-02-01} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 From 9aa076abfb893e6de9fee48f4c280b007f5887d3 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Fri, 5 Feb 2010 12:18:40 -0500 Subject: [PATCH 0331/1492] Bump dependency version of activesupport to 3.0.0.beta --- History.txt | 6 ++++++ Thorfile | 2 +- arel.gemspec | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/History.txt b/History.txt index 8267acb031c95..465c6b670e787 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== git + +* Enhancements + + * Bump dependency version of activesupport to 3.0.0.beta + == 0.2.0 / 2010-01-31 * Ruby 1.9 compatibility diff --git a/Thorfile b/Thorfile index eebb58254f361..3b55e45a91f4c 100644 --- a/Thorfile +++ b/Thorfile @@ -38,7 +38,7 @@ and query generation. # circular dependency chain. The solution is for ActiveRecord to release # the connection adapters which Arel uses in a separate gem # s.add_dependency "activerecord", ">= 3.0.pre" - s.add_dependency "activesupport", ">= 3.0.pre" + s.add_dependency "activesupport", ">= 3.0.0.beta" end end diff --git a/arel.gemspec b/arel.gemspec index 465dcb7567be9..b4873575234cf 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-02-01} + s.date = %q{2010-02-05} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 @@ -238,11 +238,11 @@ and query generation.} s.specification_version = 3 if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 3.0.pre"]) + s.add_runtime_dependency(%q, [">= 3.0.0.beta"]) else - s.add_dependency(%q, [">= 3.0.pre"]) + s.add_dependency(%q, [">= 3.0.0.beta"]) end else - s.add_dependency(%q, [">= 3.0.pre"]) + s.add_dependency(%q, [">= 3.0.0.beta"]) end end From 7caf242cf484f8875a0cfdf2c252a2fefc273358 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Fri, 5 Feb 2010 12:19:55 -0500 Subject: [PATCH 0332/1492] Release v0.2.1 --- History.txt | 2 +- arel.gemspec | 2 +- lib/arel.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.txt b/History.txt index 465c6b670e787..36dde74e4e38e 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== git +== 0.2.1 / 2010-02-05 * Enhancements diff --git a/arel.gemspec b/arel.gemspec index b4873575234cf..b5267cf3337e9 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.2.0" + s.version = "0.2.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] diff --git a/lib/arel.rb b/lib/arel.rb index 286c7a1ed8eab..36fd961188be5 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -7,5 +7,5 @@ module Arel require 'arel/engines' autoload :Session, 'arel/session' - VERSION = "0.2.0" + VERSION = "0.2.1" end \ No newline at end of file From 6e9cf0cb4390f1d210edbecc660290aaea6b4d72 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 15 Feb 2010 17:20:24 -0300 Subject: [PATCH 0333/1492] Extract SQL logic from Arel::Relation into compilers. --- .../engines/sql/compilers/mysql_compiler.rb | 7 ++ .../sql/compilers/postgresql_compiler.rb | 33 ++++++++ .../engines/sql/compilers/sqlite_compiler.rb | 9 +++ lib/arel/engines/sql/engine.rb | 3 +- lib/arel/engines/sql/relations.rb | 1 + lib/arel/engines/sql/relations/compiler.rb | 63 +++++++++++++++ lib/arel/engines/sql/relations/relation.rb | 78 ++----------------- lib/arel/engines/sql/relations/table.rb | 8 ++ .../relations/utilities/externalization.rb | 2 +- 9 files changed, 130 insertions(+), 74 deletions(-) create mode 100644 lib/arel/engines/sql/compilers/mysql_compiler.rb create mode 100644 lib/arel/engines/sql/compilers/postgresql_compiler.rb create mode 100644 lib/arel/engines/sql/compilers/sqlite_compiler.rb create mode 100644 lib/arel/engines/sql/relations/compiler.rb diff --git a/lib/arel/engines/sql/compilers/mysql_compiler.rb b/lib/arel/engines/sql/compilers/mysql_compiler.rb new file mode 100644 index 0000000000000..e3cf1f2add00b --- /dev/null +++ b/lib/arel/engines/sql/compilers/mysql_compiler.rb @@ -0,0 +1,7 @@ +module Arel + module SqlCompiler + class MySQLCompiler < GenericCompiler + end + end +end + diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb new file mode 100644 index 0000000000000..c3360b53a5aa8 --- /dev/null +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -0,0 +1,33 @@ +module Arel + module SqlCompiler + class PostgreSQLCompiler < GenericCompiler + + def select_sql + if !orders.blank? && using_distinct_on? + # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this + # by wrapping the +sql+ string as a sub-select and ordering in that query. + order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?) + order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') + + query = build_query \ + "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", + "FROM #{from_clauses}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), + ("#{locked}" unless locked.blank? ) + + build_query \ + "SELECT * FROM (#{query}) AS id_list", + "ORDER BY #{order}", + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) + + else + super + end + end + end + end +end diff --git a/lib/arel/engines/sql/compilers/sqlite_compiler.rb b/lib/arel/engines/sql/compilers/sqlite_compiler.rb new file mode 100644 index 0000000000000..c2f78cd235050 --- /dev/null +++ b/lib/arel/engines/sql/compilers/sqlite_compiler.rb @@ -0,0 +1,9 @@ +module Arel + module SqlCompiler + class SQLiteCompiler < GenericCompiler + def locked + nil + end + end + end +end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index eb9dd85602f7c..5bb8463699ba3 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -1,12 +1,13 @@ module Arel module Sql class Engine + def initialize(ar = nil) @ar = ar end def connection - @ar.connection + @ar ? @ar.connection : nil end def adapter_name diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 8360a1f80685d..afe6ac775ff32 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -2,6 +2,7 @@ require 'arel/engines/sql/relations/utilities/recursion' require 'arel/engines/sql/relations/utilities/externalization' require 'arel/engines/sql/relations/utilities/nil' +require 'arel/engines/sql/relations/compiler' require 'arel/engines/sql/relations/relation' require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb new file mode 100644 index 0000000000000..6026fc126f621 --- /dev/null +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -0,0 +1,63 @@ +module Arel + module SqlCompiler + class GenericCompiler + attr_reader :relation + + def initialize(relation) + @relation = relation + end + + def select_sql + build_query \ + "SELECT #{select_clauses.join(', ')}", + "FROM #{from_clauses}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), + ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ), + ("#{locked}" unless locked.blank?) + end + + protected + def method_missing(method, *args, &block) + relation.send(method, *args, &block) + end + + def build_query(*parts) + parts.compact.join(" ") + end + + def from_clauses + sources.blank? ? table_sql(Sql::TableReference.new(relation)) : sources + end + + def select_clauses + attributes.collect { |a| a.to_sql(Sql::SelectClause.new(relation)) } + end + + def where_clauses + wheres.collect { |w| w.to_sql(Sql::WhereClause.new(relation)) } + end + + def group_clauses + groupings.collect { |g| g.to_sql(Sql::GroupClause.new(relation)) } + end + + def having_clauses + havings.collect { |g| g.to_sql(Sql::HavingClause.new(relation)) } + end + + def order_clauses + orders.collect { |o| o.to_sql(Sql::OrderClause.new(relation)) } + end + + def using_distinct_on? + select_clauses.any? { |x| x =~ /DISTINCT ON/ } + end + end + + end +end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 78508595fd4f4..15903412d5fe8 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -1,86 +1,20 @@ module Arel class Relation - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select select_sql, self - end - - def select_sql - if engine.adapter_name == "PostgreSQL" && !orders.blank? && using_distinct_on? - # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the +sql+ string as a sub-select and ordering in that query. - order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?) - order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') - - query = build_query \ - "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", - "FROM #{from_clauses}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), - ("#{locked}" unless locked.blank? ) - build_query \ - "SELECT * FROM (#{query}) AS id_list", - "ORDER BY #{order}", - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) - - else - build_query \ - "SELECT #{select_clauses.join(', ')}", - "FROM #{from_clauses}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), - ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ), - ("#{locked}" unless engine.adapter_name =~ /SQLite/ || locked.blank?) - end + def compiler + @compiler ||= "Arel::SqlCompiler::#{engine.adapter_name}Compiler".constantize.new(self) end - def inclusion_predicate_sql - "IN" + def to_sql(formatter = Sql::SelectStatement.new(self)) + formatter.select compiler.select_sql, self end def christener @christener ||= Sql::Christener.new end - protected - - def build_query(*parts) - parts.compact.join(" ") - end - - def from_clauses - sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources - end - - def select_clauses - attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } - end - - def where_clauses - wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } - end - - def group_clauses - groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } - end - - def having_clauses - havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } - end - - def order_clauses - orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } - end - - def using_distinct_on? - select_clauses.any? { |x| x =~ /DISTINCT ON/ } + def inclusion_predicate_sql + "IN" end end end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index a409d8223f016..9ea07a00a1b5c 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -15,6 +15,14 @@ def initialize(name, options = {}) else @engine = options # Table.new('foo', engine) end + + if @engine.connection + begin + require "lib/arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler" + rescue LoadError + raise "#{@engine.adapter_name} is not supported by Arel." + end + end end def as(table_alias) diff --git a/lib/arel/engines/sql/relations/utilities/externalization.rb b/lib/arel/engines/sql/relations/utilities/externalization.rb index 7f937e84231c3..a0230e90f302c 100644 --- a/lib/arel/engines/sql/relations/utilities/externalization.rb +++ b/lib/arel/engines/sql/relations/utilities/externalization.rb @@ -3,7 +3,7 @@ class Externalization < Compound include Recursion::BaseCase def table_sql(formatter = Sql::TableReference.new(relation)) - formatter.select relation.select_sql, self + formatter.select relation.compiler.select_sql, self end # REMOVEME From bfc8bdf667cf22395938c206f44ab089b4873347 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 16 Feb 2010 10:08:27 -0300 Subject: [PATCH 0334/1492] Move using_distinct_on? to PostgreSQL compiler. Extract order tweaking to a new method. --- .../sql/compilers/postgresql_compiler.rb | 17 ++++++++++++----- lib/arel/engines/sql/relations/compiler.rb | 4 ---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb index c3360b53a5aa8..809485bb4dbf4 100644 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -4,10 +4,6 @@ class PostgreSQLCompiler < GenericCompiler def select_sql if !orders.blank? && using_distinct_on? - # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the +sql+ string as a sub-select and ordering in that query. - order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?) - order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') query = build_query \ "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", @@ -20,7 +16,7 @@ def select_sql build_query \ "SELECT * FROM (#{query}) AS id_list", - "ORDER BY #{order}", + "ORDER BY #{aliased_orders(order_clauses)}", ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) @@ -28,6 +24,17 @@ def select_sql super end end + + def using_distinct_on? + select_clauses.any? { |x| x =~ /DISTINCT ON/ } + end + + def aliased_orders(orders) + # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this + # by wrapping the +sql+ string as a sub-select and ordering in that query. + order = orders.join(', ').split(/,/).map { |s| s.strip }.reject(&:blank?) + order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') + end end end end diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 6026fc126f621..b85d227705ac1 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -53,10 +53,6 @@ def having_clauses def order_clauses orders.collect { |o| o.to_sql(Sql::OrderClause.new(relation)) } end - - def using_distinct_on? - select_clauses.any? { |x| x =~ /DISTINCT ON/ } - end end end From e4d6689f14960a6faf2aa6d6e1f7220e30eff549 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 16 Feb 2010 10:11:14 -0300 Subject: [PATCH 0335/1492] Removed blank lines, rename query to subquery. --- lib/arel/engines/sql/compilers/postgresql_compiler.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb index 809485bb4dbf4..4122bc730eb19 100644 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -4,8 +4,7 @@ class PostgreSQLCompiler < GenericCompiler def select_sql if !orders.blank? && using_distinct_on? - - query = build_query \ + subquery = build_query \ "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), @@ -15,11 +14,10 @@ def select_sql ("#{locked}" unless locked.blank? ) build_query \ - "SELECT * FROM (#{query}) AS id_list", + "SELECT * FROM (#{subquery}) AS id_list", "ORDER BY #{aliased_orders(order_clauses)}", ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) - else super end From 7dc7cd5d6dffae18b41c07ac5c6e291d0ea8cd74 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 16 Feb 2010 10:14:40 -0300 Subject: [PATCH 0336/1492] If a compiler is not found for the current adapter, use the generic one. --- lib/arel/engines/sql/relations/relation.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 15903412d5fe8..13e9f0a6a2ea2 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -2,7 +2,11 @@ module Arel class Relation def compiler - @compiler ||= "Arel::SqlCompiler::#{engine.adapter_name}Compiler".constantize.new(self) + @compiler ||= begin + "Arel::SqlCompiler::#{engine.adapter_name}Compiler".constantize.new(self) + rescue + Arel::SqlCompiler::GenericCompiler.new(self) + end end def to_sql(formatter = Sql::SelectStatement.new(self)) From f21f289ebf8cd4b89f507d48e62e7c5c986922d8 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 16 Feb 2010 10:29:23 -0300 Subject: [PATCH 0337/1492] Move update conditions with limit logic into compilers. --- lib/arel/engines/sql/compilers/mysql_compiler.rb | 3 +++ lib/arel/engines/sql/relations/compiler.rb | 10 ++++++++++ lib/arel/engines/sql/relations/writes.rb | 12 ++---------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/arel/engines/sql/compilers/mysql_compiler.rb b/lib/arel/engines/sql/compilers/mysql_compiler.rb index e3cf1f2add00b..ba3312ba721a1 100644 --- a/lib/arel/engines/sql/compilers/mysql_compiler.rb +++ b/lib/arel/engines/sql/compilers/mysql_compiler.rb @@ -1,6 +1,9 @@ module Arel module SqlCompiler class MySQLCompiler < GenericCompiler + def limited_update_conditions(conditions) + conditions + end end end end diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index b85d227705ac1..46f728a7bdd27 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -21,6 +21,16 @@ def select_sql ("#{locked}" unless locked.blank?) end + def limited_update_conditions(conditions) + begin + quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key) + rescue NameError + quote_primary_key = engine.quote_column_name("id") + end + + "WHERE #{quote_primary_key} IN (SELECT #{quote_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" + end + protected def method_missing(method, *args, &block) relation.send(method, *args, &block) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 83c5fbad42e26..30b36ddda8775 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -5,7 +5,7 @@ def to_sql "DELETE", "FROM #{table_sql}", ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) + ("LIMIT #{taken}" unless taken.blank? ) end end @@ -69,15 +69,7 @@ def build_update_conditions_sql unless taken.blank? conditions << " LIMIT #{taken}" - if engine.adapter_name != "MySQL" - begin - quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key) - rescue NameError - quote_primary_key = engine.quote_column_name("id") - end - - conditions = "WHERE #{quote_primary_key} IN (SELECT #{quote_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" - end + conditions = compiler.limited_update_conditions(conditions) end conditions From f37c4a4d690888aa5cf8e54c8b404dd10f219f46 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 17 Feb 2010 11:50:03 -0300 Subject: [PATCH 0338/1492] Fix test which depends on the RUBY_VERSION when using sqlite3 adapter. --- spec/arel/engines/sql/unit/predicates/in_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index a8ae9e4b5f489..a1c42f714e258 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -99,7 +99,11 @@ module Predicates end adapter_is :sqlite3 do - sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'}) + if RUBY_VERSION < '1.9' + sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00.000000' AND '2010-02-01 00:00:00.000000'}) + else + sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'}) + end end adapter_is :postgresql do From 1c0d7dc7f62e8744b476464f8aefc1867986f0bd Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 18 Feb 2010 18:11:43 -0300 Subject: [PATCH 0339/1492] Moved primary_key to relation, send pk to engine, to build a better query if possible. --- lib/arel/engines/sql/engine.rb | 2 +- lib/arel/engines/sql/relations/compiler.rb | 9 ++------- lib/arel/engines/sql/relations/relation.rb | 8 ++++++++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 5bb8463699ba3..82915fe8907c6 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -20,7 +20,7 @@ def method_missing(method, *args, &block) module CRUD def create(relation) - connection.insert(relation.to_sql) + connection.insert(relation.to_sql, nil, relation.primary_key) end def read(relation) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 46f728a7bdd27..4bc169096aaff 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -22,13 +22,8 @@ def select_sql end def limited_update_conditions(conditions) - begin - quote_primary_key = engine.quote_column_name(table.name.classify.constantize.primary_key) - rescue NameError - quote_primary_key = engine.quote_column_name("id") - end - - "WHERE #{quote_primary_key} IN (SELECT #{quote_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" + quoted_primary_key = engine.quote_table_name(primary_key) + "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" end protected diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 13e9f0a6a2ea2..5038e1db81bd7 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -20,5 +20,13 @@ def christener def inclusion_predicate_sql "IN" end + + def primary_key + @primary_key ||= begin + table.name.classify.constantize.primary_key + rescue NameError + "id" + end + end end end From d51697d2bd2cdd6394cb5e665aab8ab43ce9a14a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 18 Feb 2010 18:28:27 -0300 Subject: [PATCH 0340/1492] Added support for RETURNING primary key when available, only for PostgreSQL. --- .../engines/sql/compilers/postgresql_compiler.rb | 4 ++++ lib/arel/engines/sql/engine.rb | 2 +- lib/arel/engines/sql/relations/compiler.rb | 4 ++++ lib/arel/engines/sql/relations/writes.rb | 3 ++- spec/arel/engines/sql/unit/relations/insert_spec.rb | 13 ++++++++++++- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb index 4122bc730eb19..1f6e74d57a648 100644 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -33,6 +33,10 @@ def aliased_orders(orders) order = orders.join(', ').split(/,/).map { |s| s.strip }.reject(&:blank?) order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') end + + def supports_insert_with_returning? + engine.postgresql_version >= 80200 + end end end end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 82915fe8907c6..79011a3db5944 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -20,7 +20,7 @@ def method_missing(method, *args, &block) module CRUD def create(relation) - connection.insert(relation.to_sql, nil, relation.primary_key) + connection.execute(relation.to_sql) end def read(relation) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 4bc169096aaff..185f1a5c871a1 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -26,6 +26,10 @@ def limited_update_conditions(conditions) "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" end + def supports_insert_with_returning? + false + end + protected def method_missing(method, *args, &block) relation.send(method, *args, &block) diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 30b36ddda8775..00cd61cddeda4 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -32,7 +32,8 @@ def to_sql build_query \ "INSERT", "INTO #{table_sql}", - insertion_attributes_values_sql + insertion_attributes_values_sql, + ("RETURNING #{engine.quote_column_name(primary_key)}" if compiler.supports_insert_with_returning?) end end diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb index 1884e32a3db03..69c5bb052cfd4 100644 --- a/spec/arel/engines/sql/unit/relations/insert_spec.rb +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -43,6 +43,7 @@ module Arel INSERT INTO "users" ("id", "name") VALUES (1, E'nick') + RETURNING "id" }) end end @@ -74,6 +75,7 @@ module Arel INSERT INTO "users" ("name") VALUES (E'nick') + RETURNING "id" }) end end @@ -93,11 +95,20 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id") VALUES (1) + }) + end + + adapter_is :postgresql do @insertion.to_sql.should be_like(%Q{ INSERT INTO "users" ("id") VALUES (1) + RETURNING "id" }) end end From 39d88b8bce309fe9bdc1011b312c857ef194fbfa Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 18 Feb 2010 18:58:01 -0300 Subject: [PATCH 0341/1492] Fixed compiler require. --- lib/arel/engines/sql/relations/table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 9ea07a00a1b5c..e4b75d6c3d6e9 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -18,7 +18,7 @@ def initialize(name, options = {}) if @engine.connection begin - require "lib/arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler" + require "arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler" rescue LoadError raise "#{@engine.adapter_name} is not supported by Arel." end From 18b2a3ce6b4519b7d5e0f4a63bc6cfb5b8808632 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 18 Feb 2010 19:17:55 -0300 Subject: [PATCH 0342/1492] Insertions should use insert and not execute to get a valid returning value. Moved clasuses to Arel::Relation. --- lib/arel/engines/sql/engine.rb | 2 +- lib/arel/engines/sql/relations/compiler.rb | 23 ------------------ lib/arel/engines/sql/relations/relation.rb | 28 +++++++++++++++++++++- lib/arel/engines/sql/relations/writes.rb | 4 ++-- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 79011a3db5944..f0991f0a0feec 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -20,7 +20,7 @@ def method_missing(method, *args, &block) module CRUD def create(relation) - connection.execute(relation.to_sql) + connection.insert(relation.to_sql(false), nil, relation.primary_key) end def read(relation) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 185f1a5c871a1..c974e43b88726 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -39,29 +39,6 @@ def build_query(*parts) parts.compact.join(" ") end - def from_clauses - sources.blank? ? table_sql(Sql::TableReference.new(relation)) : sources - end - - def select_clauses - attributes.collect { |a| a.to_sql(Sql::SelectClause.new(relation)) } - end - - def where_clauses - wheres.collect { |w| w.to_sql(Sql::WhereClause.new(relation)) } - end - - def group_clauses - groupings.collect { |g| g.to_sql(Sql::GroupClause.new(relation)) } - end - - def having_clauses - havings.collect { |g| g.to_sql(Sql::HavingClause.new(relation)) } - end - - def order_clauses - orders.collect { |o| o.to_sql(Sql::OrderClause.new(relation)) } - end end end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 5038e1db81bd7..52b91c71ea011 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -25,8 +25,34 @@ def primary_key @primary_key ||= begin table.name.classify.constantize.primary_key rescue NameError - "id" + nil end end + + protected + + def from_clauses + sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources + end + + def select_clauses + attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } + end + + def where_clauses + wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } + end + + def group_clauses + groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } + end + + def having_clauses + havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } + end + + def order_clauses + orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } + end end end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 00cd61cddeda4..0a6250a3b9b02 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -10,7 +10,7 @@ def to_sql end class Insert < Compound - def to_sql + def to_sql(include_returning = true) insertion_attributes_values_sql = if record.is_a?(Value) record.value else @@ -33,7 +33,7 @@ def to_sql "INSERT", "INTO #{table_sql}", insertion_attributes_values_sql, - ("RETURNING #{engine.quote_column_name(primary_key)}" if compiler.supports_insert_with_returning?) + ("RETURNING #{engine.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?) end end From debd111a39a683592873e7af2d277233b6ec14d2 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 19 Feb 2010 12:08:47 -0300 Subject: [PATCH 0343/1492] Refactored primary_key to look up for the real primary_key and cache it. --- lib/arel/engines/sql/relations/relation.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 52b91c71ea011..4249cf9b0df38 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -1,5 +1,6 @@ module Arel class Relation + @@tables_primary_keys = {} def compiler @compiler ||= begin @@ -22,10 +23,10 @@ def inclusion_predicate_sql end def primary_key - @primary_key ||= begin - table.name.classify.constantize.primary_key - rescue NameError - nil + if @@tables_primary_keys.has_key?(table.name) + @@tables_primary_keys[table.name] + else + @@tables_primary_keys[table.name] = engine.primary_key(table.name) end end From 4525b1ff89a84ba9be70942a3e90c913c162a839 Mon Sep 17 00:00:00 2001 From: Praveen Devarao Date: Thu, 25 Feb 2010 12:49:19 +0530 Subject: [PATCH 0344/1492] Moved adding of limit on deletion and adding of limit on update conditions to GenericCompiler, to provide flexibility to handle db specifics Signed-off-by: Emilio Tagua --- .../engines/sql/compilers/ibm_db_compiler.rb | 62 +++++++++++++++++++ lib/arel/engines/sql/relations/compiler.rb | 7 ++- lib/arel/engines/sql/relations/writes.rb | 6 +- 3 files changed, 70 insertions(+), 5 deletions(-) create mode 100644 lib/arel/engines/sql/compilers/ibm_db_compiler.rb diff --git a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb new file mode 100644 index 0000000000000..e6be73d6a131c --- /dev/null +++ b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb @@ -0,0 +1,62 @@ +# +-----------------------------------------------------------------------+ +# | | +# | Copyright (c) 2010 IBM Corporation | +# | | +# | 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. | +# | | +# +-----------------------------------------------------------------------+ + +# +# Author: Praveen Devarao +# + +module Arel + module SqlCompiler + class IBM_DBCompiler < GenericCompiler + + def select_sql + query = build_query \ + "SELECT #{select_clauses.join(', ')}", + "FROM #{from_clauses}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), + ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) + engine.add_limit_offset!(query,{:limit=>taken,:offset=>skipped}) unless taken.blank? + query << "#{locked}" unless locked.blank? + query + end + + def limited_update_conditions(conditions, taken) + quoted_primary_key = engine.quote_table_name(primary_key) + update_conditions = "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions} " #Note: - ')' not added, limit segment is to be appended + engine.add_limit_offset!(update_conditions,{:limit=>taken,:offset=>nil}) + update_conditions << ")" # Close the sql segment + update_conditions + end + + def add_limit_on_delete(taken) + "" # Limiting the number of rows to be deleted is not supported by IBM_DB + end + + end + end +end diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index c974e43b88726..597ed88683a5d 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -21,11 +21,16 @@ def select_sql ("#{locked}" unless locked.blank?) end - def limited_update_conditions(conditions) + def limited_update_conditions(conditions, taken) + conditions << " LIMIT #{taken}" quoted_primary_key = engine.quote_table_name(primary_key) "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" end + def add_limit_on_delete(taken) + "LIMIT #{taken}" + end + def supports_insert_with_returning? false end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 0a6250a3b9b02..54eaee9ead12f 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -5,7 +5,7 @@ def to_sql "DELETE", "FROM #{table_sql}", ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) + (compiler.add_limit_on_delete(taken) unless taken.blank? ) end end @@ -68,9 +68,7 @@ def build_update_conditions_sql conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? unless taken.blank? - conditions << " LIMIT #{taken}" - - conditions = compiler.limited_update_conditions(conditions) + conditions = compiler.limited_update_conditions(conditions,taken) end conditions From 3c9f4be465126051d4a5230ada3dfea87d435fcd Mon Sep 17 00:00:00 2001 From: Praveen Devarao Date: Thu, 25 Feb 2010 14:35:16 +0530 Subject: [PATCH 0345/1492] raise an error if limit for deletion is specified while using IBM_DB Signed-off-by: Emilio Tagua --- lib/arel/engines/sql/compilers/ibm_db_compiler.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb index e6be73d6a131c..e15e7831604d3 100644 --- a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb +++ b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb @@ -54,7 +54,7 @@ def limited_update_conditions(conditions, taken) end def add_limit_on_delete(taken) - "" # Limiting the number of rows to be deleted is not supported by IBM_DB + raise "IBM_DB does not support limit on deletion" # Limiting the number of rows to be deleted is not supported by IBM_DB end end From 6762cf774cfa84804650a12e4397891869ab6106 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Feb 2010 12:15:22 -0300 Subject: [PATCH 0346/1492] Fix limited_update_conditions on MySQLCompiler to receive and build limit. --- lib/arel/engines/sql/compilers/mysql_compiler.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/compilers/mysql_compiler.rb b/lib/arel/engines/sql/compilers/mysql_compiler.rb index ba3312ba721a1..cb12e7377aab9 100644 --- a/lib/arel/engines/sql/compilers/mysql_compiler.rb +++ b/lib/arel/engines/sql/compilers/mysql_compiler.rb @@ -1,7 +1,8 @@ module Arel module SqlCompiler class MySQLCompiler < GenericCompiler - def limited_update_conditions(conditions) + def limited_update_conditions(conditions, taken) + conditions << " LIMIT #{taken}" conditions end end From 98a87e181aed8131797e55db2ca957bc515cdaca Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 26 Feb 2010 15:27:04 -0300 Subject: [PATCH 0347/1492] Arel should not be consired alpha anymore. --- README.markdown | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.markdown b/README.markdown index 20d6e62b448b0..f28ed1e0a18b6 100644 --- a/README.markdown +++ b/README.markdown @@ -4,8 +4,6 @@ Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex o ## Status ## -Arel is alpha software, BEWARE. Nevertheless, at this point, many (most?) SELECT queries can be composed, including very very complicated ones. Writes are only experimental for now. - For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. On the horizon is the use of DataObjects instead. The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc. From 20a10e5302ce8f912d27c57702b542a019c7f9f9 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Wed, 10 Feb 2010 19:50:59 +0200 Subject: [PATCH 0348/1492] changes for Oracle support - OracleCompiler and corresponding tests with Oracle syntax --- Rakefile | 4 +- arel.gemspec | 6 +- .../engines/sql/compilers/oracle_compiler.rb | 101 ++++++++++++++++++ lib/arel/engines/sql/engine.rb | 8 +- lib/arel/engines/sql/formatters.rb | 11 +- lib/arel/engines/sql/relations/compiler.rb | 76 ++++++++++++- lib/arel/engines/sql/relations/writes.rb | 64 +---------- .../integration/joins/cross_engine_spec.rb | 13 ++- .../integration/joins/with_adjacency_spec.rb | 59 +++++++++- .../joins/with_aggregations_spec.rb | 66 ++++++++++-- .../integration/joins/with_compounds_spec.rb | 36 ++++++- .../sql/unit/predicates/binary_spec.rb | 24 ++++- .../sql/unit/predicates/equality_spec.rb | 18 +++- .../engines/sql/unit/predicates/in_spec.rb | 36 ++++++- .../sql/unit/predicates/predicates_spec.rb | 12 +++ .../sql/unit/primitives/attribute_spec.rb | 6 +- .../sql/unit/primitives/expression_spec.rb | 6 +- .../sql/unit/primitives/literal_spec.rb | 12 ++- .../engines/sql/unit/relations/alias_spec.rb | 12 ++- .../engines/sql/unit/relations/delete_spec.rb | 26 ++++- .../engines/sql/unit/relations/from_spec.rb | 18 +++- .../engines/sql/unit/relations/group_spec.rb | 20 +++- .../engines/sql/unit/relations/having_spec.rb | 11 +- .../engines/sql/unit/relations/insert_spec.rb | 25 +++++ .../engines/sql/unit/relations/join_spec.rb | 52 ++++++++- .../engines/sql/unit/relations/lock_spec.rb | 25 +++++ .../engines/sql/unit/relations/order_spec.rb | 56 +++++++++- .../sql/unit/relations/project_spec.rb | 43 +++++++- .../engines/sql/unit/relations/skip_spec.rb | 11 +- .../engines/sql/unit/relations/table_spec.rb | 27 ++++- .../engines/sql/unit/relations/take_spec.rb | 19 +++- .../engines/sql/unit/relations/update_spec.rb | 48 ++++++++- .../engines/sql/unit/relations/where_spec.rb | 20 +++- spec/connections/oracle_connection.rb | 19 ++++ spec/schemas/oracle_schema.rb | 20 ++++ spec/spec_helper.rb | 23 ++-- 36 files changed, 892 insertions(+), 141 deletions(-) create mode 100644 lib/arel/engines/sql/compilers/oracle_compiler.rb create mode 100644 spec/connections/oracle_connection.rb create mode 100644 spec/schemas/oracle_schema.rb diff --git a/Rakefile b/Rakefile index fba44e620f6af..a1384196a2c5b 100644 --- a/Rakefile +++ b/Rakefile @@ -20,13 +20,13 @@ else end namespace :spec do - for adapter in %w[mysql sqlite3 postgresql] + for adapter in %w[mysql sqlite3 postgresql oracle] desc "Run specs with the #{adapter} database adapter" Spec::Rake::SpecTask.new(adapter) do |t| t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" t.libs << "#{File.dirname(__FILE__)}/spec" - t.warning = true + # t.warning = true t.spec_files = ["spec/connections/#{adapter}_connection.rb"] + ["spec/schemas/#{adapter}_schema.rb"] + diff --git a/arel.gemspec b/arel.gemspec index b5267cf3337e9..24a73d78cd530 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-02-05} + s.date = %q{2010-02-13} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 @@ -146,6 +146,7 @@ and query generation.} "spec/arel/engines/sql/unit/relations/update_spec.rb", "spec/arel/engines/sql/unit/relations/where_spec.rb", "spec/connections/mysql_connection.rb", + "spec/connections/oracle_connection.rb", "spec/connections/postgresql_connection.rb", "spec/connections/sqlite3_connection.rb", "spec/doubles/hash.rb", @@ -153,6 +154,7 @@ and query generation.} "spec/matchers/disambiguate_attributes.rb", "spec/matchers/hash_the_same_as.rb", "spec/schemas/mysql_schema.rb", + "spec/schemas/oracle_schema.rb", "spec/schemas/postgresql_schema.rb", "spec/schemas/sqlite3_schema.rb", "spec/spec.opts", @@ -221,6 +223,7 @@ and query generation.} "spec/arel/engines/sql/unit/relations/update_spec.rb", "spec/arel/engines/sql/unit/relations/where_spec.rb", "spec/connections/mysql_connection.rb", + "spec/connections/oracle_connection.rb", "spec/connections/postgresql_connection.rb", "spec/connections/sqlite3_connection.rb", "spec/doubles/hash.rb", @@ -228,6 +231,7 @@ and query generation.} "spec/matchers/disambiguate_attributes.rb", "spec/matchers/hash_the_same_as.rb", "spec/schemas/mysql_schema.rb", + "spec/schemas/oracle_schema.rb", "spec/schemas/postgresql_schema.rb", "spec/schemas/sqlite3_schema.rb", "spec/spec_helper.rb" diff --git a/lib/arel/engines/sql/compilers/oracle_compiler.rb b/lib/arel/engines/sql/compilers/oracle_compiler.rb new file mode 100644 index 0000000000000..1f6b82dd2feae --- /dev/null +++ b/lib/arel/engines/sql/compilers/oracle_compiler.rb @@ -0,0 +1,101 @@ +module Arel + module SqlCompiler + class OracleCompiler < GenericCompiler + + def select_sql + where_clauses_array = where_clauses + if limit_or_offset = !taken.blank? || !skipped.blank? + # if need to select first records without ORDER BY and GROUP BY + # then can use simple ROWNUM in WHERE clause + if skipped.blank? && groupings.blank? && orders.blank? + where_clauses_array << "ROWNUM <= #{taken}" if !taken.blank? && skipped.blank? && groupings.blank? && orders.blank? + limit_or_offset = false + end + end + + # when limit or offset subquery is used then cannot use FOR UPDATE directly + # and need to construct separate subquery for primary key + if use_subquery_for_lock = limit_or_offset && !locked.blank? + primary_key = begin + engine.quote_column_name(table.name.classify.constantize.primary_key) + rescue NameError + engine.quote_column_name("id") + end + select_attributes_string = primary_key + else + select_attributes_string = select_clauses.join(', ') + end + + # OracleEnhanced adapter workaround when ORDER BY is used with columns not + # present in DISTINCT columns list + order_clauses_array = if select_attributes_string =~ /DISTINCT.*FIRST_VALUE/ && !orders.blank? + order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?) + order = order.zip((0...order.size).to_a).map { |s,i| "alias_#{i}__ #{'DESC' if s =~ /\bdesc$/i}" } + else + order_clauses + end + + query = build_query \ + "SELECT #{select_attributes_string}", + "FROM #{from_clauses}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses_array.join(" AND ")}" unless where_clauses_array.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), + ("ORDER BY #{order_clauses_array.join(', ')}" unless order_clauses_array.blank? ) + + # Use existing method from oracle_enhanced adapter to implement limit and offset using subqueries + engine.add_limit_offset!(query, :limit => taken, :offset => skipped) if limit_or_offset + + if use_subquery_for_lock + build_query \ + "SELECT #{select_clauses.join(', ')}", + "FROM #{from_clauses}", + "WHERE #{primary_key} IN (#{query})", + "#{locked}" + elsif !locked.blank? + build_query query, "#{locked}" + else + query + end + end + + def delete_sql + where_clauses_array = wheres.collect(&:to_sql) + where_clauses_array << "ROWNUM <= #{taken}" unless taken.blank? + build_query \ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? ) + end + + protected + + def build_update_conditions_sql + conditions = "" + where_clauses_array = wheres.collect(&:to_sql) + # if need to select first records without ORDER BY + # then can use simple ROWNUM in WHERE clause + if !taken.blank? && orders.blank? + where_clauses_array << "ROWNUM <= #{taken}" + end + conditions << " WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? + unless taken.blank? + conditions = limited_update_conditions(conditions, taken) + end + conditions + end + + def limited_update_conditions(conditions, taken) + # need to add ORDER BY only if just taken ones should be updated + conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? + quoted_primary_key = engine.quote_column_name(primary_key) + subquery = "SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions}" + # Use existing method from oracle_enhanced adapter to get taken records when ORDER BY is used + engine.add_limit_offset!(subquery, :limit => taken) unless orders.blank? + "WHERE #{quoted_primary_key} IN (#{subquery})" + end + + end + end +end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index f0991f0a0feec..054de21a705b2 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -11,7 +11,13 @@ def connection end def adapter_name - @adapter_name ||= connection.adapter_name + @adapter_name ||= case (name = connection.adapter_name) + # map OracleEnanced adapter to Oracle + when /Oracle/ + 'Oracle' + else + name + end end def method_missing(method, *args, &block) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 8da362ef3bcd0..892f0c29eee8e 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -93,7 +93,7 @@ def select(select_sql, table) class TableReference < Formatter def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(name_for(table))}" + "(#{select_sql})#{as_keyword}#{quote_table_name(name_for(table))}" end def table(table) @@ -101,9 +101,16 @@ def table(table) table.name else quote_table_name(table.name) + - (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') + (table.name != name_for(table) ? as_keyword + quote_table_name(name_for(table)) : '') end end + + private + + def as_keyword + # AS keyword should not be used before table alias in Oracle + as_keyword = engine.adapter_name == "Oracle" ? " " : " AS " + end end class Attribute < WhereCondition diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 597ed88683a5d..fc8d484276580 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -21,20 +21,55 @@ def select_sql ("#{locked}" unless locked.blank?) end - def limited_update_conditions(conditions, taken) - conditions << " LIMIT #{taken}" - quoted_primary_key = engine.quote_table_name(primary_key) - "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" + def delete_sql + build_query \ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ), + (add_limit_on_delete(taken) unless taken.blank? ) end def add_limit_on_delete(taken) "LIMIT #{taken}" end + def insert_sql(include_returning = true) + insertion_attributes_values_sql = if record.is_a?(Value) + record.value + else + attributes = record.keys.sort_by do |attribute| + attribute.name.to_s + end + + first = attributes.collect do |key| + engine.quote_column_name(key.name) + end.join(', ') + + second = attributes.collect do |key| + key.format(record[key]) + end.join(', ') + + build_query "(#{first})", "VALUES (#{second})" + end + + build_query \ + "INSERT", + "INTO #{table_sql}", + insertion_attributes_values_sql, + ("RETURNING #{engine.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?) + end + def supports_insert_with_returning? false end + def update_sql + build_query \ + "UPDATE #{table_sql} SET", + assignment_sql, + build_update_conditions_sql + end + protected def method_missing(method, *args, &block) relation.send(method, *args, &block) @@ -44,6 +79,39 @@ def build_query(*parts) parts.compact.join(" ") end + def assignment_sql + if assignments.respond_to?(:collect) + attributes = assignments.keys.sort_by do |attribute| + attribute.name.to_s + end + + attributes.map do |attribute| + value = assignments[attribute] + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(", ") + else + assignments.value + end + end + + def build_update_conditions_sql + conditions = "" + conditions << " WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? + conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? + + unless taken.blank? + conditions = limited_update_conditions(conditions, taken) + end + + conditions + end + + def limited_update_conditions(conditions, taken) + conditions << " LIMIT #{taken}" + quoted_primary_key = engine.quote_column_name(primary_key) + "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" + end + end end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 54eaee9ead12f..4ed817f85d080 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -1,77 +1,19 @@ module Arel class Deletion < Compound def to_sql - build_query \ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ), - (compiler.add_limit_on_delete(taken) unless taken.blank? ) + compiler.delete_sql end end class Insert < Compound def to_sql(include_returning = true) - insertion_attributes_values_sql = if record.is_a?(Value) - record.value - else - attributes = record.keys.sort_by do |attribute| - attribute.name.to_s - end - - first = attributes.collect do |key| - engine.quote_column_name(key.name) - end.join(', ') - - second = attributes.collect do |key| - key.format(record[key]) - end.join(', ') - - build_query "(#{first})", "VALUES (#{second})" - end - - build_query \ - "INSERT", - "INTO #{table_sql}", - insertion_attributes_values_sql, - ("RETURNING #{engine.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?) + compiler.insert_sql(include_returning) end end class Update < Compound def to_sql - build_query \ - "UPDATE #{table_sql} SET", - assignment_sql, - build_update_conditions_sql - end - - protected - - def assignment_sql - if assignments.respond_to?(:collect) - attributes = assignments.keys.sort_by do |attribute| - attribute.name.to_s - end - - attributes.map do |attribute| - value = assignments[attribute] - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(", ") - else - assignments.value - end - end - - def build_update_conditions_sql - conditions = "" - conditions << " WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? - conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? - - unless taken.blank? - conditions = compiler.limited_update_conditions(conditions,taken) - end - - conditions + compiler.update_sql end end end diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index db754d9cec57c..0dfcff1ee8f89 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -12,6 +12,11 @@ module Arel @photos.delete @photos.insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) @photos.insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) + # Oracle adapter returns database integers as Ruby integers and not strings + @adapter_returns_integer = false + adapter_is :oracle do + @adapter_returns_integer = true + end end describe 'when the in memory relation is on the left' do @@ -22,8 +27,8 @@ module Arel .project(@users[:name], @photos[:camera_id]) \ .let do |relation| relation.call.should == [ - Row.new(relation, ['bryan', '6']), - Row.new(relation, ['emilio', '42']) + Row.new(relation, ['bryan', @adapter_returns_integer ? 6 : '6']), + Row.new(relation, ['emilio', @adapter_returns_integer ? 42 : '42']) ] end end @@ -37,8 +42,8 @@ module Arel .project(@users[:name], @photos[:camera_id]) \ .let do |relation| relation.call.should == [ - Row.new(relation, ['bryan', '6']), - Row.new(relation, ['emilio', '42']) + Row.new(relation, ['bryan', @adapter_returns_integer ? 6 : '6']), + Row.new(relation, ['emilio', @adapter_returns_integer ? 42 : '42']) ] end end diff --git a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb index 37afb1a8f2728..47d37415ae6a9 100644 --- a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb @@ -22,7 +22,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME" + FROM "USERS" + INNER JOIN "USERS" "USERS_2" + ON "USERS"."ID" = "USERS_2"."ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" FROM "users" @@ -48,7 +57,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME" + FROM "USERS" + INNER JOIN "USERS" "USERS_2" + ON "USERS"."ID" = "USERS_2"."ID" AND "USERS_2"."ID" = 1 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" FROM "users" @@ -76,7 +94,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME" + FROM "USERS" + INNER JOIN "USERS" "USERS_2" + ON "USERS_2"."ID" = "USERS"."ID" AND "USERS_2"."ID" = 1 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" FROM "users" @@ -113,7 +140,18 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME", "USERS_3"."ID", "USERS_3"."NAME" + FROM "USERS" + INNER JOIN "USERS" "USERS_2" + ON "USERS"."ID" = "USERS_2"."ID" + INNER JOIN "USERS" "USERS_3" + ON "USERS_2"."ID" = "USERS_3"."ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" FROM "users" @@ -144,7 +182,18 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME", "USERS_3"."ID", "USERS_3"."NAME" + FROM "USERS" + INNER JOIN "USERS" "USERS_2" + ON "USERS"."ID" = "USERS_2"."ID" + INNER JOIN "USERS" "USERS_3" + ON "USERS_2"."ID" = "USERS_3"."ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" FROM "users" diff --git a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb index 5ed530508ad58..1ed056ca59374 100644 --- a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb @@ -29,7 +29,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS_EXTERNAL"."ID", "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CAMERA_ID" + FROM "USERS" + INNER JOIN (SELECT "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" FROM "PHOTOS" WHERE ROWNUM <= 3) "PHOTOS_EXTERNAL" + ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" FROM "users" @@ -52,7 +61,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT" + FROM "USERS" + INNER JOIN (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" + ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" FROM "users" @@ -76,7 +94,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT", "USERS"."ID", "USERS"."NAME" + FROM (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" + INNER JOIN "USERS" + ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" @@ -101,7 +128,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT", "PHOTOS_EXTERNAL_2"."USER_ID", "PHOTOS_EXTERNAL_2"."CNT" + FROM (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" + INNER JOIN (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL_2" + ON "PHOTOS_EXTERNAL_2"."USER_ID" = "PHOTOS_EXTERNAL"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" @@ -126,7 +162,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT" + FROM "USERS" + INNER JOIN (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" WHERE "PHOTOS"."USER_ID" = 1 GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" + ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" FROM "users" @@ -150,7 +195,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT", "USERS"."ID", "USERS"."NAME" + FROM (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" WHERE "PHOTOS"."USER_ID" = 1 GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" + INNER JOIN "USERS" + ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" diff --git a/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb index 5909716542353..65fe49d128e2c 100644 --- a/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb @@ -26,7 +26,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" + FROM "USERS" + INNER JOIN "PHOTOS" + ON "USERS"."ID" = "PHOTOS"."USER_ID" AND asdf + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "users" @@ -59,7 +68,18 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" + FROM "USERS" + INNER JOIN "PHOTOS" + ON "USERS"."ID" = "PHOTOS"."USER_ID" + WHERE "USERS"."ID" = 1 + AND "USERS"."ID" = 1 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "users" @@ -90,7 +110,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" + FROM "USERS" + INNER JOIN "PHOTOS" + ON "USERS"."ID" = "PHOTOS"."USER_ID" + GROUP BY "USERS"."ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "users" diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 08f3310f8e01e..72c8e448881f6 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -37,6 +37,10 @@ def predicate_sql adapter_is :sqlite3 do sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) end + + adapter_is :oracle do + sql.should be_like(%Q{("USERS"."ID" <=> 1 OR "USERS"."NAME" <=> 'name')}) + end end end end @@ -57,6 +61,10 @@ def predicate_sql adapter_is :postgresql do sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> E'name')}) end + + adapter_is :oracle do + sql.should be_like(%Q{("USERS"."ID" <=> 1 AND "USERS"."NAME" <=> 'name')}) + end end end end @@ -71,7 +79,11 @@ def predicate_sql sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" <=> "USERS"."NAME"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" <=> "users"."name"}) end end @@ -90,7 +102,11 @@ def predicate_sql sql.should be_like(%Q{`users`.`id` <=> 1}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" <=> 1}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" <=> 1}) end end @@ -111,6 +127,10 @@ def predicate_sql adapter_is :postgresql do sql.should be_like(%Q{"users"."name" <=> E'1-asdf'}) end + + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."NAME" <=> '1-asdf'}) + end end end end diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index 7a5cb42c85de6..bfd61185f28b5 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -19,7 +19,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" = "PHOTOS"."USER_ID"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) end end @@ -37,7 +41,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` IS NULL}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IS NULL}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" IS NULL}) end end @@ -52,7 +60,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` IS NULL}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IS NULL}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" IS NULL}) end end diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index a1c42f714e258..5d9b2cdcaac49 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -22,7 +22,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IN (1, 2, 3)}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) end end @@ -40,7 +44,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IN (1, 2, 3)}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) end end @@ -58,7 +66,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` IN (NULL)}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IN (NULL)}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" IN (NULL)}) end end @@ -78,7 +90,11 @@ module Predicates sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" BETWEEN 1 AND 2}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) end end @@ -109,6 +125,10 @@ module Predicates adapter_is :postgresql do sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00.000000' AND '2010-02-01 00:00:00.000000'}) end + + adapter_is :oracle do + sql.should be_like(%Q{"DEVELOPERS"."CREATED_AT" BETWEEN TO_TIMESTAMP('2010-01-01 00:00:00:000000','YYYY-MM-DD HH24:MI:SS:FF6') AND TO_TIMESTAMP('2010-02-01 00:00:00:000000','YYYY-MM-DD HH24:MI:SS:FF6')}) + end end end @@ -122,7 +142,13 @@ module Predicates }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + "USERS"."ID" IN (SELECT "USERS"."ID", "USERS"."NAME" FROM "USERS") + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") }) diff --git a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb index 81c348357ce38..e6130cf267dd6 100644 --- a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb @@ -33,6 +33,12 @@ module Predicates ("users"."id" = 1 AND "users"."name" = E'name') }) end + + adapter_is :oracle do + sql.should be_like(%Q{ + ("USERS"."ID" = 1 AND "USERS"."NAME" = 'name') + }) + end end end end @@ -59,6 +65,12 @@ module Predicates ("users"."id" = 1 OR "users"."name" = E'name') }) end + + adapter_is :oracle do + sql.should be_like(%Q{ + ("USERS"."ID" = 1 OR "USERS"."NAME" = 'name') + }) + end end end end diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index d24b6a9d13c8c..9f864dd3a1f62 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -22,7 +22,11 @@ module Arel sql.should be_like(%Q{`users`.`id`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{"users"."id"}) end end diff --git a/spec/arel/engines/sql/unit/primitives/expression_spec.rb b/spec/arel/engines/sql/unit/primitives/expression_spec.rb index d4df4f8d5a798..3b6a7314a287d 100644 --- a/spec/arel/engines/sql/unit/primitives/expression_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/expression_spec.rb @@ -15,7 +15,11 @@ module Arel sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{COUNT("USERS"."ID") AS "ALIAS"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{COUNT("users"."id") AS "alias"}) end end diff --git a/spec/arel/engines/sql/unit/primitives/literal_spec.rb b/spec/arel/engines/sql/unit/primitives/literal_spec.rb index cf66a60be9f91..3bf60100f12cb 100644 --- a/spec/arel/engines/sql/unit/primitives/literal_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/literal_spec.rb @@ -14,7 +14,11 @@ module Arel sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM `users`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "USERS"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "users"}) end end @@ -26,7 +30,11 @@ module Arel sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM `users`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM "USERS"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM "users"}) end end diff --git a/spec/arel/engines/sql/unit/relations/alias_spec.rb b/spec/arel/engines/sql/unit/relations/alias_spec.rb index 55d5a9b671387..a6fd7ab036f9c 100644 --- a/spec/arel/engines/sql/unit/relations/alias_spec.rb +++ b/spec/arel/engines/sql/unit/relations/alias_spec.rb @@ -27,7 +27,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID" + FROM "USERS" + WHERE "USERS"."ID" = 1 + GROUP BY "USERS"."ID" + ORDER BY "USERS"."ID" ASC + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/delete_spec.rb b/spec/arel/engines/sql/unit/relations/delete_spec.rb index 0b1e2329b63d4..302a13c688ef7 100644 --- a/spec/arel/engines/sql/unit/relations/delete_spec.rb +++ b/spec/arel/engines/sql/unit/relations/delete_spec.rb @@ -14,7 +14,11 @@ module Arel sql.should be_like(%Q{DELETE FROM `users`}) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{DELETE FROM "USERS"}) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{DELETE FROM "users"}) end end @@ -30,7 +34,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + DELETE + FROM "USERS" + WHERE "USERS"."ID" = 1 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ DELETE FROM "users" @@ -50,7 +62,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + DELETE + FROM "USERS" + WHERE ROWNUM <= 1 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ DELETE FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/from_spec.rb b/spec/arel/engines/sql/unit/relations/from_spec.rb index a611cd65f440e..0be3ac0f9ac36 100644 --- a/spec/arel/engines/sql/unit/relations/from_spec.rb +++ b/spec/arel/engines/sql/unit/relations/from_spec.rb @@ -17,7 +17,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM workers + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM workers @@ -37,7 +44,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM users + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM users diff --git a/spec/arel/engines/sql/unit/relations/group_spec.rb b/spec/arel/engines/sql/unit/relations/group_spec.rb index 703dc35be5e14..72a9f4e99e1aa 100644 --- a/spec/arel/engines/sql/unit/relations/group_spec.rb +++ b/spec/arel/engines/sql/unit/relations/group_spec.rb @@ -20,7 +20,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + GROUP BY "USERS"."ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -42,7 +50,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + GROUP BY asdf + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/having_spec.rb b/spec/arel/engines/sql/unit/relations/having_spec.rb index 915ee3af0887f..fe6f3cc5201ca 100644 --- a/spec/arel/engines/sql/unit/relations/having_spec.rb +++ b/spec/arel/engines/sql/unit/relations/having_spec.rb @@ -20,7 +20,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "DEVELOPERS"."ID", "DEVELOPERS"."NAME", "DEVELOPERS"."SALARY", "DEVELOPERS"."DEPARTMENT", "DEVELOPERS"."CREATED_AT" + FROM "DEVELOPERS" + GROUP BY "DEVELOPERS"."DEPARTMENT" + HAVING MIN(salary) > 1000 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department", "developers"."created_at" FROM "developers" diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb index 69c5bb052cfd4..4b412093e4fc3 100644 --- a/spec/arel/engines/sql/unit/relations/insert_spec.rb +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -46,6 +46,14 @@ module Arel RETURNING "id" }) end + + adapter_is :oracle do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "USERS" + ("ID", "NAME") VALUES (1, 'nick') + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -78,6 +86,14 @@ module Arel RETURNING "id" }) end + + adapter_is :oracle do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "USERS" + ("NAME") VALUES ('nick') + }) + end end end @@ -111,6 +127,15 @@ module Arel RETURNING "id" }) end + + adapter_is :oracle do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "USERS" + ("ID") VALUES (1) + }) + end + end end end diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index b926c2aaabaaa..2d23a06397e6e 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -28,7 +28,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" + FROM "USERS" + INNER JOIN "PHOTOS" ON "USERS"."ID" = "PHOTOS"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "users" @@ -49,7 +57,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "SUPER_USERS"."ID", "SUPER_USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" + FROM "USERS" "SUPER_USERS" + INNER JOIN "PHOTOS" ON "SUPER_USERS"."ID" = "PHOTOS"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "super_users"."id", "super_users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "users" AS "super_users" @@ -71,7 +87,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "SUPER_USERS"."ID", "SUPER_USERS"."NAME", "SUPER_PHOTOS"."ID", "SUPER_PHOTOS"."USER_ID", "SUPER_PHOTOS"."CAMERA_ID" + FROM "USERS" "SUPER_USERS" + INNER JOIN "PHOTOS" "SUPER_PHOTOS" ON "SUPER_USERS"."ID" = "SUPER_PHOTOS"."USER_ID" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "super_users"."id", "super_users"."name", "super_photos"."id", "super_photos"."user_id", "super_photos"."camera_id" FROM "users" AS "super_users" @@ -95,7 +119,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + INNER JOIN asdf ON fdsa + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -119,7 +151,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + INNER JOIN asdf ON fdsa + INNER JOIN lifo ON fifo + INNER JOIN hatful ON hallow + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/lock_spec.rb b/spec/arel/engines/sql/unit/relations/lock_spec.rb index 23f8a9f577a8b..72a8a2e457ce6 100644 --- a/spec/arel/engines/sql/unit/relations/lock_spec.rb +++ b/spec/arel/engines/sql/unit/relations/lock_spec.rb @@ -30,6 +30,24 @@ module Arel FROM "users" }) end + + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" FOR UPDATE + }) + + sql_with_order_by = @relation.order(@relation[:id]).take(1).lock.to_sql + sql_with_order_by.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + WHERE "ID" IN (select * from + (SELECT "ID" FROM "USERS" ORDER BY "USERS"."ID" ASC) + where rownum <= 1) + FOR UPDATE + }) + + end end it "manufactures a select query locking with a given lock" do @@ -55,6 +73,13 @@ module Arel FROM "users" }) end + + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" LOCK IN SHARE MODE + }) + end end end end diff --git a/spec/arel/engines/sql/unit/relations/order_spec.rb b/spec/arel/engines/sql/unit/relations/order_spec.rb index 575e617021fe7..3c9d9ef59884a 100644 --- a/spec/arel/engines/sql/unit/relations/order_spec.rb +++ b/spec/arel/engines/sql/unit/relations/order_spec.rb @@ -20,7 +20,31 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + ORDER BY "USERS"."ID" ASC + }) + + distinct_attributes = ActiveRecord::Base.connection.distinct('"USERS"."NAME"', '"USERS"."ID"') + @relation.project(distinct_attributes).order(@relation[:id]).to_sql.should be_like(%Q{ + SELECT DISTINCT "USERS"."NAME", + FIRST_VALUE("USERS"."ID") OVER (PARTITION BY "USERS"."NAME" ORDER BY "USERS"."ID") AS alias_0__ + FROM "USERS" + ORDER BY alias_0__ + }) + + distinct_attributes = ActiveRecord::Base.connection.distinct('"USERS"."NAME"', '"USERS"."ID" DESC') + @relation.project(distinct_attributes).order('"USERS"."ID" DESC').to_sql.should be_like(%Q{ + SELECT DISTINCT "USERS"."NAME", + FIRST_VALUE("USERS"."ID") OVER (PARTITION BY "USERS"."NAME" ORDER BY "USERS"."ID" DESC) AS alias_0__ + FROM "USERS" + ORDER BY alias_0__ DESC + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -46,7 +70,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + ORDER BY "USERS"."ID" ASC, "USERS"."NAME" ASC + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -72,7 +104,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + ORDER BY asdf + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -99,7 +139,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + ORDER BY "USERS"."NAME" ASC, "USERS"."ID" ASC + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/project_spec.rb b/spec/arel/engines/sql/unit/relations/project_spec.rb index 70f2dff70a4ae..e73c7775a1076 100644 --- a/spec/arel/engines/sql/unit/relations/project_spec.rb +++ b/spec/arel/engines/sql/unit/relations/project_spec.rb @@ -19,7 +19,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID" + FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id" FROM "users" @@ -42,7 +49,13 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT (SELECT "USERS"."NAME" FROM "USERS") AS "USERS" FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users" }) @@ -60,7 +73,13 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT asdf FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT asdf FROM "users" }) @@ -79,7 +98,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT COUNT("USERS"."ID") AS count_id + FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT COUNT("users"."id") AS count_id FROM "users" @@ -97,7 +123,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT "USERS"."ID") AS count_id + FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT COUNT(DISTINCT "users"."id") AS count_id FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/skip_spec.rb b/spec/arel/engines/sql/unit/relations/skip_spec.rb index 2d606359ee4dd..41b80d12d8117 100644 --- a/spec/arel/engines/sql/unit/relations/skip_spec.rb +++ b/spec/arel/engines/sql/unit/relations/skip_spec.rb @@ -19,7 +19,16 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + select * from (select raw_sql_.*, rownum raw_rnum_ from + (SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS") raw_sql_) + where raw_rnum_ > 4 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index d8584ccaeceed..e497e1b6c2a8e 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -17,7 +17,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -37,7 +44,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "SUPER_USERS"."ID", "SUPER_USERS"."NAME" + FROM "USERS" "SUPER_USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "super_users"."id", "super_users"."name" FROM "users" AS "super_users" @@ -55,7 +69,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/take_spec.rb b/spec/arel/engines/sql/unit/relations/take_spec.rb index 2a8aea3d9de3d..9f2967a0bd373 100644 --- a/spec/arel/engines/sql/unit/relations/take_spec.rb +++ b/spec/arel/engines/sql/unit/relations/take_spec.rb @@ -19,7 +19,24 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + WHERE ROWNUM <= 4 + }) + + sql_with_order_by = Take.new(@relation.order(@relation[:id]), @taken).to_sql + sql_with_order_by.should be_like(%Q{ + select * from + (SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + ORDER BY "USERS"."ID" ASC) + where rownum <= 4 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb index fd444e27a8329..cc2ad9913bbbc 100644 --- a/spec/arel/engines/sql/unit/relations/update_spec.rb +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -36,6 +36,13 @@ module Arel SET "id" = 1, "name" = E'nick' }) end + + adapter_is :oracle do + sql.should be_like(%Q{ + UPDATE "USERS" + SET "ID" = 1, "NAME" = 'nick' + }) + end end it "manufactures sql updating attributes when given a ranged relation" do @@ -64,6 +71,23 @@ module Arel WHERE "id" IN (SELECT "id" FROM "users" LIMIT 1) }) end + + adapter_is :oracle do + sql.should be_like(%Q{ + UPDATE "USERS" SET + "NAME" = 'nick' + WHERE "ID" IN (SELECT "ID" FROM "USERS" WHERE ROWNUM <= 1) + }) + + sql_with_order_by = Update.new(@relation.order(@relation[:id]).take(1), @relation[:name] => "nick").to_sql + sql_with_order_by.should be_like(%Q{ + UPDATE "USERS" SET + "NAME" = 'nick' + WHERE "ID" IN (select * from + (SELECT "ID" FROM "USERS" ORDER BY "USERS"."ID" ASC) + where rownum <= 1) + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -92,6 +116,13 @@ module Arel SET "name" = E'nick' }) end + + adapter_is :oracle do + @update.to_sql.should be_like(%Q{ + UPDATE "USERS" + SET "NAME" = 'nick' + }) + end end end @@ -108,7 +139,14 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + @update.to_sql.should be_like(%Q{ + UPDATE "USERS" + SET "ID" = 1 + }) + end + + adapter_is_not :mysql, :oracle do @update.to_sql.should be_like(%Q{ UPDATE "users" SET "id" = 1 @@ -149,6 +187,14 @@ module Arel WHERE "users"."id" = 1 }) end + + adapter_is :oracle do + @update.to_sql.should be_like(%Q{ + UPDATE "USERS" + SET "NAME" = 'nick' + WHERE "USERS"."ID" = 1 + }) + end end end end diff --git a/spec/arel/engines/sql/unit/relations/where_spec.rb b/spec/arel/engines/sql/unit/relations/where_spec.rb index 8f9a8db4c7094..5f559efad3e37 100644 --- a/spec/arel/engines/sql/unit/relations/where_spec.rb +++ b/spec/arel/engines/sql/unit/relations/where_spec.rb @@ -20,7 +20,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + WHERE "USERS"."ID" = 1 + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" @@ -42,7 +50,15 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "USERS"."ID", "USERS"."NAME" + FROM "USERS" + WHERE asdf + }) + end + + adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" diff --git a/spec/connections/oracle_connection.rb b/spec/connections/oracle_connection.rb new file mode 100644 index 0000000000000..05be04e410f68 --- /dev/null +++ b/spec/connections/oracle_connection.rb @@ -0,0 +1,19 @@ +puts "Using native Oracle" +require "active_record" +require 'logger' + +# Prepend oracle_enhanced local development directory in front of load path +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../oracle-enhanced/lib" + +ActiveRecord::Base.logger = Logger.new("debug.log") + +ActiveRecord::Base.configurations = { + 'unit' => { + :adapter => 'oracle_enhanced', + :username => 'arel_unit', + :password => 'arel_unit', + :database => 'orcl', + } +} + +ActiveRecord::Base.establish_connection 'unit' diff --git a/spec/schemas/oracle_schema.rb b/spec/schemas/oracle_schema.rb new file mode 100644 index 0000000000000..c8207c8d98a60 --- /dev/null +++ b/spec/schemas/oracle_schema.rb @@ -0,0 +1,20 @@ +ActiveRecord::Schema.define do + suppress_messages do + create_table :users, :primary_key_trigger => true, :force => true do |t| + t.string :name, :limit => 255, :null => false + end + + create_table :photos, :primary_key_trigger => true, :force => true do |t| + t.integer :user_id + t.integer :camera_id + end + + create_table :developers, :primary_key_trigger => true, :force => true do |t| + t.string :name, :limit => 255, :null => false + t.integer :salary + t.string :department, :limit => 255, :null => false + t.timestamp :created_at, :null => false + end + + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6d99fa40385b6..1c45f34dfedf7 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,18 +12,21 @@ end module AdapterGuards - def adapter_is(name) - verify_adapter_name(name) - yield if name.to_s == adapter_name + def adapter_is(*names) + names = names.map(&:to_s) + names.each{|name| verify_adapter_name(name)} + yield if names.include? adapter_name end - def adapter_is_not(name) - verify_adapter_name(name) - yield if name.to_s != adapter_name + def adapter_is_not(*names) + names = names.map(&:to_s) + names.each{|name| verify_adapter_name(name)} + yield unless names.include? adapter_name end def adapter_name name = ActiveRecord::Base.configurations["unit"][:adapter] + name = 'oracle' if name == 'oracle_enhanced' verify_adapter_name(name) name end @@ -33,7 +36,7 @@ def verify_adapter_name(name) end def valid_adapters - %w[mysql postgresql sqlite3] + %w[mysql postgresql sqlite3 oracle] end end @@ -53,3 +56,9 @@ def check(*args) Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) end end + +# load corresponding adapter using ADAPTER environment variable when running single *_spec.rb file +if adapter = ENV['ADAPTER'] + require "#{dir}/connections/#{adapter}_connection.rb" + require "#{dir}/schemas/#{adapter}_schema.rb" +end From 19c4de17ed40b323b5d771b81e28fe7b7490efc2 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 1 Mar 2010 13:14:52 +0200 Subject: [PATCH 0349/1492] use primary_key method in OracleCompiler#select_sql --- lib/arel/engines/sql/compilers/oracle_compiler.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/arel/engines/sql/compilers/oracle_compiler.rb b/lib/arel/engines/sql/compilers/oracle_compiler.rb index 1f6b82dd2feae..ce575c21700dc 100644 --- a/lib/arel/engines/sql/compilers/oracle_compiler.rb +++ b/lib/arel/engines/sql/compilers/oracle_compiler.rb @@ -16,15 +16,9 @@ def select_sql # when limit or offset subquery is used then cannot use FOR UPDATE directly # and need to construct separate subquery for primary key if use_subquery_for_lock = limit_or_offset && !locked.blank? - primary_key = begin - engine.quote_column_name(table.name.classify.constantize.primary_key) - rescue NameError - engine.quote_column_name("id") - end - select_attributes_string = primary_key - else - select_attributes_string = select_clauses.join(', ') + quoted_primary_key = engine.quote_column_name(primary_key) end + select_attributes_string = use_subquery_for_lock ? quoted_primary_key : select_clauses.join(', ') # OracleEnhanced adapter workaround when ORDER BY is used with columns not # present in DISTINCT columns list @@ -51,7 +45,7 @@ def select_sql build_query \ "SELECT #{select_clauses.join(', ')}", "FROM #{from_clauses}", - "WHERE #{primary_key} IN (#{query})", + "WHERE #{quoted_primary_key} IN (#{query})", "#{locked}" elsif !locked.blank? build_query query, "#{locked}" From 07dcfd4ea7c052063e912ab479f64da78848a66e Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 1 Mar 2010 14:19:25 +0200 Subject: [PATCH 0350/1492] cache primary key per engine connection, updated gemspec file --- arel.gemspec | 8 +++++++- lib/arel/engines/sql/relations/relation.rb | 10 ++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 24a73d78cd530..4e1a52d077100 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-02-13} + s.date = %q{2010-03-01} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 @@ -69,6 +69,11 @@ and query generation.} "lib/arel/engines/memory/relations/writes.rb", "lib/arel/engines/sql.rb", "lib/arel/engines/sql/christener.rb", + "lib/arel/engines/sql/compilers/ibm_db_compiler.rb", + "lib/arel/engines/sql/compilers/mysql_compiler.rb", + "lib/arel/engines/sql/compilers/oracle_compiler.rb", + "lib/arel/engines/sql/compilers/postgresql_compiler.rb", + "lib/arel/engines/sql/compilers/sqlite_compiler.rb", "lib/arel/engines/sql/core_extensions.rb", "lib/arel/engines/sql/core_extensions/array.rb", "lib/arel/engines/sql/core_extensions/nil_class.rb", @@ -79,6 +84,7 @@ and query generation.} "lib/arel/engines/sql/predicates.rb", "lib/arel/engines/sql/primitives.rb", "lib/arel/engines/sql/relations.rb", + "lib/arel/engines/sql/relations/compiler.rb", "lib/arel/engines/sql/relations/operations/alias.rb", "lib/arel/engines/sql/relations/operations/join.rb", "lib/arel/engines/sql/relations/relation.rb", diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 4249cf9b0df38..5e8fc2e83e52a 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -1,6 +1,6 @@ module Arel class Relation - @@tables_primary_keys = {} + @@connection_tables_primary_keys = {} def compiler @compiler ||= begin @@ -23,10 +23,12 @@ def inclusion_predicate_sql end def primary_key - if @@tables_primary_keys.has_key?(table.name) - @@tables_primary_keys[table.name] + connection_id = engine.connection.object_id + if @@connection_tables_primary_keys[connection_id] && @@connection_tables_primary_keys[connection_id].has_key?(table.name) + @@connection_tables_primary_keys[connection_id][table.name] else - @@tables_primary_keys[table.name] = engine.primary_key(table.name) + @@connection_tables_primary_keys[connection_id] ||= {} + @@connection_tables_primary_keys[connection_id][table.name] = engine.connection.primary_key(table.name) end end From 5ab0598b091dbe5679f96b1f7a097178c3caaf3b Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Mon, 1 Mar 2010 16:23:09 +0200 Subject: [PATCH 0351/1492] pass primary_key value to AR adapter insert method (necessary for Oracle adapter) --- lib/arel/engines/sql/engine.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 054de21a705b2..6087a26816f36 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -26,7 +26,13 @@ def method_missing(method, *args, &block) module CRUD def create(relation) - connection.insert(relation.to_sql(false), nil, relation.primary_key) + primary_key_value = nil + if primary_key = relation.primary_key + if primary_key_attribute_and_value = relation.record.detect{|k, v| k.name.to_s == primary_key.to_s} + primary_key_value = primary_key_attribute_and_value[1].value + end + end + connection.insert(relation.to_sql(false), nil, primary_key, primary_key_value) end def read(relation) From 52b9eb1d8dea2615a8ff6182278dc53e1cf33c1d Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 1 Mar 2010 12:40:56 -0300 Subject: [PATCH 0352/1492] Prevent from getting errors when trying to get primary key value. --- lib/arel/engines/sql/engine.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 6087a26816f36..8accf3874c65e 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -26,13 +26,13 @@ def method_missing(method, *args, &block) module CRUD def create(relation) - primary_key_value = nil - if primary_key = relation.primary_key - if primary_key_attribute_and_value = relation.record.detect{|k, v| k.name.to_s == primary_key.to_s} - primary_key_value = primary_key_attribute_and_value[1].value + attribute = [*relation.record].map do |attr, value| + if attr.respond_to?(:name) && !relation.primary_key.blank? && attr.name == relation.primary_key + value end - end - connection.insert(relation.to_sql(false), nil, primary_key, primary_key_value) + end.compact.first + primary_key_value = attribute ? attribute.value : nil + connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value) end def read(relation) From 1994d3e61dd841ad1367922c5c608c9f5f277161 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 1 Mar 2010 12:51:44 -0300 Subject: [PATCH 0353/1492] Remove " AS " keyword from table aliasing. --- lib/arel/engines/sql/formatters.rb | 11 ++------ .../integration/joins/with_adjacency_spec.rb | 28 +++++++++---------- .../joins/with_aggregations_spec.rb | 28 +++++++++---------- .../engines/sql/unit/relations/join_spec.rb | 12 ++++---- .../engines/sql/unit/relations/table_spec.rb | 4 +-- 5 files changed, 38 insertions(+), 45 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 892f0c29eee8e..cdbda5ea33ee5 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -93,7 +93,7 @@ def select(select_sql, table) class TableReference < Formatter def select(select_sql, table) - "(#{select_sql})#{as_keyword}#{quote_table_name(name_for(table))}" + "(#{select_sql}) #{quote_table_name(name_for(table))}" end def table(table) @@ -101,16 +101,9 @@ def table(table) table.name else quote_table_name(table.name) + - (table.name != name_for(table) ? as_keyword + quote_table_name(name_for(table)) : '') + (table.name != name_for(table) ? " #{quote_table_name(name_for(table))}" : '') end end - - private - - def as_keyword - # AS keyword should not be used before table alias in Oracle - as_keyword = engine.adapter_name == "Oracle" ? " " : " AS " - end end class Attribute < WhereCondition diff --git a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb index 47d37415ae6a9..1a0e28838d45c 100644 --- a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb @@ -17,7 +17,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` - INNER JOIN `users` AS `users_2` + INNER JOIN `users` `users_2` ON `users`.`id` = `users_2`.`id` }) end @@ -35,7 +35,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" FROM "users" - INNER JOIN "users" AS "users_2" + INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" }) end @@ -52,7 +52,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` - INNER JOIN `users` AS `users_2` + INNER JOIN `users` `users_2` ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 }) end @@ -70,7 +70,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" FROM "users" - INNER JOIN "users" AS "users_2" + INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1 }) end @@ -89,7 +89,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` - INNER JOIN `users` AS `users_2` + INNER JOIN `users` `users_2` ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 }) end @@ -107,7 +107,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" FROM "users" - INNER JOIN "users" AS "users_2" + INNER JOIN "users" "users_2" ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1 }) end @@ -133,9 +133,9 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` FROM `users` - INNER JOIN `users` AS `users_2` + INNER JOIN `users` `users_2` ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` + INNER JOIN `users` `users_3` ON `users_2`.`id` = `users_3`.`id` }) end @@ -155,9 +155,9 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" FROM "users" - INNER JOIN "users" AS "users_2" + INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" - INNER JOIN "users" AS "users_3" + INNER JOIN "users" "users_3" ON "users_2"."id" = "users_3"."id" }) end @@ -175,9 +175,9 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` FROM `users` - INNER JOIN `users` AS `users_2` + INNER JOIN `users` `users_2` ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` + INNER JOIN `users` `users_3` ON `users_2`.`id` = `users_3`.`id` }) end @@ -197,9 +197,9 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" FROM "users" - INNER JOIN "users" AS "users_2" + INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" - INNER JOIN "users" AS "users_3" + INNER JOIN "users" "users_3" ON "users_2"."id" = "users_3"."id" }) end diff --git a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb index 1ed056ca59374..62e1b8baea34f 100644 --- a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb @@ -24,7 +24,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` FROM `users` - INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` + INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) `photos_external` ON `users`.`id` = `photos_external`.`user_id` }) end @@ -42,7 +42,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" FROM "users" - INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) AS "photos_external" + INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) "photos_external" ON "users"."id" = "photos_external"."user_id" }) end @@ -56,7 +56,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external` ON `users`.`id` = `photos_external`.`user_id` }) end @@ -74,7 +74,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" FROM "users" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external" ON "users"."id" = "photos_external"."user_id" }) end @@ -88,7 +88,7 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external` INNER JOIN `users` ON `users`.`id` = `photos_external`.`user_id` }) @@ -106,7 +106,7 @@ module Arel adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external" INNER JOIN "users" ON "users"."id" = "photos_external"."user_id" }) @@ -122,8 +122,8 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external_2` ON `photos_external_2`.`user_id` = `photos_external`.`user_id` }) end @@ -140,8 +140,8 @@ module Arel adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external_2" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external_2" ON "photos_external_2"."user_id" = "photos_external"."user_id" }) end @@ -157,7 +157,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) `photos_external` ON `users`.`id` = `photos_external`.`user_id` }) end @@ -175,7 +175,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" FROM "users" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") "photos_external" ON "users"."id" = "photos_external"."user_id" }) end @@ -189,7 +189,7 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) `photos_external` INNER JOIN `users` ON `users`.`id` = `photos_external`.`user_id` }) @@ -207,7 +207,7 @@ module Arel adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") "photos_external" INNER JOIN "users" ON "users"."id" = "photos_external"."user_id" }) diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index 2d23a06397e6e..cbbcb18244d0f 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -52,7 +52,7 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ SELECT `super_users`.`id`, `super_users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` AS `super_users` + FROM `users` `super_users` INNER JOIN `photos` ON `super_users`.`id` = `photos`.`user_id` }) end @@ -68,7 +68,7 @@ module Arel adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "super_users"."id", "super_users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" AS "super_users" + FROM "users" "super_users" INNER JOIN "photos" ON "super_users"."id" = "photos"."user_id" }) end @@ -82,8 +82,8 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ SELECT `super_users`.`id`, `super_users`.`name`, `super_photos`.`id`, `super_photos`.`user_id`, `super_photos`.`camera_id` - FROM `users` AS `super_users` - INNER JOIN `photos` AS `super_photos` ON `super_users`.`id` = `super_photos`.`user_id` + FROM `users` `super_users` + INNER JOIN `photos` `super_photos` ON `super_users`.`id` = `super_photos`.`user_id` }) end @@ -98,8 +98,8 @@ module Arel adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "super_users"."id", "super_users"."name", "super_photos"."id", "super_photos"."user_id", "super_photos"."camera_id" - FROM "users" AS "super_users" - INNER JOIN "photos" AS "super_photos" ON "super_users"."id" = "super_photos"."user_id" + FROM "users" "super_users" + INNER JOIN "photos" "super_photos" ON "super_users"."id" = "super_photos"."user_id" }) end end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index e497e1b6c2a8e..6afd9964a4190 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -40,7 +40,7 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ SELECT `super_users`.`id`, `super_users`.`name` - FROM `users` AS `super_users` + FROM `users` `super_users` }) end @@ -54,7 +54,7 @@ module Arel adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ SELECT "super_users"."id", "super_users"."name" - FROM "users" AS "super_users" + FROM "users" "super_users" }) end end From c03d4bb8e4acac95961a1a9eb9578fa33a47da66 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 1 Mar 2010 13:17:36 -0300 Subject: [PATCH 0354/1492] Refactor thethe wayy to obtain primary key value. --- lib/arel/engines/sql/engine.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 8accf3874c65e..c0e5a39e97239 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -26,12 +26,13 @@ def method_missing(method, *args, &block) module CRUD def create(relation) - attribute = [*relation.record].map do |attr, value| - if attr.respond_to?(:name) && !relation.primary_key.blank? && attr.name == relation.primary_key - value - end - end.compact.first - primary_key_value = attribute ? attribute.value : nil + primary_key_value = if relation.primary_key.blank? + nil + elsif relation.record.is_a?(Hash) + attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s } + attribute && attribute.last.value + end + connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value) end From b706f690b611d647aae15a85caa19d167814ae3c Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 10 Mar 2010 18:16:07 -0300 Subject: [PATCH 0355/1492] Arel doesn't has to know if a table or column exists. --- lib/arel/algebra/relations/relation.rb | 5 +++-- lib/arel/engines/sql/relations/table.rb | 18 +++++++++++++--- .../algebra/unit/relations/relation_spec.rb | 3 +-- .../arel/algebra/unit/relations/table_spec.rb | 1 - .../sql/unit/primitives/attribute_spec.rb | 21 ++++++++++++++++++- 5 files changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index e848c8aa1c473..4cd3f8e109365 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -84,7 +84,8 @@ def on(*predicates) module AttributeAccessable def [](index) - case index + @cached_attributes ||= {} + @cached_attributes[index] ||= case index when Symbol, String find_attribute_matching_name(index) when Attribute, Expression @@ -96,7 +97,7 @@ def [](index) end def find_attribute_matching_name(name) - attributes.detect { |a| a.named?(name) } + attributes.detect { |a| a.named?(name) } || Attribute.new(self, name) end def find_attribute_matching_attribute(attribute) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index e4b75d6c3d6e9..d10b761ea3d1f 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -2,7 +2,7 @@ module Arel class Table < Relation include Recursion::BaseCase - cattr_accessor :engine + cattr_accessor :engine, :tables attr_reader :name, :engine, :table_alias, :options def initialize(name, options = {}) @@ -19,6 +19,7 @@ def initialize(name, options = {}) if @engine.connection begin require "arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler" + @@tables ||= engine.tables rescue LoadError raise "#{@engine.adapter_name} is not supported by Arel." end @@ -29,9 +30,20 @@ def as(table_alias) Table.new(name, options.merge(:as => table_alias)) end + def table_exists? + if @table_exists + true + else + @table_exists = @@tables.include?(name) || engine.table_exists?(name) + end + end + def attributes - @attributes ||= columns.collect do |column| - Attribute.new(self, column.name.to_sym) + return @attributes if defined?(@attributes) + if table_exists? + @attributes = columns.collect { |column| Attribute.new(self, column.name.to_sym) } + else + [] end end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index cf6509fe6aa35..a1d1793d92406 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -16,10 +16,9 @@ module Arel end describe 'when given a', Symbol, String do - it "returns the attribute with the same name, if it exists" do + it "returns the attribute with the same name" do check @relation[:id].should == @attribute1 check @relation['id'].should == @attribute1 - @relation[:does_not_exist].should be_nil end end end diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb index 19c1ba2bea8cd..d93446f1b9036 100644 --- a/spec/arel/algebra/unit/relations/table_spec.rb +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -10,7 +10,6 @@ module Arel describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do check @relation[:id].should == Attribute.new(@relation, :id) - @relation[:does_not_exist].should be_nil end end diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index 9f864dd3a1f62..8daa0d9fd5b03 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#column' do it "returns the corresponding column in the relation" do - @attribute.column.should == @relation.column_for(@attribute) + @attribute.column.should == @relation.column_for(@attribute) end end @@ -31,6 +31,25 @@ module Arel end end end + + describe 'for an inexistent attribute' do + it "manufactures sql" do + sql = @relation[:does_not_exist].to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`does_not_exist`}) + end + + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."DOEST_NOT_EXIST"}) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{"users"."does_not_exist"}) + end + end + end + end end end From 54359f00b10f76e80b134dfdae973a5208da32f1 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 10 Mar 2010 18:51:01 -0300 Subject: [PATCH 0356/1492] Release v0.3.0 --- History.txt | 8 ++++++++ arel.gemspec | 2 +- lib/arel.rb | 4 ++-- spec/arel/engines/sql/unit/primitives/attribute_spec.rb | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/History.txt b/History.txt index 36dde74e4e38e..470e988b2295a 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,11 @@ +== 0.3.0 / 2010-02-05 + +* Enhancements + + * Introduced "SQL compilers" for query generation. + * Added support for Oracle (Raimonds Simanovskis) and IBM/DB (Praveen Devarao). + * Improvements to give better support to ActiveRecord. + == 0.2.1 / 2010-02-05 * Enhancements diff --git a/arel.gemspec b/arel.gemspec index 4e1a52d077100..cebbd7642b906 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.2.1" + s.version = "0.3.0" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] diff --git a/lib/arel.rb b/lib/arel.rb index 36fd961188be5..305ae99181a8c 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -7,5 +7,5 @@ module Arel require 'arel/engines' autoload :Session, 'arel/session' - VERSION = "0.2.1" -end \ No newline at end of file + VERSION = "0.3.0" +end diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index 8daa0d9fd5b03..c467d902ad4df 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#column' do it "returns the corresponding column in the relation" do - @attribute.column.should == @relation.column_for(@attribute) + @attribute.column.should == @relation.column_for(@attribute) end end From 56ff38e2b2f1faeb51d83903b4c4285c6be67a41 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 10 Mar 2010 19:05:00 -0300 Subject: [PATCH 0357/1492] Update release dates. --- History.txt | 2 +- arel.gemspec | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.txt b/History.txt index 470e988b2295a..bcec68b6cfda0 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 0.3.0 / 2010-02-05 +== 0.3.0 / 2010-03-10 * Enhancements diff --git a/arel.gemspec b/arel.gemspec index cebbd7642b906..3ea8e75211563 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-03-01} + s.date = %q{2010-03-10} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 @@ -169,7 +169,7 @@ and query generation.} s.homepage = %q{http://github.com/brynary/arel} s.require_paths = ["lib"] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.3.5} + s.rubygems_version = %q{1.3.6} s.summary = %q{Arel is a relational algebra engine for Ruby} s.test_files = [ "spec/arel/algebra/unit/predicates/binary_spec.rb", From 939b31da148aaa518640dc5c1a67d4e57febf6f1 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 10 Mar 2010 19:08:30 -0300 Subject: [PATCH 0358/1492] Release v0.3.1 --- arel.gemspec | 2 +- lib/arel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 3ea8e75211563..695f504203841 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "0.3.0" + s.version = "0.3.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] diff --git a/lib/arel.rb b/lib/arel.rb index 305ae99181a8c..14511d5b38bea 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -7,5 +7,5 @@ module Arel require 'arel/engines' autoload :Session, 'arel/session' - VERSION = "0.3.0" + VERSION = "0.3.1" end From 915606d10923e3c5de6d904b58eb13b9b5658ea4 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 11 Mar 2010 11:15:52 -0800 Subject: [PATCH 0359/1492] Latest ActiveSupport replaces metaclass with singleton_class --- lib/arel/session.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/session.rb b/lib/arel/session.rb index d844cd7423c55..c7fcc53a3b33b 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -11,13 +11,13 @@ def start begin @started = true @instance = manufacture - metaclass.class_eval do + singleton_class.class_eval do undef :new alias_method :new, :instance end yield ensure - metaclass.class_eval do + singleton_class.class_eval do undef :new alias_method :new, :manufacture end From 9e3450dd830caa8d1c12a0ce33b3837dc29d779c Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 11 Mar 2010 15:52:01 -0800 Subject: [PATCH 0360/1492] Get the specs to start when an AR connection is not present. --- lib/arel.rb | 3 ++- spec/spec_helper.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index 14511d5b38bea..ef2308ca5311b 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,7 @@ require 'active_support/inflector' -require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/class/attribute_accessors' +require 'active_support/core_ext/module/delegation' +require 'active_support/core_ext/object/blank' module Arel require 'arel/algebra' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1c45f34dfedf7..b210af5ab4d1d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -53,7 +53,7 @@ def check(*args) config.include Check config.before do - Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) + Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) if defined?(ActiveRecord::Base) end end From e3461239adfa972de8f25a2bc6b48b4a8aa62c9c Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 11 Mar 2010 16:13:47 -0800 Subject: [PATCH 0361/1492] Start writing integration specs for arel. --- .../algebra/relations/operations/where.rb | 9 ++ spec/arel/algebra/integration/basic_spec.rb | 120 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 spec/arel/algebra/integration/basic_spec.rb diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 608aaeb4b7f7f..2fc51c7f24e3f 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -9,6 +9,15 @@ def initialize(relation, *predicates, &block) @predicate = predicate.bind(@relation) end + def engine + # Temporary check of whether or not the engine supports where. + if relation.engine.respond_to?(:supports) && !relation.engine.supports(:where) + Memory::Engine.new + else + relation.engine + end + end + def wheres @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } end diff --git a/spec/arel/algebra/integration/basic_spec.rb b/spec/arel/algebra/integration/basic_spec.rb new file mode 100644 index 0000000000000..84b8105f66a48 --- /dev/null +++ b/spec/arel/algebra/integration/basic_spec.rb @@ -0,0 +1,120 @@ +require 'spec_helper' + +module Arel + module Testing + class Engine + attr_reader :rows + + def initialize + @rows = [] + end + + def supports(operation) + false + end + + def read(relation) + @rows.dup.map { |r| Row.new(relation, r) } + end + + def create(insert) + @rows << insert.record.tuple + insert + end + end + end +end + +class Thing < Arel::Relation + attr_reader :engine, :attributes + + def initialize(engine, attributes) + @engine = engine + @attributes = attributes.map { |a| a.to_attribute(self) } + end + + def format(attribute, value) + value + end + + def insert(row) + insert = super Arel::Row.new(self, row) + insert.record + end +end + +def have_rows(expected) + simple_matcher "have rows" do |given, matcher| + found, got, expected = [], [], expected.map { |r| r.tuple } + given.each do |row| + got << row.tuple + found << expected.find { |r| row.tuple == r } + end + + matcher.failure_message = "Expected to get:\n" \ + "#{expected.map {|r| " #{r.inspect}" }.join("\n")}\n" \ + "instead, got:\n" \ + "#{got.map {|r| " #{r.inspect}" }.join("\n")}" + + found.compact.length == expected.length && got.compact.length == expected.length + end +end + +share_examples_for 'A Relation' do + + before :all do + # The two needed instance variables need to be set in a + # before :all callback. + # @relation is the relation being tested here. + # @expected is an array of the elements that are expected to be in + # the relation. + %w[ @relation @expected ].each do |ivar| + raise "#{ivar} needs to be defined" unless instance_variable_get(ivar) + end + + # There needs to be enough items to be able to run all the tests + raise "@expected needs to have at least 6 items" unless @expected.length >= 6 + end + + describe "#each" do + it "iterates over the rows in any order" do + @relation.should have_rows(@expected) + end + end + + describe "#where" do + before :all do + @expected = @expected.sort_by { |r| r[@relation[:age]] } + @pivot = @expected[@expected.length / 2] + end + + it "finds rows with an equal to predicate" do + expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } + @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) + end + end +end + +describe "Arel::Relation" do + + before :all do + @engine = Arel::Testing::Engine.new + @relation = Thing.new(@engine, [:id, :name, :age]) + end + + describe "..." do + before :all do + @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) } + end + + it_should_behave_like 'A Relation' + end + + describe "#insert" do + it "inserts the row into the engine" do + @relation.insert([1, 'Foo', 10]) + @engine.rows.should == [[1, 'Foo', 10]] + end + end + +end \ No newline at end of file From 8db90ba95d4a240fde68127e806162b3e600c383 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 11 Mar 2010 17:08:55 -0800 Subject: [PATCH 0362/1492] Move all spec support files into spec/support --- .gitignore | 2 +- Rakefile | 4 +- spec/spec/fixtures/fixture_database.sqlite3 | Bin 0 -> 4096 bytes spec/spec_helper.rb | 44 ++---------------- spec/support/check.rb | 6 +++ .../connections/mysql_connection.rb | 0 .../connections/oracle_connection.rb | 0 .../connections/postgresql_connection.rb | 0 .../connections/sqlite3_connection.rb | 2 +- spec/support/doubles.rb | 1 + spec/{ => support}/doubles/hash.rb | 0 spec/support/guards.rb | 28 +++++++++++ spec/support/matchers.rb | 3 ++ spec/{ => support}/matchers/be_like.rb | 0 .../matchers/disambiguate_attributes.rb | 0 .../matchers/hash_the_same_as.rb | 0 spec/{ => support}/schemas/mysql_schema.rb | 0 spec/{ => support}/schemas/oracle_schema.rb | 0 .../schemas/postgresql_schema.rb | 0 spec/{ => support}/schemas/sqlite3_schema.rb | 0 20 files changed, 46 insertions(+), 44 deletions(-) create mode 100644 spec/spec/fixtures/fixture_database.sqlite3 create mode 100644 spec/support/check.rb rename spec/{ => support}/connections/mysql_connection.rb (100%) rename spec/{ => support}/connections/oracle_connection.rb (100%) rename spec/{ => support}/connections/postgresql_connection.rb (100%) rename spec/{ => support}/connections/sqlite3_connection.rb (92%) create mode 100644 spec/support/doubles.rb rename spec/{ => support}/doubles/hash.rb (100%) create mode 100644 spec/support/guards.rb create mode 100644 spec/support/matchers.rb rename spec/{ => support}/matchers/be_like.rb (100%) rename spec/{ => support}/matchers/disambiguate_attributes.rb (100%) rename spec/{ => support}/matchers/hash_the_same_as.rb (100%) rename spec/{ => support}/schemas/mysql_schema.rb (100%) rename spec/{ => support}/schemas/oracle_schema.rb (100%) rename spec/{ => support}/schemas/postgresql_schema.rb (100%) rename spec/{ => support}/schemas/sqlite3_schema.rb (100%) diff --git a/.gitignore b/.gitignore index 39cbb3948b811..3fec2d912b86f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ coverage/* config/database.yml -spec/fixtures/*database* +spec/support/fixtures/*database* *.DS_Store debug.log pkg diff --git a/Rakefile b/Rakefile index a1384196a2c5b..ef633c00428b6 100644 --- a/Rakefile +++ b/Rakefile @@ -28,8 +28,8 @@ else t.libs << "#{File.dirname(__FILE__)}/spec" # t.warning = true t.spec_files = - ["spec/connections/#{adapter}_connection.rb"] + - ["spec/schemas/#{adapter}_schema.rb"] + + ["spec/support/connections/#{adapter}_connection.rb"] + + ["spec/support/schemas/#{adapter}_schema.rb"] + FileList['spec/**/*_spec.rb'] end end diff --git a/spec/spec/fixtures/fixture_database.sqlite3 b/spec/spec/fixtures/fixture_database.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..cb52aacf7e137c4345145934580f9a81e92e5d1c GIT binary patch literal 4096 zcmeHGK}*9h6i(X7Q1B*{;pOeNfhT2m>j+wG>&&XK(}-(igLW-x6g*as{#}27X)9aD zrm&mPJZSp*z3}pVU-QQI?m}{SPDIQkT%Z=h7+nG&gbvhGkK!BGfO=kox6@+UQzRsbo(P5BV#Pl9Y>VowbIP*a3mSzH$kyap)a^ibV*HACPN8 z!M_W@e{fwGQOC3C1a8UXtlYF@F^5N+4sUGQJ0A@CtG!h{V-XW?TaBt>$Wta{%$M@7 z7Bj(_J&wypPv|QtJA^nW+^qDCo;*Z)!dL+Vf)B?$+(#AFrwl= zQ{n~NRWE2|xNTV$&PmCt=#-U { diff --git a/spec/support/doubles.rb b/spec/support/doubles.rb new file mode 100644 index 0000000000000..212859cbd6d8d --- /dev/null +++ b/spec/support/doubles.rb @@ -0,0 +1 @@ +require "support/doubles/hash" \ No newline at end of file diff --git a/spec/doubles/hash.rb b/spec/support/doubles/hash.rb similarity index 100% rename from spec/doubles/hash.rb rename to spec/support/doubles/hash.rb diff --git a/spec/support/guards.rb b/spec/support/guards.rb new file mode 100644 index 0000000000000..cfa4b7b79a989 --- /dev/null +++ b/spec/support/guards.rb @@ -0,0 +1,28 @@ +module AdapterGuards + def adapter_is(*names) + names = names.map(&:to_s) + names.each{|name| verify_adapter_name(name)} + yield if names.include? adapter_name + end + + def adapter_is_not(*names) + names = names.map(&:to_s) + names.each{|name| verify_adapter_name(name)} + yield unless names.include? adapter_name + end + + def adapter_name + name = ActiveRecord::Base.configurations["unit"][:adapter] + name = 'oracle' if name == 'oracle_enhanced' + verify_adapter_name(name) + name + end + + def verify_adapter_name(name) + raise "Invalid adapter name: #{name}" unless valid_adapters.include?(name.to_s) + end + + def valid_adapters + %w[mysql postgresql sqlite3 oracle] + end +end \ No newline at end of file diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb new file mode 100644 index 0000000000000..6f50d6cbc7f39 --- /dev/null +++ b/spec/support/matchers.rb @@ -0,0 +1,3 @@ +require "support/matchers/be_like" +require "support/matchers/disambiguate_attributes" +require "support/matchers/hash_the_same_as" \ No newline at end of file diff --git a/spec/matchers/be_like.rb b/spec/support/matchers/be_like.rb similarity index 100% rename from spec/matchers/be_like.rb rename to spec/support/matchers/be_like.rb diff --git a/spec/matchers/disambiguate_attributes.rb b/spec/support/matchers/disambiguate_attributes.rb similarity index 100% rename from spec/matchers/disambiguate_attributes.rb rename to spec/support/matchers/disambiguate_attributes.rb diff --git a/spec/matchers/hash_the_same_as.rb b/spec/support/matchers/hash_the_same_as.rb similarity index 100% rename from spec/matchers/hash_the_same_as.rb rename to spec/support/matchers/hash_the_same_as.rb diff --git a/spec/schemas/mysql_schema.rb b/spec/support/schemas/mysql_schema.rb similarity index 100% rename from spec/schemas/mysql_schema.rb rename to spec/support/schemas/mysql_schema.rb diff --git a/spec/schemas/oracle_schema.rb b/spec/support/schemas/oracle_schema.rb similarity index 100% rename from spec/schemas/oracle_schema.rb rename to spec/support/schemas/oracle_schema.rb diff --git a/spec/schemas/postgresql_schema.rb b/spec/support/schemas/postgresql_schema.rb similarity index 100% rename from spec/schemas/postgresql_schema.rb rename to spec/support/schemas/postgresql_schema.rb diff --git a/spec/schemas/sqlite3_schema.rb b/spec/support/schemas/sqlite3_schema.rb similarity index 100% rename from spec/schemas/sqlite3_schema.rb rename to spec/support/schemas/sqlite3_schema.rb From cbb524122c6132ba37661934c09b540a68b1c64d Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 11 Mar 2010 17:12:52 -0800 Subject: [PATCH 0363/1492] Remove crazy --- spec/support/doubles.rb | 1 - spec/support/doubles/hash.rb | 27 --------------------------- 2 files changed, 28 deletions(-) delete mode 100644 spec/support/doubles.rb delete mode 100644 spec/support/doubles/hash.rb diff --git a/spec/support/doubles.rb b/spec/support/doubles.rb deleted file mode 100644 index 212859cbd6d8d..0000000000000 --- a/spec/support/doubles.rb +++ /dev/null @@ -1 +0,0 @@ -require "support/doubles/hash" \ No newline at end of file diff --git a/spec/support/doubles/hash.rb b/spec/support/doubles/hash.rb deleted file mode 100644 index fd9edd34adfb1..0000000000000 --- a/spec/support/doubles/hash.rb +++ /dev/null @@ -1,27 +0,0 @@ -class Hash - def ordered_array - to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash } - end - - undef :keys - def keys - ordered_array.collect(&:first) - end - - undef :values - def values - ordered_array.collect { |_, v| v } - end - - undef :each - def each(&block) - ordered_array.each(&block) - end - - undef :shift - def shift - returning to_a.first do |k, v| - delete(k) - end - end -end From 5e76aa7962c4e02c67c1e1515e6ae1b5ca6190a7 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Fri, 12 Mar 2010 11:31:32 -0300 Subject: [PATCH 0364/1492] Add accessibility to projections applied to the relation. --- lib/arel/algebra/relations/relation.rb | 1 + lib/arel/algebra/relations/utilities/compound.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 4cd3f8e109365..51c622cbe8422 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -128,6 +128,7 @@ def has_attribute?(attribute) module DefaultOperations def attributes; [] end + def projections; [] end def wheres; [] end def orders; [] end def inserts; [] end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 9eca02c8c4e5e..1a43c76a94748 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -5,7 +5,7 @@ class Compound < Relation :column_for, :engine, :sources, :locked, :table_alias, :to => :relation - [:attributes, :wheres, :groupings, :orders, :havings].each do |operation_name| + [:attributes, :wheres, :groupings, :orders, :havings, :projections].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } From 83c27c0b5e2e341307b7a160d831fb930a9552b4 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 12:51:20 -0800 Subject: [PATCH 0365/1492] Attributes should be typed --- lib/arel/algebra.rb | 2 +- lib/arel/algebra/attributes.rb | 7 ++++ .../algebra/{ => attributes}/attribute.rb | 31 ++++++++++++++ lib/arel/algebra/attributes/boolean.rb | 20 +++++++++ lib/arel/algebra/attributes/decimal.rb | 9 ++++ lib/arel/algebra/attributes/float.rb | 9 ++++ lib/arel/algebra/attributes/integer.rb | 10 +++++ lib/arel/algebra/attributes/string.rb | 10 +++++ lib/arel/algebra/attributes/time.rb | 6 +++ lib/arel/engines/memory/relations/array.rb | 11 +++-- lib/arel/engines/sql.rb | 1 + lib/arel/engines/sql/attributes.rb | 40 ++++++++++++++++++ lib/arel/engines/sql/primitives.rb | 4 -- lib/arel/engines/sql/relations/table.rb | 8 ++-- spec/arel/algebra/integration/basic_spec.rb | 41 +++++++++++-------- .../integration/joins/cross_engine_spec.rb | 2 +- .../memory/unit/relations/array_spec.rb | 2 +- .../memory/unit/relations/insert_spec.rb | 2 +- .../memory/unit/relations/join_spec.rb | 2 +- .../memory/unit/relations/order_spec.rb | 2 +- .../memory/unit/relations/project_spec.rb | 2 +- .../memory/unit/relations/skip_spec.rb | 2 +- .../memory/unit/relations/take_spec.rb | 2 +- .../memory/unit/relations/where_spec.rb | 2 +- 24 files changed, 188 insertions(+), 39 deletions(-) create mode 100644 lib/arel/algebra/attributes.rb rename lib/arel/algebra/{ => attributes}/attribute.rb (77%) create mode 100644 lib/arel/algebra/attributes/boolean.rb create mode 100644 lib/arel/algebra/attributes/decimal.rb create mode 100644 lib/arel/algebra/attributes/float.rb create mode 100644 lib/arel/algebra/attributes/integer.rb create mode 100644 lib/arel/algebra/attributes/string.rb create mode 100644 lib/arel/algebra/attributes/time.rb create mode 100644 lib/arel/engines/sql/attributes.rb diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index 980c558918e01..83f6a54326253 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,6 +1,6 @@ require 'arel/algebra/core_extensions' -require 'arel/algebra/attribute' +require 'arel/algebra/attributes' require 'arel/algebra/expression' require 'arel/algebra/ordering' require 'arel/algebra/predicates' diff --git a/lib/arel/algebra/attributes.rb b/lib/arel/algebra/attributes.rb new file mode 100644 index 0000000000000..98302b6b18d80 --- /dev/null +++ b/lib/arel/algebra/attributes.rb @@ -0,0 +1,7 @@ +require "arel/algebra/attributes/attribute" +require "arel/algebra/attributes/boolean" +require "arel/algebra/attributes/decimal" +require "arel/algebra/attributes/float" +require "arel/algebra/attributes/integer" +require "arel/algebra/attributes/string" +require "arel/algebra/attributes/time" \ No newline at end of file diff --git a/lib/arel/algebra/attribute.rb b/lib/arel/algebra/attributes/attribute.rb similarity index 77% rename from lib/arel/algebra/attribute.rb rename to lib/arel/algebra/attributes/attribute.rb index 40a7d61a53fc7..f4cec828e3dfb 100644 --- a/lib/arel/algebra/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -1,6 +1,7 @@ require 'set' module Arel + class TypecastError < StandardError ; end class Attribute attributes :relation, :name, :alias, :ancestor deriving :== @@ -146,5 +147,35 @@ def desc alias_method :to_ordering, :asc end include Orderings + + module Types + def type_cast(value) + if root == self + raise NotImplementedError, "#type_cast should be implemented in a subclass." + else + root.type_cast(value) + end + end + + def type_cast_to_numeric(value, method) + return unless value + if value.respond_to?(:to_str) + if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/ + $1.send(method) + else + value + end + elsif value.respond_to?(method) + value.send(method) + else + raise typecast_error(value) + end + end + + def typecast_error(value) + raise TypecastError, "could not typecast #{value.inspect} to #{self.class.name.split('::').last}" + end + end + include Types end end diff --git a/lib/arel/algebra/attributes/boolean.rb b/lib/arel/algebra/attributes/boolean.rb new file mode 100644 index 0000000000000..0ca7cd6d24690 --- /dev/null +++ b/lib/arel/algebra/attributes/boolean.rb @@ -0,0 +1,20 @@ +module Arel + module Attributes + class Boolean < Attribute + def type_cast(value) + case value + when true, false then value + when nil then options[:allow_nil] ? nil : false + when 1 then true + when 0 then false + else + case value.to_s.downcase.strip + when 'true' then true + when 'false' then false + else raise typecast_error(value) + end + end + end + end + end +end diff --git a/lib/arel/algebra/attributes/decimal.rb b/lib/arel/algebra/attributes/decimal.rb new file mode 100644 index 0000000000000..bf6587fa34761 --- /dev/null +++ b/lib/arel/algebra/attributes/decimal.rb @@ -0,0 +1,9 @@ +module Arel + module Attributes + class Decimal < Attribute + def type_cast(val) + type_cast_to_numeric(val, :to_d) + end + end + end +end diff --git a/lib/arel/algebra/attributes/float.rb b/lib/arel/algebra/attributes/float.rb new file mode 100644 index 0000000000000..01c95e69f9f9e --- /dev/null +++ b/lib/arel/algebra/attributes/float.rb @@ -0,0 +1,9 @@ +module Arel + module Attributes + class Float < Attribute + def type_cast(val) + type_cast_to_numeric(val, :to_f) + end + end + end +end diff --git a/lib/arel/algebra/attributes/integer.rb b/lib/arel/algebra/attributes/integer.rb new file mode 100644 index 0000000000000..9a564565ff04d --- /dev/null +++ b/lib/arel/algebra/attributes/integer.rb @@ -0,0 +1,10 @@ +module Arel + module Attributes + class Integer < Attribute + def type_cast(val) + type_cast_to_numeric(val, :to_i) + end + end + end +end + \ No newline at end of file diff --git a/lib/arel/algebra/attributes/string.rb b/lib/arel/algebra/attributes/string.rb new file mode 100644 index 0000000000000..5ea91a59d810f --- /dev/null +++ b/lib/arel/algebra/attributes/string.rb @@ -0,0 +1,10 @@ +module Arel + module Attributes + class String < Attribute + def type_cast(value) + return unless value + value.to_s + end + end + end +end diff --git a/lib/arel/algebra/attributes/time.rb b/lib/arel/algebra/attributes/time.rb new file mode 100644 index 0000000000000..7a2de726c88b7 --- /dev/null +++ b/lib/arel/algebra/attributes/time.rb @@ -0,0 +1,6 @@ +module Arel + module Attributes + class Time < Attribute + end + end +end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 5e7c0a4ab1203..577e327b19d72 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -1,16 +1,21 @@ module Arel class Array < Relation - attributes :array, :attribute_names + attributes :array, :attribute_names_and_types include Recursion::BaseCase deriving :==, :initialize + def initialize(array, attribute_names_and_types) + @array, @attribute_names_and_types = array, attribute_names_and_types + end + def engine @engine ||= Memory::Engine.new end def attributes - @attributes ||= @attribute_names.collect do |name| - name.to_attribute(self) + @attributes ||= @attribute_names_and_types.collect do |attribute, type| + attribute = type.new(self, attribute) if Symbol === attribute + attribute end end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index dc40428b777e4..a7721eb909445 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -1,3 +1,4 @@ +require 'arel/engines/sql/attributes' require 'arel/engines/sql/engine' require 'arel/engines/sql/relations' require 'arel/engines/sql/primitives' diff --git a/lib/arel/engines/sql/attributes.rb b/lib/arel/engines/sql/attributes.rb new file mode 100644 index 0000000000000..2d315d53fc2be --- /dev/null +++ b/lib/arel/engines/sql/attributes.rb @@ -0,0 +1,40 @@ +module Arel + module Sql + module Attributes + def self.for(column) + case column.type + when :string then String + when :text then String + when :integer then Integer + when :float then Float + when :decimal then Decimal + when :date then Time + when :datetime then Time + when :timestamp then Time + when :time then Time + when :binary then String + when :boolean then Boolean + else + raise NotImplementedError, "Column type `#{column.type}` is not currently handled" + end + end + + def initialize(column, *args) + @column = column + super(*args) + end + + def type_cast(value) + @column.type_cast(value) + end + + %w(Boolean Decimal Float Integer String Time).each do |klass| + class_eval <<-R + class #{klass} < Arel::Attributes::#{klass} + include Attributes + end + R + end + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 6cce46a4419f9..666579331ac8d 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -16,10 +16,6 @@ def column original_relation.column_for(self) end - def type_cast(value) - root.relation.format(self, value) - end - def format(object) object.to_sql(Sql::Attribute.new(self)) end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index d10b761ea3d1f..c0d3386463f7b 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -41,7 +41,9 @@ def table_exists? def attributes return @attributes if defined?(@attributes) if table_exists? - @attributes = columns.collect { |column| Attribute.new(self, column.name.to_sym) } + @attributes = columns.collect do |column| + Sql::Attributes.for(column).new(column, self, column.name.to_sym) + end else [] end @@ -55,10 +57,6 @@ def hash @hash ||= :name.hash end - def format(attribute, value) - attribute.column.type_cast(value) - end - def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end diff --git a/spec/arel/algebra/integration/basic_spec.rb b/spec/arel/algebra/integration/basic_spec.rb index 84b8105f66a48..6ade5c40ac99e 100644 --- a/spec/arel/algebra/integration/basic_spec.rb +++ b/spec/arel/algebra/integration/basic_spec.rb @@ -29,8 +29,10 @@ class Thing < Arel::Relation attr_reader :engine, :attributes def initialize(engine, attributes) - @engine = engine - @attributes = attributes.map { |a| a.to_attribute(self) } + @engine, @attributes = engine, [] + attributes.each do |name, type| + @attributes << type.new(self, name) + end end def format(attribute, value) @@ -95,26 +97,31 @@ def have_rows(expected) end end -describe "Arel::Relation" do - - before :all do - @engine = Arel::Testing::Engine.new - @relation = Thing.new(@engine, [:id, :name, :age]) - end +module Arel + describe "Relation" do - describe "..." do before :all do - @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) } + @engine = Testing::Engine.new + @relation = Thing.new(@engine, + :id => Attributes::Integer, + :name => Attributes::String, + :age => Attributes::Integer) end - it_should_behave_like 'A Relation' - end + describe "..." do + before :all do + @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) } + end - describe "#insert" do - it "inserts the row into the engine" do - @relation.insert([1, 'Foo', 10]) - @engine.rows.should == [[1, 'Foo', 10]] + it_should_behave_like 'A Relation' + end + + describe "#insert" do + it "inserts the row into the engine" do + @relation.insert([1, 'Foo', 10]) + @engine.rows.should == [[1, 'Foo', 10]] + end end - end + end end \ No newline at end of file diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index 0dfcff1ee8f89..606f3154c7d74 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'bryan' ], [2, 'emilio' ], [3, 'nick'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) @photos = Table.new(:photos) @photos.delete @photos.insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 9a834148b1596..dcec2afa19dba 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#attributes' do diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb index 222e525c7bd0d..987e708e0b029 100644 --- a/spec/arel/engines/memory/unit/relations/insert_spec.rb +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#call' do diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb index 112434ae1d008..ed5fe89ef0b92 100644 --- a/spec/arel/engines/memory/unit/relations/join_spec.rb +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) @relation2 = @relation1.alias end diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/arel/engines/memory/unit/relations/order_spec.rb index 21d77a2a24829..9546449bfbf73 100644 --- a/spec/arel/engines/memory/unit/relations/order_spec.rb +++ b/spec/arel/engines/memory/unit/relations/order_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#call' do diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/arel/engines/memory/unit/relations/project_spec.rb index e688b93a392c5..92ed9fa74b944 100644 --- a/spec/arel/engines/memory/unit/relations/project_spec.rb +++ b/spec/arel/engines/memory/unit/relations/project_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#call' do diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/arel/engines/memory/unit/relations/skip_spec.rb index 0c2077db80a9b..089db24ceabd1 100644 --- a/spec/arel/engines/memory/unit/relations/skip_spec.rb +++ b/spec/arel/engines/memory/unit/relations/skip_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#call' do diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/arel/engines/memory/unit/relations/take_spec.rb index 4b08a63d227a1..16b99872c5385 100644 --- a/spec/arel/engines/memory/unit/relations/take_spec.rb +++ b/spec/arel/engines/memory/unit/relations/take_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#call' do diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/arel/engines/memory/unit/relations/where_spec.rb index 8d0af4b52deb1..b45c009d83433 100644 --- a/spec/arel/engines/memory/unit/relations/where_spec.rb +++ b/spec/arel/engines/memory/unit/relations/where_spec.rb @@ -7,7 +7,7 @@ module Arel [1, 'duck' ], [2, 'duck' ], [3, 'goose'] - ], [:id, :name]) + ], [[:id, Attributes::Integer], [:name, Attributes::String]]) end describe '#call' do From 61916e408d86d19d1659cd8042de6503aecc6c98 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 14:34:13 -0800 Subject: [PATCH 0366/1492] Add a bunch of specs for attribute type casting. --- lib/arel/algebra/attributes/attribute.rb | 13 +-- lib/arel/algebra/attributes/boolean.rb | 11 +- spec/arel/algebra/integration/basic_spec.rb | 58 ++-------- spec/attributes/boolean_spec.rb | 57 ++++++++++ spec/attributes/float_spec.rb | 119 ++++++++++++++++++++ spec/attributes/integer_spec.rb | 119 ++++++++++++++++++++ spec/attributes/string_spec.rb | 43 +++++++ spec/attributes/time_spec.rb | 22 ++++ spec/support/model.rb | 56 +++++++++ 9 files changed, 435 insertions(+), 63 deletions(-) create mode 100644 spec/attributes/boolean_spec.rb create mode 100644 spec/attributes/float_spec.rb create mode 100644 spec/attributes/integer_spec.rb create mode 100644 spec/attributes/string_spec.rb create mode 100644 spec/attributes/time_spec.rb create mode 100644 spec/support/model.rb diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index f4cec828e3dfb..03cf44a55212b 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -160,16 +160,13 @@ def type_cast(value) def type_cast_to_numeric(value, method) return unless value if value.respond_to?(:to_str) - if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/ - $1.send(method) - else - value - end + str = value.to_str.strip + return if str.empty? + return $1.send(method) if str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/ elsif value.respond_to?(method) - value.send(method) - else - raise typecast_error(value) + return value.send(method) end + raise typecast_error(value) end def typecast_error(value) diff --git a/lib/arel/algebra/attributes/boolean.rb b/lib/arel/algebra/attributes/boolean.rb index 0ca7cd6d24690..d69f2465df453 100644 --- a/lib/arel/algebra/attributes/boolean.rb +++ b/lib/arel/algebra/attributes/boolean.rb @@ -3,11 +3,12 @@ module Attributes class Boolean < Attribute def type_cast(value) case value - when true, false then value - when nil then options[:allow_nil] ? nil : false - when 1 then true - when 0 then false - else + when true, false then value + # when nil then options[:allow_nil] ? nil : false + when nil then false + when 1 then true + when 0 then false + else case value.to_s.downcase.strip when 'true' then true when 'false' then false diff --git a/spec/arel/algebra/integration/basic_spec.rb b/spec/arel/algebra/integration/basic_spec.rb index 6ade5c40ac99e..7aa4f7305c7fd 100644 --- a/spec/arel/algebra/integration/basic_spec.rb +++ b/spec/arel/algebra/integration/basic_spec.rb @@ -1,50 +1,5 @@ require 'spec_helper' -module Arel - module Testing - class Engine - attr_reader :rows - - def initialize - @rows = [] - end - - def supports(operation) - false - end - - def read(relation) - @rows.dup.map { |r| Row.new(relation, r) } - end - - def create(insert) - @rows << insert.record.tuple - insert - end - end - end -end - -class Thing < Arel::Relation - attr_reader :engine, :attributes - - def initialize(engine, attributes) - @engine, @attributes = engine, [] - attributes.each do |name, type| - @attributes << type.new(self, name) - end - end - - def format(attribute, value) - value - end - - def insert(row) - insert = super Arel::Row.new(self, row) - insert.record - end -end - def have_rows(expected) simple_matcher "have rows" do |given, matcher| found, got, expected = [], [], expected.map { |r| r.tuple } @@ -101,11 +56,14 @@ module Arel describe "Relation" do before :all do - @engine = Testing::Engine.new - @relation = Thing.new(@engine, - :id => Attributes::Integer, - :name => Attributes::String, - :age => Attributes::Integer) + @engine = Testing::Engine.new + @relation = Model.build do |r| + r.engine @engine + + r.attribute :id, Attributes::Integer + r.attribute :name, Attributes::String + r.attribute :age, Attributes::Integer + end end describe "..." do diff --git a/spec/attributes/boolean_spec.rb b/spec/attributes/boolean_spec.rb new file mode 100644 index 0000000000000..bb7eeb886db26 --- /dev/null +++ b/spec/attributes/boolean_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +module Arel + describe "Attributes::Boolean" do + + before :all do + @relation = Model.build do |r| + r.engine Testing::Engine.new + r.attribute :awesome, Attributes::Boolean + end + end + + def type_cast(val) + @relation[:awesome].type_cast(val) + end + + describe "#type_cast" do + it "returns same value if passed a boolean" do + val = true + type_cast(val).should eql(val) + end + + it "returns boolean representation (false) of nil" do + type_cast(nil).should eql(false) + end + + it "returns boolean representation of 'true', 'false'" do + type_cast('true').should eql(true) + type_cast('false').should eql(false) + end + + it "returns boolean representation of :true, :false" do + type_cast(:true).should eql(true) + type_cast(:false).should eql(false) + end + + it "returns boolean representation of 0, 1" do + type_cast(1).should == true + type_cast(0).should == false + end + + it "calls #to_s on arbitrary objects" do + obj = Object.new + obj.extend Module.new { def to_s ; 'true' ; end } + type_cast(obj).should == true + end + + [ Object.new, 'string', '00.0', 5 ].each do |value| + it "raises exception when attempting type_cast of non-boolean value #{value.inspect}" do + lambda do + type_cast(value) + end.should raise_error(TypecastError, /could not typecast/) + end + end + end + end +end \ No newline at end of file diff --git a/spec/attributes/float_spec.rb b/spec/attributes/float_spec.rb new file mode 100644 index 0000000000000..3d8acbde7b63d --- /dev/null +++ b/spec/attributes/float_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' +require 'bigdecimal' + +module Arel + describe "Attributes::Float" do + + before :all do + @relation = Model.build do |r| + r.engine Testing::Engine.new + r.attribute :percentage, Attributes::Float + end + end + + def type_cast(val) + @relation[:percentage].type_cast(val) + end + + describe "#type_cast" do + it "returns same value if an float" do + type_cast(24.01).should eql(24.01) + end + + it "returns nil if passed nil" do + type_cast(nil).should be_nil + end + + it "returns nil if passed empty string" do + type_cast('').should be_nil + end + + it "returns float representation of a zero string float" do + type_cast('0').should eql(0.0) + end + + it "returns float representation of a positive string integer" do + type_cast('24').should eql(24.0) + end + + it "returns float representation of a positive string integer with spaces" do + type_cast(' 24').should eql(24.0) + type_cast('24 ').should eql(24.0) + end + + it "returns float representation of a negative string float" do + type_cast('-24.23').should eql(-24.23) + end + + it "returns float representation of a negative string integer with spaces" do + type_cast('-24 ').should eql(-24.0) + type_cast(' -24').should eql(-24.0) + end + + it "returns integer representation of a zero string float" do + type_cast('0.0').should eql(0.0) + end + + it "returns integer representation of a positive string float" do + type_cast('24.35').should eql(24.35) + end + + it "returns integer representation of a positive string float with spaces" do + type_cast(' 24.35').should eql(24.35) + type_cast('24.35 ').should eql(24.35) + end + + it "returns integer representation of a negative string float" do + type_cast('-24.35').should eql(-24.35) + end + + it "returns integer representation of a negative string float with spaces" do + type_cast(' -24.35 ').should eql(-24.35) + end + + it "returns integer representation of a zero string float, with no leading digits" do + type_cast('.0').should eql(0.0) + end + + it "returns integer representation of a zero string float, with no leading digits with spaces" do + type_cast(' .0').should eql(0.0) + end + + it "returns integer representation of a positive string float, with no leading digits" do + type_cast('.41').should eql(0.41) + end + + it "returns integer representation of a zero float" do + type_cast(0.0).should eql(0.0) + end + + it "returns integer representation of a positive float" do + type_cast(24.35).should eql(24.35) + end + + it "returns integer representation of a negative float" do + type_cast(-24.35).should eql(-24.35) + end + + it "returns integer representation of a zero decimal" do + type_cast(BigDecimal('0.0')).should eql(0.0) + end + + it "returns integer representation of a positive decimal" do + type_cast(BigDecimal('24.35')).should eql(24.35) + end + + it "returns integer representation of a negative decimal" do + type_cast(BigDecimal('-24.35')).should eql(-24.35) + end + + [ Object.new, true, '00.0', '0.', 'string' ].each do |value| + it "raises exception when attempting type_cast of non-numeric value #{value.inspect}" do + lambda do + type_cast(value) + end.should raise_error(TypecastError, /could not typecast/) + end + end + end + end +end \ No newline at end of file diff --git a/spec/attributes/integer_spec.rb b/spec/attributes/integer_spec.rb new file mode 100644 index 0000000000000..611bbf2b24584 --- /dev/null +++ b/spec/attributes/integer_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' +require 'bigdecimal' + +module Arel + describe "Attributes::Integer" do + + before :all do + @relation = Model.build do |r| + r.engine Testing::Engine.new + r.attribute :age, Attributes::Integer + end + end + + def type_cast(val) + @relation[:age].type_cast(val) + end + + describe "#type_cast" do + it "returns same value if an integer" do + type_cast(24).should eql(24) + end + + it "returns nil if passed nil" do + type_cast(nil).should be_nil + end + + it "returns nil if passed empty string" do + type_cast('').should be_nil + end + + it "returns integer representation of a zero string integer" do + type_cast('0').should eql(0) + end + + it "returns integer representation of a positive string integer" do + type_cast('24').should eql(24) + end + + it "returns integer representation of a positive string integer with spaces" do + type_cast(' 24').should eql(24) + type_cast('24 ').should eql(24) + end + + it "returns integer representation of a negative string integer" do + type_cast('-24').should eql(-24) + end + + it "returns integer representation of a negative string integer with spaces" do + type_cast('-24 ').should eql(-24) + type_cast(' -24').should eql(-24) + end + + it "returns integer representation of a zero string float" do + type_cast('0.0').should eql(0) + end + + it "returns integer representation of a positive string float" do + type_cast('24.35').should eql(24) + end + + it "returns integer representation of a positive string float with spaces" do + type_cast(' 24.35').should eql(24) + type_cast('24.35 ').should eql(24) + end + + it "returns integer representation of a negative string float" do + type_cast('-24.35').should eql(-24) + end + + it "returns integer representation of a negative string float with spaces" do + type_cast(' -24.35 ').should eql(-24) + end + + it "returns integer representation of a zero string float, with no leading digits" do + type_cast('.0').should eql(0) + end + + it "returns integer representation of a zero string float, with no leading digits with spaces" do + type_cast(' .0').should eql(0) + end + + it "returns integer representation of a positive string float, with no leading digits" do + type_cast('.41').should eql(0) + end + + it "returns integer representation of a zero float" do + type_cast(0.0).should eql(0) + end + + it "returns integer representation of a positive float" do + type_cast(24.35).should eql(24) + end + + it "returns integer representation of a negative float" do + type_cast(-24.35).should eql(-24) + end + + it "returns integer representation of a zero decimal" do + type_cast(BigDecimal('0.0')).should eql(0) + end + + it "returns integer representation of a positive decimal" do + type_cast(BigDecimal('24.35')).should eql(24) + end + + it "returns integer representation of a negative decimal" do + type_cast(BigDecimal('-24.35')).should eql(-24) + end + + [ Object.new, true, '00.0', '0.', 'string' ].each do |value| + it "raises exception when attempting type_cast of non-numeric value #{value.inspect}" do + lambda do + type_cast(value) + end.should raise_error(TypecastError, /could not typecast/) + end + end + end + end +end \ No newline at end of file diff --git a/spec/attributes/string_spec.rb b/spec/attributes/string_spec.rb new file mode 100644 index 0000000000000..f6d65dd045144 --- /dev/null +++ b/spec/attributes/string_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' +require 'bigdecimal' + +module Arel + describe "Attributes::String" do + + before :all do + @relation = Model.build do |r| + r.engine Testing::Engine.new + r.attribute :name, Attributes::String + end + end + + def type_cast(val) + @relation[:name].type_cast(val) + end + + describe "#type_cast" do + it "returns same value if passed a String" do + val = "hell" + type_cast(val).should eql(val) + end + + it "returns nil if passed nil" do + type_cast(nil).should be_nil + end + + it "returns String representation of Symbol" do + type_cast(:hello).should == "hello" + end + + it "returns string representation of Integer" do + type_cast(1).should == '1' + end + + it "calls #to_s on arbitrary objects" do + obj = Object.new + obj.extend Module.new { def to_s ; 'hello' ; end } + type_cast(obj).should == 'hello' + end + end + end +end \ No newline at end of file diff --git a/spec/attributes/time_spec.rb b/spec/attributes/time_spec.rb new file mode 100644 index 0000000000000..fcbe4f58e54f0 --- /dev/null +++ b/spec/attributes/time_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' +require 'bigdecimal' + +module Arel + describe "Attributes::Time" do + + before :all do + @relation = Model.build do |r| + r.engine Testing::Engine.new + r.attribute :created_at, Attributes::Time + end + end + + def type_cast(val) + @relation[:created_at].type_cast(val) + end + + describe "#type_cast" do + it "works" + end + end +end \ No newline at end of file diff --git a/spec/support/model.rb b/spec/support/model.rb new file mode 100644 index 0000000000000..bd4376efcbb44 --- /dev/null +++ b/spec/support/model.rb @@ -0,0 +1,56 @@ +module Arel + module Testing + class Engine + attr_reader :rows + + def initialize + @rows = [] + end + + def supports(operation) + false + end + + def read(relation) + @rows.dup.map { |r| Row.new(relation, r) } + end + + def create(insert) + @rows << insert.record.tuple + insert + end + end + end + + class Model < Relation + attr_reader :engine, :attributes + + def self.build + relation = new + yield relation + relation + end + + def initialize + @attributes = [] + end + + def engine(engine = nil) + @engine = engine if engine + @engine + end + + def attribute(name, type) + @attributes << type.new(self, name) + end + + def format(attribute, value) + value + end + + def insert(row) + insert = super Arel::Row.new(self, row) + insert.record + end + end +end \ No newline at end of file From 0b8b87fb947a746d4e58d11ea73ef20cfb23f576 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 14:43:47 -0800 Subject: [PATCH 0367/1492] This seems like it accidentally got included into the repo --- spec/spec/fixtures/fixture_database.sqlite3 | Bin 4096 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 spec/spec/fixtures/fixture_database.sqlite3 diff --git a/spec/spec/fixtures/fixture_database.sqlite3 b/spec/spec/fixtures/fixture_database.sqlite3 deleted file mode 100644 index cb52aacf7e137c4345145934580f9a81e92e5d1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmeHGK}*9h6i(X7Q1B*{;pOeNfhT2m>j+wG>&&XK(}-(igLW-x6g*as{#}27X)9aD zrm&mPJZSp*z3}pVU-QQI?m}{SPDIQkT%Z=h7+nG&gbvhGkK!BGfO=kox6@+UQzRsbo(P5BV#Pl9Y>VowbIP*a3mSzH$kyap)a^ibV*HACPN8 z!M_W@e{fwGQOC3C1a8UXtlYF@F^5N+4sUGQJ0A@CtG!h{V-XW?TaBt>$Wta{%$M@7 z7Bj(_J&wypPv|QtJA^nW+^qDCo;*Z)!dL+Vf)B?$+(#AFrwl= zQ{n~NRWE2|xNTV$&PmCt=#-U Date: Fri, 12 Mar 2010 14:46:37 -0800 Subject: [PATCH 0368/1492] We're obviously writing specs for arel. No need for a sub directory. --- spec/{arel => }/algebra/integration/basic_spec.rb | 0 spec/{arel => }/algebra/unit/predicates/binary_spec.rb | 0 spec/{arel => }/algebra/unit/predicates/equality_spec.rb | 0 spec/{arel => }/algebra/unit/predicates/in_spec.rb | 0 spec/{arel => }/algebra/unit/primitives/attribute_spec.rb | 0 spec/{arel => }/algebra/unit/primitives/expression_spec.rb | 0 spec/{arel => }/algebra/unit/primitives/value_spec.rb | 0 spec/{arel => }/algebra/unit/relations/alias_spec.rb | 0 spec/{arel => }/algebra/unit/relations/delete_spec.rb | 0 spec/{arel => }/algebra/unit/relations/group_spec.rb | 0 spec/{arel => }/algebra/unit/relations/insert_spec.rb | 0 spec/{arel => }/algebra/unit/relations/join_spec.rb | 0 spec/{arel => }/algebra/unit/relations/order_spec.rb | 0 spec/{arel => }/algebra/unit/relations/project_spec.rb | 0 spec/{arel => }/algebra/unit/relations/relation_spec.rb | 0 spec/{arel => }/algebra/unit/relations/skip_spec.rb | 0 spec/{arel => }/algebra/unit/relations/table_spec.rb | 0 spec/{arel => }/algebra/unit/relations/take_spec.rb | 0 spec/{arel => }/algebra/unit/relations/update_spec.rb | 0 spec/{arel => }/algebra/unit/relations/where_spec.rb | 0 spec/{arel => }/algebra/unit/session/session_spec.rb | 0 .../engines/memory/integration/joins/cross_engine_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/array_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/insert_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/join_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/order_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/project_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/skip_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/take_spec.rb | 0 spec/{arel => }/engines/memory/unit/relations/where_spec.rb | 0 .../engines/sql/integration/joins/with_adjacency_spec.rb | 0 .../engines/sql/integration/joins/with_aggregations_spec.rb | 0 .../engines/sql/integration/joins/with_compounds_spec.rb | 0 spec/{arel => }/engines/sql/unit/engine_spec.rb | 0 spec/{arel => }/engines/sql/unit/predicates/binary_spec.rb | 0 spec/{arel => }/engines/sql/unit/predicates/equality_spec.rb | 0 spec/{arel => }/engines/sql/unit/predicates/in_spec.rb | 0 spec/{arel => }/engines/sql/unit/predicates/predicates_spec.rb | 0 spec/{arel => }/engines/sql/unit/primitives/attribute_spec.rb | 0 spec/{arel => }/engines/sql/unit/primitives/expression_spec.rb | 0 spec/{arel => }/engines/sql/unit/primitives/literal_spec.rb | 0 spec/{arel => }/engines/sql/unit/primitives/value_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/alias_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/delete_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/from_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/group_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/having_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/insert_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/join_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/lock_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/order_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/project_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/skip_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/table_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/take_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/update_spec.rb | 0 spec/{arel => }/engines/sql/unit/relations/where_spec.rb | 0 57 files changed, 0 insertions(+), 0 deletions(-) rename spec/{arel => }/algebra/integration/basic_spec.rb (100%) rename spec/{arel => }/algebra/unit/predicates/binary_spec.rb (100%) rename spec/{arel => }/algebra/unit/predicates/equality_spec.rb (100%) rename spec/{arel => }/algebra/unit/predicates/in_spec.rb (100%) rename spec/{arel => }/algebra/unit/primitives/attribute_spec.rb (100%) rename spec/{arel => }/algebra/unit/primitives/expression_spec.rb (100%) rename spec/{arel => }/algebra/unit/primitives/value_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/alias_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/delete_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/group_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/insert_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/join_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/order_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/project_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/relation_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/skip_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/table_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/take_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/update_spec.rb (100%) rename spec/{arel => }/algebra/unit/relations/where_spec.rb (100%) rename spec/{arel => }/algebra/unit/session/session_spec.rb (100%) rename spec/{arel => }/engines/memory/integration/joins/cross_engine_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/array_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/insert_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/join_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/order_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/project_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/skip_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/take_spec.rb (100%) rename spec/{arel => }/engines/memory/unit/relations/where_spec.rb (100%) rename spec/{arel => }/engines/sql/integration/joins/with_adjacency_spec.rb (100%) rename spec/{arel => }/engines/sql/integration/joins/with_aggregations_spec.rb (100%) rename spec/{arel => }/engines/sql/integration/joins/with_compounds_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/engine_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/predicates/binary_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/predicates/equality_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/predicates/in_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/predicates/predicates_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/primitives/attribute_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/primitives/expression_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/primitives/literal_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/primitives/value_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/alias_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/delete_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/from_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/group_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/having_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/insert_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/join_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/lock_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/order_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/project_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/skip_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/table_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/take_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/update_spec.rb (100%) rename spec/{arel => }/engines/sql/unit/relations/where_spec.rb (100%) diff --git a/spec/arel/algebra/integration/basic_spec.rb b/spec/algebra/integration/basic_spec.rb similarity index 100% rename from spec/arel/algebra/integration/basic_spec.rb rename to spec/algebra/integration/basic_spec.rb diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/algebra/unit/predicates/binary_spec.rb similarity index 100% rename from spec/arel/algebra/unit/predicates/binary_spec.rb rename to spec/algebra/unit/predicates/binary_spec.rb diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/algebra/unit/predicates/equality_spec.rb similarity index 100% rename from spec/arel/algebra/unit/predicates/equality_spec.rb rename to spec/algebra/unit/predicates/equality_spec.rb diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/algebra/unit/predicates/in_spec.rb similarity index 100% rename from spec/arel/algebra/unit/predicates/in_spec.rb rename to spec/algebra/unit/predicates/in_spec.rb diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb similarity index 100% rename from spec/arel/algebra/unit/primitives/attribute_spec.rb rename to spec/algebra/unit/primitives/attribute_spec.rb diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/algebra/unit/primitives/expression_spec.rb similarity index 100% rename from spec/arel/algebra/unit/primitives/expression_spec.rb rename to spec/algebra/unit/primitives/expression_spec.rb diff --git a/spec/arel/algebra/unit/primitives/value_spec.rb b/spec/algebra/unit/primitives/value_spec.rb similarity index 100% rename from spec/arel/algebra/unit/primitives/value_spec.rb rename to spec/algebra/unit/primitives/value_spec.rb diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/algebra/unit/relations/alias_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/alias_spec.rb rename to spec/algebra/unit/relations/alias_spec.rb diff --git a/spec/arel/algebra/unit/relations/delete_spec.rb b/spec/algebra/unit/relations/delete_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/delete_spec.rb rename to spec/algebra/unit/relations/delete_spec.rb diff --git a/spec/arel/algebra/unit/relations/group_spec.rb b/spec/algebra/unit/relations/group_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/group_spec.rb rename to spec/algebra/unit/relations/group_spec.rb diff --git a/spec/arel/algebra/unit/relations/insert_spec.rb b/spec/algebra/unit/relations/insert_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/insert_spec.rb rename to spec/algebra/unit/relations/insert_spec.rb diff --git a/spec/arel/algebra/unit/relations/join_spec.rb b/spec/algebra/unit/relations/join_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/join_spec.rb rename to spec/algebra/unit/relations/join_spec.rb diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/algebra/unit/relations/order_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/order_spec.rb rename to spec/algebra/unit/relations/order_spec.rb diff --git a/spec/arel/algebra/unit/relations/project_spec.rb b/spec/algebra/unit/relations/project_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/project_spec.rb rename to spec/algebra/unit/relations/project_spec.rb diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/relation_spec.rb rename to spec/algebra/unit/relations/relation_spec.rb diff --git a/spec/arel/algebra/unit/relations/skip_spec.rb b/spec/algebra/unit/relations/skip_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/skip_spec.rb rename to spec/algebra/unit/relations/skip_spec.rb diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/algebra/unit/relations/table_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/table_spec.rb rename to spec/algebra/unit/relations/table_spec.rb diff --git a/spec/arel/algebra/unit/relations/take_spec.rb b/spec/algebra/unit/relations/take_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/take_spec.rb rename to spec/algebra/unit/relations/take_spec.rb diff --git a/spec/arel/algebra/unit/relations/update_spec.rb b/spec/algebra/unit/relations/update_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/update_spec.rb rename to spec/algebra/unit/relations/update_spec.rb diff --git a/spec/arel/algebra/unit/relations/where_spec.rb b/spec/algebra/unit/relations/where_spec.rb similarity index 100% rename from spec/arel/algebra/unit/relations/where_spec.rb rename to spec/algebra/unit/relations/where_spec.rb diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/algebra/unit/session/session_spec.rb similarity index 100% rename from spec/arel/algebra/unit/session/session_spec.rb rename to spec/algebra/unit/session/session_spec.rb diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/engines/memory/integration/joins/cross_engine_spec.rb similarity index 100% rename from spec/arel/engines/memory/integration/joins/cross_engine_spec.rb rename to spec/engines/memory/integration/joins/cross_engine_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/engines/memory/unit/relations/array_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/array_spec.rb rename to spec/engines/memory/unit/relations/array_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/engines/memory/unit/relations/insert_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/insert_spec.rb rename to spec/engines/memory/unit/relations/insert_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/engines/memory/unit/relations/join_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/join_spec.rb rename to spec/engines/memory/unit/relations/join_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/engines/memory/unit/relations/order_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/order_spec.rb rename to spec/engines/memory/unit/relations/order_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/engines/memory/unit/relations/project_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/project_spec.rb rename to spec/engines/memory/unit/relations/project_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/engines/memory/unit/relations/skip_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/skip_spec.rb rename to spec/engines/memory/unit/relations/skip_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/engines/memory/unit/relations/take_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/take_spec.rb rename to spec/engines/memory/unit/relations/take_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/engines/memory/unit/relations/where_spec.rb similarity index 100% rename from spec/arel/engines/memory/unit/relations/where_spec.rb rename to spec/engines/memory/unit/relations/where_spec.rb diff --git a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb b/spec/engines/sql/integration/joins/with_adjacency_spec.rb similarity index 100% rename from spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb rename to spec/engines/sql/integration/joins/with_adjacency_spec.rb diff --git a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb b/spec/engines/sql/integration/joins/with_aggregations_spec.rb similarity index 100% rename from spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb rename to spec/engines/sql/integration/joins/with_aggregations_spec.rb diff --git a/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb b/spec/engines/sql/integration/joins/with_compounds_spec.rb similarity index 100% rename from spec/arel/engines/sql/integration/joins/with_compounds_spec.rb rename to spec/engines/sql/integration/joins/with_compounds_spec.rb diff --git a/spec/arel/engines/sql/unit/engine_spec.rb b/spec/engines/sql/unit/engine_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/engine_spec.rb rename to spec/engines/sql/unit/engine_spec.rb diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/engines/sql/unit/predicates/binary_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/predicates/binary_spec.rb rename to spec/engines/sql/unit/predicates/binary_spec.rb diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/engines/sql/unit/predicates/equality_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/predicates/equality_spec.rb rename to spec/engines/sql/unit/predicates/equality_spec.rb diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/engines/sql/unit/predicates/in_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/predicates/in_spec.rb rename to spec/engines/sql/unit/predicates/in_spec.rb diff --git a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb b/spec/engines/sql/unit/predicates/predicates_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/predicates/predicates_spec.rb rename to spec/engines/sql/unit/predicates/predicates_spec.rb diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/engines/sql/unit/primitives/attribute_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/primitives/attribute_spec.rb rename to spec/engines/sql/unit/primitives/attribute_spec.rb diff --git a/spec/arel/engines/sql/unit/primitives/expression_spec.rb b/spec/engines/sql/unit/primitives/expression_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/primitives/expression_spec.rb rename to spec/engines/sql/unit/primitives/expression_spec.rb diff --git a/spec/arel/engines/sql/unit/primitives/literal_spec.rb b/spec/engines/sql/unit/primitives/literal_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/primitives/literal_spec.rb rename to spec/engines/sql/unit/primitives/literal_spec.rb diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/engines/sql/unit/primitives/value_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/primitives/value_spec.rb rename to spec/engines/sql/unit/primitives/value_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/alias_spec.rb b/spec/engines/sql/unit/relations/alias_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/alias_spec.rb rename to spec/engines/sql/unit/relations/alias_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/delete_spec.rb b/spec/engines/sql/unit/relations/delete_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/delete_spec.rb rename to spec/engines/sql/unit/relations/delete_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/from_spec.rb b/spec/engines/sql/unit/relations/from_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/from_spec.rb rename to spec/engines/sql/unit/relations/from_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/group_spec.rb b/spec/engines/sql/unit/relations/group_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/group_spec.rb rename to spec/engines/sql/unit/relations/group_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/having_spec.rb b/spec/engines/sql/unit/relations/having_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/having_spec.rb rename to spec/engines/sql/unit/relations/having_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/engines/sql/unit/relations/insert_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/insert_spec.rb rename to spec/engines/sql/unit/relations/insert_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/engines/sql/unit/relations/join_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/join_spec.rb rename to spec/engines/sql/unit/relations/join_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/lock_spec.rb b/spec/engines/sql/unit/relations/lock_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/lock_spec.rb rename to spec/engines/sql/unit/relations/lock_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/order_spec.rb b/spec/engines/sql/unit/relations/order_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/order_spec.rb rename to spec/engines/sql/unit/relations/order_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/project_spec.rb b/spec/engines/sql/unit/relations/project_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/project_spec.rb rename to spec/engines/sql/unit/relations/project_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/skip_spec.rb b/spec/engines/sql/unit/relations/skip_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/skip_spec.rb rename to spec/engines/sql/unit/relations/skip_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/engines/sql/unit/relations/table_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/table_spec.rb rename to spec/engines/sql/unit/relations/table_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/take_spec.rb b/spec/engines/sql/unit/relations/take_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/take_spec.rb rename to spec/engines/sql/unit/relations/take_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/engines/sql/unit/relations/update_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/update_spec.rb rename to spec/engines/sql/unit/relations/update_spec.rb diff --git a/spec/arel/engines/sql/unit/relations/where_spec.rb b/spec/engines/sql/unit/relations/where_spec.rb similarity index 100% rename from spec/arel/engines/sql/unit/relations/where_spec.rb rename to spec/engines/sql/unit/relations/where_spec.rb From 0e6888232a19c8c59416490d3da6079e590fab77 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 15:25:21 -0800 Subject: [PATCH 0369/1492] Add support for a NOT predicate --- lib/arel/algebra/attributes/attribute.rb | 4 +++ lib/arel/algebra/predicates.rb | 1 + lib/arel/engines/memory/predicates.rb | 6 +++++ lib/arel/engines/sql/predicates.rb | 4 +++ spec/algebra/integration/basic_spec.rb | 33 ++++++++++++++++++++++++ 5 files changed, 48 insertions(+) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 03cf44a55212b..b372be5e1d744 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -86,6 +86,10 @@ def eq(other) Predicates::Equality.new(self, other) end + def not(other) + Predicates::Not.new(self, other) + end + def lt(other) Predicates::LessThan.new(self, other) end diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 8a0b41fa18f5e..700cd6afaaaa0 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -33,6 +33,7 @@ def ==(other) end end + class Not < Binary; end class GreaterThanOrEqualTo < Binary; end class GreaterThan < Binary; end class LessThanOrEqualTo < Binary; end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index dd2559c70f088..f87bf68357d3d 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -10,6 +10,12 @@ class Equality < Binary def operator; :== end end + class Not < Binary + def eval(row) + operand1.eval(row) != operand2.eval(row) + end + end + class GreaterThanOrEqualTo < Binary def operator; :>= end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index e563a9ba3e2e7..3756231a4669c 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -26,6 +26,10 @@ def predicate_sql end end + class Not < Binary + def predicate_sql; '!=' end + end + class GreaterThanOrEqualTo < Binary def predicate_sql; '>=' end end diff --git a/spec/algebra/integration/basic_spec.rb b/spec/algebra/integration/basic_spec.rb index 7aa4f7305c7fd..e48f94625dcc3 100644 --- a/spec/algebra/integration/basic_spec.rb +++ b/spec/algebra/integration/basic_spec.rb @@ -49,6 +49,39 @@ def have_rows(expected) expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) end + + it "finds rows with a not predicate" do + expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } + @relation.where(@relation[:age].not(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a less than predicate" do + expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } + @relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a less than or equal to predicate" do + expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } + @relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a greater than predicate" do + expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } + @relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a greater than or equal to predicate" do + expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } + @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a matches predicate" + + it "finds rows with an in predicate" do + pending + set = @expected[1..(@expected.length/2+1)] + @relation.all(:id.in => set.map { |r| r.id }).should have_resources(set) + end end end From 3ab6ae0c601d1b4459efd8bb39650fee370aa5b8 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 16:38:36 -0800 Subject: [PATCH 0370/1492] Organize the matchers a bit more --- spec/algebra/integration/basic_spec.rb | 87 ------------------ spec/shared/relation_spec.rb | 92 +++++++++++++++++++ spec/spec_helper.rb | 4 +- spec/support/matchers.rb | 3 +- spec/support/matchers/be_like.rb | 2 +- .../matchers/disambiguate_attributes.rb | 2 +- spec/support/matchers/hash_the_same_as.rb | 2 +- spec/support/matchers/have_rows.rb | 18 ++++ 8 files changed, 117 insertions(+), 93 deletions(-) create mode 100644 spec/shared/relation_spec.rb create mode 100644 spec/support/matchers/have_rows.rb diff --git a/spec/algebra/integration/basic_spec.rb b/spec/algebra/integration/basic_spec.rb index e48f94625dcc3..ae9da3a03763a 100644 --- a/spec/algebra/integration/basic_spec.rb +++ b/spec/algebra/integration/basic_spec.rb @@ -1,93 +1,7 @@ require 'spec_helper' -def have_rows(expected) - simple_matcher "have rows" do |given, matcher| - found, got, expected = [], [], expected.map { |r| r.tuple } - given.each do |row| - got << row.tuple - found << expected.find { |r| row.tuple == r } - end - - matcher.failure_message = "Expected to get:\n" \ - "#{expected.map {|r| " #{r.inspect}" }.join("\n")}\n" \ - "instead, got:\n" \ - "#{got.map {|r| " #{r.inspect}" }.join("\n")}" - - found.compact.length == expected.length && got.compact.length == expected.length - end -end - -share_examples_for 'A Relation' do - - before :all do - # The two needed instance variables need to be set in a - # before :all callback. - # @relation is the relation being tested here. - # @expected is an array of the elements that are expected to be in - # the relation. - %w[ @relation @expected ].each do |ivar| - raise "#{ivar} needs to be defined" unless instance_variable_get(ivar) - end - - # There needs to be enough items to be able to run all the tests - raise "@expected needs to have at least 6 items" unless @expected.length >= 6 - end - - describe "#each" do - it "iterates over the rows in any order" do - @relation.should have_rows(@expected) - end - end - - describe "#where" do - before :all do - @expected = @expected.sort_by { |r| r[@relation[:age]] } - @pivot = @expected[@expected.length / 2] - end - - it "finds rows with an equal to predicate" do - expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } - @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a not predicate" do - expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } - @relation.where(@relation[:age].not(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a less than predicate" do - expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } - @relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a less than or equal to predicate" do - expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } - @relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a greater than predicate" do - expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } - @relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a greater than or equal to predicate" do - expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } - @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a matches predicate" - - it "finds rows with an in predicate" do - pending - set = @expected[1..(@expected.length/2+1)] - @relation.all(:id.in => set.map { |r| r.id }).should have_resources(set) - end - end -end - module Arel describe "Relation" do - before :all do @engine = Testing::Engine.new @relation = Model.build do |r| @@ -113,6 +27,5 @@ module Arel @engine.rows.should == [[1, 'Foo', 10]] end end - end end \ No newline at end of file diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb new file mode 100644 index 0000000000000..c492ca847eb41 --- /dev/null +++ b/spec/shared/relation_spec.rb @@ -0,0 +1,92 @@ +share_examples_for 'A Relation' do + + before :all do + # The two needed instance variables need to be set in a + # before :all callback. + # @relation is the relation being tested here. + # @expected is an array of the elements that are expected to be in + # the relation. + %w[ @relation @expected ].each do |ivar| + raise "#{ivar} needs to be defined" unless instance_variable_get(ivar) + end + + # There needs to be enough items to be able to run all the tests + raise "@expected needs to have at least 6 items" unless @expected.length >= 6 + end + + describe "#each" do + it "iterates over the rows in any order" do + @relation.should have_rows(@expected) + end + end + + describe "#where" do + before :all do + @expected = @expected.sort_by { |r| r[@relation[:age]] } + @pivot = @expected[@expected.length / 2] + end + + it "finds rows with an equal to predicate" do + expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } + @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a not predicate" do + expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } + @relation.where(@relation[:age].not(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a less than predicate" do + expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } + @relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a less than or equal to predicate" do + expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } + @relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a greater than predicate" do + expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } + @relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a greater than or equal to predicate" do + expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } + @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) + end + + it "finds rows with a matches predicate" + + it "finds rows with an in predicate" do + pending + set = @expected[1..(@expected.length/2+1)] + @relation.all(:id.in => set.map { |r| r.id }).should have_resources(set) + end + end + + describe "#order" do + describe "by one attribute" do + before :all do + @expected.map! { |r| r[@relation[:age]] } + @expected.sort! + end + + it "can be specified as ascending order" do + actual = [] + @relation.order(@relation[:age].asc).each { |r| actual << r[@relation[:age]] } + actual.should == @expected + end + + it "can be specified as descending order" do + actual = [] + @relation.order(@relation[:age].desc).each { |r| actual << r[@relation[:age]] } + actual.should == @expected.reverse + end + end + + describe "by two attributes" do + it "works" + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 894e70c29d1f7..5941840437d93 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,12 +7,12 @@ require 'fileutils' require 'arel' -Dir["#{dir}/support/*.rb"].each do |file| +Dir["#{dir}/{support,shared}/*.rb"].each do |file| require file end Spec::Runner.configure do |config| - config.include BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher + config.include Matchers config.include AdapterGuards config.include Check diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb index 6f50d6cbc7f39..8cef5d947e6d9 100644 --- a/spec/support/matchers.rb +++ b/spec/support/matchers.rb @@ -1,3 +1,4 @@ require "support/matchers/be_like" require "support/matchers/disambiguate_attributes" -require "support/matchers/hash_the_same_as" \ No newline at end of file +require "support/matchers/hash_the_same_as" +require "support/matchers/have_rows" \ No newline at end of file diff --git a/spec/support/matchers/be_like.rb b/spec/support/matchers/be_like.rb index c9d4d4b979235..0608abbbb47f2 100644 --- a/spec/support/matchers/be_like.rb +++ b/spec/support/matchers/be_like.rb @@ -1,4 +1,4 @@ -module BeLikeMatcher +module Matchers class BeLike def initialize(expected) @expected = expected diff --git a/spec/support/matchers/disambiguate_attributes.rb b/spec/support/matchers/disambiguate_attributes.rb index bc4a5215d4c9d..cec5924ca1ecd 100644 --- a/spec/support/matchers/disambiguate_attributes.rb +++ b/spec/support/matchers/disambiguate_attributes.rb @@ -1,4 +1,4 @@ -module DisambiguateAttributesMatcher +module Matchers class DisambiguateAttributes def initialize(attributes) @attributes = attributes diff --git a/spec/support/matchers/hash_the_same_as.rb b/spec/support/matchers/hash_the_same_as.rb index 03e955a0cb5b0..ed00d37f281ac 100644 --- a/spec/support/matchers/hash_the_same_as.rb +++ b/spec/support/matchers/hash_the_same_as.rb @@ -1,4 +1,4 @@ -module HashTheSameAsMatcher +module Matchers class HashTheSameAs def initialize(expected) @expected = expected diff --git a/spec/support/matchers/have_rows.rb b/spec/support/matchers/have_rows.rb new file mode 100644 index 0000000000000..7d9c6a20c9e7d --- /dev/null +++ b/spec/support/matchers/have_rows.rb @@ -0,0 +1,18 @@ +module Matchers + def have_rows(expected) + simple_matcher "have rows" do |given, matcher| + found, got, expected = [], [], expected.map { |r| r.tuple } + given.each do |row| + got << row.tuple + found << expected.find { |r| row.tuple == r } + end + + matcher.failure_message = "Expected to get:\n" \ + "#{expected.map {|r| " #{r.inspect}" }.join("\n")}\n" \ + "instead, got:\n" \ + "#{got.map {|r| " #{r.inspect}" }.join("\n")}" + + found.compact.length == expected.length && got.compact.length == expected.length + end + end +end \ No newline at end of file From e9c71a864bd33b3109e802efc7d03255037a899f Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 16:39:32 -0800 Subject: [PATCH 0371/1492] Support in memory ordering better. --- lib/arel/algebra/relations/operations/order.rb | 3 ++- lib/arel/algebra/relations/operations/where.rb | 12 ++---------- .../algebra/relations/utilities/compound.rb | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index a589b56997637..df54735630b49 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -1,7 +1,8 @@ module Arel class Order < Compound attributes :relation, :orderings - deriving :== + deriving :== + requires :ordering def initialize(relation, *orderings, &block) @relation = relation diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 2fc51c7f24e3f..6c9c5ed75586f 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -1,7 +1,8 @@ module Arel class Where < Compound attributes :relation, :predicate - deriving :== + deriving :== + requires :restricting def initialize(relation, *predicates, &block) predicate = block_given?? yield(relation) : predicates.shift @@ -9,15 +10,6 @@ def initialize(relation, *predicates, &block) @predicate = predicate.bind(@relation) end - def engine - # Temporary check of whether or not the engine supports where. - if relation.engine.respond_to?(:supports) && !relation.engine.supports(:where) - Memory::Engine.new - else - relation.engine - end - end - def wheres @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 1a43c76a94748..882cf8a76b0a6 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -5,6 +5,11 @@ class Compound < Relation :column_for, :engine, :sources, :locked, :table_alias, :to => :relation + def self.requires(feature = nil) + @requires = feature if feature + @requires + end + [:attributes, :wheres, :groupings, :orders, :havings, :projections].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} @@ -21,6 +26,18 @@ def eql?(other) self == other end + def engine + requires = self.class.requires + engine = relation.engine + + # Temporary check of whether or not the engine supports where. + if requires && engine.respond_to?(:supports) && !engine.supports(requires) + Memory::Engine.new + else + engine + end + end + private def arguments_from_block(relation, &block) From 07e133e97ed422436810b7398dcbd780cabea2c3 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 17:02:43 -0800 Subject: [PATCH 0372/1492] Add full stack tests for #take --- lib/arel/algebra/relations/operations/take.rb | 3 ++- spec/shared/relation_spec.rb | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index eb32ec492e345..cc636642b1e04 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -1,7 +1,8 @@ module Arel class Take < Compound attributes :relation, :taken - deriving :initialize, :== + deriving :initialize, :== + requires :limiting def externalizable? true diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index c492ca847eb41..aa03ab6c0a6bf 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -14,6 +14,10 @@ raise "@expected needs to have at least 6 items" unless @expected.length >= 6 end + before :each do + @expected = @expected.dup + end + describe "#each" do it "iterates over the rows in any order" do @relation.should have_rows(@expected) @@ -89,4 +93,27 @@ it "works" end end + + describe "#take" do + it "returns a relation" do + @relation.take(3).should be_a(Arel::Relation) + end + + it "returns X items from the collection" do + length = @expected.length + + @relation.take(3).each do |resource| + @expected.delete_if { |r| r.tuple == resource.tuple } + end + + @expected.length.should == length - 3 + end + + it "works with ordering" do + expected = @expected.sort_by { |r| [r[@relation[:age]], r[@relation[:id]]] }.map { |r| r[@relation[:id]] } + actual = @relation.order(@relation[:age].asc, @relation[:id].asc).take(3).map { |r| r[@relation[:id]] } + + actual.should == expected[0,3] + end + end end \ No newline at end of file From c2f9f707fc56ca610fb1706886b3111dfe1d286f Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 17:19:59 -0800 Subject: [PATCH 0373/1492] Add shared tests for skip --- lib/arel/algebra/relations/operations/skip.rb | 3 ++- spec/shared/relation_spec.rb | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 689e06e1c3ed8..43db134ea0869 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -1,6 +1,7 @@ module Arel class Skip < Compound attributes :relation, :skipped - deriving :initialize, :== + deriving :initialize, :== + requires :skipping end end diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index aa03ab6c0a6bf..5f0ae4b46ef8f 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -116,4 +116,27 @@ actual.should == expected[0,3] end end + + describe "#skip" do + it "returns a relation" do + @relation.skip(3).should be_a(Arel::Relation) + end + + it "skips X items from the collection" do + length = @expected.length + + @relation.skip(3).each do |resource| + @expected.delete_if { |r| r.tuple == resource.tuple } + end + + @expected.length.should == 3 + end + + it "works with ordering" do + expected = @expected.sort_by { |r| [r[@relation[:age]], r[@relation[:id]]] }.map { |r| r[@relation[:id]] } + actual = @relation.order(@relation[:age].asc, @relation[:id].asc).skip(3).map { |r| r[@relation[:id]] } + + actual.should == expected[3..-1] + end + end end \ No newline at end of file From a33ab1b34e74c3b1d6f3bae4a2477527e5f8ca55 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 17:31:45 -0800 Subject: [PATCH 0374/1492] Move the relation "integration" specs to specs/relations --- spec/algebra/integration/basic_spec.rb | 31 -------------------------- spec/relations/relation_spec.rb | 31 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 spec/algebra/integration/basic_spec.rb create mode 100644 spec/relations/relation_spec.rb diff --git a/spec/algebra/integration/basic_spec.rb b/spec/algebra/integration/basic_spec.rb deleted file mode 100644 index ae9da3a03763a..0000000000000 --- a/spec/algebra/integration/basic_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'spec_helper' - -module Arel - describe "Relation" do - before :all do - @engine = Testing::Engine.new - @relation = Model.build do |r| - r.engine @engine - - r.attribute :id, Attributes::Integer - r.attribute :name, Attributes::String - r.attribute :age, Attributes::Integer - end - end - - describe "..." do - before :all do - @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) } - end - - it_should_behave_like 'A Relation' - end - - describe "#insert" do - it "inserts the row into the engine" do - @relation.insert([1, 'Foo', 10]) - @engine.rows.should == [[1, 'Foo', 10]] - end - end - end -end \ No newline at end of file diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb new file mode 100644 index 0000000000000..808ddf1444c57 --- /dev/null +++ b/spec/relations/relation_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe "Arel" do + before :all do + @engine = Arel::Testing::Engine.new + @relation = Arel::Model.build do |r| + r.engine @engine + + r.attribute :id, Arel::Attributes::Integer + r.attribute :name, Arel::Attributes::String + r.attribute :age, Arel::Attributes::Integer + end + end + + describe "Relation" do + before :all do + @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) } + end + + it_should_behave_like 'A Relation' + end + + describe "Relation" do + describe "#insert" do + it "inserts the row into the engine" do + @relation.insert([1, 'Foo', 10]) + @engine.rows.should == [[1, 'Foo', 10]] + end + end + end +end \ No newline at end of file From d2bf57135f7293a1998a25bd828b0c470cf6b85c Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 12 Mar 2010 20:13:04 -0800 Subject: [PATCH 0375/1492] Add specs for simple in memory joins. --- spec/relations/join_spec.rb | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 spec/relations/join_spec.rb diff --git a/spec/relations/join_spec.rb b/spec/relations/join_spec.rb new file mode 100644 index 0000000000000..47e468a9f951b --- /dev/null +++ b/spec/relations/join_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe "Arel" do + before :all do + @owner = Arel::Model.build do |r| + r.engine Arel::Testing::Engine.new + + r.attribute :id, Arel::Attributes::Integer + end + + @thing = Arel::Model.build do |r| + r.engine Arel::Testing::Engine.new + + r.attribute :id, Arel::Attributes::Integer + r.attribute :owner_id, Arel::Attributes::Integer + r.attribute :age, Arel::Attributes::Integer + end + end + + describe "Join" do + before :all do + @relation = @thing.join(@owner).on(@thing[:owner_id].eq(@owner[:id])) + @expected = [] + + 3.times do |owner_id| + @owner.insert([owner_id]) + + 8.times do |i| + thing_id = owner_id * 8 + i + age = 2 * thing_id + + @thing.insert([thing_id, owner_id, age]) + @expected << Arel::Row.new(@relation, [thing_id, owner_id, age, owner_id]) + end + end + end + + it_should_behave_like 'A Relation' + end +end \ No newline at end of file From cb5a46d0c60928ab4a479d7787f83700fda62b6a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 14 Mar 2010 17:29:13 -0700 Subject: [PATCH 0376/1492] fixing uninitialized ivar warning --- lib/arel/engines/sql/relations/table.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index c0d3386463f7b..aa70eaaa28900 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -7,6 +7,7 @@ class Table < Relation def initialize(name, options = {}) @name = name.to_s + @table_exists = nil if options.is_a?(Hash) @options = options From d0b47c64e2c44ef1cc0e9cfb3dc8681599d4d1f3 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 22 Mar 2010 15:49:56 -0300 Subject: [PATCH 0377/1492] Fix uninitialized ivar warning --- lib/arel/algebra/relations/utilities/compound.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 882cf8a76b0a6..0734842b27626 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -6,6 +6,7 @@ class Compound < Relation :to => :relation def self.requires(feature = nil) + @requires ||= nil @requires = feature if feature @requires end From 30fb25d3abfc002b85f290587b979d54c35a2e98 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 22 Mar 2010 16:26:00 -0700 Subject: [PATCH 0378/1492] Switch Arel::Relation to a module. This will allow for classes with Relation extended on them to represent relations themselves (as opposed to their instances being relations). --- lib/arel/algebra/relations/operations/join.rb | 6 ++++-- lib/arel/algebra/relations/relation.rb | 2 +- lib/arel/algebra/relations/utilities/compound.rb | 4 +++- lib/arel/algebra/relations/utilities/externalization.rb | 2 +- lib/arel/algebra/relations/utilities/nil.rb | 4 ++-- lib/arel/engines/memory/relations/array.rb | 4 +++- lib/arel/engines/memory/relations/compound.rb | 2 +- lib/arel/engines/memory/relations/operations.rb | 2 +- lib/arel/engines/sql/relations/operations/join.rb | 2 +- lib/arel/engines/sql/relations/relation.rb | 2 +- lib/arel/engines/sql/relations/table.rb | 4 ++-- lib/arel/engines/sql/relations/utilities/compound.rb | 2 +- lib/arel/engines/sql/relations/utilities/nil.rb | 2 +- spec/support/model.rb | 4 +++- 14 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index df457686ccef3..300cd31bcde4b 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -1,5 +1,7 @@ module Arel - class Join < Relation + class Join + include Relation + attributes :relation1, :relation2, :predicates deriving :== delegate :name, :to => :relation1 @@ -60,7 +62,7 @@ def engine end end - class Relation + module Relation def join? false end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 51c622cbe8422..1c1ded15c9e96 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -1,5 +1,5 @@ module Arel - class Relation + module Relation attr_reader :count def session diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 0734842b27626..7039b825755cd 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -1,5 +1,7 @@ module Arel - class Compound < Relation + class Compound + include Relation + attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, :column_for, :engine, :sources, :locked, :table_alias, diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index 13758ccec9802..795a3919f2387 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -12,7 +12,7 @@ def attributes end end - class Relation + module Relation def externalize @externalized ||= externalizable?? Externalization.new(self) : self end diff --git a/lib/arel/algebra/relations/utilities/nil.rb b/lib/arel/algebra/relations/utilities/nil.rb index 6a9d678c45de4..04055d0ddbe2e 100644 --- a/lib/arel/algebra/relations/utilities/nil.rb +++ b/lib/arel/algebra/relations/utilities/nil.rb @@ -1,7 +1,7 @@ require 'singleton' module Arel - class Nil < Relation - include Singleton + class Nil + include Relation, Singleton end end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 577e327b19d72..6486dcbcc1b29 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -1,5 +1,7 @@ module Arel - class Array < Relation + class Array + include Relation + attributes :array, :attribute_names_and_types include Recursion::BaseCase deriving :==, :initialize diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index 6dda92a6a1242..0f3c24f9ece3e 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -1,5 +1,5 @@ module Arel - class Compound < Relation + class Compound delegate :array, :to => :relation def unoperated_rows diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index a5082715a1aff..5d7b7670b6cdd 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -50,7 +50,7 @@ def eval end end - class Join < Relation + class Join def eval result = [] relation1.call.each do |row1| diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index a3aaaa163ba1e..7fad6400adeb5 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -1,5 +1,5 @@ module Arel - class Join < Relation + class Join def table_sql(formatter = Sql::TableReference.new(self)) relation1.externalize.table_sql(formatter) end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 5e8fc2e83e52a..f372589af1276 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -1,5 +1,5 @@ module Arel - class Relation + module Relation @@connection_tables_primary_keys = {} def compiler diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index aa70eaaa28900..8ee7a943578e8 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -1,6 +1,6 @@ module Arel - class Table < Relation - include Recursion::BaseCase + class Table + include Relation, Recursion::BaseCase cattr_accessor :engine, :tables attr_reader :name, :engine, :table_alias, :options diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index b8b0e7d2691af..55853be742804 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -1,5 +1,5 @@ module Arel - class Compound < Relation + class Compound delegate :table, :table_sql, :to => :relation def build_query(*parts) diff --git a/lib/arel/engines/sql/relations/utilities/nil.rb b/lib/arel/engines/sql/relations/utilities/nil.rb index 519ea8acf1b6e..0f7ca5d7575bf 100644 --- a/lib/arel/engines/sql/relations/utilities/nil.rb +++ b/lib/arel/engines/sql/relations/utilities/nil.rb @@ -1,5 +1,5 @@ module Arel - class Nil < Relation + class Nil def table_sql(formatter = nil); '' end def name; '' end end diff --git a/spec/support/model.rb b/spec/support/model.rb index bd4376efcbb44..10a14d7092fde 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -22,7 +22,9 @@ def create(insert) end end - class Model < Relation + class Model + include Relation + attr_reader :engine, :attributes def self.build From 195cc1402284d0e965cd96e572514fe2ff300788 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Tue, 23 Mar 2010 11:23:21 -0700 Subject: [PATCH 0379/1492] Rake is a better build tool than Thor. Move the gem building and releasing tasks to the Rakefile. --- .gitignore | 1 + Rakefile | 41 +++++++ Thorfile | 124 -------------------- arel.gemspec | 273 ++++---------------------------------------- lib/arel.rb | 4 +- lib/arel/version.rb | 3 + 6 files changed, 70 insertions(+), 376 deletions(-) delete mode 100644 Thorfile create mode 100644 lib/arel/version.rb diff --git a/.gitignore b/.gitignore index 3fec2d912b86f..30bd888ba613e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ spec/support/fixtures/*database* *.DS_Store debug.log pkg +.bundle \ No newline at end of file diff --git a/Rakefile b/Rakefile index ef633c00428b6..bc4fe6f8391c6 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,12 @@ require "rubygems" +def gemspec + @gemspec ||= begin + gemspec_file = File.expand_path('../arel.gemspec', __FILE__) + gemspec = eval(File.read(gemspec_file), binding, gemspec_file) + end +end + begin require "spec/rake/spectask" rescue LoadError @@ -46,3 +53,37 @@ desc 'Removes trailing whitespace' task :whitespace do sh %{find . -name '*.rb' -exec sed -i '' 's/ *$//g' {} \\;} end + +desc "Build pkg/#{gemspec.full_name}.gem" +task :build => "gemspec:validate" do + sh %{gem build arel.gemspec} + FileUtils.mkdir_p "pkg" + FileUtils.mv gemspec.file_name, "pkg" +end + +desc "Install the latest built gem" +task :install => :build do + sh "gem install --local pkg/#{gemspec.file_name}" +end + +namespace :release do + task :tag do + release_tag = "v#{gemspec.version}" + sh "git tag -a #{release_tag} -m 'Tagging #{release_tag}'" + sh "git push origin #{release_tag}" + end + + task :gem => :build do + sh "gem push pkg/#{gemspec.file_name}" + end +end + +desc "Release the current branch to GitHub and Gemcutter" +task :release => %w(release:tag release:gem) + +namespace :gemspec do + desc 'Validate the gemspec' + task :validate do + gemspec.validate + end +end \ No newline at end of file diff --git a/Thorfile b/Thorfile deleted file mode 100644 index 3b55e45a91f4c..0000000000000 --- a/Thorfile +++ /dev/null @@ -1,124 +0,0 @@ -require "active_support" - -module GemHelpers - - def generate_gemspec - $LOAD_PATH << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" - $LOAD_PATH << "#{File.dirname(__FILE__)}/vendor/rails/activesupport/lib" - - $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "lib"))) - require "arel" - - Gem::Specification.new do |s| - s.name = "arel" - s.version = Arel::VERSION - s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.email = "bryan@brynary.com" - s.homepage = "http://github.com/brynary/arel" - s.summary = "Arel is a relational algebra engine for Ruby" - s.description = <<-EOS.strip -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex -of SQL queries and it 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. - EOS - s.rubyforge_project = "arel" - - require "git" - repo = Git.open(".") - - s.files = normalize_files(repo.ls_files.keys - repo.lib.ignored_files) - s.test_files = normalize_files(Dir['spec/**/*.rb'] - repo.lib.ignored_files) - - s.has_rdoc = true - s.extra_rdoc_files = %w[History.txt README.markdown] - - # Arel required ActiveRecord, but we're not declaring it to avoid a - # circular dependency chain. The solution is for ActiveRecord to release - # the connection adapters which Arel uses in a separate gem - # s.add_dependency "activerecord", ">= 3.0.pre" - s.add_dependency "activesupport", ">= 3.0.0.beta" - end - end - - def normalize_files(array) - # only keep files, no directories, and sort - array.select do |path| - File.file?(path) - end.sort - end - - # Adds extra space when outputting an array. This helps create better version - # control diffs, because otherwise it is all on the same line. - def prettyify_array(gemspec_ruby, array_name) - gemspec_ruby.gsub(/s\.#{array_name.to_s} = \[.+?\]/) do |match| - leadin, files = match[0..-2].split("[") - leadin + "[\n #{files.split(",").join(",\n ")}\n ]" - end - end - - def read_gemspec - @read_gemspec ||= eval(File.read("arel.gemspec")) - end - - def sh(command) - puts command - system command - end -end - -class Default < Thor - include GemHelpers - - desc "gemspec", "Regenerate arel.gemspec" - def gemspec - File.open("arel.gemspec", "w") do |file| - gemspec_ruby = generate_gemspec.to_ruby - gemspec_ruby = prettyify_array(gemspec_ruby, :files) - gemspec_ruby = prettyify_array(gemspec_ruby, :test_files) - gemspec_ruby = prettyify_array(gemspec_ruby, :extra_rdoc_files) - - file.write gemspec_ruby - end - - puts "Wrote gemspec to arel.gemspec" - read_gemspec.validate - end - - desc "build", "Build a arel gem" - def build - sh "gem build arel.gemspec" - FileUtils.mkdir_p "pkg" - FileUtils.mv read_gemspec.file_name, "pkg" - end - - desc "install", "Install the latest built gem" - def install - sh "gem install --local pkg/#{read_gemspec.file_name}" - end - - desc "release", "Release the current branch to GitHub and Gemcutter" - def release - gemspec - build - Release.new.tag - Release.new.gem - end -end - -class Release < Thor - include GemHelpers - - desc "tag", "Tag the gem on the origin server" - def tag - release_tag = "v#{read_gemspec.version}" - sh "git tag -a #{release_tag} -m 'Tagging #{release_tag}'" - sh "git push origin #{release_tag}" - end - - desc "gem", "Push the gem to Gemcutter" - def gem - sh "gem push pkg/#{read_gemspec.file_name}" - end -end \ No newline at end of file diff --git a/arel.gemspec b/arel.gemspec index 695f504203841..31a3b558a9469 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,258 +1,31 @@ # -*- encoding: utf-8 -*- +require File.expand_path('../lib/arel/version.rb', __FILE__) Gem::Specification.new do |s| - s.name = %q{arel} - s.version = "0.3.1" - - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-03-10} - s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex + s.name = "arel" + s.version = Arel::VERSION + s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] + s.email = "bryan@brynary.com" + s.homepage = "http://github.com/brynary/arel" + s.summary = "Arel is a relational algebra engine for Ruby" + s.description = <<-EOS.strip +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} - s.email = %q{bryan@brynary.com} - s.extra_rdoc_files = [ - "History.txt", - "README.markdown" - ] - s.files = [ - ".gitignore", - ".gitmodules", - "History.txt", - "README.markdown", - "Rakefile", - "Thorfile", - "arel.gemspec", - "doc/CONVENTIONS", - "doc/TODO", - "lib/arel.rb", - "lib/arel/algebra.rb", - "lib/arel/algebra/attribute.rb", - "lib/arel/algebra/core_extensions.rb", - "lib/arel/algebra/core_extensions/class.rb", - "lib/arel/algebra/core_extensions/hash.rb", - "lib/arel/algebra/core_extensions/object.rb", - "lib/arel/algebra/core_extensions/symbol.rb", - "lib/arel/algebra/expression.rb", - "lib/arel/algebra/ordering.rb", - "lib/arel/algebra/predicates.rb", - "lib/arel/algebra/relations.rb", - "lib/arel/algebra/relations/operations/alias.rb", - "lib/arel/algebra/relations/operations/from.rb", - "lib/arel/algebra/relations/operations/group.rb", - "lib/arel/algebra/relations/operations/having.rb", - "lib/arel/algebra/relations/operations/join.rb", - "lib/arel/algebra/relations/operations/lock.rb", - "lib/arel/algebra/relations/operations/order.rb", - "lib/arel/algebra/relations/operations/project.rb", - "lib/arel/algebra/relations/operations/skip.rb", - "lib/arel/algebra/relations/operations/take.rb", - "lib/arel/algebra/relations/operations/where.rb", - "lib/arel/algebra/relations/relation.rb", - "lib/arel/algebra/relations/row.rb", - "lib/arel/algebra/relations/utilities/compound.rb", - "lib/arel/algebra/relations/utilities/externalization.rb", - "lib/arel/algebra/relations/utilities/nil.rb", - "lib/arel/algebra/relations/writes.rb", - "lib/arel/algebra/value.rb", - "lib/arel/engines.rb", - "lib/arel/engines/memory.rb", - "lib/arel/engines/memory/engine.rb", - "lib/arel/engines/memory/predicates.rb", - "lib/arel/engines/memory/primitives.rb", - "lib/arel/engines/memory/relations.rb", - "lib/arel/engines/memory/relations/array.rb", - "lib/arel/engines/memory/relations/compound.rb", - "lib/arel/engines/memory/relations/operations.rb", - "lib/arel/engines/memory/relations/writes.rb", - "lib/arel/engines/sql.rb", - "lib/arel/engines/sql/christener.rb", - "lib/arel/engines/sql/compilers/ibm_db_compiler.rb", - "lib/arel/engines/sql/compilers/mysql_compiler.rb", - "lib/arel/engines/sql/compilers/oracle_compiler.rb", - "lib/arel/engines/sql/compilers/postgresql_compiler.rb", - "lib/arel/engines/sql/compilers/sqlite_compiler.rb", - "lib/arel/engines/sql/core_extensions.rb", - "lib/arel/engines/sql/core_extensions/array.rb", - "lib/arel/engines/sql/core_extensions/nil_class.rb", - "lib/arel/engines/sql/core_extensions/object.rb", - "lib/arel/engines/sql/core_extensions/range.rb", - "lib/arel/engines/sql/engine.rb", - "lib/arel/engines/sql/formatters.rb", - "lib/arel/engines/sql/predicates.rb", - "lib/arel/engines/sql/primitives.rb", - "lib/arel/engines/sql/relations.rb", - "lib/arel/engines/sql/relations/compiler.rb", - "lib/arel/engines/sql/relations/operations/alias.rb", - "lib/arel/engines/sql/relations/operations/join.rb", - "lib/arel/engines/sql/relations/relation.rb", - "lib/arel/engines/sql/relations/table.rb", - "lib/arel/engines/sql/relations/utilities/compound.rb", - "lib/arel/engines/sql/relations/utilities/externalization.rb", - "lib/arel/engines/sql/relations/utilities/nil.rb", - "lib/arel/engines/sql/relations/utilities/recursion.rb", - "lib/arel/engines/sql/relations/writes.rb", - "lib/arel/session.rb", - "spec/arel/algebra/unit/predicates/binary_spec.rb", - "spec/arel/algebra/unit/predicates/equality_spec.rb", - "spec/arel/algebra/unit/predicates/in_spec.rb", - "spec/arel/algebra/unit/primitives/attribute_spec.rb", - "spec/arel/algebra/unit/primitives/expression_spec.rb", - "spec/arel/algebra/unit/primitives/value_spec.rb", - "spec/arel/algebra/unit/relations/alias_spec.rb", - "spec/arel/algebra/unit/relations/delete_spec.rb", - "spec/arel/algebra/unit/relations/group_spec.rb", - "spec/arel/algebra/unit/relations/insert_spec.rb", - "spec/arel/algebra/unit/relations/join_spec.rb", - "spec/arel/algebra/unit/relations/order_spec.rb", - "spec/arel/algebra/unit/relations/project_spec.rb", - "spec/arel/algebra/unit/relations/relation_spec.rb", - "spec/arel/algebra/unit/relations/skip_spec.rb", - "spec/arel/algebra/unit/relations/table_spec.rb", - "spec/arel/algebra/unit/relations/take_spec.rb", - "spec/arel/algebra/unit/relations/update_spec.rb", - "spec/arel/algebra/unit/relations/where_spec.rb", - "spec/arel/algebra/unit/session/session_spec.rb", - "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", - "spec/arel/engines/memory/unit/relations/array_spec.rb", - "spec/arel/engines/memory/unit/relations/insert_spec.rb", - "spec/arel/engines/memory/unit/relations/join_spec.rb", - "spec/arel/engines/memory/unit/relations/order_spec.rb", - "spec/arel/engines/memory/unit/relations/project_spec.rb", - "spec/arel/engines/memory/unit/relations/skip_spec.rb", - "spec/arel/engines/memory/unit/relations/take_spec.rb", - "spec/arel/engines/memory/unit/relations/where_spec.rb", - "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", - "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", - "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", - "spec/arel/engines/sql/unit/engine_spec.rb", - "spec/arel/engines/sql/unit/predicates/binary_spec.rb", - "spec/arel/engines/sql/unit/predicates/equality_spec.rb", - "spec/arel/engines/sql/unit/predicates/in_spec.rb", - "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", - "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", - "spec/arel/engines/sql/unit/primitives/expression_spec.rb", - "spec/arel/engines/sql/unit/primitives/literal_spec.rb", - "spec/arel/engines/sql/unit/primitives/value_spec.rb", - "spec/arel/engines/sql/unit/relations/alias_spec.rb", - "spec/arel/engines/sql/unit/relations/delete_spec.rb", - "spec/arel/engines/sql/unit/relations/from_spec.rb", - "spec/arel/engines/sql/unit/relations/group_spec.rb", - "spec/arel/engines/sql/unit/relations/having_spec.rb", - "spec/arel/engines/sql/unit/relations/insert_spec.rb", - "spec/arel/engines/sql/unit/relations/join_spec.rb", - "spec/arel/engines/sql/unit/relations/lock_spec.rb", - "spec/arel/engines/sql/unit/relations/order_spec.rb", - "spec/arel/engines/sql/unit/relations/project_spec.rb", - "spec/arel/engines/sql/unit/relations/skip_spec.rb", - "spec/arel/engines/sql/unit/relations/table_spec.rb", - "spec/arel/engines/sql/unit/relations/take_spec.rb", - "spec/arel/engines/sql/unit/relations/update_spec.rb", - "spec/arel/engines/sql/unit/relations/where_spec.rb", - "spec/connections/mysql_connection.rb", - "spec/connections/oracle_connection.rb", - "spec/connections/postgresql_connection.rb", - "spec/connections/sqlite3_connection.rb", - "spec/doubles/hash.rb", - "spec/matchers/be_like.rb", - "spec/matchers/disambiguate_attributes.rb", - "spec/matchers/hash_the_same_as.rb", - "spec/schemas/mysql_schema.rb", - "spec/schemas/oracle_schema.rb", - "spec/schemas/postgresql_schema.rb", - "spec/schemas/sqlite3_schema.rb", - "spec/spec.opts", - "spec/spec_helper.rb" - ] - s.homepage = %q{http://github.com/brynary/arel} - s.require_paths = ["lib"] - s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.3.6} - s.summary = %q{Arel is a relational algebra engine for Ruby} - s.test_files = [ - "spec/arel/algebra/unit/predicates/binary_spec.rb", - "spec/arel/algebra/unit/predicates/equality_spec.rb", - "spec/arel/algebra/unit/predicates/in_spec.rb", - "spec/arel/algebra/unit/primitives/attribute_spec.rb", - "spec/arel/algebra/unit/primitives/expression_spec.rb", - "spec/arel/algebra/unit/primitives/value_spec.rb", - "spec/arel/algebra/unit/relations/alias_spec.rb", - "spec/arel/algebra/unit/relations/delete_spec.rb", - "spec/arel/algebra/unit/relations/group_spec.rb", - "spec/arel/algebra/unit/relations/insert_spec.rb", - "spec/arel/algebra/unit/relations/join_spec.rb", - "spec/arel/algebra/unit/relations/order_spec.rb", - "spec/arel/algebra/unit/relations/project_spec.rb", - "spec/arel/algebra/unit/relations/relation_spec.rb", - "spec/arel/algebra/unit/relations/skip_spec.rb", - "spec/arel/algebra/unit/relations/table_spec.rb", - "spec/arel/algebra/unit/relations/take_spec.rb", - "spec/arel/algebra/unit/relations/update_spec.rb", - "spec/arel/algebra/unit/relations/where_spec.rb", - "spec/arel/algebra/unit/session/session_spec.rb", - "spec/arel/engines/memory/integration/joins/cross_engine_spec.rb", - "spec/arel/engines/memory/unit/relations/array_spec.rb", - "spec/arel/engines/memory/unit/relations/insert_spec.rb", - "spec/arel/engines/memory/unit/relations/join_spec.rb", - "spec/arel/engines/memory/unit/relations/order_spec.rb", - "spec/arel/engines/memory/unit/relations/project_spec.rb", - "spec/arel/engines/memory/unit/relations/skip_spec.rb", - "spec/arel/engines/memory/unit/relations/take_spec.rb", - "spec/arel/engines/memory/unit/relations/where_spec.rb", - "spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb", - "spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb", - "spec/arel/engines/sql/integration/joins/with_compounds_spec.rb", - "spec/arel/engines/sql/unit/engine_spec.rb", - "spec/arel/engines/sql/unit/predicates/binary_spec.rb", - "spec/arel/engines/sql/unit/predicates/equality_spec.rb", - "spec/arel/engines/sql/unit/predicates/in_spec.rb", - "spec/arel/engines/sql/unit/predicates/predicates_spec.rb", - "spec/arel/engines/sql/unit/primitives/attribute_spec.rb", - "spec/arel/engines/sql/unit/primitives/expression_spec.rb", - "spec/arel/engines/sql/unit/primitives/literal_spec.rb", - "spec/arel/engines/sql/unit/primitives/value_spec.rb", - "spec/arel/engines/sql/unit/relations/alias_spec.rb", - "spec/arel/engines/sql/unit/relations/delete_spec.rb", - "spec/arel/engines/sql/unit/relations/from_spec.rb", - "spec/arel/engines/sql/unit/relations/group_spec.rb", - "spec/arel/engines/sql/unit/relations/having_spec.rb", - "spec/arel/engines/sql/unit/relations/insert_spec.rb", - "spec/arel/engines/sql/unit/relations/join_spec.rb", - "spec/arel/engines/sql/unit/relations/lock_spec.rb", - "spec/arel/engines/sql/unit/relations/order_spec.rb", - "spec/arel/engines/sql/unit/relations/project_spec.rb", - "spec/arel/engines/sql/unit/relations/skip_spec.rb", - "spec/arel/engines/sql/unit/relations/table_spec.rb", - "spec/arel/engines/sql/unit/relations/take_spec.rb", - "spec/arel/engines/sql/unit/relations/update_spec.rb", - "spec/arel/engines/sql/unit/relations/where_spec.rb", - "spec/connections/mysql_connection.rb", - "spec/connections/oracle_connection.rb", - "spec/connections/postgresql_connection.rb", - "spec/connections/sqlite3_connection.rb", - "spec/doubles/hash.rb", - "spec/matchers/be_like.rb", - "spec/matchers/disambiguate_attributes.rb", - "spec/matchers/hash_the_same_as.rb", - "spec/schemas/mysql_schema.rb", - "spec/schemas/oracle_schema.rb", - "spec/schemas/postgresql_schema.rb", - "spec/schemas/sqlite3_schema.rb", - "spec/spec_helper.rb" - ] +and query generation. + EOS + s.rubyforge_project = "arel" + + s.files = Dir['lib/**/*'] + s.test_files = Dir['spec/**/*.rb'] - Dir['spec/support/fixtures/**/*.rb'] - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 3 + s.has_rdoc = true + s.extra_rdoc_files = %w[History.txt README.markdown] - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_runtime_dependency(%q, [">= 3.0.0.beta"]) - else - s.add_dependency(%q, [">= 3.0.0.beta"]) - end - else - s.add_dependency(%q, [">= 3.0.0.beta"]) - end -end + # Arel required ActiveRecord, but we're not declaring it to avoid a + # circular dependency chain. The solution is for ActiveRecord to release + # the connection adapters which Arel uses in a separate gem + # s.add_dependency "activerecord", ">= 3.0.pre" + s.add_dependency "activesupport", ">= 3.0.0.beta" +end \ No newline at end of file diff --git a/lib/arel.rb b/lib/arel.rb index ef2308ca5311b..ae4240bf8a640 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -6,7 +6,7 @@ module Arel require 'arel/algebra' require 'arel/engines' - autoload :Session, 'arel/session' + require 'arel/version' - VERSION = "0.3.1" + autoload :Session, 'arel/session' end diff --git a/lib/arel/version.rb b/lib/arel/version.rb new file mode 100644 index 0000000000000..ab126caff46c3 --- /dev/null +++ b/lib/arel/version.rb @@ -0,0 +1,3 @@ +module Arel + VERSION = "0.3.1" +end \ No newline at end of file From 09765829d38e78c0d260aac805c9f405a1523d56 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Tue, 23 Mar 2010 12:05:35 -0700 Subject: [PATCH 0380/1492] Cleanup the spec helper and spec rake task a bit --- Rakefile | 15 +++++++----- lib/arel/version.rb | 2 +- spec/spec_helper.rb | 24 ++++++++++++------- spec/support/connections/mysql_connection.rb | 6 ++--- spec/support/connections/oracle_connection.rb | 8 +++---- .../connections/postgresql_connection.rb | 6 ++--- .../support/connections/sqlite3_connection.rb | 4 +--- 7 files changed, 34 insertions(+), 31 deletions(-) diff --git a/Rakefile b/Rakefile index bc4fe6f8391c6..66e4db38a6176 100644 --- a/Rakefile +++ b/Rakefile @@ -27,18 +27,21 @@ else end namespace :spec do - for adapter in %w[mysql sqlite3 postgresql oracle] - desc "Run specs with the #{adapter} database adapter" + %w[mysql sqlite3 postgresql oracle].each do |adapter| + task "set_env_for_#{adapter}" do + ENV['ADAPTER'] = adapter + end + Spec::Rake::SpecTask.new(adapter) do |t| t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" t.libs << "#{File.dirname(__FILE__)}/spec" # t.warning = true - t.spec_files = - ["spec/support/connections/#{adapter}_connection.rb"] + - ["spec/support/schemas/#{adapter}_schema.rb"] + - FileList['spec/**/*_spec.rb'] + t.spec_files = FileList['spec/**/*_spec.rb'] end + + desc "Run specs with the #{adapter} database adapter" + task adapter => "set_env_for_#{adapter}" end end diff --git a/lib/arel/version.rb b/lib/arel/version.rb index ab126caff46c3..cf421c5db0d4b 100644 --- a/lib/arel/version.rb +++ b/lib/arel/version.rb @@ -1,3 +1,3 @@ module Arel - VERSION = "0.3.1" + VERSION = "0.3.1" unless defined?(Arel::VERSION) end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5941840437d93..a52fa257b7c6d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,6 +7,10 @@ require 'fileutils' require 'arel' +if adapter = ENV['ADAPTER'] + require "support/connections/#{adapter}_connection.rb" +end + Dir["#{dir}/{support,shared}/*.rb"].each do |file| require file end @@ -16,13 +20,17 @@ config.include AdapterGuards config.include Check - config.before do - Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) if defined?(ActiveRecord::Base) - end -end + if defined?(ActiveRecord::Base) + tmp = File.expand_path('../../tmp', __FILE__) -# load corresponding adapter using ADAPTER environment variable when running single *_spec.rb file -if adapter = ENV['ADAPTER'] - require "#{dir}/support/connections/#{adapter}_connection.rb" - require "#{dir}/support/schemas/#{adapter}_schema.rb" + FileUtils.mkdir_p(tmp) + ActiveRecord::Base.logger = Logger.new("#{tmp}/debug.log") + ActiveRecord::Base.establish_connection("unit") + + require "support/schemas/#{ENV['ADAPTER']}_schema.rb" + + config.before do + Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) + end + end end diff --git a/spec/support/connections/mysql_connection.rb b/spec/support/connections/mysql_connection.rb index 66a53b5037b17..de9d05c2ceb86 100644 --- a/spec/support/connections/mysql_connection.rb +++ b/spec/support/connections/mysql_connection.rb @@ -2,7 +2,7 @@ require "active_record" require 'logger' -ActiveRecord::Base.logger = Logger.new("debug.log") +ENV['ADAPTER'] = 'mysql' ActiveRecord::Base.configurations = { 'unit' => { @@ -11,6 +11,4 @@ :encoding => 'utf8', :database => 'arel_unit', } -} - -ActiveRecord::Base.establish_connection 'unit' +} \ No newline at end of file diff --git a/spec/support/connections/oracle_connection.rb b/spec/support/connections/oracle_connection.rb index 05be04e410f68..c28602b1341ee 100644 --- a/spec/support/connections/oracle_connection.rb +++ b/spec/support/connections/oracle_connection.rb @@ -2,11 +2,11 @@ require "active_record" require 'logger' +ENV['ADAPTER'] = 'oracle' + # Prepend oracle_enhanced local development directory in front of load path $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../oracle-enhanced/lib" -ActiveRecord::Base.logger = Logger.new("debug.log") - ActiveRecord::Base.configurations = { 'unit' => { :adapter => 'oracle_enhanced', @@ -14,6 +14,4 @@ :password => 'arel_unit', :database => 'orcl', } -} - -ActiveRecord::Base.establish_connection 'unit' +} \ No newline at end of file diff --git a/spec/support/connections/postgresql_connection.rb b/spec/support/connections/postgresql_connection.rb index 0fb6dfe065282..34d304efa9eed 100644 --- a/spec/support/connections/postgresql_connection.rb +++ b/spec/support/connections/postgresql_connection.rb @@ -2,7 +2,7 @@ require "active_record" require 'logger' -ActiveRecord::Base.logger = Logger.new("debug.log") +ENV['ADAPTER'] = 'postgresql' ActiveRecord::Base.configurations = { 'unit' => { @@ -10,6 +10,4 @@ :encoding => 'utf8', :database => 'arel_unit', } -} - -ActiveRecord::Base.establish_connection 'unit' +} \ No newline at end of file diff --git a/spec/support/connections/sqlite3_connection.rb b/spec/support/connections/sqlite3_connection.rb index abdbd24fe4c2b..4c8627c795887 100644 --- a/spec/support/connections/sqlite3_connection.rb +++ b/spec/support/connections/sqlite3_connection.rb @@ -2,7 +2,7 @@ require "active_record" require 'logger' -ActiveRecord::Base.logger = Logger.new("debug.log") +ENV['ADAPTER'] = 'sqlite3' db_file = "spec/support/fixtures/fixture_database.sqlite3" @@ -22,5 +22,3 @@ puts "Executing '#{sqlite_command}'" raise "Seems that there is no sqlite3 executable available" unless system(sqlite_command) end - -ActiveRecord::Base.establish_connection("unit") From 8991daa5e3077e31f90500fd52d77b69d979cc97 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Tue, 23 Mar 2010 13:48:35 -0700 Subject: [PATCH 0381/1492] Restrictions should be able to contain multiple predicates. --- lib/arel/algebra/relations/operations/where.rb | 10 +++++----- lib/arel/engines/memory/relations/operations.rb | 2 +- spec/algebra/unit/relations/where_spec.rb | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 6c9c5ed75586f..5c50fe8640af7 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -1,17 +1,17 @@ module Arel class Where < Compound - attributes :relation, :predicate + attributes :relation, :predicates deriving :== requires :restricting def initialize(relation, *predicates, &block) - predicate = block_given?? yield(relation) : predicates.shift - @relation = predicates.empty?? relation : Where.new(relation, *predicates) - @predicate = predicate.bind(@relation) + predicates = [yield(relation)] + predicates if block_given? + @predicates = predicates.map { |p| p.bind(relation) } + @relation = relation end def wheres - @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } + @wheres ||= relation.wheres + predicates end end end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 5d7b7670b6cdd..55b4dcb6779e7 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -1,7 +1,7 @@ module Arel class Where < Compound def eval - unoperated_rows.select { |row| predicate.eval(row) } + unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } } end end diff --git a/spec/algebra/unit/relations/where_spec.rb b/spec/algebra/unit/relations/where_spec.rb index 96b95b58238c5..48a8dc50383fe 100644 --- a/spec/algebra/unit/relations/where_spec.rb +++ b/spec/algebra/unit/relations/where_spec.rb @@ -9,6 +9,7 @@ module Arel describe '#initialize' do it "manufactures nested where relations if multiple predicates are provided" do + pending "This is not true anymore" another_predicate = @relation[:name].lt(2) Where.new(@relation, @predicate, another_predicate). \ should == Where.new(Where.new(@relation, another_predicate), @predicate) From 8cae1ba11067f685d313a92d49331c076bbbe71e Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Tue, 23 Mar 2010 14:38:54 -0700 Subject: [PATCH 0382/1492] Bump up the AS dependency to 3.0.0.beta1 --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 31a3b558a9469..0f9eef38331f3 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -27,5 +27,5 @@ and query generation. # circular dependency chain. The solution is for ActiveRecord to release # the connection adapters which Arel uses in a separate gem # s.add_dependency "activerecord", ">= 3.0.pre" - s.add_dependency "activesupport", ">= 3.0.0.beta" + s.add_dependency "activesupport", ">= 3.0.0.beta1" end \ No newline at end of file From e7fb6a9f92fc9208a85735ecebc7fc4292498700 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Tue, 23 Mar 2010 14:49:34 -0700 Subject: [PATCH 0383/1492] Add a Gemfile --- Gemfile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Gemfile diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000000..2e80c2172a6b4 --- /dev/null +++ b/Gemfile @@ -0,0 +1,9 @@ +source :rubygems + +gem "activerecord", :path => ENV["RAILS_SOURCE"] +gem "diff-lcs" +gem "mysql" +gem "pg" +gem "rake" +gem "rspec" +gem "sqlite3-ruby" \ No newline at end of file From 99694fdb00878f06942deb5f8686d7e3d2fca62b Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Mar 2010 12:09:19 -0300 Subject: [PATCH 0384/1492] Use adapter add_limit_offset! method when building query. --- lib/arel/engines/sql/compilers/ibm_db_compiler.rb | 14 -------------- lib/arel/engines/sql/relations/compiler.rb | 10 +++++----- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb index e15e7831604d3..8c5779a35e8af 100644 --- a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb +++ b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb @@ -31,20 +31,6 @@ module Arel module SqlCompiler class IBM_DBCompiler < GenericCompiler - def select_sql - query = build_query \ - "SELECT #{select_clauses.join(', ')}", - "FROM #{from_clauses}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), - ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) - engine.add_limit_offset!(query,{:limit=>taken,:offset=>skipped}) unless taken.blank? - query << "#{locked}" unless locked.blank? - query - end - def limited_update_conditions(conditions, taken) quoted_primary_key = engine.quote_table_name(primary_key) update_conditions = "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions} " #Note: - ')' not added, limit segment is to be appended diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index fc8d484276580..cc0deb7c88f1e 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -8,17 +8,17 @@ def initialize(relation) end def select_sql - build_query \ + query = build_query \ "SELECT #{select_clauses.join(', ')}", "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), - ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ), - ("#{locked}" unless locked.blank?) + ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) + engine.add_limit_offset!(query,{ :limit => taken, :offset => skipped }) if taken || skipped + query << " #{locked}" unless locked.blank? + query end def delete_sql From b04ebb7602d4e318469977649cf7a02f381b3143 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Mar 2010 12:16:02 -0300 Subject: [PATCH 0385/1492] Bump the version to 0.3.2 --- arel.gemspec | 3 ++- lib/arel/version.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 0f9eef38331f3..3a236d11b3624 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -5,6 +5,7 @@ Gem::Specification.new do |s| s.name = "arel" s.version = Arel::VERSION s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] + s.date = %q{2010-03-25} s.email = "bryan@brynary.com" s.homepage = "http://github.com/brynary/arel" s.summary = "Arel is a relational algebra engine for Ruby" @@ -28,4 +29,4 @@ and query generation. # the connection adapters which Arel uses in a separate gem # s.add_dependency "activerecord", ">= 3.0.pre" s.add_dependency "activesupport", ">= 3.0.0.beta1" -end \ No newline at end of file +end diff --git a/lib/arel/version.rb b/lib/arel/version.rb index cf421c5db0d4b..16eccdee4ccb4 100644 --- a/lib/arel/version.rb +++ b/lib/arel/version.rb @@ -1,3 +1,3 @@ module Arel - VERSION = "0.3.1" unless defined?(Arel::VERSION) -end \ No newline at end of file + VERSION = "0.3.2" unless defined?(Arel::VERSION) +end From 2700d6c04436be383b1b099559002d851f0aca50 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Mar 2010 15:57:45 -0300 Subject: [PATCH 0386/1492] Use ActiveSupport beta since beta1 is not released yet. Added singleton_class until beta1 is out. --- arel.gemspec | 2 +- lib/arel/algebra/core_extensions/object.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 3a236d11b3624..8091bec4d4a07 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -28,5 +28,5 @@ and query generation. # circular dependency chain. The solution is for ActiveRecord to release # the connection adapters which Arel uses in a separate gem # s.add_dependency "activerecord", ">= 3.0.pre" - s.add_dependency "activesupport", ">= 3.0.0.beta1" + s.add_dependency "activesupport", ">= 3.0.0.beta" end diff --git a/lib/arel/algebra/core_extensions/object.rb b/lib/arel/algebra/core_extensions/object.rb index 85a4d951a4f23..82fa28546c0fc 100644 --- a/lib/arel/algebra/core_extensions/object.rb +++ b/lib/arel/algebra/core_extensions/object.rb @@ -12,6 +12,19 @@ def let yield(self) end + # TODO remove this when ActiveSupport beta1 is out. + # Returns the object's singleton class. + def singleton_class + class << self + self + end + end unless respond_to?(:singleton_class) + + # class_eval on an object acts like singleton_class_eval. + def class_eval(*args, &block) + singleton_class.class_eval(*args, &block) + end + Object.send(:include, self) end end From aa9559c39999030aee24391f6a09f1116672a471 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 25 Mar 2010 15:59:29 -0300 Subject: [PATCH 0387/1492] Bump the version to 0.3.3 --- lib/arel/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/version.rb b/lib/arel/version.rb index 16eccdee4ccb4..0e1758947f239 100644 --- a/lib/arel/version.rb +++ b/lib/arel/version.rb @@ -1,3 +1,3 @@ module Arel - VERSION = "0.3.2" unless defined?(Arel::VERSION) + VERSION = "0.3.3" unless defined?(Arel::VERSION) end From 233ee77f4511255ff2ff7c0b0ebf1cee13e7fc10 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 29 Mar 2010 12:31:25 -0300 Subject: [PATCH 0388/1492] Handle ranges with excluded end. --- lib/arel/algebra/attributes/attribute.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index b372be5e1d744..331f21846303a 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -111,7 +111,11 @@ def matches(regexp) end def in(array) - Predicates::In.new(self, array) + if array.is_a?(Range) && array.exclude_end? + [Predicates::GreaterThanOrEqualTo.new(self, array.begin), Predicates::LessThan.new(self, array.end)] + else + Predicates::In.new(self, array) + end end end include Predications From a46922e4a1089c9880c30b389e1e1d9dfbab02ae Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 2 Apr 2010 19:04:23 -0700 Subject: [PATCH 0389/1492] Create an Arel::Header class representing a relation's attributes --- lib/arel/algebra.rb | 1 + lib/arel/algebra/attributes/attribute.rb | 2 +- lib/arel/algebra/header.rb | 71 +++++++++++++++++++ lib/arel/algebra/relations/operations/join.rb | 3 +- .../algebra/relations/operations/project.rb | 2 +- lib/arel/algebra/relations/relation.rb | 40 +++++------ .../algebra/relations/utilities/compound.rb | 6 +- .../relations/utilities/externalization.rb | 2 +- lib/arel/engines/memory/relations/array.rb | 9 ++- .../engines/sql/relations/operations/join.rb | 2 +- lib/arel/engines/sql/relations/table.rb | 12 ++-- spec/algebra/unit/relations/join_spec.rb | 3 +- spec/algebra/unit/relations/table_spec.rb | 2 +- spec/attributes/header_spec.rb | 35 +++++++++ spec/support/matchers/be_like.rb | 6 +- spec/support/model.rb | 6 +- 16 files changed, 160 insertions(+), 42 deletions(-) create mode 100644 lib/arel/algebra/header.rb create mode 100644 spec/attributes/header_spec.rb diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index 83f6a54326253..bc7b2fef2d8d6 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,6 +1,7 @@ require 'arel/algebra/core_extensions' require 'arel/algebra/attributes' +require 'arel/algebra/header' require 'arel/algebra/expression' require 'arel/algebra/ordering' require 'arel/algebra/predicates' diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 331f21846303a..afcbdd8301e5d 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -29,7 +29,7 @@ def self.included(klass) end def hash - @hash ||= history.size + name.hash + relation.hash + @hash ||= name.hash + root.relation.hash end def as(aliaz = nil) diff --git a/lib/arel/algebra/header.rb b/lib/arel/algebra/header.rb new file mode 100644 index 0000000000000..ec45488dbf5e2 --- /dev/null +++ b/lib/arel/algebra/header.rb @@ -0,0 +1,71 @@ +module Arel + class Header + include Enumerable + + def initialize(attrs = []) + @attributes = attrs.to_ary + @names = Hash.new do |h,k| + h[k] = @attributes.detect { |a| a.named?(k) } + end + end + + def each(&block) + to_ary.each(&block) + self + end + + def [](key) + case key + when String, Symbol then find_by_name(key) + when Attribute then find_by_attribute(key) + end + end + + def ==(other) + to_set == other.to_set + end + + def union(other) + new(to_ary | other) + end + + alias | union + + def to_ary + @attributes + end + + def bind(relation) + Header.new(map { |a| a.bind(relation) }) + end + + # TMP + def index(i) + to_ary.index(i) + end + + private + + def new(attrs) + self.class.new(attrs) + end + + def matching(attribute) + # (@matching_attributes ||= attributes.inject({}) do |hash, a| + # (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a + # hash + # end)[attribute.root] || [] + select { |a| !a.is_a?(Value) && a.root == attribute.root } + end + + def find_by_name(name) + @names[name.to_sym] + end + + def find_by_attribute(attr) + matching(attr).max do |a, b| + (a.original_attribute / attr) <=> (b.original_attribute / attr) + end + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 300cd31bcde4b..21bcfaa62d4cf 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -19,8 +19,7 @@ def eql?(other) end def attributes - @attributes ||= (relation1.externalize.attributes + - relation2.externalize.attributes).collect { |a| a.bind(self) } + @attributes ||= (relation1.externalize.attributes | relation2.externalize.attributes).bind(self) end def wheres diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index a1140e91c184e..49d0e1be36a9c 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -10,7 +10,7 @@ def initialize(relation, *projections, &block) end def attributes - @attributes ||= projections.collect { |p| p.bind(self) } + @attributes ||= Header.new(projections).bind(self) end def externalizable? diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 1c1ded15c9e96..ef2108dcaa124 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -84,16 +84,14 @@ def on(*predicates) module AttributeAccessable def [](index) - @cached_attributes ||= {} - @cached_attributes[index] ||= case index - when Symbol, String - find_attribute_matching_name(index) - when Attribute, Expression - find_attribute_matching_attribute(index) - when ::Array - # TESTME - index.collect { |i| self[i] } + attr = attributes[index] + + # Handles a strange ActiveRecord case + if !attr && (index.is_a?(String) || index.is_a?(Symbol)) + attr = Attribute.new(self, index) end + + attr end def find_attribute_matching_name(name) @@ -127,18 +125,18 @@ def has_attribute?(attribute) include AttributeAccessable module DefaultOperations - def attributes; [] end - def projections; [] end - def wheres; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def havings; [] end - def joins(formatter = nil); nil end # FIXME - def taken; nil end - def skipped; nil end - def sources; [] end - def locked; [] end + def attributes; Header.new end + def projections; [] end + def wheres; [] end + def orders; [] end + def inserts; [] end + def groupings; [] end + def havings; [] end + def joins(formatter = nil); nil end # FIXME + def taken; nil end + def skipped; nil end + def sources; [] end + def locked; [] end end include DefaultOperations end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 7039b825755cd..416717310c901 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -13,7 +13,7 @@ def self.requires(feature = nil) @requires end - [:attributes, :wheres, :groupings, :orders, :havings, :projections].each do |operation_name| + [:wheres, :groupings, :orders, :havings, :projections].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } @@ -21,6 +21,10 @@ def #{operation_name} OPERATION end + def attributes + @attributes ||= relation.attributes.bind(self) + end + def hash @hash ||= :relation.hash end diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index 795a3919f2387..edd8f99221c85 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -8,7 +8,7 @@ def wheres end def attributes - @attributes ||= relation.attributes.collect { |a| a.to_attribute(self) } + @attributes ||= Header.new(relation.attributes.map { |a| a.to_attribute(self) }) end end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 6486dcbcc1b29..d8751fa6264c9 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -15,9 +15,12 @@ def engine end def attributes - @attributes ||= @attribute_names_and_types.collect do |attribute, type| - attribute = type.new(self, attribute) if Symbol === attribute - attribute + @attributes ||= begin + attrs = @attribute_names_and_types.collect do |attribute, type| + attribute = type.new(self, attribute) if Symbol === attribute + attribute + end + Header.new(attrs) end end diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index 7fad6400adeb5..97336573655d2 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -10,7 +10,7 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) join_sql, relation2.externalize.table_sql(formatter), ("ON" unless predicates.blank?), - (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + (ons + relation2.externalize.wheres).collect { |p| p.bind(environment.relation).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') ].compact.join(" ") [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 8ee7a943578e8..7940fd781fd0f 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -42,11 +42,14 @@ def table_exists? def attributes return @attributes if defined?(@attributes) if table_exists? - @attributes = columns.collect do |column| - Sql::Attributes.for(column).new(column, self, column.name.to_sym) + @attributes ||= begin + attrs = columns.collect do |column| + Sql::Attributes.for(column).new(column, self, column.name.to_sym) + end + Header.new(attrs) end else - [] + Header.new end end @@ -67,7 +70,8 @@ def columns end def reset - @attributes = @columns = nil + @columns = nil + @attributes = Header.new([]) end def ==(other) diff --git a/spec/algebra/unit/relations/join_spec.rb b/spec/algebra/unit/relations/join_spec.rb index 9c1422c57182e..5fa326905282c 100644 --- a/spec/algebra/unit/relations/join_spec.rb +++ b/spec/algebra/unit/relations/join_spec.rb @@ -18,8 +18,7 @@ module Arel describe '#attributes' do it 'combines the attributes of the two relations' do join = InnerJoin.new(@relation1, @relation2, @predicate) - join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } + join.attributes.should == (@relation1.attributes | @relation2.attributes).bind(join) end end end diff --git a/spec/algebra/unit/relations/table_spec.rb b/spec/algebra/unit/relations/table_spec.rb index d93446f1b9036..d1c7cc46ba8e3 100644 --- a/spec/algebra/unit/relations/table_spec.rb +++ b/spec/algebra/unit/relations/table_spec.rb @@ -9,7 +9,7 @@ module Arel describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do - check @relation[:id].should == Attribute.new(@relation, :id) + check @relation[:id].should == Attributes::Integer.new(@relation, :id) end end diff --git a/spec/attributes/header_spec.rb b/spec/attributes/header_spec.rb new file mode 100644 index 0000000000000..5811041734a43 --- /dev/null +++ b/spec/attributes/header_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +module Arel + describe "Header" do + before :all do + @relation = Model.build do |r| + r.attribute :id, Attributes::Integer + r.attribute :name, Attributes::String + r.attribute :age, Attributes::Integer + end + + @other = Model.build do |r| + r.attribute :foo, Attributes::String + end + + @subset = Model.build do |r| + r.attribute :id, Attributes::Integer + end + end + + it "finds attributes by name" do + @relation.attributes[:name].should == Attributes::String.new(@relation, :name) + end + + describe "#union" do + it "keeps all attributes from disjoint headers" do + (@relation.attributes.union @other.attributes).to_ary.should have(4).items + end + + it "keeps all attributes from both relations even if they seem like subsets" do + (@relation.attributes.union @subset.attributes).to_ary.should have(4).items + end + end + end +end \ No newline at end of file diff --git a/spec/support/matchers/be_like.rb b/spec/support/matchers/be_like.rb index 0608abbbb47f2..ca49b9127461f 100644 --- a/spec/support/matchers/be_like.rb +++ b/spec/support/matchers/be_like.rb @@ -1,12 +1,12 @@ module Matchers class BeLike def initialize(expected) - @expected = expected + @expected = expected.gsub(/\s+/, ' ').strip end def matches?(actual) - @actual = actual - @expected.gsub(/\s+/, ' ').strip == @actual.gsub(/\s+/, ' ').strip + @actual = actual.gsub(/\s+/, ' ').strip + @expected == @actual end def failure_message diff --git a/spec/support/model.rb b/spec/support/model.rb index 10a14d7092fde..be692e53ec56b 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -25,7 +25,7 @@ def create(insert) class Model include Relation - attr_reader :engine, :attributes + attr_reader :engine def self.build relation = new @@ -46,6 +46,10 @@ def attribute(name, type) @attributes << type.new(self, name) end + def attributes + Header.new(@attributes) + end + def format(attribute, value) value end From 406fa3d37e8a531bec5646a46a7d109f6ed8c345 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 2 Apr 2010 19:13:12 -0700 Subject: [PATCH 0390/1492] Remove commented out code --- lib/arel/algebra/header.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/algebra/header.rb b/lib/arel/algebra/header.rb index ec45488dbf5e2..3b74d31684f62 100644 --- a/lib/arel/algebra/header.rb +++ b/lib/arel/algebra/header.rb @@ -51,10 +51,6 @@ def new(attrs) end def matching(attribute) - # (@matching_attributes ||= attributes.inject({}) do |hash, a| - # (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a - # hash - # end)[attribute.root] || [] select { |a| !a.is_a?(Value) && a.root == attribute.root } end From e5454e8d8adcf53829a44702f2328f8ea119a16a Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sat, 3 Apr 2010 10:40:46 -0700 Subject: [PATCH 0391/1492] Return nil when looking up an attribute by name that does not exist instead of returning a fictitious attribute. --- lib/arel/algebra/relations/relation.rb | 9 +-------- spec/attributes/header_spec.rb | 11 +++++++++-- .../sql/unit/primitives/attribute_spec.rb | 19 ------------------- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index ef2108dcaa124..ffd31ae4703aa 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -84,14 +84,7 @@ def on(*predicates) module AttributeAccessable def [](index) - attr = attributes[index] - - # Handles a strange ActiveRecord case - if !attr && (index.is_a?(String) || index.is_a?(Symbol)) - attr = Attribute.new(self, index) - end - - attr + attributes[index] end def find_attribute_matching_name(name) diff --git a/spec/attributes/header_spec.rb b/spec/attributes/header_spec.rb index 5811041734a43..8fb4007003f65 100644 --- a/spec/attributes/header_spec.rb +++ b/spec/attributes/header_spec.rb @@ -18,8 +18,15 @@ module Arel end end - it "finds attributes by name" do - @relation.attributes[:name].should == Attributes::String.new(@relation, :name) + describe "attribute lookup" do + it "finds attributes by name" do + @relation.attributes[:name].should == Attributes::String.new(@relation, :name) + end + + it "returns nil if no attribute is found" do + @relation.attributes[:does_not_exist].should be_nil + @relation[:does_not_exist].should be_nil + end end describe "#union" do diff --git a/spec/engines/sql/unit/primitives/attribute_spec.rb b/spec/engines/sql/unit/primitives/attribute_spec.rb index c467d902ad4df..9f864dd3a1f62 100644 --- a/spec/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/engines/sql/unit/primitives/attribute_spec.rb @@ -31,25 +31,6 @@ module Arel end end end - - describe 'for an inexistent attribute' do - it "manufactures sql" do - sql = @relation[:does_not_exist].to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`does_not_exist`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."DOEST_NOT_EXIST"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."does_not_exist"}) - end - end - end - end end end From a7a5027f4f17e12cf11c310dd807f5c41e798cdb Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Apr 2010 20:21:07 -0300 Subject: [PATCH 0392/1492] build expression not(nil) as IS NOT NULL --- .../engines/sql/core_extensions/nil_class.rb | 4 + .../engines/sql/core_extensions/object.rb | 4 + lib/arel/engines/sql/predicates.rb | 4 +- lib/arel/engines/sql/primitives.rb | 4 + spec/engines/sql/unit/predicates/not_spec.rb | 75 +++++++++++++++++++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 spec/engines/sql/unit/predicates/not_spec.rb diff --git a/lib/arel/engines/sql/core_extensions/nil_class.rb b/lib/arel/engines/sql/core_extensions/nil_class.rb index c3dbc8cd76f75..3f70677ba6f06 100644 --- a/lib/arel/engines/sql/core_extensions/nil_class.rb +++ b/lib/arel/engines/sql/core_extensions/nil_class.rb @@ -5,6 +5,10 @@ def equality_predicate_sql 'IS' end + def not_predicate_sql + 'IS NOT' + end + NilClass.send(:include, self) end end diff --git a/lib/arel/engines/sql/core_extensions/object.rb b/lib/arel/engines/sql/core_extensions/object.rb index 9f15dff7715bd..b71ef29fd53aa 100644 --- a/lib/arel/engines/sql/core_extensions/object.rb +++ b/lib/arel/engines/sql/core_extensions/object.rb @@ -9,6 +9,10 @@ def equality_predicate_sql '=' end + def not_predicate_sql + '!=' + end + Object.send(:include, self) end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 3756231a4669c..e40240eec5a4d 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -27,7 +27,9 @@ def predicate_sql end class Not < Binary - def predicate_sql; '!=' end + def predicate_sql + operand2.not_predicate_sql + end end class GreaterThanOrEqualTo < Binary diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 666579331ac8d..78e1ed7f0bb1d 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -34,6 +34,10 @@ def equality_predicate_sql value.equality_predicate_sql end + def not_predicate_sql + value.not_predicate_sql + end + def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value end diff --git a/spec/engines/sql/unit/predicates/not_spec.rb b/spec/engines/sql/unit/predicates/not_spec.rb new file mode 100644 index 0000000000000..b124d4c80b7bc --- /dev/null +++ b/spec/engines/sql/unit/predicates/not_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +module Arel + module Predicates + describe Equality do + before do + @relation1 = Arel::Table.new(:users) + @relation2 = Arel::Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] + end + + describe '#to_sql' do + describe 'when relating to a non-nil value' do + it "manufactures a not predicate" do + sql = Not.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` != `photos`.`user_id`}) + end + + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" != "PHOTOS"."USER_ID"}) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{"users"."id" != "photos"."user_id"}) + end + end + end + + describe 'when relation to a nil value' do + before do + @nil = nil + end + + it "manufactures an is null predicate" do + sql = Not.new(@attribute1, @nil).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NOT NULL}) + end + + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IS NOT NULL}) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{"users"."id" IS NOT NULL}) + end + end + end + + describe "when relating to a nil Value" do + it "manufactures an IS NULL predicate" do + value = nil.bind(@relation1) + sql = Not.new(@attribute1, value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NOT NULL}) + end + + adapter_is :oracle do + sql.should be_like(%Q{"USERS"."ID" IS NOT NULL}) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{"users"."id" IS NOT NULL}) + end + end + end + end + end + end +end From def75c7b54ccc18f3a8daf79b6144ddcb538d4e8 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 24 Mar 2010 16:22:15 -0400 Subject: [PATCH 0393/1492] Added NotMatch and NotIn predicates, made Not derive from Equality (reverted later) --- lib/arel/algebra/attributes/attribute.rb | 8 ++++++++ lib/arel/algebra/predicates.rb | 16 +++++++++------- lib/arel/engines/memory/predicates.rb | 12 +++++++++++- lib/arel/engines/sql/core_extensions/array.rb | 4 ++++ lib/arel/engines/sql/core_extensions/range.rb | 4 ++++ lib/arel/engines/sql/predicates.rb | 8 ++++++++ lib/arel/engines/sql/relations/relation.rb | 4 ++++ spec/shared/relation_spec.rb | 4 ++++ 8 files changed, 52 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index afcbdd8301e5d..d9ea58812840d 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -110,6 +110,10 @@ def matches(regexp) Predicates::Match.new(self, regexp) end + def notmatches(regexp) + Predicates::NotMatch.new(self, regexp) + end + def in(array) if array.is_a?(Range) && array.exclude_end? [Predicates::GreaterThanOrEqualTo.new(self, array.begin), Predicates::LessThan.new(self, array.end)] @@ -117,6 +121,10 @@ def in(array) Predicates::In.new(self, array) end end + + def notin(array) + Predicates::NotIn.new(self, array) + end end include Predications diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 700cd6afaaaa0..05a1de983de2b 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -33,12 +33,14 @@ def ==(other) end end - class Not < Binary; end - class GreaterThanOrEqualTo < Binary; end - class GreaterThan < Binary; end - class LessThanOrEqualTo < Binary; end - class LessThan < Binary; end - class Match < Binary; end - class In < Binary; end + class Not < Equality; end + class GreaterThanOrEqualTo < Binary; end + class GreaterThan < Binary; end + class LessThanOrEqualTo < Binary; end + class LessThan < Binary; end + class Match < Binary; end + class NotMatch < Binary; end + class In < Binary; end + class NotIn < Binary; end end end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index f87bf68357d3d..b8642136d8602 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -10,7 +10,7 @@ class Equality < Binary def operator; :== end end - class Not < Binary + class Not < Equality def eval(row) operand1.eval(row) != operand2.eval(row) end @@ -35,9 +35,19 @@ def operator; :< end class Match < Binary def operator; :=~ end end + + class NotMatch < Binary + def operator; :!~ end + end class In < Binary def operator; :include? end end + + class NotIn < Binary + def eval(row) + !(operand1.eval(row).include?(operand2.eval(row))) + end + end end end diff --git a/lib/arel/engines/sql/core_extensions/array.rb b/lib/arel/engines/sql/core_extensions/array.rb index 72f579b7ebfbe..412479dc8306c 100644 --- a/lib/arel/engines/sql/core_extensions/array.rb +++ b/lib/arel/engines/sql/core_extensions/array.rb @@ -12,6 +12,10 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "IN" end + + def exclusion_predicate_sql + "NOT IN" + end Array.send(:include, self) end diff --git a/lib/arel/engines/sql/core_extensions/range.rb b/lib/arel/engines/sql/core_extensions/range.rb index 46124f8865486..b5b1534e48a16 100644 --- a/lib/arel/engines/sql/core_extensions/range.rb +++ b/lib/arel/engines/sql/core_extensions/range.rb @@ -8,6 +8,10 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "BETWEEN" end + + def exclusion_predicate_sql + "NOT BETWEEN" + end Range.send(:include, self) end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index e40240eec5a4d..e9a068fb13033 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -51,9 +51,17 @@ def predicate_sql; '<' end class Match < Binary def predicate_sql; 'LIKE' end end + + class NotMatch < Binary + def predicate_sql; 'NOT LIKE' end + end class In < Binary def predicate_sql; operand2.inclusion_predicate_sql end end + + class NotIn < Binary + def predicate_sql; operand2.exclusion_predicate_sql end + end end end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index f372589af1276..fc353fe0c82b0 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -21,6 +21,10 @@ def christener def inclusion_predicate_sql "IN" end + + def exclusion_predicate_sql + "NOT IN" + end def primary_key connection_id = engine.connection.object_id diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index 5f0ae4b46ef8f..06e8fd20271fe 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -61,12 +61,16 @@ end it "finds rows with a matches predicate" + + it "finds rows with a not matches predicate" it "finds rows with an in predicate" do pending set = @expected[1..(@expected.length/2+1)] @relation.all(:id.in => set.map { |r| r.id }).should have_resources(set) end + + it "finds rows with a not in predicate" end describe "#order" do From 32fbb70f100d0d6f9800020ef519a09a0852ae47 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Thu, 25 Mar 2010 20:18:36 -0400 Subject: [PATCH 0394/1492] Add grouped predicates (_any/_all) and refactored predication method definitions --- lib/arel/algebra/attributes/attribute.rb | 72 +++++++++++------------- lib/arel/algebra/predicates.rb | 26 +++++++++ lib/arel/engines/sql/predicates.rb | 18 ++++++ 3 files changed, 78 insertions(+), 38 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index d9ea58812840d..5689d69b0209f 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -82,48 +82,44 @@ def /(other) include Congruence module Predications - def eq(other) - Predicates::Equality.new(self, other) - end - - def not(other) - Predicates::Not.new(self, other) - end - - def lt(other) - Predicates::LessThan.new(self, other) - end - - def lteq(other) - Predicates::LessThanOrEqualTo.new(self, other) - end - - def gt(other) - Predicates::GreaterThan.new(self, other) - end - - def gteq(other) - Predicates::GreaterThanOrEqualTo.new(self, other) - end - - def matches(regexp) - Predicates::Match.new(self, regexp) - end - - def notmatches(regexp) - Predicates::NotMatch.new(self, regexp) - end + methods = { + :eq => "Equality", + :not => "Not", + :lt => "LessThan", + :lteq => "LessThanOrEqualTo", + :gt => "GreaterThan", + :gteq => "GreaterThanOrEqualTo", + :matches => "Match", + :notmatches => "NotMatch", + :in => "In", + :notin => "NotIn" + } - def in(array) - if array.is_a?(Range) && array.exclude_end? - [Predicates::GreaterThanOrEqualTo.new(self, array.begin), Predicates::LessThan.new(self, array.end)] - else - Predicates::In.new(self, array) + def self.predication(name, klass) + methods = { + :operator => " + def #{name}(other) + Predicates::#{klass}.new(self, other) + end + ", + :any => " + def #{name}_any(*others) + Predicates::Any.new(Predicates::#{klass}, self, *others) + end + ", + :all => " + def #{name}_all(*others) + Predicates::All.new(Predicates::#{klass}, self, *others) + end + " + } + [:operator, :any, :all].each do |method_name| + module_eval methods[method_name], __FILE__, __LINE__ end end - def notin(array) - Predicates::NotIn.new(self, array) + methods.each_pair do |method_name, class_name| + predication(method_name, class_name) end end include Predications diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 05a1de983de2b..ea1f771abba7a 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -9,6 +9,32 @@ def and(other_predicate) And.new(self, other_predicate) end end + + class Grouped < Predicate + attributes :operator, :operand1, :operands2 + + def initialize(operator, operand1, *operands2) + @operator = operator + @operand1 = operand1 + @operands2 = operands2.uniq + end + + def ==(other) + self.class === other and + @operand1 == other.operand1 and + same_elements?(@operands2, other.operands2) + end + + private + + def same_elements?(a1, a2) + [:select, :inject, :size].each do |m| + return false unless [a1, a2].each {|a| a.respond_to?(m) } + end + a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h } == + a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } + end + end class Binary < Predicate attributes :operand1, :operand2 diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index e9a068fb13033..53bac7a2ca9ff 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -19,6 +19,24 @@ def predicate_sql; "OR" end class And < CompoundPredicate def predicate_sql; "AND" end end + + class GroupedPredicate < Grouped + def to_sql(formatter = nil) + "(" + + operands2.inject([]) { |predicates, operand| + predicates << operator.new(operand1, operand).to_sql + }.join(" #{predicate_sql} ") + + ")" + end + end + + class Any < GroupedPredicate + def predicate_sql; "OR" end + end + + class All < GroupedPredicate + def predicate_sql; "AND" end + end class Equality < Binary def predicate_sql From 7e7a3548bb7e024b0bac0a03e3ac9f774c3486d4 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Tue, 30 Mar 2010 08:45:09 -0400 Subject: [PATCH 0395/1492] Cleaner support for Ranges with excluded end. --- lib/arel/engines/sql/predicates.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 53bac7a2ca9ff..7fac09e750317 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -75,6 +75,16 @@ def predicate_sql; 'NOT LIKE' end end class In < Binary + def to_sql + if operand2.is_a?(Range) && operand2.exclude_end? + GreaterThanOrEqualTo.new(operand1, operand2.begin).and( + LessThan.new(operand1, operand2.end) + ).to_sql + else + super + end + end + def predicate_sql; operand2.inclusion_predicate_sql end end From 0afcfa27c9f386ca7c190cd1f66db1cdd9971f3b Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Tue, 30 Mar 2010 09:52:22 -0400 Subject: [PATCH 0396/1492] Rename Attribute Not -> Inequality and add a Not predicate (complement) --- lib/arel/algebra/attributes/attribute.rb | 2 +- lib/arel/algebra/predicates.rb | 11 ++++++++++- lib/arel/engines/memory/predicates.rb | 2 +- lib/arel/engines/sql/predicates.rb | 20 ++++++++++++++------ spec/shared/relation_spec.rb | 2 +- 5 files changed, 27 insertions(+), 10 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 5689d69b0209f..0266b38db3cf9 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -84,7 +84,7 @@ def /(other) module Predications methods = { :eq => "Equality", - :not => "Not", + :noteq => "Inequality", :lt => "LessThan", :lteq => "LessThanOrEqualTo", :gt => "GreaterThan", diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index ea1f771abba7a..43606139b06b5 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -8,6 +8,10 @@ def or(other_predicate) def and(other_predicate) And.new(self, other_predicate) end + + def not + Not.new(self) + end end class Grouped < Predicate @@ -35,6 +39,11 @@ def same_elements?(a1, a2) a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } end end + + class Unary < Predicate + attributes :operand + deriving :initialize, :== + end class Binary < Predicate attributes :operand1, :operand2 @@ -59,7 +68,7 @@ def ==(other) end end - class Not < Equality; end + class Inequality < Equality; end class GreaterThanOrEqualTo < Binary; end class GreaterThan < Binary; end class LessThanOrEqualTo < Binary; end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index b8642136d8602..d0963e2f74cb9 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -10,7 +10,7 @@ class Equality < Binary def operator; :== end end - class Not < Equality + class Inequality < Equality def eval(row) operand1.eval(row) != operand2.eval(row) end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 7fac09e750317..29bc74c6053db 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -5,6 +5,16 @@ def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end end + + class Unary < Predicate + def to_sql(formatter = nil) + "#{predicate_sql} (#{operand.to_sql(formatter)})" + end + end + + class Not < Unary + def predicate_sql; "NOT" end + end class CompoundPredicate < Binary def to_sql(formatter = nil) @@ -44,10 +54,8 @@ def predicate_sql end end - class Not < Binary - def predicate_sql - operand2.not_predicate_sql - end + class Inequality < Equality + def predicate_sql; '!=' end end class GreaterThanOrEqualTo < Binary @@ -75,11 +83,11 @@ def predicate_sql; 'NOT LIKE' end end class In < Binary - def to_sql + def to_sql(formatter = nil) if operand2.is_a?(Range) && operand2.exclude_end? GreaterThanOrEqualTo.new(operand1, operand2.begin).and( LessThan.new(operand1, operand2.end) - ).to_sql + ).to_sql(formatter) else super end diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index 06e8fd20271fe..1407dddb2aacf 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -37,7 +37,7 @@ it "finds rows with a not predicate" do expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } - @relation.where(@relation[:age].not(@pivot[@relation[:age]])).should have_rows(expected) + @relation.where(@relation[:age].noteq(@pivot[@relation[:age]])).should have_rows(expected) end it "finds rows with a less than predicate" do From 0433b054eebd5a53ff6c5f35383a6c0aed0015b2 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Tue, 30 Mar 2010 15:32:39 -0400 Subject: [PATCH 0397/1492] Tests for notmatches and notin, and fixes for issues found in tests --- lib/arel/algebra/predicates.rb | 23 +++++++++--- lib/arel/engines/memory/predicates.rb | 53 +++++++++++++++++++++++++-- lib/arel/engines/sql/predicates.rb | 6 +-- spec/relations/join_spec.rb | 6 ++- spec/relations/relation_spec.rb | 2 +- spec/shared/relation_spec.rb | 37 +++++++++++++++---- 6 files changed, 106 insertions(+), 21 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 43606139b06b5..be80f2a987f81 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -14,19 +14,28 @@ def not end end - class Grouped < Predicate - attributes :operator, :operand1, :operands2 + class Polyadic < Predicate + attributes :operator, :operand1, :additional_operands - def initialize(operator, operand1, *operands2) + def initialize(operator, operand1, *additional_operands) @operator = operator @operand1 = operand1 - @operands2 = operands2.uniq + @additional_operands = additional_operands.uniq end def ==(other) self.class === other and + @operator == operator and @operand1 == other.operand1 and - same_elements?(@operands2, other.operands2) + same_elements?(@additional_operands, other.additional_operands) + end + + def bind(relation) + self.class.new( + operator, + operand1.find_correlate_in(relation), + *additional_operands.map {|o| o.find_correlate_in(relation)} + ) end private @@ -43,6 +52,10 @@ def same_elements?(a1, a2) class Unary < Predicate attributes :operand deriving :initialize, :== + + def bind(relation) + self.class.new(operand.find_correlate_in(relation)) + end end class Binary < Predicate diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index d0963e2f74cb9..c0ee862626036 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -5,6 +5,49 @@ def eval(row) operand1.eval(row).send(operator, operand2.eval(row)) end end + + class Unary < Predicate + def eval(row) + operand.eval(row).send(operator) + end + end + + class Not < Unary + def operator; '!' end + end + + class CompoundPredicate < Binary + def eval(row) + eval "operand1.eval(row) #{operator} operand2.eval(row)" + end + end + + class Or < CompoundPredicate + def operator; :or end + end + + class And < CompoundPredicate + def operator; :and end + end + + class GroupedPredicate < Polyadic + def eval(row) + group = additional_operands.inject([]) do |results, operand| + results << operator.new(operand1, operand) + end + group.send(compounder) do |operation| + operation.eval(row) + end + end + end + + class Any < GroupedPredicate + def compounder; :any? end + end + + class All < GroupedPredicate + def compounder; :all? end + end class Equality < Binary def operator; :== end @@ -37,16 +80,20 @@ def operator; :=~ end end class NotMatch < Binary - def operator; :!~ end + def eval(row) + operand1.eval(row) !~ operand2.eval(row) + end end class In < Binary - def operator; :include? end + def eval(row) + operand2.eval(row).include?(operand1.eval(row)) + end end class NotIn < Binary def eval(row) - !(operand1.eval(row).include?(operand2.eval(row))) + !(operand2.eval(row).include?(operand1.eval(row))) end end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 29bc74c6053db..b4591686204db 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -30,11 +30,11 @@ class And < CompoundPredicate def predicate_sql; "AND" end end - class GroupedPredicate < Grouped + class GroupedPredicate < Polyadic def to_sql(formatter = nil) "(" + - operands2.inject([]) { |predicates, operand| - predicates << operator.new(operand1, operand).to_sql + additional_operands.inject([]) { |predicates, operand| + predicates << operator.new(operand1, operand).to_sql(formatter) }.join(" #{predicate_sql} ") + ")" end diff --git a/spec/relations/join_spec.rb b/spec/relations/join_spec.rb index 47e468a9f951b..3894d175e8116 100644 --- a/spec/relations/join_spec.rb +++ b/spec/relations/join_spec.rb @@ -13,6 +13,7 @@ r.attribute :id, Arel::Attributes::Integer r.attribute :owner_id, Arel::Attributes::Integer + r.attribute :name, Arel::Attributes::String r.attribute :age, Arel::Attributes::Integer end end @@ -28,9 +29,10 @@ 8.times do |i| thing_id = owner_id * 8 + i age = 2 * thing_id + name = "Name#{thing_id}" - @thing.insert([thing_id, owner_id, age]) - @expected << Arel::Row.new(@relation, [thing_id, owner_id, age, owner_id]) + @thing.insert([thing_id, owner_id, name, age]) + @expected << Arel::Row.new(@relation, [thing_id, owner_id, name, age, owner_id]) end end end diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index 808ddf1444c57..0381f8759db2e 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -14,7 +14,7 @@ describe "Relation" do before :all do - @expected = (1..20).map { |i| @relation.insert([i, nil, 2 * i]) } + @expected = (1..20).map { |i| @relation.insert([i, "Name#{i}", 2 * i]) } end it_should_behave_like 'A Relation' diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index 1407dddb2aacf..dabbde2dd59d3 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -35,7 +35,7 @@ @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) end - it "finds rows with a not predicate" do + it "finds rows with a noteq predicate" do expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } @relation.where(@relation[:age].noteq(@pivot[@relation[:age]])).should have_rows(expected) end @@ -60,17 +60,40 @@ @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) end - it "finds rows with a matches predicate" + it "finds rows with a matches predicate" do + expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } + @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) + end - it "finds rows with a not matches predicate" + it "finds rows with a not matches predicate" do + expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } + @relation.where(@relation[:name].notmatches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) + end it "finds rows with an in predicate" do - pending - set = @expected[1..(@expected.length/2+1)] - @relation.all(:id.in => set.map { |r| r.id }).should have_resources(set) + expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} + @relation.where(@relation[:age].in(3..20)).should have_rows(expected) end - it "finds rows with a not in predicate" + it "finds rows with a not in predicate" do + expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} + @relation.where(@relation[:age].notin(3..20)).should have_rows(expected) + end + + it "finds rows with a not predicate" do + expected = @expected.select {|r| !(r[@relation[:age]] >= 3 && r[@relation[:age]] <= 20)} + @relation.where(@relation[:age].in(3..20).not).should have_rows(expected) + end + + it "finds rows with a grouped predicate of class Any" do + expected = @expected.select {|r| [2,4,8,16].include?(r[@relation[:age]])} + @relation.where(@relation[:age].in_any([2,4], [8, 16])).should have_rows(expected) + end + + it "finds rows with a grouped predicate of class All" do + expected = @expected.select {|r| r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/} + @relation.where(@relation[:name].matches_all(/Name/, /1/)).should have_rows(expected) + end end describe "#order" do From bd473344000bd538d353e4bc6d20ca8fff2e4704 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 9 Apr 2010 19:52:43 -0400 Subject: [PATCH 0398/1492] Support predicate complements and alternate not syntax (overload BasicObject#!) --- lib/arel/algebra/attributes/attribute.rb | 4 +- lib/arel/algebra/predicates.rb | 144 +++++++++++++++--- lib/arel/engines/memory/predicates.rb | 39 +++-- .../engines/sql/core_extensions/nil_class.rb | 4 + .../engines/sql/core_extensions/object.rb | 4 + lib/arel/engines/sql/predicates.rb | 14 +- lib/arel/engines/sql/primitives.rb | 8 + 7 files changed, 166 insertions(+), 51 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 0266b38db3cf9..640d6facde0ee 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -104,12 +104,12 @@ def #{name}(other) ", :any => " def #{name}_any(*others) - Predicates::Any.new(Predicates::#{klass}, self, *others) + Predicates::Any.build(Predicates::#{klass}, self, *others) end ", :all => " def #{name}_all(*others) - Predicates::All.new(Predicates::#{klass}, self, *others) + Predicates::All.build(Predicates::#{klass}, self, *others) end " } diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index be80f2a987f81..2da37af2e71cb 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -9,32 +9,52 @@ def and(other_predicate) And.new(self, other_predicate) end - def not + def complement Not.new(self) end + + def not + complement + end + + if respond_to?('!') # Nice! We're running Ruby 1.9 and can override the inherited BasicObject#! + def empty? # Need to define empty? to keep Object#blank? from going haywire + false + end + + define_method('!') do + self.complement + end + end end class Polyadic < Predicate - attributes :operator, :operand1, :additional_operands + attributes :predicates - def initialize(operator, operand1, *additional_operands) - @operator = operator - @operand1 = operand1 - @additional_operands = additional_operands.uniq + def initialize(*predicates) + @predicates = predicates + end + + # Build a Polyadic predicate based on: + # * operator - The Predicate subclass that defines the type of operation + # (LessThan, Equality, etc) + # * operand1 - The left-hand operand (normally an Arel::Attribute) + # * additional_operands - All possible right-hand operands + def self.build(operator, operand1, *additional_operands) + new( + *additional_operands.uniq.inject([]) do |predicates, operand| + predicates << operator.new(operand1, operand) + end + ) end def ==(other) - self.class === other and - @operator == operator and - @operand1 == other.operand1 and - same_elements?(@additional_operands, other.additional_operands) + same_elements?(@predicates, other.predicates) end def bind(relation) self.class.new( - operator, - operand1.find_correlate_in(relation), - *additional_operands.map {|o| o.find_correlate_in(relation)} + *predicates.map {|p| p.find_correlate_in(relation)} ) end @@ -49,6 +69,18 @@ def same_elements?(a1, a2) end end + class Any < Polyadic + def complement + All.new(*predicates.map {|p| p.complement}) + end + end + + class All < Polyadic + def complement + Any.new(*predicates.map {|p| p.complement}) + end + end + class Unary < Predicate attributes :operand deriving :initialize, :== @@ -57,6 +89,12 @@ def bind(relation) self.class.new(operand.find_correlate_in(relation)) end end + + class Not < Unary + def complement + operand + end + end class Binary < Predicate attributes :operand1, :operand2 @@ -72,6 +110,20 @@ def bind(relation) self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end end + + class CompoundPredicate < Binary; end + + class And < CompoundPredicate + def complement + Or.new(operand1.complement, operand2.complement) + end + end + + class Or < CompoundPredicate + def complement + And.new(operand1.complement, operand2.complement) + end + end class Equality < Binary def ==(other) @@ -79,16 +131,64 @@ def ==(other) ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end + + def complement + Inequality.new(operand1, operand2) + end end - class Inequality < Equality; end - class GreaterThanOrEqualTo < Binary; end - class GreaterThan < Binary; end - class LessThanOrEqualTo < Binary; end - class LessThan < Binary; end - class Match < Binary; end - class NotMatch < Binary; end - class In < Binary; end - class NotIn < Binary; end + class Inequality < Equality + def complement + Equality.new(operand1, operand2) + end + end + + class GreaterThanOrEqualTo < Binary + def complement + LessThan.new(operand1, operand2) + end + end + + class GreaterThan < Binary + def complement + LessThanOrEqualTo.new(operand1, operand2) + end + end + + class LessThanOrEqualTo < Binary + def complement + GreaterThan.new(operand1, operand2) + end + end + + class LessThan < Binary + def complement + GreaterThanOrEqualTo.new(operand1, operand2) + end + end + + class Match < Binary + def complement + NotMatch.new(operand1, operand2) + end + end + + class NotMatch < Binary + def complement + Match.new(operand1, operand2) + end + end + + class In < Binary + def complement + NotIn.new(operand1, operand2) + end + end + + class NotIn < Binary + def complement + In.new(operand1, operand2) + end + end end end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index c0ee862626036..0e88810e7df20 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -13,41 +13,40 @@ def eval(row) end class Not < Unary - def operator; '!' end - end - - class CompoundPredicate < Binary def eval(row) - eval "operand1.eval(row) #{operator} operand2.eval(row)" + !operand.eval(row) end end - - class Or < CompoundPredicate - def operator; :or end - end - - class And < CompoundPredicate - def operator; :and end - end - class GroupedPredicate < Polyadic + class Polyadic < Predicate def eval(row) - group = additional_operands.inject([]) do |results, operand| - results << operator.new(operand1, operand) - end - group.send(compounder) do |operation| + predicates.send(compounder) do |operation| operation.eval(row) end end end - class Any < GroupedPredicate + class Any < Polyadic def compounder; :any? end end - class All < GroupedPredicate + class All < Polyadic def compounder; :all? end end + + class CompoundPredicate < Binary + def eval(row) + eval "operand1.eval(row) #{operator} operand2.eval(row)" + end + end + + class Or < CompoundPredicate + def operator; :or end + end + + class And < CompoundPredicate + def operator; :and end + end class Equality < Binary def operator; :== end diff --git a/lib/arel/engines/sql/core_extensions/nil_class.rb b/lib/arel/engines/sql/core_extensions/nil_class.rb index 3f70677ba6f06..d4bb0e4c3343a 100644 --- a/lib/arel/engines/sql/core_extensions/nil_class.rb +++ b/lib/arel/engines/sql/core_extensions/nil_class.rb @@ -4,6 +4,10 @@ module NilClassExtensions def equality_predicate_sql 'IS' end + + def inequality_predicate_sql + 'IS NOT' + end def not_predicate_sql 'IS NOT' diff --git a/lib/arel/engines/sql/core_extensions/object.rb b/lib/arel/engines/sql/core_extensions/object.rb index b71ef29fd53aa..5415c84706bc8 100644 --- a/lib/arel/engines/sql/core_extensions/object.rb +++ b/lib/arel/engines/sql/core_extensions/object.rb @@ -8,6 +8,10 @@ def to_sql(formatter) def equality_predicate_sql '=' end + + def inequality_predicate_sql + '!=' + end def not_predicate_sql '!=' diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index b4591686204db..df8700a5007a1 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -30,21 +30,19 @@ class And < CompoundPredicate def predicate_sql; "AND" end end - class GroupedPredicate < Polyadic + class Polyadic < Predicate def to_sql(formatter = nil) "(" + - additional_operands.inject([]) { |predicates, operand| - predicates << operator.new(operand1, operand).to_sql(formatter) - }.join(" #{predicate_sql} ") + + predicates.map {|p| p.to_sql(formatter)}.join(" #{predicate_sql} ") + ")" end end - class Any < GroupedPredicate + class Any < Polyadic def predicate_sql; "OR" end end - class All < GroupedPredicate + class All < Polyadic def predicate_sql; "AND" end end @@ -55,7 +53,9 @@ def predicate_sql end class Inequality < Equality - def predicate_sql; '!=' end + def predicate_sql + operand2.inequality_predicate_sql + end end class GreaterThanOrEqualTo < Binary diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 78e1ed7f0bb1d..41769fa510ad5 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -29,10 +29,18 @@ class Value def inclusion_predicate_sql value.inclusion_predicate_sql end + + def exclusion_predicate_sql + value.exclusion_predicate_sql + end def equality_predicate_sql value.equality_predicate_sql end + + def inequality_predicate_sql + value.inequality_predicate_sql + end def not_predicate_sql value.not_predicate_sql From acdb9ea3036466b6553c85486f8fdfc5909f1275 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Thu, 15 Apr 2010 19:40:30 -0400 Subject: [PATCH 0399/1492] Alternate syntax for Predicate#and and Predicate#or, using & and | --- lib/arel/algebra/predicates.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 2da37af2e71cb..5e17cdd101df4 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -4,11 +4,19 @@ class Predicate def or(other_predicate) Or.new(self, other_predicate) end + + def |(other_predicate) + Or.new(self, other_predicate) + end def and(other_predicate) And.new(self, other_predicate) end + def &(other_predicate) + And.new(self, other_predicate) + end + def complement Not.new(self) end From 5afed6d45def1e72df24679a746cbe96b52c1709 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 24 Apr 2010 08:02:47 -0400 Subject: [PATCH 0400/1492] Inequality shouldn't descend from equality, due to Rails type checks, and resolve conflicts from rebase --- lib/arel/algebra/predicates.rb | 8 +++++++- lib/arel/engines/memory/predicates.rb | 2 +- lib/arel/engines/sql/core_extensions/nil_class.rb | 4 ---- lib/arel/engines/sql/core_extensions/object.rb | 4 ---- lib/arel/engines/sql/predicates.rb | 2 +- lib/arel/engines/sql/primitives.rb | 4 ---- .../sql/unit/predicates/{not_spec.rb => noteq_spec.rb} | 6 +++--- 7 files changed, 12 insertions(+), 18 deletions(-) rename spec/engines/sql/unit/predicates/{not_spec.rb => noteq_spec.rb} (91%) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 5e17cdd101df4..d789c1d8a2b8f 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -145,7 +145,13 @@ def complement end end - class Inequality < Equality + class Inequality < Binary + def ==(other) + Equality === other and + ((operand1 == other.operand1 and operand2 == other.operand2) or + (operand1 == other.operand2 and operand2 == other.operand1)) + end + def complement Equality.new(operand1, operand2) end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index 0e88810e7df20..8b3e5843cc67d 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -52,7 +52,7 @@ class Equality < Binary def operator; :== end end - class Inequality < Equality + class Inequality < Binary def eval(row) operand1.eval(row) != operand2.eval(row) end diff --git a/lib/arel/engines/sql/core_extensions/nil_class.rb b/lib/arel/engines/sql/core_extensions/nil_class.rb index d4bb0e4c3343a..ab990d621161a 100644 --- a/lib/arel/engines/sql/core_extensions/nil_class.rb +++ b/lib/arel/engines/sql/core_extensions/nil_class.rb @@ -9,10 +9,6 @@ def inequality_predicate_sql 'IS NOT' end - def not_predicate_sql - 'IS NOT' - end - NilClass.send(:include, self) end end diff --git a/lib/arel/engines/sql/core_extensions/object.rb b/lib/arel/engines/sql/core_extensions/object.rb index 5415c84706bc8..01c3c5479de8d 100644 --- a/lib/arel/engines/sql/core_extensions/object.rb +++ b/lib/arel/engines/sql/core_extensions/object.rb @@ -13,10 +13,6 @@ def inequality_predicate_sql '!=' end - def not_predicate_sql - '!=' - end - Object.send(:include, self) end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index df8700a5007a1..59b0ab0929830 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -52,7 +52,7 @@ def predicate_sql end end - class Inequality < Equality + class Inequality < Binary def predicate_sql operand2.inequality_predicate_sql end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 41769fa510ad5..15a27b22566b2 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -42,10 +42,6 @@ def inequality_predicate_sql value.inequality_predicate_sql end - def not_predicate_sql - value.not_predicate_sql - end - def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value end diff --git a/spec/engines/sql/unit/predicates/not_spec.rb b/spec/engines/sql/unit/predicates/noteq_spec.rb similarity index 91% rename from spec/engines/sql/unit/predicates/not_spec.rb rename to spec/engines/sql/unit/predicates/noteq_spec.rb index b124d4c80b7bc..ed24627323539 100644 --- a/spec/engines/sql/unit/predicates/not_spec.rb +++ b/spec/engines/sql/unit/predicates/noteq_spec.rb @@ -13,7 +13,7 @@ module Predicates describe '#to_sql' do describe 'when relating to a non-nil value' do it "manufactures a not predicate" do - sql = Not.new(@attribute1, @attribute2).to_sql + sql = Inequality.new(@attribute1, @attribute2).to_sql adapter_is :mysql do sql.should be_like(%Q{`users`.`id` != `photos`.`user_id`}) @@ -35,7 +35,7 @@ module Predicates end it "manufactures an is null predicate" do - sql = Not.new(@attribute1, @nil).to_sql + sql = Inequality.new(@attribute1, @nil).to_sql adapter_is :mysql do sql.should be_like(%Q{`users`.`id` IS NOT NULL}) @@ -54,7 +54,7 @@ module Predicates describe "when relating to a nil Value" do it "manufactures an IS NULL predicate" do value = nil.bind(@relation1) - sql = Not.new(@attribute1, value).to_sql + sql = Inequality.new(@attribute1, value).to_sql adapter_is :mysql do sql.should be_like(%Q{`users`.`id` IS NOT NULL}) From 0f68c734b1642c4960778f8924d2c752717e2790 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 5 May 2010 14:05:56 -0400 Subject: [PATCH 0401/1492] noteq -> not_eq, notmatches -> not_matches, notin -> not_in --- lib/arel/algebra/attributes/attribute.rb | 6 +++--- spec/shared/relation_spec.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 640d6facde0ee..64ea93d227c08 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -84,15 +84,15 @@ def /(other) module Predications methods = { :eq => "Equality", - :noteq => "Inequality", + :not_eq => "Inequality", :lt => "LessThan", :lteq => "LessThanOrEqualTo", :gt => "GreaterThan", :gteq => "GreaterThanOrEqualTo", :matches => "Match", - :notmatches => "NotMatch", + :not_matches => "NotMatch", :in => "In", - :notin => "NotIn" + :not_in => "NotIn" } def self.predication(name, klass) diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index dabbde2dd59d3..0759700d8afc0 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -35,9 +35,9 @@ @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) end - it "finds rows with a noteq predicate" do + it "finds rows with a not eq predicate" do expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } - @relation.where(@relation[:age].noteq(@pivot[@relation[:age]])).should have_rows(expected) + @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]])).should have_rows(expected) end it "finds rows with a less than predicate" do @@ -67,7 +67,7 @@ it "finds rows with a not matches predicate" do expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } - @relation.where(@relation[:name].notmatches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) + @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) end it "finds rows with an in predicate" do @@ -77,7 +77,7 @@ it "finds rows with a not in predicate" do expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} - @relation.where(@relation[:age].notin(3..20)).should have_rows(expected) + @relation.where(@relation[:age].not_in(3..20)).should have_rows(expected) end it "finds rows with a not predicate" do From 6249e5822a105719a09b7ccebc14336f37a8917c Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 5 May 2010 14:12:22 -0400 Subject: [PATCH 0402/1492] Tests for ranges with excluded ends and complements --- spec/engines/sql/unit/predicates/in_spec.rb | 22 +++++++ spec/shared/relation_spec.rb | 65 +++++++++++++++++++-- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/spec/engines/sql/unit/predicates/in_spec.rb b/spec/engines/sql/unit/predicates/in_spec.rb index 5d9b2cdcaac49..f62ee6e829615 100644 --- a/spec/engines/sql/unit/predicates/in_spec.rb +++ b/spec/engines/sql/unit/predicates/in_spec.rb @@ -99,6 +99,28 @@ module Predicates end end end + + describe 'when relating to a range with an excluded end' do + before do + @range = 1...3 + end + + it 'manufactures sql with a >= and <' do + sql = In.new(@attribute, @range).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` >= 1 AND `users`.`id` < 3)}) + end + + adapter_is :oracle do + sql.should be_like(%Q{("USERS"."ID" >= 1 AND "USERS"."ID" < 3)}) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{("users"."id" >= 1 AND "users"."id" < 3)}) + end + end + end describe 'when relating to a time range' do before do diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index 0759700d8afc0..e0c74fc7ee85a 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -35,65 +35,120 @@ @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) end + it "finds rows with an equal to complement predicate" do + expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } + @relation.where(@relation[:age].eq(@pivot[@relation[:age]]).complement).should have_rows(expected) + end + it "finds rows with a not eq predicate" do expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]])).should have_rows(expected) end + + it "finds rows with an not eq complement predicate" do + expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } + @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]]).complement).should have_rows(expected) + end it "finds rows with a less than predicate" do expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } @relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected) end + + it "finds rows with a less than complement predicate" do + expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } + @relation.where(@relation[:age].lt(@pivot[@relation[:age]]).complement).should have_rows(expected) + end it "finds rows with a less than or equal to predicate" do expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } @relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected) end + + it "finds rows with a less than or equal to complement predicate" do + expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } + @relation.where(@relation[:age].lteq(@pivot[@relation[:age]]).complement).should have_rows(expected) + end it "finds rows with a greater than predicate" do expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } @relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected) end + + it "finds rows with a greater than complement predicate" do + expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } + @relation.where(@relation[:age].gt(@pivot[@relation[:age]]).complement).should have_rows(expected) + end it "finds rows with a greater than or equal to predicate" do expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) end + + it "finds rows with a greater than or equal to complement predicate" do + expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } + @relation.where(@relation[:age].gteq(@pivot[@relation[:age]]).complement).should have_rows(expected) + end it "finds rows with a matches predicate" do expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) end + it "finds rows with a matches complement predicate" do + expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } + @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected) + end + it "finds rows with a not matches predicate" do expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) end + + it "finds rows with a not matches complement predicate" do + expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } + @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected) + end it "finds rows with an in predicate" do expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} @relation.where(@relation[:age].in(3..20)).should have_rows(expected) end + it "finds rows with an in complement predicate" do + expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} + @relation.where(@relation[:age].in(3..20).complement).should have_rows(expected) + end + it "finds rows with a not in predicate" do expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} @relation.where(@relation[:age].not_in(3..20)).should have_rows(expected) end - it "finds rows with a not predicate" do - expected = @expected.select {|r| !(r[@relation[:age]] >= 3 && r[@relation[:age]] <= 20)} - @relation.where(@relation[:age].in(3..20).not).should have_rows(expected) + it "finds rows with a not in complement predicate" do + expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} + @relation.where(@relation[:age].not_in(3..20).complement).should have_rows(expected) end - it "finds rows with a grouped predicate of class Any" do + it "finds rows with a polyadic predicate of class Any" do expected = @expected.select {|r| [2,4,8,16].include?(r[@relation[:age]])} @relation.where(@relation[:age].in_any([2,4], [8, 16])).should have_rows(expected) end - it "finds rows with a grouped predicate of class All" do + it "finds rows with a polyadic predicate of class Any complement" do + expected = @expected.select {|r| ![2,4,8,16].include?(r[@relation[:age]])} + @relation.where(@relation[:age].in_any([2,4], [8, 16]).complement).should have_rows(expected) + end + + it "finds rows with a polyadic predicate of class All" do expected = @expected.select {|r| r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/} @relation.where(@relation[:name].matches_all(/Name/, /1/)).should have_rows(expected) end + + it "finds rows with a polyadic predicate of class All complement" do + expected = @expected.select {|r| !(r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/)} + @relation.where(@relation[:name].matches_all(/Name/, /1/).complement).should have_rows(expected) + end end describe "#order" do From b11b75096984279a8a8e751ae9158c32bd2312aa Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 7 May 2010 09:08:41 -0400 Subject: [PATCH 0403/1492] Removal of operator overrides --- lib/arel/algebra/predicates.rb | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index d789c1d8a2b8f..2de867b77995a 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -4,35 +4,17 @@ class Predicate def or(other_predicate) Or.new(self, other_predicate) end - - def |(other_predicate) - Or.new(self, other_predicate) - end def and(other_predicate) And.new(self, other_predicate) end - def &(other_predicate) - And.new(self, other_predicate) - end - def complement Not.new(self) end def not - complement - end - - if respond_to?('!') # Nice! We're running Ruby 1.9 and can override the inherited BasicObject#! - def empty? # Need to define empty? to keep Object#blank? from going haywire - false - end - - define_method('!') do - self.complement - end + self.complement end end From d144b8d5af11c819b8f70a97006998bf89ee926c Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 14 May 2010 10:49:42 -0400 Subject: [PATCH 0404/1492] No longer define predications using metaprogramming. --- lib/arel/algebra/attributes/attribute.rb | 152 +++++++++++++++++------ 1 file changed, 116 insertions(+), 36 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 64ea93d227c08..30e26f75845a6 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -82,44 +82,124 @@ def /(other) include Congruence module Predications - methods = { - :eq => "Equality", - :not_eq => "Inequality", - :lt => "LessThan", - :lteq => "LessThanOrEqualTo", - :gt => "GreaterThan", - :gteq => "GreaterThanOrEqualTo", - :matches => "Match", - :not_matches => "NotMatch", - :in => "In", - :not_in => "NotIn" - } - - def self.predication(name, klass) - methods = { - :operator => " - def #{name}(other) - Predicates::#{klass}.new(self, other) - end - ", - :any => " - def #{name}_any(*others) - Predicates::Any.build(Predicates::#{klass}, self, *others) - end - ", - :all => " - def #{name}_all(*others) - Predicates::All.build(Predicates::#{klass}, self, *others) - end - " - } - [:operator, :any, :all].each do |method_name| - module_eval methods[method_name], __FILE__, __LINE__ - end + def eq(other) + Predicates::Equality.new(self, other) + end + + def eq_any(*others) + Predicates::Any.build(Predicates::Equality, self, *others) + end + + def eq_all(*others) + Predicates::All.build(Predicates::Equality, self, *others) + end + + def not_eq(other) + Predicates::Inequality.new(self, other) + end + + def not_eq_any(*others) + Predicates::Any.build(Predicates::Inequality, self, *others) + end + + def not_eq_all(*others) + Predicates::All.build(Predicates::Inequality, self, *others) + end + + def lt(other) + Predicates::LessThan.new(self, other) + end + + def lt_any(*others) + Predicates::Any.build(Predicates::LessThan, self, *others) + end + + def lt_all(*others) + Predicates::All.build(Predicates::LessThan, self, *others) + end + + def lteq(other) + Predicates::LessThanOrEqualTo.new(self, other) + end + + def lteq_any(*others) + Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others) + end + + def lteq_all(*others) + Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others) + end + + def gt(other) + Predicates::GreaterThan.new(self, other) + end + + def gt_any(*others) + Predicates::Any.build(Predicates::GreaterThan, self, *others) + end + + def gt_all(*others) + Predicates::All.build(Predicates::GreaterThan, self, *others) + end + + def gteq(other) + Predicates::GreaterThanOrEqualTo.new(self, other) + end + + def gteq_any(*others) + Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others) + end + + def gteq_all(*others) + Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others) + end + + def matches(other) + Predicates::Match.new(self, other) + end + + def matches_any(*others) + Predicates::Any.build(Predicates::Match, self, *others) + end + + def matches_all(*others) + Predicates::All.build(Predicates::Match, self, *others) + end + + def not_matches(other) + Predicates::NotMatch.new(self, other) + end + + def not_matches_any(*others) + Predicates::Any.build(Predicates::NotMatch, self, *others) + end + + def not_matches_all(*others) + Predicates::All.build(Predicates::NotMatch, self, *others) + end + + def in(other) + Predicates::In.new(self, other) + end + + def in_any(*others) + Predicates::Any.build(Predicates::In, self, *others) + end + + def in_all(*others) + Predicates::All.build(Predicates::In, self, *others) + end + + def not_in(other) + Predicates::NotIn.new(self, other) + end + + def not_in_any(*others) + Predicates::Any.build(Predicates::NotIn, self, *others) end - methods.each_pair do |method_name, class_name| - predication(method_name, class_name) + def not_in_all(*others) + Predicates::All.build(Predicates::NotIn, self, *others) end end include Predications From 43bfd3fae496a2a859aad0a654a91437357c3450 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 21 May 2010 11:45:12 -0400 Subject: [PATCH 0405/1492] Fix tests to work properly on Ruby 1.9, honor multiple calls to #order in memory engine, and make having clauses behave like where clauses in SQL engine (join with AND, allow multiple calls to having to add predicates) --- .../algebra/relations/operations/having.rb | 18 +++++--- .../engines/memory/relations/operations.rb | 2 +- lib/arel/engines/sql/relations/compiler.rb | 4 +- spec/attributes/time_spec.rb | 4 +- .../integration/joins/cross_engine_spec.rb | 7 ++- spec/engines/sql/unit/predicates/in_spec.rb | 6 +-- .../engines/sql/unit/relations/having_spec.rb | 33 ++++++++++++++ spec/relations/join_spec.rb | 2 +- spec/relations/relation_spec.rb | 2 +- spec/shared/relation_spec.rb | 43 ++++++++++++++++--- 10 files changed, 93 insertions(+), 28 deletions(-) diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index cd1653560954f..0cd86c284e31b 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -1,13 +1,17 @@ module Arel class Having < Compound - attributes :relation, :havings - deriving :== + attributes :relation, :predicates + deriving :== + requires :restricting - def initialize(relation, *havings, &block) - @relation = relation - @havings = (havings + arguments_from_block(relation, &block)) \ - .collect { |g| g.bind(relation) } + def initialize(relation, *predicates, &block) + predicates = [yield(relation)] + predicates if block_given? + @predicates = predicates.map { |p| p.bind(relation) } + @relation = relation + end + + def havings + @havings ||= relation.havings + predicates end end end - diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 55b4dcb6779e7..75777a0c7fef1 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -8,7 +8,7 @@ def eval class Order < Compound def eval unoperated_rows.sort do |row1, row2| - ordering = orderings.detect { |o| o.eval(row1, row2) != 0 } || orderings.last + ordering = orders.detect { |o| o.eval(row1, row2) != 0 } || orders.last ordering.eval(row1, row2) end end diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index cc0deb7c88f1e..374967b7bebab 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -12,9 +12,9 @@ def select_sql "SELECT #{select_clauses.join(', ')}", "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), + ("WHERE #{where_clauses.join(' AND ')}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), + ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ), ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) engine.add_limit_offset!(query,{ :limit => taken, :offset => skipped }) if taken || skipped query << " #{locked}" unless locked.blank? diff --git a/spec/attributes/time_spec.rb b/spec/attributes/time_spec.rb index fcbe4f58e54f0..044b98d6ec859 100644 --- a/spec/attributes/time_spec.rb +++ b/spec/attributes/time_spec.rb @@ -16,7 +16,9 @@ def type_cast(val) end describe "#type_cast" do - it "works" + it "works" do + pending + end end end end \ No newline at end of file diff --git a/spec/engines/memory/integration/joins/cross_engine_spec.rb b/spec/engines/memory/integration/joins/cross_engine_spec.rb index 606f3154c7d74..5dc1a6cb99514 100644 --- a/spec/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/engines/memory/integration/joins/cross_engine_spec.rb @@ -13,10 +13,9 @@ module Arel @photos.insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) @photos.insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) # Oracle adapter returns database integers as Ruby integers and not strings - @adapter_returns_integer = false - adapter_is :oracle do - @adapter_returns_integer = true - end + # So does the FFI sqlite library + db_int_return = @photos.project(@photos[:camera_id]).first.tuple.first + @adapter_returns_integer = db_int_return.is_a?(String) ? false : true end describe 'when the in memory relation is on the left' do diff --git a/spec/engines/sql/unit/predicates/in_spec.rb b/spec/engines/sql/unit/predicates/in_spec.rb index f62ee6e829615..be311f9f836a3 100644 --- a/spec/engines/sql/unit/predicates/in_spec.rb +++ b/spec/engines/sql/unit/predicates/in_spec.rb @@ -137,11 +137,7 @@ module Predicates end adapter_is :sqlite3 do - if RUBY_VERSION < '1.9' - sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00.000000' AND '2010-02-01 00:00:00.000000'}) - else - sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'}) - end + sql.should match(/"developers"."created_at" BETWEEN '2010-01-01 00:00:00(?:\.\d+)' AND '2010-02-01 00:00:00(?:\.\d+)'/) end adapter_is :postgresql do diff --git a/spec/engines/sql/unit/relations/having_spec.rb b/spec/engines/sql/unit/relations/having_spec.rb index fe6f3cc5201ca..a7f2f0da96937 100644 --- a/spec/engines/sql/unit/relations/having_spec.rb +++ b/spec/engines/sql/unit/relations/having_spec.rb @@ -39,6 +39,39 @@ module Arel end end end + + describe 'when given two predicates' do + it "manufactures sql with where clause conditions joined by AND" do + sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000", "MAX(salary) < 10000").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department`, `developers`.`created_at` + FROM `developers` + GROUP BY `developers`.`department` + HAVING MIN(salary) > 1000 AND MAX(salary) < 10000 + }) + end + + adapter_is :oracle do + sql.should be_like(%Q{ + SELECT "DEVELOPERS"."ID", "DEVELOPERS"."NAME", "DEVELOPERS"."SALARY", "DEVELOPERS"."DEPARTMENT", "DEVELOPERS"."CREATED_AT" + FROM "DEVELOPERS" + GROUP BY "DEVELOPERS"."DEPARTMENT" + HAVING MIN(salary) > 1000 AND MAX(salary) < 10000 + }) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{ + SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department", "developers"."created_at" + FROM "developers" + GROUP BY "developers"."department" + HAVING MIN(salary) > 1000 AND MAX(salary) < 10000 + }) + end + end + end end end end diff --git a/spec/relations/join_spec.rb b/spec/relations/join_spec.rb index 3894d175e8116..b5ead51053ec2 100644 --- a/spec/relations/join_spec.rb +++ b/spec/relations/join_spec.rb @@ -29,7 +29,7 @@ 8.times do |i| thing_id = owner_id * 8 + i age = 2 * thing_id - name = "Name#{thing_id}" + name = "Name #{thing_id % 6}" @thing.insert([thing_id, owner_id, name, age]) @expected << Arel::Row.new(@relation, [thing_id, owner_id, name, age, owner_id]) diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index 0381f8759db2e..b5b73e2205ba5 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -14,7 +14,7 @@ describe "Relation" do before :all do - @expected = (1..20).map { |i| @relation.insert([i, "Name#{i}", 2 * i]) } + @expected = (1..20).map { |i| @relation.insert([i, "Name #{i % 6}", 2 * i]) } end it_should_behave_like 'A Relation' diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index e0c74fc7ee85a..b49e79f13d77a 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -154,25 +154,56 @@ describe "#order" do describe "by one attribute" do before :all do - @expected.map! { |r| r[@relation[:age]] } - @expected.sort! + @expected.sort! { |a, b| a[@relation[:age]] <=> b[@relation[:age]]}.map! {|e| e[@relation[:id]]} end it "can be specified as ascending order" do actual = [] - @relation.order(@relation[:age].asc).each { |r| actual << r[@relation[:age]] } + @relation.order(@relation[:age].asc).each { |r| actual << r[@relation[:id]] } actual.should == @expected end it "can be specified as descending order" do actual = [] - @relation.order(@relation[:age].desc).each { |r| actual << r[@relation[:age]] } + @relation.order(@relation[:age].desc).each { |r| actual << r[@relation[:id]] } actual.should == @expected.reverse end end - describe "by two attributes" do - it "works" + describe "by two attributes in two separate calls to #order" do + before :all do + @expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]} + end + + it "can be specified as ascending order" do + actual = [] + @relation.order(@relation[:age].asc).order(@relation[:name].asc).each { |r| actual << r[@relation[:id]] } + actual.should == @expected + end + + it "can be specified as descending order" do + actual = [] + @relation.order(@relation[:age].desc).order(@relation[:name].desc).each { |r| actual << r[@relation[:id]] } + actual.should == @expected.reverse + end + end + + describe "by two attributes in one call to #order" do + before :all do + @expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]} + end + + it "can be specified as ascending order in one call to #order" do + actual = [] + @relation.order(@relation[:name].asc, @relation[:age].asc).each { |r| actual << r[@relation[:id]] } + actual.should == @expected + end + + it "can be specified as descending order in one call to #order" do + actual = [] + @relation.order(@relation[:name].desc, @relation[:age].desc).each { |r| actual << r[@relation[:id]] } + actual.should == @expected.reverse + end end end From 2ee391231842eec5ce75517c0b24576c1e2a3261 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Wed, 26 May 2010 18:15:21 -0400 Subject: [PATCH 0406/1492] Whitespace fixes --- lib/arel/algebra/attributes.rb | 2 +- lib/arel/algebra/attributes/attribute.rb | 58 +++++++++---------- lib/arel/algebra/attributes/integer.rb | 2 +- lib/arel/algebra/header.rb | 2 +- lib/arel/algebra/predicates.rb | 52 ++++++++--------- lib/arel/engines/memory/predicates.rb | 16 ++--- lib/arel/engines/sql/attributes.rb | 2 +- lib/arel/engines/sql/core_extensions/array.rb | 2 +- .../engines/sql/core_extensions/nil_class.rb | 2 +- .../engines/sql/core_extensions/object.rb | 2 +- lib/arel/engines/sql/core_extensions/range.rb | 2 +- lib/arel/engines/sql/predicates.rb | 18 +++--- lib/arel/engines/sql/primitives.rb | 4 +- lib/arel/engines/sql/relations/relation.rb | 2 +- spec/attributes/boolean_spec.rb | 2 +- spec/attributes/float_spec.rb | 2 +- spec/attributes/header_spec.rb | 2 +- spec/attributes/integer_spec.rb | 2 +- spec/attributes/string_spec.rb | 2 +- spec/attributes/time_spec.rb | 2 +- spec/engines/sql/unit/predicates/in_spec.rb | 2 +- spec/relations/join_spec.rb | 2 +- spec/relations/relation_spec.rb | 2 +- spec/shared/relation_spec.rb | 32 +++++----- spec/support/check.rb | 2 +- spec/support/connections/mysql_connection.rb | 2 +- spec/support/connections/oracle_connection.rb | 2 +- .../connections/postgresql_connection.rb | 2 +- spec/support/guards.rb | 2 +- spec/support/matchers.rb | 2 +- spec/support/matchers/have_rows.rb | 2 +- spec/support/model.rb | 2 +- 32 files changed, 116 insertions(+), 116 deletions(-) diff --git a/lib/arel/algebra/attributes.rb b/lib/arel/algebra/attributes.rb index 98302b6b18d80..6ce65fe132a36 100644 --- a/lib/arel/algebra/attributes.rb +++ b/lib/arel/algebra/attributes.rb @@ -4,4 +4,4 @@ require "arel/algebra/attributes/float" require "arel/algebra/attributes/integer" require "arel/algebra/attributes/string" -require "arel/algebra/attributes/time" \ No newline at end of file +require "arel/algebra/attributes/time" diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 30e26f75845a6..faa6c068d57f9 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -85,119 +85,119 @@ module Predications def eq(other) Predicates::Equality.new(self, other) end - + def eq_any(*others) Predicates::Any.build(Predicates::Equality, self, *others) end - + def eq_all(*others) Predicates::All.build(Predicates::Equality, self, *others) end - + def not_eq(other) Predicates::Inequality.new(self, other) end - + def not_eq_any(*others) Predicates::Any.build(Predicates::Inequality, self, *others) end - + def not_eq_all(*others) Predicates::All.build(Predicates::Inequality, self, *others) end - + def lt(other) Predicates::LessThan.new(self, other) end - + def lt_any(*others) Predicates::Any.build(Predicates::LessThan, self, *others) end - + def lt_all(*others) Predicates::All.build(Predicates::LessThan, self, *others) end - + def lteq(other) Predicates::LessThanOrEqualTo.new(self, other) end - + def lteq_any(*others) Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others) end - + def lteq_all(*others) Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others) end - + def gt(other) Predicates::GreaterThan.new(self, other) end - + def gt_any(*others) Predicates::Any.build(Predicates::GreaterThan, self, *others) end - + def gt_all(*others) Predicates::All.build(Predicates::GreaterThan, self, *others) end - + def gteq(other) Predicates::GreaterThanOrEqualTo.new(self, other) end - + def gteq_any(*others) Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others) end - + def gteq_all(*others) Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others) end - + def matches(other) Predicates::Match.new(self, other) end - + def matches_any(*others) Predicates::Any.build(Predicates::Match, self, *others) end - + def matches_all(*others) Predicates::All.build(Predicates::Match, self, *others) end - + def not_matches(other) Predicates::NotMatch.new(self, other) end - + def not_matches_any(*others) Predicates::Any.build(Predicates::NotMatch, self, *others) end - + def not_matches_all(*others) Predicates::All.build(Predicates::NotMatch, self, *others) end - + def in(other) Predicates::In.new(self, other) end - + def in_any(*others) Predicates::Any.build(Predicates::In, self, *others) end - + def in_all(*others) Predicates::All.build(Predicates::In, self, *others) end - + def not_in(other) Predicates::NotIn.new(self, other) end - + def not_in_any(*others) Predicates::Any.build(Predicates::NotIn, self, *others) end - + def not_in_all(*others) Predicates::All.build(Predicates::NotIn, self, *others) end diff --git a/lib/arel/algebra/attributes/integer.rb b/lib/arel/algebra/attributes/integer.rb index 9a564565ff04d..8d4f572989bde 100644 --- a/lib/arel/algebra/attributes/integer.rb +++ b/lib/arel/algebra/attributes/integer.rb @@ -7,4 +7,4 @@ def type_cast(val) end end end - \ No newline at end of file + diff --git a/lib/arel/algebra/header.rb b/lib/arel/algebra/header.rb index 3b74d31684f62..9954da5b65271 100644 --- a/lib/arel/algebra/header.rb +++ b/lib/arel/algebra/header.rb @@ -64,4 +64,4 @@ def find_by_attribute(attr) end end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 2de867b77995a..5f780f32ff5ff 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -8,23 +8,23 @@ def or(other_predicate) def and(other_predicate) And.new(self, other_predicate) end - + def complement Not.new(self) end - + def not self.complement end end - + class Polyadic < Predicate attributes :predicates - + def initialize(*predicates) @predicates = predicates end - + # Build a Polyadic predicate based on: # * operator - The Predicate subclass that defines the type of operation # (LessThan, Equality, etc) @@ -37,19 +37,19 @@ def self.build(operator, operand1, *additional_operands) end ) end - + def ==(other) same_elements?(@predicates, other.predicates) end - + def bind(relation) self.class.new( *predicates.map {|p| p.find_correlate_in(relation)} ) end - + private - + def same_elements?(a1, a2) [:select, :inject, :size].each do |m| return false unless [a1, a2].each {|a| a.respond_to?(m) } @@ -58,28 +58,28 @@ def same_elements?(a1, a2) a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } end end - + class Any < Polyadic def complement All.new(*predicates.map {|p| p.complement}) end end - + class All < Polyadic def complement Any.new(*predicates.map {|p| p.complement}) end end - + class Unary < Predicate attributes :operand deriving :initialize, :== - + def bind(relation) self.class.new(operand.find_correlate_in(relation)) end end - + class Not < Unary def complement operand @@ -100,7 +100,7 @@ def bind(relation) self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end end - + class CompoundPredicate < Binary; end class And < CompoundPredicate @@ -108,7 +108,7 @@ def complement Or.new(operand1.complement, operand2.complement) end end - + class Or < CompoundPredicate def complement And.new(operand1.complement, operand2.complement) @@ -121,7 +121,7 @@ def ==(other) ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end - + def complement Inequality.new(operand1, operand2) end @@ -133,54 +133,54 @@ def ==(other) ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end - + def complement Equality.new(operand1, operand2) end end - + class GreaterThanOrEqualTo < Binary def complement LessThan.new(operand1, operand2) end end - + class GreaterThan < Binary def complement LessThanOrEqualTo.new(operand1, operand2) end end - + class LessThanOrEqualTo < Binary def complement GreaterThan.new(operand1, operand2) end end - + class LessThan < Binary def complement GreaterThanOrEqualTo.new(operand1, operand2) end end - + class Match < Binary def complement NotMatch.new(operand1, operand2) end end - + class NotMatch < Binary def complement Match.new(operand1, operand2) end end - + class In < Binary def complement NotIn.new(operand1, operand2) end end - + class NotIn < Binary def complement In.new(operand1, operand2) diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index 8b3e5843cc67d..cca6739424ef5 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -5,19 +5,19 @@ def eval(row) operand1.eval(row).send(operator, operand2.eval(row)) end end - + class Unary < Predicate def eval(row) operand.eval(row).send(operator) end end - + class Not < Unary def eval(row) !operand.eval(row) end end - + class Polyadic < Predicate def eval(row) predicates.send(compounder) do |operation| @@ -25,15 +25,15 @@ def eval(row) end end end - + class Any < Polyadic def compounder; :any? end end - + class All < Polyadic def compounder; :all? end end - + class CompoundPredicate < Binary def eval(row) eval "operand1.eval(row) #{operator} operand2.eval(row)" @@ -77,7 +77,7 @@ def operator; :< end class Match < Binary def operator; :=~ end end - + class NotMatch < Binary def eval(row) operand1.eval(row) !~ operand2.eval(row) @@ -89,7 +89,7 @@ def eval(row) operand2.eval(row).include?(operand1.eval(row)) end end - + class NotIn < Binary def eval(row) !(operand2.eval(row).include?(operand1.eval(row))) diff --git a/lib/arel/engines/sql/attributes.rb b/lib/arel/engines/sql/attributes.rb index 2d315d53fc2be..50cc8021621c1 100644 --- a/lib/arel/engines/sql/attributes.rb +++ b/lib/arel/engines/sql/attributes.rb @@ -37,4 +37,4 @@ class #{klass} < Arel::Attributes::#{klass} end end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/core_extensions/array.rb b/lib/arel/engines/sql/core_extensions/array.rb index 412479dc8306c..05a1bb774c1cd 100644 --- a/lib/arel/engines/sql/core_extensions/array.rb +++ b/lib/arel/engines/sql/core_extensions/array.rb @@ -12,7 +12,7 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "IN" end - + def exclusion_predicate_sql "NOT IN" end diff --git a/lib/arel/engines/sql/core_extensions/nil_class.rb b/lib/arel/engines/sql/core_extensions/nil_class.rb index ab990d621161a..9f060ff36e7ac 100644 --- a/lib/arel/engines/sql/core_extensions/nil_class.rb +++ b/lib/arel/engines/sql/core_extensions/nil_class.rb @@ -4,7 +4,7 @@ module NilClassExtensions def equality_predicate_sql 'IS' end - + def inequality_predicate_sql 'IS NOT' end diff --git a/lib/arel/engines/sql/core_extensions/object.rb b/lib/arel/engines/sql/core_extensions/object.rb index 01c3c5479de8d..d2fda0fe5fea6 100644 --- a/lib/arel/engines/sql/core_extensions/object.rb +++ b/lib/arel/engines/sql/core_extensions/object.rb @@ -8,7 +8,7 @@ def to_sql(formatter) def equality_predicate_sql '=' end - + def inequality_predicate_sql '!=' end diff --git a/lib/arel/engines/sql/core_extensions/range.rb b/lib/arel/engines/sql/core_extensions/range.rb index b5b1534e48a16..c711ffdde6868 100644 --- a/lib/arel/engines/sql/core_extensions/range.rb +++ b/lib/arel/engines/sql/core_extensions/range.rb @@ -8,7 +8,7 @@ def to_sql(formatter = nil) def inclusion_predicate_sql "BETWEEN" end - + def exclusion_predicate_sql "NOT BETWEEN" end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 59b0ab0929830..93d2a2f619599 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -5,13 +5,13 @@ def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end end - + class Unary < Predicate def to_sql(formatter = nil) "#{predicate_sql} (#{operand.to_sql(formatter)})" end end - + class Not < Unary def predicate_sql; "NOT" end end @@ -29,19 +29,19 @@ def predicate_sql; "OR" end class And < CompoundPredicate def predicate_sql; "AND" end end - + class Polyadic < Predicate def to_sql(formatter = nil) - "(" + + "(" + predicates.map {|p| p.to_sql(formatter)}.join(" #{predicate_sql} ") + ")" end end - + class Any < Polyadic def predicate_sql; "OR" end end - + class All < Polyadic def predicate_sql; "AND" end end @@ -77,7 +77,7 @@ def predicate_sql; '<' end class Match < Binary def predicate_sql; 'LIKE' end end - + class NotMatch < Binary def predicate_sql; 'NOT LIKE' end end @@ -92,10 +92,10 @@ def to_sql(formatter = nil) super end end - + def predicate_sql; operand2.inclusion_predicate_sql end end - + class NotIn < Binary def predicate_sql; operand2.exclusion_predicate_sql end end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 15a27b22566b2..1b215d2b5467a 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -29,7 +29,7 @@ class Value def inclusion_predicate_sql value.inclusion_predicate_sql end - + def exclusion_predicate_sql value.exclusion_predicate_sql end @@ -37,7 +37,7 @@ def exclusion_predicate_sql def equality_predicate_sql value.equality_predicate_sql end - + def inequality_predicate_sql value.inequality_predicate_sql end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index fc353fe0c82b0..2136f85e5a52b 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -21,7 +21,7 @@ def christener def inclusion_predicate_sql "IN" end - + def exclusion_predicate_sql "NOT IN" end diff --git a/spec/attributes/boolean_spec.rb b/spec/attributes/boolean_spec.rb index bb7eeb886db26..12b243e828e80 100644 --- a/spec/attributes/boolean_spec.rb +++ b/spec/attributes/boolean_spec.rb @@ -54,4 +54,4 @@ def type_cast(val) end end end -end \ No newline at end of file +end diff --git a/spec/attributes/float_spec.rb b/spec/attributes/float_spec.rb index 3d8acbde7b63d..3a9a8debbcdfc 100644 --- a/spec/attributes/float_spec.rb +++ b/spec/attributes/float_spec.rb @@ -116,4 +116,4 @@ def type_cast(val) end end end -end \ No newline at end of file +end diff --git a/spec/attributes/header_spec.rb b/spec/attributes/header_spec.rb index 8fb4007003f65..51cba93df31bb 100644 --- a/spec/attributes/header_spec.rb +++ b/spec/attributes/header_spec.rb @@ -39,4 +39,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/attributes/integer_spec.rb b/spec/attributes/integer_spec.rb index 611bbf2b24584..59b7afb2b4c26 100644 --- a/spec/attributes/integer_spec.rb +++ b/spec/attributes/integer_spec.rb @@ -116,4 +116,4 @@ def type_cast(val) end end end -end \ No newline at end of file +end diff --git a/spec/attributes/string_spec.rb b/spec/attributes/string_spec.rb index f6d65dd045144..487d82249dd92 100644 --- a/spec/attributes/string_spec.rb +++ b/spec/attributes/string_spec.rb @@ -40,4 +40,4 @@ def type_cast(val) end end end -end \ No newline at end of file +end diff --git a/spec/attributes/time_spec.rb b/spec/attributes/time_spec.rb index fcbe4f58e54f0..8cee574c5153a 100644 --- a/spec/attributes/time_spec.rb +++ b/spec/attributes/time_spec.rb @@ -19,4 +19,4 @@ def type_cast(val) it "works" end end -end \ No newline at end of file +end diff --git a/spec/engines/sql/unit/predicates/in_spec.rb b/spec/engines/sql/unit/predicates/in_spec.rb index f62ee6e829615..45aa12bac6cdd 100644 --- a/spec/engines/sql/unit/predicates/in_spec.rb +++ b/spec/engines/sql/unit/predicates/in_spec.rb @@ -99,7 +99,7 @@ module Predicates end end end - + describe 'when relating to a range with an excluded end' do before do @range = 1...3 diff --git a/spec/relations/join_spec.rb b/spec/relations/join_spec.rb index 3894d175e8116..d980451ca9d8c 100644 --- a/spec/relations/join_spec.rb +++ b/spec/relations/join_spec.rb @@ -39,4 +39,4 @@ it_should_behave_like 'A Relation' end -end \ No newline at end of file +end diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb index 0381f8759db2e..c660ac3597e6d 100644 --- a/spec/relations/relation_spec.rb +++ b/spec/relations/relation_spec.rb @@ -28,4 +28,4 @@ end end end -end \ No newline at end of file +end diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index e0c74fc7ee85a..8fd478d05f5d5 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -44,7 +44,7 @@ expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]])).should have_rows(expected) end - + it "finds rows with an not eq complement predicate" do expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]]).complement).should have_rows(expected) @@ -54,7 +54,7 @@ expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } @relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected) end - + it "finds rows with a less than complement predicate" do expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } @relation.where(@relation[:age].lt(@pivot[@relation[:age]]).complement).should have_rows(expected) @@ -64,7 +64,7 @@ expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } @relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected) end - + it "finds rows with a less than or equal to complement predicate" do expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } @relation.where(@relation[:age].lteq(@pivot[@relation[:age]]).complement).should have_rows(expected) @@ -74,7 +74,7 @@ expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } @relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected) end - + it "finds rows with a greater than complement predicate" do expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } @relation.where(@relation[:age].gt(@pivot[@relation[:age]]).complement).should have_rows(expected) @@ -84,7 +84,7 @@ expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) end - + it "finds rows with a greater than or equal to complement predicate" do expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } @relation.where(@relation[:age].gteq(@pivot[@relation[:age]]).complement).should have_rows(expected) @@ -94,17 +94,17 @@ expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) end - + it "finds rows with a matches complement predicate" do expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected) end - + it "finds rows with a not matches predicate" do expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) end - + it "finds rows with a not matches complement predicate" do expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected) @@ -114,37 +114,37 @@ expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} @relation.where(@relation[:age].in(3..20)).should have_rows(expected) end - + it "finds rows with an in complement predicate" do expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} @relation.where(@relation[:age].in(3..20).complement).should have_rows(expected) end - + it "finds rows with a not in predicate" do expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} @relation.where(@relation[:age].not_in(3..20)).should have_rows(expected) end - + it "finds rows with a not in complement predicate" do expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} @relation.where(@relation[:age].not_in(3..20).complement).should have_rows(expected) end - + it "finds rows with a polyadic predicate of class Any" do expected = @expected.select {|r| [2,4,8,16].include?(r[@relation[:age]])} @relation.where(@relation[:age].in_any([2,4], [8, 16])).should have_rows(expected) end - + it "finds rows with a polyadic predicate of class Any complement" do expected = @expected.select {|r| ![2,4,8,16].include?(r[@relation[:age]])} @relation.where(@relation[:age].in_any([2,4], [8, 16]).complement).should have_rows(expected) end - + it "finds rows with a polyadic predicate of class All" do expected = @expected.select {|r| r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/} @relation.where(@relation[:name].matches_all(/Name/, /1/)).should have_rows(expected) end - + it "finds rows with a polyadic predicate of class All complement" do expected = @expected.select {|r| !(r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/)} @relation.where(@relation[:name].matches_all(/Name/, /1/).complement).should have_rows(expected) @@ -221,4 +221,4 @@ actual.should == expected[3..-1] end end -end \ No newline at end of file +end diff --git a/spec/support/check.rb b/spec/support/check.rb index 0a89349629d18..c9adce420cefc 100644 --- a/spec/support/check.rb +++ b/spec/support/check.rb @@ -3,4 +3,4 @@ module Check # See: https://rspec.lighthouseapp.com/projects/5645/tickets/504 def check(*args) end -end \ No newline at end of file +end diff --git a/spec/support/connections/mysql_connection.rb b/spec/support/connections/mysql_connection.rb index de9d05c2ceb86..c924c27080cd5 100644 --- a/spec/support/connections/mysql_connection.rb +++ b/spec/support/connections/mysql_connection.rb @@ -11,4 +11,4 @@ :encoding => 'utf8', :database => 'arel_unit', } -} \ No newline at end of file +} diff --git a/spec/support/connections/oracle_connection.rb b/spec/support/connections/oracle_connection.rb index c28602b1341ee..309d127071304 100644 --- a/spec/support/connections/oracle_connection.rb +++ b/spec/support/connections/oracle_connection.rb @@ -14,4 +14,4 @@ :password => 'arel_unit', :database => 'orcl', } -} \ No newline at end of file +} diff --git a/spec/support/connections/postgresql_connection.rb b/spec/support/connections/postgresql_connection.rb index 34d304efa9eed..692533d10d184 100644 --- a/spec/support/connections/postgresql_connection.rb +++ b/spec/support/connections/postgresql_connection.rb @@ -10,4 +10,4 @@ :encoding => 'utf8', :database => 'arel_unit', } -} \ No newline at end of file +} diff --git a/spec/support/guards.rb b/spec/support/guards.rb index cfa4b7b79a989..db6075f73ad43 100644 --- a/spec/support/guards.rb +++ b/spec/support/guards.rb @@ -25,4 +25,4 @@ def verify_adapter_name(name) def valid_adapters %w[mysql postgresql sqlite3 oracle] end -end \ No newline at end of file +end diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb index 8cef5d947e6d9..5f51a686336bb 100644 --- a/spec/support/matchers.rb +++ b/spec/support/matchers.rb @@ -1,4 +1,4 @@ require "support/matchers/be_like" require "support/matchers/disambiguate_attributes" require "support/matchers/hash_the_same_as" -require "support/matchers/have_rows" \ No newline at end of file +require "support/matchers/have_rows" diff --git a/spec/support/matchers/have_rows.rb b/spec/support/matchers/have_rows.rb index 7d9c6a20c9e7d..e476d25f4fa0f 100644 --- a/spec/support/matchers/have_rows.rb +++ b/spec/support/matchers/have_rows.rb @@ -15,4 +15,4 @@ def have_rows(expected) found.compact.length == expected.length && got.compact.length == expected.length end end -end \ No newline at end of file +end diff --git a/spec/support/model.rb b/spec/support/model.rb index be692e53ec56b..d5be35cbba98f 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -59,4 +59,4 @@ def insert(row) insert.record end end -end \ No newline at end of file +end From a9b3581007a3609c21c1093ab3a07bf8d6408031 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Thu, 27 May 2010 08:24:26 -0400 Subject: [PATCH 0407/1492] Whitespace cleanup --- spec/engines/sql/unit/relations/having_spec.rb | 2 +- spec/shared/relation_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/engines/sql/unit/relations/having_spec.rb b/spec/engines/sql/unit/relations/having_spec.rb index a7f2f0da96937..931e8d0a06806 100644 --- a/spec/engines/sql/unit/relations/having_spec.rb +++ b/spec/engines/sql/unit/relations/having_spec.rb @@ -39,7 +39,7 @@ module Arel end end end - + describe 'when given two predicates' do it "manufactures sql with where clause conditions joined by AND" do sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000", "MAX(salary) < 10000").to_sql diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb index d6d0de1da464d..a5a22edb7d717 100644 --- a/spec/shared/relation_spec.rb +++ b/spec/shared/relation_spec.rb @@ -187,12 +187,12 @@ actual.should == @expected.reverse end end - + describe "by two attributes in one call to #order" do before :all do @expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]} end - + it "can be specified as ascending order in one call to #order" do actual = [] @relation.order(@relation[:name].asc, @relation[:age].asc).each { |r| actual << r[@relation[:id]] } From 8a3327526fab96745850606a45f7ccf5ad9e868a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Mon, 31 May 2010 10:47:24 -0300 Subject: [PATCH 0408/1492] Remove unnecessary code since AS beta1 is out. --- lib/arel/algebra/core_extensions/object.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/lib/arel/algebra/core_extensions/object.rb b/lib/arel/algebra/core_extensions/object.rb index 82fa28546c0fc..85a4d951a4f23 100644 --- a/lib/arel/algebra/core_extensions/object.rb +++ b/lib/arel/algebra/core_extensions/object.rb @@ -12,19 +12,6 @@ def let yield(self) end - # TODO remove this when ActiveSupport beta1 is out. - # Returns the object's singleton class. - def singleton_class - class << self - self - end - end unless respond_to?(:singleton_class) - - # class_eval on an object acts like singleton_class_eval. - def class_eval(*args, &block) - singleton_class.class_eval(*args, &block) - end - Object.send(:include, self) end end From bbddfe7641bf1f81ba47bd3deaa56edd13d5083c Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Tue, 8 Jun 2010 14:48:31 -0400 Subject: [PATCH 0409/1492] Bump version to 0.4.0 --- arel.gemspec | 2 +- lib/arel/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 8091bec4d4a07..12df4754fd4fb 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -5,7 +5,7 @@ Gem::Specification.new do |s| s.name = "arel" s.version = Arel::VERSION s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-03-25} + s.date = %q{2010-06-08} s.email = "bryan@brynary.com" s.homepage = "http://github.com/brynary/arel" s.summary = "Arel is a relational algebra engine for Ruby" diff --git a/lib/arel/version.rb b/lib/arel/version.rb index 0e1758947f239..ddf477004d493 100644 --- a/lib/arel/version.rb +++ b/lib/arel/version.rb @@ -1,3 +1,3 @@ module Arel - VERSION = "0.3.3" unless defined?(Arel::VERSION) + VERSION = "0.4.0" unless defined?(Arel::VERSION) end From 0ffaa8d4628702bc44a1302fb9a37b92a52f9a22 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sat, 19 Jun 2010 16:02:51 +0300 Subject: [PATCH 0410/1492] use subquery to get first records if DISTINCT is used (in Oracle compiler) --- lib/arel/engines/sql/compilers/oracle_compiler.rb | 4 ++-- spec/engines/sql/unit/relations/take_spec.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/compilers/oracle_compiler.rb b/lib/arel/engines/sql/compilers/oracle_compiler.rb index ce575c21700dc..560022445a268 100644 --- a/lib/arel/engines/sql/compilers/oracle_compiler.rb +++ b/lib/arel/engines/sql/compilers/oracle_compiler.rb @@ -5,9 +5,9 @@ class OracleCompiler < GenericCompiler def select_sql where_clauses_array = where_clauses if limit_or_offset = !taken.blank? || !skipped.blank? - # if need to select first records without ORDER BY and GROUP BY + # if need to select first records without ORDER BY and GROUP BY and without DISTINCT # then can use simple ROWNUM in WHERE clause - if skipped.blank? && groupings.blank? && orders.blank? + if skipped.blank? && groupings.blank? && orders.blank? && select_clauses[0] !~ /^DISTINCT / where_clauses_array << "ROWNUM <= #{taken}" if !taken.blank? && skipped.blank? && groupings.blank? && orders.blank? limit_or_offset = false end diff --git a/spec/engines/sql/unit/relations/take_spec.rb b/spec/engines/sql/unit/relations/take_spec.rb index 9f2967a0bd373..cc3c3dbbf52bb 100644 --- a/spec/engines/sql/unit/relations/take_spec.rb +++ b/spec/engines/sql/unit/relations/take_spec.rb @@ -34,6 +34,14 @@ module Arel ORDER BY "USERS"."ID" ASC) where rownum <= 4 }) + + sql_with_distinct = Take.new(@relation.project('DISTINCT "USERS"."ID"'), @taken).to_sql + sql_with_distinct.should be_like(%Q{ + select * from + (SELECT DISTINCT "USERS"."ID" + FROM "USERS") + where rownum <= 4 + }) end adapter_is_not :mysql, :oracle do From f68115023ecc02d21d982661ba806acec095842d Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sat, 19 Jun 2010 16:11:21 +0300 Subject: [PATCH 0411/1492] fixed having clause for Oracle compiler --- lib/arel/engines/sql/compilers/oracle_compiler.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/compilers/oracle_compiler.rb b/lib/arel/engines/sql/compilers/oracle_compiler.rb index 560022445a268..66a91cecb5fb9 100644 --- a/lib/arel/engines/sql/compilers/oracle_compiler.rb +++ b/lib/arel/engines/sql/compilers/oracle_compiler.rb @@ -33,9 +33,9 @@ def select_sql "SELECT #{select_attributes_string}", "FROM #{from_clauses}", (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses_array.join(" AND ")}" unless where_clauses_array.blank? ), + ("WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), + ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ), ("ORDER BY #{order_clauses_array.join(', ')}" unless order_clauses_array.blank? ) # Use existing method from oracle_enhanced adapter to implement limit and offset using subqueries From 71e92992e66f461acaabc3ac2f3ec6480167962e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 23 Jun 2010 11:54:48 -0300 Subject: [PATCH 0412/1492] Add support for counting rows with conditions or limit using a subquery. --- lib/arel/engines/sql/relations/compiler.rb | 23 +++++++++++++++----- spec/engines/sql/unit/relations/take_spec.rb | 18 +++++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 374967b7bebab..2c2adc42fb436 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -8,17 +8,28 @@ def initialize(relation) end def select_sql - query = build_query \ - "SELECT #{select_clauses.join(', ')}", - "FROM #{from_clauses}", + if relation.projections.first.is_a?(Count) && relation.projections.size == 1 && (taken.present? || wheres.present?) + subquery = build_query("SELECT 1 FROM #{from_clauses}", build_clauses) + query = "SELECT #{select_clauses.join(', ')} FROM (#{subquery})" + else + query = build_query \ + "SELECT #{select_clauses.join(', ')}", + "FROM #{from_clauses}", + build_clauses + end + query + end + + def build_clauses + clauses = build_query "", (joins(self) unless joins(self).blank? ), ("WHERE #{where_clauses.join(' AND ')}" unless wheres.blank? ), ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ), ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) - engine.add_limit_offset!(query,{ :limit => taken, :offset => skipped }) if taken || skipped - query << " #{locked}" unless locked.blank? - query + clauses << " #{locked}" unless locked.blank? + engine.add_limit_offset!(clauses,{ :limit => taken, :offset => skipped }) if taken || skipped + clauses unless clauses.blank? end def delete_sql diff --git a/spec/engines/sql/unit/relations/take_spec.rb b/spec/engines/sql/unit/relations/take_spec.rb index cc3c3dbbf52bb..1e0d3e3cfefb7 100644 --- a/spec/engines/sql/unit/relations/take_spec.rb +++ b/spec/engines/sql/unit/relations/take_spec.rb @@ -52,6 +52,24 @@ module Arel }) end end + + it "manufactures count sql with limit" do + sql = Take.new(@relation.project(@relation[:id].count), @taken).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(`users`.`id`) AS count_id + FROM (SELECT 1 FROM `users` LIMIT 4) + }) + end + + adapter_is_not :mysql, :oracle do + sql.should be_like(%Q{ + SELECT COUNT("users"."id") AS count_id + FROM (SELECT 1 FROM "users" LIMIT 4) + }) + end + end end end end From a040b1c0e68f7a5145a6decf6731be9c371fa24a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Wed, 23 Jun 2010 13:04:59 -0300 Subject: [PATCH 0413/1492] Don't use a subquery when there are joins. Use a required alias for the subquery. --- lib/arel/engines/sql/relations/compiler.rb | 7 ++++--- spec/engines/sql/unit/relations/take_spec.rb | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 2c2adc42fb436..9684aa7d7d007 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -8,9 +8,10 @@ def initialize(relation) end def select_sql - if relation.projections.first.is_a?(Count) && relation.projections.size == 1 && (taken.present? || wheres.present?) + if relation.projections.first.is_a?(Count) && relation.projections.size == 1 && + (taken.present? || wheres.present?) && joins(self).blank? subquery = build_query("SELECT 1 FROM #{from_clauses}", build_clauses) - query = "SELECT #{select_clauses.join(', ')} FROM (#{subquery})" + query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery" else query = build_query \ "SELECT #{select_clauses.join(', ')}", @@ -27,8 +28,8 @@ def build_clauses ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ), ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) - clauses << " #{locked}" unless locked.blank? engine.add_limit_offset!(clauses,{ :limit => taken, :offset => skipped }) if taken || skipped + clauses << " #{locked}" unless locked.blank? clauses unless clauses.blank? end diff --git a/spec/engines/sql/unit/relations/take_spec.rb b/spec/engines/sql/unit/relations/take_spec.rb index 1e0d3e3cfefb7..ad46190f7e01b 100644 --- a/spec/engines/sql/unit/relations/take_spec.rb +++ b/spec/engines/sql/unit/relations/take_spec.rb @@ -58,15 +58,15 @@ module Arel adapter_is :mysql do sql.should be_like(%Q{ - SELECT COUNT(`users`.`id`) AS count_id - FROM (SELECT 1 FROM `users` LIMIT 4) + SELECT COUNT(*) AS count_id + FROM (SELECT 1 FROM `users` LIMIT 4) AS subquery }) end adapter_is_not :mysql, :oracle do sql.should be_like(%Q{ - SELECT COUNT("users"."id") AS count_id - FROM (SELECT 1 FROM "users" LIMIT 4) + SELECT COUNT(*) AS count_id + FROM (SELECT 1 FROM "users" LIMIT 4) AS subquery }) end end From 93708c2056089dce298ae3d87de87d2625164978 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 23 Jun 2010 17:04:18 -0700 Subject: [PATCH 0414/1492] Speed up Header#each by avoiding &block creation --- lib/arel/algebra/header.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/header.rb b/lib/arel/algebra/header.rb index 9954da5b65271..3b8aea3422a3f 100644 --- a/lib/arel/algebra/header.rb +++ b/lib/arel/algebra/header.rb @@ -9,8 +9,8 @@ def initialize(attrs = []) end end - def each(&block) - to_ary.each(&block) + def each + to_ary.each { |e| yield e } self end From 662b99528218ba7b86d45652438404012f8c4b07 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Wed, 23 Jun 2010 19:59:38 -0700 Subject: [PATCH 0415/1492] Allow externally defined AR adapters to define their own compiler. --- lib/arel/engines/sql/relations/table.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 7940fd781fd0f..f09457f65aa4f 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -20,10 +20,16 @@ def initialize(name, options = {}) if @engine.connection begin require "arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler" - @@tables ||= engine.tables rescue LoadError - raise "#{@engine.adapter_name} is not supported by Arel." + begin + # try to load an externally defined compiler, in case this adapter has defined the compiler on its own. + require "#{@engine.adapter_name.downcase}/arel_compiler" + rescue LoadError + raise "#{@engine.adapter_name} is not supported by Arel." + end end + + @@tables ||= engine.tables end end From d05fa0cc8da0ffa01333f8956acd4a24c9fd46be Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 24 Jun 2010 09:51:23 -0300 Subject: [PATCH 0416/1492] Improve blocks usage. --- lib/arel/algebra/relations/operations/having.rb | 2 +- lib/arel/algebra/relations/operations/lock.rb | 2 +- lib/arel/algebra/relations/operations/where.rb | 2 +- lib/arel/algebra/relations/relation.rb | 4 ++-- lib/arel/algebra/relations/utilities/compound.rb | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index 0cd86c284e31b..a1bbbb3bdcede 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -4,7 +4,7 @@ class Having < Compound deriving :== requires :restricting - def initialize(relation, *predicates, &block) + def initialize(relation, *predicates) predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } @relation = relation diff --git a/lib/arel/algebra/relations/operations/lock.rb b/lib/arel/algebra/relations/operations/lock.rb index 0d6c12e65bcc5..2da273cebc4c8 100644 --- a/lib/arel/algebra/relations/operations/lock.rb +++ b/lib/arel/algebra/relations/operations/lock.rb @@ -3,7 +3,7 @@ class Lock < Compound attributes :relation, :locked deriving :initialize, :== - def initialize(relation, locked, &block) + def initialize(relation, locked) @relation = relation @locked = locked.blank? ? " FOR UPDATE" : locked end diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 5c50fe8640af7..9d868ac18b094 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -4,7 +4,7 @@ class Where < Compound deriving :== requires :restricting - def initialize(relation, *predicates, &block) + def initialize(relation, *predicates) predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } @relation = relation diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index ffd31ae4703aa..0332482066b30 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -17,8 +17,8 @@ def bind(relation) module Enumerable include ::Enumerable - def each(&block) - session.read(self).each(&block) + def each + session.read(self).each { |e| yield e } end def first diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 416717310c901..9f653bbafb841 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -47,7 +47,7 @@ def engine private - def arguments_from_block(relation, &block) + def arguments_from_block(relation) block_given?? [yield(relation)] : [] end end From 5848f21c1f4a351200f4a93fef612b14a24e3ef4 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 24 Jun 2010 11:29:48 -0300 Subject: [PATCH 0417/1492] Performance: use blocks only when needed. --- lib/arel/engines/sql/relations/compiler.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 9684aa7d7d007..dfc2489e77123 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -83,8 +83,12 @@ def update_sql end protected - def method_missing(method, *args, &block) - relation.send(method, *args, &block) + def method_missing(method, *args) + if block_given? + relation.send(method, *args) { |*block_args| yield(*block_args) } + else + relation.send(method, *args) + end end def build_query(*parts) From e589a1ebc57d4c600eecd3464e27b0db8021ab5f Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Thu, 24 Jun 2010 11:34:08 -0300 Subject: [PATCH 0418/1492] Use block_given? instead defining block. --- lib/arel/engines/sql/engine.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index c0e5a39e97239..917da0e93ec15 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -20,8 +20,12 @@ def adapter_name end end - def method_missing(method, *args, &block) - @ar.connection.send(method, *args, &block) + def method_missing(method, *args) + if block_given? + @ar.connection.send(method, *args) { |*block_args| yield(*block_args) } + else + @ar.connection.send(method, *args) + end end module CRUD From 2edbb4b96f5d8ed52357e23ad02c64b8e7a68106 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 09:14:00 -0700 Subject: [PATCH 0419/1492] add active support to the load path --- Rakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 66e4db38a6176..3474cb6d9ed6c 100644 --- a/Rakefile +++ b/Rakefile @@ -35,6 +35,7 @@ else Spec::Rake::SpecTask.new(adapter) do |t| t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" + t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activesupport/lib" t.libs << "#{File.dirname(__FILE__)}/spec" # t.warning = true t.spec_files = FileList['spec/**/*_spec.rb'] @@ -89,4 +90,4 @@ namespace :gemspec do task :validate do gemspec.validate end -end \ No newline at end of file +end From 9fe94dd0c16facf2c9cfac9ae1166050b6f41cee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 09:14:14 -0700 Subject: [PATCH 0420/1492] avoid double call to to_s, avoid present? --- lib/arel/engines/sql/relations/table.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index f09457f65aa4f..c83ce1e5e9662 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -12,7 +12,11 @@ def initialize(name, options = {}) if options.is_a?(Hash) @options = options @engine = options[:engine] || Table.engine - @table_alias = options[:as].to_s if options[:as].present? && options[:as].to_s != @name + + if options[:as] + as = options[:as].to_s + @table_alias = as unless as == @name + end else @engine = options # Table.new('foo', engine) end From 79cb39aad39001c4f995217b168e9ea74ba52ec3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 10:08:17 -0700 Subject: [PATCH 0421/1492] using vendor/rails if the environment variable is not set --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 2e80c2172a6b4..f63d624186055 100644 --- a/Gemfile +++ b/Gemfile @@ -1,9 +1,9 @@ source :rubygems -gem "activerecord", :path => ENV["RAILS_SOURCE"] +gem "activerecord", :path => ENV["RAILS_SOURCE"] || 'vendor/rails' gem "diff-lcs" gem "mysql" gem "pg" gem "rake" gem "rspec" -gem "sqlite3-ruby" \ No newline at end of file +gem "sqlite3-ruby" From d217e57a78a5df20fe1248bac864ad0da58b2dc6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 10:58:00 -0700 Subject: [PATCH 0422/1492] avoid shadowing a variable --- lib/arel/session.rb | 4 ++-- vendor/rails | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/session.rb b/lib/arel/session.rb index c7fcc53a3b33b..6d115e7078144 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -33,8 +33,8 @@ def create(insert) end def read(select) - (@read ||= Hash.new do |hash, select| - hash[select] = select.call + (@read ||= Hash.new do |hash, x| + hash[x] = x.call end)[select] end diff --git a/vendor/rails b/vendor/rails index 181cd109d9812..e1df4b956882f 160000 --- a/vendor/rails +++ b/vendor/rails @@ -1 +1 @@ -Subproject commit 181cd109d9812d371e2d554a4846f0b2b25b1690 +Subproject commit e1df4b956882f0c10a310088c1c13dcaa655a3b1 From d6edefb5a7c1ad56c464ce5ca273a2db736e7b6e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 11:13:01 -0700 Subject: [PATCH 0423/1492] use object id as the weak ref key --- lib/arel/session.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 6d115e7078144..e6da825b97c5c 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -33,9 +33,10 @@ def create(insert) end def read(select) - (@read ||= Hash.new do |hash, x| - hash[x] = x.call - end)[select] + @read ||= {} + key = select.object_id + return @read[key] if @read.key? key + @read[key] = select.call end def update(update) From 36c8cb43ffc2d1bc217cadf4341aa4b0ea6df992 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 14:33:49 -0700 Subject: [PATCH 0424/1492] a short inspect is not helpful --- lib/arel/algebra/attributes/attribute.rb | 4 ---- spec/algebra/unit/primitives/attribute_spec.rb | 6 ------ spec/algebra/unit/primitives/expression_spec.rb | 6 ------ 3 files changed, 16 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index faa6c068d57f9..f1085aaae0166 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -19,10 +19,6 @@ def aggregation? false end - def inspect - "" - end - module Transformations def self.included(klass) klass.send :alias_method, :eql?, :== diff --git a/spec/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb index f734cc9c38a11..092eeeb2f898f 100644 --- a/spec/algebra/unit/primitives/attribute_spec.rb +++ b/spec/algebra/unit/primitives/attribute_spec.rb @@ -7,12 +7,6 @@ module Arel @attribute = @relation[:id] end - describe "#inspect" do - it "returns a simple, short inspect string" do - @attribute.inspect.should == "" - end - end - describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do diff --git a/spec/algebra/unit/primitives/expression_spec.rb b/spec/algebra/unit/primitives/expression_spec.rb index ac932ed13989a..483817f735797 100644 --- a/spec/algebra/unit/primitives/expression_spec.rb +++ b/spec/algebra/unit/primitives/expression_spec.rb @@ -7,12 +7,6 @@ module Arel @attribute = @relation[:id] end - describe "#inspect" do - it "returns a simple, short inspect string" do - @attribute.count.inspect.should == ">" - end - end - describe Expression::Transformations do before do @expression = Count.new(@attribute) From 692566733e4442947c6b6faa2f5a1b13940744d0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 14:37:53 -0700 Subject: [PATCH 0425/1492] delegate and call cached connection --- lib/arel/engines/sql/engine.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 917da0e93ec15..07940c6ef1618 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -4,10 +4,11 @@ class Engine def initialize(ar = nil) @ar = ar + @connection = nil end def connection - @ar ? @ar.connection : nil + @connection ||= @ar && @ar.connection end def adapter_name @@ -22,9 +23,9 @@ def adapter_name def method_missing(method, *args) if block_given? - @ar.connection.send(method, *args) { |*block_args| yield(*block_args) } + connection.send(method, *args) { |*block_args| yield(*block_args) } else - @ar.connection.send(method, *args) + connection.send(method, *args) end end From 703571f7e0bebb3d2bd43a7af5976ad4565ac2cb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:00:36 -0700 Subject: [PATCH 0426/1492] use Session.instance rather than Session.new for easier code --- lib/arel/algebra/relations/relation.rb | 2 +- lib/arel/session.rb | 32 +++++--------------- spec/algebra/unit/relations/relation_spec.rb | 12 ++++---- spec/algebra/unit/session/session_spec.rb | 12 ++++---- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 0332482066b30..34181beea26a7 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -3,7 +3,7 @@ module Relation attr_reader :count def session - Session.new + Session.instance end def call diff --git a/lib/arel/session.rb b/lib/arel/session.rb index e6da825b97c5c..622ca090f89cc 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -1,30 +1,14 @@ module Arel class Session - class << self - attr_accessor :instance - alias_method :manufacture, :new + def self.instance + @instance || new + end - def start - if defined?(@started) && @started - yield - else - begin - @started = true - @instance = manufacture - singleton_class.class_eval do - undef :new - alias_method :new, :instance - end - yield - ensure - singleton_class.class_eval do - undef :new - alias_method :new, :manufacture - end - @started = false - end - end - end + def self.start + @instance ||= new + yield @instance + ensure + @instance = nil end module CRUD diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index a1d1793d92406..be77c64b17455 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -148,8 +148,8 @@ module Arel describe Relation::Operable::Writable do describe '#delete' do it 'manufactures a deletion relation' do - Session.start do - Session.new.should_receive(:delete).with(Deletion.new(@relation)) + Session.start do |s| + s.should_receive(:delete).with(Deletion.new(@relation)) @relation.delete end end @@ -157,9 +157,9 @@ module Arel describe '#insert' do it 'manufactures an insertion relation' do - Session.start do + Session.start do |s| record = { @relation[:name] => 'carl' } - Session.new.should_receive(:create).with(Insert.new(@relation, record)) + s.should_receive(:create).with(Insert.new(@relation, record)) @relation.insert(record) end end @@ -167,9 +167,9 @@ module Arel describe '#update' do it 'manufactures an update relation' do - Session.start do + Session.start do |s| assignments = { @relation[:name] => Value.new('bob', @relation) } - Session.new.should_receive(:update).with(Update.new(@relation, assignments)) + s.should_receive(:update).with(Update.new(@relation, assignments)) @relation.update(assignments) end end diff --git a/spec/algebra/unit/session/session_spec.rb b/spec/algebra/unit/session/session_spec.rb index 0553a140ecfe2..421e3e363790c 100644 --- a/spec/algebra/unit/session/session_spec.rb +++ b/spec/algebra/unit/session/session_spec.rb @@ -10,16 +10,16 @@ module Arel describe '::start' do describe '::instance' do it "it is a singleton within the started session" do - Session.start do - Session.new.should == Session.new + Session.start do |session| + Session.instance.should == session end end it "is a singleton across nested sessions" do - Session.start do - outside = Session.new - Session.start do - Session.new.should == outside + Session.start do |s1| + outside = Session.instance + Session.start do |s2| + Session.instance.should == outside end end end From 8bc47e3fd412bbd2968fb65b6914c66c1e9c048c Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 21 Jul 2010 06:08:23 +0800 Subject: [PATCH 0427/1492] gitmodules are not needed anymore, AR is on Gemfile for testing purposes only and AS is on gemspec --- .gitmodules | 3 --- Rakefile | 2 -- 2 files changed, 5 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 5f43dd3ae55a2..0000000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "vendor/rails"] - path = vendor/rails - url = git://github.com/rails/rails.git diff --git a/Rakefile b/Rakefile index 3474cb6d9ed6c..40fb0afc07257 100644 --- a/Rakefile +++ b/Rakefile @@ -34,8 +34,6 @@ else Spec::Rake::SpecTask.new(adapter) do |t| t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] - t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activerecord/lib" - t.libs << "#{File.dirname(__FILE__)}/vendor/rails/activesupport/lib" t.libs << "#{File.dirname(__FILE__)}/spec" # t.warning = true t.spec_files = FileList['spec/**/*_spec.rb'] From 29c56a5831cc7c97c85b46b7f53c5b43bf2c08f9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:06:13 -0700 Subject: [PATCH 0428/1492] CRUD is not being reused, so we should not expose it --- lib/arel/session.rb | 31 ++++++++++------------- spec/algebra/unit/session/session_spec.rb | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 622ca090f89cc..07809e53ba9f9 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -11,26 +11,23 @@ def self.start @instance = nil end - module CRUD - def create(insert) - insert.call - end + def create(insert) + insert.call + end - def read(select) - @read ||= {} - key = select.object_id - return @read[key] if @read.key? key - @read[key] = select.call - end + def read(select) + @read ||= {} + key = select.object_id + return @read[key] if @read.key? key + @read[key] = select.call + end - def update(update) - update.call - end + def update(update) + update.call + end - def delete(delete) - delete.call - end + def delete(delete) + delete.call end - include CRUD end end diff --git a/spec/algebra/unit/session/session_spec.rb b/spec/algebra/unit/session/session_spec.rb index 421e3e363790c..0aaa031794c29 100644 --- a/spec/algebra/unit/session/session_spec.rb +++ b/spec/algebra/unit/session/session_spec.rb @@ -30,7 +30,7 @@ module Arel end end - describe Session::CRUD do + describe 'session crud' do before do @insert = Insert.new(@relation, @relation[:name] => 'nick') @update = Update.new(@relation, @relation[:name] => 'nick') From 35d66b6eee3cf51c37fa38eb7010c4dec8cd13a4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:18:22 -0700 Subject: [PATCH 0429/1492] classify is not needed, so removing --- lib/arel/algebra/relations/relation.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 34181beea26a7..3ed3a43503a45 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -43,10 +43,13 @@ def outer_join(other_relation = nil) join(other_relation, OuterJoin) end - [:where, :project, :order, :take, :skip, :group, :from, :having].each do |operation_name| + %w{ + where project order take skip group from having + }.each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments, &block) - arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) + arguments.all?(&:blank?) && !block_given? ? + self : #{operation_name.capitalize}.new(self, *arguments, &block) end OPERATION end From 205e59d65bf555119070c6c059c0f229f7f4e0dd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:30:20 -0700 Subject: [PATCH 0430/1492] use OO to avoid meta programming --- lib/arel/algebra/ordering.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/ordering.rb b/lib/arel/algebra/ordering.rb index 8439e937a94ce..984327aaf7061 100644 --- a/lib/arel/algebra/ordering.rb +++ b/lib/arel/algebra/ordering.rb @@ -1,5 +1,5 @@ module Arel - class Ordering + class Ordering < Struct.new(:attribute) delegate :relation, :to => :attribute def bind(relation) @@ -9,15 +9,14 @@ def bind(relation) def to_ordering self end + + def == other + super || (self.class === other && attribute == other.attribute) + end end class Ascending < Ordering - attributes :attribute - deriving :initialize, :== end - class Descending < Ordering - attributes :attribute - deriving :initialize, :== end end From 86dd717c203f6056b4fa367080c989c3411b7300 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:31:50 -0700 Subject: [PATCH 0431/1492] remove useless metaprogramming --- lib/arel/algebra/predicates.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 5f780f32ff5ff..88e0ae9b1819b 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -19,7 +19,7 @@ def not end class Polyadic < Predicate - attributes :predicates + attr_reader :predicates def initialize(*predicates) @predicates = predicates From 2f32aa068513c6bd1fab63087756417e01af06c8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:43:34 -0700 Subject: [PATCH 0432/1492] use OO instead of meta programming --- lib/arel/algebra/predicates.rb | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 88e0ae9b1819b..b60d976b4e96b 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -1,6 +1,6 @@ module Arel module Predicates - class Predicate + class Predicate < Struct.new(:children) def or(other_predicate) Or.new(self, other_predicate) end @@ -16,13 +16,17 @@ def complement def not self.complement end + + def == other + super || (self.class === other && children == other.children) + end end class Polyadic < Predicate - attr_reader :predicates + alias :predicates :children def initialize(*predicates) - @predicates = predicates + super(predicates) end # Build a Polyadic predicate based on: @@ -72,8 +76,7 @@ def complement end class Unary < Predicate - attributes :operand - deriving :initialize, :== + alias :operand :children def bind(relation) self.class.new(operand.find_correlate_in(relation)) @@ -87,13 +90,16 @@ def complement end class Binary < Predicate - attributes :operand1, :operand2 - deriving :initialize + alias :operand1 :children + attr_reader :operand2 + + def initialize left, right + super(left) + @operand2 = right + end def ==(other) - self.class === other and - @operand1 == other.operand1 and - @operand2 == other.operand2 + super && @operand2 == other.operand2 end def bind(relation) From fbb9896dddc4feb71c9526d7773ecd65888a3726 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 15:53:27 -0700 Subject: [PATCH 0433/1492] partial unfuck --- lib/arel/algebra/predicates.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index b60d976b4e96b..df2618a148589 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -55,11 +55,8 @@ def bind(relation) private def same_elements?(a1, a2) - [:select, :inject, :size].each do |m| - return false unless [a1, a2].each {|a| a.respond_to?(m) } - end - a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h } == - a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h } + a1.inject({}) { |h,e| h[e] = a1.count(e); h } == + a2.inject({}) { |h,e| h[e] = a2.count(e); h } end end From b5bcb8b11d7b95309a63a6dde07227007e22217e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 16:19:16 -0700 Subject: [PATCH 0434/1492] comparing children directly --- lib/arel/algebra/predicates.rb | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index df2618a148589..f7c6ee599faba 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -43,7 +43,7 @@ def self.build(operator, operand1, *additional_operands) end def ==(other) - same_elements?(@predicates, other.predicates) + super || children == other.children end def bind(relation) @@ -51,13 +51,6 @@ def bind(relation) *predicates.map {|p| p.find_correlate_in(relation)} ) end - - private - - def same_elements?(a1, a2) - a1.inject({}) { |h,e| h[e] = a1.count(e); h } == - a2.inject({}) { |h,e| h[e] = a2.count(e); h } - end end class Any < Polyadic From 00e39e4363c20f56ab5133743905d9d5e0ebe36c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 16:21:00 -0700 Subject: [PATCH 0435/1492] superclass == works great! --- lib/arel/algebra/predicates.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index f7c6ee599faba..e98e152dbd573 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -42,10 +42,6 @@ def self.build(operator, operand1, *additional_operands) ) end - def ==(other) - super || children == other.children - end - def bind(relation) self.class.new( *predicates.map {|p| p.find_correlate_in(relation)} From 33a9cdc9963489759b75102dd0df48b5a1987369 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 16:33:23 -0700 Subject: [PATCH 0436/1492] inequality is a special case of equality --- lib/arel/algebra/predicates.rb | 10 ++----- lib/arel/engines/memory/predicates.rb | 2 +- lib/arel/engines/sql/predicates.rb | 2 +- .../unit/predicates/inequality_spec.rb | 26 +++++++++++++++++++ .../algebra/unit/predicates/predicate_spec.rb | 22 ++++++++++++++++ 5 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 spec/algebra/unit/predicates/inequality_spec.rb create mode 100644 spec/algebra/unit/predicates/predicate_spec.rb diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index e98e152dbd573..1b9667ac13899 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -109,7 +109,7 @@ def complement class Equality < Binary def ==(other) - Equality === other and + self.class === other and ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end @@ -119,13 +119,7 @@ def complement end end - class Inequality < Binary - def ==(other) - Equality === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) - end - + class Inequality < Equality def complement Equality.new(operand1, operand2) end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index cca6739424ef5..e36afa38c2bc2 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -52,7 +52,7 @@ class Equality < Binary def operator; :== end end - class Inequality < Binary + class Inequality < Equality def eval(row) operand1.eval(row) != operand2.eval(row) end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 93d2a2f619599..21d8f840c95fe 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -52,7 +52,7 @@ def predicate_sql end end - class Inequality < Binary + class Inequality < Equality def predicate_sql operand2.inequality_predicate_sql end diff --git a/spec/algebra/unit/predicates/inequality_spec.rb b/spec/algebra/unit/predicates/inequality_spec.rb new file mode 100644 index 0000000000000..557494e2cd4f3 --- /dev/null +++ b/spec/algebra/unit/predicates/inequality_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +module Arel + module Predicates + describe Inequality do + before do + relation1 = Arel::Table.new(:users) + relation2 = Arel::Table.new(:photos) + left = relation1[:id] + right = relation2[:user_id] + @a = Inequality.new(left, right) + @b = Inequality.new(right, left) + end + + describe '==' do + it "is equal to itself" do + @a.should == @a + end + + it "should not care abount children order" do + @a.should == @b + end + end + end + end +end diff --git a/spec/algebra/unit/predicates/predicate_spec.rb b/spec/algebra/unit/predicates/predicate_spec.rb new file mode 100644 index 0000000000000..6acc047cbbf26 --- /dev/null +++ b/spec/algebra/unit/predicates/predicate_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +module Arel + module Predicates + describe Polyadic do + before do + @relation1 = Arel::Table.new(:users) + @relation2 = Arel::Table.new(:photos) + @a = @relation1[:id] + @b = @relation2[:user_id] + end + + describe '==' do + left = Polyadic.new @a, @b + right = Polyadic.new @b, @a + + left.should != right + left.should == right + end + end + end +end From 108a4531fdb63c33e77fc98145a4520acb1af980 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 16:40:23 -0700 Subject: [PATCH 0437/1492] inheritence meow meow meow --- lib/arel/algebra/relations/operations/alias.rb | 3 --- lib/arel/algebra/relations/utilities/compound.rb | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb index 0331d98b8544f..c5d23783e502c 100644 --- a/lib/arel/algebra/relations/operations/alias.rb +++ b/lib/arel/algebra/relations/operations/alias.rb @@ -1,7 +1,4 @@ module Arel class Alias < Compound - attributes :relation - deriving :initialize - alias_method :==, :equal? end end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 9f653bbafb841..42ac519907957 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -13,6 +13,10 @@ def self.requires(feature = nil) @requires end + def initialize relation + @relation = relation + end + [:wheres, :groupings, :orders, :havings, :projections].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} From 2f6ae7592ff20c8ce02113f3d349b67911103023 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 16:51:25 -0700 Subject: [PATCH 0438/1492] refactor to use inheritence --- lib/arel/algebra/relations/operations/from.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/operations/from.rb b/lib/arel/algebra/relations/operations/from.rb index 6bfd68dfc9665..fbddb4234fbdc 100644 --- a/lib/arel/algebra/relations/operations/from.rb +++ b/lib/arel/algebra/relations/operations/from.rb @@ -1,6 +1,10 @@ module Arel class From < Compound - attributes :relation, :sources - deriving :initialize, :== + attr_reader :sources + + def initialize relation, sources + super(relation) + @sources = sources + end end end From 5b3433069fc94e120555ae4d218f6be19d2e51d4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 17:07:02 -0700 Subject: [PATCH 0439/1492] removing more meta programming --- lib/arel/algebra/attributes/attribute.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index f1085aaae0166..9206b228c8198 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -3,14 +3,22 @@ module Arel class TypecastError < StandardError ; end class Attribute - attributes :relation, :name, :alias, :ancestor - deriving :== + attr_reader :relation, :name, :alias, :ancestor delegate :engine, :christener, :to => :relation def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end + def == other + super || + Attribute === other && + @relation == other.relation && + @name == other.name && + @alias == other.alias && + @ancestor == other.ancestor + end + def named?(hypothetical_name) (@alias || name).to_s == hypothetical_name.to_s end From 56f2de870a7279e11575f6d0c6f2f9eea1374407 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 17:30:54 -0700 Subject: [PATCH 0440/1492] take advantage of inheritence for easier codes --- lib/arel/algebra/relations/writes.rb | 30 +++++++++++---------- lib/arel/engines/memory/relations/writes.rb | 2 +- lib/arel/engines/sql/relations/writes.rb | 6 ++--- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb index d344987915aa9..17da2b172b8d7 100644 --- a/lib/arel/algebra/relations/writes.rb +++ b/lib/arel/algebra/relations/writes.rb @@ -1,33 +1,35 @@ module Arel - class Deletion < Compound - attributes :relation - deriving :initialize, :== + class Action < Compound + def == other + super || self.class === other && @relation == other.relation + end + end + class Deletion < Action def call engine.delete(self) end end - class Insert < Compound - attributes :relation, :record - deriving :== + class Insert < Action + attr_reader :record def initialize(relation, record) - @relation, @record = relation, record.bind(relation) + super(relation) + @record = record.bind(relation) end def call engine.create(self) end - end - class Update < Compound - attributes :relation, :assignments - deriving :== - - def initialize(relation, assignments) - @relation, @assignments = relation, assignments.bind(relation) + def == other + super && @record == other.record end + end + + class Update < Insert + alias :assignments :record def call engine.update(self) diff --git a/lib/arel/engines/memory/relations/writes.rb b/lib/arel/engines/memory/relations/writes.rb index 12c4f36c0d970..39c1170ddc496 100644 --- a/lib/arel/engines/memory/relations/writes.rb +++ b/lib/arel/engines/memory/relations/writes.rb @@ -1,5 +1,5 @@ module Arel - class Insert < Compound + class Insert < Action def eval unoperated_rows + [Row.new(self, record.values.collect(&:value))] end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 4ed817f85d080..50a2ce2e99186 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -1,17 +1,17 @@ module Arel - class Deletion < Compound + class Deletion < Action def to_sql compiler.delete_sql end end - class Insert < Compound + class Insert < Action def to_sql(include_returning = true) compiler.insert_sql(include_returning) end end - class Update < Compound + class Update < Insert def to_sql compiler.update_sql end From 6da9e6d6818b3f33b73e929ea57c40ea8d2f1829 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 20 Jul 2010 17:37:03 -0700 Subject: [PATCH 0441/1492] unfactoring more meta programming --- lib/arel/algebra/relations/operations/group.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 2bfc42214bb88..68c626e917985 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -1,12 +1,18 @@ module Arel class Group < Compound - attributes :relation, :groupings - deriving :== + attr_reader :groupings def initialize(relation, *groupings, &block) - @relation = relation + super(relation) @groupings = (groupings + arguments_from_block(relation, &block)) \ .collect { |g| g.bind(relation) } end + + def == other + super || + self.class === other && + @relation == other.relation && + @groupings == other.groupings + end end end From 862067cf14213ee9df0784250301a1987b3822db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 21 Jul 2010 11:28:40 +0200 Subject: [PATCH 0442/1492] Also remove submodule link, otherwise it will cause massive pain for people pulling out ARel. --- vendor/rails | 1 - 1 file changed, 1 deletion(-) delete mode 160000 vendor/rails diff --git a/vendor/rails b/vendor/rails deleted file mode 160000 index e1df4b956882f..0000000000000 --- a/vendor/rails +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e1df4b956882f0c10a310088c1c13dcaa655a3b1 From 2f0a8ae8d4aed502a0b6c4780d4545c147bdcb47 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 21 Jul 2010 10:34:11 -0700 Subject: [PATCH 0443/1492] fixing incompatibilities with AR --- lib/arel/algebra/predicates.rb | 28 +++++++++++++++++---------- lib/arel/engines/memory/predicates.rb | 2 +- lib/arel/engines/sql/engine.rb | 3 +-- lib/arel/engines/sql/predicates.rb | 2 +- lib/arel/session.rb | 2 ++ spec/engines/sql/unit/engine_spec.rb | 27 ++++++++++++++++++++++++++ 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 1b9667ac13899..b761eab417c62 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -1,6 +1,6 @@ module Arel module Predicates - class Predicate < Struct.new(:children) + class Predicate def or(other_predicate) Or.new(self, other_predicate) end @@ -16,17 +16,13 @@ def complement def not self.complement end - - def == other - super || (self.class === other && children == other.children) - end end class Polyadic < Predicate - alias :predicates :children + attr_reader :predicates def initialize(*predicates) - super(predicates) + @predicates = predicates end # Build a Polyadic predicate based on: @@ -42,6 +38,10 @@ def self.build(operator, operand1, *additional_operands) ) end + def ==(other) + super || predicates == other.predicates + end + def bind(relation) self.class.new( *predicates.map {|p| p.find_correlate_in(relation)} @@ -62,11 +62,19 @@ def complement end class Unary < Predicate - alias :operand :children + attr_reader :operand + + def initialize operand + @operand = operand + end def bind(relation) self.class.new(operand.find_correlate_in(relation)) end + + def == other + super || self.class === other && operand == other.operand + end end class Not < Unary @@ -75,9 +83,9 @@ def complement end end - class Binary < Predicate - alias :operand1 :children + class Binary < Unary attr_reader :operand2 + alias :operand1 :operand def initialize left, right super(left) diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index e36afa38c2bc2..1527b04056311 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -1,6 +1,6 @@ module Arel module Predicates - class Binary < Predicate + class Binary < Unary def eval(row) operand1.eval(row).send(operator, operand2.eval(row)) end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 07940c6ef1618..a314a972c016d 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -4,11 +4,10 @@ class Engine def initialize(ar = nil) @ar = ar - @connection = nil end def connection - @connection ||= @ar && @ar.connection + @ar ? @ar.connection : nil end def adapter_name diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 21d8f840c95fe..74a36d77c97bd 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -1,6 +1,6 @@ module Arel module Predicates - class Binary < Predicate + class Binary < Unary def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 07809e53ba9f9..f6016431c3b74 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -1,5 +1,7 @@ module Arel class Session + @instance = nil + def self.instance @instance || new end diff --git a/spec/engines/sql/unit/engine_spec.rb b/spec/engines/sql/unit/engine_spec.rb index f782f56938f35..85a9dc5bfb104 100644 --- a/spec/engines/sql/unit/engine_spec.rb +++ b/spec/engines/sql/unit/engine_spec.rb @@ -1,12 +1,39 @@ require 'spec_helper' module Arel + FakeAR = Struct.new(:connection) + class FakeConnection < Struct.new :called + def initialize c = []; super; end + + def method_missing name, *args, &block + called << [name, args, block] + end + end + describe Sql::Engine do before do @users = Table.new(:users) @users.delete end + describe "method missing" do + it "should pass through" do + conn = FakeConnection.new + engine = Arel::Sql::Engine.new FakeAR.new conn + engine.foo + conn.called.should == [[:foo, [], nil]] + end + + it "should ask for a connection" do + conn = FakeConnection.new + ar = FakeAR.new conn + engine = Arel::Sql::Engine.new ar + + ar.connection = nil + lambda { engine.foo }.should raise_error + end + end + describe "CRUD" do describe "#create" do it "inserts into the relation" do From 3c907173bd5a1eab82e29c802cacce887ad90cde Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 21 Jul 2010 11:27:17 -0700 Subject: [PATCH 0444/1492] reuse our superclass --- lib/arel/algebra/expression.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/arel/algebra/expression.rb b/lib/arel/algebra/expression.rb index 875498c28282e..40baf5ece0035 100644 --- a/lib/arel/algebra/expression.rb +++ b/lib/arel/algebra/expression.rb @@ -1,12 +1,15 @@ module Arel class Expression < Attribute - attributes :attribute, :alias, :ancestor - deriving :== - delegate :relation, :to => :attribute - alias_method :name, :alias + attr_reader :attribute + alias :name :alias def initialize(attribute, aliaz = nil, ancestor = nil) - @attribute, @alias, @ancestor = attribute, aliaz, ancestor + super(attribute.relation, aliaz, :alias => aliaz, :ancestor => ancestor) + @attribute = attribute + end + + def == other + super && Expression === other && attribute == other.attribute end def aggregation? From 5ff03b2745a35dc76527c6c448964d216c0034cb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 21 Jul 2010 11:27:38 -0700 Subject: [PATCH 0445/1492] custom inspect is not helpful --- lib/arel/algebra/expression.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/algebra/expression.rb b/lib/arel/algebra/expression.rb index 40baf5ece0035..183de3c005cfb 100644 --- a/lib/arel/algebra/expression.rb +++ b/lib/arel/algebra/expression.rb @@ -16,10 +16,6 @@ def aggregation? true end - def inspect - "<#{self.class.name} #{attribute.inspect}>" - end - module Transformations def as(aliaz) self.class.new(attribute, aliaz, self) From b1a55238f3ac510b535490e8ccdef65dfc351ecf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 16:42:18 -0700 Subject: [PATCH 0446/1492] fixing warnings --- lib/arel/algebra/relations/operations/having.rb | 1 - lib/arel/algebra/relations/operations/lock.rb | 2 +- lib/arel/algebra/relations/utilities/compound.rb | 2 +- lib/arel/engines/memory/relations/array.rb | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index a1bbbb3bdcede..daca1f7bcea3f 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -2,7 +2,6 @@ module Arel class Having < Compound attributes :relation, :predicates deriving :== - requires :restricting def initialize(relation, *predicates) predicates = [yield(relation)] + predicates if block_given? diff --git a/lib/arel/algebra/relations/operations/lock.rb b/lib/arel/algebra/relations/operations/lock.rb index 2da273cebc4c8..4520fd668b959 100644 --- a/lib/arel/algebra/relations/operations/lock.rb +++ b/lib/arel/algebra/relations/operations/lock.rb @@ -1,7 +1,7 @@ module Arel class Lock < Compound attributes :relation, :locked - deriving :initialize, :== + deriving :== def initialize(relation, locked) @relation = relation diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 42ac519907957..34f80b9e56e95 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -4,7 +4,7 @@ class Compound attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :sources, :locked, :table_alias, + :column_for, :sources, :locked, :table_alias, :to => :relation def self.requires(feature = nil) diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index d8751fa6264c9..9f6961818643b 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -4,7 +4,7 @@ class Array attributes :array, :attribute_names_and_types include Recursion::BaseCase - deriving :==, :initialize + deriving :== def initialize(array, attribute_names_and_types) @array, @attribute_names_and_types = array, attribute_names_and_types From 3ae0cdf21980e454b1fdaf6005179080c0114c27 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:23:25 -0700 Subject: [PATCH 0447/1492] removing more metaprogramming --- .../algebra/relations/operations/having.rb | 11 +++++--- lib/arel/algebra/relations/operations/join.rb | 26 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index daca1f7bcea3f..fdd35626af43c 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -1,16 +1,21 @@ module Arel class Having < Compound - attributes :relation, :predicates - deriving :== + attr_reader :predicates def initialize(relation, *predicates) + super(relation) predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } - @relation = relation end def havings @havings ||= relation.havings + predicates end + + def == other + super || Having === other && + relation == other.relation && + predicates == other.predicates + end end end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 21bcfaa62d4cf..dd67e8a9bf2cc 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -2,20 +2,20 @@ module Arel class Join include Relation - attributes :relation1, :relation2, :predicates - deriving :== - delegate :name, :to => :relation1 + attr_reader :relation1, :relation2, :predicates def initialize(relation1, relation2 = Nil.instance, *predicates) - @relation1, @relation2, @predicates = relation1, relation2, predicates + @relation1 = relation1 + @relation2 = relation2 + @predicates = predicates end - def hash - @hash ||= :relation1.hash + def name + relation1.name end - def eql?(other) - self == other + def hash + @hash ||= :relation1.hash end def attributes @@ -43,6 +43,16 @@ def join? def engine relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine end + + def == other + super || Join === other && + relation1 == other.relation1 && + relation2 == other.relation2 && + predicates == other.predicates + end + + # FIXME remove this. :'( + alias :eql? :== end class InnerJoin < Join; end From 9d07043eceab33113f55a6e8cb12f9f6ad296f5c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:26:06 -0700 Subject: [PATCH 0448/1492] removing more metaprogramming --- lib/arel/algebra/relations/operations/lock.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/relations/operations/lock.rb b/lib/arel/algebra/relations/operations/lock.rb index 4520fd668b959..003bd29c8ad32 100644 --- a/lib/arel/algebra/relations/operations/lock.rb +++ b/lib/arel/algebra/relations/operations/lock.rb @@ -1,12 +1,16 @@ module Arel class Lock < Compound - attributes :relation, :locked - deriving :== + attr_reader :locked def initialize(relation, locked) - @relation = relation + super(relation) @locked = locked.blank? ? " FOR UPDATE" : locked end + + def == other + super || Lock === other && + relation == other.relation && + locked == other.locked + end end end - From 5ad24febb4de206a5f5075259569223dcc09b6d6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:30:22 -0700 Subject: [PATCH 0449/1492] removing more meta programming --- lib/arel/algebra/relations/operations/order.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index df54735630b49..bb5ac1ab881c0 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -1,15 +1,21 @@ module Arel class Order < Compound - attributes :relation, :orderings - deriving :== + attr_reader :orderings requires :ordering def initialize(relation, *orderings, &block) - @relation = relation + super(relation) @orderings = (orderings + arguments_from_block(relation, &block)) \ .collect { |o| o.bind(relation) } end + def == other + super || + Order === other && + relation == other.relation && + orderings == other.orderings + end + # TESTME def orders # QUESTION - do we still need relation.orders ? From e4eb64bab3eaa40ce22f0d0c7d008c6eea2988ca Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:33:13 -0700 Subject: [PATCH 0450/1492] moving engine to the child class for future refactoring --- lib/arel/algebra/relations/operations/order.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index bb5ac1ab881c0..582abf642cf2e 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -1,7 +1,6 @@ module Arel class Order < Compound attr_reader :orderings - requires :ordering def initialize(relation, *orderings, &block) super(relation) @@ -21,5 +20,16 @@ def orders # QUESTION - do we still need relation.orders ? (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } end + + def engine + engine = relation.engine + + # Temporary check of whether or not the engine supports where. + if engine.respond_to?(:supports) && !engine.supports(:ordering) + Memory::Engine.new + else + engine + end + end end end From 89fb88982fb1a678484cd4bdacae37aa4a599a4a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:39:50 -0700 Subject: [PATCH 0451/1492] unfactoring more metaprogramming --- lib/arel/algebra/relations/operations/project.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 49d0e1be36a9c..2cdae288e3c66 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -1,10 +1,9 @@ module Arel class Project < Compound - attributes :relation, :projections - deriving :== + attr_reader :projections def initialize(relation, *projections, &block) - @relation = relation + super(relation) @projections = (projections + arguments_from_block(relation, &block)) \ .collect { |p| p.bind(relation) } end @@ -16,5 +15,12 @@ def attributes def externalizable? attributes.any? { |a| a.respond_to?(:aggregation?) && a.aggregation? } || relation.externalizable? end + + def == other + super || + Project === other && + relation == other.relation && + projections == other.projections + end end end From faf14aeed6cc79bd356f2ac9739362b2ba5732bc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:42:18 -0700 Subject: [PATCH 0452/1492] more unfactoring before we refactor --- lib/arel/algebra/relations/operations/skip.rb | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 43db134ea0869..f6a58d15bdd04 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -1,7 +1,28 @@ module Arel class Skip < Compound - attributes :relation, :skipped - deriving :initialize, :== - requires :skipping + attr_reader :relation, :skipped + + def initialize relation, skipped + super(relation) + @skipped = skipped + end + + def == other + super || + Skip === other && + relation == other.relation && + skipped == other.skipped + end + + def engine + engine = relation.engine + + # Temporary check of whether or not the engine supports where. + if engine.respond_to?(:supports) && !engine.supports(:skipping) + Memory::Engine.new + else + engine + end + end end end From 25ff3d48755fb48648b0ad4be090f7507236c722 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:50:29 -0700 Subject: [PATCH 0453/1492] more unfactoring before we refactor --- lib/arel/algebra/relations/operations/take.rb | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index cc636642b1e04..964aacacca577 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -1,8 +1,29 @@ module Arel class Take < Compound - attributes :relation, :taken - deriving :initialize, :== - requires :limiting + attr_reader :taken + + def initialize relation, taken + super(relation) + @taken = taken + end + + def == other + super || + Take === other && + relation == other.relation && + taken == other.taken + end + + def engine + engine = relation.engine + + # Temporary check of whether or not the engine supports where. + if engine.respond_to?(:supports) && !engine.supports(:limiting) + Memory::Engine.new + else + engine + end + end def externalizable? true From de71dc2a16d7487093e89253ee4e0651ce00a7d2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:51:20 -0700 Subject: [PATCH 0454/1492] initializing variables --- lib/arel/algebra/relations/operations/where.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 9d868ac18b094..3c5df117f6b3a 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -8,6 +8,7 @@ def initialize(relation, *predicates) predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } @relation = relation + @wheres = nil end def wheres From 496134516e19acd93772cfff8eafa4cb2dd8bc8d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:56:34 -0700 Subject: [PATCH 0455/1492] more unfactoring --- .../algebra/relations/operations/where.rb | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 3c5df117f6b3a..e8db2ec8b09cd 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -1,18 +1,34 @@ module Arel class Where < Compound - attributes :relation, :predicates - deriving :== - requires :restricting + attr_reader :predicates def initialize(relation, *predicates) + super(relation) predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } - @relation = relation @wheres = nil end def wheres @wheres ||= relation.wheres + predicates end + + def == other + super || + Where === other && + relation == other.relation && + predicates == other.predicates + end + + def engine + engine = relation.engine + + # Temporary check of whether or not the engine supports where. + if engine.respond_to?(:supports) && !engine.supports(:restricting) + Memory::Engine.new + else + engine + end + end end end From 12859b89e574a2965ae94053dc0cdaf92dcf8e3a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 17:59:26 -0700 Subject: [PATCH 0456/1492] more unfactoring --- lib/arel/algebra/relations/row.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index 31585574485a7..f5fe364b83239 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -1,7 +1,18 @@ module Arel class Row - attributes :relation, :tuple - deriving :==, :initialize + attr_reader :tuple, :relation + + def initialize relation, tuple + @relation = relation + @tuple = tuple + end + + def == other + super || + Row === other && + relation == other.relation && + tuple == other.tuple + end def [](attribute) attribute.type_cast(tuple[relation.position_of(attribute)]) From 9efbf51adbebcf32787cff6b470218be748b5119 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:03:56 -0700 Subject: [PATCH 0457/1492] unfactoring metaprogramming --- lib/arel/algebra/relations/utilities/externalization.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index edd8f99221c85..c7a7d9ca78892 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -1,7 +1,8 @@ module Arel class Externalization < Compound - attributes :relation - deriving :initialize, :== + def == other + super || Externalization === other && relation == other.relation + end def wheres [] From 3db95ef6a1bc26540d6908ef47b8d44818a8c305 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:08:47 -0700 Subject: [PATCH 0458/1492] removing more metaprogramming --- lib/arel/algebra/value.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/value.rb b/lib/arel/algebra/value.rb index e3638051402a8..d9fc2e061c3f0 100644 --- a/lib/arel/algebra/value.rb +++ b/lib/arel/algebra/value.rb @@ -1,7 +1,18 @@ module Arel class Value - attributes :value, :relation - deriving :initialize, :== + attr_reader :value, :relation + + def initialize value, relation + @value = value + @relation = relation + end + + def == other + super || + Value === other && + value == other.value && + relation == other.relation + end def bind(relation) Value.new(value, relation) From b0bef671e883eb4fba01d0295069e4b52d3328b1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:15:00 -0700 Subject: [PATCH 0459/1492] the rest of the unfactoring! --- lib/arel/engines/memory/relations/array.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 9f6961818643b..7f881dd849863 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -2,12 +2,21 @@ module Arel class Array include Relation - attributes :array, :attribute_names_and_types + attr_reader :array, :attribute_names_and_types include Recursion::BaseCase - deriving :== def initialize(array, attribute_names_and_types) - @array, @attribute_names_and_types = array, attribute_names_and_types + @array = array + @attribute_names_and_types = attribute_names_and_types + @engine = nil + @attributes = nil + end + + def == other + super || + Array === other && + array == other.array && + attribute_names_and_types == other.attribute_names_and_types end def engine From edb786204fb45ba2a877ec7a3b26e84119b13377 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:17:54 -0700 Subject: [PATCH 0460/1492] removing unused file --- lib/arel/algebra/core_extensions.rb | 1 - lib/arel/algebra/core_extensions/class.rb | 32 ----------------------- 2 files changed, 33 deletions(-) delete mode 100644 lib/arel/algebra/core_extensions/class.rb diff --git a/lib/arel/algebra/core_extensions.rb b/lib/arel/algebra/core_extensions.rb index bce86d04ba140..4416ff6b77b09 100644 --- a/lib/arel/algebra/core_extensions.rb +++ b/lib/arel/algebra/core_extensions.rb @@ -1,4 +1,3 @@ require 'arel/algebra/core_extensions/object' -require 'arel/algebra/core_extensions/class' require 'arel/algebra/core_extensions/symbol' require 'arel/algebra/core_extensions/hash' diff --git a/lib/arel/algebra/core_extensions/class.rb b/lib/arel/algebra/core_extensions/class.rb deleted file mode 100644 index d0894931dae51..0000000000000 --- a/lib/arel/algebra/core_extensions/class.rb +++ /dev/null @@ -1,32 +0,0 @@ -module Arel - module ClassExtensions - def attributes(*attrs) - @attributes = attrs - attr_reader(*attrs) - end - - def deriving(*methods) - methods.each { |m| derive m } - end - - def derive(method_name) - methods = { - :initialize => " - def #{method_name}(#{@attributes.join(',')}) - #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} - end - ", - :== => " - def ==(other) - #{name} === other && - #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} - end - " - } - class_eval methods[method_name], __FILE__, __LINE__ - end - - Class.send(:include, self) - end -end - From a20bd2cbd19120d821e85b929fd57ea75a916c75 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:23:37 -0700 Subject: [PATCH 0461/1492] replacing "let" with "tap" --- lib/arel/algebra/core_extensions/object.rb | 4 ---- spec/engines/memory/integration/joins/cross_engine_spec.rb | 4 ++-- spec/engines/memory/unit/relations/join_spec.rb | 2 +- spec/engines/memory/unit/relations/order_spec.rb | 2 +- spec/engines/memory/unit/relations/project_spec.rb | 2 +- spec/engines/memory/unit/relations/skip_spec.rb | 2 +- spec/engines/memory/unit/relations/take_spec.rb | 2 +- spec/engines/memory/unit/relations/where_spec.rb | 4 ++-- 8 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/arel/algebra/core_extensions/object.rb b/lib/arel/algebra/core_extensions/object.rb index 85a4d951a4f23..2dc5ea267759f 100644 --- a/lib/arel/algebra/core_extensions/object.rb +++ b/lib/arel/algebra/core_extensions/object.rb @@ -8,10 +8,6 @@ def find_correlate_in(relation) bind(relation) end - def let - yield(self) - end - Object.send(:include, self) end end diff --git a/spec/engines/memory/integration/joins/cross_engine_spec.rb b/spec/engines/memory/integration/joins/cross_engine_spec.rb index 5dc1a6cb99514..091fd2ceda6b6 100644 --- a/spec/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/engines/memory/integration/joins/cross_engine_spec.rb @@ -24,7 +24,7 @@ module Arel .join(@photos) \ .on(@users[:id].eq(@photos[:user_id])) \ .project(@users[:name], @photos[:camera_id]) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, ['bryan', @adapter_returns_integer ? 6 : '6']), Row.new(relation, ['emilio', @adapter_returns_integer ? 42 : '42']) @@ -39,7 +39,7 @@ module Arel .join(@users) \ .on(@users[:id].eq(@photos[:user_id])) \ .project(@users[:name], @photos[:camera_id]) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, ['bryan', @adapter_returns_integer ? 6 : '6']), Row.new(relation, ['emilio', @adapter_returns_integer ? 42 : '42']) diff --git a/spec/engines/memory/unit/relations/join_spec.rb b/spec/engines/memory/unit/relations/join_spec.rb index ed5fe89ef0b92..9a475d817d914 100644 --- a/spec/engines/memory/unit/relations/join_spec.rb +++ b/spec/engines/memory/unit/relations/join_spec.rb @@ -17,7 +17,7 @@ module Arel @relation1 \ .join(@relation2) \ .on(@relation1[:id].eq(@relation2[:id])) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [1, 'duck', 1, 'duck' ]), Row.new(relation, [2, 'duck', 2, 'duck' ]), diff --git a/spec/engines/memory/unit/relations/order_spec.rb b/spec/engines/memory/unit/relations/order_spec.rb index 9546449bfbf73..0d746bcd0af55 100644 --- a/spec/engines/memory/unit/relations/order_spec.rb +++ b/spec/engines/memory/unit/relations/order_spec.rb @@ -14,7 +14,7 @@ module Arel it 'sorts the relation with the provided ordering' do @relation \ .order(@relation[:id].desc) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [3, 'goose']), Row.new(relation, [2, 'duck' ]), diff --git a/spec/engines/memory/unit/relations/project_spec.rb b/spec/engines/memory/unit/relations/project_spec.rb index 92ed9fa74b944..3970a50129ef0 100644 --- a/spec/engines/memory/unit/relations/project_spec.rb +++ b/spec/engines/memory/unit/relations/project_spec.rb @@ -14,7 +14,7 @@ module Arel it 'retains only the attributes that are provided' do @relation \ .project(@relation[:id]) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [1]), Row.new(relation, [2]), diff --git a/spec/engines/memory/unit/relations/skip_spec.rb b/spec/engines/memory/unit/relations/skip_spec.rb index 089db24ceabd1..4cf6c020bc223 100644 --- a/spec/engines/memory/unit/relations/skip_spec.rb +++ b/spec/engines/memory/unit/relations/skip_spec.rb @@ -14,7 +14,7 @@ module Arel it 'removes the first n rows' do @relation \ .skip(1) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [2, 'duck']), Row.new(relation, [3, 'goose']), diff --git a/spec/engines/memory/unit/relations/take_spec.rb b/spec/engines/memory/unit/relations/take_spec.rb index 16b99872c5385..f74f1a74c822a 100644 --- a/spec/engines/memory/unit/relations/take_spec.rb +++ b/spec/engines/memory/unit/relations/take_spec.rb @@ -14,7 +14,7 @@ module Arel it 'removes the rows after the first n' do @relation \ .take(2) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [1, 'duck']), Row.new(relation, [2, 'duck']), diff --git a/spec/engines/memory/unit/relations/where_spec.rb b/spec/engines/memory/unit/relations/where_spec.rb index b45c009d83433..23aef5766e86c 100644 --- a/spec/engines/memory/unit/relations/where_spec.rb +++ b/spec/engines/memory/unit/relations/where_spec.rb @@ -14,7 +14,7 @@ module Arel it 'filters the relation with the provided predicate' do @relation \ .where(@relation[:id].lt(3)) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [1, 'duck']), Row.new(relation, [2, 'duck']), @@ -27,7 +27,7 @@ module Arel @relation \ .where(@relation[:id].gt(1)) \ .where(@relation[:id].lt(3)) \ - .let do |relation| + .tap do |relation| relation.call.should == [ Row.new(relation, [2, 'duck']) ] From bc4d913200d17da751f9b1d9bad78cb94173a4cb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:25:47 -0700 Subject: [PATCH 0462/1492] do not use a module as it slows down method lookup --- lib/arel/algebra/core_extensions/hash.rb | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/core_extensions/hash.rb b/lib/arel/algebra/core_extensions/hash.rb index c64225f68536e..82cd5e11d3372 100644 --- a/lib/arel/algebra/core_extensions/hash.rb +++ b/lib/arel/algebra/core_extensions/hash.rb @@ -1,11 +1,7 @@ -module Arel - module HashExtensions - def bind(relation) - inject({}) do |bound, (key, value)| - bound.merge(key.bind(relation) => value.bind(relation)) - end +class Hash + def bind(relation) + inject({}) do |bound, (key, value)| + bound.merge(key.bind(relation) => value.bind(relation)) end - - Hash.send(:include, self) end end From 181f4633b8aff0efdff6643ddee800d6f78d1eac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:27:58 -0700 Subject: [PATCH 0463/1492] inject is slow, lets use Hash[] and map {} --- lib/arel/algebra/core_extensions/hash.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/core_extensions/hash.rb b/lib/arel/algebra/core_extensions/hash.rb index 82cd5e11d3372..4b36a3e2bcc43 100644 --- a/lib/arel/algebra/core_extensions/hash.rb +++ b/lib/arel/algebra/core_extensions/hash.rb @@ -1,7 +1,7 @@ class Hash def bind(relation) - inject({}) do |bound, (key, value)| - bound.merge(key.bind(relation) => value.bind(relation)) - end + Hash[map { |key, value| + [key.bind(relation), value.bind(relation)] + }] end end From ef231deb9ef032e0910dcaec240b70996fc5e44e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 25 Jul 2010 18:37:00 -0700 Subject: [PATCH 0464/1492] speed up method lookup by not mixing in modules --- lib/arel/engines/memory/engine.rb | 12 +++------- lib/arel/engines/sql/engine.rb | 40 ++++++++++++++----------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb index c7ac9422d42ea..0142c49aa320a 100644 --- a/lib/arel/engines/memory/engine.rb +++ b/lib/arel/engines/memory/engine.rb @@ -1,16 +1,10 @@ module Arel module Memory class Engine - module CRUD - def read(relation) - relation.eval - end - - def create(relation) - relation.eval - end + def read(relation) + relation.eval end - include CRUD + alias :create :read end end end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index a314a972c016d..8504fec3c51af 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -1,7 +1,6 @@ module Arel module Sql class Engine - def initialize(ar = nil) @ar = ar end @@ -28,32 +27,29 @@ def method_missing(method, *args) end end - module CRUD - def create(relation) - primary_key_value = if relation.primary_key.blank? - nil - elsif relation.record.is_a?(Hash) - attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s } - attribute && attribute.last.value - end - - connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value) + def create(relation) + primary_key_value = if relation.primary_key.blank? + nil + elsif relation.record.is_a?(Hash) + attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s } + attribute && attribute.last.value end - def read(relation) - rows = connection.select_rows(relation.to_sql) - Array.new(rows, relation.attributes) - end + connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value) + end - def update(relation) - connection.update(relation.to_sql) - end + def read(relation) + rows = connection.select_rows(relation.to_sql) + Array.new(rows, relation.attributes) + end - def delete(relation) - connection.delete(relation.to_sql) - end + def update(relation) + connection.update(relation.to_sql) + end + + def delete(relation) + connection.delete(relation.to_sql) end - include CRUD end end end From 2598ee0f61ecb40b1c746d339c6853d1835992f8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 10:52:21 -0700 Subject: [PATCH 0465/1492] removing unhelpful organization --- lib/arel/algebra/predicates.rb | 59 +++++++++++++++- lib/arel/engines/memory.rb | 1 - lib/arel/engines/memory/predicates.rb | 99 --------------------------- 3 files changed, 58 insertions(+), 101 deletions(-) delete mode 100644 lib/arel/engines/memory/predicates.rb diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index b761eab417c62..5b65b59c8c907 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -47,18 +47,28 @@ def bind(relation) *predicates.map {|p| p.find_correlate_in(relation)} ) end + + def eval(row) + predicates.send(compounder) do |operation| + operation.eval(row) + end + end end class Any < Polyadic def complement All.new(*predicates.map {|p| p.complement}) end + + def compounder; :any? end end class All < Polyadic def complement Any.new(*predicates.map {|p| p.complement}) end + + def compounder; :all? end end class Unary < Predicate @@ -75,12 +85,20 @@ def bind(relation) def == other super || self.class === other && operand == other.operand end + + def eval(row) + operand.eval(row).send(operator) + end end class Not < Unary def complement operand end + + def eval(row) + !operand.eval(row) + end end class Binary < Unary @@ -99,20 +117,31 @@ def ==(other) def bind(relation) self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end + + def eval(row) + operand1.eval(row).send(operator, operand2.eval(row)) + end end - class CompoundPredicate < Binary; end + class CompoundPredicate < Binary + def eval(row) + eval "operand1.eval(row) #{operator} operand2.eval(row)" + end + end class And < CompoundPredicate def complement Or.new(operand1.complement, operand2.complement) end + + def operator; :and end end class Or < CompoundPredicate def complement And.new(operand1.complement, operand2.complement) end + def operator; :or end end class Equality < Binary @@ -125,60 +154,88 @@ def ==(other) def complement Inequality.new(operand1, operand2) end + + def operator; :== end end class Inequality < Equality def complement Equality.new(operand1, operand2) end + + def eval(row) + operand1.eval(row) != operand2.eval(row) + end end class GreaterThanOrEqualTo < Binary def complement LessThan.new(operand1, operand2) end + + def operator; :>= end end class GreaterThan < Binary def complement LessThanOrEqualTo.new(operand1, operand2) end + + def operator; :> end end class LessThanOrEqualTo < Binary def complement GreaterThan.new(operand1, operand2) end + + def operator; :<= end end class LessThan < Binary def complement GreaterThanOrEqualTo.new(operand1, operand2) end + + def operator; :< end end class Match < Binary def complement NotMatch.new(operand1, operand2) end + + def operator; :=~ end end class NotMatch < Binary def complement Match.new(operand1, operand2) end + + def eval(row) + operand1.eval(row) !~ operand2.eval(row) + end end class In < Binary def complement NotIn.new(operand1, operand2) end + + def eval(row) + operand2.eval(row).include?(operand1.eval(row)) + end end class NotIn < Binary def complement In.new(operand1, operand2) end + + def eval(row) + !(operand2.eval(row).include?(operand1.eval(row))) + end end end end diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb index 9e7193ef1353c..5a963e8ba1364 100644 --- a/lib/arel/engines/memory.rb +++ b/lib/arel/engines/memory.rb @@ -1,4 +1,3 @@ require 'arel/engines/memory/relations' require 'arel/engines/memory/primitives' require 'arel/engines/memory/engine' -require 'arel/engines/memory/predicates' diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb deleted file mode 100644 index 1527b04056311..0000000000000 --- a/lib/arel/engines/memory/predicates.rb +++ /dev/null @@ -1,99 +0,0 @@ -module Arel - module Predicates - class Binary < Unary - def eval(row) - operand1.eval(row).send(operator, operand2.eval(row)) - end - end - - class Unary < Predicate - def eval(row) - operand.eval(row).send(operator) - end - end - - class Not < Unary - def eval(row) - !operand.eval(row) - end - end - - class Polyadic < Predicate - def eval(row) - predicates.send(compounder) do |operation| - operation.eval(row) - end - end - end - - class Any < Polyadic - def compounder; :any? end - end - - class All < Polyadic - def compounder; :all? end - end - - class CompoundPredicate < Binary - def eval(row) - eval "operand1.eval(row) #{operator} operand2.eval(row)" - end - end - - class Or < CompoundPredicate - def operator; :or end - end - - class And < CompoundPredicate - def operator; :and end - end - - class Equality < Binary - def operator; :== end - end - - class Inequality < Equality - def eval(row) - operand1.eval(row) != operand2.eval(row) - end - end - - class GreaterThanOrEqualTo < Binary - def operator; :>= end - end - - class GreaterThan < Binary - def operator; :> end - end - - class LessThanOrEqualTo < Binary - def operator; :<= end - end - - class LessThan < Binary - def operator; :< end - end - - class Match < Binary - def operator; :=~ end - end - - class NotMatch < Binary - def eval(row) - operand1.eval(row) !~ operand2.eval(row) - end - end - - class In < Binary - def eval(row) - operand2.eval(row).include?(operand1.eval(row)) - end - end - - class NotIn < Binary - def eval(row) - !(operand2.eval(row).include?(operand1.eval(row))) - end - end - end -end From d657c3f102cd7d39df67ed396f111929c7056402 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 10:54:28 -0700 Subject: [PATCH 0466/1492] removing useless file --- lib/arel/algebra/relations.rb | 1 - lib/arel/algebra/relations/operations/alias.rb | 4 ---- 2 files changed, 5 deletions(-) delete mode 100644 lib/arel/algebra/relations/operations/alias.rb diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index 9481554667d64..9f438615cd0b0 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -4,7 +4,6 @@ require 'arel/algebra/relations/utilities/externalization' require 'arel/algebra/relations/row' require 'arel/algebra/relations/writes' -require 'arel/algebra/relations/operations/alias' require 'arel/algebra/relations/operations/from' require 'arel/algebra/relations/operations/group' require 'arel/algebra/relations/operations/having' diff --git a/lib/arel/algebra/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb deleted file mode 100644 index c5d23783e502c..0000000000000 --- a/lib/arel/algebra/relations/operations/alias.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Arel - class Alias < Compound - end -end From 72e76c1757b9fa08545e0340c3c684e836a4bceb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 10:58:40 -0700 Subject: [PATCH 0467/1492] removing more useless files --- lib/arel/engines/memory/relations/operations.rb | 2 ++ lib/arel/engines/sql/relations.rb | 1 - lib/arel/engines/sql/relations/operations/alias.rb | 5 ----- 3 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 lib/arel/engines/sql/relations/operations/alias.rb diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 75777a0c7fef1..d026db460d93f 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -45,6 +45,8 @@ def eval end class Alias < Compound + include Recursion::BaseCase + def eval unoperated_rows end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index afe6ac775ff32..981455760f681 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -6,5 +6,4 @@ require 'arel/engines/sql/relations/relation' require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' -require 'arel/engines/sql/relations/operations/alias' require 'arel/engines/sql/relations/writes' diff --git a/lib/arel/engines/sql/relations/operations/alias.rb b/lib/arel/engines/sql/relations/operations/alias.rb deleted file mode 100644 index 9b6a484463764..0000000000000 --- a/lib/arel/engines/sql/relations/operations/alias.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Arel - class Alias < Compound - include Recursion::BaseCase - end -end From 87b2f70fe143ec2abab5f3831ade706b3cf8707e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 11:49:54 -0700 Subject: [PATCH 0468/1492] removing unhelful organization --- lib/arel/algebra/predicates.rb | 66 ++++++++++++++++++ lib/arel/engines/sql.rb | 1 - lib/arel/engines/sql/predicates.rb | 103 ----------------------------- 3 files changed, 66 insertions(+), 104 deletions(-) delete mode 100644 lib/arel/engines/sql/predicates.rb diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 5b65b59c8c907..8d3aef9d1822f 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -53,6 +53,12 @@ def eval(row) operation.eval(row) end end + + def to_sql(formatter = nil) + "(" + + predicates.map {|p| p.to_sql(formatter)}.join(" #{predicate_sql} ") + + ")" + end end class Any < Polyadic @@ -61,6 +67,8 @@ def complement end def compounder; :any? end + + def predicate_sql; "OR" end end class All < Polyadic @@ -69,6 +77,8 @@ def complement end def compounder; :all? end + + def predicate_sql; "AND" end end class Unary < Predicate @@ -89,6 +99,10 @@ def == other def eval(row) operand.eval(row).send(operator) end + + def to_sql(formatter = nil) + "#{predicate_sql} (#{operand.to_sql(formatter)})" + end end class Not < Unary @@ -99,6 +113,8 @@ def complement def eval(row) !operand.eval(row) end + + def predicate_sql; "NOT" end end class Binary < Unary @@ -121,12 +137,23 @@ def bind(relation) def eval(row) operand1.eval(row).send(operator, operand2.eval(row)) end + + def to_sql(formatter = nil) + "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" + end + def to_sql(formatter = nil) + "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" + end end class CompoundPredicate < Binary def eval(row) eval "operand1.eval(row) #{operator} operand2.eval(row)" end + + def to_sql(formatter = nil) + "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + end end class And < CompoundPredicate @@ -135,13 +162,18 @@ def complement end def operator; :and end + + def predicate_sql; "AND" end end class Or < CompoundPredicate def complement And.new(operand1.complement, operand2.complement) end + def operator; :or end + + def predicate_sql; "OR" end end class Equality < Binary @@ -156,6 +188,10 @@ def complement end def operator; :== end + + def predicate_sql + operand2.equality_predicate_sql + end end class Inequality < Equality @@ -166,6 +202,10 @@ def complement def eval(row) operand1.eval(row) != operand2.eval(row) end + + def predicate_sql + operand2.inequality_predicate_sql + end end class GreaterThanOrEqualTo < Binary @@ -174,6 +214,8 @@ def complement end def operator; :>= end + + def predicate_sql; '>=' end end class GreaterThan < Binary @@ -182,6 +224,8 @@ def complement end def operator; :> end + + def predicate_sql; '>' end end class LessThanOrEqualTo < Binary @@ -190,6 +234,8 @@ def complement end def operator; :<= end + + def predicate_sql; '<=' end end class LessThan < Binary @@ -198,6 +244,8 @@ def complement end def operator; :< end + + def predicate_sql; '<' end end class Match < Binary @@ -206,6 +254,8 @@ def complement end def operator; :=~ end + + def predicate_sql; 'LIKE' end end class NotMatch < Binary @@ -216,6 +266,8 @@ def complement def eval(row) operand1.eval(row) !~ operand2.eval(row) end + + def predicate_sql; 'NOT LIKE' end end class In < Binary @@ -226,6 +278,18 @@ def complement def eval(row) operand2.eval(row).include?(operand1.eval(row)) end + + def to_sql(formatter = nil) + if operand2.is_a?(Range) && operand2.exclude_end? + GreaterThanOrEqualTo.new(operand1, operand2.begin).and( + LessThan.new(operand1, operand2.end) + ).to_sql(formatter) + else + super + end + end + + def predicate_sql; operand2.inclusion_predicate_sql end end class NotIn < Binary @@ -236,6 +300,8 @@ def complement def eval(row) !(operand2.eval(row).include?(operand1.eval(row))) end + + def predicate_sql; operand2.exclusion_predicate_sql end end end end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index a7721eb909445..686078826cf16 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -2,7 +2,6 @@ require 'arel/engines/sql/engine' require 'arel/engines/sql/relations' require 'arel/engines/sql/primitives' -require 'arel/engines/sql/predicates' require 'arel/engines/sql/formatters' require 'arel/engines/sql/core_extensions' require 'arel/engines/sql/christener' diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb deleted file mode 100644 index 74a36d77c97bd..0000000000000 --- a/lib/arel/engines/sql/predicates.rb +++ /dev/null @@ -1,103 +0,0 @@ -module Arel - module Predicates - class Binary < Unary - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" - end - end - - class Unary < Predicate - def to_sql(formatter = nil) - "#{predicate_sql} (#{operand.to_sql(formatter)})" - end - end - - class Not < Unary - def predicate_sql; "NOT" end - end - - class CompoundPredicate < Binary - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" - end - end - - class Or < CompoundPredicate - def predicate_sql; "OR" end - end - - class And < CompoundPredicate - def predicate_sql; "AND" end - end - - class Polyadic < Predicate - def to_sql(formatter = nil) - "(" + - predicates.map {|p| p.to_sql(formatter)}.join(" #{predicate_sql} ") + - ")" - end - end - - class Any < Polyadic - def predicate_sql; "OR" end - end - - class All < Polyadic - def predicate_sql; "AND" end - end - - class Equality < Binary - def predicate_sql - operand2.equality_predicate_sql - end - end - - class Inequality < Equality - def predicate_sql - operand2.inequality_predicate_sql - end - end - - class GreaterThanOrEqualTo < Binary - def predicate_sql; '>=' end - end - - class GreaterThan < Binary - def predicate_sql; '>' end - end - - class LessThanOrEqualTo < Binary - def predicate_sql; '<=' end - end - - class LessThan < Binary - def predicate_sql; '<' end - end - - class Match < Binary - def predicate_sql; 'LIKE' end - end - - class NotMatch < Binary - def predicate_sql; 'NOT LIKE' end - end - - class In < Binary - def to_sql(formatter = nil) - if operand2.is_a?(Range) && operand2.exclude_end? - GreaterThanOrEqualTo.new(operand1, operand2.begin).and( - LessThan.new(operand1, operand2.end) - ).to_sql(formatter) - else - super - end - end - - def predicate_sql; operand2.inclusion_predicate_sql end - end - - class NotIn < Binary - def predicate_sql; operand2.exclusion_predicate_sql end - end - end -end From 3f1ab2b977d921ed7f6cd4ec2e9204b8ad22148e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 13:32:25 -0700 Subject: [PATCH 0469/1492] removing more duplication --- lib/arel.rb | 1 + lib/arel/algebra/attributes/attribute.rb | 12 +++ lib/arel/algebra/expression.rb | 33 ++++++-- lib/arel/algebra/ordering.rb | 13 ++++ lib/arel/algebra/value.rb | 24 ++++++ lib/arel/engines/memory/primitives.rb | 14 ---- lib/arel/engines/sql.rb | 1 - lib/arel/engines/sql/primitives.rb | 97 ------------------------ lib/arel/sql_literal.rb | 13 ++++ 9 files changed, 90 insertions(+), 118 deletions(-) delete mode 100644 lib/arel/engines/sql/primitives.rb create mode 100644 lib/arel/sql_literal.rb diff --git a/lib/arel.rb b/lib/arel.rb index ae4240bf8a640..30b3faadf903a 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -5,6 +5,7 @@ module Arel require 'arel/algebra' + require 'arel/sql_literal' require 'arel/engines' require 'arel/version' diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 9206b228c8198..8a7993f284ee0 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -270,5 +270,17 @@ def typecast_error(value) end end include Types + + def column + original_relation.column_for(self) + end + + def format(object) + object.to_sql(Sql::Attribute.new(self)) + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self + end end end diff --git a/lib/arel/algebra/expression.rb b/lib/arel/algebra/expression.rb index 183de3c005cfb..5a93ca9735e7b 100644 --- a/lib/arel/algebra/expression.rb +++ b/lib/arel/algebra/expression.rb @@ -16,6 +16,10 @@ def aggregation? true end + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + module Transformations def as(aliaz) self.class.new(attribute, aliaz, self) @@ -32,11 +36,28 @@ def to_attribute(relation) include Transformations end - class Count < Expression; end - class Distinct < Expression; end - class Sum < Expression; end - class Maximum < Expression; end - class Minimum < Expression; end - class Average < Expression; end + class Count < Expression + def function_sql; 'COUNT' end + end + + class Distinct < Expression + def function_sql; 'DISTINCT' end + end + + class Sum < Expression + def function_sql; 'SUM' end + end + + class Maximum < Expression + def function_sql; 'MAX' end + end + + class Minimum < Expression + def function_sql; 'MIN' end + end + + class Average < Expression + def function_sql; 'AVG' end + end end diff --git a/lib/arel/algebra/ordering.rb b/lib/arel/algebra/ordering.rb index 984327aaf7061..8ed3e1e6e62b0 100644 --- a/lib/arel/algebra/ordering.rb +++ b/lib/arel/algebra/ordering.rb @@ -13,10 +13,23 @@ def to_ordering def == other super || (self.class === other && attribute == other.attribute) end + + def eval(row1, row2) + (attribute.eval(row1) <=> attribute.eval(row2)) * direction + end + + def to_sql(formatter = Sql::OrderClause.new(relation)) + formatter.ordering self + end end class Ascending < Ordering + def direction; 1 end + def direction_sql; 'ASC' end end + class Descending < Ordering + def direction_sql; 'DESC' end + def direction; -1 end end end diff --git a/lib/arel/algebra/value.rb b/lib/arel/algebra/value.rb index d9fc2e061c3f0..90787fa5eacf8 100644 --- a/lib/arel/algebra/value.rb +++ b/lib/arel/algebra/value.rb @@ -21,5 +21,29 @@ def bind(relation) def to_ordering self end + + def inclusion_predicate_sql + value.inclusion_predicate_sql + end + + def exclusion_predicate_sql + value.exclusion_predicate_sql + end + + def equality_predicate_sql + value.equality_predicate_sql + end + + def inequality_predicate_sql + value.inequality_predicate_sql + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.value value + end + + def format(object) + object.to_sql(Sql::Value.new(relation)) + end end end diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index 935b34f5ee490..0c9471fb49d1b 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -10,18 +10,4 @@ def eval(row) value end end - - class Ordering - def eval(row1, row2) - (attribute.eval(row1) <=> attribute.eval(row2)) * direction - end - end - - class Descending < Ordering - def direction; -1 end - end - - class Ascending < Ordering - def direction; 1 end - end end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index 686078826cf16..438d028606ead 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -1,7 +1,6 @@ require 'arel/engines/sql/attributes' require 'arel/engines/sql/engine' require 'arel/engines/sql/relations' -require 'arel/engines/sql/primitives' require 'arel/engines/sql/formatters' require 'arel/engines/sql/core_extensions' require 'arel/engines/sql/christener' diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb deleted file mode 100644 index 1b215d2b5467a..0000000000000 --- a/lib/arel/engines/sql/primitives.rb +++ /dev/null @@ -1,97 +0,0 @@ -module Arel - class SqlLiteral < String - def relation - nil - end - - def to_sql(formatter = nil) - self - end - - include Attribute::Expressions - end - - class Attribute - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - end - - class Value - def inclusion_predicate_sql - value.inclusion_predicate_sql - end - - def exclusion_predicate_sql - value.exclusion_predicate_sql - end - - def equality_predicate_sql - value.equality_predicate_sql - end - - def inequality_predicate_sql - value.inequality_predicate_sql - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.value value - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - end - - class Ordering - def to_sql(formatter = Sql::OrderClause.new(relation)) - formatter.ordering self - end - end - - class Ascending < Ordering - def direction_sql; 'ASC' end - end - - class Descending < Ordering - def direction_sql; 'DESC' end - end - - class Expression < Attribute - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - end - - class Count < Expression - def function_sql; 'COUNT' end - end - - class Distinct < Expression - def function_sql; 'DISTINCT' end - end - - class Sum < Expression - def function_sql; 'SUM' end - end - - class Maximum < Expression - def function_sql; 'MAX' end - end - - class Minimum < Expression - def function_sql; 'MIN' end - end - - class Average < Expression - def function_sql; 'AVG' end - end -end diff --git a/lib/arel/sql_literal.rb b/lib/arel/sql_literal.rb new file mode 100644 index 0000000000000..a98a9a058cfcb --- /dev/null +++ b/lib/arel/sql_literal.rb @@ -0,0 +1,13 @@ +module Arel + class SqlLiteral < String + def relation + nil + end + + def to_sql(formatter = nil) + self + end + + include Attribute::Expressions + end +end From c2023a2656319c509a5803c9fb71f288e713b0c9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 13:36:18 -0700 Subject: [PATCH 0470/1492] better organizing classes --- lib/arel/algebra/attributes/attribute.rb | 4 ++++ lib/arel/algebra/value.rb | 4 ++++ lib/arel/engines/memory.rb | 1 - lib/arel/engines/memory/primitives.rb | 13 ------------- 4 files changed, 8 insertions(+), 14 deletions(-) delete mode 100644 lib/arel/engines/memory/primitives.rb diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 8a7993f284ee0..0ad9382a52105 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -27,6 +27,10 @@ def aggregation? false end + def eval(row) + row[self] + end + module Transformations def self.included(klass) klass.send :alias_method, :eql?, :== diff --git a/lib/arel/algebra/value.rb b/lib/arel/algebra/value.rb index 90787fa5eacf8..70e94e0ad0fff 100644 --- a/lib/arel/algebra/value.rb +++ b/lib/arel/algebra/value.rb @@ -14,6 +14,10 @@ def == other relation == other.relation end + def eval(row) + value + end + def bind(relation) Value.new(value, relation) end diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb index 5a963e8ba1364..c0fdf6c5d6f31 100644 --- a/lib/arel/engines/memory.rb +++ b/lib/arel/engines/memory.rb @@ -1,3 +1,2 @@ require 'arel/engines/memory/relations' -require 'arel/engines/memory/primitives' require 'arel/engines/memory/engine' diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb deleted file mode 100644 index 0c9471fb49d1b..0000000000000 --- a/lib/arel/engines/memory/primitives.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - class Attribute - def eval(row) - row[self] - end - end - - class Value - def eval(row) - value - end - end -end From 58629d6b95818b7e9e9fa377a4a2729a9f9b9eef Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 13:42:49 -0700 Subject: [PATCH 0471/1492] removing unused code --- lib/arel/algebra/relations/utilities/compound.rb | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 34f80b9e56e95..7edbff3a3145a 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -7,12 +7,6 @@ class Compound :column_for, :sources, :locked, :table_alias, :to => :relation - def self.requires(feature = nil) - @requires ||= nil - @requires = feature if feature - @requires - end - def initialize relation @relation = relation end @@ -38,15 +32,7 @@ def eql?(other) end def engine - requires = self.class.requires - engine = relation.engine - - # Temporary check of whether or not the engine supports where. - if requires && engine.respond_to?(:supports) && !engine.supports(requires) - Memory::Engine.new - else - engine - end + relation.engine end private From 91a66677fa6d3962ad5ab9fd49a9c8bc1cf97ef0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 13:45:33 -0700 Subject: [PATCH 0472/1492] initializing ivars --- lib/arel/algebra/relations/utilities/compound.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 7edbff3a3145a..17960081176fa 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -9,6 +9,7 @@ class Compound def initialize relation @relation = relation + @attributes = nil end [:wheres, :groupings, :orders, :havings, :projections].each do |operation_name| From 7e4e37eae9ce82d42a10de2917bc97529fa4a4b3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 13:51:54 -0700 Subject: [PATCH 0473/1492] reducing files --- lib/arel/algebra/relations/utilities/compound.rb | 6 +++++- lib/arel/engines/memory/relations.rb | 1 - lib/arel/engines/memory/relations/compound.rb | 9 --------- 3 files changed, 5 insertions(+), 11 deletions(-) delete mode 100644 lib/arel/engines/memory/relations/compound.rb diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 17960081176fa..31b2159883f8c 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -4,7 +4,7 @@ class Compound attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :sources, :locked, :table_alias, + :column_for, :sources, :locked, :table_alias, :array, :to => :relation def initialize relation @@ -24,6 +24,10 @@ def attributes @attributes ||= relation.attributes.bind(self) end + def unoperated_rows + relation.call.collect { |row| row.bind(self) } + end + def hash @hash ||= :relation.hash end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index c67af2d63ba61..2ab56adb3b8cf 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,5 +1,4 @@ require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' require 'arel/engines/memory/relations/writes' -require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb deleted file mode 100644 index 0f3c24f9ece3e..0000000000000 --- a/lib/arel/engines/memory/relations/compound.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - class Compound - delegate :array, :to => :relation - - def unoperated_rows - relation.call.collect { |row| row.bind(self) } - end - end -end From 29fea82cc67259974a78a5ca8872bd515c9042ae Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 14:13:00 -0700 Subject: [PATCH 0474/1492] more class organizing --- lib/arel/algebra/relations/operations/join.rb | 6 ---- .../algebra/relations/operations/order.rb | 7 ++++ .../algebra/relations/operations/project.rb | 4 +++ lib/arel/algebra/relations/operations/skip.rb | 4 +++ lib/arel/algebra/relations/operations/take.rb | 4 +++ .../algebra/relations/operations/where.rb | 4 +++ lib/arel/algebra/relations/relation.rb | 4 +++ .../engines/memory/relations/operations.rb | 33 ------------------- 8 files changed, 27 insertions(+), 39 deletions(-) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index dd67e8a9bf2cc..9eee84113a6ee 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -70,10 +70,4 @@ def engine relation1.engine end end - - module Relation - def join? - false - end - end end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 582abf642cf2e..94bd7bcd598d6 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -31,5 +31,12 @@ def engine engine end end + + def eval + unoperated_rows.sort do |row1, row2| + ordering = orders.detect { |o| o.eval(row1, row2) != 0 } || orders.last + ordering.eval(row1, row2) + end + end end end diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 2cdae288e3c66..daca7420390c4 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -22,5 +22,9 @@ def == other relation == other.relation && projections == other.projections end + + def eval + unoperated_rows.collect { |r| r.slice(*projections) } + end end end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index f6a58d15bdd04..5a87fbb7b5225 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -24,5 +24,9 @@ def engine engine end end + + def eval + unoperated_rows[skipped..-1] + end end end diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index 964aacacca577..7098d578d5def 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -28,5 +28,9 @@ def engine def externalizable? true end + + def eval + unoperated_rows[0, taken] + end end end diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index e8db2ec8b09cd..b447b18809960 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -30,5 +30,9 @@ def engine engine end end + + def eval + unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } } + end end end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 3ed3a43503a45..17a2cf3190a73 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -6,6 +6,10 @@ def session Session.instance end + def join? + false + end + def call engine.read(self) end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index d026db460d93f..f233c48db0ee3 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -1,37 +1,4 @@ module Arel - class Where < Compound - def eval - unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } } - end - end - - class Order < Compound - def eval - unoperated_rows.sort do |row1, row2| - ordering = orders.detect { |o| o.eval(row1, row2) != 0 } || orders.last - ordering.eval(row1, row2) - end - end - end - - class Project < Compound - def eval - unoperated_rows.collect { |r| r.slice(*projections) } - end - end - - class Take < Compound - def eval - unoperated_rows[0, taken] - end - end - - class Skip < Compound - def eval - unoperated_rows[skipped..-1] - end - end - class From < Compound def eval unoperated_rows[sources..-1] From 700cc8418800911aaab75e2ec1478ee958ef4df8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 14:15:37 -0700 Subject: [PATCH 0475/1492] more class organization --- .../algebra/relations/operations/group.rb | 4 ++++ lib/arel/algebra/relations/operations/join.rb | 13 ++++++++++++ .../engines/memory/relations/operations.rb | 21 ------------------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 68c626e917985..af0d3c680868b 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -14,5 +14,9 @@ def == other @relation == other.relation && @groupings == other.groupings end + + def eval + raise NotImplementedError + end end end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 9eee84113a6ee..5d19873f623a7 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -53,6 +53,19 @@ def == other # FIXME remove this. :'( alias :eql? :== + + def eval + result = [] + relation1.call.each do |row1| + relation2.call.each do |row2| + combined_row = row1.combine(row2, self) + if predicates.all? { |p| p.eval(combined_row) } + result << combined_row + end + end + end + result + end end class InnerJoin < Join; end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index f233c48db0ee3..8ab6f08ab0ce1 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -5,12 +5,6 @@ def eval end end - class Group < Compound - def eval - raise NotImplementedError - end - end - class Alias < Compound include Recursion::BaseCase @@ -18,19 +12,4 @@ def eval unoperated_rows end end - - class Join - def eval - result = [] - relation1.call.each do |row1| - relation2.call.each do |row2| - combined_row = row1.combine(row2, self) - if predicates.all? { |p| p.eval(combined_row) } - result << combined_row - end - end - end - result - end - end end From d2092e7e0bb5260bd02d9eeea4decf7efa34e29c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 14:23:13 -0700 Subject: [PATCH 0476/1492] reorganizing classes --- lib/arel/algebra/relations/relation.rb | 70 +++++++++++++++++++ .../relations/utilities/externalization.rb | 10 --- lib/arel/engines/sql/relations.rb | 1 - lib/arel/engines/sql/relations/relation.rb | 65 ----------------- 4 files changed, 70 insertions(+), 76 deletions(-) delete mode 100644 lib/arel/engines/sql/relations/relation.rb diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 17a2cf3190a73..3f6151e27b6a6 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -1,5 +1,7 @@ module Arel module Relation + @@connection_tables_primary_keys = {} + attr_reader :count def session @@ -18,6 +20,74 @@ def bind(relation) self end + def externalize + @externalized ||= externalizable?? Externalization.new(self) : self + end + + def externalizable? + false + end + + def compiler + @compiler ||= begin + "Arel::SqlCompiler::#{engine.adapter_name}Compiler".constantize.new(self) + rescue + Arel::SqlCompiler::GenericCompiler.new(self) + end + end + + def to_sql(formatter = Sql::SelectStatement.new(self)) + formatter.select compiler.select_sql, self + end + + def christener + @christener ||= Sql::Christener.new + end + + def inclusion_predicate_sql + "IN" + end + + def exclusion_predicate_sql + "NOT IN" + end + + def primary_key + connection_id = engine.connection.object_id + if @@connection_tables_primary_keys[connection_id] && @@connection_tables_primary_keys[connection_id].has_key?(table.name) + @@connection_tables_primary_keys[connection_id][table.name] + else + @@connection_tables_primary_keys[connection_id] ||= {} + @@connection_tables_primary_keys[connection_id][table.name] = engine.connection.primary_key(table.name) + end + end + + protected + + def from_clauses + sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources + end + + def select_clauses + attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } + end + + def where_clauses + wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } + end + + def group_clauses + groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } + end + + def having_clauses + havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } + end + + def order_clauses + orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } + end + module Enumerable include ::Enumerable diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index c7a7d9ca78892..815e1e0aa7770 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -12,14 +12,4 @@ def attributes @attributes ||= Header.new(relation.attributes.map { |a| a.to_attribute(self) }) end end - - module Relation - def externalize - @externalized ||= externalizable?? Externalization.new(self) : self - end - - def externalizable? - false - end - end end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 981455760f681..1dea1423b8a61 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -3,7 +3,6 @@ require 'arel/engines/sql/relations/utilities/externalization' require 'arel/engines/sql/relations/utilities/nil' require 'arel/engines/sql/relations/compiler' -require 'arel/engines/sql/relations/relation' require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' require 'arel/engines/sql/relations/writes' diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb deleted file mode 100644 index 2136f85e5a52b..0000000000000 --- a/lib/arel/engines/sql/relations/relation.rb +++ /dev/null @@ -1,65 +0,0 @@ -module Arel - module Relation - @@connection_tables_primary_keys = {} - - def compiler - @compiler ||= begin - "Arel::SqlCompiler::#{engine.adapter_name}Compiler".constantize.new(self) - rescue - Arel::SqlCompiler::GenericCompiler.new(self) - end - end - - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select compiler.select_sql, self - end - - def christener - @christener ||= Sql::Christener.new - end - - def inclusion_predicate_sql - "IN" - end - - def exclusion_predicate_sql - "NOT IN" - end - - def primary_key - connection_id = engine.connection.object_id - if @@connection_tables_primary_keys[connection_id] && @@connection_tables_primary_keys[connection_id].has_key?(table.name) - @@connection_tables_primary_keys[connection_id][table.name] - else - @@connection_tables_primary_keys[connection_id] ||= {} - @@connection_tables_primary_keys[connection_id][table.name] = engine.connection.primary_key(table.name) - end - end - - protected - - def from_clauses - sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources - end - - def select_clauses - attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } - end - - def where_clauses - wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } - end - - def group_clauses - groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } - end - - def having_clauses - havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } - end - - def order_clauses - orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } - end - end -end From 82e0b8dd85a82fc9907f96bb1af849453a87b01a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 14:29:21 -0700 Subject: [PATCH 0477/1492] reorganizing more classes --- lib/arel/algebra/relations/writes.rb | 16 ++++++++++++++++ lib/arel/engines/memory/relations.rb | 2 -- lib/arel/engines/memory/relations/writes.rb | 7 ------- lib/arel/engines/sql/relations.rb | 1 - lib/arel/engines/sql/relations/writes.rb | 19 ------------------- 5 files changed, 16 insertions(+), 29 deletions(-) delete mode 100644 lib/arel/engines/memory/relations/writes.rb delete mode 100644 lib/arel/engines/sql/relations/writes.rb diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb index 17da2b172b8d7..8cf7a7cdad1d6 100644 --- a/lib/arel/algebra/relations/writes.rb +++ b/lib/arel/algebra/relations/writes.rb @@ -9,6 +9,10 @@ class Deletion < Action def call engine.delete(self) end + + def to_sql + compiler.delete_sql + end end class Insert < Action @@ -26,6 +30,14 @@ def call def == other super && @record == other.record end + + def eval + unoperated_rows + [Row.new(self, record.values.collect(&:value))] + end + + def to_sql(include_returning = true) + compiler.insert_sql(include_returning) + end end class Update < Insert @@ -34,5 +46,9 @@ class Update < Insert def call engine.update(self) end + + def to_sql + compiler.update_sql + end end end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 2ab56adb3b8cf..046017d78acb1 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,4 +1,2 @@ require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' -require 'arel/engines/memory/relations/writes' - diff --git a/lib/arel/engines/memory/relations/writes.rb b/lib/arel/engines/memory/relations/writes.rb deleted file mode 100644 index 39c1170ddc496..0000000000000 --- a/lib/arel/engines/memory/relations/writes.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Insert < Action - def eval - unoperated_rows + [Row.new(self, record.values.collect(&:value))] - end - end -end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 1dea1423b8a61..b6098a6e42557 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -5,4 +5,3 @@ require 'arel/engines/sql/relations/compiler' require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' -require 'arel/engines/sql/relations/writes' diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb deleted file mode 100644 index 50a2ce2e99186..0000000000000 --- a/lib/arel/engines/sql/relations/writes.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Deletion < Action - def to_sql - compiler.delete_sql - end - end - - class Insert < Action - def to_sql(include_returning = true) - compiler.insert_sql(include_returning) - end - end - - class Update < Insert - def to_sql - compiler.update_sql - end - end -end From 66cedcc76bf8ac97a65bf12f6b7dd2eea83ebfe3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 14:55:59 -0700 Subject: [PATCH 0478/1492] reorganizing classes more --- lib/arel.rb | 2 ++ .../algebra/relations/utilities/externalization.rb | 11 +++++++++++ lib/arel/engines/sql/relations.rb | 2 -- .../sql/relations/utilities/externalization.rb | 14 -------------- .../engines/sql/relations/utilities/recursion.rb | 13 ------------- 5 files changed, 13 insertions(+), 29 deletions(-) delete mode 100644 lib/arel/engines/sql/relations/utilities/externalization.rb delete mode 100644 lib/arel/engines/sql/relations/utilities/recursion.rb diff --git a/lib/arel.rb b/lib/arel.rb index 30b3faadf903a..92a82b695bb4d 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -3,6 +3,8 @@ require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/blank' +require 'arel/recursion/base_case' + module Arel require 'arel/algebra' require 'arel/sql_literal' diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index 815e1e0aa7770..8e97573f68d91 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -1,5 +1,7 @@ module Arel class Externalization < Compound + include Recursion::BaseCase + def == other super || Externalization === other && relation == other.relation end @@ -11,5 +13,14 @@ def wheres def attributes @attributes ||= Header.new(relation.attributes.map { |a| a.to_attribute(self) }) end + + def table_sql(formatter = Sql::TableReference.new(relation)) + formatter.select relation.compiler.select_sql, self + end + + # REMOVEME + def name + relation.name + '_external' + end end end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index b6098a6e42557..c29739ef7fe97 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -1,6 +1,4 @@ require 'arel/engines/sql/relations/utilities/compound' -require 'arel/engines/sql/relations/utilities/recursion' -require 'arel/engines/sql/relations/utilities/externalization' require 'arel/engines/sql/relations/utilities/nil' require 'arel/engines/sql/relations/compiler' require 'arel/engines/sql/relations/table' diff --git a/lib/arel/engines/sql/relations/utilities/externalization.rb b/lib/arel/engines/sql/relations/utilities/externalization.rb deleted file mode 100644 index a0230e90f302c..0000000000000 --- a/lib/arel/engines/sql/relations/utilities/externalization.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Externalization < Compound - include Recursion::BaseCase - - def table_sql(formatter = Sql::TableReference.new(relation)) - formatter.select relation.compiler.select_sql, self - end - - # REMOVEME - def name - relation.name + '_external' - end - end -end diff --git a/lib/arel/engines/sql/relations/utilities/recursion.rb b/lib/arel/engines/sql/relations/utilities/recursion.rb deleted file mode 100644 index 84a526f57c7dd..0000000000000 --- a/lib/arel/engines/sql/relations/utilities/recursion.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Recursion - module BaseCase - def table - self - end - - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self - end - end - end -end From d41b9c54aaafb852ff2e4fbba56962cb3eeb1837 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 14:59:46 -0700 Subject: [PATCH 0479/1492] more class reorganization --- lib/arel/algebra/relations/operations/join.rb | 30 +++++++++++++++-- lib/arel/engines/sql/relations.rb | 1 - .../engines/sql/relations/operations/join.rb | 33 ------------------- lib/arel/recursion/base_case.rb | 13 ++++++++ 4 files changed, 41 insertions(+), 36 deletions(-) delete mode 100644 lib/arel/engines/sql/relations/operations/join.rb create mode 100644 lib/arel/recursion/base_case.rb diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 5d19873f623a7..83ebfc129fcda 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -44,6 +44,22 @@ def engine relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine end + def table_sql(formatter = Sql::TableReference.new(self)) + relation1.externalize.table_sql(formatter) + end + + def joins(environment, formatter = Sql::TableReference.new(environment)) + @joins ||= begin + this_join = [ + join_sql, + relation2.externalize.table_sql(formatter), + ("ON" unless predicates.blank?), + (ons + relation2.externalize.wheres).collect { |p| p.bind(environment.relation).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + ].compact.join(" ") + [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") + end + end + def == other super || Join === other && relation1 == other.relation1 && @@ -68,9 +84,19 @@ def eval end end - class InnerJoin < Join; end - class OuterJoin < Join; end + class InnerJoin < Join + def join_sql; "INNER JOIN" end + end + + class OuterJoin < Join + def join_sql; "LEFT OUTER JOIN" end + end + class StringJoin < Join + def joins(environment, formatter = Sql::TableReference.new(environment)) + [relation1.joins(environment), relation2].compact.join(" ") + end + def externalizable? relation1.externalizable? end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index c29739ef7fe97..c6926834215a1 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -2,4 +2,3 @@ require 'arel/engines/sql/relations/utilities/nil' require 'arel/engines/sql/relations/compiler' require 'arel/engines/sql/relations/table' -require 'arel/engines/sql/relations/operations/join' diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb deleted file mode 100644 index 97336573655d2..0000000000000 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ /dev/null @@ -1,33 +0,0 @@ -module Arel - class Join - def table_sql(formatter = Sql::TableReference.new(self)) - relation1.externalize.table_sql(formatter) - end - - def joins(environment, formatter = Sql::TableReference.new(environment)) - @joins ||= begin - this_join = [ - join_sql, - relation2.externalize.table_sql(formatter), - ("ON" unless predicates.blank?), - (ons + relation2.externalize.wheres).collect { |p| p.bind(environment.relation).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') - ].compact.join(" ") - [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") - end - end - end - - class InnerJoin < Join - def join_sql; "INNER JOIN" end - end - - class OuterJoin < Join - def join_sql; "LEFT OUTER JOIN" end - end - - class StringJoin < Join - def joins(environment, formatter = Sql::TableReference.new(environment)) - [relation1.joins(environment), relation2].compact.join(" ") - end - end -end diff --git a/lib/arel/recursion/base_case.rb b/lib/arel/recursion/base_case.rb new file mode 100644 index 0000000000000..84a526f57c7dd --- /dev/null +++ b/lib/arel/recursion/base_case.rb @@ -0,0 +1,13 @@ +module Arel + module Recursion + module BaseCase + def table + self + end + + def table_sql(formatter = Sql::TableReference.new(self)) + formatter.table self + end + end + end +end From 9b316874243152db47b6127372c51d4c6e97ebea Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 15:02:24 -0700 Subject: [PATCH 0480/1492] more class reorganization --- lib/arel/algebra/relations/operations/from.rb | 4 ++++ lib/arel/engines/memory/relations/operations.rb | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/relations/operations/from.rb b/lib/arel/algebra/relations/operations/from.rb index fbddb4234fbdc..3ebfb10cb21b3 100644 --- a/lib/arel/algebra/relations/operations/from.rb +++ b/lib/arel/algebra/relations/operations/from.rb @@ -6,5 +6,9 @@ def initialize relation, sources super(relation) @sources = sources end + + def eval + unoperated_rows[sources..-1] + end end end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 8ab6f08ab0ce1..2269fadf721fd 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -1,10 +1,4 @@ module Arel - class From < Compound - def eval - unoperated_rows[sources..-1] - end - end - class Alias < Compound include Recursion::BaseCase From 21cf9e4a7214a97fa2c81c84cd970aac30311dda Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 15:10:11 -0700 Subject: [PATCH 0481/1492] removing cattr_accessor --- lib/arel.rb | 1 - lib/arel/engines/sql/relations/table.rb | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index 92a82b695bb4d..857a7f651b213 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,5 +1,4 @@ require 'active_support/inflector' -require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/object/blank' diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index c83ce1e5e9662..94843ec62d20b 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -2,7 +2,16 @@ module Arel class Table include Relation, Recursion::BaseCase - cattr_accessor :engine, :tables + @@engine = nil + @@tables = nil + class << self # FIXME: Do we really need these? + def engine; @@engine; end + def engine= e; @@engine = e; end + + def tables; @@tables; end + def tables= e; @@tables = e; end + end + attr_reader :name, :engine, :table_alias, :options def initialize(name, options = {}) From 4104de6a11c022e82a0fedd786cf39bc6c7bb62f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 16:35:15 -0700 Subject: [PATCH 0482/1492] PERF: cache christener, initialize hash in initialize --- lib/arel/algebra/relations/operations/join.rb | 1 + lib/arel/engines/sql/christener.rb | 13 +++++++++---- lib/arel/engines/sql/formatters.rb | 5 +++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 83ebfc129fcda..72b4c9b8fe1bd 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -8,6 +8,7 @@ def initialize(relation1, relation2 = Nil.instance, *predicates) @relation1 = relation1 @relation2 = relation2 @predicates = predicates + @attributes = nil end def name diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index a2a2da799a9dc..2c96020554292 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -1,13 +1,18 @@ module Arel module Sql class Christener - def name_for(relation) - @used_names ||= Hash.new(0) - (@relation_names ||= Hash.new do |hash, relation| + def initialize + # FIXME: this exists because all objects hash the same. :'( + @used_names = Hash.new(0) + @relation_names = Hash.new do |hash, relation| name = relation.table_alias ? relation.table_alias : relation.name @used_names[name] += 1 hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') - end)[relation.table] + end + end + + def name_for(relation) + @relation_names[relation.table] end end end diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index cdbda5ea33ee5..de8278479d76d 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -1,13 +1,14 @@ module Arel module Sql class Formatter - attr_reader :environment - delegate :christener, :engine, :to => :environment + attr_reader :environment, :christener + delegate :engine, :to => :environment delegate :name_for, :to => :christener delegate :quote_table_name, :quote_column_name, :quote, :to => :engine def initialize(environment) @environment = environment + @christener = environment.christener end end From 07a803c9f607b938f004b4adb6fe9abbad6fc8c4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 17:11:30 -0700 Subject: [PATCH 0483/1492] PERF: removing *args calls, do not call send on protected methods then they are public methods --- lib/arel/algebra/relations/relation.rb | 38 ++++++++++------------ lib/arel/engines/sql/relations/compiler.rb | 27 ++++++++++----- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 3f6151e27b6a6..b89abd5b8a1b2 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -62,31 +62,29 @@ def primary_key end end - protected - - def from_clauses - sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources - end + def select_clauses + attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } + end - def select_clauses - attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } - end + def from_clauses + sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources + end - def where_clauses - wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } - end + def where_clauses + wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } + end - def group_clauses - groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } - end + def group_clauses + groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } + end - def having_clauses - havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } - end + def having_clauses + havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } + end - def order_clauses - orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } - end + def order_clauses + orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } + end module Enumerable include ::Enumerable diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index dfc2489e77123..abd0d0abfdc1a 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -13,21 +13,30 @@ def select_sql subquery = build_query("SELECT 1 FROM #{from_clauses}", build_clauses) query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery" else - query = build_query \ - "SELECT #{select_clauses.join(', ')}", - "FROM #{from_clauses}", + query = [ + "SELECT #{relation.select_clauses.join(', ')}", + "FROM #{relation.from_clauses}", build_clauses + ].compact.join ' ' end query end def build_clauses - clauses = build_query "", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join(' AND ')}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ), - ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ) + joins = joins(self) + wheres = relation.where_clauses + groups = relation.group_clauses + havings = relation.having_clauses + orders = relation.order_clauses + + clauses = [ "", + joins, + ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?), + ("GROUP BY #{groups.join(', ')}" unless groups.empty?), + ("HAVING #{havings.join(' AND ')}" unless havings.empty?), + ("ORDER BY #{orders.join(', ')}" unless orders.empty?) + ].compact.join ' ' + engine.add_limit_offset!(clauses,{ :limit => taken, :offset => skipped }) if taken || skipped clauses << " #{locked}" unless locked.blank? clauses unless clauses.blank? From 4d625d6bd9b56907dcedf14590d0edd083260f0c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 17:23:13 -0700 Subject: [PATCH 0484/1492] PERF: symbol to proc is slow, lets remove it --- lib/arel/algebra/relations/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index b89abd5b8a1b2..34d798837c446 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -120,7 +120,7 @@ def outer_join(other_relation = nil) }.each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments, &block) - arguments.all?(&:blank?) && !block_given? ? + arguments.all? { |x| x.blank? } && !block_given? ? self : #{operation_name.capitalize}.new(self, *arguments, &block) end OPERATION From ae6a14251462597ca13f255c02307f5308062214 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 17:32:36 -0700 Subject: [PATCH 0485/1492] PERF: a block is never given to this method, so stop checking --- lib/arel/algebra/relations/relation.rb | 6 +++--- lib/arel/algebra/relations/utilities/compound.rb | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 34d798837c446..b3dccaf8be218 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -119,9 +119,9 @@ def outer_join(other_relation = nil) where project order take skip group from having }.each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ - def #{operation_name}(*arguments, &block) - arguments.all? { |x| x.blank? } && !block_given? ? - self : #{operation_name.capitalize}.new(self, *arguments, &block) + def #{operation_name}(*arguments) + arguments.all? { |x| x.blank? } ? + self : #{operation_name.capitalize}.new(self, *arguments) end OPERATION end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 31b2159883f8c..dbd9af9d3d217 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -28,6 +28,7 @@ def unoperated_rows relation.call.collect { |row| row.bind(self) } end + # FIXME: remove this. :'( def hash @hash ||= :relation.hash end From c9d025261c14a1972bbad92796e1ba6adcc97d2b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 26 Jul 2010 17:43:22 -0700 Subject: [PATCH 0486/1492] PERF: caching engine, fewer calls to method_missing --- lib/arel/engines/sql/relations/compiler.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index abd0d0abfdc1a..05a071b4bfd5b 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -5,6 +5,7 @@ class GenericCompiler def initialize(relation) @relation = relation + @engine = relation.engine end def select_sql @@ -37,7 +38,11 @@ def build_clauses ("ORDER BY #{orders.join(', ')}" unless orders.empty?) ].compact.join ' ' - engine.add_limit_offset!(clauses,{ :limit => taken, :offset => skipped }) if taken || skipped + offset = relation.skipped + limit = relation.taken + @engine.add_limit_offset!(clauses, :limit => limit, + :offset => offset) if offset || limit + clauses << " #{locked}" unless locked.blank? clauses unless clauses.blank? end From 9b5ca7a78f53da1ba1a817041e1c78ae673887a0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 14:44:06 -0700 Subject: [PATCH 0487/1492] PERF: avoiding more method missing --- lib/arel/engines/sql/formatters.rb | 23 +++++++++++++++++++--- lib/arel/engines/sql/relations/compiler.rb | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index de8278479d76d..2597beba9529f 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -2,14 +2,31 @@ module Arel module Sql class Formatter attr_reader :environment, :christener - delegate :engine, :to => :environment - delegate :name_for, :to => :christener - delegate :quote_table_name, :quote_column_name, :quote, :to => :engine def initialize(environment) @environment = environment @christener = environment.christener end + + def name_for thing + @christener.name_for thing + end + + def engine + @environment.engine + end + + def quote_column_name name + engine.connection.quote_column_name name + end + + def quote_table_name name + engine.connection.quote_column_name name + end + + def quote value, column = nil + engine.connection.quote value, column + end end class SelectClause < Formatter diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 05a071b4bfd5b..2941fc2a06dfc 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -40,7 +40,7 @@ def build_clauses offset = relation.skipped limit = relation.taken - @engine.add_limit_offset!(clauses, :limit => limit, + @engine.connection.add_limit_offset!(clauses, :limit => limit, :offset => offset) if offset || limit clauses << " #{locked}" unless locked.blank? From 1f25ba3786ff6aaa1e04e038a84acafa4138ee17 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 15:26:12 -0700 Subject: [PATCH 0488/1492] PERF: eliminating method_missing --- lib/arel/engines/sql/compilers/oracle_compiler.rb | 10 +++++----- lib/arel/engines/sql/compilers/postgresql_compiler.rb | 2 +- lib/arel/engines/sql/engine.rb | 8 -------- lib/arel/engines/sql/relations/compiler.rb | 8 ++++---- lib/arel/engines/sql/relations/table.rb | 4 ++-- spec/engines/sql/unit/engine_spec.rb | 7 ------- 6 files changed, 12 insertions(+), 27 deletions(-) diff --git a/lib/arel/engines/sql/compilers/oracle_compiler.rb b/lib/arel/engines/sql/compilers/oracle_compiler.rb index 66a91cecb5fb9..1963454d369a7 100644 --- a/lib/arel/engines/sql/compilers/oracle_compiler.rb +++ b/lib/arel/engines/sql/compilers/oracle_compiler.rb @@ -16,7 +16,7 @@ def select_sql # when limit or offset subquery is used then cannot use FOR UPDATE directly # and need to construct separate subquery for primary key if use_subquery_for_lock = limit_or_offset && !locked.blank? - quoted_primary_key = engine.quote_column_name(primary_key) + quoted_primary_key = engine.connection.quote_column_name(primary_key) end select_attributes_string = use_subquery_for_lock ? quoted_primary_key : select_clauses.join(', ') @@ -39,7 +39,7 @@ def select_sql ("ORDER BY #{order_clauses_array.join(', ')}" unless order_clauses_array.blank? ) # Use existing method from oracle_enhanced adapter to implement limit and offset using subqueries - engine.add_limit_offset!(query, :limit => taken, :offset => skipped) if limit_or_offset + engine.connection.add_limit_offset!(query, :limit => taken, :offset => skipped) if limit_or_offset if use_subquery_for_lock build_query \ @@ -83,10 +83,10 @@ def build_update_conditions_sql def limited_update_conditions(conditions, taken) # need to add ORDER BY only if just taken ones should be updated conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? - quoted_primary_key = engine.quote_column_name(primary_key) - subquery = "SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions}" + quoted_primary_key = engine.connection.quote_column_name(primary_key) + subquery = "SELECT #{quoted_primary_key} FROM #{engine.connection.connection.quote_table_name table.name} #{conditions}" # Use existing method from oracle_enhanced adapter to get taken records when ORDER BY is used - engine.add_limit_offset!(subquery, :limit => taken) unless orders.blank? + engine.connection.add_limit_offset!(subquery, :limit => taken) unless orders.blank? "WHERE #{quoted_primary_key} IN (#{subquery})" end diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb index 1f6e74d57a648..3f814255e9ade 100644 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -35,7 +35,7 @@ def aliased_orders(orders) end def supports_insert_with_returning? - engine.postgresql_version >= 80200 + engine.connection.send(:postgresql_version) >= 80200 end end end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 8504fec3c51af..7e841d68bb2fd 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -19,14 +19,6 @@ def adapter_name end end - def method_missing(method, *args) - if block_given? - connection.send(method, *args) { |*block_args| yield(*block_args) } - else - connection.send(method, *args) - end - end - def create(relation) primary_key_value = if relation.primary_key.blank? nil diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 2941fc2a06dfc..9691c8518c65a 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -68,7 +68,7 @@ def insert_sql(include_returning = true) end first = attributes.collect do |key| - engine.quote_column_name(key.name) + engine.connection.quote_column_name(key.name) end.join(', ') second = attributes.collect do |key| @@ -82,7 +82,7 @@ def insert_sql(include_returning = true) "INSERT", "INTO #{table_sql}", insertion_attributes_values_sql, - ("RETURNING #{engine.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?) + ("RETURNING #{engine.connection.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?) end def supports_insert_with_returning? @@ -117,7 +117,7 @@ def assignment_sql attributes.map do |attribute| value = assignments[attribute] - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + "#{engine.connection.quote_column_name(attribute.name)} = #{attribute.format(value)}" end.join(", ") else assignments.value @@ -138,7 +138,7 @@ def build_update_conditions_sql def limited_update_conditions(conditions, taken) conditions << " LIMIT #{taken}" - quoted_primary_key = engine.quote_column_name(primary_key) + quoted_primary_key = engine.connection.quote_column_name(primary_key) "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 94843ec62d20b..236a36c7a78de 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -42,7 +42,7 @@ def initialize(name, options = {}) end end - @@tables ||= engine.tables + @@tables ||= engine.connection.tables end end @@ -85,7 +85,7 @@ def column_for(attribute) end def columns - @columns ||= engine.columns(name, "#{name} Columns") + @columns ||= engine.connection.columns(name, "#{name} Columns") end def reset diff --git a/spec/engines/sql/unit/engine_spec.rb b/spec/engines/sql/unit/engine_spec.rb index 85a9dc5bfb104..9d3c41ccc0664 100644 --- a/spec/engines/sql/unit/engine_spec.rb +++ b/spec/engines/sql/unit/engine_spec.rb @@ -17,13 +17,6 @@ def method_missing name, *args, &block end describe "method missing" do - it "should pass through" do - conn = FakeConnection.new - engine = Arel::Sql::Engine.new FakeAR.new conn - engine.foo - conn.called.should == [[:foo, [], nil]] - end - it "should ask for a connection" do conn = FakeConnection.new ar = FakeAR.new conn From e2578f1289f34ab53153a6b94252b61745a80961 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 16:10:42 -0700 Subject: [PATCH 0489/1492] PERF: removing more method missing --- .../sql/compilers/postgresql_compiler.rb | 4 +- lib/arel/engines/sql/relations/compiler.rb | 64 ++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb index 3f814255e9ade..250d582545f6f 100644 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -3,7 +3,7 @@ module SqlCompiler class PostgreSQLCompiler < GenericCompiler def select_sql - if !orders.blank? && using_distinct_on? + if !relation.orders.blank? && using_distinct_on? subquery = build_query \ "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", "FROM #{from_clauses}", @@ -24,7 +24,7 @@ def select_sql end def using_distinct_on? - select_clauses.any? { |x| x =~ /DISTINCT ON/ } + relation.select_clauses.any? { |x| x =~ /DISTINCT ON/ } end def aliased_orders(orders) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 9691c8518c65a..2fb4c7841e0e6 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -1,17 +1,21 @@ module Arel module SqlCompiler class GenericCompiler - attr_reader :relation + attr_reader :relation, :engine def initialize(relation) @relation = relation @engine = relation.engine end + def christener + relation.christener + end + def select_sql if relation.projections.first.is_a?(Count) && relation.projections.size == 1 && - (taken.present? || wheres.present?) && joins(self).blank? - subquery = build_query("SELECT 1 FROM #{from_clauses}", build_clauses) + (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank? + subquery = build_query("SELECT 1 FROM #{relation.from_clauses}", build_clauses) query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery" else query = [ @@ -24,7 +28,7 @@ def select_sql end def build_clauses - joins = joins(self) + joins = relation.joins(self) wheres = relation.where_clauses groups = relation.group_clauses havings = relation.having_clauses @@ -50,9 +54,9 @@ def build_clauses def delete_sql build_query \ "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? ), - (add_limit_on_delete(taken) unless taken.blank? ) + "FROM #{relation.table_sql}", + ("WHERE #{relation.wheres.collect { |x| x.to_sql }.join(' AND ')}" unless relation.wheres.blank? ), + (add_limit_on_delete(relation.taken) unless relation.taken.blank? ) end def add_limit_on_delete(taken) @@ -60,19 +64,19 @@ def add_limit_on_delete(taken) end def insert_sql(include_returning = true) - insertion_attributes_values_sql = if record.is_a?(Value) - record.value + insertion_attributes_values_sql = if relation.record.is_a?(Value) + relation.record.value else - attributes = record.keys.sort_by do |attribute| + attributes = relation.record.keys.sort_by do |attribute| attribute.name.to_s end first = attributes.collect do |key| - engine.connection.quote_column_name(key.name) + @engine.connection.quote_column_name(key.name) end.join(', ') second = attributes.collect do |key| - key.format(record[key]) + key.format(relation.record[key]) end.join(', ') build_query "(#{first})", "VALUES (#{second})" @@ -80,9 +84,9 @@ def insert_sql(include_returning = true) build_query \ "INSERT", - "INTO #{table_sql}", + "INTO #{relation.table_sql}", insertion_attributes_values_sql, - ("RETURNING #{engine.connection.quote_column_name(primary_key)}" if include_returning && compiler.supports_insert_with_returning?) + ("RETURNING #{engine.connection.quote_column_name(primary_key)}" if include_returning && relation.compiler.supports_insert_with_returning?) end def supports_insert_with_returning? @@ -91,18 +95,15 @@ def supports_insert_with_returning? def update_sql build_query \ - "UPDATE #{table_sql} SET", + "UPDATE #{relation.table_sql} SET", assignment_sql, build_update_conditions_sql end - protected - def method_missing(method, *args) - if block_given? - relation.send(method, *args) { |*block_args| yield(*block_args) } - else - relation.send(method, *args) - end + protected + + def locked + relation.locked end def build_query(*parts) @@ -110,25 +111,26 @@ def build_query(*parts) end def assignment_sql - if assignments.respond_to?(:collect) - attributes = assignments.keys.sort_by do |attribute| + if relation.assignments.respond_to?(:collect) + attributes = relation.assignments.keys.sort_by do |attribute| attribute.name.to_s end attributes.map do |attribute| - value = assignments[attribute] - "#{engine.connection.quote_column_name(attribute.name)} = #{attribute.format(value)}" + value = relation.assignments[attribute] + "#{@engine.connection.quote_column_name(attribute.name)} = #{attribute.format(value)}" end.join(", ") else - assignments.value + relation.assignments.value end end def build_update_conditions_sql conditions = "" - conditions << " WHERE #{wheres.collect(&:to_sql).join(' AND ')}" unless wheres.blank? - conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? + conditions << " WHERE #{relation.wheres.map { |x| x.to_sql }.join(' AND ')}" unless relation.wheres.blank? + conditions << " ORDER BY #{relation.order_clauses.join(', ')}" unless relation.orders.blank? + taken = relation.taken unless taken.blank? conditions = limited_update_conditions(conditions, taken) end @@ -138,8 +140,8 @@ def build_update_conditions_sql def limited_update_conditions(conditions, taken) conditions << " LIMIT #{taken}" - quoted_primary_key = engine.connection.quote_column_name(primary_key) - "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions})" + quoted_primary_key = @engine.connection.quote_column_name(relation.primary_key) + "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{@engine.connection.quote_table_name relation.table.name} #{conditions})" end end From 1a1e5c144b3192c552b6398607622c3d10e417ca Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 16:43:06 -0700 Subject: [PATCH 0490/1492] removing duplicate code --- lib/arel/algebra/predicates.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 8d3aef9d1822f..4920bc9713d56 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -141,9 +141,6 @@ def eval(row) def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" - end end class CompoundPredicate < Binary From 3aaac5b646ecd73a2fc684896402b1456e5238d8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 17:22:40 -0700 Subject: [PATCH 0491/1492] PERF: fewer objects --- lib/arel/algebra/relations/relation.rb | 9 ++++++++- lib/arel/engines/sql/christener.rb | 2 +- lib/arel/engines/sql/relations/table.rb | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index b3dccaf8be218..af97aa8344619 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -71,7 +71,14 @@ def from_clauses end def where_clauses - wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } + wheres.collect { |w| + case w + when Value + w.value + else # FIXME: why do we have to pass in a whereclause? + w.to_sql(Sql::WhereClause.new(self)) + end + } end def group_clauses diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index 2c96020554292..6160f244f7c3a 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -5,7 +5,7 @@ def initialize # FIXME: this exists because all objects hash the same. :'( @used_names = Hash.new(0) @relation_names = Hash.new do |hash, relation| - name = relation.table_alias ? relation.table_alias : relation.name + name = relation.table_alias || relation.name @used_names[name] += 1 hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 236a36c7a78de..9e64e8e590b70 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -94,8 +94,9 @@ def reset end def ==(other) - Table === other and - name == other.name and + super || + Table === other && + name == other.name && table_alias == other.table_alias end end From 7624b39a69ba2cb06e4d7e5ba8ac005af939f052 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 17:25:16 -0700 Subject: [PATCH 0492/1492] constantize is not required --- lib/arel/algebra/relations/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index af97aa8344619..1d395777c10cc 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -30,7 +30,7 @@ def externalizable? def compiler @compiler ||= begin - "Arel::SqlCompiler::#{engine.adapter_name}Compiler".constantize.new(self) + Arel::SqlCompiler.const_get("#{engine.adapter_name}Compiler").new(self) rescue Arel::SqlCompiler::GenericCompiler.new(self) end From b4b510b2b15a964e804037c7a7fd9291feabdd45 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 17:57:25 -0700 Subject: [PATCH 0493/1492] fixing AR incompatibility --- lib/arel/engines/sql/relations/table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 9e64e8e590b70..9ad939b896e0c 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -54,7 +54,7 @@ def table_exists? if @table_exists true else - @table_exists = @@tables.include?(name) || engine.table_exists?(name) + @table_exists = @@tables.include?(name) || engine.connection.table_exists?(name) end end From c0cadc86e054f2c2eead3482d54cbc57e3828671 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 17:58:28 -0700 Subject: [PATCH 0494/1492] never called with a block, so no reason to test --- lib/arel/algebra/relations/operations/where.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index b447b18809960..3aa06406cfd91 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -4,7 +4,6 @@ class Where < Compound def initialize(relation, *predicates) super(relation) - predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } @wheres = nil end From b2ee120f56fa7e0205b2d3fc602b6ad68a438ac9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 18:01:59 -0700 Subject: [PATCH 0495/1492] PERF: never called with a block, so no need to test --- lib/arel/algebra/relations/operations/project.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index daca7420390c4..8136f7ce9bf5c 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -2,10 +2,9 @@ module Arel class Project < Compound attr_reader :projections - def initialize(relation, *projections, &block) + def initialize(relation, *projections) super(relation) - @projections = (projections + arguments_from_block(relation, &block)) \ - .collect { |p| p.bind(relation) } + @projections = projections.collect { |p| p.bind(relation) } end def attributes From ade53fbc3cedbf3c8f4942b3aade1e86ea6dc8a3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 18:02:56 -0700 Subject: [PATCH 0496/1492] PERF: again. never called with a block, so no need to test :-( --- lib/arel/algebra/relations/operations/order.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 94bd7bcd598d6..5d9b752627cf4 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -4,8 +4,7 @@ class Order < Compound def initialize(relation, *orderings, &block) super(relation) - @orderings = (orderings + arguments_from_block(relation, &block)) \ - .collect { |o| o.bind(relation) } + @orderings = orderings.collect { |o| o.bind(relation) } end def == other From d05d70f73ac624ffebb69c2e1e145ddb2934ae31 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 18:05:19 -0700 Subject: [PATCH 0497/1492] PERF: NERD RAGE. never called with a block, so no need to test --- lib/arel/algebra/relations/operations/group.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index af0d3c680868b..89e56b3a98daf 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -2,10 +2,9 @@ module Arel class Group < Compound attr_reader :groupings - def initialize(relation, *groupings, &block) + def initialize(relation, *groupings) super(relation) - @groupings = (groupings + arguments_from_block(relation, &block)) \ - .collect { |g| g.bind(relation) } + @groupings = groupings.collect { |g| g.bind(relation) } end def == other From 7a7f3a2d3b9223cbac79813ed9b61aa2f7d7ee8f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 18:06:38 -0700 Subject: [PATCH 0498/1492] PERF: dead code is dead --- lib/arel/algebra/relations/operations/having.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index fdd35626af43c..447e836c1ae7c 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -4,7 +4,6 @@ class Having < Compound def initialize(relation, *predicates) super(relation) - predicates = [yield(relation)] + predicates if block_given? @predicates = predicates.map { |p| p.bind(relation) } end From 79f5f87bd5ee18b832edf81c3ee7b75f86fec194 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 18:07:15 -0700 Subject: [PATCH 0499/1492] removing more dead code --- lib/arel/algebra/relations/utilities/compound.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index dbd9af9d3d217..ab66c72e5e0ec 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -40,11 +40,5 @@ def eql?(other) def engine relation.engine end - - private - - def arguments_from_block(relation) - block_given?? [yield(relation)] : [] - end end end From 4bc43c7152a30752166964249f81302c21187e66 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 19:13:30 -0700 Subject: [PATCH 0500/1492] block not used --- lib/arel/algebra/relations/operations/order.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 5d9b752627cf4..54be2f5af028c 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -2,7 +2,7 @@ module Arel class Order < Compound attr_reader :orderings - def initialize(relation, *orderings, &block) + def initialize(relation, *orderings) super(relation) @orderings = orderings.collect { |o| o.bind(relation) } end From c9fa1b47f83f6d07b91fe10922b0e8d042933c1f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 19:21:58 -0700 Subject: [PATCH 0501/1492] PERF: *args is slow. also removing a non-feature --- lib/arel/algebra/relations/relation.rb | 10 +++++++++- spec/algebra/unit/relations/relation_spec.rb | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 1d395777c10cc..9936b9689f7fb 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -123,7 +123,7 @@ def outer_join(other_relation = nil) end %w{ - where project order take skip group from having + where project order skip group having }.each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments) @@ -133,6 +133,14 @@ def #{operation_name}(*arguments) OPERATION end + def take thing + Take.new self, thing + end + + def from thing + From.new self, thing + end + def lock(locking = nil) Lock.new(self, locking) end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index be77c64b17455..4e25de73d187b 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -115,8 +115,8 @@ module Arel end describe 'when given a blank number of items' do - it 'returns self' do - @relation.take.should == @relation + it 'raises error' do + lambda { @relation.take }.should raise_exception end end end From bf6fbc4591bd7fe696f48f1db06eec714c0ec790 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 20:33:59 -0700 Subject: [PATCH 0502/1492] PERF: reducing delegate methods --- lib/arel/algebra/attributes/attribute.rb | 9 ++++++++- lib/arel/algebra/relations/relation.rb | 4 ++++ lib/arel/engines/sql/formatters.rb | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 0ad9382a52105..770e0950c5d52 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -4,12 +4,19 @@ module Arel class TypecastError < StandardError ; end class Attribute attr_reader :relation, :name, :alias, :ancestor - delegate :engine, :christener, :to => :relation def initialize(relation, name, options = {}) @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] end + def engine + @relation.engine + end + + def christener + @relation.christener + end + def == other super || Attribute === other && diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9936b9689f7fb..cb7b30bb3c776 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -41,6 +41,10 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) end def christener + puts "#" * 50 + puts self.class.name + puts caller + puts "#" * 50 @christener ||= Sql::Christener.new end diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 2597beba9529f..7b0be4ea3b41a 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -4,6 +4,7 @@ class Formatter attr_reader :environment, :christener def initialize(environment) + p :formatter => environment.class @environment = environment @christener = environment.christener end From 9e2a02d397ce05539cb409013934a7c0bca06d41 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 20:53:53 -0700 Subject: [PATCH 0503/1492] speed up method lookup --- lib/arel/algebra/attributes/attribute.rb | 181 +++++++++++------------ 1 file changed, 89 insertions(+), 92 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 770e0950c5d52..317b7e79f1fdf 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -96,128 +96,125 @@ def /(other) end include Congruence - module Predications - def eq(other) - Predicates::Equality.new(self, other) - end + def eq(other) + Predicates::Equality.new(self, other) + end - def eq_any(*others) - Predicates::Any.build(Predicates::Equality, self, *others) - end + def eq_any(*others) + Predicates::Any.build(Predicates::Equality, self, *others) + end - def eq_all(*others) - Predicates::All.build(Predicates::Equality, self, *others) - end + def eq_all(*others) + Predicates::All.build(Predicates::Equality, self, *others) + end - def not_eq(other) - Predicates::Inequality.new(self, other) - end + def not_eq(other) + Predicates::Inequality.new(self, other) + end - def not_eq_any(*others) - Predicates::Any.build(Predicates::Inequality, self, *others) - end + def not_eq_any(*others) + Predicates::Any.build(Predicates::Inequality, self, *others) + end - def not_eq_all(*others) - Predicates::All.build(Predicates::Inequality, self, *others) - end + def not_eq_all(*others) + Predicates::All.build(Predicates::Inequality, self, *others) + end - def lt(other) - Predicates::LessThan.new(self, other) - end + def lt(other) + Predicates::LessThan.new(self, other) + end - def lt_any(*others) - Predicates::Any.build(Predicates::LessThan, self, *others) - end + def lt_any(*others) + Predicates::Any.build(Predicates::LessThan, self, *others) + end - def lt_all(*others) - Predicates::All.build(Predicates::LessThan, self, *others) - end + def lt_all(*others) + Predicates::All.build(Predicates::LessThan, self, *others) + end - def lteq(other) - Predicates::LessThanOrEqualTo.new(self, other) - end + def lteq(other) + Predicates::LessThanOrEqualTo.new(self, other) + end - def lteq_any(*others) - Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others) - end + def lteq_any(*others) + Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others) + end - def lteq_all(*others) - Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others) - end + def lteq_all(*others) + Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others) + end - def gt(other) - Predicates::GreaterThan.new(self, other) - end + def gt(other) + Predicates::GreaterThan.new(self, other) + end - def gt_any(*others) - Predicates::Any.build(Predicates::GreaterThan, self, *others) - end + def gt_any(*others) + Predicates::Any.build(Predicates::GreaterThan, self, *others) + end - def gt_all(*others) - Predicates::All.build(Predicates::GreaterThan, self, *others) - end + def gt_all(*others) + Predicates::All.build(Predicates::GreaterThan, self, *others) + end - def gteq(other) - Predicates::GreaterThanOrEqualTo.new(self, other) - end + def gteq(other) + Predicates::GreaterThanOrEqualTo.new(self, other) + end - def gteq_any(*others) - Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others) - end + def gteq_any(*others) + Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others) + end - def gteq_all(*others) - Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others) - end + def gteq_all(*others) + Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others) + end - def matches(other) - Predicates::Match.new(self, other) - end + def matches(other) + Predicates::Match.new(self, other) + end - def matches_any(*others) - Predicates::Any.build(Predicates::Match, self, *others) - end + def matches_any(*others) + Predicates::Any.build(Predicates::Match, self, *others) + end - def matches_all(*others) - Predicates::All.build(Predicates::Match, self, *others) - end + def matches_all(*others) + Predicates::All.build(Predicates::Match, self, *others) + end - def not_matches(other) - Predicates::NotMatch.new(self, other) - end + def not_matches(other) + Predicates::NotMatch.new(self, other) + end - def not_matches_any(*others) - Predicates::Any.build(Predicates::NotMatch, self, *others) - end + def not_matches_any(*others) + Predicates::Any.build(Predicates::NotMatch, self, *others) + end - def not_matches_all(*others) - Predicates::All.build(Predicates::NotMatch, self, *others) - end + def not_matches_all(*others) + Predicates::All.build(Predicates::NotMatch, self, *others) + end - def in(other) - Predicates::In.new(self, other) - end + def in(other) + Predicates::In.new(self, other) + end - def in_any(*others) - Predicates::Any.build(Predicates::In, self, *others) - end + def in_any(*others) + Predicates::Any.build(Predicates::In, self, *others) + end - def in_all(*others) - Predicates::All.build(Predicates::In, self, *others) - end + def in_all(*others) + Predicates::All.build(Predicates::In, self, *others) + end - def not_in(other) - Predicates::NotIn.new(self, other) - end + def not_in(other) + Predicates::NotIn.new(self, other) + end - def not_in_any(*others) - Predicates::Any.build(Predicates::NotIn, self, *others) - end + def not_in_any(*others) + Predicates::Any.build(Predicates::NotIn, self, *others) + end - def not_in_all(*others) - Predicates::All.build(Predicates::NotIn, self, *others) - end + def not_in_all(*others) + Predicates::All.build(Predicates::NotIn, self, *others) end - include Predications module Expressions def count(distinct = false) From 90347db36520038ef361e3c9d935b7ff1c920400 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 21:00:24 -0700 Subject: [PATCH 0504/1492] fixing spec case for method lookup improvement --- spec/algebra/unit/primitives/attribute_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb index 092eeeb2f898f..d030e60a4ce5a 100644 --- a/spec/algebra/unit/primitives/attribute_spec.rb +++ b/spec/algebra/unit/primitives/attribute_spec.rb @@ -74,7 +74,7 @@ module Arel end end - describe Attribute::Predications do + describe 'Attribute::Predications' do before do @attribute = Attribute.new(@relation, :name) end From 288eb6d7ba4fd1f2a27357f8ec889496e9b8542c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 21:02:33 -0700 Subject: [PATCH 0505/1492] oops! removing debug puts --- lib/arel/algebra/relations/relation.rb | 4 ---- lib/arel/engines/sql/formatters.rb | 1 - 2 files changed, 5 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index cb7b30bb3c776..9936b9689f7fb 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -41,10 +41,6 @@ def to_sql(formatter = Sql::SelectStatement.new(self)) end def christener - puts "#" * 50 - puts self.class.name - puts caller - puts "#" * 50 @christener ||= Sql::Christener.new end diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 7b0be4ea3b41a..2597beba9529f 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -4,7 +4,6 @@ class Formatter attr_reader :environment, :christener def initialize(environment) - p :formatter => environment.class @environment = environment @christener = environment.christener end From c47c3ff918f00e26926fca574614f1bd56c7dcfd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 21:10:23 -0700 Subject: [PATCH 0506/1492] faster method lookup again --- lib/arel/algebra/relations/relation.rb | 51 ++++++++++++-------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9936b9689f7fb..9cb38218c0d7d 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -172,40 +172,37 @@ def on(*predicates) end include Operable - module AttributeAccessable - def [](index) - attributes[index] - end + def [](index) + attributes[index] + end - def find_attribute_matching_name(name) - attributes.detect { |a| a.named?(name) } || Attribute.new(self, name) - end + def find_attribute_matching_name(name) + attributes.detect { |a| a.named?(name) } || Attribute.new(self, name) + end - def find_attribute_matching_attribute(attribute) - matching_attributes(attribute).max do |a1, a2| - (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) - end + def find_attribute_matching_attribute(attribute) + matching_attributes(attribute).max do |a1, a2| + (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) end + end - def position_of(attribute) - (@position_of ||= Hash.new do |h, attribute| - h[attribute] = attributes.index(self[attribute]) - end)[attribute] - end + def position_of(attribute) + (@position_of ||= Hash.new do |h, attribute| + h[attribute] = attributes.index(self[attribute]) + end)[attribute] + end - private - def matching_attributes(attribute) - (@matching_attributes ||= attributes.inject({}) do |hash, a| - (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a - hash - end)[attribute.root] || [] - end + private + def matching_attributes(attribute) + (@matching_attributes ||= attributes.inject({}) do |hash, a| + (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a + hash + end)[attribute.root] || [] + end - def has_attribute?(attribute) - !matching_attributes(attribute).empty? - end + def has_attribute?(attribute) + !matching_attributes(attribute).empty? end - include AttributeAccessable module DefaultOperations def attributes; Header.new end From ef719e021dffe03f06f8d0e34c298474d944838d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Jul 2010 21:14:40 -0700 Subject: [PATCH 0507/1492] cleaning up code formatting --- lib/arel/algebra/attributes/attribute.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 317b7e79f1fdf..351e553877c30 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -6,7 +6,10 @@ class Attribute attr_reader :relation, :name, :alias, :ancestor def initialize(relation, name, options = {}) - @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] + @relation = relation # this is actually a table (I think) + @name = name + @alias = options[:alias] + @ancestor = options[:ancestor] end def engine From f962fb70a07722483d4443d40805e6e2dd791fa1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 08:55:11 -0700 Subject: [PATCH 0508/1492] defining a list of predicate methods for easy metaprogramming --- lib/arel/algebra/attributes/attribute.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 351e553877c30..a59c7c3308bc9 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -99,6 +99,21 @@ def /(other) end include Congruence + PREDICATES = [ + :eq, :eq_any, :eq_all, :not_eq, :not_eq_any, :not_eq_all, :lt, :lt_any, + :lt_all, :lteq, :lteq_any, :lteq_all, :gt, :gt_any, :gt_all, :gteq, + :gteq_any, :gteq_all, :matches, :matches_any, :matches_all, :not_matches, + :not_matches_any, :not_matches_all, :in, :in_any, :in_all, :not_in, + :not_in_any, :not_in_all + ] + + Predicate = Class.new do + def instance_methods *args + warn "this module is deprecated, please use the PREDICATES constant" + PREDICATES + end + end + def eq(other) Predicates::Equality.new(self, other) end From 03a0002d9f8fde60bd4ce87e7f5979eddc0ad3a4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 09:33:51 -0700 Subject: [PATCH 0509/1492] #hash #eql? and #== were only used in tests. removed them and wrote better tests --- lib/arel/algebra/relations/operations/join.rb | 14 ------------ spec/algebra/unit/relations/join_spec.rb | 7 ------ spec/algebra/unit/relations/relation_spec.rb | 22 ++++++++++++++----- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 72b4c9b8fe1bd..bfb7727313018 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -15,10 +15,6 @@ def name relation1.name end - def hash - @hash ||= :relation1.hash - end - def attributes @attributes ||= (relation1.externalize.attributes | relation2.externalize.attributes).bind(self) end @@ -61,16 +57,6 @@ def joins(environment, formatter = Sql::TableReference.new(environment)) end end - def == other - super || Join === other && - relation1 == other.relation1 && - relation2 == other.relation2 && - predicates == other.predicates - end - - # FIXME remove this. :'( - alias :eql? :== - def eval result = [] relation1.call.each do |row1| diff --git a/spec/algebra/unit/relations/join_spec.rb b/spec/algebra/unit/relations/join_spec.rb index 5fa326905282c..54034a2e320c4 100644 --- a/spec/algebra/unit/relations/join_spec.rb +++ b/spec/algebra/unit/relations/join_spec.rb @@ -8,13 +8,6 @@ module Arel @predicate = @relation1[:id].eq(@relation2[:user_id]) end - describe 'hashing' do - it 'implements hash equality' do - InnerJoin.new(@relation1, @relation2, @predicate) \ - .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) - end - end - describe '#attributes' do it 'combines the attributes of the two relations' do join = InnerJoin.new(@relation1, @relation2, @predicate) diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 4e25de73d187b..40b8c6585a874 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -32,14 +32,23 @@ module Arel describe '#join' do describe 'when given a relation' do it "manufactures an inner join operation between those two relations" do - @relation.join(@relation).on(@predicate). \ - should == InnerJoin.new(@relation, @relation, @predicate) + join = @relation.join(@relation).on(@predicate) + join.relation1.should == @relation + join.relation2.should == @relation + join.predicates.should == [@predicate] + join.should be_kind_of(InnerJoin) end end describe "when given a string" do it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) + arbitrary_string = "ASDF" + + join = @relation.join(arbitrary_string) + join.relation1.should == @relation + join.relation2.should == arbitrary_string + join.predicates.should == [] + join.should be_kind_of StringJoin end end @@ -52,8 +61,11 @@ module Arel describe '#outer_join' do it "manufactures a left outer join operation between those two relations" do - @relation.outer_join(@relation).on(@predicate). \ - should == OuterJoin.new(@relation, @relation, @predicate) + join = @relation.outer_join(@relation).on(@predicate) + join.relation1.should == @relation + join.relation2.should == @relation + join.predicates.should == [@predicate] + join.should be_kind_of OuterJoin end end end From 6761d07f41573e9c8559cc2e77030d29e38320ae Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 09:48:31 -0700 Subject: [PATCH 0510/1492] fixing a typo! --- lib/arel/algebra/attributes/attribute.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index a59c7c3308bc9..62c1a6432420d 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -107,8 +107,8 @@ def /(other) :not_in_any, :not_in_all ] - Predicate = Class.new do - def instance_methods *args + Predications = Class.new do + def self.instance_methods *args warn "this module is deprecated, please use the PREDICATES constant" PREDICATES end From 8f808807a96c9755a3d0684900228ac594793d03 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 28 Jul 2010 14:41:46 -0300 Subject: [PATCH 0511/1492] PostgreSQLCompiler#select_sql fixed --- .../sql/compilers/postgresql_compiler.rb | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb index 250d582545f6f..3079451064f18 100644 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ b/lib/arel/engines/sql/compilers/postgresql_compiler.rb @@ -4,20 +4,28 @@ class PostgreSQLCompiler < GenericCompiler def select_sql if !relation.orders.blank? && using_distinct_on? - subquery = build_query \ - "SELECT #{select_clauses.kind_of?(::Array) ? select_clauses.join("") : select_clauses.to_s}", - "FROM #{from_clauses}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses.join(" AND ")}" unless wheres.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(', ')}" unless havings.blank? ), - ("#{locked}" unless locked.blank? ) + selects = relation.select_clauses + joins = relation.joins(self) + wheres = relation.where_clauses + groups = relation.group_clauses + havings = relation.having_clauses + orders = relation.order_clauses + + subquery_clauses = [ "", + "SELECT #{selects.kind_of?(::Array) ? selects.join("") : selects.to_s}", + "FROM #{relation.from_clauses}", + joins, + ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?), + ("GROUP BY #{groups.join(', ')}" unless groups.empty?), + ("HAVING #{havings.join(' AND ')}" unless havings.empty?) + ].compact.join ' ' + subquery_clauses << " #{locked}" unless locked.blank? build_query \ - "SELECT * FROM (#{subquery}) AS id_list", - "ORDER BY #{aliased_orders(order_clauses)}", - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) + "SELECT * FROM (#{build_query subquery_clauses}) AS id_list", + "ORDER BY #{aliased_orders(orders)}", + ("LIMIT #{relation.taken}" unless relation.taken.blank? ), + ("OFFSET #{relation.skipped}" unless relation.skipped.blank? ) else super end From a0425099d78c1884478ee3e69a09ea5f7afa1aa9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 13:51:51 -0700 Subject: [PATCH 0512/1492] simplifying the Christener --- lib/arel/algebra/attributes/attribute.rb | 6 ++---- lib/arel/engines/sql/christener.rb | 17 +++++++++-------- lib/arel/engines/sql/relations/table.rb | 1 + 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 62c1a6432420d..90a3b13938ec4 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -41,11 +41,9 @@ def eval(row) row[self] end - module Transformations - def self.included(klass) - klass.send :alias_method, :eql?, :== - end + alias :eql? :== + module Transformations def hash @hash ||= name.hash + root.relation.hash end diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index 6160f244f7c3a..3c7fb0425e054 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -2,17 +2,18 @@ module Arel module Sql class Christener def initialize - # FIXME: this exists because all objects hash the same. :'( - @used_names = Hash.new(0) - @relation_names = Hash.new do |hash, relation| - name = relation.table_alias || relation.name - @used_names[name] += 1 - hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') - end + @names = {} end def name_for(relation) - @relation_names[relation.table] + table = relation.table + name = table.table_alias || table.name + @names[name] ||= [] + + @names[name] << table unless @names[name].include? table + + idx = @names[name].index table + name + (idx == 0 ? '' : "_#{idx + 1}") end end end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 9ad939b896e0c..d9ff95265bd60 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -17,6 +17,7 @@ def tables= e; @@tables = e; end def initialize(name, options = {}) @name = name.to_s @table_exists = nil + @table_alias = nil if options.is_a?(Hash) @options = options From afcfe97517f6c0c872c0eb79fc505cf85b1a3e74 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 13:55:22 -0700 Subject: [PATCH 0513/1492] speed up method lookup and reduce API footprint --- lib/arel/algebra/attributes/attribute.rb | 25 ++++++++----------- .../algebra/unit/primitives/attribute_spec.rb | 2 +- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 90a3b13938ec4..50d79fa4b98a7 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -43,24 +43,21 @@ def eval(row) alias :eql? :== - module Transformations - def hash - @hash ||= name.hash + root.relation.hash - end + def hash + @hash ||= name.hash + root.relation.hash + end - def as(aliaz = nil) - Attribute.new(relation, name, :alias => aliaz, :ancestor => self) - end + def as(aliaz = nil) + Attribute.new(relation, name, :alias => aliaz, :ancestor => self) + end - def bind(new_relation) - relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) - end + def bind(new_relation) + relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) + end - def to_attribute(relation) - bind(relation) - end + def to_attribute(relation) + bind(relation) end - include Transformations module Congruence def history diff --git a/spec/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb index d030e60a4ce5a..08d32614a155f 100644 --- a/spec/algebra/unit/primitives/attribute_spec.rb +++ b/spec/algebra/unit/primitives/attribute_spec.rb @@ -7,7 +7,7 @@ module Arel @attribute = @relation[:id] end - describe Attribute::Transformations do + describe 'Attribute::Transformations' do describe '#as' do it "manufactures an aliased attributed" do @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) From e26006fb877f8b9e75d814f3499c7e3dd7dc47b7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 14:03:20 -0700 Subject: [PATCH 0514/1492] adding tests for the christener --- spec/sql/christener_spec.rb | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 spec/sql/christener_spec.rb diff --git a/spec/sql/christener_spec.rb b/spec/sql/christener_spec.rb new file mode 100644 index 0000000000000..d50cb56261e0b --- /dev/null +++ b/spec/sql/christener_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' + +module Arel + module Sql + describe "Christener" do + it "returns the same name with two table objects" do + christener = Christener.new + table = Table.new 'users' + table2 = Table.new 'users' + christener.name_for(table).should == 'users' + christener.name_for(table2).should == 'users' + end + + it "returns the first name" do + christener = Christener.new + table = Table.new 'users' + table2 = Table.new 'pictures' + christener.name_for(table).should == 'users' + christener.name_for(table2).should == 'pictures' + christener.name_for(table).should == 'users' + end + + it "returns a unique name for an alias" do + christener = Christener.new + table = Table.new 'users' + table2 = Table.new 'users', :as => 'friends' + christener.name_for(table).should == 'users' + christener.name_for(table2).should == 'friends' + end + + it "returns a unique name for an alias with same name" do + christener = Christener.new + table = Table.new 'users' + table2 = Table.new 'friends', :as => 'users' + christener.name_for(table).should == 'users' + christener.name_for(table2).should == 'users_2' + end + + it "returns alias name" do + christener = Christener.new + table = Table.new 'users' + aliaz = Alias.new table + + christener.name_for(table).should == 'users' + christener.name_for(aliaz).should == 'users_2' + end + + it "returns alias first" do + christener = Christener.new + table = Table.new 'users' + aliaz = Alias.new table + + christener.name_for(aliaz).should == 'users' + christener.name_for(table).should == 'users_2' + end + + it "returns externalization name" do + christener = Christener.new + table = Table.new 'users' + ext = Externalization.new table + + christener.name_for(table).should == 'users' + christener.name_for(ext).should == 'users_external' + end + + it "returns aliases externalizations and tables" do + christener = Christener.new + table = Table.new 'users' + aliaz = Alias.new table + ext = Externalization.new table + + christener.name_for(table).should == 'users' + christener.name_for(aliaz).should == 'users_2' + christener.name_for(ext).should == 'users_external' + end + end + end +end From 635f11d7fb8e7382314f5484d924b755a1e91be6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 14:16:09 -0700 Subject: [PATCH 0515/1492] no need for a lambda --- lib/arel/algebra/attributes/attribute.rb | 4 ++-- lib/arel/algebra/relations/relation.rb | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 50d79fa4b98a7..13781f47e0eab 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -29,6 +29,8 @@ def == other @ancestor == other.ancestor end + alias :eql? :== + def named?(hypothetical_name) (@alias || name).to_s == hypothetical_name.to_s end @@ -41,8 +43,6 @@ def eval(row) row[self] end - alias :eql? :== - def hash @hash ||= name.hash + root.relation.hash end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9cb38218c0d7d..62d9bf177c1e8 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -187,9 +187,11 @@ def find_attribute_matching_attribute(attribute) end def position_of(attribute) - (@position_of ||= Hash.new do |h, attribute| - h[attribute] = attributes.index(self[attribute]) - end)[attribute] + @position_of ||= {} + + return @position_of[attribute] if @position_of.key? attribute + + @position_of[attribute] = attributes.index(attributes[attribute]) end private From 58c7733bf7c5c4d3559cd9bf8f99153cb1e36b49 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 14:46:21 -0700 Subject: [PATCH 0516/1492] speed up hash calculation and hash method --- lib/arel/algebra/attributes/attribute.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 13781f47e0eab..2a4b274a963f3 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -3,13 +3,16 @@ module Arel class TypecastError < StandardError ; end class Attribute - attr_reader :relation, :name, :alias, :ancestor + attr_reader :relation, :name, :alias, :ancestor, :hash def initialize(relation, name, options = {}) @relation = relation # this is actually a table (I think) @name = name @alias = options[:alias] @ancestor = options[:ancestor] + + # FIXME: I think we can remove this eventually + @hash = name.hash + root.relation.class.hash end def engine @@ -23,10 +26,10 @@ def christener def == other super || Attribute === other && - @relation == other.relation && @name == other.name && @alias == other.alias && - @ancestor == other.ancestor + @ancestor == other.ancestor && + @relation == other.relation end alias :eql? :== @@ -43,10 +46,6 @@ def eval(row) row[self] end - def hash - @hash ||= name.hash + root.relation.hash - end - def as(aliaz = nil) Attribute.new(relation, name, :alias => aliaz, :ancestor => self) end From f97b8d5b9df6b1f496fce1170e4331746b37662f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 14:48:22 -0700 Subject: [PATCH 0517/1492] no code is faster than no code --- lib/arel/algebra/relations/utilities/compound.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index ab66c72e5e0ec..451097b5510d3 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -28,15 +28,6 @@ def unoperated_rows relation.call.collect { |row| row.bind(self) } end - # FIXME: remove this. :'( - def hash - @hash ||= :relation.hash - end - - def eql?(other) - self == other - end - def engine relation.engine end From 1dbbc1b9871bd65d6ba149152b5deb23a53b67f8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 14:50:32 -0700 Subject: [PATCH 0518/1492] Enumerable implements #first --- lib/arel/algebra/relations/relation.rb | 15 ++++----------- spec/algebra/unit/relations/relation_spec.rb | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 62d9bf177c1e8..ccc1ab558fcc2 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -1,5 +1,7 @@ module Arel module Relation + include Enumerable + @@connection_tables_primary_keys = {} attr_reader :count @@ -93,18 +95,9 @@ def order_clauses orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } end - module Enumerable - include ::Enumerable - - def each - session.read(self).each { |e| yield e } - end - - def first - session.read(self).first - end + def each + session.read(self).each { |e| yield e } end - include Enumerable module Operable def join(other_relation = nil, join_class = InnerJoin) diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 40b8c6585a874..f51ecd7789397 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -189,7 +189,7 @@ module Arel end end - describe Relation::Enumerable do + describe 'is enumerable' do it "implements enumerable" do @relation.map { |value| value }.should == @relation.session.read(@relation).map { |value| value } From c93f75619441cc394ce193b8af9823a5d3acf0d4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 15:16:07 -0700 Subject: [PATCH 0519/1492] initializing variables, removing == --- lib/arel/algebra/relations/operations/project.rb | 8 +------- spec/algebra/unit/relations/relation_spec.rb | 6 ++++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 8136f7ce9bf5c..b78d5d3e97345 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -5,6 +5,7 @@ class Project < Compound def initialize(relation, *projections) super(relation) @projections = projections.collect { |p| p.bind(relation) } + @attributes = nil end def attributes @@ -15,13 +16,6 @@ def externalizable? attributes.any? { |a| a.respond_to?(:aggregation?) && a.aggregation? } || relation.externalizable? end - def == other - super || - Project === other && - relation == other.relation && - projections == other.projections - end - def eval unoperated_rows.collect { |r| r.slice(*projections) } end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index f51ecd7789397..8d0639ee07390 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -72,8 +72,10 @@ module Arel describe '#project' do it "manufactures a projection relation" do - @relation.project(@attribute1, @attribute2). \ - should == Project.new(@relation, @attribute1, @attribute2) + project = @relation.project(@attribute1, @attribute2) + project.relation.should == @relation + project.projections.should == [@attribute1, @attribute2] + project.should be_kind_of Project end describe "when given blank attributes" do From ea1d050266e76d0200f8ff749e537fc66c17ff4f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 15:25:24 -0700 Subject: [PATCH 0520/1492] PERF: fewer objects, using attr_reader for faster method lookup --- lib/arel/algebra/relations/operations/project.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index b78d5d3e97345..17431c9a8298f 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -1,15 +1,11 @@ module Arel class Project < Compound - attr_reader :projections + attr_reader :projections, :attributes def initialize(relation, *projections) super(relation) @projections = projections.collect { |p| p.bind(relation) } - @attributes = nil - end - - def attributes - @attributes ||= Header.new(projections).bind(self) + @attributes = Header.new(projections.map { |x| x.bind(self) }) end def externalizable? From 60b8a98c15186429a9bf216dbbae0f3b71b666bd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 15:27:18 -0700 Subject: [PATCH 0521/1492] implementing hash is a non-requirement --- lib/arel/engines/sql/relations/table.rb | 8 -------- spec/engines/sql/unit/relations/table_spec.rb | 7 ------- 2 files changed, 15 deletions(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index d9ff95265bd60..28c56a6bb00f1 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -73,14 +73,6 @@ def attributes end end - def eql?(other) - self == other - end - - def hash - @hash ||= :name.hash - end - def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end diff --git a/spec/engines/sql/unit/relations/table_spec.rb b/spec/engines/sql/unit/relations/table_spec.rb index 6afd9964a4190..1a0914006bbdf 100644 --- a/spec/engines/sql/unit/relations/table_spec.rb +++ b/spec/engines/sql/unit/relations/table_spec.rb @@ -108,13 +108,6 @@ module Arel end end - describe 'hashing' do - it "implements hash equality" do - Table.new(:users).should hash_the_same_as(Table.new(:users)) - Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) - end - end - describe '#engine' do it "defaults to global engine" do Table.engine = engine = Sql::Engine.new From 6d44a1349ef23f8969eeec91b0facb0adf6df52b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 15:32:53 -0700 Subject: [PATCH 0522/1492] PERF: fewer objects, less lambdas, less memory --- lib/arel/algebra/header.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/header.rb b/lib/arel/algebra/header.rb index 3b8aea3422a3f..dc779d53c3aca 100644 --- a/lib/arel/algebra/header.rb +++ b/lib/arel/algebra/header.rb @@ -4,9 +4,7 @@ class Header def initialize(attrs = []) @attributes = attrs.to_ary - @names = Hash.new do |h,k| - h[k] = @attributes.detect { |a| a.named?(k) } - end + @names = {} end def each @@ -55,7 +53,8 @@ def matching(attribute) end def find_by_name(name) - @names[name.to_sym] + k = name.to_sym + @names[k] ||= @attributes.detect { |a| a.named?(k) } end def find_by_attribute(attr) From 3878a115a3d53eb817c0fbab3e5ca7ec1427f0be Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 15:58:36 -0700 Subject: [PATCH 0523/1492] refactor for faster method lookup --- lib/arel/algebra/relations/relation.rb | 26 +++++++++++--------- spec/algebra/unit/relations/relation_spec.rb | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index ccc1ab558fcc2..e8ef9b395d02f 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -116,7 +116,7 @@ def outer_join(other_relation = nil) end %w{ - where project order skip group having + where order skip group having }.each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments) @@ -126,6 +126,11 @@ def #{operation_name}(*arguments) OPERATION end + def project *args + return self if args.all? { |x| x.blank? } + Project.new self, *args + end + def take thing Take.new self, thing end @@ -142,20 +147,17 @@ def alias Alias.new(self) end - module Writable - def insert(record) - session.create Insert.new(self, record) - end + def insert(record) + session.create Insert.new(self, record) + end - def update(assignments) - session.update Update.new(self, assignments) - end + def update(assignments) + session.update Update.new(self, assignments) + end - def delete - session.delete Deletion.new(self) - end + def delete + session.delete Deletion.new(self) end - include Writable JoinOperation = Struct.new(:join_class, :relation1, :relation2) do def on(*predicates) diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 8d0639ee07390..2a2fb15d89d0c 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -159,7 +159,7 @@ module Arel end end - describe Relation::Operable::Writable do + describe 'relation is writable' do describe '#delete' do it 'manufactures a deletion relation' do Session.start do |s| From ccbf1e4b7cb29780b9411ecb2bee97be004ae8dc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 28 Jul 2010 17:00:47 -0700 Subject: [PATCH 0524/1492] call map to make perftools reports more nice --- lib/arel/algebra/relations/operations/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 17431c9a8298f..0590b8dd88b70 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -4,7 +4,7 @@ class Project < Compound def initialize(relation, *projections) super(relation) - @projections = projections.collect { |p| p.bind(relation) } + @projections = projections.map { |p| p.bind(relation) } @attributes = Header.new(projections.map { |x| x.bind(self) }) end From 06dbb824b9a1e431914ec18c42e6586e49714e97 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 28 Jul 2010 22:25:03 -0300 Subject: [PATCH 0525/1492] if-else logic doesn't needed --- lib/arel/engines/sql/relations/table.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 28c56a6bb00f1..65a0f91e8cd74 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -52,11 +52,7 @@ def as(table_alias) end def table_exists? - if @table_exists - true - else - @table_exists = @@tables.include?(name) || engine.connection.table_exists?(name) - end + @table_exists ||= @@tables.include?(name) || engine.connection.table_exists?(name) end def attributes From 26ed429976ac6486c0473f13b6e0f16e05ede484 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 10:36:11 -0700 Subject: [PATCH 0526/1492] fisting postgres tests. thanks santiago! --- lib/arel/engines/sql/formatters.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 2597beba9529f..59fb836b86fcd 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -21,7 +21,7 @@ def quote_column_name name end def quote_table_name name - engine.connection.quote_column_name name + engine.connection.quote_table_name name end def quote value, column = nil From 068b184a59a98b4acdc63a2833c360199d138c1d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 12:01:08 -0700 Subject: [PATCH 0527/1492] PERF: removing many splats --- lib/arel/algebra/relations/operations/group.rb | 2 +- lib/arel/algebra/relations/operations/having.rb | 2 +- lib/arel/algebra/relations/operations/order.rb | 2 +- lib/arel/algebra/relations/operations/project.rb | 2 +- lib/arel/algebra/relations/operations/where.rb | 2 +- lib/arel/algebra/relations/relation.rb | 14 ++++++-------- spec/algebra/unit/relations/project_spec.rb | 6 +++--- spec/algebra/unit/relations/relation_spec.rb | 8 ++++---- spec/engines/sql/unit/relations/group_spec.rb | 4 ++-- spec/engines/sql/unit/relations/order_spec.rb | 10 +++++----- spec/engines/sql/unit/relations/project_spec.rb | 8 ++++---- spec/engines/sql/unit/relations/where_spec.rb | 2 +- 12 files changed, 30 insertions(+), 32 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 89e56b3a98daf..f3666cacf838b 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -2,7 +2,7 @@ module Arel class Group < Compound attr_reader :groupings - def initialize(relation, *groupings) + def initialize(relation, groupings) super(relation) @groupings = groupings.collect { |g| g.bind(relation) } end diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index 447e836c1ae7c..d36aad071b9d0 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -2,7 +2,7 @@ module Arel class Having < Compound attr_reader :predicates - def initialize(relation, *predicates) + def initialize(relation, predicates) super(relation) @predicates = predicates.map { |p| p.bind(relation) } end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 54be2f5af028c..bf0e0f723c5e1 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -2,7 +2,7 @@ module Arel class Order < Compound attr_reader :orderings - def initialize(relation, *orderings) + def initialize(relation, orderings) super(relation) @orderings = orderings.collect { |o| o.bind(relation) } end diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 0590b8dd88b70..649ec19713e6c 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -2,7 +2,7 @@ module Arel class Project < Compound attr_reader :projections, :attributes - def initialize(relation, *projections) + def initialize(relation, projections) super(relation) @projections = projections.map { |p| p.bind(relation) } @attributes = Header.new(projections.map { |x| x.bind(self) }) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 3aa06406cfd91..3b70b49f3aa24 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -2,7 +2,7 @@ module Arel class Where < Compound attr_reader :predicates - def initialize(relation, *predicates) + def initialize(relation, predicates) super(relation) @predicates = predicates.map { |p| p.bind(relation) } @wheres = nil diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index e8ef9b395d02f..dd0684b88eb05 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -116,19 +116,17 @@ def outer_join(other_relation = nil) end %w{ - where order skip group having - }.each do |operation_name| + having group order where project + }.each do |op| class_eval <<-OPERATION, __FILE__, __LINE__ - def #{operation_name}(*arguments) - arguments.all? { |x| x.blank? } ? - self : #{operation_name.capitalize}.new(self, *arguments) + def #{op}(*args) + args.all? { |x| x.blank? } ? self : #{op.capitalize}.new(self, args) end OPERATION end - def project *args - return self if args.all? { |x| x.blank? } - Project.new self, *args + def skip thing = nil + thing ? Skip.new(self, thing) : self end def take thing diff --git a/spec/algebra/unit/relations/project_spec.rb b/spec/algebra/unit/relations/project_spec.rb index 8886e65a2eee5..294bffafe96af 100644 --- a/spec/algebra/unit/relations/project_spec.rb +++ b/spec/algebra/unit/relations/project_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#attributes' do before do - @projection = Project.new(@relation, @attribute) + @projection = Project.new(@relation, [@attribute]) end it "manufactures attributes associated with the projection relation" do @@ -20,13 +20,13 @@ module Arel describe '#externalizable?' do describe 'when the projections are attributes' do it 'returns false' do - Project.new(@relation, @attribute).should_not be_externalizable + Project.new(@relation, [@attribute]).should_not be_externalizable end end describe 'when the projections include an aggregation' do it "obtains" do - Project.new(@relation, @attribute.sum).should be_externalizable + Project.new(@relation, [@attribute.sum]).should be_externalizable end end end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 2a2fb15d89d0c..f4769526da5ae 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -97,11 +97,11 @@ module Arel end it "manufactures a where relation" do - @relation.where(@predicate).should == Where.new(@relation, @predicate) + @relation.where(@predicate).should == Where.new(@relation, [@predicate]) end it "accepts arbitrary strings" do - @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") + @relation.where("arbitrary").should == Where.new(@relation, ["arbitrary"]) end describe 'when given a blank predicate' do @@ -113,7 +113,7 @@ module Arel describe '#order' do it "manufactures an order relation" do - @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) + @relation.order(@attribute1, @attribute2).should == Order.new(@relation, [@attribute1, @attribute2]) end describe 'when given a blank ordering' do @@ -149,7 +149,7 @@ module Arel describe '#group' do it 'manufactures a group relation' do - @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) + @relation.group(@attribute1, @attribute2).should == Group.new(@relation, [@attribute1, @attribute2]) end describe 'when given blank groupings' do diff --git a/spec/engines/sql/unit/relations/group_spec.rb b/spec/engines/sql/unit/relations/group_spec.rb index 72a9f4e99e1aa..c32091bf08f80 100644 --- a/spec/engines/sql/unit/relations/group_spec.rb +++ b/spec/engines/sql/unit/relations/group_spec.rb @@ -10,7 +10,7 @@ module Arel describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - sql = Group.new(@relation, @attribute).to_sql + sql = Group.new(@relation, [@attribute]).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -40,7 +40,7 @@ module Arel describe 'when given a string' do it "passes the string through to the where clause" do - sql = Group.new(@relation, 'asdf').to_sql + sql = Group.new(@relation, ['asdf']).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/engines/sql/unit/relations/order_spec.rb b/spec/engines/sql/unit/relations/order_spec.rb index 3c9d9ef59884a..59637876bf564 100644 --- a/spec/engines/sql/unit/relations/order_spec.rb +++ b/spec/engines/sql/unit/relations/order_spec.rb @@ -10,7 +10,7 @@ module Arel describe '#to_sql' do describe "when given an attribute" do it "manufactures sql with an order clause populated by the attribute" do - sql = Order.new(@relation, @attribute).to_sql + sql = Order.new(@relation, [@attribute]).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -60,7 +60,7 @@ module Arel end it "manufactures sql with an order clause populated by comma-separated attributes" do - sql = Order.new(@relation, @attribute, @another_attribute).to_sql + sql = Order.new(@relation, [@attribute, @another_attribute]).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -94,7 +94,7 @@ module Arel end it "passes the string through to the order clause" do - sql = Order.new(@relation, @string).to_sql + sql = Order.new(@relation, [@string]).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -124,12 +124,12 @@ module Arel describe "when ordering an ordered relation" do before do - @ordered_relation = Order.new(@relation, @attribute) + @ordered_relation = Order.new(@relation, [@attribute]) @another_attribute = @relation[:name] end it "manufactures sql with the order clause of the last ordering preceding the first ordering" do - sql = Order.new(@ordered_relation, @another_attribute).to_sql + sql = Order.new(@ordered_relation, [@another_attribute]).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/engines/sql/unit/relations/project_spec.rb b/spec/engines/sql/unit/relations/project_spec.rb index e73c7775a1076..b5d2d33d4b959 100644 --- a/spec/engines/sql/unit/relations/project_spec.rb +++ b/spec/engines/sql/unit/relations/project_spec.rb @@ -10,7 +10,7 @@ module Arel describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do - sql = Project.new(@relation, @attribute).to_sql + sql = Project.new(@relation, [@attribute]).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -37,11 +37,11 @@ module Arel describe 'when given a relation' do before do - @scalar_relation = Project.new(@relation, @relation[:name]) + @scalar_relation = Project.new(@relation, [@relation[:name]]) end it "manufactures sql with scalar selects" do - sql = Project.new(@relation, @scalar_relation).to_sql + sql = Project.new(@relation, [@scalar_relation]).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -65,7 +65,7 @@ module Arel describe 'when given a string' do it "passes the string through to the select clause" do - sql = Project.new(@relation, 'asdf').to_sql + sql = Project.new(@relation, ['asdf']).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/engines/sql/unit/relations/where_spec.rb b/spec/engines/sql/unit/relations/where_spec.rb index 5f559efad3e37..69793d63a1a7e 100644 --- a/spec/engines/sql/unit/relations/where_spec.rb +++ b/spec/engines/sql/unit/relations/where_spec.rb @@ -10,7 +10,7 @@ module Arel describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - sql = Where.new(@relation, @predicate).to_sql + sql = Where.new(@relation, [@predicate]).to_sql adapter_is :mysql do sql.should be_like(%Q{ From f87c8398d95f3f4b162a3a78299489189d7a0a45 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 12:13:26 -0700 Subject: [PATCH 0528/1492] PERF: pushing christener down for faster method lookup and calling --- lib/arel/algebra/relations/operations/project.rb | 3 ++- lib/arel/engines/sql/relations/table.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 649ec19713e6c..1c24ae6caff73 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -1,10 +1,11 @@ module Arel class Project < Compound - attr_reader :projections, :attributes + attr_reader :projections, :attributes, :christener def initialize(relation, projections) super(relation) @projections = projections.map { |p| p.bind(relation) } + @christener = Sql::Christener.new @attributes = Header.new(projections.map { |x| x.bind(self) }) end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 65a0f91e8cd74..f56fd7d813821 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -12,12 +12,13 @@ def tables; @@tables; end def tables= e; @@tables = e; end end - attr_reader :name, :engine, :table_alias, :options + attr_reader :name, :engine, :table_alias, :options, :christener def initialize(name, options = {}) @name = name.to_s @table_exists = nil @table_alias = nil + @christener = Sql::Christener.new if options.is_a?(Hash) @options = options From 49e4dcbd7407da096506f387c73e265b15751730 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 12:14:52 -0700 Subject: [PATCH 0529/1492] PERF: avoid *args --- lib/arel/engines/sql/relations/compiler.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 2fb4c7841e0e6..ad68a7ea2e49c 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -15,7 +15,9 @@ def christener def select_sql if relation.projections.first.is_a?(Count) && relation.projections.size == 1 && (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank? - subquery = build_query("SELECT 1 FROM #{relation.from_clauses}", build_clauses) + subquery = [ + "SELECT 1 FROM #{relation.from_clauses}", build_clauses + ].join ' ' query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery" else query = [ From 4d271c96b9e090a3fa75797f82e8d1d423a009c8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 12:23:03 -0700 Subject: [PATCH 0530/1492] fewer function calls --- lib/arel/engines/sql/relations/compiler.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index ad68a7ea2e49c..43d0e1aeb9cd9 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -13,7 +13,8 @@ def christener end def select_sql - if relation.projections.first.is_a?(Count) && relation.projections.size == 1 && + projections = @relation.projections + if projections.first.is_a?(Count) && projections.size == 1 && (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank? subquery = [ "SELECT 1 FROM #{relation.from_clauses}", build_clauses From dfe79da73e13d44294ce5b167d6519b394cefa1b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 13:47:44 -0700 Subject: [PATCH 0531/1492] PERF: fewer objects, pass through on values --- lib/arel/algebra/relations/relation.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index dd0684b88eb05..eeb5918f4b856 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -65,7 +65,14 @@ def primary_key end def select_clauses - attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } + attributes.map { |a| + case a + when Value + a.value + else + a.to_sql(Sql::SelectClause.new(self)) + end + } end def from_clauses From 4e3b99dad53a25dd369bef9b19ae1cb794ab3e73 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Jul 2010 14:26:07 -0700 Subject: [PATCH 0532/1492] initialize our instance variables --- lib/arel/algebra/relations/utilities/compound.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 451097b5510d3..25f634ef78c49 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -8,8 +8,13 @@ class Compound :to => :relation def initialize relation - @relation = relation - @attributes = nil + @relation = relation + @attributes = nil + @wheres = nil + @groupings = nil + @orders = nil + @havings = nil + @projections = nil end [:wheres, :groupings, :orders, :havings, :projections].each do |operation_name| From b176daecddb81849c5db15472bd1b6847900e75c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 09:23:12 -0700 Subject: [PATCH 0533/1492] PERF: fewer function calls --- lib/arel/engines/sql/formatters.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 59fb836b86fcd..aab4282f04838 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -115,12 +115,13 @@ def select(select_sql, table) end def table(table) - if table.name =~ /\s/ - table.name - else - quote_table_name(table.name) + - (table.name != name_for(table) ? " #{quote_table_name(name_for(table))}" : '') - end + table_name = table.name + return table_name if table_name =~ /\s/ + + unique_name = name_for(table) + + quote_table_name(table_name) + + (table_name != unique_name ? " #{quote_table_name(unique_name)}" : '') end end From 19926cf6d3304b713ede84ae931e25700fd0db81 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 09:24:28 -0700 Subject: [PATCH 0534/1492] PERF: fewer objects, short circuit unless necessary --- lib/arel/algebra/relations/relation.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index eeb5918f4b856..97aa779926ce2 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -38,8 +38,11 @@ def compiler end end - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select compiler.select_sql, self + def to_sql(formatter = nil) + sql = compiler.select_sql + + return sql unless formatter + formatter.select sql, self end def christener @@ -76,7 +79,7 @@ def select_clauses end def from_clauses - sources.blank? ? table_sql(Sql::TableReference.new(self)) : sources + sources.empty? ? table_sql : sources end def where_clauses From d22b2169f7151d076b06bfa5da85dbe5497d8ea4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:02:34 -0700 Subject: [PATCH 0535/1492] PERF: where is only ever called with 0 or 1 arguments. eliminate *args --- lib/arel/algebra/relations/relation.rb | 6 +++++- lib/arel/engines/sql/relations/compiler.rb | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 97aa779926ce2..0441b1438215e 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -126,7 +126,7 @@ def outer_join(other_relation = nil) end %w{ - having group order where project + having group order project }.each do |op| class_eval <<-OPERATION, __FILE__, __LINE__ def #{op}(*args) @@ -135,6 +135,10 @@ def #{op}(*args) OPERATION end + def where clause = nil + clause ? Where.new(self, [clause]) : self + end + def skip thing = nil thing ? Skip.new(self, thing) : self end diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb index 43d0e1aeb9cd9..c8511374d9559 100644 --- a/lib/arel/engines/sql/relations/compiler.rb +++ b/lib/arel/engines/sql/relations/compiler.rb @@ -14,7 +14,7 @@ def christener def select_sql projections = @relation.projections - if projections.first.is_a?(Count) && projections.size == 1 && + if Count === projections.first && projections.size == 1 && (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank? subquery = [ "SELECT 1 FROM #{relation.from_clauses}", build_clauses From 0e957e05acc8bd53a42d53bf94d6cd4f2441737a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:08:47 -0700 Subject: [PATCH 0536/1492] better tests for Where construction, removing Where#== --- lib/arel/algebra/relations/operations/where.rb | 7 ------- spec/algebra/unit/relations/relation_spec.rb | 13 +++++++++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 3b70b49f3aa24..d851aebc4495c 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -12,13 +12,6 @@ def wheres @wheres ||= relation.wheres + predicates end - def == other - super || - Where === other && - relation == other.relation && - predicates == other.predicates - end - def engine engine = relation.engine diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index f4769526da5ae..ec311d0c43697 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -97,11 +97,20 @@ module Arel end it "manufactures a where relation" do - @relation.where(@predicate).should == Where.new(@relation, [@predicate]) + where = @relation.where(@predicate) + where.relation.should == @relation + where.predicates.should == [@predicate] + where.should be_kind_of Where end it "accepts arbitrary strings" do - @relation.where("arbitrary").should == Where.new(@relation, ["arbitrary"]) + where = @relation.where("arbitrary") + where.relation.should == @relation + + where.predicates.length.should == 1 + where.predicates.first.value.should == "arbitrary" + + where.should be_kind_of Where end describe 'when given a blank predicate' do From ee6443f21709c8fb2927316bc90f9e2db8a17566 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:13:55 -0700 Subject: [PATCH 0537/1492] better tests for Taken constructor, removing Take#== --- lib/arel/algebra/relations/operations/take.rb | 7 ------- spec/algebra/unit/relations/relation_spec.rb | 4 +++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index 7098d578d5def..421051124c90c 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -7,13 +7,6 @@ def initialize relation, taken @taken = taken end - def == other - super || - Take === other && - relation == other.relation && - taken == other.taken - end - def engine engine = relation.engine diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index ec311d0c43697..1a15471f9aa3f 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -134,7 +134,9 @@ module Arel describe '#take' do it "manufactures a take relation" do - @relation.take(5).should == Take.new(@relation, 5) + take = @relation.take(5) + take.relation.should == @relation + take.taken.should == 5 end describe 'when given a blank number of items' do From a672a525f821aed061c2aa68ec804e895ac3ebf3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:15:32 -0700 Subject: [PATCH 0538/1492] variable name clarity --- lib/arel/algebra/relations/relation.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 0441b1438215e..9ff436ecb7ed7 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -143,8 +143,8 @@ def skip thing = nil thing ? Skip.new(self, thing) : self end - def take thing - Take.new self, thing + def take count + Take.new self, count end def from thing From 04b3f0611c69532526d8b16799a7625b92dcf1fc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:38:54 -0700 Subject: [PATCH 0539/1492] PERF: removing def engine --- lib/arel/algebra/relations/operations/take.rb | 11 ----------- spec/support/model.rb | 9 +++++++-- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index 421051124c90c..299c29ab727f4 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -7,17 +7,6 @@ def initialize relation, taken @taken = taken end - def engine - engine = relation.engine - - # Temporary check of whether or not the engine supports where. - if engine.respond_to?(:supports) && !engine.supports(:limiting) - Memory::Engine.new - else - engine - end - end - def externalizable? true end diff --git a/spec/support/model.rb b/spec/support/model.rb index d5be35cbba98f..969af83cc633f 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -1,6 +1,6 @@ module Arel module Testing - class Engine + class Engine < Arel::Memory::Engine attr_reader :rows def initialize @@ -12,7 +12,12 @@ def supports(operation) end def read(relation) - @rows.dup.map { |r| Row.new(relation, r) } + case relation + when Arel::Take + relation.eval + else + @rows.dup.map { |r| Row.new(relation, r) } + end end def create(insert) From a323b3d0b561ca3145e4ae0fe94c137f9620e8f6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:40:01 -0700 Subject: [PATCH 0540/1492] PERF: removing another def engine --- lib/arel/algebra/relations/operations/order.rb | 11 ----------- spec/support/model.rb | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index bf0e0f723c5e1..d91e400419e55 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -20,17 +20,6 @@ def orders (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } end - def engine - engine = relation.engine - - # Temporary check of whether or not the engine supports where. - if engine.respond_to?(:supports) && !engine.supports(:ordering) - Memory::Engine.new - else - engine - end - end - def eval unoperated_rows.sort do |row1, row2| ordering = orders.detect { |o| o.eval(row1, row2) != 0 } || orders.last diff --git a/spec/support/model.rb b/spec/support/model.rb index 969af83cc633f..ebcde0ee9a4d1 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -13,7 +13,7 @@ def supports(operation) def read(relation) case relation - when Arel::Take + when Arel::Take, Arel::Order relation.eval else @rows.dup.map { |r| Row.new(relation, r) } From 5bbd3d03d327b34ab2f3865f64b9008f6064d89a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:40:55 -0700 Subject: [PATCH 0541/1492] PERF: removing another def engine --- lib/arel/algebra/relations/operations/skip.rb | 11 ----------- spec/support/model.rb | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 5a87fbb7b5225..7e4ad2b2785e6 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -14,17 +14,6 @@ def == other skipped == other.skipped end - def engine - engine = relation.engine - - # Temporary check of whether or not the engine supports where. - if engine.respond_to?(:supports) && !engine.supports(:skipping) - Memory::Engine.new - else - engine - end - end - def eval unoperated_rows[skipped..-1] end diff --git a/spec/support/model.rb b/spec/support/model.rb index ebcde0ee9a4d1..f4973f4c57972 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -13,7 +13,7 @@ def supports(operation) def read(relation) case relation - when Arel::Take, Arel::Order + when Arel::Take, Arel::Order, Arel::Skip relation.eval else @rows.dup.map { |r| Row.new(relation, r) } From 1e327a5047f71ea6c93cde208c8b9206627c7302 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 10:41:50 -0700 Subject: [PATCH 0542/1492] PERF: removing another def engine --- lib/arel/algebra/relations/operations/where.rb | 11 ----------- spec/support/model.rb | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index d851aebc4495c..98efb72ec11d9 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -12,17 +12,6 @@ def wheres @wheres ||= relation.wheres + predicates end - def engine - engine = relation.engine - - # Temporary check of whether or not the engine supports where. - if engine.respond_to?(:supports) && !engine.supports(:restricting) - Memory::Engine.new - else - engine - end - end - def eval unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } } end diff --git a/spec/support/model.rb b/spec/support/model.rb index f4973f4c57972..45fe254d6ff20 100644 --- a/spec/support/model.rb +++ b/spec/support/model.rb @@ -13,7 +13,7 @@ def supports(operation) def read(relation) case relation - when Arel::Take, Arel::Order, Arel::Skip + when Arel::Take, Arel::Order, Arel::Skip, Arel::Where relation.eval else @rows.dup.map { |r| Row.new(relation, r) } From 53bfaedaca5387bbc27a4ce04ea47367aaf4401a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 11:00:09 -0700 Subject: [PATCH 0543/1492] PERF caching engine, converting to an attr_reader --- lib/arel/algebra/relations/utilities/compound.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 25f634ef78c49..80ac0b1351409 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -2,13 +2,14 @@ module Arel class Compound include Relation - attr_reader :relation + attr_reader :relation, :engine delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, :column_for, :sources, :locked, :table_alias, :array, :to => :relation def initialize relation @relation = relation + @engine = relation.engine @attributes = nil @wheres = nil @groupings = nil @@ -32,9 +33,5 @@ def attributes def unoperated_rows relation.call.collect { |row| row.bind(self) } end - - def engine - relation.engine - end end end From fa0f32d3cd0bc9fbc17ddfa5bbb699064c443c5c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 13:05:58 -0700 Subject: [PATCH 0544/1492] PERF: eliminating a case statement --- lib/arel/algebra/predicates.rb | 1 + lib/arel/algebra/relations/relation.rb | 9 +-------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 4920bc9713d56..9764c4cfa2ce6 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -141,6 +141,7 @@ def eval(row) def to_sql(formatter = nil) "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" end + alias :value :to_sql end class CompoundPredicate < Binary diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9ff436ecb7ed7..804ef5a09f923 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -83,14 +83,7 @@ def from_clauses end def where_clauses - wheres.collect { |w| - case w - when Value - w.value - else # FIXME: why do we have to pass in a whereclause? - w.to_sql(Sql::WhereClause.new(self)) - end - } + wheres.map { |w| w.value } end def group_clauses From 165a312fb3c3ad0e55478b99fa1851b5ee8c56a0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 13:26:11 -0700 Subject: [PATCH 0545/1492] changing default value to TrueClass --- lib/arel/algebra/relations/operations/lock.rb | 8 +------- lib/arel/algebra/relations/relation.rb | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/relations/operations/lock.rb b/lib/arel/algebra/relations/operations/lock.rb index 003bd29c8ad32..394ad6f0ecd13 100644 --- a/lib/arel/algebra/relations/operations/lock.rb +++ b/lib/arel/algebra/relations/operations/lock.rb @@ -4,13 +4,7 @@ class Lock < Compound def initialize(relation, locked) super(relation) - @locked = locked.blank? ? " FOR UPDATE" : locked - end - - def == other - super || Lock === other && - relation == other.relation && - locked == other.locked + @locked = true == locked ? " FOR UPDATE" : locked end end end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 804ef5a09f923..c6e2727c8f53c 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -144,7 +144,7 @@ def from thing From.new self, thing end - def lock(locking = nil) + def lock(locking = true) Lock.new(self, locking) end From 19c5a95f1093653d2628dfb2f53637b0425dbba4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 14:41:26 -0700 Subject: [PATCH 0546/1492] caching existence of a table --- lib/arel/engines/sql/relations/table.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index f56fd7d813821..82668970985cb 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -13,6 +13,8 @@ def tables= e; @@tables = e; end end attr_reader :name, :engine, :table_alias, :options, :christener + attr_reader :table_exists + alias :table_exists? :table_exists def initialize(name, options = {}) @name = name.to_s @@ -45,6 +47,8 @@ def initialize(name, options = {}) end @@tables ||= engine.connection.tables + @table_exists = @@tables.include?(name) || + @engine.connection.table_exists?(name) end end @@ -52,10 +56,6 @@ def as(table_alias) Table.new(name, options.merge(:as => table_alias)) end - def table_exists? - @table_exists ||= @@tables.include?(name) || engine.connection.table_exists?(name) - end - def attributes return @attributes if defined?(@attributes) if table_exists? From bef0d30e30b99c8e56325645a9f643b60ce3dff9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 14:47:37 -0700 Subject: [PATCH 0547/1492] removing Table#== as it is not actually used --- lib/arel/algebra/relations/relation.rb | 2 +- lib/arel/engines/sql/relations/table.rb | 7 ------- spec/sql/christener_spec.rb | 8 -------- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index c6e2727c8f53c..9b90142de9ce5 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -129,7 +129,7 @@ def #{op}(*args) end def where clause = nil - clause ? Where.new(self, [clause]) : self + clause ? Where.new(self, Array(clause)) : self end def skip thing = nil diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 82668970985cb..35b6b5ce5c9fe 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -82,13 +82,6 @@ def reset @columns = nil @attributes = Header.new([]) end - - def ==(other) - super || - Table === other && - name == other.name && - table_alias == other.table_alias - end end end diff --git a/spec/sql/christener_spec.rb b/spec/sql/christener_spec.rb index d50cb56261e0b..895ec2a9b65e0 100644 --- a/spec/sql/christener_spec.rb +++ b/spec/sql/christener_spec.rb @@ -3,14 +3,6 @@ module Arel module Sql describe "Christener" do - it "returns the same name with two table objects" do - christener = Christener.new - table = Table.new 'users' - table2 = Table.new 'users' - christener.name_for(table).should == 'users' - christener.name_for(table2).should == 'users' - end - it "returns the first name" do christener = Christener.new table = Table.new 'users' From 23294241b10d162c3eb90353bfec5735711a7eab Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 15:15:03 -0700 Subject: [PATCH 0548/1492] PERF: reducing call stack --- lib/arel/algebra/relations/utilities/compound.rb | 8 ++++++++ lib/arel/engines/sql/relations.rb | 1 - lib/arel/engines/sql/relations/utilities/compound.rb | 10 ---------- 3 files changed, 8 insertions(+), 11 deletions(-) delete mode 100644 lib/arel/engines/sql/relations/utilities/compound.rb diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 80ac0b1351409..8a8f3ab6092b6 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -18,6 +18,14 @@ def initialize relation @projections = nil end + def table + @relation.table + end + + def table_sql(formatter = Sql::TableReference.new(self)) + @relation.table_sql formatter + end + [:wheres, :groupings, :orders, :havings, :projections].each do |operation_name| class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index c6926834215a1..d1711d058fa5d 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -1,4 +1,3 @@ -require 'arel/engines/sql/relations/utilities/compound' require 'arel/engines/sql/relations/utilities/nil' require 'arel/engines/sql/relations/compiler' require 'arel/engines/sql/relations/table' diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb deleted file mode 100644 index 55853be742804..0000000000000 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Compound - delegate :table, :table_sql, :to => :relation - - def build_query(*parts) - parts.compact.join(" ") - end - end -end - From 020b03749fff4b1fcea52553846ece822ea8e840 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 16:05:11 -0700 Subject: [PATCH 0549/1492] PERF: cache the engine in the formatter --- lib/arel/engines/sql/formatters.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index aab4282f04838..03e7deec007f8 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -1,21 +1,18 @@ module Arel module Sql class Formatter - attr_reader :environment, :christener + attr_reader :environment, :christener, :engine def initialize(environment) @environment = environment @christener = environment.christener + @engine = environment.engine end def name_for thing @christener.name_for thing end - def engine - @environment.engine - end - def quote_column_name name engine.connection.quote_column_name name end From 34303cc6176f47c1359a2fca8f50365e601509f0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 30 Jul 2010 19:05:41 -0700 Subject: [PATCH 0550/1492] removing module for faster method lookup --- lib/arel/algebra/expression.rb | 23 ++++++++----------- .../unit/primitives/expression_spec.rb | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/arel/algebra/expression.rb b/lib/arel/algebra/expression.rb index 5a93ca9735e7b..f7ba57a757a17 100644 --- a/lib/arel/algebra/expression.rb +++ b/lib/arel/algebra/expression.rb @@ -20,20 +20,17 @@ def to_sql(formatter = Sql::SelectClause.new(relation)) formatter.expression self end - module Transformations - def as(aliaz) - self.class.new(attribute, aliaz, self) - end - - def bind(new_relation) - new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) - end - - def to_attribute(relation) - Attribute.new(relation, @alias, :ancestor => self) - end + def as(aliaz) + self.class.new(attribute, aliaz, self) + end + + def bind(new_relation) + new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) + end + + def to_attribute(relation) + Attribute.new(relation, @alias, :ancestor => self) end - include Transformations end class Count < Expression diff --git a/spec/algebra/unit/primitives/expression_spec.rb b/spec/algebra/unit/primitives/expression_spec.rb index 483817f735797..f95ef69f96dde 100644 --- a/spec/algebra/unit/primitives/expression_spec.rb +++ b/spec/algebra/unit/primitives/expression_spec.rb @@ -7,7 +7,7 @@ module Arel @attribute = @relation[:id] end - describe Expression::Transformations do + describe 'Expression::Transformations' do before do @expression = Count.new(@attribute) end From b41d3609be49f74c840a7d9001e7dc2d75296155 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 2 Aug 2010 09:43:20 -0700 Subject: [PATCH 0551/1492] unfactoring WHERE to_sql --- lib/arel/algebra/relations/operations/where.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb index 98efb72ec11d9..ed80fd93ba934 100644 --- a/lib/arel/algebra/relations/operations/where.rb +++ b/lib/arel/algebra/relations/operations/where.rb @@ -15,5 +15,9 @@ def wheres def eval unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } } end + + def to_sql(formatter = nil) + compiler.select_sql + end end end From a7e0d6e85a9d4562a3e16e7fdc2dbd0719ae36ed Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 2 Aug 2010 09:48:00 -0700 Subject: [PATCH 0552/1492] unfactoring JOIN to_sql --- lib/arel/algebra/relations/operations/join.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index bfb7727313018..35374972be325 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -69,6 +69,10 @@ def eval end result end + + def to_sql(formatter = nil) + compiler.select_sql + end end class InnerJoin < Join From fa12b394ff6240358a32ecff63700f85084da5ac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Aug 2010 16:04:28 -0700 Subject: [PATCH 0553/1492] removing Group#==, improving Group test --- lib/arel/algebra/relations/operations/group.rb | 7 ------- spec/algebra/unit/relations/relation_spec.rb | 5 ++++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index f3666cacf838b..16a2963c93444 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -7,13 +7,6 @@ def initialize(relation, groupings) @groupings = groupings.collect { |g| g.bind(relation) } end - def == other - super || - self.class === other && - @relation == other.relation && - @groupings == other.groupings - end - def eval raise NotImplementedError end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 1a15471f9aa3f..4a7d9be0dce64 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -160,7 +160,10 @@ module Arel describe '#group' do it 'manufactures a group relation' do - @relation.group(@attribute1, @attribute2).should == Group.new(@relation, [@attribute1, @attribute2]) + group = @relation.group(@attribute1, @attribute2) + group.relation.should == @relation + group.groupings.should == [@attribute1, @attribute2] + group.should be_kind_of Group end describe 'when given blank groupings' do From 1b4e7715d3872cee9fbcd3ce0b6713294d04b5bc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Aug 2010 16:05:49 -0700 Subject: [PATCH 0554/1492] adding a spec for Group#to_sql --- spec/algebra/unit/relations/relation_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 4a7d9be0dce64..1219f80bc3d97 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -164,6 +164,8 @@ module Arel group.relation.should == @relation group.groupings.should == [@attribute1, @attribute2] group.should be_kind_of Group + sql = group.to_sql + sql.should =~ /GROUP BY/ end describe 'when given blank groupings' do From 0bb00a6999c7df2ea1c641e8bd6ada3023981617 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Aug 2010 16:55:53 -0700 Subject: [PATCH 0555/1492] unfactoring DefaultOperations --- lib/arel/algebra/relations/relation.rb | 29 ++++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9b90142de9ce5..de48aaf04e06e 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -194,6 +194,19 @@ def position_of(attribute) @position_of[attribute] = attributes.index(attributes[attribute]) end + def attributes; Header.new end + def projections; [] end + def wheres; [] end + def orders; [] end + def inserts; [] end + def groupings; [] end + def havings; [] end + def joins(formatter = nil); nil end # FIXME + def taken; nil end + def skipped; nil end + def sources; [] end + def locked; [] end + private def matching_attributes(attribute) (@matching_attributes ||= attributes.inject({}) do |hash, a| @@ -205,21 +218,5 @@ def matching_attributes(attribute) def has_attribute?(attribute) !matching_attributes(attribute).empty? end - - module DefaultOperations - def attributes; Header.new end - def projections; [] end - def wheres; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def havings; [] end - def joins(formatter = nil); nil end # FIXME - def taken; nil end - def skipped; nil end - def sources; [] end - def locked; [] end - end - include DefaultOperations end end From 4781d510da928862b2dd3eac3f9363eda321e60c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Aug 2010 17:15:02 -0700 Subject: [PATCH 0556/1492] PERF: delegate is slow, lets just write a delegate method --- lib/arel/algebra/relations/utilities/compound.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 8a8f3ab6092b6..58c9c7422e72f 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -4,7 +4,7 @@ class Compound attr_reader :relation, :engine delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :sources, :locked, :table_alias, :array, + :column_for, :locked, :table_alias, :array, :to => :relation def initialize relation @@ -18,6 +18,10 @@ def initialize relation @projections = nil end + def sources + @relation.sources + end + def table @relation.table end From 4fcd1622ba6f9a2a44301bffcb7f5aee0d5db605 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Aug 2010 17:18:37 -0700 Subject: [PATCH 0557/1492] separating test code from implementation code --- lib/arel/algebra/relations/operations/order.rb | 7 ------- spec/algebra/unit/relations/relation_spec.rb | 5 ++++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index d91e400419e55..e7306fe384ba3 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -7,13 +7,6 @@ def initialize(relation, orderings) @orderings = orderings.collect { |o| o.bind(relation) } end - def == other - super || - Order === other && - relation == other.relation && - orderings == other.orderings - end - # TESTME def orders # QUESTION - do we still need relation.orders ? diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 1219f80bc3d97..07a7dcb843969 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -122,7 +122,10 @@ module Arel describe '#order' do it "manufactures an order relation" do - @relation.order(@attribute1, @attribute2).should == Order.new(@relation, [@attribute1, @attribute2]) + order = @relation.order(@attribute1, @attribute2) + order.relation.should == @relation + order.orderings.should == [@attribute1, @attribute2] + order.should be_kind_of Order end describe 'when given a blank ordering' do From 1b62990cfa10feea7f3937bbcd2145adae84db85 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 4 Aug 2010 17:37:01 -0700 Subject: [PATCH 0558/1492] unfactoring to use concrete delegate methods --- lib/arel/algebra/relations/utilities/compound.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 58c9c7422e72f..0a270f78a1897 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -3,9 +3,6 @@ class Compound include Relation attr_reader :relation, :engine - delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :locked, :table_alias, :array, - :to => :relation def initialize relation @relation = relation @@ -18,6 +15,15 @@ def initialize relation @projections = nil end + def join?; @relation.join? end + def name; @relation.name end + def table_alias; @relation.table_alias end + def skipped; @relation.skipped end + def taken; @relation.taken end + def joins env; @relation.joins env end + def column_for attr; @relation.column_for attr end + def externalizable?; @relation.externalizable? end + def sources @relation.sources end From 4c43dac54e649f579a96505e0038cfb6ea52ef1e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 08:58:58 -0700 Subject: [PATCH 0559/1492] unfactoring more module inclusion --- lib/arel/algebra/relations/relation.rb | 97 ++++++++++---------- spec/algebra/unit/relations/relation_spec.rb | 2 +- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index de48aaf04e06e..e2f9f128660e0 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -102,75 +102,72 @@ def each session.read(self).each { |e| yield e } end - module Operable - def join(other_relation = nil, join_class = InnerJoin) - case other_relation - when String - StringJoin.new(self, other_relation) - when Relation - JoinOperation.new(join_class, self, other_relation) - else - self - end + def join(other_relation = nil, join_class = InnerJoin) + case other_relation + when String + StringJoin.new(self, other_relation) + when Relation + JoinOperation.new(join_class, self, other_relation) + else + self end + end - def outer_join(other_relation = nil) - join(other_relation, OuterJoin) - end + def outer_join(other_relation = nil) + join(other_relation, OuterJoin) + end - %w{ + %w{ having group order project - }.each do |op| - class_eval <<-OPERATION, __FILE__, __LINE__ + }.each do |op| + class_eval <<-OPERATION, __FILE__, __LINE__ def #{op}(*args) args.all? { |x| x.blank? } ? self : #{op.capitalize}.new(self, args) end - OPERATION - end + OPERATION + end - def where clause = nil - clause ? Where.new(self, Array(clause)) : self - end + def where clause = nil + clause ? Where.new(self, Array(clause)) : self + end - def skip thing = nil - thing ? Skip.new(self, thing) : self - end + def skip thing = nil + thing ? Skip.new(self, thing) : self + end - def take count - Take.new self, count - end + def take count + Take.new self, count + end - def from thing - From.new self, thing - end + def from thing + From.new self, thing + end - def lock(locking = true) - Lock.new(self, locking) - end + def lock(locking = true) + Lock.new(self, locking) + end - def alias - Alias.new(self) - end + def alias + Alias.new(self) + end - def insert(record) - session.create Insert.new(self, record) - end + def insert(record) + session.create Insert.new(self, record) + end - def update(assignments) - session.update Update.new(self, assignments) - end + def update(assignments) + session.update Update.new(self, assignments) + end - def delete - session.delete Deletion.new(self) - end + def delete + session.delete Deletion.new(self) + end - JoinOperation = Struct.new(:join_class, :relation1, :relation2) do - def on(*predicates) - join_class.new(relation1, relation2, *predicates) - end + JoinOperation = Struct.new(:join_class, :relation1, :relation2) do + def on(*predicates) + join_class.new(relation1, relation2, *predicates) end end - include Operable def [](index) attributes[index] diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index 07a7dcb843969..d08c38acd5c57 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -23,7 +23,7 @@ module Arel end end - describe Relation::Operable do + describe 'Relation::Operable' do describe 'joins' do before do @predicate = @relation[:id].eq(@relation[:id]) From 0e9a9c7aa7791de708657c269dd7b9bb0f42b01c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 09:14:10 -0700 Subject: [PATCH 0560/1492] removing test code from implementation --- lib/arel/algebra/relations/writes.rb | 7 ------- spec/algebra/unit/relations/relation_spec.rb | 21 ++++++++++++++++---- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb index 8cf7a7cdad1d6..7df6d861a8917 100644 --- a/lib/arel/algebra/relations/writes.rb +++ b/lib/arel/algebra/relations/writes.rb @@ -1,8 +1,5 @@ module Arel class Action < Compound - def == other - super || self.class === other && @relation == other.relation - end end class Deletion < Action @@ -27,10 +24,6 @@ def call engine.create(self) end - def == other - super && @record == other.record - end - def eval unoperated_rows + [Row.new(self, record.values.collect(&:value))] end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index d08c38acd5c57..a7e14e6be5dc8 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -182,7 +182,10 @@ module Arel describe '#delete' do it 'manufactures a deletion relation' do Session.start do |s| - s.should_receive(:delete).with(Deletion.new(@relation)) + s.should_receive(:delete) do |delete| + delete.relation.should == @relation + delete.should be_kind_of Deletion + end @relation.delete end end @@ -191,8 +194,13 @@ module Arel describe '#insert' do it 'manufactures an insertion relation' do Session.start do |s| - record = { @relation[:name] => 'carl' } - s.should_receive(:create).with(Insert.new(@relation, record)) + record = { @relation[:name] => Value.new('carl', @relation) } + s.should_receive(:create) do |insert| + insert.relation.should == @relation + insert.record.should == record + insert.should be_kind_of Insert + insert + end @relation.insert(record) end end @@ -202,7 +210,12 @@ module Arel it 'manufactures an update relation' do Session.start do |s| assignments = { @relation[:name] => Value.new('bob', @relation) } - s.should_receive(:update).with(Update.new(@relation, assignments)) + s.should_receive(:update) do |update| + update.relation.should == @relation + update.assignments.should == assignments + update.should be_kind_of Update + update + end @relation.update(assignments) end end From f9e2a2eb44477f2a966310cd2cb37bf744476fb1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 09:17:58 -0700 Subject: [PATCH 0561/1492] removing unused code --- lib/arel/algebra/ordering.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/algebra/ordering.rb b/lib/arel/algebra/ordering.rb index 8ed3e1e6e62b0..c1a4ef8b70ff4 100644 --- a/lib/arel/algebra/ordering.rb +++ b/lib/arel/algebra/ordering.rb @@ -10,10 +10,6 @@ def to_ordering self end - def == other - super || (self.class === other && attribute == other.attribute) - end - def eval(row1, row2) (attribute.eval(row1) <=> attribute.eval(row2)) * direction end From a70455b9d74eba1ec2653739bcb742a3fee6d437 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 09:18:24 -0700 Subject: [PATCH 0562/1492] removing unused code --- lib/arel/algebra/expression.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/algebra/expression.rb b/lib/arel/algebra/expression.rb index f7ba57a757a17..32cf4f12c9746 100644 --- a/lib/arel/algebra/expression.rb +++ b/lib/arel/algebra/expression.rb @@ -8,10 +8,6 @@ def initialize(attribute, aliaz = nil, ancestor = nil) @attribute = attribute end - def == other - super && Expression === other && attribute == other.attribute - end - def aggregation? true end From 53db9d80021f399fae312eff935e437a413f8e2d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 09:22:36 -0700 Subject: [PATCH 0563/1492] removing test code from implementation --- lib/arel/algebra/relations/operations/having.rb | 6 ------ lib/arel/algebra/relations/operations/skip.rb | 7 ------- spec/algebra/unit/relations/relation_spec.rb | 5 ++++- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb index d36aad071b9d0..3d8115c2f61e3 100644 --- a/lib/arel/algebra/relations/operations/having.rb +++ b/lib/arel/algebra/relations/operations/having.rb @@ -10,11 +10,5 @@ def initialize(relation, predicates) def havings @havings ||= relation.havings + predicates end - - def == other - super || Having === other && - relation == other.relation && - predicates == other.predicates - end end end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 7e4ad2b2785e6..a9157e914ccb1 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -7,13 +7,6 @@ def initialize relation, skipped @skipped = skipped end - def == other - super || - Skip === other && - relation == other.relation && - skipped == other.skipped - end - def eval unoperated_rows[skipped..-1] end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb index a7e14e6be5dc8..a1ffd901d7f19 100644 --- a/spec/algebra/unit/relations/relation_spec.rb +++ b/spec/algebra/unit/relations/relation_spec.rb @@ -151,7 +151,10 @@ module Arel describe '#skip' do it "manufactures a skip relation" do - @relation.skip(4).should == Skip.new(@relation, 4) + skip = @relation.skip(4) + skip.relation.should == @relation + skip.skipped.should == 4 + skip.should be_kind_of Skip end describe 'when given a blank number of items' do From 09a5847044e63bcc2b391720cf6bf084f03b4501 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 10:06:19 -0700 Subject: [PATCH 0564/1492] removing test code from implementation --- lib/arel/algebra/relations/row.rb | 7 ----- .../integration/joins/cross_engine_spec.rb | 26 +++++++++++++------ .../memory/unit/relations/array_spec.rb | 11 ++++---- .../memory/unit/relations/join_spec.rb | 11 ++++---- .../memory/unit/relations/order_spec.rb | 11 ++++---- .../memory/unit/relations/project_spec.rb | 10 +++---- .../memory/unit/relations/skip_spec.rb | 13 +++++++--- .../memory/unit/relations/take_spec.rb | 10 ++++--- .../memory/unit/relations/where_spec.rb | 18 ++++++++----- 9 files changed, 67 insertions(+), 50 deletions(-) diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index f5fe364b83239..f303dcd8d1b47 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -7,13 +7,6 @@ def initialize relation, tuple @tuple = tuple end - def == other - super || - Row === other && - relation == other.relation && - tuple == other.tuple - end - def [](attribute) attribute.type_cast(tuple[relation.position_of(attribute)]) end diff --git a/spec/engines/memory/integration/joins/cross_engine_spec.rb b/spec/engines/memory/integration/joins/cross_engine_spec.rb index 091fd2ceda6b6..4646eeba2f6f7 100644 --- a/spec/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/engines/memory/integration/joins/cross_engine_spec.rb @@ -25,10 +25,15 @@ module Arel .on(@users[:id].eq(@photos[:user_id])) \ .project(@users[:name], @photos[:camera_id]) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, ['bryan', @adapter_returns_integer ? 6 : '6']), - Row.new(relation, ['emilio', @adapter_returns_integer ? 42 : '42']) - ] + rows = relation.call + rows.length.should == 2 + [ + ['bryan', @adapter_returns_integer ? 6 : '6'], + ['emilio', @adapter_returns_integer ? 42 : '42'] + ].zip(rows).each do |tuple, row| + row.relation.should == relation + row.tuple.should == tuple + end end end end @@ -40,10 +45,15 @@ module Arel .on(@users[:id].eq(@photos[:user_id])) \ .project(@users[:name], @photos[:camera_id]) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, ['bryan', @adapter_returns_integer ? 6 : '6']), - Row.new(relation, ['emilio', @adapter_returns_integer ? 42 : '42']) - ] + rows = relation.call + rows.length.should == 2 + [ + ['bryan', @adapter_returns_integer ? 6 : '6'], + ['emilio', @adapter_returns_integer ? 42 : '42'] + ].zip(rows).each do |tuple, row| + row.relation.should == relation + row.tuple.should == tuple + end end end end diff --git a/spec/engines/memory/unit/relations/array_spec.rb b/spec/engines/memory/unit/relations/array_spec.rb index dcec2afa19dba..65bfb4025fa81 100644 --- a/spec/engines/memory/unit/relations/array_spec.rb +++ b/spec/engines/memory/unit/relations/array_spec.rb @@ -21,11 +21,12 @@ module Arel describe '#call' do it "manufactures an array of hashes of attributes to values" do - @relation.call.should == [ - Row.new(@relation, [1, 'duck']), - Row.new(@relation, [2, 'duck']), - Row.new(@relation, [3, 'goose']) - ] + rows = @relation.call + rows.length.should == 3 + @relation.array.zip(rows).each do |tuple, row| + row.relation.should == @relation + row.tuple.should == tuple + end end end end diff --git a/spec/engines/memory/unit/relations/join_spec.rb b/spec/engines/memory/unit/relations/join_spec.rb index 9a475d817d914..93379985cbc67 100644 --- a/spec/engines/memory/unit/relations/join_spec.rb +++ b/spec/engines/memory/unit/relations/join_spec.rb @@ -18,11 +18,12 @@ module Arel .join(@relation2) \ .on(@relation1[:id].eq(@relation2[:id])) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck', 1, 'duck' ]), - Row.new(relation, [2, 'duck', 2, 'duck' ]), - Row.new(relation, [3, 'goose', 3, 'goose']) - ] + rows = relation.call + rows.length.should == 3 + @relation1.array.zip(rows).each do |tuple, row| + row.relation.should == relation + row.tuple.should == (tuple * 2) + end end end end diff --git a/spec/engines/memory/unit/relations/order_spec.rb b/spec/engines/memory/unit/relations/order_spec.rb index 0d746bcd0af55..86c59ffc465a1 100644 --- a/spec/engines/memory/unit/relations/order_spec.rb +++ b/spec/engines/memory/unit/relations/order_spec.rb @@ -15,11 +15,12 @@ module Arel @relation \ .order(@relation[:id].desc) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [3, 'goose']), - Row.new(relation, [2, 'duck' ]), - Row.new(relation, [1, 'duck' ]) - ] + rows = relation.call + rows.length.should == 3 + @relation.array.reverse.zip(rows) do |tuple, row| + row.relation.should == relation + row.tuple.should == tuple + end end end end diff --git a/spec/engines/memory/unit/relations/project_spec.rb b/spec/engines/memory/unit/relations/project_spec.rb index 3970a50129ef0..cf20573fd2447 100644 --- a/spec/engines/memory/unit/relations/project_spec.rb +++ b/spec/engines/memory/unit/relations/project_spec.rb @@ -15,11 +15,11 @@ module Arel @relation \ .project(@relation[:id]) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [1]), - Row.new(relation, [2]), - Row.new(relation, [3]) - ] + rows = relation.call + @relation.array.zip(rows) do |tuple, row| + row.relation.should == relation + row.tuple.should == [tuple.first] + end end end end diff --git a/spec/engines/memory/unit/relations/skip_spec.rb b/spec/engines/memory/unit/relations/skip_spec.rb index 4cf6c020bc223..abb87d2e3849b 100644 --- a/spec/engines/memory/unit/relations/skip_spec.rb +++ b/spec/engines/memory/unit/relations/skip_spec.rb @@ -15,10 +15,15 @@ module Arel @relation \ .skip(1) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [2, 'duck']), - Row.new(relation, [3, 'goose']), - ] + rows = relation.call + rows.length.should == 2 + one, two = *rows + + one.relation.should == relation + one.tuple.should == [2, 'duck'] + + two.relation.should == relation + two.tuple.should == [3, 'goose'] end end end diff --git a/spec/engines/memory/unit/relations/take_spec.rb b/spec/engines/memory/unit/relations/take_spec.rb index f74f1a74c822a..b7e49ddca6195 100644 --- a/spec/engines/memory/unit/relations/take_spec.rb +++ b/spec/engines/memory/unit/relations/take_spec.rb @@ -15,10 +15,12 @@ module Arel @relation \ .take(2) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - ] + rows = relation.call + rows.length.should == 2 + rows.each_with_index do |row, i| + row.relation.should == relation + row.tuple.should == [i + 1, 'duck'] + end end end end diff --git a/spec/engines/memory/unit/relations/where_spec.rb b/spec/engines/memory/unit/relations/where_spec.rb index 23aef5766e86c..c75fe10f1b74c 100644 --- a/spec/engines/memory/unit/relations/where_spec.rb +++ b/spec/engines/memory/unit/relations/where_spec.rb @@ -15,10 +15,12 @@ module Arel @relation \ .where(@relation[:id].lt(3)) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - ] + rows = relation.call + rows.length.should == 2 + rows.each_with_index do |row, i| + row.relation.should == relation + row.tuple.should == [i + 1, 'duck'] + end end end @@ -28,9 +30,11 @@ module Arel .where(@relation[:id].gt(1)) \ .where(@relation[:id].lt(3)) \ .tap do |relation| - relation.call.should == [ - Row.new(relation, [2, 'duck']) - ] + rows = relation.call + rows.length.should == 1 + row = rows.first + row.relation.should == relation + row.tuple.should == [2, 'duck'] end end end From 71e0cf6d062f58f3349be53a7ac8421e2c3f488f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 10:16:12 -0700 Subject: [PATCH 0565/1492] removing unused code --- lib/arel/engines/memory/relations/array.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 7f881dd849863..028f5c026952b 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -12,13 +12,6 @@ def initialize(array, attribute_names_and_types) @attributes = nil end - def == other - super || - Array === other && - array == other.array && - attribute_names_and_types == other.attribute_names_and_types - end - def engine @engine ||= Memory::Engine.new end From 21267d3c59457141e6dd6e47ba290df2cd583866 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 10:23:16 -0700 Subject: [PATCH 0566/1492] inject([]) is a fancy map! --- lib/arel/algebra/relations/row.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index f303dcd8d1b47..84f19e372f5b9 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -12,10 +12,9 @@ def [](attribute) end def slice(*attributes) - Row.new(relation, attributes.inject([]) do |cheese, attribute| + Row.new(relation, attributes.map do |attribute| # FIXME TESTME method chaining - cheese << tuple[relation.relation.position_of(attribute)] - cheese + tuple[relation.relation.position_of(attribute)] end) end From 389c4fc2582ae42c32a20b7f6a6cb2c5680343fc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 11:30:53 -0700 Subject: [PATCH 0567/1492] add an operator to inequality --- lib/arel/algebra/predicates.rb | 1 + spec/algebra/unit/predicates/inequality_spec.rb | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 9764c4cfa2ce6..e9fb51d889d06 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -197,6 +197,7 @@ def complement Equality.new(operand1, operand2) end + def operator; :"!=" end def eval(row) operand1.eval(row) != operand2.eval(row) end diff --git a/spec/algebra/unit/predicates/inequality_spec.rb b/spec/algebra/unit/predicates/inequality_spec.rb index 557494e2cd4f3..f95b8d120ec80 100644 --- a/spec/algebra/unit/predicates/inequality_spec.rb +++ b/spec/algebra/unit/predicates/inequality_spec.rb @@ -12,6 +12,12 @@ module Predicates @b = Inequality.new(right, left) end + describe 'operator' do + it "should have one" do + @a.operator.should == :"!=" + end + end + describe '==' do it "is equal to itself" do @a.should == @a From bbc42ff03d60fca1d51791399ae7041fa20e4185 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 13:29:17 -0700 Subject: [PATCH 0568/1492] removing a fancy map --- lib/arel/algebra/predicates.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index e9fb51d889d06..2426aae3961d9 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -32,8 +32,8 @@ def initialize(*predicates) # * additional_operands - All possible right-hand operands def self.build(operator, operand1, *additional_operands) new( - *additional_operands.uniq.inject([]) do |predicates, operand| - predicates << operator.new(operand1, operand) + *additional_operands.uniq.map do |operand| + operator.new(operand1, operand) end ) end From 12ba765448582cb86e5f57d6befc42c59eb295d9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 14:05:01 -0700 Subject: [PATCH 0569/1492] initializing instance variables --- lib/arel/engines/sql/relations/table.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 35b6b5ce5c9fe..dd9000d660b58 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -21,6 +21,8 @@ def initialize(name, options = {}) @table_exists = nil @table_alias = nil @christener = Sql::Christener.new + @attributes = nil + @matching_attributes = nil if options.is_a?(Hash) @options = options @@ -57,14 +59,12 @@ def as(table_alias) end def attributes - return @attributes if defined?(@attributes) + return @attributes if @attributes if table_exists? - @attributes ||= begin - attrs = columns.collect do |column| - Sql::Attributes.for(column).new(column, self, column.name.to_sym) - end - Header.new(attrs) + attrs = columns.collect do |column| + Sql::Attributes.for(column).new(column, self, column.name.to_sym) end + @attributes = Header.new(attrs) else Header.new end From c86f94986d60d607f374ef01f9b6428fc64ddc81 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 14:05:56 -0700 Subject: [PATCH 0570/1492] unfactoring module inclusion --- lib/arel/algebra/attributes/attribute.rb | 49 +++++++++---------- .../algebra/unit/primitives/attribute_spec.rb | 2 +- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 2a4b274a963f3..5b391f86b0de0 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -58,40 +58,37 @@ def to_attribute(relation) bind(relation) end - module Congruence - def history - @history ||= [self] + (ancestor ? ancestor.history : []) - end + def history + @history ||= [self] + (ancestor ? ancestor.history : []) + end - def join? - relation.join? - end + def join? + relation.join? + end - def root - history.last - end + def root + history.last + end - def original_relation - @original_relation ||= original_attribute.relation - end + def original_relation + @original_relation ||= original_attribute.relation + end - def original_attribute - @original_attribute ||= history.detect { |a| !a.join? } - end + def original_attribute + @original_attribute ||= history.detect { |a| !a.join? } + end - def find_correlate_in(relation) - relation[self] || self - end + def find_correlate_in(relation) + relation[self] || self + end - def descends_from?(other) - history.include?(other) - end + def descends_from?(other) + history.include?(other) + end - def /(other) - other ? (history & other.history).size : 0 - end + def /(other) + other ? (history & other.history).size : 0 end - include Congruence PREDICATES = [ :eq, :eq_any, :eq_all, :not_eq, :not_eq_any, :not_eq_all, :lt, :lt_any, diff --git a/spec/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb index 08d32614a155f..4026c0de14e2e 100644 --- a/spec/algebra/unit/primitives/attribute_spec.rb +++ b/spec/algebra/unit/primitives/attribute_spec.rb @@ -52,7 +52,7 @@ module Arel end end - describe Attribute::Congruence do + describe 'Attribute::Congruence' do describe '/' do before do @aliased_relation = @relation.alias From 60f8668d41d45b21d962bdc534bbc417d22e701b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 14:19:09 -0700 Subject: [PATCH 0571/1492] initializing instance variables, converting to attr-reader --- lib/arel/algebra/attributes/attribute.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb index 5b391f86b0de0..16124abcc41bf 100644 --- a/lib/arel/algebra/attributes/attribute.rb +++ b/lib/arel/algebra/attributes/attribute.rb @@ -4,12 +4,17 @@ module Arel class TypecastError < StandardError ; end class Attribute attr_reader :relation, :name, :alias, :ancestor, :hash + attr_reader :history, :root def initialize(relation, name, options = {}) @relation = relation # this is actually a table (I think) @name = name @alias = options[:alias] @ancestor = options[:ancestor] + @history = [self] + (@ancestor ? @ancestor.history : []) + @root = @history.last + @original_relation = nil + @original_attribute = nil # FIXME: I think we can remove this eventually @hash = name.hash + root.relation.class.hash @@ -58,10 +63,6 @@ def to_attribute(relation) bind(relation) end - def history - @history ||= [self] + (ancestor ? ancestor.history : []) - end - def join? relation.join? end From 677d77d43d0a09ab2ffca1cd45f5b1b090475ec4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 14:33:39 -0700 Subject: [PATCH 0572/1492] PERF: this hash only ever has one value, also avoid inject --- lib/arel/algebra/relations/relation.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index e2f9f128660e0..d51e24d08828f 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -206,10 +206,12 @@ def locked; [] end private def matching_attributes(attribute) - (@matching_attributes ||= attributes.inject({}) do |hash, a| - (hash[a.is_a?(Value) ? a.value : a.root] ||= []) << a - hash - end)[attribute.root] || [] + unless @matching_attributes + @matching_attributes = Hash[attributes.map do |a| + [a.root, a] + end] + end + [@matching_attributes[attribute.root]] || [] end def has_attribute?(attribute) From 06cc73cc9efbe2cacdbf8c6765ad6dab5a6e1aa0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 14:36:16 -0700 Subject: [PATCH 0573/1492] removing method that is never used --- lib/arel/algebra/relations/relation.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index d51e24d08828f..4c739edb4d683 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -177,12 +177,6 @@ def find_attribute_matching_name(name) attributes.detect { |a| a.named?(name) } || Attribute.new(self, name) end - def find_attribute_matching_attribute(attribute) - matching_attributes(attribute).max do |a1, a2| - (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) - end - end - def position_of(attribute) @position_of ||= {} From c7b4f12d9339504b58431de0145d9a965008e650 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 14:57:54 -0700 Subject: [PATCH 0574/1492] removing parameter requirement for matching_attributes --- lib/arel/algebra/relations/relation.rb | 14 -------------- lib/arel/engines/sql/relations/table.rb | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 4c739edb4d683..9807cfb984acb 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -197,19 +197,5 @@ def taken; nil end def skipped; nil end def sources; [] end def locked; [] end - - private - def matching_attributes(attribute) - unless @matching_attributes - @matching_attributes = Hash[attributes.map do |a| - [a.root, a] - end] - end - [@matching_attributes[attribute.root]] || [] - end - - def has_attribute?(attribute) - !matching_attributes(attribute).empty? - end end end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index dd9000d660b58..b31df7a6d0860 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -82,6 +82,15 @@ def reset @columns = nil @attributes = Header.new([]) end + + private + def matching_attributes + @matching_attributes ||= Hash[attributes.map { |a| [a.root, true] }] + end + + def has_attribute?(attribute) + matching_attributes.key? attribute.root + end end end From cf00da66924de0a4435391be70efe04ccfb12787 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 6 Aug 2010 16:14:50 -0700 Subject: [PATCH 0575/1492] PERF: reduce calls to Hash#[] --- lib/arel/engines/sql/christener.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index 3c7fb0425e054..b30883e47cbca 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -8,11 +8,11 @@ def initialize def name_for(relation) table = relation.table name = table.table_alias || table.name - @names[name] ||= [] + list = @names[name] ||= [] - @names[name] << table unless @names[name].include? table + list << table unless list.include? table - idx = @names[name].index table + idx = list.index table name + (idx == 0 ? '' : "_#{idx + 1}") end end From 72d329055508bddb4ee4852384446a319ebffb48 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 10 Aug 2010 14:00:37 -0700 Subject: [PATCH 0576/1492] lib is already in the load path --- spec/spec_helper.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a52fa257b7c6d..e92129d723432 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,3 @@ -dir = File.dirname(__FILE__) -$LOAD_PATH.unshift "#{dir}/../lib" - require 'rubygems' require 'spec' require 'pp' @@ -11,7 +8,7 @@ require "support/connections/#{adapter}_connection.rb" end -Dir["#{dir}/{support,shared}/*.rb"].each do |file| +Dir["spec/{support,shared}/*.rb"].each do |file| require file end From bcf73b8c482ef07dc6f037dd4acc41ebc2e36bec Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 11 Aug 2010 15:02:19 -0700 Subject: [PATCH 0577/1492] use empty? over all? --- lib/arel/algebra/relations/relation.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 9807cfb984acb..765d6fe9308d7 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -118,7 +118,7 @@ def outer_join(other_relation = nil) end %w{ - having group order project + having group order }.each do |op| class_eval <<-OPERATION, __FILE__, __LINE__ def #{op}(*args) @@ -127,6 +127,10 @@ def #{op}(*args) OPERATION end + def project *args + args.empty? ? self : Project.new(self, args) + end + def where clause = nil clause ? Where.new(self, Array(clause)) : self end From 48361010f28605debe070563679d3b2db265daed Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 11 Aug 2010 16:00:16 -0700 Subject: [PATCH 0578/1492] ivar lookup is slightly faster --- lib/arel/engines/sql/formatters.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 03e7deec007f8..da899902ff58c 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -14,15 +14,15 @@ def name_for thing end def quote_column_name name - engine.connection.quote_column_name name + @engine.connection.quote_column_name name end def quote_table_name name - engine.connection.quote_table_name name + @engine.connection.quote_table_name name end def quote value, column = nil - engine.connection.quote value, column + @engine.connection.quote value, column end end From 8543c9d302a726a13ef697cbedd96a2135678958 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 11 Aug 2010 16:05:28 -0700 Subject: [PATCH 0579/1492] speeding up Engine#connection --- lib/arel/engines/sql/engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 7e841d68bb2fd..ab9dcb48b5486 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -6,7 +6,7 @@ def initialize(ar = nil) end def connection - @ar ? @ar.connection : nil + @ar && @ar.connection end def adapter_name From 139038130dd0dadc995aeffd2300f0ef72b74258 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 11:09:54 -0700 Subject: [PATCH 0580/1492] clean slate --- lib/arel.rb | 12 - lib/arel/algebra.rb | 10 - lib/arel/algebra/attributes.rb | 7 - lib/arel/algebra/attributes/attribute.rb | 304 ----------------- lib/arel/algebra/attributes/boolean.rb | 21 -- lib/arel/algebra/attributes/decimal.rb | 9 - lib/arel/algebra/attributes/float.rb | 9 - lib/arel/algebra/attributes/integer.rb | 10 - lib/arel/algebra/attributes/string.rb | 10 - lib/arel/algebra/attributes/time.rb | 6 - lib/arel/algebra/core_extensions.rb | 3 - lib/arel/algebra/core_extensions/hash.rb | 7 - lib/arel/algebra/core_extensions/object.rb | 13 - lib/arel/algebra/core_extensions/symbol.rb | 9 - lib/arel/algebra/expression.rb | 56 ---- lib/arel/algebra/header.rb | 66 ---- lib/arel/algebra/ordering.rb | 31 -- lib/arel/algebra/predicates.rb | 306 ------------------ lib/arel/algebra/relations.rb | 16 - lib/arel/algebra/relations/operations/from.rb | 14 - .../algebra/relations/operations/group.rb | 14 - .../algebra/relations/operations/having.rb | 14 - lib/arel/algebra/relations/operations/join.rb | 103 ------ lib/arel/algebra/relations/operations/lock.rb | 10 - .../algebra/relations/operations/order.rb | 23 -- .../algebra/relations/operations/project.rb | 20 -- lib/arel/algebra/relations/operations/skip.rb | 14 - lib/arel/algebra/relations/operations/take.rb | 18 -- .../algebra/relations/operations/where.rb | 23 -- lib/arel/algebra/relations/relation.rb | 205 ------------ lib/arel/algebra/relations/row.rb | 29 -- .../algebra/relations/utilities/compound.rb | 55 ---- .../relations/utilities/externalization.rb | 26 -- lib/arel/algebra/relations/utilities/nil.rb | 7 - lib/arel/algebra/relations/writes.rb | 47 --- lib/arel/algebra/value.rb | 53 --- lib/arel/engines.rb | 2 - lib/arel/engines/memory.rb | 2 - lib/arel/engines/memory/engine.rb | 10 - lib/arel/engines/memory/relations.rb | 2 - lib/arel/engines/memory/relations/array.rb | 37 --- .../engines/memory/relations/operations.rb | 9 - lib/arel/engines/sql.rb | 6 - lib/arel/engines/sql/attributes.rb | 40 --- lib/arel/engines/sql/christener.rb | 20 -- .../engines/sql/compilers/ibm_db_compiler.rb | 48 --- .../engines/sql/compilers/mysql_compiler.rb | 11 - .../engines/sql/compilers/oracle_compiler.rb | 95 ------ .../sql/compilers/postgresql_compiler.rb | 50 --- .../engines/sql/compilers/sqlite_compiler.rb | 9 - lib/arel/engines/sql/core_extensions.rb | 4 - lib/arel/engines/sql/core_extensions/array.rb | 24 -- .../engines/sql/core_extensions/nil_class.rb | 15 - .../engines/sql/core_extensions/object.rb | 19 -- lib/arel/engines/sql/core_extensions/range.rb | 19 -- lib/arel/engines/sql/engine.rb | 47 --- lib/arel/engines/sql/formatters.rb | 138 -------- lib/arel/engines/sql/relations.rb | 3 - lib/arel/engines/sql/relations/compiler.rb | 153 --------- lib/arel/engines/sql/relations/table.rb | 100 ------ .../engines/sql/relations/utilities/nil.rb | 6 - lib/arel/recursion/base_case.rb | 13 - lib/arel/session.rb | 35 -- lib/arel/sql_literal.rb | 13 - lib/arel/version.rb | 3 - 65 files changed, 2513 deletions(-) delete mode 100644 lib/arel/algebra.rb delete mode 100644 lib/arel/algebra/attributes.rb delete mode 100644 lib/arel/algebra/attributes/attribute.rb delete mode 100644 lib/arel/algebra/attributes/boolean.rb delete mode 100644 lib/arel/algebra/attributes/decimal.rb delete mode 100644 lib/arel/algebra/attributes/float.rb delete mode 100644 lib/arel/algebra/attributes/integer.rb delete mode 100644 lib/arel/algebra/attributes/string.rb delete mode 100644 lib/arel/algebra/attributes/time.rb delete mode 100644 lib/arel/algebra/core_extensions.rb delete mode 100644 lib/arel/algebra/core_extensions/hash.rb delete mode 100644 lib/arel/algebra/core_extensions/object.rb delete mode 100644 lib/arel/algebra/core_extensions/symbol.rb delete mode 100644 lib/arel/algebra/expression.rb delete mode 100644 lib/arel/algebra/header.rb delete mode 100644 lib/arel/algebra/ordering.rb delete mode 100644 lib/arel/algebra/predicates.rb delete mode 100644 lib/arel/algebra/relations.rb delete mode 100644 lib/arel/algebra/relations/operations/from.rb delete mode 100644 lib/arel/algebra/relations/operations/group.rb delete mode 100644 lib/arel/algebra/relations/operations/having.rb delete mode 100644 lib/arel/algebra/relations/operations/join.rb delete mode 100644 lib/arel/algebra/relations/operations/lock.rb delete mode 100644 lib/arel/algebra/relations/operations/order.rb delete mode 100644 lib/arel/algebra/relations/operations/project.rb delete mode 100644 lib/arel/algebra/relations/operations/skip.rb delete mode 100644 lib/arel/algebra/relations/operations/take.rb delete mode 100644 lib/arel/algebra/relations/operations/where.rb delete mode 100644 lib/arel/algebra/relations/relation.rb delete mode 100644 lib/arel/algebra/relations/row.rb delete mode 100644 lib/arel/algebra/relations/utilities/compound.rb delete mode 100644 lib/arel/algebra/relations/utilities/externalization.rb delete mode 100644 lib/arel/algebra/relations/utilities/nil.rb delete mode 100644 lib/arel/algebra/relations/writes.rb delete mode 100644 lib/arel/algebra/value.rb delete mode 100644 lib/arel/engines.rb delete mode 100644 lib/arel/engines/memory.rb delete mode 100644 lib/arel/engines/memory/engine.rb delete mode 100644 lib/arel/engines/memory/relations.rb delete mode 100644 lib/arel/engines/memory/relations/array.rb delete mode 100644 lib/arel/engines/memory/relations/operations.rb delete mode 100644 lib/arel/engines/sql.rb delete mode 100644 lib/arel/engines/sql/attributes.rb delete mode 100644 lib/arel/engines/sql/christener.rb delete mode 100644 lib/arel/engines/sql/compilers/ibm_db_compiler.rb delete mode 100644 lib/arel/engines/sql/compilers/mysql_compiler.rb delete mode 100644 lib/arel/engines/sql/compilers/oracle_compiler.rb delete mode 100644 lib/arel/engines/sql/compilers/postgresql_compiler.rb delete mode 100644 lib/arel/engines/sql/compilers/sqlite_compiler.rb delete mode 100644 lib/arel/engines/sql/core_extensions.rb delete mode 100644 lib/arel/engines/sql/core_extensions/array.rb delete mode 100644 lib/arel/engines/sql/core_extensions/nil_class.rb delete mode 100644 lib/arel/engines/sql/core_extensions/object.rb delete mode 100644 lib/arel/engines/sql/core_extensions/range.rb delete mode 100644 lib/arel/engines/sql/engine.rb delete mode 100644 lib/arel/engines/sql/formatters.rb delete mode 100644 lib/arel/engines/sql/relations.rb delete mode 100644 lib/arel/engines/sql/relations/compiler.rb delete mode 100644 lib/arel/engines/sql/relations/table.rb delete mode 100644 lib/arel/engines/sql/relations/utilities/nil.rb delete mode 100644 lib/arel/recursion/base_case.rb delete mode 100644 lib/arel/session.rb delete mode 100644 lib/arel/sql_literal.rb delete mode 100644 lib/arel/version.rb diff --git a/lib/arel.rb b/lib/arel.rb index 857a7f651b213..9a48ff1afbff0 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,14 +1,2 @@ -require 'active_support/inflector' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/object/blank' - -require 'arel/recursion/base_case' - module Arel - require 'arel/algebra' - require 'arel/sql_literal' - require 'arel/engines' - require 'arel/version' - - autoload :Session, 'arel/session' end diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb deleted file mode 100644 index bc7b2fef2d8d6..0000000000000 --- a/lib/arel/algebra.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'arel/algebra/core_extensions' - -require 'arel/algebra/attributes' -require 'arel/algebra/header' -require 'arel/algebra/expression' -require 'arel/algebra/ordering' -require 'arel/algebra/predicates' -require 'arel/algebra/relations' -require 'arel/algebra/value' - diff --git a/lib/arel/algebra/attributes.rb b/lib/arel/algebra/attributes.rb deleted file mode 100644 index 6ce65fe132a36..0000000000000 --- a/lib/arel/algebra/attributes.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "arel/algebra/attributes/attribute" -require "arel/algebra/attributes/boolean" -require "arel/algebra/attributes/decimal" -require "arel/algebra/attributes/float" -require "arel/algebra/attributes/integer" -require "arel/algebra/attributes/string" -require "arel/algebra/attributes/time" diff --git a/lib/arel/algebra/attributes/attribute.rb b/lib/arel/algebra/attributes/attribute.rb deleted file mode 100644 index 16124abcc41bf..0000000000000 --- a/lib/arel/algebra/attributes/attribute.rb +++ /dev/null @@ -1,304 +0,0 @@ -require 'set' - -module Arel - class TypecastError < StandardError ; end - class Attribute - attr_reader :relation, :name, :alias, :ancestor, :hash - attr_reader :history, :root - - def initialize(relation, name, options = {}) - @relation = relation # this is actually a table (I think) - @name = name - @alias = options[:alias] - @ancestor = options[:ancestor] - @history = [self] + (@ancestor ? @ancestor.history : []) - @root = @history.last - @original_relation = nil - @original_attribute = nil - - # FIXME: I think we can remove this eventually - @hash = name.hash + root.relation.class.hash - end - - def engine - @relation.engine - end - - def christener - @relation.christener - end - - def == other - super || - Attribute === other && - @name == other.name && - @alias == other.alias && - @ancestor == other.ancestor && - @relation == other.relation - end - - alias :eql? :== - - def named?(hypothetical_name) - (@alias || name).to_s == hypothetical_name.to_s - end - - def aggregation? - false - end - - def eval(row) - row[self] - end - - def as(aliaz = nil) - Attribute.new(relation, name, :alias => aliaz, :ancestor => self) - end - - def bind(new_relation) - relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) - end - - def to_attribute(relation) - bind(relation) - end - - def join? - relation.join? - end - - def root - history.last - end - - def original_relation - @original_relation ||= original_attribute.relation - end - - def original_attribute - @original_attribute ||= history.detect { |a| !a.join? } - end - - def find_correlate_in(relation) - relation[self] || self - end - - def descends_from?(other) - history.include?(other) - end - - def /(other) - other ? (history & other.history).size : 0 - end - - PREDICATES = [ - :eq, :eq_any, :eq_all, :not_eq, :not_eq_any, :not_eq_all, :lt, :lt_any, - :lt_all, :lteq, :lteq_any, :lteq_all, :gt, :gt_any, :gt_all, :gteq, - :gteq_any, :gteq_all, :matches, :matches_any, :matches_all, :not_matches, - :not_matches_any, :not_matches_all, :in, :in_any, :in_all, :not_in, - :not_in_any, :not_in_all - ] - - Predications = Class.new do - def self.instance_methods *args - warn "this module is deprecated, please use the PREDICATES constant" - PREDICATES - end - end - - def eq(other) - Predicates::Equality.new(self, other) - end - - def eq_any(*others) - Predicates::Any.build(Predicates::Equality, self, *others) - end - - def eq_all(*others) - Predicates::All.build(Predicates::Equality, self, *others) - end - - def not_eq(other) - Predicates::Inequality.new(self, other) - end - - def not_eq_any(*others) - Predicates::Any.build(Predicates::Inequality, self, *others) - end - - def not_eq_all(*others) - Predicates::All.build(Predicates::Inequality, self, *others) - end - - def lt(other) - Predicates::LessThan.new(self, other) - end - - def lt_any(*others) - Predicates::Any.build(Predicates::LessThan, self, *others) - end - - def lt_all(*others) - Predicates::All.build(Predicates::LessThan, self, *others) - end - - def lteq(other) - Predicates::LessThanOrEqualTo.new(self, other) - end - - def lteq_any(*others) - Predicates::Any.build(Predicates::LessThanOrEqualTo, self, *others) - end - - def lteq_all(*others) - Predicates::All.build(Predicates::LessThanOrEqualTo, self, *others) - end - - def gt(other) - Predicates::GreaterThan.new(self, other) - end - - def gt_any(*others) - Predicates::Any.build(Predicates::GreaterThan, self, *others) - end - - def gt_all(*others) - Predicates::All.build(Predicates::GreaterThan, self, *others) - end - - def gteq(other) - Predicates::GreaterThanOrEqualTo.new(self, other) - end - - def gteq_any(*others) - Predicates::Any.build(Predicates::GreaterThanOrEqualTo, self, *others) - end - - def gteq_all(*others) - Predicates::All.build(Predicates::GreaterThanOrEqualTo, self, *others) - end - - def matches(other) - Predicates::Match.new(self, other) - end - - def matches_any(*others) - Predicates::Any.build(Predicates::Match, self, *others) - end - - def matches_all(*others) - Predicates::All.build(Predicates::Match, self, *others) - end - - def not_matches(other) - Predicates::NotMatch.new(self, other) - end - - def not_matches_any(*others) - Predicates::Any.build(Predicates::NotMatch, self, *others) - end - - def not_matches_all(*others) - Predicates::All.build(Predicates::NotMatch, self, *others) - end - - def in(other) - Predicates::In.new(self, other) - end - - def in_any(*others) - Predicates::Any.build(Predicates::In, self, *others) - end - - def in_all(*others) - Predicates::All.build(Predicates::In, self, *others) - end - - def not_in(other) - Predicates::NotIn.new(self, other) - end - - def not_in_any(*others) - Predicates::Any.build(Predicates::NotIn, self, *others) - end - - def not_in_all(*others) - Predicates::All.build(Predicates::NotIn, self, *others) - end - - module Expressions - def count(distinct = false) - distinct ? Distinct.new(self).count : Count.new(self) - end - - def sum - Sum.new(self) - end - - def maximum - Maximum.new(self) - end - - def minimum - Minimum.new(self) - end - - def average - Average.new(self) - end - end - include Expressions - - module Orderings - def asc - Ascending.new(self) - end - - def desc - Descending.new(self) - end - - alias_method :to_ordering, :asc - end - include Orderings - - module Types - def type_cast(value) - if root == self - raise NotImplementedError, "#type_cast should be implemented in a subclass." - else - root.type_cast(value) - end - end - - def type_cast_to_numeric(value, method) - return unless value - if value.respond_to?(:to_str) - str = value.to_str.strip - return if str.empty? - return $1.send(method) if str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/ - elsif value.respond_to?(method) - return value.send(method) - end - raise typecast_error(value) - end - - def typecast_error(value) - raise TypecastError, "could not typecast #{value.inspect} to #{self.class.name.split('::').last}" - end - end - include Types - - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - end -end diff --git a/lib/arel/algebra/attributes/boolean.rb b/lib/arel/algebra/attributes/boolean.rb deleted file mode 100644 index d69f2465df453..0000000000000 --- a/lib/arel/algebra/attributes/boolean.rb +++ /dev/null @@ -1,21 +0,0 @@ -module Arel - module Attributes - class Boolean < Attribute - def type_cast(value) - case value - when true, false then value - # when nil then options[:allow_nil] ? nil : false - when nil then false - when 1 then true - when 0 then false - else - case value.to_s.downcase.strip - when 'true' then true - when 'false' then false - else raise typecast_error(value) - end - end - end - end - end -end diff --git a/lib/arel/algebra/attributes/decimal.rb b/lib/arel/algebra/attributes/decimal.rb deleted file mode 100644 index bf6587fa34761..0000000000000 --- a/lib/arel/algebra/attributes/decimal.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - module Attributes - class Decimal < Attribute - def type_cast(val) - type_cast_to_numeric(val, :to_d) - end - end - end -end diff --git a/lib/arel/algebra/attributes/float.rb b/lib/arel/algebra/attributes/float.rb deleted file mode 100644 index 01c95e69f9f9e..0000000000000 --- a/lib/arel/algebra/attributes/float.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - module Attributes - class Float < Attribute - def type_cast(val) - type_cast_to_numeric(val, :to_f) - end - end - end -end diff --git a/lib/arel/algebra/attributes/integer.rb b/lib/arel/algebra/attributes/integer.rb deleted file mode 100644 index 8d4f572989bde..0000000000000 --- a/lib/arel/algebra/attributes/integer.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - module Attributes - class Integer < Attribute - def type_cast(val) - type_cast_to_numeric(val, :to_i) - end - end - end -end - diff --git a/lib/arel/algebra/attributes/string.rb b/lib/arel/algebra/attributes/string.rb deleted file mode 100644 index 5ea91a59d810f..0000000000000 --- a/lib/arel/algebra/attributes/string.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - module Attributes - class String < Attribute - def type_cast(value) - return unless value - value.to_s - end - end - end -end diff --git a/lib/arel/algebra/attributes/time.rb b/lib/arel/algebra/attributes/time.rb deleted file mode 100644 index 7a2de726c88b7..0000000000000 --- a/lib/arel/algebra/attributes/time.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Attributes - class Time < Attribute - end - end -end diff --git a/lib/arel/algebra/core_extensions.rb b/lib/arel/algebra/core_extensions.rb deleted file mode 100644 index 4416ff6b77b09..0000000000000 --- a/lib/arel/algebra/core_extensions.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/algebra/core_extensions/object' -require 'arel/algebra/core_extensions/symbol' -require 'arel/algebra/core_extensions/hash' diff --git a/lib/arel/algebra/core_extensions/hash.rb b/lib/arel/algebra/core_extensions/hash.rb deleted file mode 100644 index 4b36a3e2bcc43..0000000000000 --- a/lib/arel/algebra/core_extensions/hash.rb +++ /dev/null @@ -1,7 +0,0 @@ -class Hash - def bind(relation) - Hash[map { |key, value| - [key.bind(relation), value.bind(relation)] - }] - end -end diff --git a/lib/arel/algebra/core_extensions/object.rb b/lib/arel/algebra/core_extensions/object.rb deleted file mode 100644 index 2dc5ea267759f..0000000000000 --- a/lib/arel/algebra/core_extensions/object.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module ObjectExtensions - def bind(relation) - Arel::Value.new(self, relation) - end - - def find_correlate_in(relation) - bind(relation) - end - - Object.send(:include, self) - end -end diff --git a/lib/arel/algebra/core_extensions/symbol.rb b/lib/arel/algebra/core_extensions/symbol.rb deleted file mode 100644 index f575ad533abcc..0000000000000 --- a/lib/arel/algebra/core_extensions/symbol.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - module SymbolExtensions - def to_attribute(relation) - Arel::Attribute.new(relation, self) - end - - Symbol.send(:include, self) - end -end diff --git a/lib/arel/algebra/expression.rb b/lib/arel/algebra/expression.rb deleted file mode 100644 index 32cf4f12c9746..0000000000000 --- a/lib/arel/algebra/expression.rb +++ /dev/null @@ -1,56 +0,0 @@ -module Arel - class Expression < Attribute - attr_reader :attribute - alias :name :alias - - def initialize(attribute, aliaz = nil, ancestor = nil) - super(attribute.relation, aliaz, :alias => aliaz, :ancestor => ancestor) - @attribute = attribute - end - - def aggregation? - true - end - - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - - def as(aliaz) - self.class.new(attribute, aliaz, self) - end - - def bind(new_relation) - new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) - end - - def to_attribute(relation) - Attribute.new(relation, @alias, :ancestor => self) - end - end - - class Count < Expression - def function_sql; 'COUNT' end - end - - class Distinct < Expression - def function_sql; 'DISTINCT' end - end - - class Sum < Expression - def function_sql; 'SUM' end - end - - class Maximum < Expression - def function_sql; 'MAX' end - end - - class Minimum < Expression - def function_sql; 'MIN' end - end - - class Average < Expression - def function_sql; 'AVG' end - end -end - diff --git a/lib/arel/algebra/header.rb b/lib/arel/algebra/header.rb deleted file mode 100644 index dc779d53c3aca..0000000000000 --- a/lib/arel/algebra/header.rb +++ /dev/null @@ -1,66 +0,0 @@ -module Arel - class Header - include Enumerable - - def initialize(attrs = []) - @attributes = attrs.to_ary - @names = {} - end - - def each - to_ary.each { |e| yield e } - self - end - - def [](key) - case key - when String, Symbol then find_by_name(key) - when Attribute then find_by_attribute(key) - end - end - - def ==(other) - to_set == other.to_set - end - - def union(other) - new(to_ary | other) - end - - alias | union - - def to_ary - @attributes - end - - def bind(relation) - Header.new(map { |a| a.bind(relation) }) - end - - # TMP - def index(i) - to_ary.index(i) - end - - private - - def new(attrs) - self.class.new(attrs) - end - - def matching(attribute) - select { |a| !a.is_a?(Value) && a.root == attribute.root } - end - - def find_by_name(name) - k = name.to_sym - @names[k] ||= @attributes.detect { |a| a.named?(k) } - end - - def find_by_attribute(attr) - matching(attr).max do |a, b| - (a.original_attribute / attr) <=> (b.original_attribute / attr) - end - end - end -end diff --git a/lib/arel/algebra/ordering.rb b/lib/arel/algebra/ordering.rb deleted file mode 100644 index c1a4ef8b70ff4..0000000000000 --- a/lib/arel/algebra/ordering.rb +++ /dev/null @@ -1,31 +0,0 @@ -module Arel - class Ordering < Struct.new(:attribute) - delegate :relation, :to => :attribute - - def bind(relation) - self.class.new(attribute.bind(relation)) - end - - def to_ordering - self - end - - def eval(row1, row2) - (attribute.eval(row1) <=> attribute.eval(row2)) * direction - end - - def to_sql(formatter = Sql::OrderClause.new(relation)) - formatter.ordering self - end - end - - class Ascending < Ordering - def direction; 1 end - def direction_sql; 'ASC' end - end - - class Descending < Ordering - def direction_sql; 'DESC' end - def direction; -1 end - end -end diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb deleted file mode 100644 index 2426aae3961d9..0000000000000 --- a/lib/arel/algebra/predicates.rb +++ /dev/null @@ -1,306 +0,0 @@ -module Arel - module Predicates - class Predicate - def or(other_predicate) - Or.new(self, other_predicate) - end - - def and(other_predicate) - And.new(self, other_predicate) - end - - def complement - Not.new(self) - end - - def not - self.complement - end - end - - class Polyadic < Predicate - attr_reader :predicates - - def initialize(*predicates) - @predicates = predicates - end - - # Build a Polyadic predicate based on: - # * operator - The Predicate subclass that defines the type of operation - # (LessThan, Equality, etc) - # * operand1 - The left-hand operand (normally an Arel::Attribute) - # * additional_operands - All possible right-hand operands - def self.build(operator, operand1, *additional_operands) - new( - *additional_operands.uniq.map do |operand| - operator.new(operand1, operand) - end - ) - end - - def ==(other) - super || predicates == other.predicates - end - - def bind(relation) - self.class.new( - *predicates.map {|p| p.find_correlate_in(relation)} - ) - end - - def eval(row) - predicates.send(compounder) do |operation| - operation.eval(row) - end - end - - def to_sql(formatter = nil) - "(" + - predicates.map {|p| p.to_sql(formatter)}.join(" #{predicate_sql} ") + - ")" - end - end - - class Any < Polyadic - def complement - All.new(*predicates.map {|p| p.complement}) - end - - def compounder; :any? end - - def predicate_sql; "OR" end - end - - class All < Polyadic - def complement - Any.new(*predicates.map {|p| p.complement}) - end - - def compounder; :all? end - - def predicate_sql; "AND" end - end - - class Unary < Predicate - attr_reader :operand - - def initialize operand - @operand = operand - end - - def bind(relation) - self.class.new(operand.find_correlate_in(relation)) - end - - def == other - super || self.class === other && operand == other.operand - end - - def eval(row) - operand.eval(row).send(operator) - end - - def to_sql(formatter = nil) - "#{predicate_sql} (#{operand.to_sql(formatter)})" - end - end - - class Not < Unary - def complement - operand - end - - def eval(row) - !operand.eval(row) - end - - def predicate_sql; "NOT" end - end - - class Binary < Unary - attr_reader :operand2 - alias :operand1 :operand - - def initialize left, right - super(left) - @operand2 = right - end - - def ==(other) - super && @operand2 == other.operand2 - end - - def bind(relation) - self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) - end - - def eval(row) - operand1.eval(row).send(operator, operand2.eval(row)) - end - - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" - end - alias :value :to_sql - end - - class CompoundPredicate < Binary - def eval(row) - eval "operand1.eval(row) #{operator} operand2.eval(row)" - end - - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" - end - end - - class And < CompoundPredicate - def complement - Or.new(operand1.complement, operand2.complement) - end - - def operator; :and end - - def predicate_sql; "AND" end - end - - class Or < CompoundPredicate - def complement - And.new(operand1.complement, operand2.complement) - end - - def operator; :or end - - def predicate_sql; "OR" end - end - - class Equality < Binary - def ==(other) - self.class === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) - end - - def complement - Inequality.new(operand1, operand2) - end - - def operator; :== end - - def predicate_sql - operand2.equality_predicate_sql - end - end - - class Inequality < Equality - def complement - Equality.new(operand1, operand2) - end - - def operator; :"!=" end - def eval(row) - operand1.eval(row) != operand2.eval(row) - end - - def predicate_sql - operand2.inequality_predicate_sql - end - end - - class GreaterThanOrEqualTo < Binary - def complement - LessThan.new(operand1, operand2) - end - - def operator; :>= end - - def predicate_sql; '>=' end - end - - class GreaterThan < Binary - def complement - LessThanOrEqualTo.new(operand1, operand2) - end - - def operator; :> end - - def predicate_sql; '>' end - end - - class LessThanOrEqualTo < Binary - def complement - GreaterThan.new(operand1, operand2) - end - - def operator; :<= end - - def predicate_sql; '<=' end - end - - class LessThan < Binary - def complement - GreaterThanOrEqualTo.new(operand1, operand2) - end - - def operator; :< end - - def predicate_sql; '<' end - end - - class Match < Binary - def complement - NotMatch.new(operand1, operand2) - end - - def operator; :=~ end - - def predicate_sql; 'LIKE' end - end - - class NotMatch < Binary - def complement - Match.new(operand1, operand2) - end - - def eval(row) - operand1.eval(row) !~ operand2.eval(row) - end - - def predicate_sql; 'NOT LIKE' end - end - - class In < Binary - def complement - NotIn.new(operand1, operand2) - end - - def eval(row) - operand2.eval(row).include?(operand1.eval(row)) - end - - def to_sql(formatter = nil) - if operand2.is_a?(Range) && operand2.exclude_end? - GreaterThanOrEqualTo.new(operand1, operand2.begin).and( - LessThan.new(operand1, operand2.end) - ).to_sql(formatter) - else - super - end - end - - def predicate_sql; operand2.inclusion_predicate_sql end - end - - class NotIn < Binary - def complement - In.new(operand1, operand2) - end - - def eval(row) - !(operand2.eval(row).include?(operand1.eval(row))) - end - - def predicate_sql; operand2.exclusion_predicate_sql end - end - end -end diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb deleted file mode 100644 index 9f438615cd0b0..0000000000000 --- a/lib/arel/algebra/relations.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'arel/algebra/relations/relation' -require 'arel/algebra/relations/utilities/compound' -require 'arel/algebra/relations/utilities/nil' -require 'arel/algebra/relations/utilities/externalization' -require 'arel/algebra/relations/row' -require 'arel/algebra/relations/writes' -require 'arel/algebra/relations/operations/from' -require 'arel/algebra/relations/operations/group' -require 'arel/algebra/relations/operations/having' -require 'arel/algebra/relations/operations/join' -require 'arel/algebra/relations/operations/order' -require 'arel/algebra/relations/operations/project' -require 'arel/algebra/relations/operations/where' -require 'arel/algebra/relations/operations/skip' -require 'arel/algebra/relations/operations/take' -require 'arel/algebra/relations/operations/lock' diff --git a/lib/arel/algebra/relations/operations/from.rb b/lib/arel/algebra/relations/operations/from.rb deleted file mode 100644 index 3ebfb10cb21b3..0000000000000 --- a/lib/arel/algebra/relations/operations/from.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class From < Compound - attr_reader :sources - - def initialize relation, sources - super(relation) - @sources = sources - end - - def eval - unoperated_rows[sources..-1] - end - end -end diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb deleted file mode 100644 index 16a2963c93444..0000000000000 --- a/lib/arel/algebra/relations/operations/group.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Group < Compound - attr_reader :groupings - - def initialize(relation, groupings) - super(relation) - @groupings = groupings.collect { |g| g.bind(relation) } - end - - def eval - raise NotImplementedError - end - end -end diff --git a/lib/arel/algebra/relations/operations/having.rb b/lib/arel/algebra/relations/operations/having.rb deleted file mode 100644 index 3d8115c2f61e3..0000000000000 --- a/lib/arel/algebra/relations/operations/having.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Having < Compound - attr_reader :predicates - - def initialize(relation, predicates) - super(relation) - @predicates = predicates.map { |p| p.bind(relation) } - end - - def havings - @havings ||= relation.havings + predicates - end - end -end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb deleted file mode 100644 index 35374972be325..0000000000000 --- a/lib/arel/algebra/relations/operations/join.rb +++ /dev/null @@ -1,103 +0,0 @@ -module Arel - class Join - include Relation - - attr_reader :relation1, :relation2, :predicates - - def initialize(relation1, relation2 = Nil.instance, *predicates) - @relation1 = relation1 - @relation2 = relation2 - @predicates = predicates - @attributes = nil - end - - def name - relation1.name - end - - def attributes - @attributes ||= (relation1.externalize.attributes | relation2.externalize.attributes).bind(self) - end - - def wheres - # TESTME bind to self? - relation1.externalize.wheres - end - - def ons - @ons ||= @predicates.collect { |p| p.bind(self) } - end - - # TESTME - def externalizable? - relation1.externalizable? or relation2.externalizable? - end - - def join? - true - end - - def engine - relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine - end - - def table_sql(formatter = Sql::TableReference.new(self)) - relation1.externalize.table_sql(formatter) - end - - def joins(environment, formatter = Sql::TableReference.new(environment)) - @joins ||= begin - this_join = [ - join_sql, - relation2.externalize.table_sql(formatter), - ("ON" unless predicates.blank?), - (ons + relation2.externalize.wheres).collect { |p| p.bind(environment.relation).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') - ].compact.join(" ") - [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") - end - end - - def eval - result = [] - relation1.call.each do |row1| - relation2.call.each do |row2| - combined_row = row1.combine(row2, self) - if predicates.all? { |p| p.eval(combined_row) } - result << combined_row - end - end - end - result - end - - def to_sql(formatter = nil) - compiler.select_sql - end - end - - class InnerJoin < Join - def join_sql; "INNER JOIN" end - end - - class OuterJoin < Join - def join_sql; "LEFT OUTER JOIN" end - end - - class StringJoin < Join - def joins(environment, formatter = Sql::TableReference.new(environment)) - [relation1.joins(environment), relation2].compact.join(" ") - end - - def externalizable? - relation1.externalizable? - end - - def attributes - relation1.externalize.attributes - end - - def engine - relation1.engine - end - end -end diff --git a/lib/arel/algebra/relations/operations/lock.rb b/lib/arel/algebra/relations/operations/lock.rb deleted file mode 100644 index 394ad6f0ecd13..0000000000000 --- a/lib/arel/algebra/relations/operations/lock.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Lock < Compound - attr_reader :locked - - def initialize(relation, locked) - super(relation) - @locked = true == locked ? " FOR UPDATE" : locked - end - end -end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb deleted file mode 100644 index e7306fe384ba3..0000000000000 --- a/lib/arel/algebra/relations/operations/order.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Arel - class Order < Compound - attr_reader :orderings - - def initialize(relation, orderings) - super(relation) - @orderings = orderings.collect { |o| o.bind(relation) } - end - - # TESTME - def orders - # QUESTION - do we still need relation.orders ? - (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } - end - - def eval - unoperated_rows.sort do |row1, row2| - ordering = orders.detect { |o| o.eval(row1, row2) != 0 } || orders.last - ordering.eval(row1, row2) - end - end - end -end diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb deleted file mode 100644 index 1c24ae6caff73..0000000000000 --- a/lib/arel/algebra/relations/operations/project.rb +++ /dev/null @@ -1,20 +0,0 @@ -module Arel - class Project < Compound - attr_reader :projections, :attributes, :christener - - def initialize(relation, projections) - super(relation) - @projections = projections.map { |p| p.bind(relation) } - @christener = Sql::Christener.new - @attributes = Header.new(projections.map { |x| x.bind(self) }) - end - - def externalizable? - attributes.any? { |a| a.respond_to?(:aggregation?) && a.aggregation? } || relation.externalizable? - end - - def eval - unoperated_rows.collect { |r| r.slice(*projections) } - end - end -end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb deleted file mode 100644 index a9157e914ccb1..0000000000000 --- a/lib/arel/algebra/relations/operations/skip.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Skip < Compound - attr_reader :relation, :skipped - - def initialize relation, skipped - super(relation) - @skipped = skipped - end - - def eval - unoperated_rows[skipped..-1] - end - end -end diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb deleted file mode 100644 index 299c29ab727f4..0000000000000 --- a/lib/arel/algebra/relations/operations/take.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Arel - class Take < Compound - attr_reader :taken - - def initialize relation, taken - super(relation) - @taken = taken - end - - def externalizable? - true - end - - def eval - unoperated_rows[0, taken] - end - end -end diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb deleted file mode 100644 index ed80fd93ba934..0000000000000 --- a/lib/arel/algebra/relations/operations/where.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Arel - class Where < Compound - attr_reader :predicates - - def initialize(relation, predicates) - super(relation) - @predicates = predicates.map { |p| p.bind(relation) } - @wheres = nil - end - - def wheres - @wheres ||= relation.wheres + predicates - end - - def eval - unoperated_rows.select { |row| predicates.all? { |p| p.eval(row) } } - end - - def to_sql(formatter = nil) - compiler.select_sql - end - end -end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb deleted file mode 100644 index 765d6fe9308d7..0000000000000 --- a/lib/arel/algebra/relations/relation.rb +++ /dev/null @@ -1,205 +0,0 @@ -module Arel - module Relation - include Enumerable - - @@connection_tables_primary_keys = {} - - attr_reader :count - - def session - Session.instance - end - - def join? - false - end - - def call - engine.read(self) - end - - def bind(relation) - self - end - - def externalize - @externalized ||= externalizable?? Externalization.new(self) : self - end - - def externalizable? - false - end - - def compiler - @compiler ||= begin - Arel::SqlCompiler.const_get("#{engine.adapter_name}Compiler").new(self) - rescue - Arel::SqlCompiler::GenericCompiler.new(self) - end - end - - def to_sql(formatter = nil) - sql = compiler.select_sql - - return sql unless formatter - formatter.select sql, self - end - - def christener - @christener ||= Sql::Christener.new - end - - def inclusion_predicate_sql - "IN" - end - - def exclusion_predicate_sql - "NOT IN" - end - - def primary_key - connection_id = engine.connection.object_id - if @@connection_tables_primary_keys[connection_id] && @@connection_tables_primary_keys[connection_id].has_key?(table.name) - @@connection_tables_primary_keys[connection_id][table.name] - else - @@connection_tables_primary_keys[connection_id] ||= {} - @@connection_tables_primary_keys[connection_id][table.name] = engine.connection.primary_key(table.name) - end - end - - def select_clauses - attributes.map { |a| - case a - when Value - a.value - else - a.to_sql(Sql::SelectClause.new(self)) - end - } - end - - def from_clauses - sources.empty? ? table_sql : sources - end - - def where_clauses - wheres.map { |w| w.value } - end - - def group_clauses - groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } - end - - def having_clauses - havings.collect { |g| g.to_sql(Sql::HavingClause.new(self)) } - end - - def order_clauses - orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } - end - - def each - session.read(self).each { |e| yield e } - end - - def join(other_relation = nil, join_class = InnerJoin) - case other_relation - when String - StringJoin.new(self, other_relation) - when Relation - JoinOperation.new(join_class, self, other_relation) - else - self - end - end - - def outer_join(other_relation = nil) - join(other_relation, OuterJoin) - end - - %w{ - having group order - }.each do |op| - class_eval <<-OPERATION, __FILE__, __LINE__ - def #{op}(*args) - args.all? { |x| x.blank? } ? self : #{op.capitalize}.new(self, args) - end - OPERATION - end - - def project *args - args.empty? ? self : Project.new(self, args) - end - - def where clause = nil - clause ? Where.new(self, Array(clause)) : self - end - - def skip thing = nil - thing ? Skip.new(self, thing) : self - end - - def take count - Take.new self, count - end - - def from thing - From.new self, thing - end - - def lock(locking = true) - Lock.new(self, locking) - end - - def alias - Alias.new(self) - end - - def insert(record) - session.create Insert.new(self, record) - end - - def update(assignments) - session.update Update.new(self, assignments) - end - - def delete - session.delete Deletion.new(self) - end - - JoinOperation = Struct.new(:join_class, :relation1, :relation2) do - def on(*predicates) - join_class.new(relation1, relation2, *predicates) - end - end - - def [](index) - attributes[index] - end - - def find_attribute_matching_name(name) - attributes.detect { |a| a.named?(name) } || Attribute.new(self, name) - end - - def position_of(attribute) - @position_of ||= {} - - return @position_of[attribute] if @position_of.key? attribute - - @position_of[attribute] = attributes.index(attributes[attribute]) - end - - def attributes; Header.new end - def projections; [] end - def wheres; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def havings; [] end - def joins(formatter = nil); nil end # FIXME - def taken; nil end - def skipped; nil end - def sources; [] end - def locked; [] end - end -end diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb deleted file mode 100644 index 84f19e372f5b9..0000000000000 --- a/lib/arel/algebra/relations/row.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Arel - class Row - attr_reader :tuple, :relation - - def initialize relation, tuple - @relation = relation - @tuple = tuple - end - - def [](attribute) - attribute.type_cast(tuple[relation.position_of(attribute)]) - end - - def slice(*attributes) - Row.new(relation, attributes.map do |attribute| - # FIXME TESTME method chaining - tuple[relation.relation.position_of(attribute)] - end) - end - - def bind(relation) - Row.new(relation, tuple) - end - - def combine(other, relation) - Row.new(relation, tuple + other.tuple) - end - end -end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb deleted file mode 100644 index 0a270f78a1897..0000000000000 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ /dev/null @@ -1,55 +0,0 @@ -module Arel - class Compound - include Relation - - attr_reader :relation, :engine - - def initialize relation - @relation = relation - @engine = relation.engine - @attributes = nil - @wheres = nil - @groupings = nil - @orders = nil - @havings = nil - @projections = nil - end - - def join?; @relation.join? end - def name; @relation.name end - def table_alias; @relation.table_alias end - def skipped; @relation.skipped end - def taken; @relation.taken end - def joins env; @relation.joins env end - def column_for attr; @relation.column_for attr end - def externalizable?; @relation.externalizable? end - - def sources - @relation.sources - end - - def table - @relation.table - end - - def table_sql(formatter = Sql::TableReference.new(self)) - @relation.table_sql formatter - end - - [:wheres, :groupings, :orders, :havings, :projections].each do |operation_name| - class_eval <<-OPERATION, __FILE__, __LINE__ - def #{operation_name} - @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } - end - OPERATION - end - - def attributes - @attributes ||= relation.attributes.bind(self) - end - - def unoperated_rows - relation.call.collect { |row| row.bind(self) } - end - end -end diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb deleted file mode 100644 index 8e97573f68d91..0000000000000 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Arel - class Externalization < Compound - include Recursion::BaseCase - - def == other - super || Externalization === other && relation == other.relation - end - - def wheres - [] - end - - def attributes - @attributes ||= Header.new(relation.attributes.map { |a| a.to_attribute(self) }) - end - - def table_sql(formatter = Sql::TableReference.new(relation)) - formatter.select relation.compiler.select_sql, self - end - - # REMOVEME - def name - relation.name + '_external' - end - end -end diff --git a/lib/arel/algebra/relations/utilities/nil.rb b/lib/arel/algebra/relations/utilities/nil.rb deleted file mode 100644 index 04055d0ddbe2e..0000000000000 --- a/lib/arel/algebra/relations/utilities/nil.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'singleton' - -module Arel - class Nil - include Relation, Singleton - end -end diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb deleted file mode 100644 index 7df6d861a8917..0000000000000 --- a/lib/arel/algebra/relations/writes.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Arel - class Action < Compound - end - - class Deletion < Action - def call - engine.delete(self) - end - - def to_sql - compiler.delete_sql - end - end - - class Insert < Action - attr_reader :record - - def initialize(relation, record) - super(relation) - @record = record.bind(relation) - end - - def call - engine.create(self) - end - - def eval - unoperated_rows + [Row.new(self, record.values.collect(&:value))] - end - - def to_sql(include_returning = true) - compiler.insert_sql(include_returning) - end - end - - class Update < Insert - alias :assignments :record - - def call - engine.update(self) - end - - def to_sql - compiler.update_sql - end - end -end diff --git a/lib/arel/algebra/value.rb b/lib/arel/algebra/value.rb deleted file mode 100644 index 70e94e0ad0fff..0000000000000 --- a/lib/arel/algebra/value.rb +++ /dev/null @@ -1,53 +0,0 @@ -module Arel - class Value - attr_reader :value, :relation - - def initialize value, relation - @value = value - @relation = relation - end - - def == other - super || - Value === other && - value == other.value && - relation == other.relation - end - - def eval(row) - value - end - - def bind(relation) - Value.new(value, relation) - end - - def to_ordering - self - end - - def inclusion_predicate_sql - value.inclusion_predicate_sql - end - - def exclusion_predicate_sql - value.exclusion_predicate_sql - end - - def equality_predicate_sql - value.equality_predicate_sql - end - - def inequality_predicate_sql - value.inequality_predicate_sql - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.value value - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - end -end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb deleted file mode 100644 index cd848d83e2331..0000000000000 --- a/lib/arel/engines.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/engines/sql' -require 'arel/engines/memory' diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb deleted file mode 100644 index c0fdf6c5d6f31..0000000000000 --- a/lib/arel/engines/memory.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/engines/memory/relations' -require 'arel/engines/memory/engine' diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb deleted file mode 100644 index 0142c49aa320a..0000000000000 --- a/lib/arel/engines/memory/engine.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - module Memory - class Engine - def read(relation) - relation.eval - end - alias :create :read - end - end -end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb deleted file mode 100644 index 046017d78acb1..0000000000000 --- a/lib/arel/engines/memory/relations.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/engines/memory/relations/array' -require 'arel/engines/memory/relations/operations' diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb deleted file mode 100644 index 028f5c026952b..0000000000000 --- a/lib/arel/engines/memory/relations/array.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Arel - class Array - include Relation - - attr_reader :array, :attribute_names_and_types - include Recursion::BaseCase - - def initialize(array, attribute_names_and_types) - @array = array - @attribute_names_and_types = attribute_names_and_types - @engine = nil - @attributes = nil - end - - def engine - @engine ||= Memory::Engine.new - end - - def attributes - @attributes ||= begin - attrs = @attribute_names_and_types.collect do |attribute, type| - attribute = type.new(self, attribute) if Symbol === attribute - attribute - end - Header.new(attrs) - end - end - - def format(attribute, value) - value - end - - def eval - @array.collect { |r| Row.new(self, r) } - end - end -end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb deleted file mode 100644 index 2269fadf721fd..0000000000000 --- a/lib/arel/engines/memory/relations/operations.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - class Alias < Compound - include Recursion::BaseCase - - def eval - unoperated_rows - end - end -end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb deleted file mode 100644 index 438d028606ead..0000000000000 --- a/lib/arel/engines/sql.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'arel/engines/sql/attributes' -require 'arel/engines/sql/engine' -require 'arel/engines/sql/relations' -require 'arel/engines/sql/formatters' -require 'arel/engines/sql/core_extensions' -require 'arel/engines/sql/christener' diff --git a/lib/arel/engines/sql/attributes.rb b/lib/arel/engines/sql/attributes.rb deleted file mode 100644 index 50cc8021621c1..0000000000000 --- a/lib/arel/engines/sql/attributes.rb +++ /dev/null @@ -1,40 +0,0 @@ -module Arel - module Sql - module Attributes - def self.for(column) - case column.type - when :string then String - when :text then String - when :integer then Integer - when :float then Float - when :decimal then Decimal - when :date then Time - when :datetime then Time - when :timestamp then Time - when :time then Time - when :binary then String - when :boolean then Boolean - else - raise NotImplementedError, "Column type `#{column.type}` is not currently handled" - end - end - - def initialize(column, *args) - @column = column - super(*args) - end - - def type_cast(value) - @column.type_cast(value) - end - - %w(Boolean Decimal Float Integer String Time).each do |klass| - class_eval <<-R - class #{klass} < Arel::Attributes::#{klass} - include Attributes - end - R - end - end - end -end diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb deleted file mode 100644 index b30883e47cbca..0000000000000 --- a/lib/arel/engines/sql/christener.rb +++ /dev/null @@ -1,20 +0,0 @@ -module Arel - module Sql - class Christener - def initialize - @names = {} - end - - def name_for(relation) - table = relation.table - name = table.table_alias || table.name - list = @names[name] ||= [] - - list << table unless list.include? table - - idx = list.index table - name + (idx == 0 ? '' : "_#{idx + 1}") - end - end - end -end diff --git a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb b/lib/arel/engines/sql/compilers/ibm_db_compiler.rb deleted file mode 100644 index 8c5779a35e8af..0000000000000 --- a/lib/arel/engines/sql/compilers/ibm_db_compiler.rb +++ /dev/null @@ -1,48 +0,0 @@ -# +-----------------------------------------------------------------------+ -# | | -# | Copyright (c) 2010 IBM Corporation | -# | | -# | 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. | -# | | -# +-----------------------------------------------------------------------+ - -# -# Author: Praveen Devarao -# - -module Arel - module SqlCompiler - class IBM_DBCompiler < GenericCompiler - - def limited_update_conditions(conditions, taken) - quoted_primary_key = engine.quote_table_name(primary_key) - update_conditions = "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{engine.connection.quote_table_name table.name} #{conditions} " #Note: - ')' not added, limit segment is to be appended - engine.add_limit_offset!(update_conditions,{:limit=>taken,:offset=>nil}) - update_conditions << ")" # Close the sql segment - update_conditions - end - - def add_limit_on_delete(taken) - raise "IBM_DB does not support limit on deletion" # Limiting the number of rows to be deleted is not supported by IBM_DB - end - - end - end -end diff --git a/lib/arel/engines/sql/compilers/mysql_compiler.rb b/lib/arel/engines/sql/compilers/mysql_compiler.rb deleted file mode 100644 index cb12e7377aab9..0000000000000 --- a/lib/arel/engines/sql/compilers/mysql_compiler.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Arel - module SqlCompiler - class MySQLCompiler < GenericCompiler - def limited_update_conditions(conditions, taken) - conditions << " LIMIT #{taken}" - conditions - end - end - end -end - diff --git a/lib/arel/engines/sql/compilers/oracle_compiler.rb b/lib/arel/engines/sql/compilers/oracle_compiler.rb deleted file mode 100644 index 1963454d369a7..0000000000000 --- a/lib/arel/engines/sql/compilers/oracle_compiler.rb +++ /dev/null @@ -1,95 +0,0 @@ -module Arel - module SqlCompiler - class OracleCompiler < GenericCompiler - - def select_sql - where_clauses_array = where_clauses - if limit_or_offset = !taken.blank? || !skipped.blank? - # if need to select first records without ORDER BY and GROUP BY and without DISTINCT - # then can use simple ROWNUM in WHERE clause - if skipped.blank? && groupings.blank? && orders.blank? && select_clauses[0] !~ /^DISTINCT / - where_clauses_array << "ROWNUM <= #{taken}" if !taken.blank? && skipped.blank? && groupings.blank? && orders.blank? - limit_or_offset = false - end - end - - # when limit or offset subquery is used then cannot use FOR UPDATE directly - # and need to construct separate subquery for primary key - if use_subquery_for_lock = limit_or_offset && !locked.blank? - quoted_primary_key = engine.connection.quote_column_name(primary_key) - end - select_attributes_string = use_subquery_for_lock ? quoted_primary_key : select_clauses.join(', ') - - # OracleEnhanced adapter workaround when ORDER BY is used with columns not - # present in DISTINCT columns list - order_clauses_array = if select_attributes_string =~ /DISTINCT.*FIRST_VALUE/ && !orders.blank? - order = order_clauses.join(', ').split(',').map { |s| s.strip }.reject(&:blank?) - order = order.zip((0...order.size).to_a).map { |s,i| "alias_#{i}__ #{'DESC' if s =~ /\bdesc$/i}" } - else - order_clauses - end - - query = build_query \ - "SELECT #{select_attributes_string}", - "FROM #{from_clauses}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? ), - ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), - ("HAVING #{having_clauses.join(' AND ')}" unless havings.blank? ), - ("ORDER BY #{order_clauses_array.join(', ')}" unless order_clauses_array.blank? ) - - # Use existing method from oracle_enhanced adapter to implement limit and offset using subqueries - engine.connection.add_limit_offset!(query, :limit => taken, :offset => skipped) if limit_or_offset - - if use_subquery_for_lock - build_query \ - "SELECT #{select_clauses.join(', ')}", - "FROM #{from_clauses}", - "WHERE #{quoted_primary_key} IN (#{query})", - "#{locked}" - elsif !locked.blank? - build_query query, "#{locked}" - else - query - end - end - - def delete_sql - where_clauses_array = wheres.collect(&:to_sql) - where_clauses_array << "ROWNUM <= #{taken}" unless taken.blank? - build_query \ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? ) - end - - protected - - def build_update_conditions_sql - conditions = "" - where_clauses_array = wheres.collect(&:to_sql) - # if need to select first records without ORDER BY - # then can use simple ROWNUM in WHERE clause - if !taken.blank? && orders.blank? - where_clauses_array << "ROWNUM <= #{taken}" - end - conditions << " WHERE #{where_clauses_array.join(' AND ')}" unless where_clauses_array.blank? - unless taken.blank? - conditions = limited_update_conditions(conditions, taken) - end - conditions - end - - def limited_update_conditions(conditions, taken) - # need to add ORDER BY only if just taken ones should be updated - conditions << " ORDER BY #{order_clauses.join(', ')}" unless orders.blank? - quoted_primary_key = engine.connection.quote_column_name(primary_key) - subquery = "SELECT #{quoted_primary_key} FROM #{engine.connection.connection.quote_table_name table.name} #{conditions}" - # Use existing method from oracle_enhanced adapter to get taken records when ORDER BY is used - engine.connection.add_limit_offset!(subquery, :limit => taken) unless orders.blank? - "WHERE #{quoted_primary_key} IN (#{subquery})" - end - - end - end -end diff --git a/lib/arel/engines/sql/compilers/postgresql_compiler.rb b/lib/arel/engines/sql/compilers/postgresql_compiler.rb deleted file mode 100644 index 3079451064f18..0000000000000 --- a/lib/arel/engines/sql/compilers/postgresql_compiler.rb +++ /dev/null @@ -1,50 +0,0 @@ -module Arel - module SqlCompiler - class PostgreSQLCompiler < GenericCompiler - - def select_sql - if !relation.orders.blank? && using_distinct_on? - selects = relation.select_clauses - joins = relation.joins(self) - wheres = relation.where_clauses - groups = relation.group_clauses - havings = relation.having_clauses - orders = relation.order_clauses - - subquery_clauses = [ "", - "SELECT #{selects.kind_of?(::Array) ? selects.join("") : selects.to_s}", - "FROM #{relation.from_clauses}", - joins, - ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?), - ("GROUP BY #{groups.join(', ')}" unless groups.empty?), - ("HAVING #{havings.join(' AND ')}" unless havings.empty?) - ].compact.join ' ' - subquery_clauses << " #{locked}" unless locked.blank? - - build_query \ - "SELECT * FROM (#{build_query subquery_clauses}) AS id_list", - "ORDER BY #{aliased_orders(orders)}", - ("LIMIT #{relation.taken}" unless relation.taken.blank? ), - ("OFFSET #{relation.skipped}" unless relation.skipped.blank? ) - else - super - end - end - - def using_distinct_on? - relation.select_clauses.any? { |x| x =~ /DISTINCT ON/ } - end - - def aliased_orders(orders) - # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this - # by wrapping the +sql+ string as a sub-select and ordering in that query. - order = orders.join(', ').split(/,/).map { |s| s.strip }.reject(&:blank?) - order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{'DESC' if s =~ /\bdesc$/i}" }.join(', ') - end - - def supports_insert_with_returning? - engine.connection.send(:postgresql_version) >= 80200 - end - end - end -end diff --git a/lib/arel/engines/sql/compilers/sqlite_compiler.rb b/lib/arel/engines/sql/compilers/sqlite_compiler.rb deleted file mode 100644 index c2f78cd235050..0000000000000 --- a/lib/arel/engines/sql/compilers/sqlite_compiler.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - module SqlCompiler - class SQLiteCompiler < GenericCompiler - def locked - nil - end - end - end -end diff --git a/lib/arel/engines/sql/core_extensions.rb b/lib/arel/engines/sql/core_extensions.rb deleted file mode 100644 index c8d9ec239eacd..0000000000000 --- a/lib/arel/engines/sql/core_extensions.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/engines/sql/core_extensions/object' -require 'arel/engines/sql/core_extensions/array' -require 'arel/engines/sql/core_extensions/range' -require 'arel/engines/sql/core_extensions/nil_class' diff --git a/lib/arel/engines/sql/core_extensions/array.rb b/lib/arel/engines/sql/core_extensions/array.rb deleted file mode 100644 index 05a1bb774c1cd..0000000000000 --- a/lib/arel/engines/sql/core_extensions/array.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Arel - module Sql - module ArrayExtensions - def to_sql(formatter = nil) - if any? - "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" - else - "(NULL)" - end - end - - def inclusion_predicate_sql - "IN" - end - - def exclusion_predicate_sql - "NOT IN" - end - - Array.send(:include, self) - end - end -end - diff --git a/lib/arel/engines/sql/core_extensions/nil_class.rb b/lib/arel/engines/sql/core_extensions/nil_class.rb deleted file mode 100644 index 9f060ff36e7ac..0000000000000 --- a/lib/arel/engines/sql/core_extensions/nil_class.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Arel - module Sql - module NilClassExtensions - def equality_predicate_sql - 'IS' - end - - def inequality_predicate_sql - 'IS NOT' - end - - NilClass.send(:include, self) - end - end -end diff --git a/lib/arel/engines/sql/core_extensions/object.rb b/lib/arel/engines/sql/core_extensions/object.rb deleted file mode 100644 index d2fda0fe5fea6..0000000000000 --- a/lib/arel/engines/sql/core_extensions/object.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - module Sql - module ObjectExtensions - def to_sql(formatter) - formatter.scalar self - end - - def equality_predicate_sql - '=' - end - - def inequality_predicate_sql - '!=' - end - - Object.send(:include, self) - end - end -end diff --git a/lib/arel/engines/sql/core_extensions/range.rb b/lib/arel/engines/sql/core_extensions/range.rb deleted file mode 100644 index c711ffdde6868..0000000000000 --- a/lib/arel/engines/sql/core_extensions/range.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - module Sql - module RangeExtensions - def to_sql(formatter = nil) - formatter.range self.begin, self.end - end - - def inclusion_predicate_sql - "BETWEEN" - end - - def exclusion_predicate_sql - "NOT BETWEEN" - end - - Range.send(:include, self) - end - end -end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb deleted file mode 100644 index ab9dcb48b5486..0000000000000 --- a/lib/arel/engines/sql/engine.rb +++ /dev/null @@ -1,47 +0,0 @@ -module Arel - module Sql - class Engine - def initialize(ar = nil) - @ar = ar - end - - def connection - @ar && @ar.connection - end - - def adapter_name - @adapter_name ||= case (name = connection.adapter_name) - # map OracleEnanced adapter to Oracle - when /Oracle/ - 'Oracle' - else - name - end - end - - def create(relation) - primary_key_value = if relation.primary_key.blank? - nil - elsif relation.record.is_a?(Hash) - attribute = relation.record.detect { |attr, _| attr.name.to_s == relation.primary_key.to_s } - attribute && attribute.last.value - end - - connection.insert(relation.to_sql(false), nil, relation.primary_key, primary_key_value) - end - - def read(relation) - rows = connection.select_rows(relation.to_sql) - Array.new(rows, relation.attributes) - end - - def update(relation) - connection.update(relation.to_sql) - end - - def delete(relation) - connection.delete(relation.to_sql) - end - end - end -end diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb deleted file mode 100644 index da899902ff58c..0000000000000 --- a/lib/arel/engines/sql/formatters.rb +++ /dev/null @@ -1,138 +0,0 @@ -module Arel - module Sql - class Formatter - attr_reader :environment, :christener, :engine - - def initialize(environment) - @environment = environment - @christener = environment.christener - @engine = environment.engine - end - - def name_for thing - @christener.name_for thing - end - - def quote_column_name name - @engine.connection.quote_column_name name - end - - def quote_table_name name - @engine.connection.quote_table_name name - end - - def quote value, column = nil - @engine.connection.quote value, column - end - end - - class SelectClause < Formatter - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + - (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - end - - def expression(expression) - if expression.function_sql == "DISTINCT" - "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + - (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') - else - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + - (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") - end - end - - def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(name_for(table))}" - end - - def value(value) - value - end - end - - class PassThrough < Formatter - def value(value) - value - end - end - - class WhereClause < PassThrough - end - - class OrderClause < PassThrough - def ordering(ordering) - "#{quote_table_name(name_for(ordering.attribute.original_relation))}.#{quote_column_name(ordering.attribute.name)} #{ordering.direction_sql}" - end - end - - class GroupClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - end - - class HavingClause < PassThrough - def attribute(attribute) - attribute - end - end - - class WhereCondition < Formatter - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - - def expression(expression) - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" - end - - def value(value) - value.to_sql(self) - end - - def scalar(value, column = nil) - quote(value, column) - end - - def select(select_sql, table) - "(#{select_sql})" - end - end - - class SelectStatement < Formatter - def select(select_sql, table) - select_sql - end - end - - class TableReference < Formatter - def select(select_sql, table) - "(#{select_sql}) #{quote_table_name(name_for(table))}" - end - - def table(table) - table_name = table.name - return table_name if table_name =~ /\s/ - - unique_name = name_for(table) - - quote_table_name(table_name) + - (table_name != unique_name ? " #{quote_table_name(unique_name)}" : '') - end - end - - class Attribute < WhereCondition - def scalar(scalar) - quote(scalar, environment.column) - end - - def range(left, right) - "#{scalar(left)} AND #{scalar(right)}" - end - end - - class Value < WhereCondition - end - end -end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb deleted file mode 100644 index d1711d058fa5d..0000000000000 --- a/lib/arel/engines/sql/relations.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/engines/sql/relations/utilities/nil' -require 'arel/engines/sql/relations/compiler' -require 'arel/engines/sql/relations/table' diff --git a/lib/arel/engines/sql/relations/compiler.rb b/lib/arel/engines/sql/relations/compiler.rb deleted file mode 100644 index c8511374d9559..0000000000000 --- a/lib/arel/engines/sql/relations/compiler.rb +++ /dev/null @@ -1,153 +0,0 @@ -module Arel - module SqlCompiler - class GenericCompiler - attr_reader :relation, :engine - - def initialize(relation) - @relation = relation - @engine = relation.engine - end - - def christener - relation.christener - end - - def select_sql - projections = @relation.projections - if Count === projections.first && projections.size == 1 && - (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank? - subquery = [ - "SELECT 1 FROM #{relation.from_clauses}", build_clauses - ].join ' ' - query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery" - else - query = [ - "SELECT #{relation.select_clauses.join(', ')}", - "FROM #{relation.from_clauses}", - build_clauses - ].compact.join ' ' - end - query - end - - def build_clauses - joins = relation.joins(self) - wheres = relation.where_clauses - groups = relation.group_clauses - havings = relation.having_clauses - orders = relation.order_clauses - - clauses = [ "", - joins, - ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?), - ("GROUP BY #{groups.join(', ')}" unless groups.empty?), - ("HAVING #{havings.join(' AND ')}" unless havings.empty?), - ("ORDER BY #{orders.join(', ')}" unless orders.empty?) - ].compact.join ' ' - - offset = relation.skipped - limit = relation.taken - @engine.connection.add_limit_offset!(clauses, :limit => limit, - :offset => offset) if offset || limit - - clauses << " #{locked}" unless locked.blank? - clauses unless clauses.blank? - end - - def delete_sql - build_query \ - "DELETE", - "FROM #{relation.table_sql}", - ("WHERE #{relation.wheres.collect { |x| x.to_sql }.join(' AND ')}" unless relation.wheres.blank? ), - (add_limit_on_delete(relation.taken) unless relation.taken.blank? ) - end - - def add_limit_on_delete(taken) - "LIMIT #{taken}" - end - - def insert_sql(include_returning = true) - insertion_attributes_values_sql = if relation.record.is_a?(Value) - relation.record.value - else - attributes = relation.record.keys.sort_by do |attribute| - attribute.name.to_s - end - - first = attributes.collect do |key| - @engine.connection.quote_column_name(key.name) - end.join(', ') - - second = attributes.collect do |key| - key.format(relation.record[key]) - end.join(', ') - - build_query "(#{first})", "VALUES (#{second})" - end - - build_query \ - "INSERT", - "INTO #{relation.table_sql}", - insertion_attributes_values_sql, - ("RETURNING #{engine.connection.quote_column_name(primary_key)}" if include_returning && relation.compiler.supports_insert_with_returning?) - end - - def supports_insert_with_returning? - false - end - - def update_sql - build_query \ - "UPDATE #{relation.table_sql} SET", - assignment_sql, - build_update_conditions_sql - end - - protected - - def locked - relation.locked - end - - def build_query(*parts) - parts.compact.join(" ") - end - - def assignment_sql - if relation.assignments.respond_to?(:collect) - attributes = relation.assignments.keys.sort_by do |attribute| - attribute.name.to_s - end - - attributes.map do |attribute| - value = relation.assignments[attribute] - "#{@engine.connection.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(", ") - else - relation.assignments.value - end - end - - def build_update_conditions_sql - conditions = "" - conditions << " WHERE #{relation.wheres.map { |x| x.to_sql }.join(' AND ')}" unless relation.wheres.blank? - conditions << " ORDER BY #{relation.order_clauses.join(', ')}" unless relation.orders.blank? - - taken = relation.taken - unless taken.blank? - conditions = limited_update_conditions(conditions, taken) - end - - conditions - end - - def limited_update_conditions(conditions, taken) - conditions << " LIMIT #{taken}" - quoted_primary_key = @engine.connection.quote_column_name(relation.primary_key) - "WHERE #{quoted_primary_key} IN (SELECT #{quoted_primary_key} FROM #{@engine.connection.quote_table_name relation.table.name} #{conditions})" - end - - end - - end -end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb deleted file mode 100644 index b31df7a6d0860..0000000000000 --- a/lib/arel/engines/sql/relations/table.rb +++ /dev/null @@ -1,100 +0,0 @@ -module Arel - class Table - include Relation, Recursion::BaseCase - - @@engine = nil - @@tables = nil - class << self # FIXME: Do we really need these? - def engine; @@engine; end - def engine= e; @@engine = e; end - - def tables; @@tables; end - def tables= e; @@tables = e; end - end - - attr_reader :name, :engine, :table_alias, :options, :christener - attr_reader :table_exists - alias :table_exists? :table_exists - - def initialize(name, options = {}) - @name = name.to_s - @table_exists = nil - @table_alias = nil - @christener = Sql::Christener.new - @attributes = nil - @matching_attributes = nil - - if options.is_a?(Hash) - @options = options - @engine = options[:engine] || Table.engine - - if options[:as] - as = options[:as].to_s - @table_alias = as unless as == @name - end - else - @engine = options # Table.new('foo', engine) - end - - if @engine.connection - begin - require "arel/engines/sql/compilers/#{@engine.adapter_name.downcase}_compiler" - rescue LoadError - begin - # try to load an externally defined compiler, in case this adapter has defined the compiler on its own. - require "#{@engine.adapter_name.downcase}/arel_compiler" - rescue LoadError - raise "#{@engine.adapter_name} is not supported by Arel." - end - end - - @@tables ||= engine.connection.tables - @table_exists = @@tables.include?(name) || - @engine.connection.table_exists?(name) - end - end - - def as(table_alias) - Table.new(name, options.merge(:as => table_alias)) - end - - def attributes - return @attributes if @attributes - if table_exists? - attrs = columns.collect do |column| - Sql::Attributes.for(column).new(column, self, column.name.to_sym) - end - @attributes = Header.new(attrs) - else - Header.new - end - end - - def column_for(attribute) - has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } - end - - def columns - @columns ||= engine.connection.columns(name, "#{name} Columns") - end - - def reset - @columns = nil - @attributes = Header.new([]) - end - - private - def matching_attributes - @matching_attributes ||= Hash[attributes.map { |a| [a.root, true] }] - end - - def has_attribute?(attribute) - matching_attributes.key? attribute.root - end - end -end - -def Table(name, engine = Arel::Table.engine) - Arel::Table.new(name, engine) -end - diff --git a/lib/arel/engines/sql/relations/utilities/nil.rb b/lib/arel/engines/sql/relations/utilities/nil.rb deleted file mode 100644 index 0f7ca5d7575bf..0000000000000 --- a/lib/arel/engines/sql/relations/utilities/nil.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - class Nil - def table_sql(formatter = nil); '' end - def name; '' end - end -end diff --git a/lib/arel/recursion/base_case.rb b/lib/arel/recursion/base_case.rb deleted file mode 100644 index 84a526f57c7dd..0000000000000 --- a/lib/arel/recursion/base_case.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Recursion - module BaseCase - def table - self - end - - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self - end - end - end -end diff --git a/lib/arel/session.rb b/lib/arel/session.rb deleted file mode 100644 index f6016431c3b74..0000000000000 --- a/lib/arel/session.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Arel - class Session - @instance = nil - - def self.instance - @instance || new - end - - def self.start - @instance ||= new - yield @instance - ensure - @instance = nil - end - - def create(insert) - insert.call - end - - def read(select) - @read ||= {} - key = select.object_id - return @read[key] if @read.key? key - @read[key] = select.call - end - - def update(update) - update.call - end - - def delete(delete) - delete.call - end - end -end diff --git a/lib/arel/sql_literal.rb b/lib/arel/sql_literal.rb deleted file mode 100644 index a98a9a058cfcb..0000000000000 --- a/lib/arel/sql_literal.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - class SqlLiteral < String - def relation - nil - end - - def to_sql(formatter = nil) - self - end - - include Attribute::Expressions - end -end diff --git a/lib/arel/version.rb b/lib/arel/version.rb deleted file mode 100644 index ddf477004d493..0000000000000 --- a/lib/arel/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module Arel - VERSION = "0.4.0" unless defined?(Arel::VERSION) -end From bd5f19371f473f032ca297cb412b3410e9494b3d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 11:24:16 -0700 Subject: [PATCH 0581/1492] adding a table and engine --- lib/arel.rb | 5 +++-- lib/arel/sql/engine.rb | 10 ++++++++++ lib/arel/table.rb | 15 +++++++++++++++ lib/arel/version.rb | 3 +++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 lib/arel/sql/engine.rb create mode 100644 lib/arel/table.rb create mode 100644 lib/arel/version.rb diff --git a/lib/arel.rb b/lib/arel.rb index 9a48ff1afbff0..a805cf60fab35 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,2 +1,3 @@ -module Arel -end +require 'arel/version' +require 'arel/table' +require 'arel/sql/engine' diff --git a/lib/arel/sql/engine.rb b/lib/arel/sql/engine.rb new file mode 100644 index 0000000000000..d1a3880735912 --- /dev/null +++ b/lib/arel/sql/engine.rb @@ -0,0 +1,10 @@ +module Arel + module Sql + class Engine + def self.new thing + warn "#{caller.first} -- Engine will be removed" + thing + end + end + end +end diff --git a/lib/arel/table.rb b/lib/arel/table.rb new file mode 100644 index 0000000000000..e4056074ae54e --- /dev/null +++ b/lib/arel/table.rb @@ -0,0 +1,15 @@ +module Arel + class Table + @engine = nil + class << self; attr_accessor :engine; end + + def initialize table_name, engine + @table_name = table_name + @engine = engine + end + + def [] attribute + raise attribute + end + end +end diff --git a/lib/arel/version.rb b/lib/arel/version.rb new file mode 100644 index 0000000000000..ba9cca430aa10 --- /dev/null +++ b/lib/arel/version.rb @@ -0,0 +1,3 @@ +module Arel + VERSION = '0.4.1.beta.1' +end From 25083947e3f3ca8cf19380366bd3e186261b17f3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 14:24:11 -0700 Subject: [PATCH 0582/1492] stripping the spec helper --- spec/{algebra/unit/relations => arel}/table_spec.rb | 0 spec/spec_helper.rb | 9 --------- 2 files changed, 9 deletions(-) rename spec/{algebra/unit/relations => arel}/table_spec.rb (100%) diff --git a/spec/algebra/unit/relations/table_spec.rb b/spec/arel/table_spec.rb similarity index 100% rename from spec/algebra/unit/relations/table_spec.rb rename to spec/arel/table_spec.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e92129d723432..5d3f5a2950c24 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,6 +1,5 @@ require 'rubygems' require 'spec' -require 'pp' require 'fileutils' require 'arel' @@ -8,15 +7,7 @@ require "support/connections/#{adapter}_connection.rb" end -Dir["spec/{support,shared}/*.rb"].each do |file| - require file -end - Spec::Runner.configure do |config| - config.include Matchers - config.include AdapterGuards - config.include Check - if defined?(ActiveRecord::Base) tmp = File.expand_path('../../tmp', __FILE__) From 1036749e394e5f7f039e75cdec7675f9ca5047b0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 14:24:21 -0700 Subject: [PATCH 0583/1492] starting a spec for the table --- lib/arel/table.rb | 2 +- spec/arel/table_spec.rb | 37 +++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index e4056074ae54e..a4ae9bd18d0e4 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -3,7 +3,7 @@ class Table @engine = nil class << self; attr_accessor :engine; end - def initialize table_name, engine + def initialize table_name, engine = Table.engine @table_name = table_name @engine = engine end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index d1c7cc46ba8e3..20c962c26a9a8 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -9,30 +9,31 @@ module Arel describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do - check @relation[:id].should == Attributes::Integer.new(@relation, :id) + column = @relation[:id] + #.should == Attributes::Integer.new(@relation, :id) end end - describe 'when given an', Attribute do - it "returns the attribute if the attribute is within the relation" do - @relation[@relation[:id]].should == @relation[:id] - end + #describe 'when given an', Attribute do + # it "returns the attribute if the attribute is within the relation" do + # @relation[@relation[:id]].should == @relation[:id] + # end - it "returns nil if the attribtue is not within the relation" do - another_relation = Table.new(:photos) - @relation[another_relation[:id]].should be_nil - end - end + # it "returns nil if the attribtue is not within the relation" do + # another_relation = Table.new(:photos) + # @relation[another_relation[:id]].should be_nil + # end + #end - describe 'when given an', Expression do - before do - @expression = @relation[:id].count - end + #describe 'when given an', Expression do + # before do + # @expression = @relation[:id].count + # end - it "returns the Expression if the Expression is within the relation" do - @relation[@expression].should be_nil - end - end + # it "returns the Expression if the Expression is within the relation" do + # @relation[@expression].should be_nil + # end + #end end end end From 196b4e05b7390ac31e12a17ae224b1cf35e4becd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 14:55:31 -0700 Subject: [PATCH 0584/1492] tables can fetch attributes --- lib/arel.rb | 3 +++ lib/arel/attributes.rb | 20 ++++++++++++++++ lib/arel/attributes/attribute.rb | 13 ++++++++++ lib/arel/table.rb | 17 +++++++++---- spec/arel/attributes_spec.rb | 41 ++++++++++++++++++++++++++++++++ spec/arel/table_spec.rb | 12 +++++++++- 6 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 lib/arel/attributes.rb create mode 100644 lib/arel/attributes/attribute.rb create mode 100644 spec/arel/attributes_spec.rb diff --git a/lib/arel.rb b/lib/arel.rb index a805cf60fab35..afab11cd91ad7 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,3 +1,6 @@ require 'arel/version' require 'arel/table' +require 'arel/attributes' + +# below is deprecated require 'arel/sql/engine' diff --git a/lib/arel/attributes.rb b/lib/arel/attributes.rb new file mode 100644 index 0000000000000..a7fb00293b130 --- /dev/null +++ b/lib/arel/attributes.rb @@ -0,0 +1,20 @@ +require '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 + raise NotImplementedError, "Column type `#{column.type}` is not currently handled" + end + end + end +end diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb new file mode 100644 index 0000000000000..b83a32bee76af --- /dev/null +++ b/lib/arel/attributes/attribute.rb @@ -0,0 +1,13 @@ +module Arel + module Attributes + class Attribute < Struct.new :relation, :name, :column + 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 + end +end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index a4ae9bd18d0e4..78b3ea9933c54 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -3,13 +3,20 @@ class Table @engine = nil class << self; attr_accessor :engine; end - def initialize table_name, engine = Table.engine - @table_name = table_name - @engine = engine + def initialize name, engine = Table.engine + @name = name + @engine = engine end - def [] attribute - raise attribute + def columns + @engine.connection.columns(@name, "#{@name} Columns").map do |column| + Attributes.for(column).new self, column.name, column + end + end + + def [] name + name = name.to_s + columns.find { |column| column.name == name } end end end diff --git a/spec/arel/attributes_spec.rb b/spec/arel/attributes_spec.rb new file mode 100644 index 0000000000000..8b437dff9b862 --- /dev/null +++ b/spec/arel/attributes_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +module Arel + describe 'Attributes' do + describe 'for' do + it 'returns the correct constant for strings' do + [:string, :text, :binary].each do |type| + column = Struct.new(:type).new type + Attributes.for(column).should == Attributes::String + end + end + + it 'returns the correct constant for ints' do + column = Struct.new(:type).new :integer + Attributes.for(column).should == Attributes::Integer + end + + it 'returns the correct constant for floats' do + column = Struct.new(:type).new :float + Attributes.for(column).should == Attributes::Float + end + + it 'returns the correct constant for decimals' do + column = Struct.new(:type).new :decimal + Attributes.for(column).should == Attributes::Decimal + end + + it 'returns the correct constant for boolean' do + column = Struct.new(:type).new :boolean + Attributes.for(column).should == 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).should == Attributes::Time + end + end + end + end +end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 20c962c26a9a8..c52a111489006 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,14 +6,24 @@ module Arel @relation = Table.new(:users) end + describe 'columns' do + it 'returns a list of columns' do + columns = @relation.columns + columns.length.should == 2 + columns.map { |x| x.name }.sort.should == %w{ name id }.sort + end + 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] - #.should == Attributes::Integer.new(@relation, :id) + column.name.should == 'id' + column.should be_kind_of Attributes::Integer end end + ### FIXME: this seems like a bad requirement. #describe 'when given an', Attribute do # it "returns the attribute if the attribute is within the relation" do # @relation[@relation[:id]].should == @relation[:id] From 4127484bc172900f0817d6adda666a1397ff038e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 15:22:26 -0700 Subject: [PATCH 0585/1492] adding first node --- lib/arel.rb | 1 + lib/arel/attributes/attribute.rb | 9 ++++++--- lib/arel/nodes.rb | 1 + lib/arel/nodes/equality.rb | 12 ++++++++++++ spec/arel/attributes/attribute_spec.rb | 17 +++++++++++++++++ 5 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 lib/arel/nodes.rb create mode 100644 lib/arel/nodes/equality.rb create mode 100644 spec/arel/attributes/attribute_spec.rb diff --git a/lib/arel.rb b/lib/arel.rb index afab11cd91ad7..b322e930be0a4 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,7 @@ require 'arel/version' require 'arel/table' require 'arel/attributes' +require 'arel/nodes' # below is deprecated require 'arel/sql/engine' diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index b83a32bee76af..fdc64d62e08f6 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -1,13 +1,16 @@ module Arel module Attributes class Attribute < Struct.new :relation, :name, :column + def eq other + Nodes::Equality.new self, other + end end - class String < Attribute; end - class Time < Attribute; end + class String < Attribute; end + class Time < Attribute; end class Boolean < Attribute; end class Decimal < Attribute; end - class Float < Attribute; end + class Float < Attribute; end class Integer < Attribute; end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb new file mode 100644 index 0000000000000..855d8cf236142 --- /dev/null +++ b/lib/arel/nodes.rb @@ -0,0 +1 @@ +require 'arel/nodes/equality' diff --git a/lib/arel/nodes/equality.rb b/lib/arel/nodes/equality.rb new file mode 100644 index 0000000000000..11383b1d8948b --- /dev/null +++ b/lib/arel/nodes/equality.rb @@ -0,0 +1,12 @@ +module Arel + module Nodes + class Equality + attr_accessor :left, :right + + def initialize left, right + @left = left + @right = right + end + end + end +end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb new file mode 100644 index 0000000000000..5599bb7b51c25 --- /dev/null +++ b/spec/arel/attributes/attribute_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +module Arel + module Attributes + describe 'attribute' do + describe '#eq' do + it 'should return an equality node' do + attribute = Attribute.new nil, nil, nil + equality = attribute.eq 1 + equality.left.should == attribute + equality.right.should == 1 + equality.should be_kind_of Nodes::Equality + end + end + end + end +end From 199d17b2dbb56000098a0372f0c64ce0aa3711ce Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 15:26:04 -0700 Subject: [PATCH 0586/1492] adding some deprecated classes --- lib/arel.rb | 1 + lib/arel/nodes.rb | 1 + lib/arel/nodes/sql_literal.rb | 11 +++++++++++ lib/arel/sql_literal.rb | 8 ++++++++ 4 files changed, 21 insertions(+) create mode 100644 lib/arel/nodes/sql_literal.rb create mode 100644 lib/arel/sql_literal.rb diff --git a/lib/arel.rb b/lib/arel.rb index b322e930be0a4..4584584c353d8 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -5,3 +5,4 @@ # below is deprecated require 'arel/sql/engine' +require 'arel/sql_literal' diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 855d8cf236142..07a687405f362 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1 +1,2 @@ require 'arel/nodes/equality' +require 'arel/nodes/sql_literal' diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb new file mode 100644 index 0000000000000..45866adfa83f6 --- /dev/null +++ b/lib/arel/nodes/sql_literal.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class SqlLiteral + attr_accessor :string + + def initialize string + @string = string + end + end + end +end diff --git a/lib/arel/sql_literal.rb b/lib/arel/sql_literal.rb new file mode 100644 index 0000000000000..f844ea62ce492 --- /dev/null +++ b/lib/arel/sql_literal.rb @@ -0,0 +1,8 @@ +module Arel + class SqlLiteral < Nodes::SqlLiteral + def initialize string + warn "#{caller.first} should use Nodes::SqlLiteral" + super + end + end +end From d827d6e9ee10fa0906b7b3cfd191e6f9ac5d6b08 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 15:40:58 -0700 Subject: [PATCH 0587/1492] to_sql visitor started --- lib/arel.rb | 1 + lib/arel/nodes/equality.rb | 5 ++++ lib/arel/table.rb | 2 ++ lib/arel/visitors/to_sql.rb | 38 ++++++++++++++++++++++++++ spec/arel/attributes/attribute_spec.rb | 10 +++++++ spec/arel/table_spec.rb | 8 ++++++ 6 files changed, 64 insertions(+) create mode 100644 lib/arel/visitors/to_sql.rb diff --git a/lib/arel.rb b/lib/arel.rb index 4584584c353d8..ea9a462d1f13e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -2,6 +2,7 @@ require 'arel/table' require 'arel/attributes' require 'arel/nodes' +require 'arel/visitors/to_sql' # below is deprecated require 'arel/sql/engine' diff --git a/lib/arel/nodes/equality.rb b/lib/arel/nodes/equality.rb index 11383b1d8948b..d778380054c6a 100644 --- a/lib/arel/nodes/equality.rb +++ b/lib/arel/nodes/equality.rb @@ -7,6 +7,11 @@ def initialize left, right @left = left @right = right end + + def to_sql + viz = Visitors::ToSql.new left.relation.engine + viz.accept self + end end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 78b3ea9933c54..0ab39f134d24e 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -3,6 +3,8 @@ class Table @engine = nil class << self; attr_accessor :engine; end + attr_reader :name, :engine + def initialize name, engine = Table.engine @name = name @engine = engine diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb new file mode 100644 index 0000000000000..ba92ca7ef132d --- /dev/null +++ b/lib/arel/visitors/to_sql.rb @@ -0,0 +1,38 @@ +module Arel + module Visitors + class ToSql + def initialize engine + @engine = engine + @connection = nil + end + + def accept object + @connection = @engine.connection + visit object + end + + private + def visit_Arel_Nodes_Equality o + "#{visit o.left} = #{visit o.right}" + end + + def visit_Arel_Attributes_Integer o + "#{quote_table_name o.relation.name}.#{quote_column_name o.name}" + end + + def visit_Fixnum o; o end + + def visit object + send :"visit_#{object.class.name.gsub('::', '_')}", object + end + + def quote_table_name name + @connection.quote_table_name name + end + + def quote_column_name name + @connection.quote_column_name name + end + end + end +end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index 5599bb7b51c25..ef0e0787fa735 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -13,5 +13,15 @@ module Attributes 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.should == '"users"."id" = 1' + end + end + end end end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index c52a111489006..be153438c4d20 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -14,6 +14,14 @@ module Arel end end + it "should have a name" do + @relation.name.should == :users + end + + it "should have an engine" do + @relation.engine.should == 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 From 16e7273245473bb6466a79a38702a52387bab44d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 16:19:54 -0700 Subject: [PATCH 0588/1492] full sql statement generation --- lib/arel.rb | 1 + lib/arel/nodes.rb | 1 + lib/arel/nodes/select.rb | 13 +++++++++++ lib/arel/tree_manager.rb | 31 ++++++++++++++++++++++++++ lib/arel/visitors/to_sql.rb | 12 ++++++++++ spec/arel/tree_manager.rb | 44 +++++++++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 lib/arel/nodes/select.rb create mode 100644 lib/arel/tree_manager.rb create mode 100644 spec/arel/tree_manager.rb diff --git a/lib/arel.rb b/lib/arel.rb index ea9a462d1f13e..e1d34d4561244 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,7 @@ require 'arel/version' require 'arel/table' require 'arel/attributes' +require 'arel/tree_manager' require 'arel/nodes' require 'arel/visitors/to_sql' diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 07a687405f362..53c17a8cca259 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,2 +1,3 @@ require 'arel/nodes/equality' require 'arel/nodes/sql_literal' +require 'arel/nodes/select' diff --git a/lib/arel/nodes/select.rb b/lib/arel/nodes/select.rb new file mode 100644 index 0000000000000..8f68adbcd59eb --- /dev/null +++ b/lib/arel/nodes/select.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class Select + attr_reader :froms, :projections, :wheres + + def initialize + @froms = [] + @projections = [] + @wheres = [] + end + end + end +end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb new file mode 100644 index 0000000000000..b111ca9557103 --- /dev/null +++ b/lib/arel/tree_manager.rb @@ -0,0 +1,31 @@ +module Arel + class TreeManager + def initialize engine + @engine = engine + @statement_list = [] + + # default to Select + @statement_list << Nodes::Select.new + end + + def from table + @statement_list.last.froms << table + self + end + + def project projection + @statement_list.last.projections << projection + self + end + + def where expr + @statement_list.last.wheres << expr + self + end + + def to_sql + viz = Visitors::ToSql.new @engine + viz.accept @statement_list.last + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ba92ca7ef132d..bb2a4d07e8f5a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -12,6 +12,18 @@ def accept object end private + def visit_Arel_Nodes_Select o + [ + "SELECT #{o.projections.map { |x| visit x }.join ', '}", + "FROM #{o.froms.map { |x| visit x }.join ', ' }", + ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.blank?) + ].compact.join ' ' + end + + def visit_Arel_Table o + quote_table_name o.name + end + def visit_Arel_Nodes_Equality o "#{visit o.left} = #{visit o.right}" end diff --git a/spec/arel/tree_manager.rb b/spec/arel/tree_manager.rb new file mode 100644 index 0000000000000..513b41e305406 --- /dev/null +++ b/spec/arel/tree_manager.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +module Arel + describe 'tree manager' do + describe 'where' do + it "knows where" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.from(table).project(table['id']) + manager.where(table['id'].eq(1)) + manager.to_sql.should == %{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + end + + it "chains" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.from(table) + manager.project(table['id']).where(table['id'].eq 1).should == manager + end + end + + describe 'from' do + it "makes sql" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + + manager.from table + manager.project table['id'] + manager.to_sql.should == 'SELECT "users"."id" FROM "users"' + end + + it "chains" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.from(table).project(table['id']).should == manager + manager.to_sql.should == 'SELECT "users"."id" FROM "users"' + end + end + end +end From e573a9ea468d748cf0ebd1a70521c1589efda23e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Aug 2010 21:21:20 -0700 Subject: [PATCH 0589/1492] limits are added --- lib/arel/nodes.rb | 3 ++- lib/arel/nodes/{select.rb => select_core.rb} | 2 +- lib/arel/nodes/select_statement.rb | 13 +++++++++++ lib/arel/table.rb | 4 ++++ lib/arel/tree_manager.rb | 21 ++++++++++++------ lib/arel/visitors/to_sql.rb | 9 +++++++- spec/arel/table_spec.rb | 13 +++++++++++ spec/arel/tree_manager.rb | 23 ++++++++++++++++++++ 8 files changed, 78 insertions(+), 10 deletions(-) rename lib/arel/nodes/{select.rb => select_core.rb} (90%) create mode 100644 lib/arel/nodes/select_statement.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 53c17a8cca259..5db177d53d47d 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,3 +1,4 @@ require 'arel/nodes/equality' require 'arel/nodes/sql_literal' -require 'arel/nodes/select' +require 'arel/nodes/select_core' +require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/select.rb b/lib/arel/nodes/select_core.rb similarity index 90% rename from lib/arel/nodes/select.rb rename to lib/arel/nodes/select_core.rb index 8f68adbcd59eb..39145de69733b 100644 --- a/lib/arel/nodes/select.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class Select + class SelectCore attr_reader :froms, :projections, :wheres def initialize diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb new file mode 100644 index 0000000000000..122f6275fe07a --- /dev/null +++ b/lib/arel/nodes/select_statement.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class SelectStatement + attr_reader :cores + attr_accessor :limit + + def initialize cores = [SelectCore.new] + @cores = cores + @limit = nil + end + end + end +end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 0ab39f134d24e..7933c8c1a4e9c 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -10,6 +10,10 @@ def initialize name, engine = Table.engine @engine = engine end + def where expression + TreeManager.new(@engine).from(self).where expression + end + def columns @engine.connection.columns(@name, "#{@name} Columns").map do |column| Attributes.for(column).new self, column.name, column diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index b111ca9557103..e92092d6e1b3e 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,31 +1,38 @@ module Arel class TreeManager def initialize engine - @engine = engine - @statement_list = [] + @engine = engine + @selects = [] # default to Select - @statement_list << Nodes::Select.new + @stmt = Nodes::SelectStatement.new + @core = @stmt.cores.last + @selects << @stmt end def from table - @statement_list.last.froms << table + @core.froms << table self end def project projection - @statement_list.last.projections << projection + @core.projections << projection self end def where expr - @statement_list.last.wheres << expr + @core.wheres << expr + self + end + + def take limit + @stmt.limit = limit self end def to_sql viz = Visitors::ToSql.new @engine - viz.accept @statement_list.last + viz.accept @stmt end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index bb2a4d07e8f5a..44a585698f63c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -12,7 +12,14 @@ def accept object end private - def visit_Arel_Nodes_Select o + def visit_Arel_Nodes_SelectStatement o + [ + o.cores.map { |x| visit x }.join, + ("LIMIT #{o.limit}" if o.limit) + ].compact.join ' ' + end + + def visit_Arel_Nodes_SelectCore o [ "SELECT #{o.projections.map { |x| visit x }.join ', '}", "FROM #{o.froms.map { |x| visit x }.join ', ' }", diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index be153438c4d20..b68fdd5a3d547 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,6 +6,19 @@ module Arel @relation = Table.new(:users) end + describe 'where' do + it "returns a tree manager" do + manager = @relation.where @relation[:id].eq 1 + manager.project @relation[:id] + manager.should be_kind_of TreeManager + manager.to_sql.should == %{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + end + end + describe 'columns' do it 'returns a list of columns' do columns = @relation.columns diff --git a/spec/arel/tree_manager.rb b/spec/arel/tree_manager.rb index 513b41e305406..44dbb9f7275f0 100644 --- a/spec/arel/tree_manager.rb +++ b/spec/arel/tree_manager.rb @@ -2,6 +2,29 @@ module Arel describe 'tree manager' do + describe 'take' do + it "knows take" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.from(table).project(table['id']) + manager.where(table['id'].eq(1)) + manager.take 1 + + manager.to_sql.should == %{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + LIMIT 1 + }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + end + + it "chains" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.take(1).should == manager + end + end + describe 'where' do it "knows where" do table = Table.new :users From 38b10d5ea1411e4adcbb190cc6a38c9529b8998c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 08:11:08 -0700 Subject: [PATCH 0590/1492] project works with strings --- lib/arel.rb | 6 ++++-- lib/arel/nodes/sql_literal.rb | 7 +------ lib/arel/sql_literal.rb | 4 ---- lib/arel/table.rb | 4 ++-- lib/arel/visitors/to_sql.rb | 17 ++++++++++++++--- spec/arel/tree_manager.rb | 20 ++++++++++++++++++++ 6 files changed, 41 insertions(+), 17 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index e1d34d4561244..aeb5161b1d120 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -3,8 +3,10 @@ require 'arel/attributes' require 'arel/tree_manager' require 'arel/nodes' -require 'arel/visitors/to_sql' -# below is deprecated +#### these are deprecated require 'arel/sql/engine' require 'arel/sql_literal' +#### + +require 'arel/visitors/to_sql' diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 45866adfa83f6..53ff376071dae 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -1,11 +1,6 @@ module Arel module Nodes - class SqlLiteral - attr_accessor :string - - def initialize string - @string = string - end + class SqlLiteral < String end end end diff --git a/lib/arel/sql_literal.rb b/lib/arel/sql_literal.rb index f844ea62ce492..5cb4973117647 100644 --- a/lib/arel/sql_literal.rb +++ b/lib/arel/sql_literal.rb @@ -1,8 +1,4 @@ module Arel class SqlLiteral < Nodes::SqlLiteral - def initialize string - warn "#{caller.first} should use Nodes::SqlLiteral" - super - end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 7933c8c1a4e9c..3d0fae07b4377 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -10,8 +10,8 @@ def initialize name, engine = Table.engine @engine = engine end - def where expression - TreeManager.new(@engine).from(self).where expression + def tm + TreeManager.new(@engine).from(self) end def columns diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 44a585698f63c..53ae6e0860111 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -22,8 +22,8 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_SelectCore o [ "SELECT #{o.projections.map { |x| visit x }.join ', '}", - "FROM #{o.froms.map { |x| visit x }.join ', ' }", - ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.blank?) + ("FROM #{o.froms.map { |x| visit x }.join ', ' }" unless o.froms.empty?), + ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?) ].compact.join ' ' end @@ -40,9 +40,20 @@ def visit_Arel_Attributes_Integer o end def visit_Fixnum o; o end + alias :visit_String :visit_Fixnum + alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum + alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated + DISPATCH = {} def visit object - send :"visit_#{object.class.name.gsub('::', '_')}", object + send DISPATCH[object.class], object + end + + private_instance_methods(false).each do |method| + method = method.to_s + next unless method =~ /^visit_(.*)$/ + const = $1.split('_').inject(Object) { |m,s| m.const_get s } + DISPATCH[const] = method end def quote_table_name name diff --git a/spec/arel/tree_manager.rb b/spec/arel/tree_manager.rb index 44dbb9f7275f0..92af2f3dcde6b 100644 --- a/spec/arel/tree_manager.rb +++ b/spec/arel/tree_manager.rb @@ -2,6 +2,26 @@ module Arel describe 'tree manager' do + describe 'project' do + it 'takes strings' do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.project '*' + manager.to_sql.should == %{ + SELECT * + }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + end + + it "takes sql literals" do + table = Table.new :users + manager = Arel::TreeManager.new Table.engine + manager.project Nodes::SqlLiteral.new '*' + manager.to_sql.should == %{ + SELECT * + }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + end + end + describe 'take' do it "knows take" do table = Table.new :users From bfe0348889d17737b91604d48c529d31ab8b9c1c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 11:30:24 -0700 Subject: [PATCH 0591/1492] table responds to where, column info is cached --- lib/arel/table.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 3d0fae07b4377..4c0404b4923fe 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -6,16 +6,21 @@ class << self; attr_accessor :engine; end attr_reader :name, :engine def initialize name, engine = Table.engine - @name = name - @engine = engine + @name = name + @engine = engine + @columns = nil end def tm TreeManager.new(@engine).from(self) end + def where condition + tm.where condition + end + def columns - @engine.connection.columns(@name, "#{@name} Columns").map do |column| + @columns ||= @engine.connection.columns(@name, "#{@name} Columns").map do |column| Attributes.for(column).new self, column.name, column end end From 5d7cad60799179e2ac6c1a7505980c85a775c55a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 11:53:36 -0700 Subject: [PATCH 0592/1492] Table.new can take a hash for the second param --- lib/arel/table.rb | 7 ++++--- spec/arel/table_spec.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 4c0404b4923fe..1b37a3b66be9a 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -6,9 +6,10 @@ class << self; attr_accessor :engine; end attr_reader :name, :engine def initialize name, engine = Table.engine - @name = name - @engine = engine - @columns = nil + @name = name + @engine = engine + @engine = engine[:engine] if Hash === engine + @columns = nil end def tm diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index b68fdd5a3d547..67024f5c520ff 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,6 +6,18 @@ module Arel @relation = Table.new(:users) end + describe 'new' do + it 'should accept an engine' do + rel = Table.new :users, 'foo' + rel.engine.should == 'foo' + end + + it 'should accept a hash' do + rel = Table.new :users, :engine => 'foo' + rel.engine.should == 'foo' + end + end + describe 'where' do it "returns a tree manager" do manager = @relation.where @relation[:id].eq 1 From 9b97d6ca9bb95e26b0806b15d7eb0818af0fc925 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 12:26:06 -0700 Subject: [PATCH 0593/1492] adding a relation thing --- lib/arel.rb | 6 ++++++ lib/arel/relation.rb | 6 ++++++ lib/arel/tree_manager.rb | 3 +++ 3 files changed, 15 insertions(+) create mode 100644 lib/arel/relation.rb diff --git a/lib/arel.rb b/lib/arel.rb index aeb5161b1d120..1cca58f31b3ae 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,12 @@ require 'arel/version' require 'arel/table' require 'arel/attributes' + +#### these are deprecated +# The Arel::Relation constant is referenced in Rails +require 'arel/relation' +#### + require 'arel/tree_manager' require 'arel/nodes' diff --git a/lib/arel/relation.rb b/lib/arel/relation.rb new file mode 100644 index 0000000000000..87786d7701761 --- /dev/null +++ b/lib/arel/relation.rb @@ -0,0 +1,6 @@ +module Arel + ### + # This is deprecated. Fix rails, then remove this. + module Relation + end +end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index e92092d6e1b3e..9de86e2add9fc 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,5 +1,8 @@ module Arel class TreeManager + # FIXME: Remove this. + include Arel::Relation + def initialize engine @engine = engine @selects = [] From a37bdba9be810fa5fc292175497ee614900c5043 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 14:13:38 -0700 Subject: [PATCH 0594/1492] table responds to "project" --- lib/arel/table.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 3 ++- spec/arel/table_spec.rb | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 1b37a3b66be9a..a189838c07dbd 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -20,6 +20,10 @@ def where condition tm.where condition end + def project thing + tm.project thing + end + def columns @columns ||= @engine.connection.columns(@name, "#{@name} Columns").map do |column| Attributes.for(column).new self, column.name, column diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 53ae6e0860111..2b3216abd3084 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -46,7 +46,8 @@ def visit_Fixnum o; o end DISPATCH = {} def visit object - send DISPATCH[object.class], object + send "visit_#{object.class.name.gsub('::', '_')}", object + #send DISPATCH[object.class], object end private_instance_methods(false).each do |method| diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 67024f5c520ff..cf309ca8ca0d6 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -18,6 +18,16 @@ module Arel end end + describe 'project' do + it 'can project' do + manager = @relation.project '*' + manager.to_sql.should == %{ + SELECT * + FROM "users" + }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + end + end + describe 'where' do it "returns a tree manager" do manager = @relation.where @relation[:id].eq 1 From b1e7bd7d026c888d4c406adc595577b7ebc84ed5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 15:30:22 -0700 Subject: [PATCH 0595/1492] insert manager is starting to take shape --- lib/arel.rb | 2 + lib/arel/insert_manager.rb | 13 +++++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/insert_statement.rb | 13 +++++++ lib/arel/select_manager.rb | 29 ++++++++++++++ lib/arel/table.rb | 2 +- lib/arel/tree_manager.rb | 30 +-------------- lib/arel/visitors/to_sql.rb | 4 ++ spec/arel/insert_manager.rb | 29 ++++++++++++++ .../{tree_manager.rb => select_manager.rb} | 38 +++++++++---------- spec/arel/table_spec.rb | 8 ++-- spec/spec_helper.rb | 4 ++ 12 files changed, 121 insertions(+), 52 deletions(-) create mode 100644 lib/arel/insert_manager.rb create mode 100644 lib/arel/nodes/insert_statement.rb create mode 100644 lib/arel/select_manager.rb create mode 100644 spec/arel/insert_manager.rb rename spec/arel/{tree_manager.rb => select_manager.rb} (60%) diff --git a/lib/arel.rb b/lib/arel.rb index 1cca58f31b3ae..8465d8e658160 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -8,6 +8,8 @@ #### require 'arel/tree_manager' +require 'arel/insert_manager' +require 'arel/select_manager' require 'arel/nodes' #### these are deprecated diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb new file mode 100644 index 0000000000000..bfd3034df42df --- /dev/null +++ b/lib/arel/insert_manager.rb @@ -0,0 +1,13 @@ +module Arel + class InsertManager < Arel::TreeManager + def initialize engine + super + @head = Nodes::InsertStatement.new + end + + def into table + @head.relation = table + self + end + end +end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 5db177d53d47d..eed9641bbc609 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -2,3 +2,4 @@ require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' +require 'arel/nodes/insert_statement' diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb new file mode 100644 index 0000000000000..ed601aa841e95 --- /dev/null +++ b/lib/arel/nodes/insert_statement.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class InsertStatement + attr_accessor :relation, :columns, :values + + def initialize + @relation = nil + @columns = [] + @values = [] + end + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb new file mode 100644 index 0000000000000..6420142fa0d4b --- /dev/null +++ b/lib/arel/select_manager.rb @@ -0,0 +1,29 @@ +module Arel + class SelectManager < Arel::TreeManager + def initialize engine + super + @head = Nodes::SelectStatement.new + @ctx = @head.cores.last + end + + def from table + @ctx.froms << table + self + end + + def project projection + @ctx.projections << projection + self + end + + def where expr + @ctx.wheres << expr + self + end + + def take limit + @head.limit = limit + self + end + end +end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index a189838c07dbd..4269dfc62fb5f 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -13,7 +13,7 @@ def initialize name, engine = Table.engine end def tm - TreeManager.new(@engine).from(self) + SelectManager.new(@engine).from(self) end def where condition diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 9de86e2add9fc..9dd9f27858fa5 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -4,38 +4,12 @@ class TreeManager include Arel::Relation def initialize engine - @engine = engine - @selects = [] - - # default to Select - @stmt = Nodes::SelectStatement.new - @core = @stmt.cores.last - @selects << @stmt - end - - def from table - @core.froms << table - self - end - - def project projection - @core.projections << projection - self - end - - def where expr - @core.wheres << expr - self - end - - def take limit - @stmt.limit = limit - self + @engine = engine end def to_sql viz = Visitors::ToSql.new @engine - viz.accept @stmt + viz.accept @head end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2b3216abd3084..7a97b0d4457b5 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -12,6 +12,10 @@ def accept object end private + def visit_Arel_Nodes_InsertStatement o + "INSERT INTO #{visit o.relation}" + end + def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit x }.join, diff --git a/spec/arel/insert_manager.rb b/spec/arel/insert_manager.rb new file mode 100644 index 0000000000000..8d49556fa9952 --- /dev/null +++ b/spec/arel/insert_manager.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +module Arel + describe 'insert manager' do + describe 'new' do + it 'takes an engine' do + Arel::InsertManager.new Table.engine + end + end + + describe 'into' do + it 'takes an engine' do + manager = Arel::InsertManager.new Table.engine + manager.into(Table.new(:users)).should == manager + end + end + + describe 'to_sql' do + it 'converts to sql' do + table = Table.new :users + manager = Arel::InsertManager.new Table.engine + manager.into table + manager.to_sql.should be_like %{ + INSERT INTO "users" + } + end + end + end +end diff --git a/spec/arel/tree_manager.rb b/spec/arel/select_manager.rb similarity index 60% rename from spec/arel/tree_manager.rb rename to spec/arel/select_manager.rb index 92af2f3dcde6b..928db49c5298b 100644 --- a/spec/arel/tree_manager.rb +++ b/spec/arel/select_manager.rb @@ -1,46 +1,46 @@ require 'spec_helper' module Arel - describe 'tree manager' do + describe 'select manager' do describe 'project' do it 'takes strings' do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.project '*' - manager.to_sql.should == %{ + manager.to_sql.should be_like %{ SELECT * - }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + } end it "takes sql literals" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new '*' - manager.to_sql.should == %{ + manager.to_sql.should be_like %{ SELECT * - }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + } end end describe 'take' do it "knows take" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.from(table).project(table['id']) manager.where(table['id'].eq(1)) manager.take 1 - manager.to_sql.should == %{ + manager.to_sql.should be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 1 LIMIT 1 - }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + } end it "chains" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.take(1).should == manager end end @@ -48,19 +48,19 @@ module Arel describe 'where' do it "knows where" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.from(table).project(table['id']) manager.where(table['id'].eq(1)) - manager.to_sql.should == %{ + manager.to_sql.should be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 1 - }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + } end it "chains" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.from(table) manager.project(table['id']).where(table['id'].eq 1).should == manager end @@ -69,18 +69,18 @@ module Arel describe 'from' do it "makes sql" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.from table manager.project table['id'] - manager.to_sql.should == 'SELECT "users"."id" FROM "users"' + manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' end it "chains" do table = Table.new :users - manager = Arel::TreeManager.new Table.engine + manager = Arel::SelectManager.new Table.engine manager.from(table).project(table['id']).should == manager - manager.to_sql.should == 'SELECT "users"."id" FROM "users"' + manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' end end end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index cf309ca8ca0d6..c2bcd3911a630 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -21,10 +21,10 @@ module Arel describe 'project' do it 'can project' do manager = @relation.project '*' - manager.to_sql.should == %{ + manager.to_sql.should be_like %{ SELECT * FROM "users" - }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + } end end @@ -33,11 +33,11 @@ module Arel manager = @relation.where @relation[:id].eq 1 manager.project @relation[:id] manager.should be_kind_of TreeManager - manager.to_sql.should == %{ + manager.to_sql.should be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 1 - }.gsub("\n", '').gsub(/(^\s*|\s*$)/, '').squeeze(' ') + } end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5d3f5a2950c24..797fe0a028a8e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,11 +3,15 @@ require 'fileutils' require 'arel' +require 'support/matchers/be_like' + if adapter = ENV['ADAPTER'] require "support/connections/#{adapter}_connection.rb" end Spec::Runner.configure do |config| + config.include Matchers + if defined?(ActiveRecord::Base) tmp = File.expand_path('../../tmp', __FILE__) From 71803320501604f19dc3312ebcf1bab91d9c5f4c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 15:43:32 -0700 Subject: [PATCH 0596/1492] inserts are starting to take shape --- lib/arel/insert_manager.rb | 3 +++ lib/arel/visitors/to_sql.rb | 11 +++++++++- spec/arel/insert_manager.rb | 43 +++++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index bfd3034df42df..d6c663a9c4af3 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -9,5 +9,8 @@ def into table @head.relation = table self end + + def columns; @head.columns end + def values; @head.values end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7a97b0d4457b5..74b7dd93854e1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -13,7 +13,11 @@ def accept object private def visit_Arel_Nodes_InsertStatement o - "INSERT INTO #{visit o.relation}" + [ + "INSERT INTO #{visit o.relation}", + ("(#{o.columns.map { |x| visit x }.join ', '})" unless o.columns.empty?), + ("VALUES (#{o.values.map { |x| quote visit x }.join ', '})" unless o.values.empty?), + ].compact.join ' ' end def visit_Arel_Nodes_SelectStatement o @@ -42,6 +46,7 @@ def visit_Arel_Nodes_Equality o def visit_Arel_Attributes_Integer o "#{quote_table_name o.relation.name}.#{quote_column_name o.name}" end + alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Integer def visit_Fixnum o; o end alias :visit_String :visit_Fixnum @@ -61,6 +66,10 @@ def visit object DISPATCH[const] = method end + def quote value, column = nil + @connection.quote value, column + end + def quote_table_name name @connection.quote_table_name name end diff --git a/spec/arel/insert_manager.rb b/spec/arel/insert_manager.rb index 8d49556fa9952..fae776a39dbaa 100644 --- a/spec/arel/insert_manager.rb +++ b/spec/arel/insert_manager.rb @@ -13,9 +13,7 @@ module Arel manager = Arel::InsertManager.new Table.engine manager.into(Table.new(:users)).should == manager end - end - describe 'to_sql' do it 'converts to sql' do table = Table.new :users manager = Arel::InsertManager.new Table.engine @@ -25,5 +23,46 @@ module Arel } 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.should be_like %{ + INSERT INTO "users" ("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 << 1 + manager.to_sql.should 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 << 1 + manager.values << "aaron" + manager.columns << table[:id] + manager.columns << table[:name] + manager.to_sql.should be_like %{ + INSERT INTO "users" ("users"."id", "users"."name") VALUES (1, 'aaron') + } + end + end end end From 3eeed18e0cb71f5a56995c2d6a67eff0af618deb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 18:05:38 -0700 Subject: [PATCH 0597/1492] adding a dot visitor to make our lives easier --- lib/arel.rb | 1 + lib/arel/select_manager.rb | 5 ++ lib/arel/visitors/dot.rb | 108 +++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 lib/arel/visitors/dot.rb diff --git a/lib/arel.rb b/lib/arel.rb index 8465d8e658160..e63e2057796e9 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -18,3 +18,4 @@ #### require 'arel/visitors/to_sql' +require 'arel/visitors/dot' diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 6420142fa0d4b..c9484295d87c9 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -25,5 +25,10 @@ def take limit @head.limit = limit self end + + def insert stuff + viz = Visitors::Dot.new + puts viz.accept stuff + end end end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb new file mode 100644 index 0000000000000..6fd272883926c --- /dev/null +++ b/lib/arel/visitors/dot.rb @@ -0,0 +1,108 @@ +module Arel + module Visitors + class Dot + 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 + visit object + to_dot + end + + private + 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_String :visit_Arel_Attribute + alias :visit_Arel_Attributes_Time :visit_Arel_Attribute + + def visit_String o + @node_stack.last.fields << o + end + alias :visit_Time :visit_String + alias :visit_NilClass :visit_String + + def visit_Hash o + o.each_with_index do |(k,v),i| + edge("key_#{i}") { visit k } + edge("value_#{i}") { visit v } + 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 + send "visit_#{o.class.name.gsub('::', '_')}", o + 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 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 << "|#{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 From 9fc70e22f9bf7df8485b90b3d7e4a5c58cb0ebbb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 18:28:38 -0700 Subject: [PATCH 0598/1492] insert manager implements "insert" --- lib/arel/insert_manager.rb | 11 ++++++++ lib/arel/select_manager.rb | 8 +++--- lib/arel/visitors/dot.rb | 22 +++++++++++++--- ...sert_manager.rb => insert_manager_spec.rb} | 26 +++++++++++++++++++ ...lect_manager.rb => select_manager_spec.rb} | 0 5 files changed, 61 insertions(+), 6 deletions(-) rename spec/arel/{insert_manager.rb => insert_manager_spec.rb} (66%) rename spec/arel/{select_manager.rb => select_manager_spec.rb} (100%) diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index d6c663a9c4af3..accabb4377bfb 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -12,5 +12,16 @@ def into table def columns; @head.columns end def values; @head.values end + + def insert fields + return if fields.empty? + + @head.relation ||= fields.first.first.relation + + fields.each do |column, value| + @head.columns << column + @head.values << value + end + end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index c9484295d87c9..1728311d59695 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -26,9 +26,11 @@ def take limit self end - def insert stuff - viz = Visitors::Dot.new - puts viz.accept stuff + # FIXME: this method should go away + def insert values + im = InsertManager.new @engine + im.insert values + raise end end end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 6fd272883926c..4620920484b01 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,6 +28,17 @@ def accept object end private + def visit_Arel_Nodes_SelectCore o + visit_edge o, "froms" + visit_edge o, "projections" + visit_edge o, "wheres" + end + + def visit_Arel_Nodes_SelectStatement o + visit_edge o, "cores" + visit_edge o, "limit" + end + def visit_Arel_Table o visit_edge o, "name" end @@ -47,9 +58,14 @@ def visit_String o alias :visit_NilClass :visit_String def visit_Hash o - o.each_with_index do |(k,v),i| - edge("key_#{i}") { visit k } - edge("value_#{i}") { visit v } + 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 diff --git a/spec/arel/insert_manager.rb b/spec/arel/insert_manager_spec.rb similarity index 66% rename from spec/arel/insert_manager.rb rename to spec/arel/insert_manager_spec.rb index fae776a39dbaa..073c9c30cb78a 100644 --- a/spec/arel/insert_manager.rb +++ b/spec/arel/insert_manager_spec.rb @@ -8,6 +8,32 @@ module Arel end end + describe 'insert' do + 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.should be_like %{ + INSERT INTO "users" ("users"."id", "users"."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.should be_like %{ + INSERT INTO "users" ("users"."id", "users"."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 diff --git a/spec/arel/select_manager.rb b/spec/arel/select_manager_spec.rb similarity index 100% rename from spec/arel/select_manager.rb rename to spec/arel/select_manager_spec.rb From 74a27a0d83ecd7ed4975851ea92ee517a1581faf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 13 Aug 2010 18:55:15 -0700 Subject: [PATCH 0599/1492] inserts have the correct syntax --- lib/arel/select_manager.rb | 2 +- lib/arel/visitors/to_sql.rb | 18 ++++++++++++++---- spec/arel/insert_manager_spec.rb | 28 ++++++++++++++++++++++++---- spec/arel/visitors/to_sql_spec.rb | 17 +++++++++++++++++ 4 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 spec/arel/visitors/to_sql_spec.rb diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 1728311d59695..444ca8f716bc5 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -30,7 +30,7 @@ def take limit def insert values im = InsertManager.new @engine im.insert values - raise + @engine.connection.execute im.to_sql end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 74b7dd93854e1..d47c621f6a61a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -15,8 +15,15 @@ def accept object def visit_Arel_Nodes_InsertStatement o [ "INSERT INTO #{visit o.relation}", - ("(#{o.columns.map { |x| visit x }.join ', '})" unless o.columns.empty?), - ("VALUES (#{o.values.map { |x| quote visit x }.join ', '})" unless o.values.empty?), + + ("(#{o.columns.map { |x| + quote_column_name x.name + }.join ', '})" unless o.columns.empty?), + + ("VALUES (#{o.values.map { |value| + value ? quote(visit(value)) : 'NULL' + }.join ', '})" unless o.values.empty?), + ].compact.join ' ' end @@ -43,12 +50,15 @@ def visit_Arel_Nodes_Equality o "#{visit o.left} = #{visit o.right}" end - def visit_Arel_Attributes_Integer o + def visit_Arel_Attributes_Attribute o "#{quote_table_name o.relation.name}.#{quote_column_name o.name}" end - alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Integer + alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute + alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute + alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute def visit_Fixnum o; o end + alias :visit_Time :visit_Fixnum alias :visit_String :visit_Fixnum alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated diff --git a/spec/arel/insert_manager_spec.rb b/spec/arel/insert_manager_spec.rb index 073c9c30cb78a..14cb749b25224 100644 --- a/spec/arel/insert_manager_spec.rb +++ b/spec/arel/insert_manager_spec.rb @@ -9,13 +9,33 @@ module Arel end describe 'insert' do + it "inserts null" do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + manager.insert [[table[:id], nil]] + manager.to_sql.should 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 + manager.insert [[table[:id], time]] + manager.to_sql.should be_like %{ + INSERT INTO "users" ("id") 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.should be_like %{ - INSERT INTO "users" ("users"."id", "users"."name") VALUES (1, 'aaron') + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end @@ -24,7 +44,7 @@ module Arel manager = Arel::InsertManager.new Table.engine manager.insert [[table[:id], 1], [table[:name], 'aaron']] manager.to_sql.should be_like %{ - INSERT INTO "users" ("users"."id", "users"."name") VALUES (1, 'aaron') + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end @@ -57,7 +77,7 @@ module Arel manager.into table manager.columns << table[:id] manager.to_sql.should be_like %{ - INSERT INTO "users" ("users"."id") + INSERT INTO "users" ("id") } end end @@ -86,7 +106,7 @@ module Arel manager.columns << table[:id] manager.columns << table[:name] manager.to_sql.should be_like %{ - INSERT INTO "users" ("users"."id", "users"."name") VALUES (1, 'aaron') + INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end end diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb new file mode 100644 index 0000000000000..7600d53862882 --- /dev/null +++ b/spec/arel/visitors/to_sql_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +module Arel + module Visitors + describe 'the to_sql visitor' do + before do + @visitor = ToSql.new Table.engine + @attr = Table.new(:users)[:id] + end + + it "should visit visit_Arel_Attributes_Time" do + attr = Attributes::Time.new(@attr.relation, @attr.name, @attr.column) + @visitor.accept attr + end + end + end +end From dddf2d1f095230fde5e8704632df1ecca54e5ca6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 14 Aug 2010 18:29:32 -0700 Subject: [PATCH 0600/1492] basic updates are working --- lib/arel.rb | 1 + lib/arel/nodes.rb | 1 + lib/arel/nodes/update_statement.rb | 12 +++++++++ lib/arel/update_manager.rb | 20 ++++++++++++++ lib/arel/visitors/to_sql.rb | 7 +++++ spec/arel/update_manager_spec.rb | 43 ++++++++++++++++++++++++++++++ 6 files changed, 84 insertions(+) create mode 100644 lib/arel/nodes/update_statement.rb create mode 100644 lib/arel/update_manager.rb create mode 100644 spec/arel/update_manager_spec.rb diff --git a/lib/arel.rb b/lib/arel.rb index e63e2057796e9..5ffc46c934407 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -10,6 +10,7 @@ require 'arel/tree_manager' require 'arel/insert_manager' require 'arel/select_manager' +require 'arel/update_manager' require 'arel/nodes' #### these are deprecated diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index eed9641bbc609..9dea981a0643a 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -3,3 +3,4 @@ require 'arel/nodes/select_core' require 'arel/nodes/select_statement' require 'arel/nodes/insert_statement' +require 'arel/nodes/update_statement' diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb new file mode 100644 index 0000000000000..66996f11a3b2d --- /dev/null +++ b/lib/arel/nodes/update_statement.rb @@ -0,0 +1,12 @@ +module Arel + module Nodes + class UpdateStatement + attr_accessor :relation, :wheres + + def initialize + @relation = nil + @wheres = [] + end + end + end +end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb new file mode 100644 index 0000000000000..3af73d2962a9a --- /dev/null +++ b/lib/arel/update_manager.rb @@ -0,0 +1,20 @@ +module Arel + class UpdateManager < Arel::TreeManager + def initialize engine + super + @head = Nodes::UpdateStatement.new + end + + ### + # UPDATE +table+ + def table table + @head.relation = table + self + end + + def where expr + @head.wheres << expr + self + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d47c621f6a61a..41d1299948bf4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -12,6 +12,13 @@ def accept object end private + def visit_Arel_Nodes_UpdateStatement o + [ + "UPDATE #{visit o.relation}", + ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?) + ].compact.join ' ' + end + def visit_Arel_Nodes_InsertStatement o [ "INSERT INTO #{visit o.relation}", diff --git a/spec/arel/update_manager_spec.rb b/spec/arel/update_manager_spec.rb new file mode 100644 index 0000000000000..9d2346137f34d --- /dev/null +++ b/spec/arel/update_manager_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +module Arel + describe 'update manager' do + describe 'new' do + it 'takes an engine' do + Arel::UpdateManager.new Table.engine + 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.should be_like %{ UPDATE "users" } + end + + it 'chains' do + um = Arel::UpdateManager.new Table.engine + um.table(Table.new(:users)).should == um + 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.should 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)).should == um + end + end + end +end From 6f2230652da18bdc60de2dcbf75f29e7376b918b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 14 Aug 2010 19:12:52 -0700 Subject: [PATCH 0601/1492] update manager is working --- lib/arel/nodes/update_statement.rb | 3 ++- lib/arel/update_manager.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 3 +++ spec/arel/update_manager_spec.rb | 18 ++++++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 66996f11a3b2d..3df54bb3a943d 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -1,11 +1,12 @@ module Arel module Nodes class UpdateStatement - attr_accessor :relation, :wheres + attr_accessor :relation, :wheres, :values def initialize @relation = nil @wheres = [] + @values = nil end end end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 3af73d2962a9a..cc2f9738421f0 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -16,5 +16,10 @@ def where expr @head.wheres << expr self end + + def set values + @head.values = values + self + end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 41d1299948bf4..9a9dd20d52cb8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -15,6 +15,9 @@ def accept object def visit_Arel_Nodes_UpdateStatement o [ "UPDATE #{visit o.relation}", + ("SET #{o.values.map { |column,value| + "#{quote_column_name(column.name)} = #{quote visit value}" + }.join ', '}" if o.values), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?) ].compact.join ' ' end diff --git a/spec/arel/update_manager_spec.rb b/spec/arel/update_manager_spec.rb index 9d2346137f34d..97b497b3776b7 100644 --- a/spec/arel/update_manager_spec.rb +++ b/spec/arel/update_manager_spec.rb @@ -8,6 +8,24 @@ module Arel end end + describe 'set' do + 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.should 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']]).should == um + end + end + describe 'table' do it 'generates an update statement' do um = Arel::UpdateManager.new Table.engine From 703326cdc2e6ad426c09cfbf7983f893552ac845 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 14 Aug 2010 19:14:49 -0700 Subject: [PATCH 0602/1492] defaulting values to a list --- lib/arel/nodes/update_statement.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 3df54bb3a943d..9f069cddb3307 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -6,7 +6,7 @@ class UpdateStatement def initialize @relation = nil @wheres = [] - @values = nil + @values = [] end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9a9dd20d52cb8..4c2a6a10e4698 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -17,7 +17,7 @@ def visit_Arel_Nodes_UpdateStatement o "UPDATE #{visit o.relation}", ("SET #{o.values.map { |column,value| "#{quote_column_name(column.name)} = #{quote visit value}" - }.join ', '}" if o.values), + }.join ', '}" unless o.values.empty?), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?) ].compact.join ' ' end From e1155aa922a04e1cce60a660b4b779bfe3d7d7f5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 14 Aug 2010 19:48:33 -0700 Subject: [PATCH 0603/1492] update is working on the select manager --- lib/arel/select_manager.rb | 9 ++++++ lib/arel/update_manager.rb | 4 +++ lib/arel/visitors/to_sql.rb | 2 +- spec/arel/select_manager_spec.rb | 48 ++++++++++++++++++++++++++++++++ spec/arel/update_manager_spec.rb | 8 ++++++ 5 files changed, 70 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 444ca8f716bc5..7379596abae33 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -26,6 +26,15 @@ def take limit self end + # FIXME: this method should go away + def update values + um = UpdateManager.new @engine + um.table values.first.first.relation + um.set values + um.wheres = @ctx.wheres + @engine.connection.execute um.to_sql + end + # FIXME: this method should go away def insert values im = InsertManager.new @engine diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index cc2f9738421f0..f712103f9804e 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -12,6 +12,10 @@ def table table self end + def wheres= exprs + @head.wheres = exprs + end + def where expr @head.wheres << expr self diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4c2a6a10e4698..5536ba0267d32 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -16,7 +16,7 @@ def visit_Arel_Nodes_UpdateStatement o [ "UPDATE #{visit o.relation}", ("SET #{o.values.map { |column,value| - "#{quote_column_name(column.name)} = #{quote visit value}" + "#{quote_column_name(column.name)} = #{value ? quote(visit(value)) : 'NULL'}" }.join ', '}" unless o.values.empty?), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?) ].compact.join ' ' diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 928db49c5298b..e456cabc16ae1 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -1,7 +1,55 @@ require 'spec_helper' module Arel + class EngineProxy + attr_reader :executed + + def initialize engine + @engine = engine + @executed = [] + 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 execute sql + @executed << sql + end + end + describe 'select manager' do + describe 'update' do + 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 + manager.update(table[:id] => 1) + + engine.executed.last.should be_like %{ + UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 + } + end + + it 'executes an update statement' do + engine = EngineProxy.new Table.engine + table = Table.new :users + manager = Arel::SelectManager.new engine + manager.from table + manager.update(table[:id] => 1) + + engine.executed.last.should be_like %{ + UPDATE "users" SET "id" = 1 + } + end + end + describe 'project' do it 'takes strings' do table = Table.new :users diff --git a/spec/arel/update_manager_spec.rb b/spec/arel/update_manager_spec.rb index 97b497b3776b7..9c3789193e840 100644 --- a/spec/arel/update_manager_spec.rb +++ b/spec/arel/update_manager_spec.rb @@ -9,6 +9,14 @@ module Arel 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.should be_like %{ UPDATE "users" SET "name" = NULL } + end + it 'takes a list of lists' do table = Table.new(:users) um = Arel::UpdateManager.new Table.engine From bd3ecd761e7b52eabf32efe2f5c4ad722423a623 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 14:09:48 -0700 Subject: [PATCH 0604/1492] quoting strings from equality statements, adding to_dot --- lib/arel/tree_manager.rb | 4 ++++ lib/arel/visitors/dot.rb | 8 +++++++- lib/arel/visitors/to_sql.rb | 2 +- spec/arel/visitors/to_sql_spec.rb | 9 +++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 9dd9f27858fa5..d2027bedfa05e 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -7,6 +7,10 @@ def initialize engine @engine = engine end + def to_dot + Visitors::Dot.new.accept @head + end + def to_sql viz = Visitors::ToSql.new @engine viz.accept @head diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 4620920484b01..4b37927685d6a 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -56,6 +56,8 @@ def visit_String o end alias :visit_Time :visit_String alias :visit_NilClass :visit_String + alias :visit_Arel_SqlLiteral :visit_String + alias :visit_Fixnum :visit_String def visit_Hash o o.each_with_index do |pair, i| @@ -105,13 +107,17 @@ def with_node node @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 << "|#{field}" + label << "|#{quote field}" end "#{node.id} [label=\"#{label}\"];" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5536ba0267d32..736c0ce77bbfb 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -57,7 +57,7 @@ def visit_Arel_Table o end def visit_Arel_Nodes_Equality o - "#{visit o.left} = #{visit o.right}" + "#{visit o.left} = #{quote visit o.right}" end def visit_Arel_Attributes_Attribute o diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index 7600d53862882..a266e87d2264d 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -12,6 +12,15 @@ module Visitors attr = Attributes::Time.new(@attr.relation, @attr.name, @attr.column) @visitor.accept attr end + + describe 'Equality' do + it "should escape strings" do + test = @attr.eq 'Aaron Patterson' + @visitor.accept(test).should be_like %{ + "users"."id" = 'Aaron Patterson' + } + end + end end end end From d12580a7ee43dad449a1da208ec60c70c183d7ee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 14:42:20 -0700 Subject: [PATCH 0605/1492] spec:v1:sqlite3 works for running our specs --- Rakefile | 12 ++++++++++++ lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/in.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 4 ++++ 5 files changed, 27 insertions(+) create mode 100644 lib/arel/nodes/in.rb diff --git a/Rakefile b/Rakefile index 40fb0afc07257..a6f80222c85c8 100644 --- a/Rakefile +++ b/Rakefile @@ -41,6 +41,18 @@ else desc "Run specs with the #{adapter} database adapter" task adapter => "set_env_for_#{adapter}" + + namespace :v1 do + Spec::Rake::SpecTask.new(adapter) do |t| + t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] + t.libs << "#{File.dirname(__FILE__)}/spec" + t.warning = true + t.spec_files = FileList['spec/arel/**/*_spec.rb'] + end + + desc "Run specs with the #{adapter} database adapter" + task adapter => "set_env_for_#{adapter}" + end end end diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index fdc64d62e08f6..ff17d6136ca0a 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -4,6 +4,10 @@ class Attribute < Struct.new :relation, :name, :column def eq other Nodes::Equality.new self, other end + + def in other + Nodes::In.new self, other + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 9dea981a0643a..d1868adfa9399 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,4 +1,5 @@ require 'arel/nodes/equality' +require 'arel/nodes/in' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/in.rb b/lib/arel/nodes/in.rb new file mode 100644 index 0000000000000..6ccf37a053f2b --- /dev/null +++ b/lib/arel/nodes/in.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class In < Equality + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 736c0ce77bbfb..bb93876595723 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -56,6 +56,10 @@ def visit_Arel_Table o quote_table_name o.name end + def visit_Arel_Nodes_In o + "#{visit o.left} IN (#{o.right.map { |x| quote visit x }.join ', '})" + end + def visit_Arel_Nodes_Equality o "#{visit o.left} = #{quote visit o.right}" end From 4146538dfd7066eb38fff29e73c739912acad13f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 14:43:18 -0700 Subject: [PATCH 0606/1492] IN seems to work --- spec/arel/attributes/attribute_spec.rb | 16 ++++++++++++++-- spec/arel/select_manager_spec.rb | 2 +- spec/arel/table_spec.rb | 8 ++++---- spec/arel/visitors/to_sql_spec.rb | 9 +++++++++ spec/spec_helper.rb | 2 ++ 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index ef0e0787fa735..e6e6483e64ad4 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -7,11 +7,23 @@ module Attributes it 'should return an equality node' do attribute = Attribute.new nil, nil, nil equality = attribute.eq 1 - equality.left.should == attribute - equality.right.should == 1 + check equality.left.should == attribute + check equality.right.should == 1 equality.should be_kind_of Nodes::Equality 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, nil + node = Nodes::In.new attribute, [1,2,3] + check node.left.should == attribute + check node.right.should == [1, 2, 3] + end + end end describe 'equality' do diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index e456cabc16ae1..038475bf3d3c1 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -127,7 +127,7 @@ def execute sql it "chains" do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.from(table).project(table['id']).should == manager + check manager.from(table).project(table['id']).should == manager manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' end end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index c2bcd3911a630..dbb21d6d69a14 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -9,12 +9,12 @@ module Arel describe 'new' do it 'should accept an engine' do rel = Table.new :users, 'foo' - rel.engine.should == 'foo' + check rel.engine.should == 'foo' end it 'should accept a hash' do rel = Table.new :users, :engine => 'foo' - rel.engine.should == 'foo' + check rel.engine.should == 'foo' end end @@ -44,7 +44,7 @@ module Arel describe 'columns' do it 'returns a list of columns' do columns = @relation.columns - columns.length.should == 2 + check columns.length.should == 2 columns.map { |x| x.name }.sort.should == %w{ name id }.sort end end @@ -61,7 +61,7 @@ module Arel 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.should == 'id' + check column.name.should == 'id' column.should be_kind_of Attributes::Integer end end diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index a266e87d2264d..1d78395b2fcd7 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -13,6 +13,15 @@ module Visitors @visitor.accept attr end + describe "Nodes::In" do + it "should know how to visit" do + node = @attr.in [1, 2, 3] + @visitor.accept(node).should be_like %{ + "users"."id" IN (1, 2, 3) + } + end + end + describe 'Equality' do it "should escape strings" do test = @attr.eq 'Aaron Patterson' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 797fe0a028a8e..12cbe0170e21c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,6 +4,7 @@ require 'arel' require 'support/matchers/be_like' +require 'support/check' if adapter = ENV['ADAPTER'] require "support/connections/#{adapter}_connection.rb" @@ -11,6 +12,7 @@ Spec::Runner.configure do |config| config.include Matchers + config.include Check if defined?(ActiveRecord::Base) tmp = File.expand_path('../../tmp', __FILE__) From 6544a9b36976f8168b98d3a56a3acd952f1a4d18 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 14:56:56 -0700 Subject: [PATCH 0607/1492] adding deprecated crud module for backwards compat --- lib/arel.rb | 2 ++ lib/arel/crud.rb | 21 +++++++++++++++++++++ lib/arel/select_manager.rb | 18 ++---------------- lib/arel/table.rb | 2 ++ 4 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 lib/arel/crud.rb diff --git a/lib/arel.rb b/lib/arel.rb index 5ffc46c934407..a861a01a1c27f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,3 +1,5 @@ +require 'arel/crud' + require 'arel/version' require 'arel/table' require 'arel/attributes' diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb new file mode 100644 index 0000000000000..5b432cb2b65f8 --- /dev/null +++ b/lib/arel/crud.rb @@ -0,0 +1,21 @@ +module Arel + ### + # FIXME hopefully we can remove this + module Crud + # FIXME: this method should go away + def update values + um = UpdateManager.new @engine + um.table values.first.first.relation + um.set values + um.wheres = @ctx.wheres + @engine.connection.execute um.to_sql + end + + # FIXME: this method should go away + def insert values + im = InsertManager.new @engine + im.insert values + @engine.connection.execute im.to_sql + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 7379596abae33..23d85e338612f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -1,5 +1,7 @@ module Arel class SelectManager < Arel::TreeManager + include Arel::Crud + def initialize engine super @head = Nodes::SelectStatement.new @@ -25,21 +27,5 @@ def take limit @head.limit = limit self end - - # FIXME: this method should go away - def update values - um = UpdateManager.new @engine - um.table values.first.first.relation - um.set values - um.wheres = @ctx.wheres - @engine.connection.execute um.to_sql - end - - # FIXME: this method should go away - def insert values - im = InsertManager.new @engine - im.insert values - @engine.connection.execute im.to_sql - end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 4269dfc62fb5f..b629e0755bbf5 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -1,5 +1,7 @@ module Arel class Table + include Arel::Crud + @engine = nil class << self; attr_accessor :engine; end From f47d083c5bbbac1a807954a20a35888024fb4707 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 15:02:37 -0700 Subject: [PATCH 0608/1492] table responds to take --- lib/arel/table.rb | 4 ++++ spec/arel/table_spec.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index b629e0755bbf5..2df20e50e85ca 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -26,6 +26,10 @@ def project thing tm.project thing end + def take amount + tm.take amount + end + def columns @columns ||= @engine.connection.columns(@name, "#{@name} Columns").map do |column| Attributes.for(column).new self, column.name, column diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index dbb21d6d69a14..bc3d6938a7ffc 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -18,6 +18,14 @@ module Arel end end + describe 'take' do + it "should add a limit" do + manager = @relation.take 1 + manager.project '*' + manager.to_sql.should be_like %{ SELECT * FROM "users" LIMIT 1 } + end + end + describe 'project' do it 'can project' do manager = @relation.project '*' From 1aa48994b2d6a317c2692bde873b517877bba80e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 15:46:53 -0700 Subject: [PATCH 0609/1492] sql visitor can deal with TrueClass --- lib/arel/visitors/dot.rb | 8 ++++++++ lib/arel/visitors/to_sql.rb | 1 + spec/arel/visitors/to_sql_spec.rb | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 4b37927685d6a..8a0381976876d 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,6 +28,12 @@ def accept object end private + 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, "froms" visit_edge o, "projections" @@ -50,12 +56,14 @@ def visit_Arel_Attribute o alias :visit_Arel_Attributes_Integer :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 def visit_String o @node_stack.last.fields << o end alias :visit_Time :visit_String alias :visit_NilClass :visit_String + alias :visit_TrueClass :visit_String alias :visit_Arel_SqlLiteral :visit_String alias :visit_Fixnum :visit_String diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index bb93876595723..b0fed4936b612 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -74,6 +74,7 @@ def visit_Arel_Attributes_Attribute o def visit_Fixnum o; o end alias :visit_Time :visit_Fixnum alias :visit_String :visit_Fixnum + alias :visit_TrueClass :visit_Fixnum alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index 1d78395b2fcd7..554b69a5bdbba 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -13,6 +13,10 @@ module Visitors @visitor.accept attr end + it "should visit_TrueClass" do + @visitor.accept(@attr.eq(true)).should be_like %{ "users"."id" = 't' } + end + describe "Nodes::In" do it "should know how to visit" do node = @attr.in [1, 2, 3] From 66243e491d06edf0bff21000adad2837e67c21e2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 16:44:07 -0700 Subject: [PATCH 0610/1492] Rails references Arel::Expression, adding an unused module for now --- lib/arel.rb | 1 + lib/arel/expression.rb | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 lib/arel/expression.rb diff --git a/lib/arel.rb b/lib/arel.rb index a861a01a1c27f..c4e377b5bc796 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -18,6 +18,7 @@ #### these are deprecated require 'arel/sql/engine' require 'arel/sql_literal' +require 'arel/expression' #### require 'arel/visitors/to_sql' diff --git a/lib/arel/expression.rb b/lib/arel/expression.rb new file mode 100644 index 0000000000000..eb2c21bfd32b0 --- /dev/null +++ b/lib/arel/expression.rb @@ -0,0 +1,4 @@ +module Arel + module Expression + end +end From ae547dc139179720a814ae21f43f3e0aaad97c5c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 17:26:12 -0700 Subject: [PATCH 0611/1492] OR nodes are somewhat working --- lib/arel/nodes.rb | 3 +++ lib/arel/nodes/binary.rb | 24 ++++++++++++++++++++++++ lib/arel/nodes/equality.rb | 13 +------------ lib/arel/nodes/or.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/nodes/equality_spec.rb | 16 ++++++++++++++++ spec/arel/nodes/or_spec.rb | 20 ++++++++++++++++++++ spec/arel/visitors/to_sql_spec.rb | 7 +++++++ 8 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 lib/arel/nodes/binary.rb create mode 100644 lib/arel/nodes/or.rb create mode 100644 spec/arel/nodes/equality_spec.rb create mode 100644 spec/arel/nodes/or_spec.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index d1868adfa9399..12759a462f044 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,4 +1,7 @@ +require 'arel/nodes/binary' require 'arel/nodes/equality' +require 'arel/nodes/or' + require 'arel/nodes/in' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb new file mode 100644 index 0000000000000..44204d91e0767 --- /dev/null +++ b/lib/arel/nodes/binary.rb @@ -0,0 +1,24 @@ +module Arel + module Nodes + class Binary + attr_accessor :left, :right + + def initialize left, right + @left = left + @right = right + end + + def or right + Nodes::Or.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. + def to_sql + viz = Visitors::ToSql.new left.relation.engine + viz.accept self + end + end + end +end diff --git a/lib/arel/nodes/equality.rb b/lib/arel/nodes/equality.rb index d778380054c6a..b8d8281434661 100644 --- a/lib/arel/nodes/equality.rb +++ b/lib/arel/nodes/equality.rb @@ -1,17 +1,6 @@ module Arel module Nodes - class Equality - attr_accessor :left, :right - - def initialize left, right - @left = left - @right = right - end - - def to_sql - viz = Visitors::ToSql.new left.relation.engine - viz.accept self - end + class Equality < Arel::Nodes::Binary end end end diff --git a/lib/arel/nodes/or.rb b/lib/arel/nodes/or.rb new file mode 100644 index 0000000000000..bdf7f6d9b3692 --- /dev/null +++ b/lib/arel/nodes/or.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Or < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b0fed4936b612..9dc7696ad8c9c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -60,6 +60,10 @@ def visit_Arel_Nodes_In o "#{visit o.left} IN (#{o.right.map { |x| quote visit x }.join ', '})" end + def visit_Arel_Nodes_Or o + "#{visit o.left} OR #{visit o.right}" + end + def visit_Arel_Nodes_Equality o "#{visit o.left} = #{quote visit o.right}" end diff --git a/spec/arel/nodes/equality_spec.rb b/spec/arel/nodes/equality_spec.rb new file mode 100644 index 0000000000000..b74af3a039dfe --- /dev/null +++ b/spec/arel/nodes/equality_spec.rb @@ -0,0 +1,16 @@ +module Arel + module Nodes + describe 'equality' 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 + check node.left.should == left + check node.right.should == right + end + end + end + end +end diff --git a/spec/arel/nodes/or_spec.rb b/spec/arel/nodes/or_spec.rb new file mode 100644 index 0000000000000..e855b9245322d --- /dev/null +++ b/spec/arel/nodes/or_spec.rb @@ -0,0 +1,20 @@ +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 + check node.left.should == left + check node.right.should == right + + oror = node.or(right) + check oror.left == node + check oror.right == right + end + end + end + end +end diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index 554b69a5bdbba..b70c392630eaf 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,13 @@ module Visitors @attr = Table.new(:users)[:id] end + it "should visit_Arel_Nodes_Or" do + node = Nodes::Or.new @attr.eq(10), @attr.eq(11) + @visitor.accept(node).should 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, @attr.column) @visitor.accept attr From 8d46360cbd5e5ae650ac6d735f5a44f0f57b7aee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 17:27:16 -0700 Subject: [PATCH 0612/1492] adding comment to myself --- lib/arel/nodes/binary.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 44204d91e0767..4eccba276554a 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -15,6 +15,8 @@ def or right # 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 viz = Visitors::ToSql.new left.relation.engine viz.accept self From 9daa0bbe153f1a85319c97756aebcda82bac7bdd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 17:44:48 -0700 Subject: [PATCH 0613/1492] adding some activerecord compatibility --- lib/arel.rb | 1 + lib/arel/compatibility/wheres.rb | 29 +++++++++++++++++++++++++++ lib/arel/select_manager.rb | 4 ++++ spec/arel/activerecord_compat_spec.rb | 18 +++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 lib/arel/compatibility/wheres.rb create mode 100644 spec/arel/activerecord_compat_spec.rb diff --git a/lib/arel.rb b/lib/arel.rb index c4e377b5bc796..acb270728f81e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -3,6 +3,7 @@ require 'arel/version' require 'arel/table' require 'arel/attributes' +require 'arel/compatibility/wheres' #### these are deprecated # The Arel::Relation constant is referenced in Rails diff --git a/lib/arel/compatibility/wheres.rb b/lib/arel/compatibility/wheres.rb new file mode 100644 index 0000000000000..eeb7a2fa38e2b --- /dev/null +++ b/lib/arel/compatibility/wheres.rb @@ -0,0 +1,29 @@ +module Arel + module Compatibility # :nodoc: + class Wheres # :nodoc: + include Enumerable + + module Value # :nodoc: + attr_accessor :visitor + def value + visitor.accept self + 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 diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 23d85e338612f..f278465c51893 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -23,6 +23,10 @@ def where expr self end + def wheres + Compatibility::Wheres.new @engine, @ctx.wheres + end + def take limit @head.limit = limit self diff --git a/spec/arel/activerecord_compat_spec.rb b/spec/arel/activerecord_compat_spec.rb new file mode 100644 index 0000000000000..a7eeb7e5ee7e3 --- /dev/null +++ b/spec/arel/activerecord_compat_spec.rb @@ -0,0 +1,18 @@ +require 'spec_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' + + check manager.wheres.map { |x| + x.value + }.join(', ').should == "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'" + end + end + end +end From 466e3925b51aaf42c5bd02fbd566d371349a10b2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 16 Aug 2010 17:46:41 -0700 Subject: [PATCH 0614/1492] defaulting to Table.engine for now --- lib/arel/nodes/binary.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 4eccba276554a..fdfcab2d3f29b 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -18,7 +18,7 @@ def or right # # Maybe we should just use `Table.engine`? :'( def to_sql - viz = Visitors::ToSql.new left.relation.engine + viz = Visitors::ToSql.new Table.engine viz.accept self end end From 57d65bde636855872dc29a9d778a38109f4e34ee Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 16 Aug 2010 22:29:35 -0400 Subject: [PATCH 0615/1492] dot visitor supports symbols --- lib/arel/visitors/dot.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 8a0381976876d..9927b03969b24 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -66,6 +66,7 @@ def visit_String o alias :visit_TrueClass :visit_String alias :visit_Arel_SqlLiteral :visit_String alias :visit_Fixnum :visit_String + alias :visit_Symbol :visit_String def visit_Hash o o.each_with_index do |pair, i| From e6f12b13d7de1ab56426b86eec3a1c820df4aa41 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 16 Aug 2010 22:34:07 -0400 Subject: [PATCH 0616/1492] dot visitor supports Arel::Nodes::Equality --- lib/arel/visitors/dot.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 9927b03969b24..54551f06f7ae6 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -58,6 +58,11 @@ def visit_Arel_Attribute o alias :visit_Arel_Attributes_Time :visit_Arel_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute + def visit_Arel_Nodes_Equality o + visit_edge o, "left" + visit_edge o, "right" + end + def visit_String o @node_stack.last.fields << o end From f8376607cd438a48f5838204d2ec9d0747769369 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 16 Aug 2010 22:59:52 -0400 Subject: [PATCH 0617/1492] dot visitor supports Arel::Nodes::UpdateStatement --- lib/arel/visitors/dot.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 54551f06f7ae6..ec2db0814fbf1 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -45,6 +45,12 @@ def visit_Arel_Nodes_SelectStatement o visit_edge o, "limit" 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 From e9a22ec1afa62ed6be75427315a3a650fc41e629 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 Aug 2010 09:52:16 -0700 Subject: [PATCH 0618/1492] fixing update support --- lib/arel/crud.rb | 7 ++++++- lib/arel/nodes.rb | 1 + lib/arel/nodes/unqualified_column.rb | 13 +++++++++++++ lib/arel/update_manager.rb | 11 ++++++++++- lib/arel/visitors/to_sql.rb | 12 ++++++++---- spec/arel/select_manager_spec.rb | 10 ++++++++++ spec/arel/update_manager_spec.rb | 8 ++++++++ 7 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 lib/arel/nodes/unqualified_column.rb diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 5b432cb2b65f8..7f78acef84a41 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -5,7 +5,12 @@ module Crud # FIXME: this method should go away def update values um = UpdateManager.new @engine - um.table values.first.first.relation + + if String === values + um.table @ctx.froms.last + else + um.table values.first.first.relation + end um.set values um.wheres = @ctx.wheres @engine.connection.execute um.to_sql diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 12759a462f044..bf144ecaf82e9 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -8,3 +8,4 @@ require 'arel/nodes/select_statement' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' +require 'arel/nodes/unqualified_column' diff --git a/lib/arel/nodes/unqualified_column.rb b/lib/arel/nodes/unqualified_column.rb new file mode 100644 index 0000000000000..b86b55307400b --- /dev/null +++ b/lib/arel/nodes/unqualified_column.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class UnqualifiedColumn + def initialize attribute + @attribute = attribute + end + + def name + @attribute.name + end + end + end +end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index f712103f9804e..cd4342529bb49 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -22,7 +22,16 @@ def where expr end def set values - @head.values = values + if String === values + @head.values = [values] + else + @head.values = values.map { |column,value| + Nodes::Equality.new( + Nodes::UnqualifiedColumn.new(column), + value + ) + } + end self end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9dc7696ad8c9c..fd467495aec5f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -15,9 +15,7 @@ def accept object def visit_Arel_Nodes_UpdateStatement o [ "UPDATE #{visit o.relation}", - ("SET #{o.values.map { |column,value| - "#{quote_column_name(column.name)} = #{value ? quote(visit(value)) : 'NULL'}" - }.join ', '}" unless o.values.empty?), + ("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?) ].compact.join ' ' end @@ -65,7 +63,13 @@ def visit_Arel_Nodes_Or o end def visit_Arel_Nodes_Equality o - "#{visit o.left} = #{quote visit o.right}" + right = o.right + right = right ? quote(visit(right)) : 'NULL' + "#{visit o.left} = #{right}" + end + + def visit_Arel_Nodes_UnqualifiedColumn o + "#{quote_column_name o.name}" end def visit_Arel_Attributes_Attribute o diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 038475bf3d3c1..a728366e0e42f 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -24,6 +24,16 @@ def execute sql describe 'select manager' do describe 'update' do + it 'takes a string' do + engine = EngineProxy.new Table.engine + table = Table.new :users + manager = Arel::SelectManager.new engine + manager.from table + manager.update('foo = bar') + + engine.executed.last.should be_like %{ UPDATE "users" SET foo = bar } + end + it 'copies where clauses' do engine = EngineProxy.new Table.engine table = Table.new :users diff --git a/spec/arel/update_manager_spec.rb b/spec/arel/update_manager_spec.rb index 9c3789193e840..8c4c4f93b828e 100644 --- a/spec/arel/update_manager_spec.rb +++ b/spec/arel/update_manager_spec.rb @@ -17,6 +17,14 @@ module Arel um.to_sql.should 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 "foo = bar" + um.to_sql.should 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 From 0403efa4c6ad926a61dd0d134d63d962238e2c4f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 Aug 2010 11:32:44 -0700 Subject: [PATCH 0619/1492] delete manager added --- lib/arel.rb | 1 + lib/arel/crud.rb | 7 +++++ lib/arel/delete_manager.rb | 22 ++++++++++++++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/delete_statement.rb | 12 +++++++++ lib/arel/visitors/to_sql.rb | 7 +++++ spec/arel/delete_manager_spec.rb | 42 ++++++++++++++++++++++++++++++ spec/arel/select_manager_spec.rb | 25 ++++++++++++++++++ 8 files changed, 117 insertions(+) create mode 100644 lib/arel/delete_manager.rb create mode 100644 lib/arel/nodes/delete_statement.rb create mode 100644 spec/arel/delete_manager_spec.rb diff --git a/lib/arel.rb b/lib/arel.rb index acb270728f81e..0d03d0a4bb8a7 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -14,6 +14,7 @@ require 'arel/insert_manager' require 'arel/select_manager' require 'arel/update_manager' +require 'arel/delete_manager' require 'arel/nodes' #### these are deprecated diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 7f78acef84a41..6861ff016c34f 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -22,5 +22,12 @@ def insert values im.insert values @engine.connection.execute im.to_sql end + + def delete + dm = DeleteManager.new @engine + dm.wheres = @ctx.wheres + dm.from @ctx.froms.last + @engine.connection.execute dm.to_sql + end end end diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb new file mode 100644 index 0000000000000..4759f116f1919 --- /dev/null +++ b/lib/arel/delete_manager.rb @@ -0,0 +1,22 @@ +module Arel + class DeleteManager < Arel::TreeManager + def initialize engine + super + @head = Nodes::DeleteStatement.new + end + + def from relation + @head.relation = relation + self + end + + def where expression + @head.wheres << expression + self + end + + def wheres= list + @head.wheres = list + end + end +end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index bf144ecaf82e9..4d6db39aeca60 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -8,4 +8,5 @@ require 'arel/nodes/select_statement' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' +require 'arel/nodes/delete_statement' require 'arel/nodes/unqualified_column' diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb new file mode 100644 index 0000000000000..54bf513c2b172 --- /dev/null +++ b/lib/arel/nodes/delete_statement.rb @@ -0,0 +1,12 @@ +module Arel + module Nodes + class DeleteStatement + attr_accessor :relation, :wheres + + def initialize + @from = nil + @wheres = [] + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index fd467495aec5f..0e5998c5739ed 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -12,6 +12,13 @@ def accept object 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 + def visit_Arel_Nodes_UpdateStatement o [ "UPDATE #{visit o.relation}", diff --git a/spec/arel/delete_manager_spec.rb b/spec/arel/delete_manager_spec.rb new file mode 100644 index 0000000000000..88d4df061aa8f --- /dev/null +++ b/spec/arel/delete_manager_spec.rb @@ -0,0 +1,42 @@ +require 'spec_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.should be_like %{ DELETE FROM "users" } + end + + it 'chains' do + table = Table.new(:users) + dm = Arel::DeleteManager.new Table.engine + check dm.from(table).should == 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.should be_like %{ DELETE FROM "users" WHERE "users"."id" = 10} + end + + it 'chains' do + table = Table.new(:users) + dm = Arel::DeleteManager.new Table.engine + check dm.where(table[:id].eq(10)).should == dm + end + end + end +end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index a728366e0e42f..01d1b350045b8 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -23,6 +23,31 @@ def execute sql end describe 'select manager' do + describe 'delete' do + it "copies from" do + engine = EngineProxy.new Table.engine + table = Table.new :users + manager = Arel::SelectManager.new engine + manager.from table + manager.delete + + engine.executed.last.should 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 + manager.delete + + engine.executed.last.should be_like %{ + DELETE FROM "users" WHERE "users"."id" = 10 + } + end + end + describe 'update' do it 'takes a string' do engine = EngineProxy.new Table.engine From 6b851c686faefe54efce0857f8b7b7b0c04bb673 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 Aug 2010 16:32:32 -0700 Subject: [PATCH 0620/1492] joins can be created --- lib/arel/nodes.rb | 3 +++ lib/arel/nodes/inner_join.rb | 13 +++++++++++++ lib/arel/nodes/on.rb | 11 +++++++++++ lib/arel/nodes/table_alias.rb | 20 ++++++++++++++++++++ lib/arel/select_manager.rb | 9 +++++++++ lib/arel/table.rb | 13 ++++++++++++- lib/arel/visitors/to_sql.rb | 25 +++++++++++++++++++------ spec/arel/select_manager_spec.rb | 22 ++++++++++++++++++++-- spec/arel/table_spec.rb | 12 ++++++++++++ spec/arel/update_manager_spec.rb | 2 +- 10 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 lib/arel/nodes/inner_join.rb create mode 100644 lib/arel/nodes/on.rb create mode 100644 lib/arel/nodes/table_alias.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 4d6db39aeca60..7183a60591d1c 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -10,3 +10,6 @@ require 'arel/nodes/update_statement' require 'arel/nodes/delete_statement' require 'arel/nodes/unqualified_column' +require 'arel/nodes/table_alias' +require 'arel/nodes/inner_join' +require 'arel/nodes/on' diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb new file mode 100644 index 0000000000000..a39ded9f1cdbd --- /dev/null +++ b/lib/arel/nodes/inner_join.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class InnerJoin + attr_accessor :left, :right, :constraint + + def initialize left, right, constraint + @left = left + @right = right + @constraint = constraint + end + end + end +end diff --git a/lib/arel/nodes/on.rb b/lib/arel/nodes/on.rb new file mode 100644 index 0000000000000..4cc76b70dbcfc --- /dev/null +++ b/lib/arel/nodes/on.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class On + attr_accessor :expr + + def initialize expr + @expr = expr + end + end + end +end diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb new file mode 100644 index 0000000000000..4f1d70ee54ee5 --- /dev/null +++ b/lib/arel/nodes/table_alias.rb @@ -0,0 +1,20 @@ +module Arel + module Nodes + class TableAlias + attr_reader :name, :relation, :columns + + def initialize name, relation + @name = name + @relation = relation + @columns = relation.columns.map { |column| + column.dup.tap { |col| col.relation = self } + } + end + + def [] name + name = name.to_s + columns.find { |column| column.name == name } + end + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f278465c51893..533911e635ddb 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -8,12 +8,21 @@ def initialize engine @ctx = @head.cores.last end + def on expr + @ctx.froms.last.constraint = Nodes::On.new(expr) + self + end + def from table @ctx.froms << table self end def project projection + projection = ::String == projection.class ? + Nodes::SqlLiteral.new(projection) : + projection + @ctx.projections << projection self end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 2df20e50e85ca..5a66db06279ae 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -5,19 +5,30 @@ class Table @engine = nil class << self; attr_accessor :engine; end - attr_reader :name, :engine + attr_reader :name, :engine, :aliases def initialize name, engine = Table.engine @name = name @engine = engine @engine = engine[:engine] if Hash === engine @columns = nil + @aliases = [] + end + + def alias + Nodes::TableAlias.new("#{name}_2", self).tap do |node| + @aliases << node + end end def tm SelectManager.new(@engine).from(self) end + def join relation + SelectManager.new(@engine).from(Nodes::InnerJoin.new(self, relation, nil)) + end + def where condition tm.where condition end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0e5998c5739ed..3b0a0dc5df902 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -36,7 +36,7 @@ def visit_Arel_Nodes_InsertStatement o }.join ', '})" unless o.columns.empty?), ("VALUES (#{o.values.map { |value| - value ? quote(visit(value)) : 'NULL' + value ? visit(value) : 'NULL' }.join ', '})" unless o.values.empty?), ].compact.join ' ' @@ -57,12 +57,24 @@ def visit_Arel_Nodes_SelectCore o ].compact.join ' ' end + def visit_Arel_Nodes_TableAlias o + "#{visit o.relation} #{quote_table_name o.name}" + end + + def visit_Arel_Nodes_InnerJoin o + "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint}" + end + + def visit_Arel_Nodes_On o + "ON #{visit o.expr}" + end + def visit_Arel_Table o quote_table_name o.name end def visit_Arel_Nodes_In o - "#{visit o.left} IN (#{o.right.map { |x| quote visit x }.join ', '})" + "#{visit o.left} IN (#{o.right.map { |x| visit x }.join ', '})" end def visit_Arel_Nodes_Or o @@ -71,7 +83,7 @@ def visit_Arel_Nodes_Or o def visit_Arel_Nodes_Equality o right = o.right - right = right ? quote(visit(right)) : 'NULL' + right = right ? visit(right) : 'NULL' "#{visit o.left} = #{right}" end @@ -87,12 +99,13 @@ def visit_Arel_Attributes_Attribute o alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute def visit_Fixnum o; o end - alias :visit_Time :visit_Fixnum - alias :visit_String :visit_Fixnum - alias :visit_TrueClass :visit_Fixnum alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated + def visit_TrueClass o; quote(o) end + def visit_String o; quote(o) end + def visit_Time o; quote(o) end + DISPATCH = {} def visit object send "visit_#{object.class.name.gsub('::', '_')}", object diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 01d1b350045b8..74e2db408b7cf 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -54,7 +54,7 @@ def execute sql table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - manager.update('foo = bar') + manager.update(SqlLiteral.new('foo = bar')) engine.executed.last.should be_like %{ UPDATE "users" SET foo = bar } end @@ -89,7 +89,7 @@ def execute sql it 'takes strings' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.project '*' + manager.project Nodes::SqlLiteral.new('*') manager.to_sql.should be_like %{ SELECT * } @@ -149,6 +149,24 @@ def execute sql 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('*') + check mgr.on(predicate).should == mgr + + mgr.to_sql.should 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 diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index bc3d6938a7ffc..58ccc9e7be278 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,6 +6,18 @@ module Arel @relation = Table.new(:users) end + describe 'alias' do + it 'should create a node that proxies to a table' do + check @relation.aliases.should == [] + + node = @relation.alias + check @relation.aliases.should == [node] + check node.name.should == 'users_2' + check node[:id].relation.should == node + check node[:id].relation.should != node + end + end + describe 'new' do it 'should accept an engine' do rel = Table.new :users, 'foo' diff --git a/spec/arel/update_manager_spec.rb b/spec/arel/update_manager_spec.rb index 8c4c4f93b828e..e70ae2cef3d00 100644 --- a/spec/arel/update_manager_spec.rb +++ b/spec/arel/update_manager_spec.rb @@ -21,7 +21,7 @@ module Arel table = Table.new(:users) um = Arel::UpdateManager.new Table.engine um.table table - um.set "foo = bar" + um.set Nodes::SqlLiteral.new "foo = bar" um.to_sql.should be_like %{ UPDATE "users" SET foo = bar } end From 788f33fb59af40e8cb29a233a8d6be9941b52ea7 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 16 Aug 2010 23:33:41 -0400 Subject: [PATCH 0621/1492] TreeManager classes deep-copy their statements. --- lib/arel/tree_manager.rb | 5 +++++ spec/arel/insert_manager_spec.rb | 11 +++++++++++ spec/arel/select_manager_spec.rb | 11 +++++++++++ spec/arel/update_manager_spec.rb | 12 ++++++++++++ spec/spec_helper.rb | 1 + spec/support/shared/tree_manager_shared.rb | 9 +++++++++ 6 files changed, 49 insertions(+) create mode 100644 spec/support/shared/tree_manager_shared.rb diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index d2027bedfa05e..24df5e0c09171 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -15,5 +15,10 @@ def to_sql viz = Visitors::ToSql.new @engine viz.accept @head end + + def initialize_copy other + super + @head = @head.clone + end end end diff --git a/spec/arel/insert_manager_spec.rb b/spec/arel/insert_manager_spec.rb index 14cb749b25224..ed0725e79df25 100644 --- a/spec/arel/insert_manager_spec.rb +++ b/spec/arel/insert_manager_spec.rb @@ -110,5 +110,16 @@ module Arel } end end + + describe "TreeManager" do + subject do + table = Table.new(:users) + Arel::InsertManager.new(Table.engine).tap do |manager| + manager.insert [[table[:id], nil]] + end + end + + it_should_behave_like "TreeManager" + end end end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 01d1b350045b8..3984bec3fd79c 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -166,5 +166,16 @@ def execute sql manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' end end + + describe "TreeManager" do + subject do + table = Table.new :users + Arel::SelectManager.new(Table.engine).tap do |manager| + manager.from(table).project(table['id']) + end + end + + it_should_behave_like "TreeManager" + end end end diff --git a/spec/arel/update_manager_spec.rb b/spec/arel/update_manager_spec.rb index 8c4c4f93b828e..4aeb15bb14e76 100644 --- a/spec/arel/update_manager_spec.rb +++ b/spec/arel/update_manager_spec.rb @@ -73,5 +73,17 @@ module Arel um.where(table[:id].eq(1)).should == um end end + + describe "TreeManager" do + subject do + table = Table.new :users + Arel::UpdateManager.new(Table.engine).tap do |manager| + manager.table table + manager.where table[:id].eq(1) + end + end + + it_should_behave_like "TreeManager" + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 12cbe0170e21c..4ea3071515017 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,6 +5,7 @@ require 'support/matchers/be_like' require 'support/check' +Dir[File.join(File.dirname(__FILE__),'support/shared/*')].each { |f| require f } if adapter = ENV['ADAPTER'] require "support/connections/#{adapter}_connection.rb" diff --git a/spec/support/shared/tree_manager_shared.rb b/spec/support/shared/tree_manager_shared.rb new file mode 100644 index 0000000000000..48b561e1fb9aa --- /dev/null +++ b/spec/support/shared/tree_manager_shared.rb @@ -0,0 +1,9 @@ +shared_examples_for "TreeManager" do + describe "clone" do + it "clones the insert statement" do + subject.instance_variable_get("@head").should_receive(:clone).and_return(:foo) # TODO: ick. + dolly = subject.clone + dolly.instance_variable_get("@head").should == :foo + end + end +end From 02ab2b37d7fdd823cf3aaac66052437dde36daa3 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 16 Aug 2010 23:59:18 -0400 Subject: [PATCH 0622/1492] Statement nodes deep-copy AST nodes --- lib/arel/nodes/insert_statement.rb | 6 ++++++ lib/arel/nodes/select_statement.rb | 5 +++++ lib/arel/nodes/update_statement.rb | 6 ++++++ spec/arel/nodes/insert_statement_spec.rb | 22 ++++++++++++++++++++++ spec/arel/nodes/select_statement_spec.rb | 16 ++++++++++++++++ spec/arel/nodes/update_statement_spec.rb | 22 ++++++++++++++++++++++ 6 files changed, 77 insertions(+) create mode 100644 spec/arel/nodes/insert_statement_spec.rb create mode 100644 spec/arel/nodes/select_statement_spec.rb create mode 100644 spec/arel/nodes/update_statement_spec.rb diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index ed601aa841e95..8c6e1234d0bf6 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -8,6 +8,12 @@ def initialize @columns = [] @values = [] end + + def initialize_copy other + super + @columns = @columns.map { |o| o.clone } + @values = @values.map { |o| o.clone } + end end end end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 122f6275fe07a..50fef776f60f3 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -8,6 +8,11 @@ def initialize cores = [SelectCore.new] @cores = cores @limit = nil end + + def initialize_copy other + super + @cores = @cores.map { |o| o.clone } + end end end end diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 9f069cddb3307..27e3e4e6ac25d 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -8,6 +8,12 @@ def initialize @wheres = [] @values = [] end + + def initialize_copy other + super + @wheres = @wheres.map { |o| o.clone } + @values = @values.map { |o| o.clone } + end end end end diff --git a/spec/arel/nodes/insert_statement_spec.rb b/spec/arel/nodes/insert_statement_spec.rb new file mode 100644 index 0000000000000..d8b02b6703f11 --- /dev/null +++ b/spec/arel/nodes/insert_statement_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Arel::Nodes::InsertStatement do + describe "clone" do + it "clones cores" do + statement = Arel::Nodes::InsertStatement.new + statement.columns = %w[a b c] + statement.values = %w[x y z] + + statement.columns.each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + statement.values.each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + + dolly = statement.clone + dolly.columns.should == %w[a0 b1 c2] + dolly.values.should == %w[x0 y1 z2] + end + end +end diff --git a/spec/arel/nodes/select_statement_spec.rb b/spec/arel/nodes/select_statement_spec.rb new file mode 100644 index 0000000000000..04b850823cfd4 --- /dev/null +++ b/spec/arel/nodes/select_statement_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe Arel::Nodes::SelectStatement do + describe "clone" do + it "clones cores" do + statement = Arel::Nodes::SelectStatement.new %w[a b c] + + statement.cores.each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + + dolly = statement.clone + dolly.cores.should == %w[a0 b1 c2] + end + end +end diff --git a/spec/arel/nodes/update_statement_spec.rb b/spec/arel/nodes/update_statement_spec.rb new file mode 100644 index 0000000000000..438eaf1dc2540 --- /dev/null +++ b/spec/arel/nodes/update_statement_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Arel::Nodes::UpdateStatement do + describe "clone" do + it "clones cores" do + statement = Arel::Nodes::UpdateStatement.new + statement.wheres = %w[a b c] + statement.values = %w[x y z] + + statement.wheres.each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + statement.values.each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + + dolly = statement.clone + dolly.wheres.should == %w[a0 b1 c2] + dolly.values.should == %w[x0 y1 z2] + end + end +end From 6b056ef108526de90f9537e2a5f663a9a2b33409 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 19 Aug 2010 01:30:36 -0400 Subject: [PATCH 0623/1492] SelectCore deep copies attributes --- lib/arel/nodes/select_core.rb | 7 +++++++ spec/arel/nodes/select_core_spec.rb | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 spec/arel/nodes/select_core_spec.rb diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 39145de69733b..7ebdab315dafe 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -8,6 +8,13 @@ def initialize @projections = [] @wheres = [] end + + def initialize_copy other + super + @froms = @froms.map { |o| o.clone } + @projections = @projections.map { |o| o.clone } + @wheres = @wheres.map { |o| o.clone } + end end end end diff --git a/spec/arel/nodes/select_core_spec.rb b/spec/arel/nodes/select_core_spec.rb new file mode 100644 index 0000000000000..cf717a39049d6 --- /dev/null +++ b/spec/arel/nodes/select_core_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe Arel::Nodes::SelectCore do + describe "#clone" do + it "clones froms, projections and wheres" do + core = Arel::Nodes::SelectCore.new + core.instance_variable_set "@froms", %w[a b c] + core.instance_variable_set "@projections", %w[d e f] + core.instance_variable_set "@wheres", %w[g h i] + + [:froms, :projections, :wheres].each do |array_attr| + core.send(array_attr).each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + end + + dolly = core.clone + dolly.froms.should == %w[a0 b1 c2] + dolly.projections.should == %w[d0 e1 f2] + dolly.wheres.should == %w[g0 h1 i2] + end + end +end From 91fe0cd99cc9c8aa9e73ebd51ae478f80076ecea Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 19 Aug 2010 01:30:21 -0400 Subject: [PATCH 0624/1492] cleaning up describe/it block names --- spec/arel/nodes/insert_statement_spec.rb | 4 ++-- spec/arel/nodes/select_statement_spec.rb | 2 +- spec/arel/nodes/update_statement_spec.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/arel/nodes/insert_statement_spec.rb b/spec/arel/nodes/insert_statement_spec.rb index d8b02b6703f11..644e3fb192c25 100644 --- a/spec/arel/nodes/insert_statement_spec.rb +++ b/spec/arel/nodes/insert_statement_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Arel::Nodes::InsertStatement do - describe "clone" do - it "clones cores" 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] diff --git a/spec/arel/nodes/select_statement_spec.rb b/spec/arel/nodes/select_statement_spec.rb index 04b850823cfd4..a024710c78d8d 100644 --- a/spec/arel/nodes/select_statement_spec.rb +++ b/spec/arel/nodes/select_statement_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Arel::Nodes::SelectStatement do - describe "clone" do + describe "#clone" do it "clones cores" do statement = Arel::Nodes::SelectStatement.new %w[a b c] diff --git a/spec/arel/nodes/update_statement_spec.rb b/spec/arel/nodes/update_statement_spec.rb index 438eaf1dc2540..8cbca1fd73b01 100644 --- a/spec/arel/nodes/update_statement_spec.rb +++ b/spec/arel/nodes/update_statement_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Arel::Nodes::UpdateStatement do - describe "clone" do - it "clones cores" 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] From 06c92a8557f5171704a121d0f4412e4c1e9a9c2b Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 19 Aug 2010 02:00:28 -0400 Subject: [PATCH 0625/1492] DeleteStatement deep copy --- lib/arel/nodes/delete_statement.rb | 5 +++++ spec/arel/nodes/delete_statement_spec.rb | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 spec/arel/nodes/delete_statement_spec.rb diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index 54bf513c2b172..b65177af056f4 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -7,6 +7,11 @@ def initialize @from = nil @wheres = [] end + + def initialize_copy other + super + @wheres = @wheres.map { |o| o.clone } + end end end end diff --git a/spec/arel/nodes/delete_statement_spec.rb b/spec/arel/nodes/delete_statement_spec.rb new file mode 100644 index 0000000000000..dd43b70d3508a --- /dev/null +++ b/spec/arel/nodes/delete_statement_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Arel::Nodes::SelectStatement do + describe "#clone" do + it "clones where" do + statement = Arel::Nodes::DeleteStatement.new + statement.wheres = %w[a b c] + + statement.wheres.each_with_index do |o, j| + o.should_receive(:clone).and_return("#{o}#{j}") + end + + dolly = statement.clone + dolly.wheres.should == %w[a0 b1 c2] + end + end +end From 6451188abf647d6aa855d22db8d2d62a2b2c4542 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 19 Aug 2010 10:37:50 -0700 Subject: [PATCH 0626/1492] adding outer joins --- lib/arel/crud.rb | 1 + lib/arel/nodes.rb | 2 ++ lib/arel/nodes/inner_join.rb | 9 +-------- lib/arel/nodes/join.rb | 13 +++++++++++++ lib/arel/nodes/outer_join.rb | 6 ++++++ lib/arel/select_manager.rb | 13 +++++++++---- lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/select_manager_spec.rb | 24 ++++++++++++++++++++++++ spec/arel/table_spec.rb | 4 ++-- 9 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 lib/arel/nodes/join.rb create mode 100644 lib/arel/nodes/outer_join.rb diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 6861ff016c34f..2bf5f85823007 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -7,6 +7,7 @@ def update values um = UpdateManager.new @engine if String === values + values = SqlLiteral.new values um.table @ctx.froms.last else um.table values.first.first.relation diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 7183a60591d1c..67568b5fd445e 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -11,5 +11,7 @@ require 'arel/nodes/delete_statement' require 'arel/nodes/unqualified_column' require 'arel/nodes/table_alias' +require 'arel/nodes/join' require 'arel/nodes/inner_join' +require 'arel/nodes/outer_join' require 'arel/nodes/on' diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index a39ded9f1cdbd..bf10eeac18684 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -1,13 +1,6 @@ module Arel module Nodes - class InnerJoin - attr_accessor :left, :right, :constraint - - def initialize left, right, constraint - @left = left - @right = right - @constraint = constraint - end + class InnerJoin < Arel::Nodes::Join end end end diff --git a/lib/arel/nodes/join.rb b/lib/arel/nodes/join.rb new file mode 100644 index 0000000000000..6dede632c5d0f --- /dev/null +++ b/lib/arel/nodes/join.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + class Join + attr_accessor :left, :right, :constraint + + def initialize left, right, constraint + @left = left + @right = right + @constraint = constraint + end + end + end +end diff --git a/lib/arel/nodes/outer_join.rb b/lib/arel/nodes/outer_join.rb new file mode 100644 index 0000000000000..bea5578b95c69 --- /dev/null +++ b/lib/arel/nodes/outer_join.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class OuterJoin < Arel::Nodes::Join + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 533911e635ddb..462b0765a5084 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -19,10 +19,6 @@ def from table end def project projection - projection = ::String == projection.class ? - Nodes::SqlLiteral.new(projection) : - projection - @ctx.projections << projection self end @@ -40,5 +36,14 @@ def take limit @head.limit = limit self end + + def join_sql + viz = Visitors::ToSql.new @engine + @ctx.froms.grep(Nodes::Join).map { |x| viz.accept x }.join ', ' + end + + def joins manager + manager.join_sql + end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 3b0a0dc5df902..401bdb325527d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -61,6 +61,10 @@ def visit_Arel_Nodes_TableAlias o "#{visit o.relation} #{quote_table_name o.name}" end + def visit_Arel_Nodes_OuterJoin o + "#{visit o.left} OUTER JOIN #{visit o.right} #{visit o.constraint}" + end + def visit_Arel_Nodes_InnerJoin o "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint}" end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 74e2db408b7cf..331d9714a7606 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -23,6 +23,30 @@ def execute sql end describe 'select manager' do + 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(table, aliaz, table[:id].eq(aliaz[:id])) + manager.join_sql.should be_like %{ + "users" INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" + } + check manager.joins(manager).should == manager.join_sql + end + + it 'returns outer join sql' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) + manager.join_sql.should be_like %{ + "users" OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" + } + check manager.joins(manager).should == manager.join_sql + end + end + describe 'delete' do it "copies from" do engine = EngineProxy.new Table.engine diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 58ccc9e7be278..702608ed8502e 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -33,14 +33,14 @@ module Arel describe 'take' do it "should add a limit" do manager = @relation.take 1 - manager.project '*' + manager.project SqlLiteral.new '*' manager.to_sql.should be_like %{ SELECT * FROM "users" LIMIT 1 } end end describe 'project' do it 'can project' do - manager = @relation.project '*' + manager = @relation.project SqlLiteral.new '*' manager.to_sql.should be_like %{ SELECT * FROM "users" From a3b8ef8375056cd3b6a8cea49dec671f2a8f6c41 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 22 Aug 2010 18:13:39 -0700 Subject: [PATCH 0627/1492] orders are working --- lib/arel/nodes/select_statement.rb | 7 +++--- lib/arel/select_manager.rb | 5 ++++ lib/arel/visitors/to_sql.rb | 1 + spec/arel/nodes/insert_statement_spec.rb | 4 +-- spec/arel/nodes/select_core_spec.rb | 8 +++--- spec/arel/nodes/update_statement_spec.rb | 4 +-- spec/arel/select_manager_spec.rb | 31 ++++++++++++++++++++++++ 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 50fef776f60f3..d00a079dc3761 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -2,11 +2,12 @@ module Arel module Nodes class SelectStatement attr_reader :cores - attr_accessor :limit + attr_accessor :limit, :orders def initialize cores = [SelectCore.new] - @cores = cores - @limit = nil + @cores = cores + @orders = [] + @limit = nil end def initialize_copy other diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 462b0765a5084..3d6aef0745f96 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -28,6 +28,11 @@ def where expr self end + def order *expr + @head.orders.concat expr + self + end + def wheres Compatibility::Wheres.new @engine, @ctx.wheres end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 401bdb325527d..55ed53177ec02 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -45,6 +45,7 @@ def visit_Arel_Nodes_InsertStatement o def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit x }.join, + ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), ("LIMIT #{o.limit}" if o.limit) ].compact.join ' ' end diff --git a/spec/arel/nodes/insert_statement_spec.rb b/spec/arel/nodes/insert_statement_spec.rb index 644e3fb192c25..286a44130cd41 100644 --- a/spec/arel/nodes/insert_statement_spec.rb +++ b/spec/arel/nodes/insert_statement_spec.rb @@ -15,8 +15,8 @@ end dolly = statement.clone - dolly.columns.should == %w[a0 b1 c2] - dolly.values.should == %w[x0 y1 z2] + check dolly.columns.should == %w[a0 b1 c2] + check dolly.values.should == %w[x0 y1 z2] end end end diff --git a/spec/arel/nodes/select_core_spec.rb b/spec/arel/nodes/select_core_spec.rb index cf717a39049d6..30927abea6d13 100644 --- a/spec/arel/nodes/select_core_spec.rb +++ b/spec/arel/nodes/select_core_spec.rb @@ -13,11 +13,11 @@ o.should_receive(:clone).and_return("#{o}#{j}") end end - + dolly = core.clone - dolly.froms.should == %w[a0 b1 c2] - dolly.projections.should == %w[d0 e1 f2] - dolly.wheres.should == %w[g0 h1 i2] + check dolly.froms.should == %w[a0 b1 c2] + check dolly.projections.should == %w[d0 e1 f2] + check dolly.wheres.should == %w[g0 h1 i2] end end end diff --git a/spec/arel/nodes/update_statement_spec.rb b/spec/arel/nodes/update_statement_spec.rb index 8cbca1fd73b01..3d425e28435b0 100644 --- a/spec/arel/nodes/update_statement_spec.rb +++ b/spec/arel/nodes/update_statement_spec.rb @@ -15,8 +15,8 @@ end dolly = statement.clone - dolly.wheres.should == %w[a0 b1 c2] - dolly.values.should == %w[x0 y1 z2] + check dolly.wheres.should == %w[a0 b1 c2] + check dolly.values.should == %w[x0 y1 z2] end end end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index bf4ce2e13f8d4..c29754cb554e8 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -23,6 +23,37 @@ def execute sql end describe 'select manager' do + 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.should 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.should 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 + check manager.order(table[:id]).should == manager + end + end + describe 'joins' do it 'returns join sql' do table = Table.new :users From 2579fec805f23903dd6c4f1726198e010f5a9a54 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 10:14:02 -0700 Subject: [PATCH 0628/1492] adding count nodes --- lib/arel/nodes.rb | 1 + lib/arel/nodes/count.rb | 12 ++++++++++++ lib/arel/nodes/sql_literal.rb | 3 +++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/nodes/sql_literal_spec.rb | 19 +++++++++++++++++++ 5 files changed, 39 insertions(+) create mode 100644 lib/arel/nodes/count.rb create mode 100644 spec/arel/nodes/sql_literal_spec.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 67568b5fd445e..98fc04569026c 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -3,6 +3,7 @@ require 'arel/nodes/or' require 'arel/nodes/in' +require 'arel/nodes/count' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb new file mode 100644 index 0000000000000..b7c4b609484f6 --- /dev/null +++ b/lib/arel/nodes/count.rb @@ -0,0 +1,12 @@ +module Arel + module Nodes + class Count + attr_accessor :expressions, :distinct + + def initialize expr, distinct = false + @expressions = expr + @distinct = distinct + end + end + end +end diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 53ff376071dae..526d08844981d 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -1,6 +1,9 @@ module Arel module Nodes class SqlLiteral < String + def count distinct = false + Count.new [self], distinct + end end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 55ed53177ec02..05c33ddb8b1b2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -58,6 +58,10 @@ def visit_Arel_Nodes_SelectCore o ].compact.join ' ' end + def visit_Arel_Nodes_Count o + "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})" + end + def visit_Arel_Nodes_TableAlias o "#{visit o.relation} #{quote_table_name o.name}" end diff --git a/spec/arel/nodes/sql_literal_spec.rb b/spec/arel/nodes/sql_literal_spec.rb new file mode 100644 index 0000000000000..390eb708e1000 --- /dev/null +++ b/spec/arel/nodes/sql_literal_spec.rb @@ -0,0 +1,19 @@ +module Arel + module Nodes + describe 'sql literal' do + describe 'count' do + it 'makes a count node' do + node = SqlLiteral.new('*').count + viz = Visitors::ToSql.new Table.engine + viz.accept(node).should be_like %{ COUNT(*) } + end + + it 'makes a distinct node' do + node = SqlLiteral.new('*').count true + viz = Visitors::ToSql.new Table.engine + viz.accept(node).should be_like %{ COUNT(DISTINCT *) } + end + end + end + end +end From 8966434f2a0d7aaff5fdea26b40dc37e89fee239 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 13:28:08 -0700 Subject: [PATCH 0629/1492] making sure update delegates to update and insert delegates to insert --- lib/arel/crud.rb | 7 ++--- spec/arel/crud_spec.rb | 51 ++++++++++++++++++++++++++++++++ spec/arel/select_manager_spec.rb | 3 +- 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 spec/arel/crud_spec.rb diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 2bf5f85823007..ac5f70673bd7c 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -6,22 +6,21 @@ module Crud def update values um = UpdateManager.new @engine - if String === values - values = SqlLiteral.new values + if Nodes::SqlLiteral === values um.table @ctx.froms.last else um.table values.first.first.relation end um.set values um.wheres = @ctx.wheres - @engine.connection.execute um.to_sql + @engine.connection.update um.to_sql, 'AREL' end # FIXME: this method should go away def insert values im = InsertManager.new @engine im.insert values - @engine.connection.execute im.to_sql + @engine.connection.insert im.to_sql end def delete diff --git a/spec/arel/crud_spec.rb b/spec/arel/crud_spec.rb new file mode 100644 index 0000000000000..ca1b92a041f24 --- /dev/null +++ b/spec/arel/crud_spec.rb @@ -0,0 +1,51 @@ +module Arel + class FakeCrudder < SelectManager + class FakeEngine + attr_reader :calls + + def initialize + @calls = [] + 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.insert [[table[:id], 'foo']] + fc.engine.calls.find { |method, _| + method == :insert + }.should_not be_nil + end + end + + describe 'update' do + it 'should call update on the connection' do + table = Table.new :users + fc = FakeCrudder.new + fc.from table + fc.update [[table[:id], 'foo']] + fc.engine.calls.find { |method, _| + method == :update + }.should_not be_nil + end + end + end +end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index c29754cb554e8..b6e09ea65e8ad 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -17,9 +17,10 @@ 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 execute sql + def execute sql, name = nil @executed << sql end + alias :update :execute end describe 'select manager' do From 0b0609569bc37da4343c955f78e9ab8d6031ff4f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 13:41:34 -0700 Subject: [PATCH 0630/1492] delete delegates to the connection --- lib/arel/crud.rb | 2 +- spec/arel/crud_spec.rb | 12 ++++++++++++ spec/arel/select_manager_spec.rb | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index ac5f70673bd7c..b1269bd1daf73 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -27,7 +27,7 @@ def delete dm = DeleteManager.new @engine dm.wheres = @ctx.wheres dm.from @ctx.froms.last - @engine.connection.execute dm.to_sql + @engine.connection.delete dm.to_sql, 'AREL' end end end diff --git a/spec/arel/crud_spec.rb b/spec/arel/crud_spec.rb index ca1b92a041f24..cc58b8dbce760 100644 --- a/spec/arel/crud_spec.rb +++ b/spec/arel/crud_spec.rb @@ -47,5 +47,17 @@ def initialize engine = FakeEngine.new }.should_not be_nil end end + + describe 'delete' do + it 'should call delete on the connection' do + table = Table.new :users + fc = FakeCrudder.new + fc.from table + fc.delete + fc.engine.calls.find { |method, _| + method == :delete + }.should_not be_nil + end + end end end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index b6e09ea65e8ad..493b79264dfa1 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -21,6 +21,7 @@ def execute sql, name = nil @executed << sql end alias :update :execute + alias :delete :execute end describe 'select manager' do From 3bc3b145aedea216eb84e213bac1017c6090d42b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 14:24:00 -0700 Subject: [PATCH 0631/1492] Squashed commit of the following: commit 3c6727732b349551df342b9eee66ed53d47e53eb Author: Aaron Patterson Date: Mon Aug 23 14:11:34 2010 -0700 adding table alias --- lib/arel.rb | 1 + lib/arel/deprecated.rb | 3 +++ lib/arel/table.rb | 3 ++- lib/arel/visitors/to_sql.rb | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 lib/arel/deprecated.rb diff --git a/lib/arel.rb b/lib/arel.rb index 0d03d0a4bb8a7..b012c62179ed8 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -18,6 +18,7 @@ require 'arel/nodes' #### these are deprecated +require 'arel/deprecated' require 'arel/sql/engine' require 'arel/sql_literal' require 'arel/expression' diff --git a/lib/arel/deprecated.rb b/lib/arel/deprecated.rb new file mode 100644 index 0000000000000..28f96a8a8cc72 --- /dev/null +++ b/lib/arel/deprecated.rb @@ -0,0 +1,3 @@ +module Arel + InnerJoin = Nodes::InnerJoin +end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 5a66db06279ae..02ece7ff07613 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -5,7 +5,7 @@ class Table @engine = nil class << self; attr_accessor :engine; end - attr_reader :name, :engine, :aliases + attr_reader :name, :engine, :aliases, :table_alias def initialize name, engine = Table.engine @name = name @@ -13,6 +13,7 @@ def initialize name, engine = Table.engine @engine = engine[:engine] if Hash === engine @columns = nil @aliases = [] + @table_alias = nil end def alias diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 05c33ddb8b1b2..6576d82c41d8b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -71,7 +71,7 @@ def visit_Arel_Nodes_OuterJoin o end def visit_Arel_Nodes_InnerJoin o - "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint}" + "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" end def visit_Arel_Nodes_On o From c151df07acc06b06179c2dc6205db029ff9ce001 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 14:44:10 -0700 Subject: [PATCH 0632/1492] AND nodes are supported --- lib/arel/nodes.rb | 1 + lib/arel/nodes/and.rb | 6 ++++++ lib/arel/nodes/binary.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/nodes/equality_spec.rb | 11 +++++++++++ spec/arel/visitors/to_sql_spec.rb | 7 +++++++ 6 files changed, 33 insertions(+) create mode 100644 lib/arel/nodes/and.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 98fc04569026c..f2332694a8e28 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,6 +1,7 @@ require 'arel/nodes/binary' require 'arel/nodes/equality' require 'arel/nodes/or' +require 'arel/nodes/and' require 'arel/nodes/in' require 'arel/nodes/count' diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb new file mode 100644 index 0000000000000..80f420b4f1e6e --- /dev/null +++ b/lib/arel/nodes/and.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class And < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index fdfcab2d3f29b..3cd9583e79160 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -12,6 +12,10 @@ def or right Nodes::Or.new self, right end + 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. diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 6576d82c41d8b..8136039040058 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -86,6 +86,10 @@ def visit_Arel_Nodes_In o "#{visit o.left} IN (#{o.right.map { |x| visit x }.join ', '})" end + def visit_Arel_Nodes_And o + "#{visit o.left} AND #{visit o.right}" + end + def visit_Arel_Nodes_Or o "#{visit o.left} OR #{visit o.right}" end diff --git a/spec/arel/nodes/equality_spec.rb b/spec/arel/nodes/equality_spec.rb index b74af3a039dfe..d91fa0df03bf5 100644 --- a/spec/arel/nodes/equality_spec.rb +++ b/spec/arel/nodes/equality_spec.rb @@ -11,6 +11,17 @@ module Nodes check node.right.should == 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 + check node.left.should == left + check node.right.should == right + end + end end end end diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index b70c392630eaf..9807c89b3a276 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,13 @@ module Visitors @attr = Table.new(:users)[:id] end + it "should visit_Arel_Nodes_And" do + node = Nodes::And.new @attr.eq(10), @attr.eq(11) + @visitor.accept(node).should 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).should be_like %{ From 819a0920f0ca1165db3e8b05f0276b3338f1be30 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 14:47:16 -0700 Subject: [PATCH 0633/1492] visiting binary columns --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8136039040058..a0c8f67e13ccf 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -110,6 +110,7 @@ def visit_Arel_Attributes_Attribute o alias :visit_Arel_Attributes_Integer :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 visit_Fixnum o; o end alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum From f2144229f5353cbc6b932474c94978523756a644 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 14:59:53 -0700 Subject: [PATCH 0634/1492] project takes *args now --- lib/arel/select_manager.rb | 4 ++-- spec/arel/select_manager_spec.rb | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 3d6aef0745f96..1c8daf8e50eb9 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -18,8 +18,8 @@ def from table self end - def project projection - @ctx.projections << projection + def project *projections + @ctx.projections.concat projections self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 493b79264dfa1..0120650a9fee4 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -143,13 +143,19 @@ def execute sql, name = nil end describe 'project' do + it 'takes multiple args' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.project Nodes::SqlLiteral.new('foo'), + Nodes::SqlLiteral.new('bar') + manager.to_sql.should be_like %{ SELECT foo, bar } + end + it 'takes strings' do table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new('*') - manager.to_sql.should be_like %{ - SELECT * - } + manager.to_sql.should be_like %{ SELECT * } end it "takes sql literals" do From f4194815e6797b16bb5f53938be2697a2a5d1b53 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 23 Aug 2010 16:07:32 -0700 Subject: [PATCH 0635/1492] not implementing to_a yet --- lib/arel/select_manager.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 1c8daf8e50eb9..d8e67cafab824 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -50,5 +50,9 @@ def join_sql def joins manager manager.join_sql end + + def to_a + raise NotImplementedError + end end end From 55d1f9fd127397b7a4c85121a8ef02451257f756 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 24 Aug 2010 17:59:03 -0700 Subject: [PATCH 0636/1492] adding string join nodes and a visitor to produce backwards compatible "join_sql" --- lib/arel.rb | 1 + lib/arel/nodes.rb | 1 + lib/arel/nodes/string_join.rb | 11 +++++++++++ lib/arel/select_manager.rb | 6 ++++-- lib/arel/table.rb | 9 ++++++++- lib/arel/version.rb | 2 +- lib/arel/visitors/dot.rb | 5 +++++ lib/arel/visitors/join_sql.rb | 21 +++++++++++++++++++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/select_manager_spec.rb | 4 ++-- 10 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 lib/arel/nodes/string_join.rb create mode 100644 lib/arel/visitors/join_sql.rb diff --git a/lib/arel.rb b/lib/arel.rb index b012c62179ed8..2bfdef15d5791 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -25,4 +25,5 @@ #### require 'arel/visitors/to_sql' +require 'arel/visitors/join_sql' require 'arel/visitors/dot' diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index f2332694a8e28..6dcd86867aa42 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -16,4 +16,5 @@ require 'arel/nodes/join' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' +require 'arel/nodes/string_join' require 'arel/nodes/on' diff --git a/lib/arel/nodes/string_join.rb b/lib/arel/nodes/string_join.rb new file mode 100644 index 0000000000000..ea7912f92b506 --- /dev/null +++ b/lib/arel/nodes/string_join.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class StringJoin < Arel::Nodes::Join + undef :constraint + + def initialize left, right + super(left, right, nil) + end + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index d8e67cafab824..736b122399268 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -43,8 +43,10 @@ def take limit end def join_sql - viz = Visitors::ToSql.new @engine - @ctx.froms.grep(Nodes::Join).map { |x| viz.accept x }.join ', ' + viz = Visitors::JoinSql.new @engine + Nodes::SqlLiteral.new( + @ctx.froms.grep(Nodes::Join).map { |x| viz.accept x }.join ', ' + ) end def joins manager diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 02ece7ff07613..b3a1a105d85f0 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -27,7 +27,14 @@ def tm end def join relation - SelectManager.new(@engine).from(Nodes::InnerJoin.new(self, relation, nil)) + sm = SelectManager.new(@engine) + case relation + when String, Nodes::SqlLiteral + raise if relation.blank? + sm.from Nodes::StringJoin.new(self, relation) + else + sm.from Nodes::InnerJoin.new(self, relation, nil) + end end def where condition diff --git a/lib/arel/version.rb b/lib/arel/version.rb index ba9cca430aa10..2c47fd2fe0ad5 100644 --- a/lib/arel/version.rb +++ b/lib/arel/version.rb @@ -1,3 +1,3 @@ module Arel - VERSION = '0.4.1.beta.1' + VERSION = '1.0.0.beta.1' end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index ec2db0814fbf1..277573f7fe64f 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,6 +28,11 @@ def accept object end private + def visit_Arel_Nodes_StringJoin o + visit_edge o, "left" + visit_edge o, "right" + end + def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" visit_edge o, "columns" diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb new file mode 100644 index 0000000000000..95b27b44761a6 --- /dev/null +++ b/lib/arel/visitors/join_sql.rb @@ -0,0 +1,21 @@ +module 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 + class JoinSql < Arel::Visitors::ToSql + def visit_Arel_Nodes_OuterJoin o + "OUTER JOIN #{visit o.right} #{visit o.constraint}" + end + + def visit_Arel_Nodes_InnerJoin o + "INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a0c8f67e13ccf..a798d888d3724 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -66,6 +66,10 @@ def visit_Arel_Nodes_TableAlias o "#{visit o.relation} #{quote_table_name o.name}" end + def visit_Arel_Nodes_StringJoin o + "#{visit o.left} #{visit o.right}" + end + def visit_Arel_Nodes_OuterJoin o "#{visit o.left} OUTER JOIN #{visit o.right} #{visit o.constraint}" end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 0120650a9fee4..380e3817568e7 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -63,7 +63,7 @@ def execute sql, name = nil manager = Arel::SelectManager.new Table.engine manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) manager.join_sql.should be_like %{ - "users" INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" + INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" } check manager.joins(manager).should == manager.join_sql end @@ -74,7 +74,7 @@ def execute sql, name = nil manager = Arel::SelectManager.new Table.engine manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) manager.join_sql.should be_like %{ - "users" OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" + OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" } check manager.joins(manager).should == manager.join_sql end From 9c4670c6505d462c27a58a84e6b0746e20b98e7f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 24 Aug 2010 18:13:01 -0700 Subject: [PATCH 0637/1492] moving visitor logic to the visitor --- lib/arel/select_manager.rb | 4 +--- lib/arel/visitors/join_sql.rb | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 736b122399268..a791b686884ad 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -44,9 +44,7 @@ def take limit def join_sql viz = Visitors::JoinSql.new @engine - Nodes::SqlLiteral.new( - @ctx.froms.grep(Nodes::Join).map { |x| viz.accept x }.join ', ' - ) + Nodes::SqlLiteral.new viz.accept @ctx end def joins manager diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 95b27b44761a6..0353d687ebcaa 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -9,6 +9,10 @@ module Visitors # This visitor is used in SelectManager#join_sql and is for backwards # compatibility with Arel V1.0 class JoinSql < Arel::Visitors::ToSql + def visit_Arel_Nodes_SelectCore o + o.froms.grep(Nodes::Join).map { |x| visit x }.join ', ' + end + def visit_Arel_Nodes_OuterJoin o "OUTER JOIN #{visit o.right} #{visit o.constraint}" end From da958b98ea86a24b1c79cfb0cef7e42d58646ba9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 24 Aug 2010 18:36:59 -0700 Subject: [PATCH 0638/1492] adding order clauses method to the select manager --- lib/arel.rb | 1 + lib/arel/select_manager.rb | 9 ++++++++- lib/arel/visitors/order_clauses.rb | 9 +++++++++ lib/arel/visitors/to_sql.rb | 4 ++-- spec/arel/select_manager_spec.rb | 11 +++++++++++ 5 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 lib/arel/visitors/order_clauses.rb diff --git a/lib/arel.rb b/lib/arel.rb index 2bfdef15d5791..4772e9f4b03ac 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -26,4 +26,5 @@ require 'arel/visitors/to_sql' require 'arel/visitors/join_sql' +require 'arel/visitors/order_clauses' require 'arel/visitors/dot' diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index a791b686884ad..8033846a558cd 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -29,7 +29,10 @@ def where expr end def order *expr - @head.orders.concat expr + # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically + @head.orders.concat expr.map { |x| + String === x ? Nodes::SqlLiteral.new(x) : x + } self end @@ -47,6 +50,10 @@ def join_sql Nodes::SqlLiteral.new viz.accept @ctx end + def order_clauses + Visitors::OrderClauses.new(@engine).accept @head + end + def joins manager manager.join_sql end diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb new file mode 100644 index 0000000000000..9326897f687c5 --- /dev/null +++ b/lib/arel/visitors/order_clauses.rb @@ -0,0 +1,9 @@ +module Arel + module Visitors + class OrderClauses < Arel::Visitors::ToSql + def visit_Arel_Nodes_SelectStatement o + o.orders.map { |x| visit x } + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a798d888d3724..927ecbb0b05dc 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -126,8 +126,8 @@ def visit_Time o; quote(o) end DISPATCH = {} def visit object - send "visit_#{object.class.name.gsub('::', '_')}", object - #send DISPATCH[object.class], object + #send "visit_#{object.class.name.gsub('::', '_')}", object + send DISPATCH[object.class], object end private_instance_methods(false).each do |method| diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 380e3817568e7..6155842241328 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -80,6 +80,17 @@ def execute sql, name = nil end end + describe 'order_clauses' do + it 'returns order clauses as a list' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.order table[:id] + manager.order_clauses.first.should be_like %{ "users"."id" } + end + end + describe 'delete' do it "copies from" do engine = EngineProxy.new Table.engine From c59f91e4af4dad29c94d6cd969a45d9288746a0b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 24 Aug 2010 18:38:15 -0700 Subject: [PATCH 0639/1492] return sql literal nodes --- lib/arel/select_manager.rb | 4 +++- lib/arel/visitors/to_sql.rb | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 8033846a558cd..e362f369e731b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -51,7 +51,9 @@ def join_sql end def order_clauses - Visitors::OrderClauses.new(@engine).accept @head + Visitors::OrderClauses.new(@engine).accept(@head).map { |x| + Nodes::SqlLiteral.new x + } end def joins manager diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 927ecbb0b05dc..a798d888d3724 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -126,8 +126,8 @@ def visit_Time o; quote(o) end DISPATCH = {} def visit object - #send "visit_#{object.class.name.gsub('::', '_')}", object - send DISPATCH[object.class], object + send "visit_#{object.class.name.gsub('::', '_')}", object + #send DISPATCH[object.class], object end private_instance_methods(false).each do |method| From 6c875af26fc91af120d270b25a35ebc0eee311ff Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 24 Aug 2010 18:42:47 -0700 Subject: [PATCH 0640/1492] we can visit the date! --- lib/arel/visitors/to_sql.rb | 1 + spec/arel/visitors/to_sql_spec.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a798d888d3724..b6ebee3c9e38c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -123,6 +123,7 @@ def visit_Fixnum o; o end def visit_TrueClass o; quote(o) end def visit_String o; quote(o) end def visit_Time o; quote(o) end + def visit_Date o; quote(o) end DISPATCH = {} def visit object diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index 9807c89b3a276..80f1e596647ed 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,10 @@ module Visitors @attr = Table.new(:users)[:id] end + it "should visit_Date" do + @visitor.accept Date.today + end + it "should visit_Arel_Nodes_And" do node = Nodes::And.new @attr.eq(10), @attr.eq(11) @visitor.accept(node).should be_like %{ From 86b361879a342c25630ce8ab9da76f2643fb32ca Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 19 Aug 2010 02:04:17 -0400 Subject: [PATCH 0641/1492] specs for DeleteManager deep copy --- spec/arel/delete_manager_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/arel/delete_manager_spec.rb b/spec/arel/delete_manager_spec.rb index 88d4df061aa8f..74496c58c6606 100644 --- a/spec/arel/delete_manager_spec.rb +++ b/spec/arel/delete_manager_spec.rb @@ -38,5 +38,16 @@ module Arel check dm.where(table[:id].eq(10)).should == dm end end + + describe "TreeManager" do + subject do + table = Table.new :users + Arel::DeleteManager.new(Table.engine).tap do |manager| + manager.where(table[:id].eq(10)) + end + end + + it_should_behave_like "TreeManager" + end end end From dc750bef5cf5b577399c84f97b821af26c9554a2 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 19 Aug 2010 02:12:39 -0400 Subject: [PATCH 0642/1492] fixing typos in spec --- spec/arel/nodes/delete_statement_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/arel/nodes/delete_statement_spec.rb b/spec/arel/nodes/delete_statement_spec.rb index dd43b70d3508a..03fa41799a56d 100644 --- a/spec/arel/nodes/delete_statement_spec.rb +++ b/spec/arel/nodes/delete_statement_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' -describe Arel::Nodes::SelectStatement do +describe Arel::Nodes::DeleteStatement do describe "#clone" do - it "clones where" do + it "clones wheres" do statement = Arel::Nodes::DeleteStatement.new statement.wheres = %w[a b c] From 4e1dd7eeabde2bd785d47db895e45c11f1693c05 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 30 Aug 2010 18:35:13 -0400 Subject: [PATCH 0643/1492] deep copies of statements aren't necessary. shallow copy the top-level arrays. --- lib/arel/nodes/delete_statement.rb | 2 +- lib/arel/nodes/insert_statement.rb | 4 ++-- lib/arel/nodes/select_core.rb | 6 +++--- lib/arel/nodes/select_statement.rb | 2 +- lib/arel/nodes/update_statement.rb | 4 ++-- spec/arel/nodes/delete_statement_spec.rb | 6 ++---- spec/arel/nodes/insert_statement_spec.rb | 12 ++++-------- spec/arel/nodes/select_core_spec.rb | 10 ++++------ spec/arel/nodes/select_statement_spec.rb | 6 ++---- spec/arel/nodes/update_statement_spec.rb | 12 ++++-------- 10 files changed, 25 insertions(+), 39 deletions(-) diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index b65177af056f4..610d69e460391 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -10,7 +10,7 @@ def initialize def initialize_copy other super - @wheres = @wheres.map { |o| o.clone } + @wheres = @wheres.clone end end end diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index 8c6e1234d0bf6..629e7a851383e 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -11,8 +11,8 @@ def initialize def initialize_copy other super - @columns = @columns.map { |o| o.clone } - @values = @values.map { |o| o.clone } + @columns = @columns.clone + @values = @values.clone end end end diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 7ebdab315dafe..5e27c7c414bb4 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -11,9 +11,9 @@ def initialize def initialize_copy other super - @froms = @froms.map { |o| o.clone } - @projections = @projections.map { |o| o.clone } - @wheres = @wheres.map { |o| o.clone } + @froms = @froms.clone + @projections = @projections.clone + @wheres = @wheres.clone end end end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index d00a079dc3761..b7c59da275a47 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -12,7 +12,7 @@ def initialize cores = [SelectCore.new] def initialize_copy other super - @cores = @cores.map { |o| o.clone } + @cores = @cores.clone end end end diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 27e3e4e6ac25d..7a1ce9a7b129c 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -11,8 +11,8 @@ def initialize def initialize_copy other super - @wheres = @wheres.map { |o| o.clone } - @values = @values.map { |o| o.clone } + @wheres = @wheres.clone + @values = @values.clone end end end diff --git a/spec/arel/nodes/delete_statement_spec.rb b/spec/arel/nodes/delete_statement_spec.rb index 03fa41799a56d..4d12d184fbc5b 100644 --- a/spec/arel/nodes/delete_statement_spec.rb +++ b/spec/arel/nodes/delete_statement_spec.rb @@ -6,12 +6,10 @@ statement = Arel::Nodes::DeleteStatement.new statement.wheres = %w[a b c] - statement.wheres.each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end + statement.wheres.should_receive(:clone).and_return([:wheres]) dolly = statement.clone - dolly.wheres.should == %w[a0 b1 c2] + dolly.wheres.should == [:wheres] end end end diff --git a/spec/arel/nodes/insert_statement_spec.rb b/spec/arel/nodes/insert_statement_spec.rb index 286a44130cd41..0e2432c021d2b 100644 --- a/spec/arel/nodes/insert_statement_spec.rb +++ b/spec/arel/nodes/insert_statement_spec.rb @@ -7,16 +7,12 @@ statement.columns = %w[a b c] statement.values = %w[x y z] - statement.columns.each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end - statement.values.each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end + statement.columns.should_receive(:clone).and_return([:columns]) + statement.values.should_receive(:clone).and_return([:values]) dolly = statement.clone - check dolly.columns.should == %w[a0 b1 c2] - check dolly.values.should == %w[x0 y1 z2] + check dolly.columns.should == [:columns] + check dolly.values.should == [:values] end end end diff --git a/spec/arel/nodes/select_core_spec.rb b/spec/arel/nodes/select_core_spec.rb index 30927abea6d13..d2e87c2c23004 100644 --- a/spec/arel/nodes/select_core_spec.rb +++ b/spec/arel/nodes/select_core_spec.rb @@ -9,15 +9,13 @@ core.instance_variable_set "@wheres", %w[g h i] [:froms, :projections, :wheres].each do |array_attr| - core.send(array_attr).each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end + core.send(array_attr).should_receive(:clone).and_return([array_attr]) end dolly = core.clone - check dolly.froms.should == %w[a0 b1 c2] - check dolly.projections.should == %w[d0 e1 f2] - check dolly.wheres.should == %w[g0 h1 i2] + check dolly.froms.should == [:froms] + check dolly.projections.should == [:projections] + check dolly.wheres.should == [:wheres] end end end diff --git a/spec/arel/nodes/select_statement_spec.rb b/spec/arel/nodes/select_statement_spec.rb index a024710c78d8d..75463f1d958bc 100644 --- a/spec/arel/nodes/select_statement_spec.rb +++ b/spec/arel/nodes/select_statement_spec.rb @@ -5,12 +5,10 @@ it "clones cores" do statement = Arel::Nodes::SelectStatement.new %w[a b c] - statement.cores.each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end + statement.cores.should_receive(:clone).and_return([:cores]) dolly = statement.clone - dolly.cores.should == %w[a0 b1 c2] + dolly.cores.should == [:cores] end end end diff --git a/spec/arel/nodes/update_statement_spec.rb b/spec/arel/nodes/update_statement_spec.rb index 3d425e28435b0..860d1c448aa49 100644 --- a/spec/arel/nodes/update_statement_spec.rb +++ b/spec/arel/nodes/update_statement_spec.rb @@ -7,16 +7,12 @@ statement.wheres = %w[a b c] statement.values = %w[x y z] - statement.wheres.each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end - statement.values.each_with_index do |o, j| - o.should_receive(:clone).and_return("#{o}#{j}") - end + statement.wheres.should_receive(:clone).and_return([:wheres]) + statement.values.should_receive(:clone).and_return([:values]) dolly = statement.clone - check dolly.wheres.should == %w[a0 b1 c2] - check dolly.values.should == %w[x0 y1 z2] + check dolly.wheres.should == [:wheres] + check dolly.values.should == [:values] end end end From a0772a8d9cedca1f8227fc63553c3baf92f7db4c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 5 Sep 2010 14:24:23 -0700 Subject: [PATCH 0644/1492] fixing version so tests run with rails --- lib/arel/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/version.rb b/lib/arel/version.rb index 2c47fd2fe0ad5..9795347874969 100644 --- a/lib/arel/version.rb +++ b/lib/arel/version.rb @@ -1,3 +1,3 @@ module Arel - VERSION = '1.0.0.beta.1' + VERSION = '1.0.1.beta.1' end From e4f6272b844f7e6a9ee13c67fdb80897377d2f44 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Sep 2010 17:17:49 -0700 Subject: [PATCH 0645/1492] select manager responds to order --- lib/arel/table.rb | 4 ++++ spec/arel/table_spec.rb | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index b3a1a105d85f0..f115caaab32f4 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -37,6 +37,10 @@ def join relation end end + def order *expr + tm.order *expr + end + def where condition tm.where condition end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 702608ed8502e..ae43183c67f98 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -30,6 +30,13 @@ module Arel end end + describe 'order' do + it "should take an order" do + manager = @relation.order "foo" + manager.to_sql.should be_like %{ SELECT FROM "users" ORDER BY foo } + end + end + describe 'take' do it "should add a limit" do manager = @relation.take 1 From 458f9c43603df319625f1db0939635af13a85d43 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Sep 2010 17:18:10 -0700 Subject: [PATCH 0646/1492] fixing warning --- lib/arel/table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index f115caaab32f4..faf4d70f646fe 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -38,7 +38,7 @@ def join relation end def order *expr - tm.order *expr + tm.order(*expr) end def where condition From 87b685680669d13bf9ce879fa0037784150e8b62 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Sep 2010 17:39:09 -0700 Subject: [PATCH 0647/1492] adding backwards compat methods --- lib/arel/nodes/equality.rb | 3 +++ spec/arel/nodes/equality_spec.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/arel/nodes/equality.rb b/lib/arel/nodes/equality.rb index b8d8281434661..f29344e5806db 100644 --- a/lib/arel/nodes/equality.rb +++ b/lib/arel/nodes/equality.rb @@ -1,6 +1,9 @@ module Arel module Nodes class Equality < Arel::Nodes::Binary + def operator; :== end + alias :operand1 :left + alias :operand2 :right end end end diff --git a/spec/arel/nodes/equality_spec.rb b/spec/arel/nodes/equality_spec.rb index d91fa0df03bf5..d9edc352f3232 100644 --- a/spec/arel/nodes/equality_spec.rb +++ b/spec/arel/nodes/equality_spec.rb @@ -1,6 +1,33 @@ 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) + check left.operator.should == :== + end + end + + describe 'operand1' do + it "should equal left" do + attr = Table.new(:users)[:id] + left = attr.eq(10) + check left.left.should == left.operand1 + end + end + + describe 'operand2' do + it "should equal right" do + attr = Table.new(:users)[:id] + left = attr.eq(10) + check left.right.should == left.operand2 + end + end + end + describe 'or' do it 'makes an OR node' do attr = Table.new(:users)[:id] From c14c5c16f27eb1d6769ed2dd55028187f8d121a8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Sep 2010 18:07:36 -0700 Subject: [PATCH 0648/1492] dot visitor can visit count nodes --- lib/arel/visitors/dot.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 277573f7fe64f..f66dfd8a545b7 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,6 +28,11 @@ def accept object end private + def visit_Arel_Nodes_Count o + visit_edge o, "expressions" + visit_edge o, "distinct" + end + def visit_Arel_Nodes_StringJoin o visit_edge o, "left" visit_edge o, "right" From 4ef7ee8f35fdefd6eeef102f46497295a7b5d858 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 11:02:38 -0700 Subject: [PATCH 0649/1492] doing sql literal conversion --- lib/arel/select_manager.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index e362f369e731b..c8cd37b9fa502 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -19,7 +19,11 @@ def from table end def project *projections - @ctx.projections.concat projections + # FIXME: converting these to SQLLiterals is probably not good, but + # rails tests require it. + @ctx.projections.concat projections.map { |x| + String == x.class ? SqlLiteral.new(x) : x + } self end From 719eacfc81a94bde89a187356abfa090544bba80 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 14:00:19 -0700 Subject: [PATCH 0650/1492] adding backwards compat nodes --- lib/arel/nodes/inner_join.rb | 3 +++ lib/arel/nodes/outer_join.rb | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index bf10eeac18684..9fd2615f3946f 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -3,4 +3,7 @@ module Nodes class InnerJoin < Arel::Nodes::Join end end + + # FIXME: backwards compat + InnerJoin = Nodes::InnerJoin end diff --git a/lib/arel/nodes/outer_join.rb b/lib/arel/nodes/outer_join.rb index bea5578b95c69..71da6e70d5f5c 100644 --- a/lib/arel/nodes/outer_join.rb +++ b/lib/arel/nodes/outer_join.rb @@ -3,4 +3,7 @@ module Nodes class OuterJoin < Arel::Nodes::Join end end + + # FIXME: backwards compat + OuterJoin = Nodes::OuterJoin end From 90881c5841c49a2e56662b6d32e8058dfb1aa8b7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 14:02:23 -0700 Subject: [PATCH 0651/1492] adding joins method to Table --- lib/arel/table.rb | 4 ++++ spec/arel/table_spec.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index faf4d70f646fe..7811c217a72c3 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -26,6 +26,10 @@ def tm SelectManager.new(@engine).from(self) end + def joins manager + nil + end + def join relation sm = SelectManager.new(@engine) case relation diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index ae43183c67f98..2ea45dcca1659 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,6 +6,14 @@ module Arel @relation = Table.new(:users) end + describe 'backwards compat' do + describe 'joins' do + it 'returns nil' do + check @relation.joins(nil).should == nil + end + end + end + describe 'alias' do it 'should create a node that proxies to a table' do check @relation.aliases.should == [] From 502b43f00904967d9679b208a08beb764ce8911e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 14:49:06 -0700 Subject: [PATCH 0652/1492] joins are starting to work better --- lib/arel/table.rb | 4 ++-- spec/arel/table_spec.rb | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 7811c217a72c3..434f19cc6bb03 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -30,14 +30,14 @@ def joins manager nil end - def join relation + def join relation, klass = Nodes::InnerJoin sm = SelectManager.new(@engine) case relation when String, Nodes::SqlLiteral raise if relation.blank? sm.from Nodes::StringJoin.new(self, relation) else - sm.from Nodes::InnerJoin.new(self, relation, nil) + sm.from klass.new(self, relation, nil) end end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 2ea45dcca1659..78705b4f0a7de 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -12,6 +12,20 @@ module Arel check @relation.joins(nil).should == nil end end + + describe 'join' do + 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.should be_like %{ + SELECT FROM "users" + OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + end end describe 'alias' do From 40f31b6f5e9f570f92a65a6654d6b00d70cd922f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 14:49:37 -0700 Subject: [PATCH 0653/1492] failing test for join on select manager --- spec/arel/select_manager_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 6155842241328..f894d3230a211 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -56,6 +56,22 @@ def execute sql, name = nil end 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.join(right).on(predicate) + manager.to_sql.should be_like %{ + SELECT FROM "users" + OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + end + describe 'joins' do it 'returns join sql' do table = Table.new :users From 9f9b32544dd7711c41a31651e57f32a9b379e1d7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 15:10:27 -0700 Subject: [PATCH 0654/1492] getting better on joins --- lib/arel/select_manager.rb | 10 ++++++++++ lib/arel/visitors/dot.rb | 7 +++++++ spec/arel/select_manager_spec.rb | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index c8cd37b9fa502..b574253b05dad 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -18,6 +18,16 @@ def from table self end + def join relation, klass = Nodes::InnerJoin + case relation + when String, Nodes::SqlLiteral + raise if relation.blank? + from Nodes::StringJoin.new(@ctx.froms.pop, relation) + else + from klass.new(@ctx.froms.pop, relation, nil) + end + end + def project *projections # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index f66dfd8a545b7..73fcddca845f4 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,6 +28,12 @@ def accept object end private + def visit_Arel_Nodes_TableAlias o + visit_edge o, "name" + visit_edge o, "relation" + visit_edge o, "columns" + end + def visit_Arel_Nodes_Count o visit_edge o, "expressions" visit_edge o, "distinct" @@ -37,6 +43,7 @@ def visit_Arel_Nodes_StringJoin o visit_edge o, "left" visit_edge o, "right" end + alias :visit_Arel_Nodes_InnerJoin :visit_Arel_Nodes_StringJoin def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index f894d3230a211..800018aa7d89f 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -63,7 +63,23 @@ def execute sql, name = nil predicate = left[:id].eq(right[:id]) manager = Arel::SelectManager.new Table.engine + manager.from left manager.join(right).on(predicate) + manager.to_sql.should 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.should be_like %{ SELECT FROM "users" OUTER JOIN "users" "users_2" From e614fcc03f13601421f3cac3d00ba3aeefa128c9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 15:13:44 -0700 Subject: [PATCH 0655/1492] visiting outer joins --- lib/arel/visitors/dot.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 73fcddca845f4..1d44eba32f329 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -44,6 +44,7 @@ def visit_Arel_Nodes_StringJoin o visit_edge o, "right" end alias :visit_Arel_Nodes_InnerJoin :visit_Arel_Nodes_StringJoin + alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_StringJoin def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" From 5b480bc60bf5de2b90ba32e854b6a7d2955cbcbb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 15:26:21 -0700 Subject: [PATCH 0656/1492] OUTER joins should be LEFT outer joins --- lib/arel/visitors/to_sql.rb | 2 +- spec/arel/select_manager_spec.rb | 2 +- spec/arel/table_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b6ebee3c9e38c..4ac38fb13e731 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -71,7 +71,7 @@ def visit_Arel_Nodes_StringJoin o end def visit_Arel_Nodes_OuterJoin o - "#{visit o.left} OUTER JOIN #{visit o.right} #{visit o.constraint}" + "#{visit o.left} LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}" end def visit_Arel_Nodes_InnerJoin o diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 800018aa7d89f..0d7dc27571763 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -82,7 +82,7 @@ def execute sql, name = nil manager.join(right, Nodes::OuterJoin).on(predicate) manager.to_sql.should be_like %{ SELECT FROM "users" - OUTER JOIN "users" "users_2" + LEFT OUTER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" } end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 78705b4f0a7de..8e27d6007879c 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -21,7 +21,7 @@ module Arel mgr.to_sql.should be_like %{ SELECT FROM "users" - OUTER JOIN "users" "users_2" + LEFT OUTER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" } end From d0e6b969d678fe1a7da4a9f0cedc47e66dcc4173 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 15:27:08 -0700 Subject: [PATCH 0657/1492] nooping on nil parameters --- lib/arel/select_manager.rb | 2 ++ spec/arel/select_manager_spec.rb | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index b574253b05dad..c9214b20a2a81 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -19,6 +19,8 @@ def from table end def join relation, klass = Nodes::InnerJoin + return self unless relation + case relation when String, Nodes::SqlLiteral raise if relation.blank? diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 0d7dc27571763..775a0e6162f5d 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -86,6 +86,11 @@ def execute sql, name = nil ON "users"."id" = "users_2"."id" } end + + it 'noops on nil' do + manager = Arel::SelectManager.new Table.engine + check manager.join(nil).should == manager + end end describe 'joins' do From 6e05eef9e94dd8f5138bab591d9dbe926498e6ed Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 15:47:38 -0700 Subject: [PATCH 0658/1492] group nodes are working! --- lib/arel/nodes.rb | 1 + lib/arel/nodes/group.rb | 11 +++++++++++ lib/arel/nodes/select_core.rb | 8 +++++--- lib/arel/select_manager.rb | 7 +++++++ lib/arel/visitors/to_sql.rb | 7 ++++++- spec/arel/select_manager_spec.rb | 28 ++++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 lib/arel/nodes/group.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 6dcd86867aa42..bf7ae830d0c76 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -14,6 +14,7 @@ require 'arel/nodes/unqualified_column' require 'arel/nodes/table_alias' require 'arel/nodes/join' +require 'arel/nodes/group' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' require 'arel/nodes/string_join' diff --git a/lib/arel/nodes/group.rb b/lib/arel/nodes/group.rb new file mode 100644 index 0000000000000..57a7c579da2a0 --- /dev/null +++ b/lib/arel/nodes/group.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Group + attr_accessor :expr + + def initialize expr + @expr = expr + end + end + end +end diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 5e27c7c414bb4..6e85968b31047 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,19 +1,21 @@ module Arel module Nodes class SelectCore - attr_reader :froms, :projections, :wheres + attr_reader :froms, :projections, :wheres, :groups def initialize @froms = [] @projections = [] @wheres = [] + @groups = [] end def initialize_copy other super - @froms = @froms.clone + @froms = @froms.clone @projections = @projections.clone - @wheres = @wheres.clone + @wheres = @wheres.clone + @group = @groups.clone end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index c9214b20a2a81..3ac6a5cbc864e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -13,6 +13,13 @@ def on expr self end + def group *columns + columns.each do |column| + @ctx.groups.push Nodes::Group.new column + end + self + end + def from table @ctx.froms << table self diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4ac38fb13e731..55b3259e81314 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -54,10 +54,15 @@ def visit_Arel_Nodes_SelectCore o [ "SELECT #{o.projections.map { |x| visit x }.join ', '}", ("FROM #{o.froms.map { |x| visit x }.join ', ' }" unless o.froms.empty?), - ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.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?) ].compact.join ' ' end + def visit_Arel_Nodes_Group o + visit o.expr + end + def visit_Arel_Nodes_Count o "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})" end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 775a0e6162f5d..a6f5765b44d1b 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -128,6 +128,34 @@ def execute sql, name = nil 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.should be_like %{ + SELECT FROM "users" GROUP BY "users"."id" + } + end + + it 'chains' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + check manager.group(table[:id]).should == 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.should be_like %{ + SELECT FROM "users" GROUP BY "users"."id", "users"."name" + } + end + end + describe 'delete' do it "copies from" do engine = EngineProxy.new Table.engine From 7dcc76606bc1af67025e1f557e3e2184f96e4cf5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 16:07:37 -0700 Subject: [PATCH 0659/1492] adding group to Table --- lib/arel/table.rb | 4 ++++ spec/arel/table_spec.rb | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 434f19cc6bb03..28243e645e466 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -41,6 +41,10 @@ def join relation, klass = Nodes::InnerJoin end end + def group *columns + tm.group(*columns) + end + def order *expr tm.order(*expr) end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 8e27d6007879c..223453f7087ab 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -28,6 +28,15 @@ module Arel end end + describe 'group' do + it 'should create a group' do + manager = @relation.group @relation[:id] + manager.to_sql.should 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 check @relation.aliases.should == [] From cea486ac810a92ef4f96ef84e3a412fd7a4f6925 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 16:09:58 -0700 Subject: [PATCH 0660/1492] group is implemented on table --- lib/arel/select_manager.rb | 3 +++ spec/arel/select_manager_spec.rb | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 3ac6a5cbc864e..2ad9555d27f4b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -15,6 +15,9 @@ def on expr def group *columns columns.each do |column| + # FIXME: backwards compat + column = Nodes::SqlLiteral.new(column) if String === column + @ctx.groups.push Nodes::Group.new column end self diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index a6f5765b44d1b..506abb6485188 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -154,6 +154,15 @@ def execute sql, name = nil 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.should be_like %{ SELECT FROM "users" GROUP BY foo } + end end describe 'delete' do From 5ab502a755d0031d229278b6f14123c45623dd04 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 16:37:11 -0700 Subject: [PATCH 0661/1492] adding "as" and to_sql to count nodes --- lib/arel/attributes/attribute.rb | 6 ++++++ lib/arel/nodes/count.rb | 13 ++++++++++++- lib/arel/visitors/to_sql.rb | 4 +++- spec/arel/attributes/attribute_spec.rb | 7 +++++++ spec/arel/nodes/count_spec.rb | 12 ++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 spec/arel/nodes/count_spec.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index ff17d6136ca0a..6087dc8e5292f 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -8,6 +8,10 @@ def eq other def in other Nodes::In.new self, other end + + def count + Nodes::Count.new [self] + end end class String < Attribute; end @@ -17,4 +21,6 @@ class Decimal < Attribute; end class Float < Attribute; end class Integer < Attribute; end end + + Attribute = Attributes::Attribute end diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index b7c4b609484f6..1222a791bb023 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -1,11 +1,22 @@ module Arel module Nodes class Count - attr_accessor :expressions, :distinct + attr_accessor :expressions, :distinct, :alias def initialize expr, distinct = false @expressions = expr @distinct = distinct + @alias = nil + end + + def as aliaz + self.alias = SqlLiteral.new(aliaz) + self + end + + def to_sql + viz = Visitors::ToSql.new Table.engine + viz.accept self end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 55b3259e81314..38cb81717dfd4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -64,7 +64,9 @@ def visit_Arel_Nodes_Group o end def visit_Arel_Nodes_Count o - "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})" + "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| + visit x + }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_TableAlias o diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index e6e6483e64ad4..f9eb56391e59b 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,13 @@ module Arel module Attributes describe 'attribute' do + describe '#count' do + it 'should return a count node' do + relation = Table.new(:users) + relation[:id].count.should be_kind_of Nodes::Count + end + end + describe '#eq' do it 'should return an equality node' do attribute = Attribute.new nil, nil, nil diff --git a/spec/arel/nodes/count_spec.rb b/spec/arel/nodes/count_spec.rb new file mode 100644 index 0000000000000..7013a164292dc --- /dev/null +++ b/spec/arel/nodes/count_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe Arel::Nodes::Count do + describe "as" do + it 'should alias the count' do + table = Arel::Table.new :users + table[:id].count.as('foo').to_sql.should be_like %{ + COUNT("users"."id") AS foo + } + end + end +end From 437a9a2225008ce859b4485dd5808843f40f8a58 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 16:45:25 -0700 Subject: [PATCH 0662/1492] count takes distinct --- lib/arel/attributes/attribute.rb | 4 ++-- spec/arel/attributes/attribute_spec.rb | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 6087dc8e5292f..464d78188a3c5 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -9,8 +9,8 @@ def in other Nodes::In.new self, other end - def count - Nodes::Count.new [self] + def count distinct = false + Nodes::Count.new [self], distinct end end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index f9eb56391e59b..d6f07f8d99dda 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -8,6 +8,13 @@ module Attributes relation = Table.new(:users) relation[:id].count.should be_kind_of Nodes::Count end + + it 'should take a distinct param' do + relation = Table.new(:users) + count = relation[:id].count(nil) + count.should be_kind_of Nodes::Count + count.distinct.should be_nil + end end describe '#eq' do From 49432b11c1e0ebd2c5ac0d1d673a2ea9e8799d39 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 16:56:54 -0700 Subject: [PATCH 0663/1492] moving deprecated constants to the correct place --- lib/arel/deprecated.rb | 1 + lib/arel/nodes/inner_join.rb | 3 --- lib/arel/nodes/outer_join.rb | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/arel/deprecated.rb b/lib/arel/deprecated.rb index 28f96a8a8cc72..31db11bd2ccc5 100644 --- a/lib/arel/deprecated.rb +++ b/lib/arel/deprecated.rb @@ -1,3 +1,4 @@ module Arel InnerJoin = Nodes::InnerJoin + OuterJoin = Nodes::OuterJoin end diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index 9fd2615f3946f..bf10eeac18684 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -3,7 +3,4 @@ module Nodes class InnerJoin < Arel::Nodes::Join end end - - # FIXME: backwards compat - InnerJoin = Nodes::InnerJoin end diff --git a/lib/arel/nodes/outer_join.rb b/lib/arel/nodes/outer_join.rb index 71da6e70d5f5c..bea5578b95c69 100644 --- a/lib/arel/nodes/outer_join.rb +++ b/lib/arel/nodes/outer_join.rb @@ -3,7 +3,4 @@ module Nodes class OuterJoin < Arel::Nodes::Join end end - - # FIXME: backwards compat - OuterJoin = Nodes::OuterJoin end From b4bcb93276834448ad9b59e91793ad75da26ce87 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Sep 2010 17:42:40 -0700 Subject: [PATCH 0664/1492] on can take multiple args --- lib/arel/select_manager.rb | 15 ++++++++++-- spec/arel/select_manager_spec.rb | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 2ad9555d27f4b..d8e113d5eeb4a 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -8,8 +8,8 @@ def initialize engine @ctx = @head.cores.last end - def on expr - @ctx.froms.last.constraint = Nodes::On.new(expr) + def on *exprs + @ctx.froms.last.constraint = Nodes::On.new(collapse(exprs)) self end @@ -89,5 +89,16 @@ def joins manager def to_a raise NotImplementedError end + + private + def collapse exprs + return exprs.first if exprs.length == 1 + + right = exprs.pop + left = exprs.pop + + right = Nodes::And.new left, right + exprs.reverse.inject(right) { |memo,expr| Nodes::And.new(expr, memo) } + end end end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 506abb6485188..335d044febba3 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -56,6 +56,45 @@ def execute sql, name = nil 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.should 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.should 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 + describe 'join' do it 'responds to join' do left = Table.new :users From 34f23c9f5f80a5998c181060331fa394e6d6663d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 13:25:42 -0700 Subject: [PATCH 0665/1492] Table#project takes multiple parameters --- lib/arel/table.rb | 4 ++-- spec/arel/table_spec.rb | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 28243e645e466..0e8b3782bbc19 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -53,8 +53,8 @@ def where condition tm.where condition end - def project thing - tm.project thing + def project *things + tm.project *things end def take amount diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 223453f7087ab..e67c371577383 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -79,10 +79,12 @@ module Arel describe 'project' do it 'can project' do manager = @relation.project SqlLiteral.new '*' - manager.to_sql.should be_like %{ - SELECT * - FROM "users" - } + manager.to_sql.should be_like %{ SELECT * FROM "users" } + end + + it 'takes multiple parameters' do + manager = @relation.project SqlLiteral.new('*'), SqlLiteral.new('*') + manager.to_sql.should be_like %{ SELECT *, * FROM "users" } end end From ab55d3bfc18348e9f43e4604e02c4c3db7a3e23c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 13:44:34 -0700 Subject: [PATCH 0666/1492] visiting symbols in the SQL visitor --- lib/arel/table.rb | 2 +- lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/to_sql.rb | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 0e8b3782bbc19..5d8f7c1ae5f4c 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -54,7 +54,7 @@ def where condition end def project *things - tm.project *things + tm.project(*things) end def take amount diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 1d44eba32f329..ebbb211dd66d8 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -81,6 +81,7 @@ def visit_Arel_Attribute o 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 visit_Arel_Nodes_Equality o visit_edge o, "left" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 38cb81717dfd4..f45bbab793304 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -129,6 +129,7 @@ def visit_Fixnum o; o end def visit_TrueClass o; quote(o) end def visit_String o; quote(o) end + def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end def visit_Date o; quote(o) end From 7b8944cb7662509d7ba6869ff571518ac7f848ea Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 14:36:10 -0700 Subject: [PATCH 0667/1492] adding a sum node --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/sum.rb | 12 ++++++++++++ lib/arel/visitors/to_sql.rb | 5 +++++ spec/arel/attributes/attribute_spec.rb | 17 +++++++++++++++++ 5 files changed, 39 insertions(+) create mode 100644 lib/arel/nodes/sum.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 464d78188a3c5..af9bbdd4780e0 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -12,6 +12,10 @@ def in other def count distinct = false Nodes::Count.new [self], distinct end + + def sum + Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id') + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index bf7ae830d0c76..24a71c54a2e08 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -5,6 +5,7 @@ require 'arel/nodes/in' require 'arel/nodes/count' +require 'arel/nodes/sum' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/sum.rb b/lib/arel/nodes/sum.rb new file mode 100644 index 0000000000000..ecd66aba7acfd --- /dev/null +++ b/lib/arel/nodes/sum.rb @@ -0,0 +1,12 @@ +module Arel + module Nodes + class Sum + attr_accessor :expressions, :alias + + def initialize expr, aliaz = nil + @expressions = expr + @alias = aliaz + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f45bbab793304..ada8aa6a16160 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -69,6 +69,11 @@ def visit_Arel_Nodes_Count o }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end + def visit_Arel_Nodes_Sum o + "SUM(#{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 diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index d6f07f8d99dda..018f23ea9fbc2 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,23 @@ module Arel module Attributes describe 'attribute' do + describe '#sum' do + it 'should create a SUM node' do + relation = Table.new(:users) + relation[:id].sum.should 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.should 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) From 368b1c6c42545726da25debfc9a2a5e6e4aaaa8c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 14:45:38 -0700 Subject: [PATCH 0668/1492] we can visit big decimal --- lib/arel/visitors/to_sql.rb | 3 +++ spec/arel/visitors/to_sql_spec.rb | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ada8aa6a16160..2a96444d5900f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -1,3 +1,5 @@ +require 'bigdecimal' + module Arel module Visitors class ToSql @@ -137,6 +139,7 @@ def visit_String o; quote(o) end def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end def visit_Date o; quote(o) end + def visit_BigDecimal o; quote(o) end DISPATCH = {} def visit object diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index 80f1e596647ed..a4722f73d45c7 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,10 @@ module Visitors @attr = Table.new(:users)[:id] end + it "should visit_BigDecimal" do + @visitor.accept BigDecimal.new('2.14') + end + it "should visit_Date" do @visitor.accept Date.today end From 301dfa5a3888a41ea36324a390241538249e9a53 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 14:54:44 -0700 Subject: [PATCH 0669/1492] as is implemented --- lib/arel/nodes/sum.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/arel/nodes/sum.rb b/lib/arel/nodes/sum.rb index ecd66aba7acfd..d81455fa5ff1f 100644 --- a/lib/arel/nodes/sum.rb +++ b/lib/arel/nodes/sum.rb @@ -7,6 +7,16 @@ def initialize expr, aliaz = nil @expressions = expr @alias = aliaz end + + def as aliaz + self.alias = SqlLiteral.new(aliaz) + self + end + + def to_sql + viz = Visitors::ToSql.new Table.engine + viz.accept self + end end end end From 7b122f9a336c8c780dcc5a29074f17f3ec493dc6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 15:08:00 -0700 Subject: [PATCH 0670/1492] adding maximum nodes --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/max.rb | 22 ++++++++++++++++++++++ lib/arel/visitors/to_sql.rb | 5 +++++ spec/arel/attributes/attribute_spec.rb | 17 +++++++++++++++++ spec/arel/nodes/sum_spec.rb | 12 ++++++++++++ 6 files changed, 61 insertions(+) create mode 100644 lib/arel/nodes/max.rb create mode 100644 spec/arel/nodes/sum_spec.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index af9bbdd4780e0..bb85af46345d7 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -16,6 +16,10 @@ def count distinct = false def sum Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id') end + + def maximum + Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 24a71c54a2e08..28b9e61fb6419 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -6,6 +6,7 @@ require 'arel/nodes/in' require 'arel/nodes/count' require 'arel/nodes/sum' +require 'arel/nodes/max' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/max.rb b/lib/arel/nodes/max.rb new file mode 100644 index 0000000000000..1766c56058dd6 --- /dev/null +++ b/lib/arel/nodes/max.rb @@ -0,0 +1,22 @@ +module Arel + module Nodes + class Max + attr_accessor :expressions, :alias + + def initialize expr, aliaz = nil + @expressions = expr + @alias = aliaz + end + + def as aliaz + self.alias = SqlLiteral.new(aliaz) + self + end + + def to_sql + viz = Visitors::ToSql.new Table.engine + viz.accept self + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2a96444d5900f..e1cf0f377804b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -76,6 +76,11 @@ def visit_Arel_Nodes_Sum o visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end + def visit_Arel_Nodes_Max o + "MAX(#{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 diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index 018f23ea9fbc2..449cc38dad053 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,23 @@ module Arel module Attributes describe 'attribute' do + describe '#maximum' do + it 'should create a MAX node' do + relation = Table.new(:users) + relation[:id].maximum.should 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.should be_like %{ + SELECT MAX("users"."id") AS max_id + FROM "users" + } + end + end + describe '#sum' do it 'should create a SUM node' do relation = Table.new(:users) diff --git a/spec/arel/nodes/sum_spec.rb b/spec/arel/nodes/sum_spec.rb new file mode 100644 index 0000000000000..7691b06590b0e --- /dev/null +++ b/spec/arel/nodes/sum_spec.rb @@ -0,0 +1,12 @@ +require 'spec_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.should be_like %{ + SUM("users"."id") AS foo + } + end + end +end From cb6d13877c8d85bd7ba7f7286dfc8b5ae98a50b3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 15:29:22 -0700 Subject: [PATCH 0671/1492] adding having nodes --- lib/arel/nodes.rb | 1 + lib/arel/nodes/having.rb | 11 +++++++++++ lib/arel/nodes/select_core.rb | 3 +++ lib/arel/select_manager.rb | 5 +++++ lib/arel/table.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 7 ++++++- spec/arel/table_spec.rb | 9 +++++++++ 7 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/having.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 28b9e61fb6419..4c24acb16a86d 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -7,6 +7,7 @@ require 'arel/nodes/count' require 'arel/nodes/sum' require 'arel/nodes/max' +require 'arel/nodes/having' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/having.rb b/lib/arel/nodes/having.rb new file mode 100644 index 0000000000000..1944a843919c3 --- /dev/null +++ b/lib/arel/nodes/having.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Having + attr_accessor :expr + + def initialize expr + @expr = expr + end + end + end +end diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 6e85968b31047..e52db6eb77e95 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -2,12 +2,14 @@ module Arel module Nodes class SelectCore attr_reader :froms, :projections, :wheres, :groups + attr_accessor :having def initialize @froms = [] @projections = [] @wheres = [] @groups = [] + @having = nil end def initialize_copy other @@ -16,6 +18,7 @@ def initialize_copy other @projections = @projections.clone @wheres = @wheres.clone @group = @groups.clone + @having = @having.clone if @having end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index d8e113d5eeb4a..4ddae13aa4920 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -40,6 +40,11 @@ def join relation, klass = Nodes::InnerJoin end end + def having expr + @ctx.having = Nodes::Having.new(expr) + self + end + def project *projections # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 5d8f7c1ae5f4c..ce21457e60079 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -61,6 +61,10 @@ def take amount tm.take amount end + def having expr + tm.having expr + end + def columns @columns ||= @engine.connection.columns(@name, "#{@name} Columns").map do |column| Attributes.for(column).new self, column.name, column diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index e1cf0f377804b..48c8c492e03f4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -57,10 +57,15 @@ def visit_Arel_Nodes_SelectCore o "SELECT #{o.projections.map { |x| visit x }.join ', '}", ("FROM #{o.froms.map { |x| visit x }.join ', ' }" unless o.froms.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?) + ("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_Having o + "HAVING #{visit o.expr}" + end + def visit_Arel_Nodes_Group o visit o.expr end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index e67c371577383..46d9dbddf4199 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,6 +6,15 @@ module Arel @relation = Table.new(:users) end + describe 'having' do + it 'adds a having clause' do + mgr = @relation.having @relation[:id].eq(10) + mgr.to_sql.should be_like %{ + SELECT FROM "users" HAVING "users"."id" = 10 + } + end + end + describe 'backwards compat' do describe 'joins' do it 'returns nil' do From 24000a51a7e61c065817e3910bd579e8bdf6f82f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 16:23:15 -0700 Subject: [PATCH 0672/1492] average node is added --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 2 ++ lib/arel/nodes/avg.rb | 6 ++++++ lib/arel/nodes/count.rb | 21 +++++---------------- lib/arel/nodes/function.rb | 22 ++++++++++++++++++++++ lib/arel/nodes/max.rb | 18 +----------------- lib/arel/nodes/sum.rb | 18 +----------------- lib/arel/visitors/to_sql.rb | 5 +++++ spec/arel/attributes/attribute_spec.rb | 17 +++++++++++++++++ 9 files changed, 63 insertions(+), 50 deletions(-) create mode 100644 lib/arel/nodes/avg.rb create mode 100644 lib/arel/nodes/function.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index bb85af46345d7..bd47aa12fd92d 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -20,6 +20,10 @@ def sum def maximum Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') end + + def average + Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 4c24acb16a86d..8e11760c18401 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -4,9 +4,11 @@ require 'arel/nodes/and' require 'arel/nodes/in' +require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/sum' require 'arel/nodes/max' +require 'arel/nodes/avg' require 'arel/nodes/having' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' diff --git a/lib/arel/nodes/avg.rb b/lib/arel/nodes/avg.rb new file mode 100644 index 0000000000000..8fc86fc21e862 --- /dev/null +++ b/lib/arel/nodes/avg.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Avg < Arel::Nodes::Function + end + end +end diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index 1222a791bb023..2f220dbfc81a1 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -1,22 +1,11 @@ module Arel module Nodes - class Count - attr_accessor :expressions, :distinct, :alias + class Count < Arel::Nodes::Function + attr_accessor :distinct - def initialize expr, distinct = false - @expressions = expr - @distinct = distinct - @alias = nil - end - - def as aliaz - self.alias = SqlLiteral.new(aliaz) - self - end - - def to_sql - viz = Visitors::ToSql.new Table.engine - viz.accept self + def initialize expr, distinct = false, aliaz = nil + super(expr, aliaz) + @distinct = distinct end end end diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb new file mode 100644 index 0000000000000..90c6ba23a2d29 --- /dev/null +++ b/lib/arel/nodes/function.rb @@ -0,0 +1,22 @@ +module Arel + module Nodes + class Function + attr_accessor :expressions, :alias + + def initialize expr, aliaz = nil + @expressions = expr + @alias = aliaz + end + + def as aliaz + self.alias = SqlLiteral.new(aliaz) + self + end + + def to_sql + viz = Visitors::ToSql.new Table.engine + viz.accept self + end + end + end +end diff --git a/lib/arel/nodes/max.rb b/lib/arel/nodes/max.rb index 1766c56058dd6..5af611b0d682d 100644 --- a/lib/arel/nodes/max.rb +++ b/lib/arel/nodes/max.rb @@ -1,22 +1,6 @@ module Arel module Nodes - class Max - attr_accessor :expressions, :alias - - def initialize expr, aliaz = nil - @expressions = expr - @alias = aliaz - end - - def as aliaz - self.alias = SqlLiteral.new(aliaz) - self - end - - def to_sql - viz = Visitors::ToSql.new Table.engine - viz.accept self - end + class Max < Arel::Nodes::Function end end end diff --git a/lib/arel/nodes/sum.rb b/lib/arel/nodes/sum.rb index d81455fa5ff1f..3e043b733090d 100644 --- a/lib/arel/nodes/sum.rb +++ b/lib/arel/nodes/sum.rb @@ -1,22 +1,6 @@ module Arel module Nodes - class Sum - attr_accessor :expressions, :alias - - def initialize expr, aliaz = nil - @expressions = expr - @alias = aliaz - end - - def as aliaz - self.alias = SqlLiteral.new(aliaz) - self - end - - def to_sql - viz = Visitors::ToSql.new Table.engine - viz.accept self - end + class Sum < Arel::Nodes::Function end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 48c8c492e03f4..60f30967cfef8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -86,6 +86,11 @@ def visit_Arel_Nodes_Max o visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end + def visit_Arel_Nodes_Avg o + "AVG(#{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 diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index 449cc38dad053..fb6954dc7ee00 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,23 @@ module Arel module Attributes describe 'attribute' do + describe '#average' do + it 'should create a AVG node' do + relation = Table.new(:users) + relation[:id].average.should 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.should 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) From 539572f023da47c47877fe31b58303cc4b7015b5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 16:29:08 -0700 Subject: [PATCH 0673/1492] we can visit floats! --- lib/arel/visitors/to_sql.rb | 1 + spec/arel/visitors/to_sql_spec.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 60f30967cfef8..12967d27ad3c4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -154,6 +154,7 @@ def visit_String o; quote(o) end def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end def visit_Date o; quote(o) end + def visit_Float o; quote(o) end def visit_BigDecimal o; quote(o) end DISPATCH = {} diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index a4722f73d45c7..39d7a7249c802 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,10 @@ module Visitors @attr = Table.new(:users)[:id] end + it "should visit_Float" do + @visitor.accept 2.14 + end + it "should visit_BigDecimal" do @visitor.accept BigDecimal.new('2.14') end From 5c9d75db74572567d66561f6fba6c10350c530ff Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 8 Sep 2010 17:32:44 -0700 Subject: [PATCH 0674/1492] adding locking node to the AST --- lib/arel/nodes.rb | 1 + lib/arel/nodes/lock.rb | 6 ++++++ lib/arel/nodes/select_statement.rb | 3 ++- lib/arel/select_manager.rb | 7 +++++++ lib/arel/table.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 8 +++++++- spec/arel/select_manager_spec.rb | 9 +++++++++ 7 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 lib/arel/nodes/lock.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 8e11760c18401..3d73de2f7acf9 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -4,6 +4,7 @@ require 'arel/nodes/and' require 'arel/nodes/in' +require 'arel/nodes/lock' require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/sum' diff --git a/lib/arel/nodes/lock.rb b/lib/arel/nodes/lock.rb new file mode 100644 index 0000000000000..3c7a72273f215 --- /dev/null +++ b/lib/arel/nodes/lock.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Lock + end + end +end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index b7c59da275a47..a96c02a545106 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -2,12 +2,13 @@ module Arel module Nodes class SelectStatement attr_reader :cores - attr_accessor :limit, :orders + attr_accessor :limit, :orders, :lock def initialize cores = [SelectCore.new] @cores = cores @orders = [] @limit = nil + @lock = nil end def initialize_copy other diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 4ddae13aa4920..bcfb1dc4eb1fe 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -8,6 +8,13 @@ def initialize engine @ctx = @head.cores.last end + def lock locking = true + # FIXME: do we even need to store this? If locking is +false+ shouldn't + # we just remove the node from the AST? + @head.lock = Nodes::Lock.new + self + end + def on *exprs @ctx.froms.last.constraint = Nodes::On.new(collapse(exprs)) self diff --git a/lib/arel/table.rb b/lib/arel/table.rb index ce21457e60079..ac832ed2b3827 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -26,6 +26,10 @@ def tm SelectManager.new(@engine).from(self) end + def from table + SelectManager.new(@engine).from table + end + def joins manager nil end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 12967d27ad3c4..0f2de092ea709 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -48,7 +48,8 @@ def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), - ("LIMIT #{o.limit}" if o.limit) + ("LIMIT #{o.limit}" if o.limit), + (visit(o.lock) if o.lock), ].compact.join ' ' end @@ -66,6 +67,11 @@ def visit_Arel_Nodes_Having o "HAVING #{visit o.expr}" end + # FIXME: this does nothing on SQLLite3, but should do things on other + # databases. + def visit_Arel_Nodes_Lock o + end + def visit_Arel_Nodes_Group o visit o.expr end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 335d044febba3..0b45b8180c507 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -25,6 +25,15 @@ def execute sql, name = nil end describe 'select manager' do + 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.should be_like %{ SELECT FROM "users" } + end + end + describe 'order' do it 'generates order clauses' do table = Table.new :users From 3a36df69b7b8913d333b508da0a6b6cdb68bc6f5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Sep 2010 09:27:29 -0700 Subject: [PATCH 0675/1492] Table#join will noop when nil is passed --- lib/arel/table.rb | 2 ++ spec/arel/table_spec.rb | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index ac832ed2b3827..58e0c469592c2 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -35,6 +35,8 @@ def joins manager end def join relation, klass = Nodes::InnerJoin + return tm unless relation + sm = SelectManager.new(@engine) case relation when String, Nodes::SqlLiteral diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 46d9dbddf4199..6512ab310bf98 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -23,6 +23,12 @@ module Arel end describe 'join' do + it 'noops on nil' do + mgr = @relation.join nil + + mgr.to_sql.should be_like %{ SELECT FROM "users" } + end + it 'takes a second argument for join type' do right = @relation.alias predicate = @relation[:id].eq(right[:id]) From 67d2f9a922314e4ac51d99981efe886a3a7aca86 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Sep 2010 15:20:25 -0700 Subject: [PATCH 0676/1492] adding a Value node so that SqlLiteral values may be used --- lib/arel/insert_manager.rb | 17 ++++++++++++----- lib/arel/nodes.rb | 1 + lib/arel/nodes/insert_statement.rb | 4 ++-- lib/arel/nodes/values.rb | 11 +++++++++++ lib/arel/select_manager.rb | 8 ++++++++ lib/arel/sql/engine.rb | 2 +- lib/arel/visitors/to_sql.rb | 11 +++++++---- spec/arel/insert_manager_spec.rb | 5 ++--- spec/arel/select_manager_spec.rb | 15 +++++++++++++++ 9 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 lib/arel/nodes/values.rb diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index accabb4377bfb..75e6299def666 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -11,16 +11,23 @@ def into table end def columns; @head.columns end - def values; @head.values end + def values= val; @head.values = val; end def insert fields return if fields.empty? - @head.relation ||= fields.first.first.relation + if String === fields + @head.values = SqlLiteral.new(fields) + else + @head.relation ||= fields.first.first.relation - fields.each do |column, value| - @head.columns << column - @head.values << value + values = [] + + fields.each do |column, value| + @head.columns << column + values << value + end + @head.values = Nodes::Values.new values end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 3d73de2f7acf9..2894deab57795 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -7,6 +7,7 @@ require 'arel/nodes/lock' require 'arel/nodes/function' require 'arel/nodes/count' +require 'arel/nodes/values' require 'arel/nodes/sum' require 'arel/nodes/max' require 'arel/nodes/avg' diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index 629e7a851383e..a5e1a0bb9bc50 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -6,13 +6,13 @@ class InsertStatement def initialize @relation = nil @columns = [] - @values = [] + @values = nil end def initialize_copy other super @columns = @columns.clone - @values = @values.clone + @values = @values.clone if @values end end end diff --git a/lib/arel/nodes/values.rb b/lib/arel/nodes/values.rb new file mode 100644 index 0000000000000..eab70a362aaef --- /dev/null +++ b/lib/arel/nodes/values.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Values + attr_accessor :expressions + + def initialize exprs + @expressions = exprs + end + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index bcfb1dc4eb1fe..2be6d52fef44c 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -102,6 +102,14 @@ def to_a raise NotImplementedError end + # FIXME: this method should go away + def insert values + im = InsertManager.new @engine + im.into @ctx.froms.last + im.insert values + @engine.connection.insert im.to_sql + end + private def collapse exprs return exprs.first if exprs.length == 1 diff --git a/lib/arel/sql/engine.rb b/lib/arel/sql/engine.rb index d1a3880735912..8917f5f29423c 100644 --- a/lib/arel/sql/engine.rb +++ b/lib/arel/sql/engine.rb @@ -2,7 +2,7 @@ module Arel module Sql class Engine def self.new thing - warn "#{caller.first} -- Engine will be removed" + #warn "#{caller.first} -- Engine will be removed" thing end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0f2de092ea709..25b7f005ea99d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -37,13 +37,16 @@ def visit_Arel_Nodes_InsertStatement o quote_column_name x.name }.join ', '})" unless o.columns.empty?), - ("VALUES (#{o.values.map { |value| - value ? visit(value) : 'NULL' - }.join ', '})" unless o.values.empty?), - + (visit o.values if o.values), ].compact.join ' ' end + def visit_Arel_Nodes_Values o + "VALUES (#{o.expressions.map { |value| + value ? visit(value) : 'NULL' + }.join ', '})" + end + def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit x }.join, diff --git a/spec/arel/insert_manager_spec.rb b/spec/arel/insert_manager_spec.rb index ed0725e79df25..807f1324d283e 100644 --- a/spec/arel/insert_manager_spec.rb +++ b/spec/arel/insert_manager_spec.rb @@ -88,7 +88,7 @@ module Arel manager = Arel::InsertManager.new Table.engine manager.into table - manager.values << 1 + manager.values = Nodes::Values.new [1] manager.to_sql.should be_like %{ INSERT INTO "users" VALUES (1) } @@ -101,8 +101,7 @@ module Arel manager = Arel::InsertManager.new Table.engine manager.into table - manager.values << 1 - manager.values << "aaron" + manager.values = Nodes::Values.new [1, 'aaron'] manager.columns << table[:id] manager.columns << table[:name] manager.to_sql.should be_like %{ diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 0b45b8180c507..883a518acafe7 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -22,9 +22,24 @@ def execute sql, name = nil end alias :update :execute alias :delete :execute + alias :insert :execute end describe 'select manager' do + 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.should be_like %{ + INSERT INTO "users" VALUES(NULL) + } + end + end + describe 'lock' do # This should fail on other databases it 'adds a lock node' do From ef85edac7b2d7119680fe691bd9eab206e8a0d41 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Sep 2010 15:50:14 -0700 Subject: [PATCH 0677/1492] adding a deprecated method for rails --- lib/arel/select_manager.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 2be6d52fef44c..678e289814189 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -8,6 +8,12 @@ def initialize engine @ctx = @head.cores.last end + def where_clauses + warn "STOP CALLING ME" if $VERBOSE + to_sql = Visitors::ToSql.new @engine + @ctx.wheres.map { |c| to_sql.accept c } + end + def lock locking = true # FIXME: do we even need to store this? If locking is +false+ shouldn't # we just remove the node from the AST? From 9efae8f92de2361d50dc3ee9b674b2da1e782575 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Sep 2010 15:58:06 -0700 Subject: [PATCH 0678/1492] adding taken method to return the limit value --- lib/arel/select_manager.rb | 6 +++++- spec/arel/select_manager_spec.rb | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 678e289814189..569b631c7f7e7 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -8,8 +8,12 @@ def initialize engine @ctx = @head.cores.last end + def taken + @head.limit + end + def where_clauses - warn "STOP CALLING ME" if $VERBOSE + warn "where_clauses is deprecated" if $VERBOSE to_sql = Visitors::ToSql.new @engine @ctx.wheres.map { |c| to_sql.accept c } end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 883a518acafe7..5e4059084fed5 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -26,6 +26,15 @@ def execute sql, name = nil end describe 'select manager' do + describe 'taken' do + it 'should return limit' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.take 10 + check manager.taken.should == 10 + end + end + describe 'insert' do it 'uses the select FROM' do engine = EngineProxy.new Table.engine From ac2bdd1dd31c8b89578ae7f490a898838b9ef6e0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 09:47:50 -0700 Subject: [PATCH 0679/1492] adding an offset node --- lib/arel/nodes.rb | 1 + lib/arel/nodes/offset.rb | 11 +++++++++++ lib/arel/nodes/select_statement.rb | 3 ++- lib/arel/select_manager.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 5 +++++ spec/arel/select_manager_spec.rb | 15 +++++++++++++++ 6 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/offset.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 2894deab57795..89e28f138cae4 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -8,6 +8,7 @@ require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/values' +require 'arel/nodes/offset' require 'arel/nodes/sum' require 'arel/nodes/max' require 'arel/nodes/avg' diff --git a/lib/arel/nodes/offset.rb b/lib/arel/nodes/offset.rb new file mode 100644 index 0000000000000..baa4068d935c0 --- /dev/null +++ b/lib/arel/nodes/offset.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Offset + attr_accessor :value + + def initialize value + @value = value + end + end + end +end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index a96c02a545106..6272fd126da2a 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -2,13 +2,14 @@ module Arel module Nodes class SelectStatement attr_reader :cores - attr_accessor :limit, :orders, :lock + attr_accessor :limit, :orders, :lock, :offset def initialize cores = [SelectCore.new] @cores = cores @orders = [] @limit = nil @lock = nil + @offset = nil end def initialize_copy other diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 569b631c7f7e7..ce749c49773b7 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -12,6 +12,11 @@ def taken @head.limit end + def skip amount + @head.offset = Nodes::Offset.new(amount) + self + end + def where_clauses warn "where_clauses is deprecated" if $VERBOSE to_sql = Visitors::ToSql.new @engine diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 25b7f005ea99d..d45253abd5840 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -52,6 +52,7 @@ def visit_Arel_Nodes_SelectStatement o o.cores.map { |x| visit x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), ("LIMIT #{o.limit}" if o.limit), + (visit(o.offset) if o.offset), (visit(o.lock) if o.lock), ].compact.join ' ' end @@ -70,6 +71,10 @@ def visit_Arel_Nodes_Having o "HAVING #{visit o.expr}" end + def visit_Arel_Nodes_Offset o + "OFFSET #{visit o.value}" + end + # FIXME: this does nothing on SQLLite3, but should do things on other # databases. def visit_Arel_Nodes_Lock o diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 5e4059084fed5..9a2b14f920158 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -26,6 +26,21 @@ def execute sql, name = nil end describe 'select manager' do + describe 'skip' do + it 'should add an offset' do + table = Table.new :users + mgr = table.from table + mgr.skip 10 + mgr.to_sql.should 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.should be_like %{ SELECT FROM "users" OFFSET 10 } + end + end + describe 'taken' do it 'should return limit' do table = Table.new :users From 5eaf76df2d442840926eb82d1d2265c2db2aef3f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 09:51:03 -0700 Subject: [PATCH 0680/1492] we can visit DateTime --- lib/arel/visitors/to_sql.rb | 1 + spec/arel/visitors/to_sql_spec.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d45253abd5840..dc3dbc14c0418 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -168,6 +168,7 @@ def visit_String o; quote(o) end def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end def visit_Date o; quote(o) end + def visit_DateTime o; quote(o) end def visit_Float o; quote(o) end def visit_BigDecimal o; quote(o) end diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index 39d7a7249c802..ed8487c6ebf8c 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,10 @@ module Visitors @attr = Table.new(:users)[:id] end + it "should visit_DateTime" do + @visitor.accept DateTime.now + end + it "should visit_Float" do @visitor.accept 2.14 end From e7648f26921d66f1375645808a5266d8e0e3edcf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 10:45:05 -0700 Subject: [PATCH 0681/1492] adding "orders" method --- lib/arel/select_manager.rb | 4 ++++ spec/arel/select_manager_spec.rb | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index ce749c49773b7..6942014208da1 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -89,6 +89,10 @@ def order *expr self end + def orders + @head.orders + end + def wheres Compatibility::Wheres.new @engine, @ctx.wheres end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 9a2b14f920158..e5124a16c7730 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -73,6 +73,16 @@ def execute sql, name = nil 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] + check manager.orders.should == [order] + end + end + describe 'order' do it 'generates order clauses' do table = Table.new :users From 6032d40c1d1c7a7681f145c30b4c26386395ba45 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 11:39:50 -0700 Subject: [PATCH 0682/1492] added greater than or equal to node --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/greater_than_or_equal.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/attributes/attribute_spec.rb | 16 ++++++++++++++++ 5 files changed, 31 insertions(+) create mode 100644 lib/arel/nodes/greater_than_or_equal.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index bd47aa12fd92d..62bef5f1cf691 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -24,6 +24,10 @@ def maximum def average Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') end + + def gteq right + Nodes::GreaterThanOrEqual.new self, right + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 89e28f138cae4..6a6c6ece7786b 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -2,6 +2,7 @@ require 'arel/nodes/equality' require 'arel/nodes/or' require 'arel/nodes/and' +require 'arel/nodes/greater_than_or_equal' require 'arel/nodes/in' require 'arel/nodes/lock' diff --git a/lib/arel/nodes/greater_than_or_equal.rb b/lib/arel/nodes/greater_than_or_equal.rb new file mode 100644 index 0000000000000..a8cfaab04e6f3 --- /dev/null +++ b/lib/arel/nodes/greater_than_or_equal.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class GreaterThanOrEqual < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index dc3dbc14c0418..2b34fb63dceb1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -109,6 +109,10 @@ def visit_Arel_Nodes_TableAlias o "#{visit o.relation} #{quote_table_name o.name}" end + def visit_Arel_Nodes_GreaterThanOrEqual o + "#{visit o.left} >= #{visit o.right}" + end + def visit_Arel_Nodes_StringJoin o "#{visit o.left} #{visit o.right}" end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index fb6954dc7ee00..ee12aa23710ad 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,22 @@ module Arel module Attributes describe 'attribute' do + describe '#gteq' do + it 'should create a GreaterThanOrEqual node' do + relation = Table.new(:users) + relation[:id].gteq(10).should 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.should be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" >= 10 + } + end + end + describe '#average' do it 'should create a AVG node' do relation = Table.new(:users) From 9fdaf497cb346696ea538308b77ec07f051cd569 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 11:47:03 -0700 Subject: [PATCH 0683/1492] added a greater than node --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/greater_than.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/attributes/attribute_spec.rb | 16 ++++++++++++++++ 5 files changed, 31 insertions(+) create mode 100644 lib/arel/nodes/greater_than.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 62bef5f1cf691..d77574f33ea7d 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -28,6 +28,10 @@ def average def gteq right Nodes::GreaterThanOrEqual.new self, right end + + def gt right + Nodes::GreaterThan.new self, right + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 6a6c6ece7786b..1215f3f00c0b3 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -2,6 +2,7 @@ require 'arel/nodes/equality' require 'arel/nodes/or' require 'arel/nodes/and' +require 'arel/nodes/greater_than' require 'arel/nodes/greater_than_or_equal' require 'arel/nodes/in' diff --git a/lib/arel/nodes/greater_than.rb b/lib/arel/nodes/greater_than.rb new file mode 100644 index 0000000000000..2e03cc2e186e0 --- /dev/null +++ b/lib/arel/nodes/greater_than.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class GreaterThan < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2b34fb63dceb1..093deedee5a3c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -113,6 +113,10 @@ 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_StringJoin o "#{visit o.left} #{visit o.right}" end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index ee12aa23710ad..ae0f70c5ba572 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,22 @@ module Arel module Attributes describe 'attribute' do + describe '#gt' do + it 'should create a GreaterThan node' do + relation = Table.new(:users) + relation[:id].gt(10).should 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.should be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" > 10 + } + end + end + describe '#gteq' do it 'should create a GreaterThanOrEqual node' do relation = Table.new(:users) From e06061089735b34ac10465684db5a08d90623469 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 13:26:30 -0700 Subject: [PATCH 0684/1492] equality should handle nil correctly --- lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/to_sql.rb | 4 +++- spec/arel/visitors/to_sql_spec.rb | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index ebbb211dd66d8..abf28968cf5a6 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -94,6 +94,7 @@ def visit_String o alias :visit_Time :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_Fixnum :visit_String alias :visit_Symbol :visit_String diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 093deedee5a3c..f70cae943044e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -151,7 +151,8 @@ def visit_Arel_Nodes_Or o def visit_Arel_Nodes_Equality o right = o.right - right = right ? visit(right) : 'NULL' + # FIXME: maybe we should visit NilClass? + right = right.nil? ? 'NULL' : visit(right) "#{visit o.left} = #{right}" end @@ -179,6 +180,7 @@ def visit_Date o; quote(o) end def visit_DateTime o; quote(o) end def visit_Float o; quote(o) end def visit_BigDecimal o; quote(o) end + def visit_FalseClass o; quote(o) end DISPATCH = {} def visit object diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index ed8487c6ebf8c..f8327b02f67d9 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -8,6 +8,13 @@ module Visitors @attr = Table.new(:users)[:id] end + describe 'equality' do + it 'should handle false' do + sql = @visitor.accept Nodes::Equality.new(false, false) + sql.should be_like %{ 'f' = 'f' } + end + end + it "should visit_DateTime" do @visitor.accept DateTime.now end From 1ba8ac0848f40c7fa18c9e7bdac944a50d3c348c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 13:36:42 -0700 Subject: [PATCH 0685/1492] differentiating equality and assignment --- lib/arel/nodes.rb | 1 + lib/arel/nodes/assignment.rb | 6 ++++++ lib/arel/update_manager.rb | 2 +- lib/arel/visitors/to_sql.rb | 15 +++++++++++++-- 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 lib/arel/nodes/assignment.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 1215f3f00c0b3..1f31219417839 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,5 +1,6 @@ require 'arel/nodes/binary' require 'arel/nodes/equality' +require 'arel/nodes/assignment' require 'arel/nodes/or' require 'arel/nodes/and' require 'arel/nodes/greater_than' diff --git a/lib/arel/nodes/assignment.rb b/lib/arel/nodes/assignment.rb new file mode 100644 index 0000000000000..693bd5afe6645 --- /dev/null +++ b/lib/arel/nodes/assignment.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Assignment < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index cd4342529bb49..484230c4e1072 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -26,7 +26,7 @@ def set values @head.values = [values] else @head.values = values.map { |column,value| - Nodes::Equality.new( + Nodes::Assignment.new( Nodes::UnqualifiedColumn.new(column), value ) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f70cae943044e..8638bf43c30f8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -149,13 +149,24 @@ def visit_Arel_Nodes_Or o "#{visit o.left} OR #{visit o.right}" end - def visit_Arel_Nodes_Equality o + def visit_Arel_Nodes_Assignment o right = o.right - # FIXME: maybe we should visit NilClass? + right = right.nil? ? 'NULL' : visit(right) "#{visit o.left} = #{right}" end + def visit_Arel_Nodes_Equality o + right = o.right + + # FIXME: maybe we should visit NilClass? + if right.nil? + "#{visit o.left} IS NULL" + else + "#{visit o.left} = #{visit right}" + end + end + def visit_Arel_Nodes_UnqualifiedColumn o "#{quote_column_name o.name}" end From f0f6b7fb90b936cb78d786896598486821db6559 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 16:58:19 -0700 Subject: [PATCH 0686/1492] adding not equal node, column names are expected to be symbols --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/compatibility/wheres.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/not_equal.rb | 6 ++++++ lib/arel/nodes/table_alias.rb | 2 +- lib/arel/table.rb | 4 ++-- lib/arel/visitors/to_sql.rb | 11 ++++++++++- spec/arel/attributes/attribute_spec.rb | 25 +++++++++++++++++++++++++ spec/arel/table_spec.rb | 4 ++-- 9 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 lib/arel/nodes/not_equal.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index d77574f33ea7d..617112f68120b 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -1,6 +1,10 @@ module Arel module Attributes class Attribute < Struct.new :relation, :name, :column + def not_eq other + Nodes::NotEqual.new self, other + end + def eq other Nodes::Equality.new self, other end diff --git a/lib/arel/compatibility/wheres.rb b/lib/arel/compatibility/wheres.rb index eeb7a2fa38e2b..b73b1786514c7 100644 --- a/lib/arel/compatibility/wheres.rb +++ b/lib/arel/compatibility/wheres.rb @@ -8,6 +8,10 @@ module Value # :nodoc: def value visitor.accept self end + + def name + super.to_sym + end end def initialize engine, collection diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 1f31219417839..7510214cdf448 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,5 +1,6 @@ require 'arel/nodes/binary' require 'arel/nodes/equality' +require 'arel/nodes/not_equal' require 'arel/nodes/assignment' require 'arel/nodes/or' require 'arel/nodes/and' diff --git a/lib/arel/nodes/not_equal.rb b/lib/arel/nodes/not_equal.rb new file mode 100644 index 0000000000000..7f892940cb825 --- /dev/null +++ b/lib/arel/nodes/not_equal.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class NotEqual < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 4f1d70ee54ee5..656a820a605ed 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -12,7 +12,7 @@ def initialize name, relation end def [] name - name = name.to_s + name = name.to_sym columns.find { |column| column.name == name } end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 58e0c469592c2..efdc34ed94804 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -73,12 +73,12 @@ def having expr def columns @columns ||= @engine.connection.columns(@name, "#{@name} Columns").map do |column| - Attributes.for(column).new self, column.name, column + Attributes.for(column).new self, column.name.to_sym, column end end def [] name - name = name.to_s + name = name.to_sym columns.find { |column| column.name == name } end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8638bf43c30f8..761f3157636b5 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -159,7 +159,6 @@ def visit_Arel_Nodes_Assignment o def visit_Arel_Nodes_Equality o right = o.right - # FIXME: maybe we should visit NilClass? if right.nil? "#{visit o.left} IS NULL" else @@ -167,6 +166,16 @@ def visit_Arel_Nodes_Equality o 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_UnqualifiedColumn o "#{quote_column_name o.name}" end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index ae0f70c5ba572..6679ca8b7abd3 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -3,6 +3,31 @@ 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).should 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.should 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.should be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" IS NOT NULL + } + end + end + describe '#gt' do it 'should create a GreaterThan node' do relation = Table.new(:users) diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 6512ab310bf98..7cc0b20a25ebd 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -120,7 +120,7 @@ module Arel it 'returns a list of columns' do columns = @relation.columns check columns.length.should == 2 - columns.map { |x| x.name }.sort.should == %w{ name id }.sort + columns.map { |x| x.name.to_s }.sort.should == %w{ name id }.sort end end @@ -136,7 +136,7 @@ module Arel describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do column = @relation[:id] - check column.name.should == 'id' + check column.name.should == :id column.should be_kind_of Attributes::Integer end end From 54448c52099395220344bd760cefe35f7f551e4a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 17:05:10 -0700 Subject: [PATCH 0687/1492] adding some backwards compatibility for AR --- lib/arel/select_manager.rb | 2 ++ spec/arel/select_manager_spec.rb | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 6942014208da1..ce74daab82290 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -63,6 +63,8 @@ def join relation, klass = Nodes::InnerJoin end def having expr + expr = Nodes::SqlLiteral.new(expr) if String === expr + @ctx.having = Nodes::Having.new(expr) self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index e5124a16c7730..bf3b63ff493a8 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -26,6 +26,17 @@ def execute sql, name = nil end describe 'select manager' do + describe 'backwards compatibility' do + describe '#having' do + it 'converts strings to SQLLiterals' do + table = Table.new :users + mgr = table.from table + mgr.having 'foo' + mgr.to_sql.should be_like %{ SELECT FROM "users" HAVING foo } + end + end + end + describe 'skip' do it 'should add an offset' do table = Table.new :users From 77701cb501fe0dfe83ec9d13163c85423bc2770d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 17:52:46 -0700 Subject: [PATCH 0688/1492] fixing indentation --- spec/arel/select_manager_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index bf3b63ff493a8..11028ed27b91a 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -32,7 +32,7 @@ def execute sql, name = nil table = Table.new :users mgr = table.from table mgr.having 'foo' - mgr.to_sql.should be_like %{ SELECT FROM "users" HAVING foo } + mgr.to_sql.should be_like %{ SELECT FROM "users" HAVING foo } end end end From 458ef3fb7d51ef2e9d1cd9513bdc225daffe8146 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 18:01:45 -0700 Subject: [PATCH 0689/1492] inserting false works a bit better --- lib/arel/visitors/to_sql.rb | 2 +- spec/arel/insert_manager_spec.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 761f3157636b5..66e997a98617c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -43,7 +43,7 @@ def visit_Arel_Nodes_InsertStatement o def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.map { |value| - value ? visit(value) : 'NULL' + value.nil? ? 'NULL' : visit(value) }.join ', '})" end diff --git a/spec/arel/insert_manager_spec.rb b/spec/arel/insert_manager_spec.rb index 807f1324d283e..a6d34f43579c1 100644 --- a/spec/arel/insert_manager_spec.rb +++ b/spec/arel/insert_manager_spec.rb @@ -9,6 +9,15 @@ module Arel end describe 'insert' do + it "inserts false" do + table = Table.new(:users) + manager = Arel::InsertManager.new Table.engine + manager.insert [[table[:id], false]] + manager.to_sql.should be_like %{ + INSERT INTO "users" ("id") VALUES ('f') + } + end + it "inserts null" do table = Table.new(:users) manager = Arel::InsertManager.new Table.engine From e4e81cdcf00d9bc023502bf1ce2e6dad40296835 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 18:19:31 -0700 Subject: [PATCH 0690/1492] backwards compat --- lib/arel.rb | 2 +- lib/arel/nodes/count.rb | 2 ++ spec/arel/nodes/count_spec.rb | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 4772e9f4b03ac..d1c2e44567bab 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -8,6 +8,7 @@ #### these are deprecated # The Arel::Relation constant is referenced in Rails require 'arel/relation' +require 'arel/expression' #### require 'arel/tree_manager' @@ -21,7 +22,6 @@ require 'arel/deprecated' require 'arel/sql/engine' require 'arel/sql_literal' -require 'arel/expression' #### require 'arel/visitors/to_sql' diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index 2f220dbfc81a1..354659ef701f5 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -1,6 +1,8 @@ module Arel module Nodes class Count < Arel::Nodes::Function + include Arel::Expression + attr_accessor :distinct def initialize expr, distinct = false, aliaz = nil diff --git a/spec/arel/nodes/count_spec.rb b/spec/arel/nodes/count_spec.rb index 7013a164292dc..185b4d8eb92fc 100644 --- a/spec/arel/nodes/count_spec.rb +++ b/spec/arel/nodes/count_spec.rb @@ -1,6 +1,12 @@ require 'spec_helper' describe Arel::Nodes::Count do + describe 'backwards compatibility' do + it 'must be an expression' do + Arel::Nodes::Count.new('foo').should be_kind_of Arel::Expression + end + end + describe "as" do it 'should alias the count' do table = Arel::Table.new :users From 84e8875c559dd63f69bad536a660dfe2666cf289 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Sep 2010 21:40:59 -0700 Subject: [PATCH 0691/1492] implementing locked --- lib/arel/select_manager.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index ce74daab82290..c62101077a3a8 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -30,6 +30,10 @@ def lock locking = true self end + def locked + @head.lock + end + def on *exprs @ctx.froms.last.constraint = Nodes::On.new(collapse(exprs)) self From b9402889ff4cc6fc18ad0d035fecc8e36f320f90 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 11 Sep 2010 11:28:00 +0800 Subject: [PATCH 0692/1492] Add maximum to SqlLiteral. --- lib/arel/nodes/sql_literal.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 526d08844981d..6471469d9fb8a 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -4,6 +4,10 @@ class SqlLiteral < String def count distinct = false Count.new [self], distinct end + + def maximum + Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') + end end end end From 8ce904933db3ec9884194f07881581ec0cc8281e Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 11 Sep 2010 11:13:04 +0800 Subject: [PATCH 0693/1492] Visit ActiveSupport Multibyte Chars if ActiveSupport is defined. --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 66e997a98617c..599a25836a8dc 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -194,6 +194,7 @@ def visit_Fixnum o; o end def visit_TrueClass o; quote(o) end def visit_String o; quote(o) end + def visit_ActiveSupport_Multibyte_Chars o; quote(o) end if defined?(ActiveSupport) def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end def visit_Date o; quote(o) end From 5daafa8e959acc64fc19e9522470282ac0f25f33 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 11 Sep 2010 11:34:18 +0800 Subject: [PATCH 0694/1492] Add Min node. --- lib/arel/attributes/attribute.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/min.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 5 +++++ spec/arel/attributes/attribute_spec.rb | 7 +++++++ 5 files changed, 23 insertions(+) create mode 100644 lib/arel/nodes/min.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 617112f68120b..34c1f45ba6677 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -25,6 +25,10 @@ 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 diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 7510214cdf448..3ffc81d7df0bc 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -15,6 +15,7 @@ require 'arel/nodes/offset' require 'arel/nodes/sum' require 'arel/nodes/max' +require 'arel/nodes/min' require 'arel/nodes/avg' require 'arel/nodes/having' require 'arel/nodes/sql_literal' diff --git a/lib/arel/nodes/min.rb b/lib/arel/nodes/min.rb new file mode 100644 index 0000000000000..bdc137185824f --- /dev/null +++ b/lib/arel/nodes/min.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Min < Arel::Nodes::Function + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 599a25836a8dc..65dc5fdb83615 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -100,6 +100,11 @@ def visit_Arel_Nodes_Max o visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end + def visit_Arel_Nodes_Min o + "MIN(#{o.expressions.map { |x| + visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + end + def visit_Arel_Nodes_Avg o "AVG(#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/arel/attributes/attribute_spec.rb index 6679ca8b7abd3..faef096792694 100644 --- a/spec/arel/attributes/attribute_spec.rb +++ b/spec/arel/attributes/attribute_spec.rb @@ -94,6 +94,13 @@ module Attributes end end + describe '#minimum' do + it 'should create a Min node' do + relation = Table.new(:users) + relation[:id].minimum.should be_kind_of Nodes::Min + end + end + describe '#sum' do it 'should create a SUM node' do relation = Table.new(:users) From 963fc7d883351dd1623434428decb9015bd4484a Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 11 Sep 2010 11:20:00 +0800 Subject: [PATCH 0695/1492] We can visit hash. --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 65dc5fdb83615..be9a62325a6c2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -199,6 +199,7 @@ def visit_Fixnum o; o end def visit_TrueClass o; quote(o) end def visit_String o; quote(o) end + def visit_Hash o; quote(o) end def visit_ActiveSupport_Multibyte_Chars o; quote(o) end if defined?(ActiveSupport) def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end From 12ff6e13498a1990af58d5bff30dbf44095348e6 Mon Sep 17 00:00:00 2001 From: Emilio Tagua Date: Sat, 11 Sep 2010 12:48:32 +0800 Subject: [PATCH 0696/1492] Add test for Hash visitor. --- spec/arel/visitors/to_sql_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index f8327b02f67d9..c8bfb845c1496 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -23,6 +23,10 @@ module Visitors @visitor.accept 2.14 end + it "should visit_Hash" do + @visitor.accept({:a => 1}) + end + it "should visit_BigDecimal" do @visitor.accept BigDecimal.new('2.14') end From 14ad563ee1e82008bcbd56ca6ce69ce35609c8ac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 15:45:59 -0700 Subject: [PATCH 0697/1492] supporting StringJoin in the JoinSQL visitor --- lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/join_sql.rb | 4 ++++ spec/arel/select_manager_spec.rb | 9 +++++++++ 3 files changed, 14 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index abf28968cf5a6..9ecb65eae19ac 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -98,6 +98,7 @@ def visit_String o alias :visit_Arel_SqlLiteral :visit_String alias :visit_Fixnum :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| diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 0353d687ebcaa..bca15bbb0aa11 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -13,6 +13,10 @@ def visit_Arel_Nodes_SelectCore o o.froms.grep(Nodes::Join).map { |x| visit x }.join ', ' end + def visit_Arel_Nodes_StringJoin o + visit o.right + end + def visit_Arel_Nodes_OuterJoin o "OUTER JOIN #{visit o.right} #{visit o.constraint}" end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 11028ed27b91a..ba4a51eb5615c 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -223,6 +223,15 @@ def execute sql, name = nil } check manager.joins(manager).should == manager.join_sql end + + it 'returns string join sql' do + table = Table.new :users + aliaz = table.alias + manager = Arel::SelectManager.new Table.engine + manager.from Nodes::StringJoin.new(table, 'hello') + manager.join_sql.should be_like %{ 'hello' } + check manager.joins(manager).should == manager.join_sql + end end describe 'order_clauses' do From f6d6d0329705101d80ca980633bb56e5742fd95a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 16:35:13 -0700 Subject: [PATCH 0698/1492] only visiting left side if left side is a JOIN --- lib/arel/visitors/join_sql.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index bca15bbb0aa11..c1e00ea8f00de 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -14,7 +14,10 @@ def visit_Arel_Nodes_SelectCore o end def visit_Arel_Nodes_StringJoin o - visit o.right + [ + (visit o.left if Nodes::Join === o.left), + visit(o.right) + ].join ' ' end def visit_Arel_Nodes_OuterJoin o From dcb46b00163f454fa275dfc66690180dcb8f7047 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 16:53:12 -0700 Subject: [PATCH 0699/1492] adding some backwards compatibility --- lib/arel/select_manager.rb | 4 ++++ spec/arel/select_manager_spec.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index c62101077a3a8..0f70a461a31fc 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -50,6 +50,10 @@ def group *columns end def from table + if String === table + return self if @ctx.froms.any? { |x| x.name.to_s == table } + end + @ctx.froms << table self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index ba4a51eb5615c..86a4daee44d6e 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -27,6 +27,18 @@ def execute sql, name = nil describe 'select manager' do describe 'backwards compatibility' do + 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.should be_like 'SELECT "users"."id" FROM "users"' + end + end + describe '#having' do it 'converts strings to SQLLiterals' do table = Table.new :users From 53159770271c24a4c0ba6bca6a9e09683157dd9d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 17:49:08 -0700 Subject: [PATCH 0700/1492] visiting constraint edges of joins --- lib/arel/visitors/dot.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 9ecb65eae19ac..0fc6c1757f21f 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -39,9 +39,14 @@ def visit_Arel_Nodes_Count o visit_edge o, "distinct" end + def visit_Arel_Nodes_On o + visit_edge o, "expr" + end + def visit_Arel_Nodes_StringJoin o visit_edge o, "left" visit_edge o, "right" + visit_edge o, "constraint" end alias :visit_Arel_Nodes_InnerJoin :visit_Arel_Nodes_StringJoin alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_StringJoin From d4abd35feb84db37815ecd8f0b37f657317105c1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 18:15:21 -0700 Subject: [PATCH 0701/1492] using table_alias when :as is passed to the constructor --- lib/arel/table.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 6 +++++- spec/arel/select_manager_spec.rb | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index efdc34ed94804..1519efa63bdaf 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -14,6 +14,11 @@ def initialize name, engine = Table.engine @columns = nil @aliases = [] @table_alias = nil + + # 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] if Hash === engine end def alias diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index be9a62325a6c2..391d2ff1c4183 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -139,7 +139,11 @@ def visit_Arel_Nodes_On o end def visit_Arel_Table o - quote_table_name o.name + 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 diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 86a4daee44d6e..2ed1a851e5ae7 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -49,6 +49,15 @@ def execute sql, name = nil 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.should be_like %{ SELECT FROM "users" "foo" OFFSET 10 } + end + end + describe 'skip' do it 'should add an offset' do table = Table.new :users From 6cd4e8f51ff231cafb2fdb6d71328f763c934b0b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 18:23:28 -0700 Subject: [PATCH 0702/1492] supporting symbols for group statements --- lib/arel/select_manager.rb | 1 + spec/arel/select_manager_spec.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 0f70a461a31fc..423b217b8a0f2 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -43,6 +43,7 @@ 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 diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 2ed1a851e5ae7..02586f3a65e13 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -27,6 +27,18 @@ def execute sql, name = nil describe 'select manager' do describe 'backwards compatibility' do + 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.should be_like %{ + SELECT FROM "users" GROUP BY foo + } + end + end + describe 'from' do it 'ignores strings when table of same name exists' do table = Table.new :users From 5ea98130038ff5395239f3f6e46dc9276d3198ec Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 19:22:19 -0700 Subject: [PATCH 0703/1492] OUTER JOIN should be LEFT OUTER JOIN --- lib/arel/visitors/join_sql.rb | 2 +- spec/arel/select_manager_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index c1e00ea8f00de..ab3d10f99cbd4 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -21,7 +21,7 @@ def visit_Arel_Nodes_StringJoin o end def visit_Arel_Nodes_OuterJoin o - "OUTER JOIN #{visit o.right} #{visit o.constraint}" + "LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}" end def visit_Arel_Nodes_InnerJoin o diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 02586f3a65e13..df8d236bc33aa 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -252,7 +252,7 @@ def execute sql, name = nil manager = Arel::SelectManager.new Table.engine manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) manager.join_sql.should be_like %{ - OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" + LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" } check manager.joins(manager).should == manager.join_sql end From af61eedc1a98fc2b6e3011a4c2af8666c0717966 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 19:27:54 -0700 Subject: [PATCH 0704/1492] order accepts symbols for clauses --- lib/arel/select_manager.rb | 2 +- spec/arel/select_manager_spec.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 423b217b8a0f2..7512dd90edf49 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -95,7 +95,7 @@ def where expr def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @head.orders.concat expr.map { |x| - String === x ? Nodes::SqlLiteral.new(x) : x + String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x } self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index df8d236bc33aa..fa1bbdddce21e 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -27,6 +27,19 @@ def execute sql, name = nil describe 'select manager' do describe 'backwards compatibility' do + 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.should be_like %{ + SELECT * FROM "users" ORDER BY foo + } + end + end + describe 'group' do it 'takes a symbol' do table = Table.new :users From 9d95e7d3c1fa0e582192f6e271dada6d185a71e3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 19:49:02 -0700 Subject: [PATCH 0705/1492] totally lame, but arel expects FROM to only be one item --- lib/arel/nodes/select_core.rb | 2 +- lib/arel/select_manager.rb | 6 +----- spec/arel/select_manager_spec.rb | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index e52db6eb77e95..bd85dad24a1e0 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,7 +1,7 @@ module Arel module Nodes class SelectCore - attr_reader :froms, :projections, :wheres, :groups + attr_accessor :froms, :projections, :wheres, :groups attr_accessor :having def initialize diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 7512dd90edf49..df3f21c3b626d 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -51,11 +51,7 @@ def group *columns end def from table - if String === table - return self if @ctx.froms.any? { |x| x.name.to_s == table } - end - - @ctx.froms << table + @ctx.froms = [table] self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index fa1bbdddce21e..4262a7465b36d 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -60,7 +60,7 @@ def execute sql, name = nil manager.from table manager.from 'users' manager.project table['id'] - manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' + manager.to_sql.should be_like 'SELECT "users"."id" FROM \'users\'' end end From ca73ebfc239c0b9463d5d016c2e7b23088791e22 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 12 Sep 2010 19:58:48 -0700 Subject: [PATCH 0706/1492] stop the warnings --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 12df4754fd4fb..cc73a5e0ceb76 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -*- -require File.expand_path('../lib/arel/version.rb', __FILE__) +require 'arel/version' Gem::Specification.new do |s| s.name = "arel" From 5c9b50e93fcb3683c742815095104283c8f9bf07 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 14 Sep 2010 08:26:01 -0400 Subject: [PATCH 0707/1492] dot visitor for binary nodes --- lib/arel/visitors/dot.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 0fc6c1757f21f..7d68d655e845d 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -92,6 +92,13 @@ def visit_Arel_Nodes_Equality o visit_edge o, "left" visit_edge o, "right" end + alias :visit_Arel_Nodes_And :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_Or :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_NotEqual :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_GreaterThan :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_GreaterThanOrEqual :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_Assignment :visit_Arel_Nodes_Equality + def visit_String o @node_stack.last.fields << o From be852b9c2650b4584bdd70651b12521bbcb356d7 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 14 Sep 2010 08:47:08 -0400 Subject: [PATCH 0708/1492] sql visitor should emit a table alias name when visiting an attribute, if a table alias exists. --- lib/arel/visitors/to_sql.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 391d2ff1c4183..2660c7d2849d6 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -190,7 +190,8 @@ def visit_Arel_Nodes_UnqualifiedColumn o end def visit_Arel_Attributes_Attribute o - "#{quote_table_name o.relation.name}.#{quote_column_name o.name}" + 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_String :visit_Arel_Attributes_Attribute From 1903f2b26057e4d70fdbbc0b94136a99a46f9b68 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 10:06:35 -0700 Subject: [PATCH 0709/1492] updating gemspec --- arel.gemspec | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index cc73a5e0ceb76..de63a1d120742 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -23,10 +23,4 @@ and query generation. s.has_rdoc = true s.extra_rdoc_files = %w[History.txt README.markdown] - - # Arel required ActiveRecord, but we're not declaring it to avoid a - # circular dependency chain. The solution is for ActiveRecord to release - # the connection adapters which Arel uses in a separate gem - # s.add_dependency "activerecord", ">= 3.0.pre" - s.add_dependency "activesupport", ">= 3.0.0.beta" end From 886dff81c09dba2b2981b4387b02f026e6b16150 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 10:06:46 -0700 Subject: [PATCH 0710/1492] adding AND nodes to dot visitor --- lib/arel/visitors/dot.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 0fc6c1757f21f..55d5abe7e2c17 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -92,6 +92,7 @@ def visit_Arel_Nodes_Equality o visit_edge o, "left" visit_edge o, "right" end + alias :visit_Arel_Nodes_And :visit_Arel_Nodes_Equality def visit_String o @node_stack.last.fields << o From 5cf6550ef4d4f7b8b2358a99a31ce8ea6d19b428 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 11:20:46 -0700 Subject: [PATCH 0711/1492] adding table alias to the TableAlias node --- lib/arel/nodes/table_alias.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 656a820a605ed..7ec1fad272277 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -2,6 +2,7 @@ module Arel module Nodes class TableAlias attr_reader :name, :relation, :columns + alias :table_alias :name def initialize name, relation @name = name From de5f2916aa47fb1274d56a2c5c5ba636f5fe2cc4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 11:21:50 -0700 Subject: [PATCH 0712/1492] adding orders edge to the dot visitor --- lib/arel/visitors/dot.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index a00e25c6a6493..0c813bf8bff4b 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -66,6 +66,7 @@ def visit_Arel_Nodes_SelectCore o def visit_Arel_Nodes_SelectStatement o visit_edge o, "cores" visit_edge o, "limit" + visit_edge o, "orders" end def visit_Arel_Nodes_UpdateStatement o From b93a23827a2244ec730be1b46ec44fb368d00396 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 13:39:33 -0700 Subject: [PATCH 0713/1492] adding an EXISTS node, update method will generate an IN clause --- lib/arel/crud.rb | 17 +++++++++-- lib/arel/nodes.rb | 1 + lib/arel/nodes/exists.rb | 11 +++++++ lib/arel/nodes/select_statement.rb | 2 +- lib/arel/table.rb | 5 +++ lib/arel/visitors/to_sql.rb | 4 +++ spec/arel/nodes/select_statement_spec.rb | 4 +-- spec/arel/select_manager_spec.rb | 39 ++++++++++++++++++++++++ spec/arel/table_spec.rb | 6 ++++ 9 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 lib/arel/nodes/exists.rb diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index b1269bd1daf73..196dc5655477c 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -7,12 +7,23 @@ def update values um = UpdateManager.new @engine if Nodes::SqlLiteral === values - um.table @ctx.froms.last + relation = @ctx.froms.last else - um.table values.first.first.relation + relation = values.first.first.relation end + um.table relation um.set values - um.wheres = @ctx.wheres + + if @head.orders.empty? && @head.limit.nil? + um.wheres = @ctx.wheres + else + head = @head.clone + core = head.cores.first + core.projections = [relation.primary_key] + + um.wheres = [Nodes::In.new(relation.primary_key, [head])] + end + @engine.connection.update um.to_sql, 'AREL' end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 3ffc81d7df0bc..99a34c3b2b08b 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -14,6 +14,7 @@ require 'arel/nodes/values' require 'arel/nodes/offset' require 'arel/nodes/sum' +require 'arel/nodes/exists' require 'arel/nodes/max' require 'arel/nodes/min' require 'arel/nodes/avg' diff --git a/lib/arel/nodes/exists.rb b/lib/arel/nodes/exists.rb new file mode 100644 index 0000000000000..167a345006cb4 --- /dev/null +++ b/lib/arel/nodes/exists.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Exists + attr_reader :select_stmt + + def initialize select_stmt + @select_stmt = select_stmt + end + end + end +end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 6272fd126da2a..637ba5d1d0771 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -14,7 +14,7 @@ def initialize cores = [SelectCore.new] def initialize_copy other super - @cores = @cores.clone + @cores = @cores.map { |x| x.clone } end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 1519efa63bdaf..06bbe7b99e813 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -14,6 +14,7 @@ def initialize name, engine = Table.engine @columns = nil @aliases = [] @table_alias = nil + @primary_key = nil # 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 @@ -21,6 +22,10 @@ def initialize name, engine = Table.engine @table_alias = engine[:as] if Hash === engine end + def primary_key + @primary_key ||= self[@engine.connection.primary_key(name)] + end + def alias Nodes::TableAlias.new("#{name}_2", self).tap do |node| @aliases << node diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2660c7d2849d6..dc65e86219cc9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -41,6 +41,10 @@ def visit_Arel_Nodes_InsertStatement o ].compact.join ' ' end + def visit_Arel_Nodes_Exists o + "EXISTS (#{visit o.select_stmt})" + end + def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.map { |value| value.nil? ? 'NULL' : visit(value) diff --git a/spec/arel/nodes/select_statement_spec.rb b/spec/arel/nodes/select_statement_spec.rb index 75463f1d958bc..68bde3c4f7ef0 100644 --- a/spec/arel/nodes/select_statement_spec.rb +++ b/spec/arel/nodes/select_statement_spec.rb @@ -5,10 +5,10 @@ it "clones cores" do statement = Arel::Nodes::SelectStatement.new %w[a b c] - statement.cores.should_receive(:clone).and_return([:cores]) + statement.cores.map { |x| x.should_receive(:clone).and_return(:f) } dolly = statement.clone - dolly.cores.should == [:cores] + dolly.cores.should == [:f, :f, :f] end end end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 4262a7465b36d..3fe68a8db01bf 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -74,6 +74,17 @@ def execute sql, name = nil 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" + + check mgr.to_sql.should_not == m2.to_sql + end + end + describe 'initialize' do it 'uses alias in sql' do table = Table.new :users, :engine => Table.engine, :as => 'foo' @@ -354,6 +365,34 @@ def execute sql, name = nil 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 + manager.update(SqlLiteral.new('foo = bar')) + + engine.executed.last.should 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 + manager.update(SqlLiteral.new('foo = bar')) + + engine.executed.last.should 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 diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 7cc0b20a25ebd..5b68040aace34 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -6,6 +6,12 @@ module Arel @relation = Table.new(:users) end + describe 'primary_key' do + it 'should return an attribute' do + check @relation.primary_key.name.should == :id + end + end + describe 'having' do it 'adds a having clause' do mgr = @relation.having @relation[:id].eq(10) From b12a0c33c0d26bdab076c4cffbfcccd406db0974 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 14:27:37 -0700 Subject: [PATCH 0714/1492] visiting value nodes in the dot visitor --- lib/arel/visitors/dot.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 0c813bf8bff4b..e79af6c50b620 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -43,6 +43,10 @@ def visit_Arel_Nodes_On o visit_edge o, "expr" end + def visit_Arel_Nodes_Values o + visit_edge o, "expressions" + end + def visit_Arel_Nodes_StringJoin o visit_edge o, "left" visit_edge o, "right" From 37620b0c391076c557b7b03d20731e697b881b3e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 14:58:34 -0700 Subject: [PATCH 0715/1492] VALUES are getting better everyday --- lib/arel/insert_manager.rb | 2 +- lib/arel/nodes/values.rb | 5 +++-- lib/arel/visitors/to_sql.rb | 4 ++-- spec/arel/insert_manager_spec.rb | 5 +++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index 75e6299def666..175947554239b 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -27,7 +27,7 @@ def insert fields @head.columns << column values << value end - @head.values = Nodes::Values.new values + @head.values = Nodes::Values.new values, @head.columns end end end diff --git a/lib/arel/nodes/values.rb b/lib/arel/nodes/values.rb index eab70a362aaef..4c7ca76360638 100644 --- a/lib/arel/nodes/values.rb +++ b/lib/arel/nodes/values.rb @@ -1,10 +1,11 @@ module Arel module Nodes class Values - attr_accessor :expressions + attr_accessor :expressions, :columns - def initialize exprs + def initialize exprs, columns = [] @expressions = exprs + @columns = columns end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index dc65e86219cc9..46f70d0f7cef1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -46,8 +46,8 @@ def visit_Arel_Nodes_Exists o end def visit_Arel_Nodes_Values o - "VALUES (#{o.expressions.map { |value| - value.nil? ? 'NULL' : visit(value) + "VALUES (#{o.expressions.zip(o.columns).map { |value, column| + quote(value, column && column.column) }.join ', '})" end diff --git a/spec/arel/insert_manager_spec.rb b/spec/arel/insert_manager_spec.rb index a6d34f43579c1..1cd61ae630b9b 100644 --- a/spec/arel/insert_manager_spec.rb +++ b/spec/arel/insert_manager_spec.rb @@ -12,6 +12,11 @@ module Arel it "inserts false" do table = Table.new(:users) manager = Arel::InsertManager.new Table.engine + + table[:id].column.extend(Module.new { + def type; :boolean; end + }) + manager.insert [[table[:id], false]] manager.to_sql.should be_like %{ INSERT INTO "users" ("id") VALUES ('f') From 5d11fa9f6a850ac4374a01e402740ca8a7b50f32 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 15:17:09 -0700 Subject: [PATCH 0716/1492] adding sum to sql literal --- lib/arel/nodes/sql_literal.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 6471469d9fb8a..7299fb1d45d31 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -5,6 +5,10 @@ def count distinct = false 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 From 188fc7a46456bd3e5ebdb09ef8a753d7a34a6af5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Sep 2010 15:20:24 -0700 Subject: [PATCH 0717/1492] refactoring expressions to a module --- lib/arel.rb | 1 + lib/arel/attributes/attribute.rb | 22 ++-------------------- lib/arel/expressions.rb | 23 +++++++++++++++++++++++ lib/arel/nodes/sql_literal.rb | 12 +----------- 4 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 lib/arel/expressions.rb diff --git a/lib/arel.rb b/lib/arel.rb index d1c2e44567bab..989ed12c8726a 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,7 @@ require 'arel/crud' require 'arel/version' +require 'arel/expressions' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 34c1f45ba6677..28493d5cba8b0 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -1,6 +1,8 @@ module Arel module Attributes class Attribute < Struct.new :relation, :name, :column + include Arel::Expressions + def not_eq other Nodes::NotEqual.new self, other end @@ -13,26 +15,6 @@ def in other Nodes::In.new self, other end - 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 gteq right Nodes::GreaterThanOrEqual.new self, right end diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb new file mode 100644 index 0000000000000..d1fbfd83d90d9 --- /dev/null +++ b/lib/arel/expressions.rb @@ -0,0 +1,23 @@ +module 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 + end +end diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 7299fb1d45d31..e5918620d93f9 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -1,17 +1,7 @@ module Arel module Nodes class SqlLiteral < String - def count distinct = false - 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 + include Arel::Expressions end end end From ed6192c55b8e77b60e4203dc30ae056f222a1499 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 15 Sep 2010 09:26:01 -0700 Subject: [PATCH 0718/1492] adding a grouping node --- lib/arel/nodes.rb | 2 ++ lib/arel/nodes/binary.rb | 10 +--------- lib/arel/nodes/grouping.rb | 21 +++++++++++++++++++++ lib/arel/nodes/node.rb | 20 ++++++++++++++++++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/nodes/equality_spec.rb | 4 ++-- spec/arel/nodes/or_spec.rb | 8 ++++---- 7 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 lib/arel/nodes/grouping.rb create mode 100644 lib/arel/nodes/node.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 99a34c3b2b08b..ac4bba57c2119 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,3 +1,4 @@ +require 'arel/nodes/node' require 'arel/nodes/binary' require 'arel/nodes/equality' require 'arel/nodes/not_equal' @@ -29,6 +30,7 @@ require 'arel/nodes/table_alias' require 'arel/nodes/join' require 'arel/nodes/group' +require 'arel/nodes/grouping' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' require 'arel/nodes/string_join' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 3cd9583e79160..090468adfae6f 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class Binary + class Binary < Arel::Nodes::Node attr_accessor :left, :right def initialize left, right @@ -8,14 +8,6 @@ def initialize left, right @right = right end - def or right - Nodes::Or.new self, right - end - - 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. diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb new file mode 100644 index 0000000000000..0af1df1f7a6f5 --- /dev/null +++ b/lib/arel/nodes/grouping.rb @@ -0,0 +1,21 @@ +module Arel + module Nodes + class Grouping < Arel::Nodes::Node + attr_accessor :expr + + def initialize expression + @expr = expression + 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 + viz = Visitors::ToSql.new Table.engine + viz.accept self + end + end + end +end diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb new file mode 100644 index 0000000000000..fd5ea410eabda --- /dev/null +++ b/lib/arel/nodes/node.rb @@ -0,0 +1,20 @@ +module Arel + module Nodes + ### + # Abstract base class for all AST nodes + class Node + ### + # 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 + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 46f70d0f7cef1..5be95565f3adf 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -84,6 +84,10 @@ def visit_Arel_Nodes_Offset o def visit_Arel_Nodes_Lock o end + def visit_Arel_Nodes_Grouping o + "(#{visit o.expr})" + end + def visit_Arel_Nodes_Group o visit o.expr end diff --git a/spec/arel/nodes/equality_spec.rb b/spec/arel/nodes/equality_spec.rb index d9edc352f3232..81eea4d482a8b 100644 --- a/spec/arel/nodes/equality_spec.rb +++ b/spec/arel/nodes/equality_spec.rb @@ -34,8 +34,8 @@ module Nodes left = attr.eq(10) right = attr.eq(11) node = left.or right - check node.left.should == left - check node.right.should == right + check node.expr.left.should == left + check node.expr.right.should == right end end diff --git a/spec/arel/nodes/or_spec.rb b/spec/arel/nodes/or_spec.rb index e855b9245322d..88484ff4f74f5 100644 --- a/spec/arel/nodes/or_spec.rb +++ b/spec/arel/nodes/or_spec.rb @@ -7,12 +7,12 @@ module Nodes left = attr.eq(10) right = attr.eq(11) node = left.or right - check node.left.should == left - check node.right.should == right + check node.expr.left.should == left + check node.expr.right.should == right oror = node.or(right) - check oror.left == node - check oror.right == right + check oror.expr.left == node + check oror.expr.right == right end end end From f4ea59ab4d76a2745ebf50f65bfbfe26f9db7195 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 15 Sep 2010 10:50:20 -0700 Subject: [PATCH 0719/1492] JoinSql visitor will visit left side if left is a join --- lib/arel/visitors/join_sql.rb | 12 +++++++--- spec/arel/visitors/join_sql_spec.rb | 35 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 spec/arel/visitors/join_sql_spec.rb diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index ab3d10f99cbd4..099e78b6925ea 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -17,15 +17,21 @@ def visit_Arel_Nodes_StringJoin o [ (visit o.left if Nodes::Join === o.left), visit(o.right) - ].join ' ' + ].compact.join ' ' end def visit_Arel_Nodes_OuterJoin o - "LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}" + [ + (visit o.left if Nodes::Join === o.left), + "LEFT OUTER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" + ].compact.join ' ' end def visit_Arel_Nodes_InnerJoin o - "INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" + [ + (visit o.left if Nodes::Join === o.left), + "INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" + ].compact.join ' ' end end end diff --git a/spec/arel/visitors/join_sql_spec.rb b/spec/arel/visitors/join_sql_spec.rb new file mode 100644 index 0000000000000..9064dae85298e --- /dev/null +++ b/spec/arel/visitors/join_sql_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +module Arel + module Visitors + describe 'the join_sql visitor' do + before do + @visitor = JoinSql.new Table.engine + end + + describe 'inner join' do + it 'should visit left if left is a join' do + t = Table.new :users + join = Nodes::InnerJoin.new t, t, Nodes::On.new(t[:id]) + j2 = Nodes::InnerJoin.new join, t, Nodes::On.new(t[:id]) + @visitor.accept(j2).should 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 + join = Nodes::OuterJoin.new t, t, Nodes::On.new(t[:id]) + j2 = Nodes::OuterJoin.new join, t, Nodes::On.new(t[:id]) + @visitor.accept(j2).should be_like %{ + LEFT OUTER JOIN "users" ON "users"."id" + LEFT OUTER JOIN "users" ON "users"."id" + } + end + end + end + end +end From 62e36ebba05778b76b97386d5771d3aafd5c4782 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 15 Sep 2010 12:01:43 -0700 Subject: [PATCH 0720/1492] right side set to sqlliteral if it is a string --- lib/arel/select_manager.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index df3f21c3b626d..20c97f198a4f0 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -143,8 +143,12 @@ def collapse exprs right = exprs.pop left = exprs.pop + right = Nodes::SqlLiteral.new(right) if String === right + right = Nodes::And.new left, right - exprs.reverse.inject(right) { |memo,expr| Nodes::And.new(expr, memo) } + exprs.reverse.inject(right) { |memo,expr| + Nodes::And.new(expr, memo) + } end end end From e460aa96ae9bd5f1a24d798b2d22984a54810c70 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 15 Sep 2010 14:36:15 -0700 Subject: [PATCH 0721/1492] Table#[] returns nil when table does not exist --- lib/arel/table.rb | 2 ++ spec/arel/table_spec.rb | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 06bbe7b99e813..c3816135155d3 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -88,6 +88,8 @@ def columns end def [] name + return nil unless @engine.connection.table_exists?(@name) + name = name.to_sym columns.find { |column| column.name == name } end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 5b68040aace34..9c84b170a2338 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -147,6 +147,13 @@ module Arel end end + describe 'when table does not exist' do + it 'returns nil' do + table = Table.new(:foooo) + table[:id].should be_nil + end + end + ### FIXME: this seems like a bad requirement. #describe 'when given an', Attribute do # it "returns the attribute if the attribute is within the relation" do From f95f0918d745856080c06b5e3ae5c323b2de43d2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 15 Sep 2010 14:46:40 -0700 Subject: [PATCH 0722/1492] Revert "Table#[] returns nil when table does not exist" This reverts commit e460aa96ae9bd5f1a24d798b2d22984a54810c70. --- lib/arel/table.rb | 2 -- spec/arel/table_spec.rb | 7 ------- 2 files changed, 9 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index c3816135155d3..06bbe7b99e813 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -88,8 +88,6 @@ def columns end def [] name - return nil unless @engine.connection.table_exists?(@name) - name = name.to_sym columns.find { |column| column.name == name } end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 9c84b170a2338..5b68040aace34 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -147,13 +147,6 @@ module Arel end end - describe 'when table does not exist' do - it 'returns nil' do - table = Table.new(:foooo) - table[:id].should be_nil - end - end - ### FIXME: this seems like a bad requirement. #describe 'when given an', Attribute do # it "returns the attribute if the attribute is within the relation" do From 6b8a382a75d1425ecf978f1e0fe9a636d55c8cc0 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 16 Sep 2010 11:49:34 -0400 Subject: [PATCH 0723/1492] using a Hash with default proc to memoize dispatch methods --- lib/arel/visitors/to_sql.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5be95565f3adf..e8b63a1533344 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -222,17 +222,12 @@ def visit_Float o; quote(o) end def visit_BigDecimal o; quote(o) end def visit_FalseClass o; quote(o) end - DISPATCH = {} - def visit object - send "visit_#{object.class.name.gsub('::', '_')}", object - #send DISPATCH[object.class], object + DISPATCH = Hash.new do |hash, klass| + hash[klass] = "visit_#{klass.name.gsub('::', '_')}" end - private_instance_methods(false).each do |method| - method = method.to_s - next unless method =~ /^visit_(.*)$/ - const = $1.split('_').inject(Object) { |m,s| m.const_get s } - DISPATCH[const] = method + def visit object + send DISPATCH[object.class], object end def quote value, column = nil From 25e93e817eb9d2a038e556aa5a3a16c2beb94dd2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 17 Sep 2010 17:38:53 -0700 Subject: [PATCH 0724/1492] remove if defined? --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index e8b63a1533344..d3da65b425841 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -213,7 +213,7 @@ def visit_Fixnum o; o end def visit_TrueClass o; quote(o) end def visit_String o; quote(o) end def visit_Hash o; quote(o) end - def visit_ActiveSupport_Multibyte_Chars o; quote(o) end if defined?(ActiveSupport) + def visit_ActiveSupport_Multibyte_Chars o; quote(o) end def visit_Symbol o; quote(o) end def visit_Time o; quote(o) end def visit_Date o; quote(o) end From dfa520b9ab08522e10978f2ee3006ba42db418ba Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 18 Sep 2010 11:33:07 -0700 Subject: [PATCH 0725/1492] returning nil for tables that do not exist --- lib/arel/table.rb | 16 ++++++++++++++++ spec/arel/table_spec.rb | 26 +++++--------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 06bbe7b99e813..d23245691b428 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -88,8 +88,24 @@ def columns end def [] name + return nil unless table_exists? + name = name.to_sym columns.find { |column| column.name == name } end + + private + def table_exists? + @table_exists ||= tables.key?(@name) || engine.connection.table_exists?(name) + end + + def tables + self.class.table_cache(@engine) + end + + @@table_cache = nil + def self.table_cache engine # :nodoc: + @@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }] + end end end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 5b68040aace34..28fc95dec5e3b 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -147,27 +147,11 @@ module Arel end end - ### FIXME: this seems like a bad requirement. - #describe 'when given an', Attribute do - # it "returns the attribute if the attribute is within the relation" do - # @relation[@relation[:id]].should == @relation[:id] - # end - - # it "returns nil if the attribtue is not within the relation" do - # another_relation = Table.new(:photos) - # @relation[another_relation[:id]].should be_nil - # end - #end - - #describe 'when given an', Expression do - # before do - # @expression = @relation[:id].count - # end - - # it "returns the Expression if the Expression is within the relation" do - # @relation[@expression].should be_nil - # end - #end + describe 'when table does not exist' do + it 'returns nil' do + @relation[:foooo].should be_nil + end + end end end end From 6f9f83e474505d7e1c253fd8f120a06e2dcd61cd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 18 Sep 2010 13:42:54 -0700 Subject: [PATCH 0726/1492] if FROM is a string, convert to string literal --- lib/arel/select_manager.rb | 1 + spec/arel/select_manager_spec.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 20c97f198a4f0..daef9f52cad08 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -51,6 +51,7 @@ def group *columns end def from table + table = Nodes::SqlLiteral.new(table) if String === table @ctx.froms = [table] self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index 3fe68a8db01bf..e309286ebacbb 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -60,7 +60,7 @@ def execute sql, name = nil manager.from table manager.from 'users' manager.project table['id'] - manager.to_sql.should be_like 'SELECT "users"."id" FROM \'users\'' + manager.to_sql.should be_like 'SELECT "users"."id" FROM users' end end From d8de55cee197d887b478b134ec692776613bf998 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Sep 2010 13:29:12 -0700 Subject: [PATCH 0727/1492] adding crazy code to fix the last two AR tests --- lib/arel/attributes/attribute.rb | 3 +++ lib/arel/nodes/in.rb | 4 ++++ lib/arel/select_manager.rb | 36 +++++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 28493d5cba8b0..6bb880d2118f8 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -12,6 +12,9 @@ def eq other end def in other + if Arel::SelectManager === other + other = other.to_a.map { |x| x.id } + end Nodes::In.new self, other end diff --git a/lib/arel/nodes/in.rb b/lib/arel/nodes/in.rb index 6ccf37a053f2b..13163af11e6e9 100644 --- a/lib/arel/nodes/in.rb +++ b/lib/arel/nodes/in.rb @@ -1,6 +1,10 @@ module Arel module Nodes class In < Equality + def initialize left, right + raise if Arel::SelectManager === right + super + end end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index daef9f52cad08..98d9385b0ab2e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -12,13 +12,17 @@ def taken @head.limit end + def constraints + @ctx.wheres + end + def skip amount @head.offset = Nodes::Offset.new(amount) self end def where_clauses - warn "where_clauses is deprecated" if $VERBOSE + #warn "where_clauses is deprecated" if $VERBOSE to_sql = Visitors::ToSql.new @engine @ctx.wheres.map { |c| to_sql.accept c } end @@ -52,6 +56,18 @@ def group *columns 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. + unless @ctx.froms.empty? + source = @ctx.froms.first + + if Nodes::SqlLiteral === table && Nodes::Join === source + source.left = table + table = source + end + end + @ctx.froms = [table] self end @@ -125,8 +141,22 @@ def joins manager manager.join_sql end - def to_a - raise NotImplementedError + 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 From b95deec5c77f92083b456469d22ca7a4b6880827 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Sep 2010 14:27:34 -0700 Subject: [PATCH 0728/1492] from does not need to be a list --- lib/arel/crud.rb | 4 ++-- lib/arel/nodes/select_core.rb | 4 ++-- lib/arel/select_manager.rb | 14 +++++++------- lib/arel/visitors/join_sql.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 196dc5655477c..e060a82941e6a 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -7,7 +7,7 @@ def update values um = UpdateManager.new @engine if Nodes::SqlLiteral === values - relation = @ctx.froms.last + relation = @ctx.froms else relation = values.first.first.relation end @@ -37,7 +37,7 @@ def insert values def delete dm = DeleteManager.new @engine dm.wheres = @ctx.wheres - dm.from @ctx.froms.last + dm.from @ctx.froms @engine.connection.delete dm.to_sql, 'AREL' end end diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index bd85dad24a1e0..42e590ce36925 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -5,7 +5,7 @@ class SelectCore attr_accessor :having def initialize - @froms = [] + @froms = nil @projections = [] @wheres = [] @groups = [] @@ -14,7 +14,7 @@ def initialize def initialize_copy other super - @froms = @froms.clone + @froms = @froms.clone if @froms @projections = @projections.clone @wheres = @wheres.clone @group = @groups.clone diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 98d9385b0ab2e..4866ea66c933d 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -39,7 +39,7 @@ def locked end def on *exprs - @ctx.froms.last.constraint = Nodes::On.new(collapse(exprs)) + @ctx.froms.constraint = Nodes::On.new(collapse(exprs)) self end @@ -59,8 +59,8 @@ def from table # FIXME: this is a hack to support # test_with_two_tables_in_from_without_getting_double_quoted # from the AR tests. - unless @ctx.froms.empty? - source = @ctx.froms.first + if @ctx.froms + source = @ctx.froms if Nodes::SqlLiteral === table && Nodes::Join === source source.left = table @@ -68,7 +68,7 @@ def from table end end - @ctx.froms = [table] + @ctx.froms = table self end @@ -78,9 +78,9 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral raise if relation.blank? - from Nodes::StringJoin.new(@ctx.froms.pop, relation) + from Nodes::StringJoin.new(@ctx.froms, relation) else - from klass.new(@ctx.froms.pop, relation, nil) + from klass.new(@ctx.froms, relation, nil) end end @@ -162,7 +162,7 @@ def to_a # :nodoc: # FIXME: this method should go away def insert values im = InsertManager.new @engine - im.into @ctx.froms.last + im.into @ctx.froms im.insert values @engine.connection.insert im.to_sql end diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 099e78b6925ea..49625e850def1 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -10,7 +10,7 @@ module Visitors # compatibility with Arel V1.0 class JoinSql < Arel::Visitors::ToSql def visit_Arel_Nodes_SelectCore o - o.froms.grep(Nodes::Join).map { |x| visit x }.join ', ' + [o.froms].grep(Nodes::Join).map { |x| visit x }.join ', ' end def visit_Arel_Nodes_StringJoin o diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d3da65b425841..9186d28566ef7 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -64,7 +64,7 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_SelectCore o [ "SELECT #{o.projections.map { |x| visit x }.join ', '}", - ("FROM #{o.froms.map { |x| visit x }.join ', ' }" unless o.froms.empty?), + ("FROM #{visit o.froms}" if o.froms), ("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), From e12513659d2b145c216ddb755950705eb2efcb3c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Sep 2010 14:36:04 -0700 Subject: [PATCH 0729/1492] using aliases for terminal nodes --- lib/arel/visitors/to_sql.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9186d28566ef7..cbe2b6cca3a17 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -210,17 +210,18 @@ def visit_Fixnum o; o end alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated - def visit_TrueClass o; quote(o) end def visit_String o; quote(o) end - def visit_Hash o; quote(o) end - def visit_ActiveSupport_Multibyte_Chars o; quote(o) end - def visit_Symbol o; quote(o) end - def visit_Time o; quote(o) end - def visit_Date o; quote(o) end - def visit_DateTime o; quote(o) end - def visit_Float o; quote(o) end - def visit_BigDecimal o; quote(o) end - def visit_FalseClass o; quote(o) end + + alias :visit_ActiveSupport_Multibyte_Chars :visit_String + alias :visit_BigDecimal :visit_String + alias :visit_Date :visit_String + alias :visit_DateTime :visit_String + alias :visit_FalseClass :visit_String + alias :visit_Float :visit_String + alias :visit_Hash :visit_String + alias :visit_Symbol :visit_String + alias :visit_Time :visit_String + alias :visit_TrueClass :visit_String DISPATCH = Hash.new do |hash, klass| hash[klass] = "visit_#{klass.name.gsub('::', '_')}" From 9e5a4423cdbbe161dade56306d7c4d70f5371be2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Sep 2010 15:59:52 -0700 Subject: [PATCH 0730/1492] removing some debugging code. oops! --- lib/arel/nodes/in.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/nodes/in.rb b/lib/arel/nodes/in.rb index 13163af11e6e9..6ccf37a053f2b 100644 --- a/lib/arel/nodes/in.rb +++ b/lib/arel/nodes/in.rb @@ -1,10 +1,6 @@ module Arel module Nodes class In < Equality - def initialize left, right - raise if Arel::SelectManager === right - super - end end end end From cd13c3e1dad07c1168a318feb543d3b1ede9f2cf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Sep 2010 16:03:44 -0700 Subject: [PATCH 0731/1492] dealing with empty in statements --- lib/arel/visitors/to_sql.rb | 4 +++- spec/arel/visitors/to_sql_spec.rb | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index cbe2b6cca3a17..5a92e27149103 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -155,7 +155,9 @@ def visit_Arel_Table o end def visit_Arel_Nodes_In o - "#{visit o.left} IN (#{o.right.map { |x| visit x }.join ', '})" + right = o.right + right = right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') + "#{visit o.left} IN (#{right})" end def visit_Arel_Nodes_And o diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index c8bfb845c1496..b277810863bac 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -65,6 +65,13 @@ module Visitors "users"."id" IN (1, 2, 3) } end + + it "should turn empty right to NULL" do + node = @attr.in [] + @visitor.accept(node).should be_like %{ + "users"."id" IN (NULL) + } + end end describe 'Equality' do From 0e98ef149cd44dc04d40a8553e1743c5cb6d4a7c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Sep 2010 16:23:23 -0700 Subject: [PATCH 0732/1492] supporting ranges for IN statements --- lib/arel/attributes/attribute.rb | 16 +++++++++++++--- lib/arel/nodes.rb | 2 ++ lib/arel/nodes/between.rb | 6 ++++++ lib/arel/nodes/less_than.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 8 ++++++++ spec/arel/visitors/to_sql_spec.rb | 14 ++++++++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 lib/arel/nodes/between.rb create mode 100644 lib/arel/nodes/less_than.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 6bb880d2118f8..e1f7fd81d2bba 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -12,10 +12,20 @@ def eq other end def in other - if Arel::SelectManager === other - other = other.to_a.map { |x| x.id } + case other + when Arel::SelectManager + Nodes::In.new self, other.to_a.map { |x| x.id } + when Range + if other.exclude_end? + left = Nodes::GreaterThanOrEqual.new(self, other.min) + right = Nodes::LessThan.new(self, other.max + 1) + Nodes::And.new left, right + else + Nodes::Between.new(self, Nodes::And.new(other.min, other.max)) + end + else + Nodes::In.new self, other end - Nodes::In.new self, other end def gteq right diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index ac4bba57c2119..fade666ff7534 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,12 +1,14 @@ require 'arel/nodes/node' require 'arel/nodes/binary' require 'arel/nodes/equality' +require 'arel/nodes/between' require 'arel/nodes/not_equal' require 'arel/nodes/assignment' require 'arel/nodes/or' require 'arel/nodes/and' require 'arel/nodes/greater_than' require 'arel/nodes/greater_than_or_equal' +require 'arel/nodes/less_than' require 'arel/nodes/in' require 'arel/nodes/lock' diff --git a/lib/arel/nodes/between.rb b/lib/arel/nodes/between.rb new file mode 100644 index 0000000000000..2e7596cdae06e --- /dev/null +++ b/lib/arel/nodes/between.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Between < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/nodes/less_than.rb b/lib/arel/nodes/less_than.rb new file mode 100644 index 0000000000000..cfaf716c42289 --- /dev/null +++ b/lib/arel/nodes/less_than.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class LessThan < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5a92e27149103..d6a9a3697fa79 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -122,6 +122,10 @@ 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 @@ -130,6 +134,10 @@ def visit_Arel_Nodes_GreaterThan 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_StringJoin o "#{visit o.left} #{visit o.right}" end diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/arel/visitors/to_sql_spec.rb index b277810863bac..25642ee947944 100644 --- a/spec/arel/visitors/to_sql_spec.rb +++ b/spec/arel/visitors/to_sql_spec.rb @@ -72,6 +72,20 @@ module Visitors "users"."id" IN (NULL) } end + + it 'can handle two dot ranges' do + node = @attr.in 1..3 + @visitor.accept(node).should be_like %{ + "users"."id" BETWEEN 1 AND 3 + } + end + + it 'can handle three dot ranges' do + node = @attr.in 1...3 + @visitor.accept(node).should be_like %{ + "users"."id" >= 1 AND "users"."id" < 3 + } + end end describe 'Equality' do From 2b20a488519716be15fbe351f7da39c9fd70f846 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Sep 2010 09:20:14 -0700 Subject: [PATCH 0733/1492] making stuff work on mysql --- lib/arel.rb | 1 + lib/arel/crud.rb | 13 +++---------- lib/arel/nodes/update_statement.rb | 4 +++- lib/arel/update_manager.rb | 18 ++++++++++++++++++ lib/arel/visitors/to_sql.rb | 4 +++- lib/arel/visitors/update_sql.rb | 26 ++++++++++++++++++++++++++ spec/arel/crud_spec.rb | 5 ++++- spec/arel/select_manager_spec.rb | 6 ++++++ 8 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 lib/arel/visitors/update_sql.rb diff --git a/lib/arel.rb b/lib/arel.rb index 989ed12c8726a..7d870ec17edc1 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -26,6 +26,7 @@ #### require 'arel/visitors/to_sql' +require 'arel/visitors/update_sql' require 'arel/visitors/join_sql' require 'arel/visitors/order_clauses' require 'arel/visitors/dot' diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index e060a82941e6a..640189fbe96af 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -13,16 +13,9 @@ def update values end um.table relation um.set values - - if @head.orders.empty? && @head.limit.nil? - um.wheres = @ctx.wheres - else - head = @head.clone - core = head.cores.first - core.projections = [relation.primary_key] - - um.wheres = [Nodes::In.new(relation.primary_key, [head])] - end + um.take @head.limit + um.order(*@head.orders) + um.wheres = @ctx.wheres @engine.connection.update um.to_sql, 'AREL' end diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 7a1ce9a7b129c..6f21187eb1690 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -1,12 +1,14 @@ module Arel module Nodes class UpdateStatement - attr_accessor :relation, :wheres, :values + attr_accessor :relation, :wheres, :values, :orders, :limit def initialize @relation = nil @wheres = [] @values = [] + @orders = [] + @limit = nil end def initialize_copy other diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 484230c4e1072..c6a053aaa8f91 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -5,6 +5,16 @@ def initialize engine @head = Nodes::UpdateStatement.new end + def take limit + @head.limit = limit + self + end + + def order *expr + @head.orders = expr + self + end + ### # UPDATE +table+ def table table @@ -34,5 +44,13 @@ def set values end self end + + def to_sql + viz = Visitors::ToSql.new @engine + unless @engine.connection_pool.spec.config[:adapter] == 'mysql' + viz.extend(Visitors::UpdateSql) + end + viz.accept @head + end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d6a9a3697fa79..710b6143ec214 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -25,7 +25,9 @@ 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?) + ("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?), + ("LIMIT #{o.limit}" if o.limit), ].compact.join ' ' end diff --git a/lib/arel/visitors/update_sql.rb b/lib/arel/visitors/update_sql.rb new file mode 100644 index 0000000000000..02196a0fb0a67 --- /dev/null +++ b/lib/arel/visitors/update_sql.rb @@ -0,0 +1,26 @@ +module Arel + module Visitors + module UpdateSql + def visit_Arel_Nodes_UpdateStatement o + if o.orders.empty? && o.limit.nil? + wheres = o.wheres + else + stmt = Nodes::SelectStatement.new + core = stmt.cores.first + core.froms = o.relation + core.projections = [o.relation.primary_key] + stmt.limit = o.limit + stmt.orders = o.orders + + wheres = [Nodes::In.new(o.relation.primary_key, [stmt])] + 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 + end + end +end diff --git a/spec/arel/crud_spec.rb b/spec/arel/crud_spec.rb index cc58b8dbce760..5c038572842ae 100644 --- a/spec/arel/crud_spec.rb +++ b/spec/arel/crud_spec.rb @@ -1,10 +1,13 @@ module Arel class FakeCrudder < SelectManager class FakeEngine - attr_reader :calls + attr_reader :calls, :connection_pool, :spec, :config def initialize @calls = [] + @connection_pool = self + @spec = self + @config = { :adapter => 'sqlite3' } end def connection; self end diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index e309286ebacbb..f301e3afd0a26 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -3,10 +3,16 @@ 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 connection From 741b8795779d24057ffb6f98f736f4f9bf00b49b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Sep 2010 09:23:08 -0700 Subject: [PATCH 0734/1492] fixing tests for mysql2 --- lib/arel/update_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index c6a053aaa8f91..7b9b0fc29571c 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -47,7 +47,7 @@ def set values def to_sql viz = Visitors::ToSql.new @engine - unless @engine.connection_pool.spec.config[:adapter] == 'mysql' + unless @engine.connection_pool.spec.config[:adapter] =~ /^mysql/ viz.extend(Visitors::UpdateSql) end viz.accept @head From dd425e1258b8480aa8e28e52edea7ef4c9c6f55f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Sep 2010 13:50:53 -0700 Subject: [PATCH 0735/1492] constructor can take column info --- lib/arel/table.rb | 27 +++++++++++++++++++-------- spec/arel/table_spec.rb | 7 +++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index d23245691b428..a1243f582b3b9 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -10,16 +10,20 @@ class << self; attr_accessor :engine; end def initialize name, engine = Table.engine @name = name @engine = engine - @engine = engine[:engine] if Hash === engine @columns = nil @aliases = [] @table_alias = nil @primary_key = nil - # 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] if Hash === engine + if Hash === engine + @engine = engine[:engine] || Table.engine + @columns = attributes_for engine[:columns] + + # 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] + end end def primary_key @@ -82,9 +86,8 @@ def having expr end def columns - @columns ||= @engine.connection.columns(@name, "#{@name} Columns").map do |column| - Attributes.for(column).new self, column.name.to_sym, column - end + @columns ||= + attributes_for @engine.connection.columns(@name, "#{@name} Columns") end def [] name @@ -95,6 +98,14 @@ def [] name end private + def attributes_for columns + return nil unless columns + + columns.map do |column| + Attributes.for(column).new self, column.name.to_sym, column + end + end + def table_exists? @table_exists ||= tables.key?(@name) || engine.connection.table_exists?(name) end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 28fc95dec5e3b..5c8cfac0124d3 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -71,6 +71,13 @@ module Arel end describe 'new' do + it 'takes :columns' do + columns = Table.engine.connection.columns("users") + @relation = Table.new(:users, :columns => columns) + check @relation.columns.first.name.should == :id + check @relation.engine.should == Table.engine + end + it 'should accept an engine' do rel = Table.new :users, 'foo' check rel.engine.should == 'foo' From 5a67d47a968e7c9febdba1b8c24d1db84abaac83 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 22 Sep 2010 15:59:10 -0700 Subject: [PATCH 0736/1492] quoting update values using the column --- lib/arel/nodes/unqualified_column.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/arel/nodes/unqualified_column.rb b/lib/arel/nodes/unqualified_column.rb index b86b55307400b..31561fddd4afe 100644 --- a/lib/arel/nodes/unqualified_column.rb +++ b/lib/arel/nodes/unqualified_column.rb @@ -5,6 +5,10 @@ def initialize attribute @attribute = attribute end + def column + @attribute.column + end + def name @attribute.name end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 710b6143ec214..2ccc9d7d3f7d9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -179,9 +179,7 @@ def visit_Arel_Nodes_Or o end def visit_Arel_Nodes_Assignment o - right = o.right - - right = right.nil? ? 'NULL' : visit(right) + right = quote(o.right, o.left.column) "#{visit o.left} = #{right}" end From 4cc43be38c488e7ec2d83408b8cb2475e2a620e7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 13:38:18 -0700 Subject: [PATCH 0737/1492] ignoring alias --- lib/arel/table.rb | 2 +- spec/arel/table_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index a1243f582b3b9..a709a3d717766 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -22,7 +22,7 @@ def initialize name, 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] + @table_alias = engine[:as] unless engine[:as].to_s == name.to_s end end diff --git a/spec/arel/table_spec.rb b/spec/arel/table_spec.rb index 5c8cfac0124d3..15f2e024e0d70 100644 --- a/spec/arel/table_spec.rb +++ b/spec/arel/table_spec.rb @@ -87,6 +87,11 @@ module Arel rel = Table.new :users, :engine => 'foo' check rel.engine.should == 'foo' end + + it 'ignores as if it equals name' do + rel = Table.new :users, :as => 'users' + rel.table_alias.should be_nil + end end describe 'order' do From aa4c957fa1a0f9ec26727800b80316c991b4a1d6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 11:45:29 -0700 Subject: [PATCH 0738/1492] adding a postgres adapter --- lib/arel.rb | 12 +++++++----- lib/arel/tree_manager.rb | 11 +++++++++-- lib/arel/update_manager.rb | 2 +- lib/arel/visitors/postgresql.rb | 6 ++++++ 4 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 lib/arel/visitors/postgresql.rb diff --git a/lib/arel.rb b/lib/arel.rb index 7d870ec17edc1..85a866b0ce160 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -12,6 +12,13 @@ require 'arel/expression' #### +require 'arel/visitors/to_sql' +require 'arel/visitors/postgresql' +require 'arel/visitors/update_sql' +require 'arel/visitors/join_sql' +require 'arel/visitors/order_clauses' +require 'arel/visitors/dot' + require 'arel/tree_manager' require 'arel/insert_manager' require 'arel/select_manager' @@ -25,8 +32,3 @@ require 'arel/sql_literal' #### -require 'arel/visitors/to_sql' -require 'arel/visitors/update_sql' -require 'arel/visitors/join_sql' -require 'arel/visitors/order_clauses' -require 'arel/visitors/dot' diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 24df5e0c09171..11d34ec1380b4 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -3,8 +3,15 @@ class TreeManager # FIXME: Remove this. include Arel::Relation + VISITORS = { + 'postgresql' => Arel::Visitors::PostgreSQL + } + def initialize engine - @engine = engine + @engine = engine + @pool = engine.connection_pool + @adapter = @pool.spec.config[:adapter] + @visitor_klass = VISITORS[@adapter] || Visitors::ToSql end def to_dot @@ -12,7 +19,7 @@ def to_dot end def to_sql - viz = Visitors::ToSql.new @engine + viz = @visitor_klass.new @engine viz.accept @head end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 7b9b0fc29571c..0cb55549540ad 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -46,7 +46,7 @@ def set values end def to_sql - viz = Visitors::ToSql.new @engine + viz = @visitor_klass.new @engine unless @engine.connection_pool.spec.config[:adapter] =~ /^mysql/ viz.extend(Visitors::UpdateSql) end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb new file mode 100644 index 0000000000000..93535f4488111 --- /dev/null +++ b/lib/arel/visitors/postgresql.rb @@ -0,0 +1,6 @@ +module Arel + module Visitors + class PostgreSQL < Arel::Visitors::ToSql + end + end +end From 9e9e5906754abfb168faba7d265719b5e613624f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 13:07:48 -0700 Subject: [PATCH 0739/1492] adding a select statment visitor --- lib/arel/nodes/select_statement.rb | 3 ++- lib/arel/visitors/postgresql.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 637ba5d1d0771..371fd7bf21465 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -14,7 +14,8 @@ def initialize cores = [SelectCore.new] def initialize_copy other super - @cores = @cores.map { |x| x.clone } + @cores = @cores.map { |x| x.clone } + @orders = @orders.map { |x| x.clone } end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 93535f4488111..5f0b23a11e1dd 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -1,6 +1,33 @@ module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_SelectStatement o + if !o.orders.empty? && using_distinct_on?(o) + subquery = o.dup + subquery.orders = [] + subquery.limit = nil + subquery.offset = nil + + sql = super(subquery) + [ + "SELECT * FROM (#{sql}) AS id_list", + "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}", + ("LIMIT #{o.limit}" if o.limit), + (visit(o.offset) if o.offset), + ].compact.join ' ' + else + super + end + end + + def using_distinct_on?(o) + o.cores.any? do |core| + core.projections.any? do |projection| + /DISTINCT ON/ === projection + end + end + end end end end From 66fc8add90445289f4926a914b0eea0c1989450f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 13:37:03 -0700 Subject: [PATCH 0740/1492] writing code that makes me sad --- lib/arel/visitors/postgresql.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 5f0b23a11e1dd..e8aa9b8cb3dd8 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -12,7 +12,7 @@ def visit_Arel_Nodes_SelectStatement o sql = super(subquery) [ "SELECT * FROM (#{sql}) AS id_list", - "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}", + "ORDER BY #{aliased_orders(o.orders).join(', ')}", ("LIMIT #{o.limit}" if o.limit), (visit(o.offset) if o.offset), ].compact.join ' ' @@ -28,6 +28,11 @@ def using_distinct_on?(o) end end end + + def aliased_orders orders + #orders = o.orders.map { |x| visit x }.join(', ').split(',') + (0...orders.size).map { |i| "id_list.alias_#{i}" } + end end end end From 6c266b4c3fd97cc6e4b01b72c3da69ed101cb3c6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 13:48:09 -0700 Subject: [PATCH 0741/1492] reordering order clauses :'( --- lib/arel/visitors/postgresql.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index e8aa9b8cb3dd8..87fc3bd60dc39 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -31,7 +31,15 @@ def using_distinct_on?(o) def aliased_orders orders #orders = o.orders.map { |x| visit x }.join(', ').split(',') - (0...orders.size).map { |i| "id_list.alias_#{i}" } + list = [] + orders.each_with_index do |o,i| + list << + [ + "id_list.alias_#{i}", + (o.index(/desc/i) && 'DESC') + ].compact.join(' ') + end + list end end end From 445a0ea342c28b8a6598343db40ad776cffd3a2e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 14:02:12 -0700 Subject: [PATCH 0742/1492] moving expression up to function class --- lib/arel/nodes/count.rb | 1 - lib/arel/nodes/function.rb | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index 354659ef701f5..c6e19afb34820 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -1,7 +1,6 @@ module Arel module Nodes class Count < Arel::Nodes::Function - include Arel::Expression attr_accessor :distinct diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 90c6ba23a2d29..a1cd13d4d1827 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -1,6 +1,7 @@ module Arel module Nodes class Function + include Arel::Expression attr_accessor :expressions, :alias def initialize expr, aliaz = nil From 80ad95bae41f4f5923faeb2e7b9cab4287e54fe9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 15:26:08 -0700 Subject: [PATCH 0743/1492] moving visitors around --- lib/arel.rb | 7 +------ lib/arel/select_manager.rb | 5 +++-- lib/arel/table.rb | 4 ++-- lib/arel/tree_manager.rb | 22 +++++++++++++++------- lib/arel/update_manager.rb | 6 +----- lib/arel/visitors.rb | 6 ++++++ lib/arel/visitors/mysql.rb | 16 ++++++++++++++++ lib/arel/visitors/to_sql.rb | 18 ++++++++++++++---- lib/arel/visitors/update_sql.rb | 26 -------------------------- 9 files changed, 58 insertions(+), 52 deletions(-) create mode 100644 lib/arel/visitors.rb create mode 100644 lib/arel/visitors/mysql.rb delete mode 100644 lib/arel/visitors/update_sql.rb diff --git a/lib/arel.rb b/lib/arel.rb index 85a866b0ce160..afef2019d4b3c 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -12,12 +12,7 @@ require 'arel/expression' #### -require 'arel/visitors/to_sql' -require 'arel/visitors/postgresql' -require 'arel/visitors/update_sql' -require 'arel/visitors/join_sql' -require 'arel/visitors/order_clauses' -require 'arel/visitors/dot' +require 'arel/visitors' require 'arel/tree_manager' require 'arel/insert_manager' diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 4866ea66c933d..21b9395120969 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -2,10 +2,11 @@ module Arel class SelectManager < Arel::TreeManager include Arel::Crud - def initialize engine - super + def initialize engine, table = nil + super(engine) @head = Nodes::SelectStatement.new @ctx = @head.cores.last + from table end def taken diff --git a/lib/arel/table.rb b/lib/arel/table.rb index a709a3d717766..025ef30e55cd4 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -37,11 +37,11 @@ def alias end def tm - SelectManager.new(@engine).from(self) + SelectManager.new(@engine, self) end def from table - SelectManager.new(@engine).from table + SelectManager.new(@engine, table) end def joins manager diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 11d34ec1380b4..4ee4a6f21910e 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -4,23 +4,31 @@ class TreeManager include Arel::Relation VISITORS = { - 'postgresql' => Arel::Visitors::PostgreSQL + 'postgresql' => Arel::Visitors::PostgreSQL, + 'mysql' => Arel::Visitors::MySQL, + 'mysql2' => Arel::Visitors::MySQL, } + attr_accessor :visitor + def initialize engine - @engine = engine - @pool = engine.connection_pool - @adapter = @pool.spec.config[:adapter] - @visitor_klass = VISITORS[@adapter] || Visitors::ToSql + @engine = engine + @visitor = nil end def to_dot Visitors::Dot.new.accept @head end + def visitor + return @visitor if @visitor + pool = @engine.connection_pool + adapter = pool.spec.config[:adapter] + @visitor = (VISITORS[adapter] || Visitors::ToSql).new(@engine) + end + def to_sql - viz = @visitor_klass.new @engine - viz.accept @head + visitor.accept @head end def initialize_copy other diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 0cb55549540ad..b74e0f2a27763 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -46,11 +46,7 @@ def set values end def to_sql - viz = @visitor_klass.new @engine - unless @engine.connection_pool.spec.config[:adapter] =~ /^mysql/ - viz.extend(Visitors::UpdateSql) - end - viz.accept @head + visitor.accept @head end end end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb new file mode 100644 index 0000000000000..22077d59436c0 --- /dev/null +++ b/lib/arel/visitors.rb @@ -0,0 +1,6 @@ +require 'arel/visitors/to_sql' +require 'arel/visitors/postgresql' +require 'arel/visitors/mysql' +require 'arel/visitors/join_sql' +require 'arel/visitors/order_clauses' +require 'arel/visitors/dot' diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb new file mode 100644 index 0000000000000..455122359185c --- /dev/null +++ b/lib/arel/visitors/mysql.rb @@ -0,0 +1,16 @@ +module Arel + module Visitors + class MySQL < Arel::Visitors::ToSql + 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?), + ("LIMIT #{o.limit}" if o.limit), + ].compact.join ' ' + end + + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2ccc9d7d3f7d9..d1cb115238387 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -22,15 +22,25 @@ def visit_Arel_Nodes_DeleteStatement o end def visit_Arel_Nodes_UpdateStatement o + if o.orders.empty? && o.limit.nil? + wheres = o.wheres + else + stmt = Nodes::SelectStatement.new + core = stmt.cores.first + core.froms = o.relation + core.projections = [o.relation.primary_key] + stmt.limit = o.limit + stmt.orders = o.orders + + wheres = [Nodes::In.new(o.relation.primary_key, [stmt])] + end + [ "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?), - ("LIMIT #{o.limit}" if o.limit), + ("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}", diff --git a/lib/arel/visitors/update_sql.rb b/lib/arel/visitors/update_sql.rb deleted file mode 100644 index 02196a0fb0a67..0000000000000 --- a/lib/arel/visitors/update_sql.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Arel - module Visitors - module UpdateSql - def visit_Arel_Nodes_UpdateStatement o - if o.orders.empty? && o.limit.nil? - wheres = o.wheres - else - stmt = Nodes::SelectStatement.new - core = stmt.cores.first - core.froms = o.relation - core.projections = [o.relation.primary_key] - stmt.limit = o.limit - stmt.orders = o.orders - - wheres = [Nodes::In.new(o.relation.primary_key, [stmt])] - 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 - end - end -end From 871c9ebde1eeaf4ee9cd256edb5133007bd8fa92 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 15:27:17 -0700 Subject: [PATCH 0744/1492] removing duplicate code --- lib/arel/update_manager.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index b74e0f2a27763..3f6a48375103a 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -44,9 +44,5 @@ def set values end self end - - def to_sql - visitor.accept @head - end end end From 2473eae11f16ec953a33b26a65c5f74be5382015 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 15:30:27 -0700 Subject: [PATCH 0745/1492] changing accessor to a writer --- lib/arel/tree_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 4ee4a6f21910e..fb5037cd9fdcb 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -9,7 +9,7 @@ class TreeManager 'mysql2' => Arel::Visitors::MySQL, } - attr_accessor :visitor + attr_writer :visitor def initialize engine @engine = engine From 03724fb1789198cc394f6e8b69cf9404e03eddd7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Sep 2010 15:45:00 -0700 Subject: [PATCH 0746/1492] caching visitor on a per engine basis --- lib/arel/tree_manager.rb | 17 ++--------------- lib/arel/visitors.rb | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index fb5037cd9fdcb..8a13345c910bf 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -3,30 +3,17 @@ class TreeManager # FIXME: Remove this. include Arel::Relation - VISITORS = { - 'postgresql' => Arel::Visitors::PostgreSQL, - 'mysql' => Arel::Visitors::MySQL, - 'mysql2' => Arel::Visitors::MySQL, - } - - attr_writer :visitor + attr_accessor :visitor def initialize engine @engine = engine - @visitor = nil + @visitor = Visitors.visitor_for @engine end def to_dot Visitors::Dot.new.accept @head end - def visitor - return @visitor if @visitor - pool = @engine.connection_pool - adapter = pool.spec.config[:adapter] - @visitor = (VISITORS[adapter] || Visitors::ToSql).new(@engine) - end - def to_sql visitor.accept @head end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 22077d59436c0..879635575b8af 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -4,3 +4,23 @@ require 'arel/visitors/join_sql' require 'arel/visitors/order_clauses' require 'arel/visitors/dot' + +module Arel + module Visitors + VISITORS = { + 'postgresql' => Arel::Visitors::PostgreSQL, + 'mysql' => Arel::Visitors::MySQL, + 'mysql2' => Arel::Visitors::MySQL, + } + + 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 + end +end From 7615bd7f928390d0ba9501e5206fd89ce6ce44fc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 09:28:10 -0700 Subject: [PATCH 0747/1492] using the connection pool while visiting --- lib/arel/tree_manager.rb | 2 +- lib/arel/visitors/to_sql.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 8a13345c910bf..077458fe18b11 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -15,7 +15,7 @@ def to_dot end def to_sql - visitor.accept @head + @visitor.accept @head end def initialize_copy other diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d1cb115238387..69c7736a4ba9e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -9,8 +9,10 @@ def initialize engine end def accept object - @connection = @engine.connection - visit object + @engine.connection_pool.with_connection do |conn| + @connection = conn + visit object + end end private From 487df1771ded1fb065a53ebe9d1a5a9c119478e3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 09:41:48 -0700 Subject: [PATCH 0748/1492] adding an oracle visitor --- lib/arel/nodes.rb | 1 + lib/arel/nodes/less_than_or_equal.rb | 6 ++++++ lib/arel/visitors.rb | 8 +++++--- lib/arel/visitors/oracle.rb | 15 +++++++++++++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/arel/select_manager_spec.rb | 4 ++++ spec/arel/visitors/oracle_spec.rb | 22 ++++++++++++++++++++++ 7 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 lib/arel/nodes/less_than_or_equal.rb create mode 100644 lib/arel/visitors/oracle.rb create mode 100644 spec/arel/visitors/oracle_spec.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index fade666ff7534..6ed05fb31b4aa 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -9,6 +9,7 @@ require 'arel/nodes/greater_than' require 'arel/nodes/greater_than_or_equal' require 'arel/nodes/less_than' +require 'arel/nodes/less_than_or_equal' require 'arel/nodes/in' require 'arel/nodes/lock' diff --git a/lib/arel/nodes/less_than_or_equal.rb b/lib/arel/nodes/less_than_or_equal.rb new file mode 100644 index 0000000000000..55449d12f120a --- /dev/null +++ b/lib/arel/nodes/less_than_or_equal.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class LessThanOrEqual < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 879635575b8af..deb4a4f991fab 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -1,6 +1,7 @@ require 'arel/visitors/to_sql' require 'arel/visitors/postgresql' require 'arel/visitors/mysql' +require 'arel/visitors/oracle' require 'arel/visitors/join_sql' require 'arel/visitors/order_clauses' require 'arel/visitors/dot' @@ -8,9 +9,10 @@ module Arel module Visitors VISITORS = { - 'postgresql' => Arel::Visitors::PostgreSQL, - 'mysql' => Arel::Visitors::MySQL, - 'mysql2' => Arel::Visitors::MySQL, + 'postgresql' => Arel::Visitors::PostgreSQL, + 'mysql' => Arel::Visitors::MySQL, + 'mysql2' => Arel::Visitors::MySQL, + 'oracle_enhanced' => Arel::Visitors::Oracle, } ENGINE_VISITORS = Hash.new do |hash, engine| diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb new file mode 100644 index 0000000000000..840a7a9aced51 --- /dev/null +++ b/lib/arel/visitors/oracle.rb @@ -0,0 +1,15 @@ +module Arel + module Visitors + class Oracle < Arel::Visitors::ToSql + def visit_Arel_Nodes_SelectStatement o + if o.limit + o.cores.last.wheres.push Nodes::LessThanOrEqual.new( + Nodes::SqlLiteral.new('ROWNUM'), o.limit + ) + o.limit = nil + end + super + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 69c7736a4ba9e..5ec811a53acc4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -148,6 +148,10 @@ 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 diff --git a/spec/arel/select_manager_spec.rb b/spec/arel/select_manager_spec.rb index f301e3afd0a26..7002d937a2fdc 100644 --- a/spec/arel/select_manager_spec.rb +++ b/spec/arel/select_manager_spec.rb @@ -15,6 +15,10 @@ def initialize engine @config = { :adapter => 'sqlite3' } end + def with_connection + yield self + end + def connection self end diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/arel/visitors/oracle_spec.rb new file mode 100644 index 0000000000000..384725b788947 --- /dev/null +++ b/spec/arel/visitors/oracle_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +module Arel + module Visitors + describe 'the oracle visitor' do + before do + @visitor = Oracle.new Table.engine + end + + describe 'Nodes::SelectStatement' do + describe 'limit' do + it 'adds a rownum clause' do + stmt = Nodes::SelectStatement.new + stmt.limit = 10 + sql = @visitor.accept stmt + sql.should be_like %{ SELECT WHERE ROWNUM <= 10 } + end + end + end + end + end +end From f63badf42738c4a553e84e3d121786000c67c623 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 10:09:21 -0700 Subject: [PATCH 0749/1492] creating a subquery when there is an order and a limit --- lib/arel/visitors/oracle.rb | 10 +++++++++- spec/arel/visitors/oracle_spec.rb | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 840a7a9aced51..afea683080686 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -2,12 +2,20 @@ module Arel module Visitors class Oracle < Arel::Visitors::ToSql def visit_Arel_Nodes_SelectStatement o - if o.limit + if o.limit && o.orders.empty? o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit ) o.limit = nil + return super end + + if o.limit && !o.orders.empty? + limit = o.limit + o.limit = nil + return "SELECT * FROM (#{super}) WHERE ROWNUM <= #{limit}" + end + super end end diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/arel/visitors/oracle_spec.rb index 384725b788947..87a1c378ac1d1 100644 --- a/spec/arel/visitors/oracle_spec.rb +++ b/spec/arel/visitors/oracle_spec.rb @@ -15,6 +15,16 @@ module Visitors sql = @visitor.accept stmt sql.should be_like %{ SELECT WHERE ROWNUM <= 10 } end + + it 'creates a subquery when there is order_by' do + stmt = Nodes::SelectStatement.new + stmt.orders << Nodes::SqlLiteral.new('foo') + stmt.limit = 10 + sql = @visitor.accept stmt + sql.should be_like %{ + SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10 + } + end end end end From 58d82b23a102ca1eb5510b8c49bc097b402a332d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 10:24:31 -0700 Subject: [PATCH 0750/1492] dealing with limits and offsets --- lib/arel/visitors/oracle.rb | 24 +++++++++++++++++++++++- spec/arel/visitors/oracle_spec.rb | 15 +++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index afea683080686..c3af68cc363b9 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -1,8 +1,10 @@ module Arel module Visitors class Oracle < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_SelectStatement o - if o.limit && o.orders.empty? + if o.limit && o.orders.empty? && !o.offset o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit ) @@ -10,6 +12,22 @@ def visit_Arel_Nodes_SelectStatement o return super end + if o.limit && o.offset + limit = o.limit.to_i + offset = o.offset + o.limit = nil + o.offset = nil + sql = super + return <<-eosql + SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (#{sql}) raw_sql_ + WHERE rownum <= #{offset.value.to_i + limit} + ) + WHERE #{visit offset} + eosql + end + if o.limit && !o.orders.empty? limit = o.limit o.limit = nil @@ -18,6 +36,10 @@ def visit_Arel_Nodes_SelectStatement o super end + + def visit_Arel_Nodes_Offset o + "raw_rnum_ > #{visit o.value}" + end end end end diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/arel/visitors/oracle_spec.rb index 87a1c378ac1d1..07ac352893df1 100644 --- a/spec/arel/visitors/oracle_spec.rb +++ b/spec/arel/visitors/oracle_spec.rb @@ -25,6 +25,21 @@ module Visitors SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10 } end + + it 'creates a different subquery when there is an offset' do + stmt = Nodes::SelectStatement.new + stmt.limit = 10 + stmt.offset = Nodes::Offset.new(10) + sql = @visitor.accept stmt + sql.should be_like %{ + SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (SELECT ) raw_sql_ + WHERE rownum <= 20 + ) + WHERE raw_rnum_ > 10 + } + end end end end From f381da2738ec8c2aac3c34fead32688ea7b08d74 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 11:17:17 -0700 Subject: [PATCH 0751/1492] adding more oracle hacks --- lib/arel/visitors/oracle.rb | 19 +++++++++++++++++++ spec/arel/visitors/oracle_spec.rb | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index c3af68cc363b9..46a3ad4c786be 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -4,6 +4,8 @@ class Oracle < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o + order_hacks(o) + if o.limit && o.orders.empty? && !o.offset o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit @@ -40,6 +42,23 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_Offset o "raw_rnum_ > #{visit o.value}" end + + ### + # Hacks for the order clauses specific to Oracle + def order_hacks o + return if o.orders.empty? + return unless o.cores.any? do |core| + core.projections.any? do |projection| + /DISTINCT.*FIRST_VALUE/ === projection + end + end + orders = o.orders + o.orders = [] + orders.each_with_index do |order, i| + o.orders << + Nodes::SqlLiteral.new("alias_#{i}__ #{'DESC' if /\bdesc$/i === order}") + end + end end end end diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/arel/visitors/oracle_spec.rb index 07ac352893df1..0995ea6bf215e 100644 --- a/spec/arel/visitors/oracle_spec.rb +++ b/spec/arel/visitors/oracle_spec.rb @@ -7,6 +7,18 @@ module Visitors @visitor = Oracle.new Table.engine 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.should be_like %{ + SELECT #{select} ORDER BY alias_0__ + } + end + describe 'Nodes::SelectStatement' do describe 'limit' do it 'adds a rownum clause' do From d94122485a8f89f13293438142fa292640600c54 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 11:51:34 -0700 Subject: [PATCH 0752/1492] adding offset edge --- lib/arel/visitors/dot.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index e79af6c50b620..a65a7f73017cc 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -71,6 +71,7 @@ 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 From aa6a82617178698f4f5083cc8ba08d2f761583af Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 13:56:37 -0700 Subject: [PATCH 0753/1492] avoid modifying the ast in certain cases --- lib/arel/visitors/oracle.rb | 6 ++++-- spec/arel/visitors/oracle_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 46a3ad4c786be..360715f307b72 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -15,11 +15,12 @@ def visit_Arel_Nodes_SelectStatement o end if o.limit && o.offset + o = o.dup limit = o.limit.to_i offset = o.offset o.limit = nil o.offset = nil - sql = super + sql = super(o) return <<-eosql SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ @@ -31,9 +32,10 @@ def visit_Arel_Nodes_SelectStatement o end if o.limit && !o.orders.empty? + o = o.dup limit = o.limit o.limit = nil - return "SELECT * FROM (#{super}) WHERE ROWNUM <= #{limit}" + return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{limit}" end super diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/arel/visitors/oracle_spec.rb index 0995ea6bf215e..784f4b24e17dd 100644 --- a/spec/arel/visitors/oracle_spec.rb +++ b/spec/arel/visitors/oracle_spec.rb @@ -19,6 +19,18 @@ module Visitors } 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) + check sql.should == sql2 + end + describe 'Nodes::SelectStatement' do describe 'limit' do it 'adds a rownum clause' do @@ -28,6 +40,15 @@ module Visitors sql.should be_like %{ SELECT WHERE ROWNUM <= 10 } end + it 'is idempotent' do + stmt = Nodes::SelectStatement.new + stmt.orders << Nodes::SqlLiteral.new('foo') + stmt.limit = 10 + sql = @visitor.accept stmt + sql2 = @visitor.accept stmt + check sql.should == sql2 + end + it 'creates a subquery when there is order_by' do stmt = Nodes::SelectStatement.new stmt.orders << Nodes::SqlLiteral.new('foo') @@ -52,6 +73,15 @@ module Visitors WHERE raw_rnum_ > 10 } end + + it 'is idempotent with different subquery' do + stmt = Nodes::SelectStatement.new + stmt.limit = 10 + stmt.offset = Nodes::Offset.new(10) + sql = @visitor.accept stmt + sql2 = @visitor.accept stmt + check sql.should == sql2 + end end end end From 6420041b88bc16d8f838815185b4d004907b837e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 14:56:16 -0700 Subject: [PATCH 0754/1492] fixing formatting --- lib/arel/visitors/oracle.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 360715f307b72..8d6c15f37d484 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -4,7 +4,7 @@ class Oracle < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o - order_hacks(o) + o = order_hacks(o) if o.limit && o.orders.empty? && !o.offset o.cores.last.wheres.push Nodes::LessThanOrEqual.new( @@ -15,10 +15,10 @@ def visit_Arel_Nodes_SelectStatement o end if o.limit && o.offset - o = o.dup - limit = o.limit.to_i - offset = o.offset - o.limit = nil + o = o.dup + limit = o.limit.to_i + offset = o.offset + o.limit = nil o.offset = nil sql = super(o) return <<-eosql @@ -32,8 +32,8 @@ def visit_Arel_Nodes_SelectStatement o end if o.limit && !o.orders.empty? - o = o.dup - limit = o.limit + o = o.dup + limit = o.limit o.limit = nil return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{limit}" end @@ -48,18 +48,19 @@ def visit_Arel_Nodes_Offset o ### # Hacks for the order clauses specific to Oracle def order_hacks o - return if o.orders.empty? - return unless o.cores.any? do |core| + 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 - orders = o.orders + orders = o.orders o.orders = [] orders.each_with_index do |order, i| o.orders << Nodes::SqlLiteral.new("alias_#{i}__ #{'DESC' if /\bdesc$/i === order}") end + o end end end From 245d797a8ccab3ed2de9a0eedf455d3094a091ce Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 15:09:26 -0700 Subject: [PATCH 0755/1492] yay, more oracle hacks --- lib/arel/visitors/oracle.rb | 4 ++-- spec/arel/visitors/oracle_spec.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 8d6c15f37d484..659b75f16dcb6 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -54,11 +54,11 @@ def order_hacks o /DISTINCT.*FIRST_VALUE/ === projection end end - orders = o.orders + orders = o.orders.map { |x| visit x }.join(', ').split(',') o.orders = [] orders.each_with_index do |order, i| o.orders << - Nodes::SqlLiteral.new("alias_#{i}__ #{'DESC' if /\bdesc$/i === order}") + Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i === order}") end o end diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/arel/visitors/oracle_spec.rb index 784f4b24e17dd..cdf0e3427f6bd 100644 --- a/spec/arel/visitors/oracle_spec.rb +++ b/spec/arel/visitors/oracle_spec.rb @@ -31,6 +31,18 @@ module Visitors check sql.should == 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.should be_like %{ + SELECT #{select} ORDER BY alias_0__, alias_1__ + } + end + describe 'Nodes::SelectStatement' do describe 'limit' do it 'adds a rownum clause' do From 6b86ae4f9f2fb8cd145f958753fedf16aae3a0d4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 15:21:54 -0700 Subject: [PATCH 0756/1492] shuffling around the spec directory --- spec/{arel => }/activerecord_compat_spec.rb | 0 spec/algebra/unit/predicates/binary_spec.rb | 35 --- spec/algebra/unit/predicates/equality_spec.rb | 29 -- spec/algebra/unit/predicates/in_spec.rb | 12 - .../unit/predicates/inequality_spec.rb | 32 --- .../algebra/unit/predicates/predicate_spec.rb | 22 -- .../algebra/unit/primitives/attribute_spec.rb | 175 ------------ .../unit/primitives/expression_spec.rb | 39 --- spec/algebra/unit/primitives/value_spec.rb | 15 - spec/algebra/unit/relations/alias_spec.rb | 16 -- spec/algebra/unit/relations/delete_spec.rb | 9 - spec/algebra/unit/relations/group_spec.rb | 10 - spec/algebra/unit/relations/insert_spec.rb | 9 - spec/algebra/unit/relations/join_spec.rb | 18 -- spec/algebra/unit/relations/order_spec.rb | 21 -- spec/algebra/unit/relations/project_spec.rb | 34 --- spec/algebra/unit/relations/relation_spec.rb | 236 ---------------- spec/algebra/unit/relations/skip_spec.rb | 10 - spec/algebra/unit/relations/take_spec.rb | 10 - spec/algebra/unit/relations/update_spec.rb | 9 - spec/algebra/unit/relations/where_spec.rb | 19 -- spec/algebra/unit/session/session_spec.rb | 84 ------ spec/{arel => }/attributes/attribute_spec.rb | 0 spec/attributes/boolean_spec.rb | 57 ---- spec/attributes/float_spec.rb | 119 -------- spec/attributes/header_spec.rb | 42 --- spec/attributes/integer_spec.rb | 119 -------- spec/attributes/string_spec.rb | 43 --- spec/attributes/time_spec.rb | 24 -- spec/{arel => }/attributes_spec.rb | 0 spec/{arel => }/crud_spec.rb | 0 spec/{arel => }/delete_manager_spec.rb | 0 .../integration/joins/cross_engine_spec.rb | 61 ----- .../memory/unit/relations/array_spec.rb | 33 --- .../memory/unit/relations/insert_spec.rb | 28 -- .../memory/unit/relations/join_spec.rb | 32 --- .../memory/unit/relations/order_spec.rb | 28 -- .../memory/unit/relations/project_spec.rb | 27 -- .../memory/unit/relations/skip_spec.rb | 31 --- .../memory/unit/relations/take_spec.rb | 28 -- .../memory/unit/relations/where_spec.rb | 43 --- .../integration/joins/with_adjacency_spec.rb | 258 ------------------ .../joins/with_aggregations_spec.rb | 221 --------------- .../integration/joins/with_compounds_spec.rb | 137 ---------- spec/engines/sql/unit/engine_spec.rb | 65 ----- .../sql/unit/predicates/binary_spec.rb | 140 ---------- .../sql/unit/predicates/equality_spec.rb | 75 ----- spec/engines/sql/unit/predicates/in_spec.rb | 179 ------------ .../engines/sql/unit/predicates/noteq_spec.rb | 75 ----- .../sql/unit/predicates/predicates_spec.rb | 79 ------ .../sql/unit/primitives/attribute_spec.rb | 36 --- .../sql/unit/primitives/expression_spec.rb | 28 -- .../sql/unit/primitives/literal_spec.rb | 43 --- .../engines/sql/unit/primitives/value_spec.rb | 29 -- spec/engines/sql/unit/relations/alias_spec.rb | 53 ---- .../engines/sql/unit/relations/delete_spec.rb | 83 ------ spec/engines/sql/unit/relations/from_spec.rb | 64 ----- spec/engines/sql/unit/relations/group_spec.rb | 72 ----- .../engines/sql/unit/relations/having_spec.rb | 78 ------ .../engines/sql/unit/relations/insert_spec.rb | 143 ---------- spec/engines/sql/unit/relations/join_spec.rb | 180 ------------ spec/engines/sql/unit/relations/lock_spec.rb | 86 ------ spec/engines/sql/unit/relations/order_spec.rb | 161 ----------- .../sql/unit/relations/project_spec.rb | 143 ---------- spec/engines/sql/unit/relations/skip_spec.rb | 41 --- spec/engines/sql/unit/relations/table_spec.rb | 122 --------- spec/engines/sql/unit/relations/take_spec.rb | 75 ----- .../engines/sql/unit/relations/update_spec.rb | 203 -------------- spec/engines/sql/unit/relations/where_spec.rb | 72 ----- spec/{arel => }/insert_manager_spec.rb | 0 spec/{arel => }/nodes/count_spec.rb | 0 .../{arel => }/nodes/delete_statement_spec.rb | 0 spec/{arel => }/nodes/equality_spec.rb | 0 .../{arel => }/nodes/insert_statement_spec.rb | 0 spec/{arel => }/nodes/or_spec.rb | 0 spec/{arel => }/nodes/select_core_spec.rb | 0 .../{arel => }/nodes/select_statement_spec.rb | 0 spec/{arel => }/nodes/sql_literal_spec.rb | 0 spec/{arel => }/nodes/sum_spec.rb | 0 .../{arel => }/nodes/update_statement_spec.rb | 0 spec/relations/join_spec.rb | 42 --- spec/relations/relation_spec.rb | 31 --- spec/{arel => }/select_manager_spec.rb | 0 spec/shared/relation_spec.rb | 255 ----------------- spec/sql/christener_spec.rb | 70 ----- spec/{arel => }/table_spec.rb | 0 spec/{arel => }/update_manager_spec.rb | 0 spec/{arel => }/visitors/join_sql_spec.rb | 0 spec/{arel => }/visitors/oracle_spec.rb | 0 spec/{arel => }/visitors/to_sql_spec.rb | 0 90 files changed, 4898 deletions(-) rename spec/{arel => }/activerecord_compat_spec.rb (100%) delete mode 100644 spec/algebra/unit/predicates/binary_spec.rb delete mode 100644 spec/algebra/unit/predicates/equality_spec.rb delete mode 100644 spec/algebra/unit/predicates/in_spec.rb delete mode 100644 spec/algebra/unit/predicates/inequality_spec.rb delete mode 100644 spec/algebra/unit/predicates/predicate_spec.rb delete mode 100644 spec/algebra/unit/primitives/attribute_spec.rb delete mode 100644 spec/algebra/unit/primitives/expression_spec.rb delete mode 100644 spec/algebra/unit/primitives/value_spec.rb delete mode 100644 spec/algebra/unit/relations/alias_spec.rb delete mode 100644 spec/algebra/unit/relations/delete_spec.rb delete mode 100644 spec/algebra/unit/relations/group_spec.rb delete mode 100644 spec/algebra/unit/relations/insert_spec.rb delete mode 100644 spec/algebra/unit/relations/join_spec.rb delete mode 100644 spec/algebra/unit/relations/order_spec.rb delete mode 100644 spec/algebra/unit/relations/project_spec.rb delete mode 100644 spec/algebra/unit/relations/relation_spec.rb delete mode 100644 spec/algebra/unit/relations/skip_spec.rb delete mode 100644 spec/algebra/unit/relations/take_spec.rb delete mode 100644 spec/algebra/unit/relations/update_spec.rb delete mode 100644 spec/algebra/unit/relations/where_spec.rb delete mode 100644 spec/algebra/unit/session/session_spec.rb rename spec/{arel => }/attributes/attribute_spec.rb (100%) delete mode 100644 spec/attributes/boolean_spec.rb delete mode 100644 spec/attributes/float_spec.rb delete mode 100644 spec/attributes/header_spec.rb delete mode 100644 spec/attributes/integer_spec.rb delete mode 100644 spec/attributes/string_spec.rb delete mode 100644 spec/attributes/time_spec.rb rename spec/{arel => }/attributes_spec.rb (100%) rename spec/{arel => }/crud_spec.rb (100%) rename spec/{arel => }/delete_manager_spec.rb (100%) delete mode 100644 spec/engines/memory/integration/joins/cross_engine_spec.rb delete mode 100644 spec/engines/memory/unit/relations/array_spec.rb delete mode 100644 spec/engines/memory/unit/relations/insert_spec.rb delete mode 100644 spec/engines/memory/unit/relations/join_spec.rb delete mode 100644 spec/engines/memory/unit/relations/order_spec.rb delete mode 100644 spec/engines/memory/unit/relations/project_spec.rb delete mode 100644 spec/engines/memory/unit/relations/skip_spec.rb delete mode 100644 spec/engines/memory/unit/relations/take_spec.rb delete mode 100644 spec/engines/memory/unit/relations/where_spec.rb delete mode 100644 spec/engines/sql/integration/joins/with_adjacency_spec.rb delete mode 100644 spec/engines/sql/integration/joins/with_aggregations_spec.rb delete mode 100644 spec/engines/sql/integration/joins/with_compounds_spec.rb delete mode 100644 spec/engines/sql/unit/engine_spec.rb delete mode 100644 spec/engines/sql/unit/predicates/binary_spec.rb delete mode 100644 spec/engines/sql/unit/predicates/equality_spec.rb delete mode 100644 spec/engines/sql/unit/predicates/in_spec.rb delete mode 100644 spec/engines/sql/unit/predicates/noteq_spec.rb delete mode 100644 spec/engines/sql/unit/predicates/predicates_spec.rb delete mode 100644 spec/engines/sql/unit/primitives/attribute_spec.rb delete mode 100644 spec/engines/sql/unit/primitives/expression_spec.rb delete mode 100644 spec/engines/sql/unit/primitives/literal_spec.rb delete mode 100644 spec/engines/sql/unit/primitives/value_spec.rb delete mode 100644 spec/engines/sql/unit/relations/alias_spec.rb delete mode 100644 spec/engines/sql/unit/relations/delete_spec.rb delete mode 100644 spec/engines/sql/unit/relations/from_spec.rb delete mode 100644 spec/engines/sql/unit/relations/group_spec.rb delete mode 100644 spec/engines/sql/unit/relations/having_spec.rb delete mode 100644 spec/engines/sql/unit/relations/insert_spec.rb delete mode 100644 spec/engines/sql/unit/relations/join_spec.rb delete mode 100644 spec/engines/sql/unit/relations/lock_spec.rb delete mode 100644 spec/engines/sql/unit/relations/order_spec.rb delete mode 100644 spec/engines/sql/unit/relations/project_spec.rb delete mode 100644 spec/engines/sql/unit/relations/skip_spec.rb delete mode 100644 spec/engines/sql/unit/relations/table_spec.rb delete mode 100644 spec/engines/sql/unit/relations/take_spec.rb delete mode 100644 spec/engines/sql/unit/relations/update_spec.rb delete mode 100644 spec/engines/sql/unit/relations/where_spec.rb rename spec/{arel => }/insert_manager_spec.rb (100%) rename spec/{arel => }/nodes/count_spec.rb (100%) rename spec/{arel => }/nodes/delete_statement_spec.rb (100%) rename spec/{arel => }/nodes/equality_spec.rb (100%) rename spec/{arel => }/nodes/insert_statement_spec.rb (100%) rename spec/{arel => }/nodes/or_spec.rb (100%) rename spec/{arel => }/nodes/select_core_spec.rb (100%) rename spec/{arel => }/nodes/select_statement_spec.rb (100%) rename spec/{arel => }/nodes/sql_literal_spec.rb (100%) rename spec/{arel => }/nodes/sum_spec.rb (100%) rename spec/{arel => }/nodes/update_statement_spec.rb (100%) delete mode 100644 spec/relations/join_spec.rb delete mode 100644 spec/relations/relation_spec.rb rename spec/{arel => }/select_manager_spec.rb (100%) delete mode 100644 spec/shared/relation_spec.rb delete mode 100644 spec/sql/christener_spec.rb rename spec/{arel => }/table_spec.rb (100%) rename spec/{arel => }/update_manager_spec.rb (100%) rename spec/{arel => }/visitors/join_sql_spec.rb (100%) rename spec/{arel => }/visitors/oracle_spec.rb (100%) rename spec/{arel => }/visitors/to_sql_spec.rb (100%) diff --git a/spec/arel/activerecord_compat_spec.rb b/spec/activerecord_compat_spec.rb similarity index 100% rename from spec/arel/activerecord_compat_spec.rb rename to spec/activerecord_compat_spec.rb diff --git a/spec/algebra/unit/predicates/binary_spec.rb b/spec/algebra/unit/predicates/binary_spec.rb deleted file mode 100644 index 051aeeeb6e0c6..0000000000000 --- a/spec/algebra/unit/predicates/binary_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Binary do - before do - @relation = Arel::Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - class ConcreteBinary < Binary - end - end - - describe '#bind' do - before do - @another_relation = @relation.alias - end - - describe 'when both operands are attributes' do - it "manufactures an expression with the attributes bound to the relation" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ - should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) - end - end - - describe 'when an operand is a value' do - it "manufactures an expression with unmodified values" do - ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) - end - end - end - end - end -end diff --git a/spec/algebra/unit/predicates/equality_spec.rb b/spec/algebra/unit/predicates/equality_spec.rb deleted file mode 100644 index 7d1d79ff35475..0000000000000 --- a/spec/algebra/unit/predicates/equality_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Equality do - before do - @relation1 = Arel::Table.new(:users) - @relation2 = Arel::Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:user_id] - end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - check Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) - Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the predicates are identical" do - Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) - end - - it "is commutative on the attributes" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) - end - end - end - end -end diff --git a/spec/algebra/unit/predicates/in_spec.rb b/spec/algebra/unit/predicates/in_spec.rb deleted file mode 100644 index b9e15d63a4a24..0000000000000 --- a/spec/algebra/unit/predicates/in_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe In do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - end - end -end diff --git a/spec/algebra/unit/predicates/inequality_spec.rb b/spec/algebra/unit/predicates/inequality_spec.rb deleted file mode 100644 index f95b8d120ec80..0000000000000 --- a/spec/algebra/unit/predicates/inequality_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Inequality do - before do - relation1 = Arel::Table.new(:users) - relation2 = Arel::Table.new(:photos) - left = relation1[:id] - right = relation2[:user_id] - @a = Inequality.new(left, right) - @b = Inequality.new(right, left) - end - - describe 'operator' do - it "should have one" do - @a.operator.should == :"!=" - end - end - - describe '==' do - it "is equal to itself" do - @a.should == @a - end - - it "should not care abount children order" do - @a.should == @b - end - end - end - end -end diff --git a/spec/algebra/unit/predicates/predicate_spec.rb b/spec/algebra/unit/predicates/predicate_spec.rb deleted file mode 100644 index 6acc047cbbf26..0000000000000 --- a/spec/algebra/unit/predicates/predicate_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Polyadic do - before do - @relation1 = Arel::Table.new(:users) - @relation2 = Arel::Table.new(:photos) - @a = @relation1[:id] - @b = @relation2[:user_id] - end - - describe '==' do - left = Polyadic.new @a, @b - right = Polyadic.new @b, @a - - left.should != right - left.should == right - end - end - end -end diff --git a/spec/algebra/unit/primitives/attribute_spec.rb b/spec/algebra/unit/primitives/attribute_spec.rb deleted file mode 100644 index 4026c0de14e2e..0000000000000 --- a/spec/algebra/unit/primitives/attribute_spec.rb +++ /dev/null @@ -1,175 +0,0 @@ -require 'spec_helper' - -module Arel - describe Attribute do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe 'Attribute::Transformations' do - describe '#as' do - it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) - end - end - - describe '#bind' do - it "manufactures an attribute with the relation bound and self as an ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) - end - - it "returns self if the substituting to the same relation" do - @attribute.bind(@relation).should == @attribute - end - end - - describe '#to_attribute' do - describe 'when the given relation is the same as the attributes relation' do - it "returns self" do - @attribute.to_attribute(@relation).should == @attribute - end - end - - describe 'when the given relation differs from the attributes relation' do - it 'binds to the new relation' do - @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation) - end - end - end - end - - describe '#column' do - it "returns the corresponding column in the relation" do - @attribute.column.should == @relation.column_for(@attribute) - end - end - - describe '#engine' do - it "delegates to its relation" do - Attribute.new(@relation, :id).engine.should == @relation.engine - end - end - - describe 'Attribute::Congruence' do - describe '/' do - before do - @aliased_relation = @relation.alias - @doubly_aliased_relation = @aliased_relation.alias - end - - describe 'when dividing two unrelated attributes' do - it "returns 0.0" do - (@relation[:id] / @relation[:name]).should == 0.0 - end - end - - describe 'when dividing two matching attributes' do - it 'returns a the highest score for the most similar attributes' do - check((@aliased_relation[:id] / @relation[:id]).should == (@aliased_relation[:id] / @relation[:id])) - (@aliased_relation[:id] / @relation[:id]).should < (@aliased_relation[:id] / @aliased_relation[:id]) - end - end - end - end - - describe 'Attribute::Predications' do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#eq' do - it "manufactures an equality predicate" do - @attribute.eq('name').should == Predicates::Equality.new(@attribute, 'name') - end - end - - describe '#lt' do - it "manufactures a less-than predicate" do - @attribute.lt(10).should == Predicates::LessThan.new(@attribute, 10) - end - end - - describe '#lteq' do - it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == Predicates::LessThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#gt' do - it "manufactures a greater-than predicate" do - @attribute.gt(10).should == Predicates::GreaterThan.new(@attribute, 10) - end - end - - describe '#gteq' do - it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == Predicates::GreaterThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#matches' do - it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Predicates::Match.new(@attribute, /.*/) - end - end - - describe '#in' do - it "manufactures an in predicate" do - @attribute.in(1..30).should == Predicates::In.new(@attribute, (1..30)) - end - end - end - - describe Attribute::Expressions do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#count' do - it "manufactures a count Expression" do - @attribute.count.should == Count.new(@attribute) - end - end - - describe '#sum' do - it "manufactures a sum Expression" do - @attribute.sum.should == Sum.new(@attribute) - end - end - - describe '#maximum' do - it "manufactures a maximum Expression" do - @attribute.maximum.should == Maximum.new(@attribute) - end - end - - describe '#minimum' do - it "manufactures a minimum Expression" do - @attribute.minimum.should == Minimum.new(@attribute) - end - end - - describe '#average' do - it "manufactures an average Expression" do - @attribute.average.should == Average.new(@attribute) - end - end - end - - describe Attribute::Orderings do - describe '#asc' do - it 'manufactures an ascending ordering' do - @attribute.asc.should == Ascending.new(@attribute) - end - end - - describe '#desc' do - it 'manufactures a descending ordering' do - @attribute.desc.should == Descending.new(@attribute) - end - end - end - end -end diff --git a/spec/algebra/unit/primitives/expression_spec.rb b/spec/algebra/unit/primitives/expression_spec.rb deleted file mode 100644 index f95ef69f96dde..0000000000000 --- a/spec/algebra/unit/primitives/expression_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'spec_helper' - -module Arel - describe Expression do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe 'Expression::Transformations' do - before do - @expression = Count.new(@attribute) - end - - describe '#bind' do - it "manufactures an attribute with a rebound relation and self as the ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) - end - - it "returns self if the substituting to the same relation" do - @expression.bind(@relation).should == @expression - end - end - - describe '#as' do - it "manufactures an aliased expression" do - @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) - end - end - - describe '#to_attribute' do - it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression) - end - end - end - end -end diff --git a/spec/algebra/unit/primitives/value_spec.rb b/spec/algebra/unit/primitives/value_spec.rb deleted file mode 100644 index 8fed752d664b6..0000000000000 --- a/spec/algebra/unit/primitives/value_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -module Arel - describe Value do - before do - @relation = Table.new(:users) - end - - describe '#bind' do - it "manufactures a new value whose relation is the provided relation" do - Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) - end - end - end -end diff --git a/spec/algebra/unit/relations/alias_spec.rb b/spec/algebra/unit/relations/alias_spec.rb deleted file mode 100644 index eaf31652b9ca9..0000000000000 --- a/spec/algebra/unit/relations/alias_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'spec_helper' - -module Arel - describe Alias do - before do - @relation = Table.new(:users) - end - - describe '==' do - it "obtains if the objects are the same" do - check Alias.new(@relation).should_not == Alias.new(@relation) - (aliaz = Alias.new(@relation)).should == aliaz - end - end - end -end diff --git a/spec/algebra/unit/relations/delete_spec.rb b/spec/algebra/unit/relations/delete_spec.rb deleted file mode 100644 index c244be863151a..0000000000000 --- a/spec/algebra/unit/relations/delete_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'spec_helper' - -module Arel - describe Deletion do - before do - @relation = Table.new(:users) - end - end -end diff --git a/spec/algebra/unit/relations/group_spec.rb b/spec/algebra/unit/relations/group_spec.rb deleted file mode 100644 index 48fc818682579..0000000000000 --- a/spec/algebra/unit/relations/group_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'spec_helper' - -module Arel - describe Group do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - end -end diff --git a/spec/algebra/unit/relations/insert_spec.rb b/spec/algebra/unit/relations/insert_spec.rb deleted file mode 100644 index 3141fa2fc4e5c..0000000000000 --- a/spec/algebra/unit/relations/insert_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'spec_helper' - -module Arel - describe Insert do - before do - @relation = Table.new(:users) - end - end -end diff --git a/spec/algebra/unit/relations/join_spec.rb b/spec/algebra/unit/relations/join_spec.rb deleted file mode 100644 index 54034a2e320c4..0000000000000 --- a/spec/algebra/unit/relations/join_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) - end - - describe '#attributes' do - it 'combines the attributes of the two relations' do - join = InnerJoin.new(@relation1, @relation2, @predicate) - join.attributes.should == (@relation1.attributes | @relation2.attributes).bind(join) - end - end - end -end diff --git a/spec/algebra/unit/relations/order_spec.rb b/spec/algebra/unit/relations/order_spec.rb deleted file mode 100644 index 9fcdffe340981..0000000000000 --- a/spec/algebra/unit/relations/order_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'spec_helper' - -module Arel - describe Order do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe "#==" do - it "returns true when the Orders are for the same attribute and direction" do - Ascending.new(@attribute).should == Ascending.new(@attribute) - end - - it "returns false when the Orders are for a diferent direction" do - Ascending.new(@attribute).should_not == Descending.new(@attribute) - end - end - end -end - diff --git a/spec/algebra/unit/relations/project_spec.rb b/spec/algebra/unit/relations/project_spec.rb deleted file mode 100644 index 294bffafe96af..0000000000000 --- a/spec/algebra/unit/relations/project_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'spec_helper' - -module Arel - describe Project do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#attributes' do - before do - @projection = Project.new(@relation, [@attribute]) - end - - it "manufactures attributes associated with the projection relation" do - @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } - end - end - - describe '#externalizable?' do - describe 'when the projections are attributes' do - it 'returns false' do - Project.new(@relation, [@attribute]).should_not be_externalizable - end - end - - describe 'when the projections include an aggregation' do - it "obtains" do - Project.new(@relation, [@attribute.sum]).should be_externalizable - end - end - end - end -end diff --git a/spec/algebra/unit/relations/relation_spec.rb b/spec/algebra/unit/relations/relation_spec.rb deleted file mode 100644 index a1ffd901d7f19..0000000000000 --- a/spec/algebra/unit/relations/relation_spec.rb +++ /dev/null @@ -1,236 +0,0 @@ -require 'spec_helper' - -module Arel - describe Relation do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - end - - describe '[]' do - describe 'when given an', Attribute do - it "return the attribute congruent to the provided attribute" do - @relation[@attribute1].should == @attribute1 - end - end - - describe 'when given a', Symbol, String do - it "returns the attribute with the same name" do - check @relation[:id].should == @attribute1 - check @relation['id'].should == @attribute1 - end - end - end - - describe 'Relation::Operable' do - describe 'joins' do - before do - @predicate = @relation[:id].eq(@relation[:id]) - end - - describe '#join' do - describe 'when given a relation' do - it "manufactures an inner join operation between those two relations" do - join = @relation.join(@relation).on(@predicate) - join.relation1.should == @relation - join.relation2.should == @relation - join.predicates.should == [@predicate] - join.should be_kind_of(InnerJoin) - end - end - - describe "when given a string" do - it "manufactures a join operation with the string passed through" do - arbitrary_string = "ASDF" - - join = @relation.join(arbitrary_string) - join.relation1.should == @relation - join.relation2.should == arbitrary_string - join.predicates.should == [] - join.should be_kind_of StringJoin - end - end - - describe "when given something blank" do - it "returns self" do - @relation.join.should == @relation - end - end - end - - describe '#outer_join' do - it "manufactures a left outer join operation between those two relations" do - join = @relation.outer_join(@relation).on(@predicate) - join.relation1.should == @relation - join.relation2.should == @relation - join.predicates.should == [@predicate] - join.should be_kind_of OuterJoin - end - end - end - - describe '#project' do - it "manufactures a projection relation" do - project = @relation.project(@attribute1, @attribute2) - project.relation.should == @relation - project.projections.should == [@attribute1, @attribute2] - project.should be_kind_of Project - end - - describe "when given blank attributes" do - it "returns self" do - @relation.project.should == @relation - end - end - end - - describe '#alias' do - it "manufactures an alias relation" do - @relation.alias.relation.should == Alias.new(@relation).relation - end - end - - describe '#where' do - before do - @predicate = Predicates::Equality.new(@attribute1, @attribute2) - end - - it "manufactures a where relation" do - where = @relation.where(@predicate) - where.relation.should == @relation - where.predicates.should == [@predicate] - where.should be_kind_of Where - end - - it "accepts arbitrary strings" do - where = @relation.where("arbitrary") - where.relation.should == @relation - - where.predicates.length.should == 1 - where.predicates.first.value.should == "arbitrary" - - where.should be_kind_of Where - end - - describe 'when given a blank predicate' do - it 'returns self' do - @relation.where.should == @relation - end - end - end - - describe '#order' do - it "manufactures an order relation" do - order = @relation.order(@attribute1, @attribute2) - order.relation.should == @relation - order.orderings.should == [@attribute1, @attribute2] - order.should be_kind_of Order - end - - describe 'when given a blank ordering' do - it 'returns self' do - @relation.order.should == @relation - end - end - end - - describe '#take' do - it "manufactures a take relation" do - take = @relation.take(5) - take.relation.should == @relation - take.taken.should == 5 - end - - describe 'when given a blank number of items' do - it 'raises error' do - lambda { @relation.take }.should raise_exception - end - end - end - - describe '#skip' do - it "manufactures a skip relation" do - skip = @relation.skip(4) - skip.relation.should == @relation - skip.skipped.should == 4 - skip.should be_kind_of Skip - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.skip.should == @relation - end - end - end - - describe '#group' do - it 'manufactures a group relation' do - group = @relation.group(@attribute1, @attribute2) - group.relation.should == @relation - group.groupings.should == [@attribute1, @attribute2] - group.should be_kind_of Group - sql = group.to_sql - sql.should =~ /GROUP BY/ - end - - describe 'when given blank groupings' do - it 'returns self' do - @relation.group.should == @relation - end - end - end - - describe 'relation is writable' do - describe '#delete' do - it 'manufactures a deletion relation' do - Session.start do |s| - s.should_receive(:delete) do |delete| - delete.relation.should == @relation - delete.should be_kind_of Deletion - end - @relation.delete - end - end - end - - describe '#insert' do - it 'manufactures an insertion relation' do - Session.start do |s| - record = { @relation[:name] => Value.new('carl', @relation) } - s.should_receive(:create) do |insert| - insert.relation.should == @relation - insert.record.should == record - insert.should be_kind_of Insert - insert - end - @relation.insert(record) - end - end - end - - describe '#update' do - it 'manufactures an update relation' do - Session.start do |s| - assignments = { @relation[:name] => Value.new('bob', @relation) } - s.should_receive(:update) do |update| - update.relation.should == @relation - update.assignments.should == assignments - update.should be_kind_of Update - update - end - @relation.update(assignments) - end - end - end - end - end - - describe 'is enumerable' do - it "implements enumerable" do - @relation.map { |value| value }.should == - @relation.session.read(@relation).map { |value| value } - end - end - end -end diff --git a/spec/algebra/unit/relations/skip_spec.rb b/spec/algebra/unit/relations/skip_spec.rb deleted file mode 100644 index e7dea6c1cf45b..0000000000000 --- a/spec/algebra/unit/relations/skip_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'spec_helper' - -module Arel - describe Skip do - before do - @relation = Table.new(:users) - @skipped = 4 - end - end -end diff --git a/spec/algebra/unit/relations/take_spec.rb b/spec/algebra/unit/relations/take_spec.rb deleted file mode 100644 index 3ad8d269f15f5..0000000000000 --- a/spec/algebra/unit/relations/take_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require 'spec_helper' - -module Arel - describe Take do - before do - @relation = Table.new(:users) - @taken = 4 - end - end -end diff --git a/spec/algebra/unit/relations/update_spec.rb b/spec/algebra/unit/relations/update_spec.rb deleted file mode 100644 index 9ed20a446b904..0000000000000 --- a/spec/algebra/unit/relations/update_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'spec_helper' - -module Arel - describe Update do - before do - @relation = Table.new(:users) - end - end -end diff --git a/spec/algebra/unit/relations/where_spec.rb b/spec/algebra/unit/relations/where_spec.rb deleted file mode 100644 index 48a8dc50383fe..0000000000000 --- a/spec/algebra/unit/relations/where_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' - -module Arel - describe Where do - before do - @relation = Table.new(:users) - @predicate = @relation[:id].eq(1) - end - - describe '#initialize' do - it "manufactures nested where relations if multiple predicates are provided" do - pending "This is not true anymore" - another_predicate = @relation[:name].lt(2) - Where.new(@relation, @predicate, another_predicate). \ - should == Where.new(Where.new(@relation, another_predicate), @predicate) - end - end - end -end diff --git a/spec/algebra/unit/session/session_spec.rb b/spec/algebra/unit/session/session_spec.rb deleted file mode 100644 index 0aaa031794c29..0000000000000 --- a/spec/algebra/unit/session/session_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'spec_helper' - -module Arel - describe Session do - before do - @relation = Table.new(:users) - @session = Session.new - end - - describe '::start' do - describe '::instance' do - it "it is a singleton within the started session" do - Session.start do |session| - Session.instance.should == session - end - end - - it "is a singleton across nested sessions" do - Session.start do |s1| - outside = Session.instance - Session.start do |s2| - Session.instance.should == outside - end - end - end - - it "manufactures new sessions outside of the started session" do - Session.new.should_not == Session.new - end - end - end - - describe 'session crud' do - before do - @insert = Insert.new(@relation, @relation[:name] => 'nick') - @update = Update.new(@relation, @relation[:name] => 'nick') - @delete = Deletion.new(@relation) - @read = @relation - end - - describe '#create' do - it "executes an insertion on the connection" do - @insert.should_receive(:call) - @session.create(@insert) - end - end - - describe '#read' do - it "executes an selection on the connection" do - @read.should_receive(:call) - @session.read(@read) - end - - it "is memoized" do - @read.should_receive(:call).once - @session.read(@read) - @session.read(@read) - end - end - - describe '#update' do - it "executes an update on the connection" do - @update.should_receive(:call) - @session.update(@update) - end - end - - describe '#delete' do - it "executes a delete on the connection" do - @delete.should_receive(:call) - @session.delete(@delete) - end - end - end - - describe 'Transactions' do - describe '#begin' do - end - - describe '#end' do - end - end - end -end diff --git a/spec/arel/attributes/attribute_spec.rb b/spec/attributes/attribute_spec.rb similarity index 100% rename from spec/arel/attributes/attribute_spec.rb rename to spec/attributes/attribute_spec.rb diff --git a/spec/attributes/boolean_spec.rb b/spec/attributes/boolean_spec.rb deleted file mode 100644 index 12b243e828e80..0000000000000 --- a/spec/attributes/boolean_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'spec_helper' - -module Arel - describe "Attributes::Boolean" do - - before :all do - @relation = Model.build do |r| - r.engine Testing::Engine.new - r.attribute :awesome, Attributes::Boolean - end - end - - def type_cast(val) - @relation[:awesome].type_cast(val) - end - - describe "#type_cast" do - it "returns same value if passed a boolean" do - val = true - type_cast(val).should eql(val) - end - - it "returns boolean representation (false) of nil" do - type_cast(nil).should eql(false) - end - - it "returns boolean representation of 'true', 'false'" do - type_cast('true').should eql(true) - type_cast('false').should eql(false) - end - - it "returns boolean representation of :true, :false" do - type_cast(:true).should eql(true) - type_cast(:false).should eql(false) - end - - it "returns boolean representation of 0, 1" do - type_cast(1).should == true - type_cast(0).should == false - end - - it "calls #to_s on arbitrary objects" do - obj = Object.new - obj.extend Module.new { def to_s ; 'true' ; end } - type_cast(obj).should == true - end - - [ Object.new, 'string', '00.0', 5 ].each do |value| - it "raises exception when attempting type_cast of non-boolean value #{value.inspect}" do - lambda do - type_cast(value) - end.should raise_error(TypecastError, /could not typecast/) - end - end - end - end -end diff --git a/spec/attributes/float_spec.rb b/spec/attributes/float_spec.rb deleted file mode 100644 index 3a9a8debbcdfc..0000000000000 --- a/spec/attributes/float_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -require 'spec_helper' -require 'bigdecimal' - -module Arel - describe "Attributes::Float" do - - before :all do - @relation = Model.build do |r| - r.engine Testing::Engine.new - r.attribute :percentage, Attributes::Float - end - end - - def type_cast(val) - @relation[:percentage].type_cast(val) - end - - describe "#type_cast" do - it "returns same value if an float" do - type_cast(24.01).should eql(24.01) - end - - it "returns nil if passed nil" do - type_cast(nil).should be_nil - end - - it "returns nil if passed empty string" do - type_cast('').should be_nil - end - - it "returns float representation of a zero string float" do - type_cast('0').should eql(0.0) - end - - it "returns float representation of a positive string integer" do - type_cast('24').should eql(24.0) - end - - it "returns float representation of a positive string integer with spaces" do - type_cast(' 24').should eql(24.0) - type_cast('24 ').should eql(24.0) - end - - it "returns float representation of a negative string float" do - type_cast('-24.23').should eql(-24.23) - end - - it "returns float representation of a negative string integer with spaces" do - type_cast('-24 ').should eql(-24.0) - type_cast(' -24').should eql(-24.0) - end - - it "returns integer representation of a zero string float" do - type_cast('0.0').should eql(0.0) - end - - it "returns integer representation of a positive string float" do - type_cast('24.35').should eql(24.35) - end - - it "returns integer representation of a positive string float with spaces" do - type_cast(' 24.35').should eql(24.35) - type_cast('24.35 ').should eql(24.35) - end - - it "returns integer representation of a negative string float" do - type_cast('-24.35').should eql(-24.35) - end - - it "returns integer representation of a negative string float with spaces" do - type_cast(' -24.35 ').should eql(-24.35) - end - - it "returns integer representation of a zero string float, with no leading digits" do - type_cast('.0').should eql(0.0) - end - - it "returns integer representation of a zero string float, with no leading digits with spaces" do - type_cast(' .0').should eql(0.0) - end - - it "returns integer representation of a positive string float, with no leading digits" do - type_cast('.41').should eql(0.41) - end - - it "returns integer representation of a zero float" do - type_cast(0.0).should eql(0.0) - end - - it "returns integer representation of a positive float" do - type_cast(24.35).should eql(24.35) - end - - it "returns integer representation of a negative float" do - type_cast(-24.35).should eql(-24.35) - end - - it "returns integer representation of a zero decimal" do - type_cast(BigDecimal('0.0')).should eql(0.0) - end - - it "returns integer representation of a positive decimal" do - type_cast(BigDecimal('24.35')).should eql(24.35) - end - - it "returns integer representation of a negative decimal" do - type_cast(BigDecimal('-24.35')).should eql(-24.35) - end - - [ Object.new, true, '00.0', '0.', 'string' ].each do |value| - it "raises exception when attempting type_cast of non-numeric value #{value.inspect}" do - lambda do - type_cast(value) - end.should raise_error(TypecastError, /could not typecast/) - end - end - end - end -end diff --git a/spec/attributes/header_spec.rb b/spec/attributes/header_spec.rb deleted file mode 100644 index 51cba93df31bb..0000000000000 --- a/spec/attributes/header_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'spec_helper' - -module Arel - describe "Header" do - before :all do - @relation = Model.build do |r| - r.attribute :id, Attributes::Integer - r.attribute :name, Attributes::String - r.attribute :age, Attributes::Integer - end - - @other = Model.build do |r| - r.attribute :foo, Attributes::String - end - - @subset = Model.build do |r| - r.attribute :id, Attributes::Integer - end - end - - describe "attribute lookup" do - it "finds attributes by name" do - @relation.attributes[:name].should == Attributes::String.new(@relation, :name) - end - - it "returns nil if no attribute is found" do - @relation.attributes[:does_not_exist].should be_nil - @relation[:does_not_exist].should be_nil - end - end - - describe "#union" do - it "keeps all attributes from disjoint headers" do - (@relation.attributes.union @other.attributes).to_ary.should have(4).items - end - - it "keeps all attributes from both relations even if they seem like subsets" do - (@relation.attributes.union @subset.attributes).to_ary.should have(4).items - end - end - end -end diff --git a/spec/attributes/integer_spec.rb b/spec/attributes/integer_spec.rb deleted file mode 100644 index 59b7afb2b4c26..0000000000000 --- a/spec/attributes/integer_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -require 'spec_helper' -require 'bigdecimal' - -module Arel - describe "Attributes::Integer" do - - before :all do - @relation = Model.build do |r| - r.engine Testing::Engine.new - r.attribute :age, Attributes::Integer - end - end - - def type_cast(val) - @relation[:age].type_cast(val) - end - - describe "#type_cast" do - it "returns same value if an integer" do - type_cast(24).should eql(24) - end - - it "returns nil if passed nil" do - type_cast(nil).should be_nil - end - - it "returns nil if passed empty string" do - type_cast('').should be_nil - end - - it "returns integer representation of a zero string integer" do - type_cast('0').should eql(0) - end - - it "returns integer representation of a positive string integer" do - type_cast('24').should eql(24) - end - - it "returns integer representation of a positive string integer with spaces" do - type_cast(' 24').should eql(24) - type_cast('24 ').should eql(24) - end - - it "returns integer representation of a negative string integer" do - type_cast('-24').should eql(-24) - end - - it "returns integer representation of a negative string integer with spaces" do - type_cast('-24 ').should eql(-24) - type_cast(' -24').should eql(-24) - end - - it "returns integer representation of a zero string float" do - type_cast('0.0').should eql(0) - end - - it "returns integer representation of a positive string float" do - type_cast('24.35').should eql(24) - end - - it "returns integer representation of a positive string float with spaces" do - type_cast(' 24.35').should eql(24) - type_cast('24.35 ').should eql(24) - end - - it "returns integer representation of a negative string float" do - type_cast('-24.35').should eql(-24) - end - - it "returns integer representation of a negative string float with spaces" do - type_cast(' -24.35 ').should eql(-24) - end - - it "returns integer representation of a zero string float, with no leading digits" do - type_cast('.0').should eql(0) - end - - it "returns integer representation of a zero string float, with no leading digits with spaces" do - type_cast(' .0').should eql(0) - end - - it "returns integer representation of a positive string float, with no leading digits" do - type_cast('.41').should eql(0) - end - - it "returns integer representation of a zero float" do - type_cast(0.0).should eql(0) - end - - it "returns integer representation of a positive float" do - type_cast(24.35).should eql(24) - end - - it "returns integer representation of a negative float" do - type_cast(-24.35).should eql(-24) - end - - it "returns integer representation of a zero decimal" do - type_cast(BigDecimal('0.0')).should eql(0) - end - - it "returns integer representation of a positive decimal" do - type_cast(BigDecimal('24.35')).should eql(24) - end - - it "returns integer representation of a negative decimal" do - type_cast(BigDecimal('-24.35')).should eql(-24) - end - - [ Object.new, true, '00.0', '0.', 'string' ].each do |value| - it "raises exception when attempting type_cast of non-numeric value #{value.inspect}" do - lambda do - type_cast(value) - end.should raise_error(TypecastError, /could not typecast/) - end - end - end - end -end diff --git a/spec/attributes/string_spec.rb b/spec/attributes/string_spec.rb deleted file mode 100644 index 487d82249dd92..0000000000000 --- a/spec/attributes/string_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'spec_helper' -require 'bigdecimal' - -module Arel - describe "Attributes::String" do - - before :all do - @relation = Model.build do |r| - r.engine Testing::Engine.new - r.attribute :name, Attributes::String - end - end - - def type_cast(val) - @relation[:name].type_cast(val) - end - - describe "#type_cast" do - it "returns same value if passed a String" do - val = "hell" - type_cast(val).should eql(val) - end - - it "returns nil if passed nil" do - type_cast(nil).should be_nil - end - - it "returns String representation of Symbol" do - type_cast(:hello).should == "hello" - end - - it "returns string representation of Integer" do - type_cast(1).should == '1' - end - - it "calls #to_s on arbitrary objects" do - obj = Object.new - obj.extend Module.new { def to_s ; 'hello' ; end } - type_cast(obj).should == 'hello' - end - end - end -end diff --git a/spec/attributes/time_spec.rb b/spec/attributes/time_spec.rb deleted file mode 100644 index 15384e2073682..0000000000000 --- a/spec/attributes/time_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'spec_helper' -require 'bigdecimal' - -module Arel - describe "Attributes::Time" do - - before :all do - @relation = Model.build do |r| - r.engine Testing::Engine.new - r.attribute :created_at, Attributes::Time - end - end - - def type_cast(val) - @relation[:created_at].type_cast(val) - end - - describe "#type_cast" do - it "works" do - pending - end - end - end -end diff --git a/spec/arel/attributes_spec.rb b/spec/attributes_spec.rb similarity index 100% rename from spec/arel/attributes_spec.rb rename to spec/attributes_spec.rb diff --git a/spec/arel/crud_spec.rb b/spec/crud_spec.rb similarity index 100% rename from spec/arel/crud_spec.rb rename to spec/crud_spec.rb diff --git a/spec/arel/delete_manager_spec.rb b/spec/delete_manager_spec.rb similarity index 100% rename from spec/arel/delete_manager_spec.rb rename to spec/delete_manager_spec.rb diff --git a/spec/engines/memory/integration/joins/cross_engine_spec.rb b/spec/engines/memory/integration/joins/cross_engine_spec.rb deleted file mode 100644 index 4646eeba2f6f7..0000000000000 --- a/spec/engines/memory/integration/joins/cross_engine_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @users = Array.new([ - [1, 'bryan' ], - [2, 'emilio' ], - [3, 'nick'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - @photos = Table.new(:photos) - @photos.delete - @photos.insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) - @photos.insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) - # Oracle adapter returns database integers as Ruby integers and not strings - # So does the FFI sqlite library - db_int_return = @photos.project(@photos[:camera_id]).first.tuple.first - @adapter_returns_integer = db_int_return.is_a?(String) ? false : true - end - - describe 'when the in memory relation is on the left' do - it 'joins across engines' do - @users \ - .join(@photos) \ - .on(@users[:id].eq(@photos[:user_id])) \ - .project(@users[:name], @photos[:camera_id]) \ - .tap do |relation| - rows = relation.call - rows.length.should == 2 - [ - ['bryan', @adapter_returns_integer ? 6 : '6'], - ['emilio', @adapter_returns_integer ? 42 : '42'] - ].zip(rows).each do |tuple, row| - row.relation.should == relation - row.tuple.should == tuple - end - end - end - end - - describe 'when the in memory relation is on the right' do - it 'joins across engines' do - @photos \ - .join(@users) \ - .on(@users[:id].eq(@photos[:user_id])) \ - .project(@users[:name], @photos[:camera_id]) \ - .tap do |relation| - rows = relation.call - rows.length.should == 2 - [ - ['bryan', @adapter_returns_integer ? 6 : '6'], - ['emilio', @adapter_returns_integer ? 42 : '42'] - ].zip(rows).each do |tuple, row| - row.relation.should == relation - row.tuple.should == tuple - end - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/array_spec.rb b/spec/engines/memory/unit/relations/array_spec.rb deleted file mode 100644 index 65bfb4025fa81..0000000000000 --- a/spec/engines/memory/unit/relations/array_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' - -module Arel - describe Array do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#attributes' do - it 'manufactures attributes corresponding to the names given on construction' do - @relation.attributes.should == [ - Attribute.new(@relation, :id), - Attribute.new(@relation, :name) - ] - end - end - - describe '#call' do - it "manufactures an array of hashes of attributes to values" do - rows = @relation.call - rows.length.should == 3 - @relation.array.zip(rows).each do |tuple, row| - row.relation.should == @relation - row.tuple.should == tuple - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/insert_spec.rb b/spec/engines/memory/unit/relations/insert_spec.rb deleted file mode 100644 index 987e708e0b029..0000000000000 --- a/spec/engines/memory/unit/relations/insert_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -module Arel - describe Insert do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#call' do - it "manufactures an array of hashes of attributes to values" do - @relation \ - .insert(@relation[:id] => 4, @relation[:name] => 'guinea fowl') \ - do |relation| - relation.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - Row.new(relation, [3, 'goose']), - Row.new(relation, [4, 'guinea fowl']) - ] - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/join_spec.rb b/spec/engines/memory/unit/relations/join_spec.rb deleted file mode 100644 index 93379985cbc67..0000000000000 --- a/spec/engines/memory/unit/relations/join_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @relation1 = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - @relation2 = @relation1.alias - end - - describe InnerJoin do - describe '#call' do - it 'combines the two tables where the predicate obtains' do - @relation1 \ - .join(@relation2) \ - .on(@relation1[:id].eq(@relation2[:id])) \ - .tap do |relation| - rows = relation.call - rows.length.should == 3 - @relation1.array.zip(rows).each do |tuple, row| - row.relation.should == relation - row.tuple.should == (tuple * 2) - end - end - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/order_spec.rb b/spec/engines/memory/unit/relations/order_spec.rb deleted file mode 100644 index 86c59ffc465a1..0000000000000 --- a/spec/engines/memory/unit/relations/order_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -module Arel - describe Order do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#call' do - it 'sorts the relation with the provided ordering' do - @relation \ - .order(@relation[:id].desc) \ - .tap do |relation| - rows = relation.call - rows.length.should == 3 - @relation.array.reverse.zip(rows) do |tuple, row| - row.relation.should == relation - row.tuple.should == tuple - end - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/project_spec.rb b/spec/engines/memory/unit/relations/project_spec.rb deleted file mode 100644 index cf20573fd2447..0000000000000 --- a/spec/engines/memory/unit/relations/project_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spec_helper' - -module Arel - describe Project do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#call' do - it 'retains only the attributes that are provided' do - @relation \ - .project(@relation[:id]) \ - .tap do |relation| - rows = relation.call - @relation.array.zip(rows) do |tuple, row| - row.relation.should == relation - row.tuple.should == [tuple.first] - end - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/skip_spec.rb b/spec/engines/memory/unit/relations/skip_spec.rb deleted file mode 100644 index abb87d2e3849b..0000000000000 --- a/spec/engines/memory/unit/relations/skip_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'spec_helper' - -module Arel - describe Skip do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#call' do - it 'removes the first n rows' do - @relation \ - .skip(1) \ - .tap do |relation| - rows = relation.call - rows.length.should == 2 - one, two = *rows - - one.relation.should == relation - one.tuple.should == [2, 'duck'] - - two.relation.should == relation - two.tuple.should == [3, 'goose'] - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/take_spec.rb b/spec/engines/memory/unit/relations/take_spec.rb deleted file mode 100644 index b7e49ddca6195..0000000000000 --- a/spec/engines/memory/unit/relations/take_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -module Arel - describe Take do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#call' do - it 'removes the rows after the first n' do - @relation \ - .take(2) \ - .tap do |relation| - rows = relation.call - rows.length.should == 2 - rows.each_with_index do |row, i| - row.relation.should == relation - row.tuple.should == [i + 1, 'duck'] - end - end - end - end - end -end diff --git a/spec/engines/memory/unit/relations/where_spec.rb b/spec/engines/memory/unit/relations/where_spec.rb deleted file mode 100644 index c75fe10f1b74c..0000000000000 --- a/spec/engines/memory/unit/relations/where_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'spec_helper' - -module Arel - describe Where do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [[:id, Attributes::Integer], [:name, Attributes::String]]) - end - - describe '#call' do - it 'filters the relation with the provided predicate' do - @relation \ - .where(@relation[:id].lt(3)) \ - .tap do |relation| - rows = relation.call - rows.length.should == 2 - rows.each_with_index do |row, i| - row.relation.should == relation - row.tuple.should == [i + 1, 'duck'] - end - end - end - - describe 'when filtering a where relation' do - it 'further filters the already-filtered relation with the provided predicate' do - @relation \ - .where(@relation[:id].gt(1)) \ - .where(@relation[:id].lt(3)) \ - .tap do |relation| - rows = relation.call - rows.length.should == 1 - row = rows.first - row.relation.should == relation - row.tuple.should == [2, 'duck'] - end - end - end - end - end -end diff --git a/spec/engines/sql/integration/joins/with_adjacency_spec.rb b/spec/engines/sql/integration/joins/with_adjacency_spec.rb deleted file mode 100644 index 1a0e28838d45c..0000000000000 --- a/spec/engines/sql/integration/joins/with_adjacency_spec.rb +++ /dev/null @@ -1,258 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @relation1 = Table(:users) - @relation2 = @relation1.alias - @predicate = @relation1[:id].eq(@relation2[:id]) - end - - describe 'when joining a relation to itself' do - describe '#to_sql' do - it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do - sql = @relation1.join(@relation2).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` `users_2` - ON `users`.`id` = `users_2`.`id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME" - FROM "USERS" - INNER JOIN "USERS" "USERS_2" - ON "USERS"."ID" = "USERS_2"."ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" - FROM "users" - INNER JOIN "users" "users_2" - ON "users"."id" = "users_2"."id" - }) - end - end - - describe 'when joining with a where on the same relation' do - it 'manufactures sql aliasing the tables properly' do - sql = @relation1 \ - .join(@relation2.where(@relation2[:id].eq(1))) \ - .on(@predicate) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` `users_2` - ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME" - FROM "USERS" - INNER JOIN "USERS" "USERS_2" - ON "USERS"."ID" = "USERS_2"."ID" AND "USERS_2"."ID" = 1 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" - FROM "users" - INNER JOIN "users" "users_2" - ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1 - }) - end - end - - describe 'when the where occurs before the alias' do - it 'manufactures sql aliasing the predicates properly' do - relation2 = @relation1.where(@relation1[:id].eq(1)).alias - - sql = @relation1 \ - .join(relation2) \ - .on(relation2[:id].eq(@relation1[:id])) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` `users_2` - ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME" - FROM "USERS" - INNER JOIN "USERS" "USERS_2" - ON "USERS_2"."ID" = "USERS"."ID" AND "USERS_2"."ID" = 1 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" - FROM "users" - INNER JOIN "users" "users_2" - ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1 - }) - end - end - end - end - - describe 'when joining the relation to itself multiple times' do - before do - @relation3 = @relation1.alias - end - - describe 'when joining left-associatively' do - it 'manufactures sql aliasing the tables properly' do - sql = @relation1 \ - .join(@relation2 \ - .join(@relation3) \ - .on(@relation2[:id].eq(@relation3[:id]))) \ - .on(@relation1[:id].eq(@relation2[:id])) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` `users_3` - ON `users_2`.`id` = `users_3`.`id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME", "USERS_3"."ID", "USERS_3"."NAME" - FROM "USERS" - INNER JOIN "USERS" "USERS_2" - ON "USERS"."ID" = "USERS_2"."ID" - INNER JOIN "USERS" "USERS_3" - ON "USERS_2"."ID" = "USERS_3"."ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" - FROM "users" - INNER JOIN "users" "users_2" - ON "users"."id" = "users_2"."id" - INNER JOIN "users" "users_3" - ON "users_2"."id" = "users_3"."id" - }) - end - end - end - - describe 'when joining right-associatively' do - it 'manufactures sql aliasing the tables properly' do - sql = @relation1 \ - .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ - .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` `users_3` - ON `users_2`.`id` = `users_3`.`id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "USERS_2"."ID", "USERS_2"."NAME", "USERS_3"."ID", "USERS_3"."NAME" - FROM "USERS" - INNER JOIN "USERS" "USERS_2" - ON "USERS"."ID" = "USERS_2"."ID" - INNER JOIN "USERS" "USERS_3" - ON "USERS_2"."ID" = "USERS_3"."ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" - FROM "users" - INNER JOIN "users" "users_2" - ON "users"."id" = "users_2"."id" - INNER JOIN "users" "users_3" - ON "users_2"."id" = "users_3"."id" - }) - end - end - end - end - end - - describe '[]' do - describe 'when given an attribute belonging to both sub-relations' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - @relation1 \ - .join(@relation2) \ - .on(@predicate) \ - .should disambiguate_attributes(@relation1[:id], @relation2[:id]) - end - - describe 'when both relations are compound and only one is an alias' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - compound1 = @relation1.where(@predicate) - compound2 = compound1.alias - compound1 \ - .join(compound2) \ - .on(@predicate) \ - .should disambiguate_attributes(compound1[:id], compound2[:id]) - end - end - - describe 'when the left relation is extremely compound' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - @relation1 \ - .where(@predicate) \ - .where(@predicate) \ - .join(@relation2) \ - .on(@predicate) \ - .should disambiguate_attributes(@relation1[:id], @relation2[:id]) - end - end - - describe 'when the right relation is extremely compound' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - @relation1 \ - .join( \ - @relation2 \ - .where(@predicate) \ - .where(@predicate) \ - .where(@predicate)) \ - .on(@predicate) \ - .should disambiguate_attributes(@relation1[:id], @relation2[:id]) - end - end - end - end - end - end -end diff --git a/spec/engines/sql/integration/joins/with_aggregations_spec.rb b/spec/engines/sql/integration/joins/with_aggregations_spec.rb deleted file mode 100644 index 62e1b8baea34f..0000000000000 --- a/spec/engines/sql/integration/joins/with_aggregations_spec.rb +++ /dev/null @@ -1,221 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @relation1 = Table(:users) - @relation2 = Table(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) - end - - describe 'when joining aggregated relations' do - before do - @aggregation = @relation2 \ - .group(@relation2[:user_id]) \ - .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ - end - - describe '#to_sql' do - # CLEANUP - it '' do - sql = @relation1.join(@relation2.take(3)).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` - FROM `users` - INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS_EXTERNAL"."ID", "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CAMERA_ID" - FROM "USERS" - INNER JOIN (SELECT "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" FROM "PHOTOS" WHERE ROWNUM <= 3) "PHOTOS_EXTERNAL" - ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" - FROM "users" - INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) "photos_external" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - - describe 'with the aggregation on the right' do - it 'manufactures sql joining the left table to a derived table' do - sql = @relation1.join(@aggregation).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT" - FROM "USERS" - INNER JOIN (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" - ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" - FROM "users" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - - describe 'with the aggregation on the left' do - it 'manufactures sql joining the right table to a derived table' do - sql = @aggregation.join(@relation1).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT", "USERS"."ID", "USERS"."NAME" - FROM (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" - INNER JOIN "USERS" - ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external" - INNER JOIN "users" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - - describe 'with the aggregation on both sides' do - it 'it properly aliases the aggregations' do - aggregation2 = @aggregation.alias - sql = @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) `photos_external_2` - ON `photos_external_2`.`user_id` = `photos_external`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT", "PHOTOS_EXTERNAL_2"."USER_ID", "PHOTOS_EXTERNAL_2"."CNT" - FROM (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" - INNER JOIN (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL_2" - ON "PHOTOS_EXTERNAL_2"."USER_ID" = "PHOTOS_EXTERNAL"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") "photos_external_2" - ON "photos_external_2"."user_id" = "photos_external"."user_id" - }) - end - end - end - - describe 'when the aggration has a where' do - describe 'with the aggregation on the left' do - it "manufactures sql keeping wheres on the aggregation within the derived table" do - sql = @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT" - FROM "USERS" - INNER JOIN (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" WHERE "PHOTOS"."USER_ID" = 1 GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" - ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" - FROM "users" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") "photos_external" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - - describe 'with the aggregation on the right' do - it "manufactures sql keeping wheres on the aggregation within the derived table" do - sql = @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "PHOTOS_EXTERNAL"."USER_ID", "PHOTOS_EXTERNAL"."CNT", "USERS"."ID", "USERS"."NAME" - FROM (SELECT "PHOTOS"."USER_ID", COUNT("PHOTOS"."ID") AS "CNT" FROM "PHOTOS" WHERE "PHOTOS"."USER_ID" = 1 GROUP BY "PHOTOS"."USER_ID") "PHOTOS_EXTERNAL" - INNER JOIN "USERS" - ON "USERS"."ID" = "PHOTOS_EXTERNAL"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") "photos_external" - INNER JOIN "users" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - end - end - end - end -end diff --git a/spec/engines/sql/integration/joins/with_compounds_spec.rb b/spec/engines/sql/integration/joins/with_compounds_spec.rb deleted file mode 100644 index 65fe49d128e2c..0000000000000 --- a/spec/engines/sql/integration/joins/with_compounds_spec.rb +++ /dev/null @@ -1,137 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @relation1 = Table(:users) - @relation2 = Table(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) - end - - describe '#to_sql' do - describe 'when the join contains a where' do - describe 'and the where is given a string' do - it 'does not escape the string' do - sql = @relation1 \ - .join(@relation2.where("asdf")) \ - .on(@predicate) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` AND asdf - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" - FROM "USERS" - INNER JOIN "PHOTOS" - ON "USERS"."ID" = "PHOTOS"."USER_ID" AND asdf - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" - ON "users"."id" = "photos"."user_id" AND asdf - }) - end - end - end - end - - describe 'when a compound contains a join' do - describe 'and the compound is a where' do - it 'manufactures sql disambiguating the tables' do - sql = @relation1 \ - .where(@relation1[:id].eq(1)) \ - .join(@relation2) \ - .on(@predicate) \ - .where(@relation1[:id].eq(1)) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - WHERE `users`.`id` = 1 - AND `users`.`id` = 1 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" - FROM "USERS" - INNER JOIN "PHOTOS" - ON "USERS"."ID" = "PHOTOS"."USER_ID" - WHERE "USERS"."ID" = 1 - AND "USERS"."ID" = 1 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" - ON "users"."id" = "photos"."user_id" - WHERE "users"."id" = 1 - AND "users"."id" = 1 - }) - end - end - end - - describe 'and the compound is a group' do - it 'manufactures sql disambiguating the tables' do - sql = @relation1 \ - .join(@relation2) \ - .on(@predicate) \ - .group(@relation1[:id]) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - GROUP BY `users`.`id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" - FROM "USERS" - INNER JOIN "PHOTOS" - ON "USERS"."ID" = "PHOTOS"."USER_ID" - GROUP BY "USERS"."ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" - ON "users"."id" = "photos"."user_id" - GROUP BY "users"."id" - }) - end - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/engine_spec.rb b/spec/engines/sql/unit/engine_spec.rb deleted file mode 100644 index 9d3c41ccc0664..0000000000000 --- a/spec/engines/sql/unit/engine_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' - -module Arel - FakeAR = Struct.new(:connection) - class FakeConnection < Struct.new :called - def initialize c = []; super; end - - def method_missing name, *args, &block - called << [name, args, block] - end - end - - describe Sql::Engine do - before do - @users = Table.new(:users) - @users.delete - end - - describe "method missing" do - it "should ask for a connection" do - conn = FakeConnection.new - ar = FakeAR.new conn - engine = Arel::Sql::Engine.new ar - - ar.connection = nil - lambda { engine.foo }.should raise_error - end - end - - describe "CRUD" do - describe "#create" do - it "inserts into the relation" do - @users.insert @users[:name] => "Bryan" - @users.first[@users[:name]].should == "Bryan" - end - end - - describe "#read" do - it "reads from the relation" do - @users.insert @users[:name] => "Bryan" - - @users.each do |row| - row[@users[:name]].should == "Bryan" - end - end - end - - describe "#update" do - it "updates the relation" do - @users.insert @users[:name] => "Nick" - @users.update @users[:name] => "Bryan" - @users.first[@users[:name]].should == "Bryan" - end - end - - describe "#delete" do - it "deletes from the relation" do - @users.insert @users[:name] => "Bryan" - @users.delete - @users.first.should == nil - end - end - end - end -end diff --git a/spec/engines/sql/unit/predicates/binary_spec.rb b/spec/engines/sql/unit/predicates/binary_spec.rb deleted file mode 100644 index 72c8e448881f6..0000000000000 --- a/spec/engines/sql/unit/predicates/binary_spec.rb +++ /dev/null @@ -1,140 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Binary do - class ConcreteBinary < Binary - def predicate_sql - "<=>" - end - end - - before do - @relation = Arel::Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - end - - describe "with compound predicates" do - before do - @operand1 = ConcreteBinary.new(@attribute1, 1) - @operand2 = ConcreteBinary.new(@attribute2, "name") - end - - describe Or do - describe "#to_sql" do - it "manufactures sql with an OR operation" do - sql = Or.new(@operand1, @operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) - end - - adapter_is :postgresql do - sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> E'name')}) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) - end - - adapter_is :oracle do - sql.should be_like(%Q{("USERS"."ID" <=> 1 OR "USERS"."NAME" <=> 'name')}) - end - end - end - end - - describe And do - describe "#to_sql" do - it "manufactures sql with an AND operation" do - sql = And.new(@operand1, @operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) - end - - adapter_is :postgresql do - sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> E'name')}) - end - - adapter_is :oracle do - sql.should be_like(%Q{("USERS"."ID" <=> 1 AND "USERS"."NAME" <=> 'name')}) - end - end - end - end - end - - describe '#to_sql' do - describe 'when relating two attributes' do - it 'manufactures sql with a binary operation' do - sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" <=> "USERS"."NAME"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" <=> "users"."name"}) - end - end - end - - describe 'when relating an attribute and a value' do - before do - @value = "1-asdf" - end - - describe 'when relating to an integer attribute' do - it 'formats values as integers' do - sql = ConcreteBinary.new(@attribute1, @value).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` <=> 1}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" <=> 1}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" <=> 1}) - end - end - end - - describe 'when relating to a string attribute' do - it 'formats values as strings' do - sql = ConcreteBinary.new(@attribute2, @value).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) - end - - adapter_is :postgresql do - sql.should be_like(%Q{"users"."name" <=> E'1-asdf'}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."NAME" <=> '1-asdf'}) - end - end - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/predicates/equality_spec.rb b/spec/engines/sql/unit/predicates/equality_spec.rb deleted file mode 100644 index bfd61185f28b5..0000000000000 --- a/spec/engines/sql/unit/predicates/equality_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Equality do - before do - @relation1 = Arel::Table.new(:users) - @relation2 = Arel::Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:user_id] - end - - describe '#to_sql' do - describe 'when relating to a non-nil value' do - it "manufactures an equality predicate" do - sql = Equality.new(@attribute1, @attribute2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" = "PHOTOS"."USER_ID"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) - end - end - end - - describe 'when relation to a nil value' do - before do - @nil = nil - end - - it "manufactures an is null predicate" do - sql = Equality.new(@attribute1, @nil).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NULL}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IS NULL}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IS NULL}) - end - end - end - - describe "when relating to a nil Value" do - it "manufactures an IS NULL predicate" do - value = nil.bind(@relation1) - sql = Equality.new(@attribute1, value).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NULL}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IS NULL}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IS NULL}) - end - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/predicates/in_spec.rb b/spec/engines/sql/unit/predicates/in_spec.rb deleted file mode 100644 index 933e33fe998d2..0000000000000 --- a/spec/engines/sql/unit/predicates/in_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe In do - before do - @relation = Arel::Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe 'when relating to an array' do - describe 'when the array\'s elements are the same type as the attribute' do - before do - @array = [1, 2, 3] - end - - it 'manufactures sql with a comma separated list' do - sql = In.new(@attribute, @array).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IN (1, 2, 3)}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) - end - end - end - - describe 'when the array\'s elements are not same type as the attribute' do - before do - @array = ['1-asdf', 2, 3] - end - - it 'formats values in the array as the type of the attribute' do - sql = In.new(@attribute, @array).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IN (1, 2, 3)}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) - end - end - end - - describe 'when the array is empty' do - before do - @array = [] - end - - it 'manufactures sql with a comma separated list' do - sql = In.new(@attribute, @array).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (NULL)}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IN (NULL)}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IN (NULL)}) - end - end - end - - end - - describe 'when relating to a range' do - before do - @range = 1..2 - end - - it 'manufactures sql with a between' do - sql = In.new(@attribute, @range).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" BETWEEN 1 AND 2}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) - end - end - end - - describe 'when relating to a range with an excluded end' do - before do - @range = 1...3 - end - - it 'manufactures sql with a >= and <' do - sql = In.new(@attribute, @range).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` >= 1 AND `users`.`id` < 3)}) - end - - adapter_is :oracle do - sql.should be_like(%Q{("USERS"."ID" >= 1 AND "USERS"."ID" < 3)}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{("users"."id" >= 1 AND "users"."id" < 3)}) - end - end - end - - describe 'when relating to a time range' do - before do - @relation = Arel::Table.new(:developers) - @attribute = @relation[:created_at] - @range = Time.mktime(2010, 01, 01)..Time.mktime(2010, 02, 01) - end - - it 'manufactures sql with a between' do - sql = In.new(@attribute, @range).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`developers`.`created_at` BETWEEN '2010-01-01 00:00:00' AND '2010-02-01 00:00:00'}) - end - - adapter_is :sqlite3 do - sql.should match(/"developers"."created_at" BETWEEN '2010-01-01 00:00:00(?:\.\d+)' AND '2010-02-01 00:00:00(?:\.\d+)'/) - end - - adapter_is :postgresql do - sql.should be_like(%Q{"developers"."created_at" BETWEEN '2010-01-01 00:00:00.000000' AND '2010-02-01 00:00:00.000000'}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"DEVELOPERS"."CREATED_AT" BETWEEN TO_TIMESTAMP('2010-01-01 00:00:00:000000','YYYY-MM-DD HH24:MI:SS:FF6') AND TO_TIMESTAMP('2010-02-01 00:00:00:000000','YYYY-MM-DD HH24:MI:SS:FF6')}) - end - end - end - - describe 'when relating to a relation' do - it 'manufactures sql with a subselect' do - sql = In.new(@attribute, @relation).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - "USERS"."ID" IN (SELECT "USERS"."ID", "USERS"."NAME" FROM "USERS") - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") - }) - end - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/predicates/noteq_spec.rb b/spec/engines/sql/unit/predicates/noteq_spec.rb deleted file mode 100644 index ed24627323539..0000000000000 --- a/spec/engines/sql/unit/predicates/noteq_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Equality do - before do - @relation1 = Arel::Table.new(:users) - @relation2 = Arel::Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:user_id] - end - - describe '#to_sql' do - describe 'when relating to a non-nil value' do - it "manufactures a not predicate" do - sql = Inequality.new(@attribute1, @attribute2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` != `photos`.`user_id`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" != "PHOTOS"."USER_ID"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" != "photos"."user_id"}) - end - end - end - - describe 'when relation to a nil value' do - before do - @nil = nil - end - - it "manufactures an is null predicate" do - sql = Inequality.new(@attribute1, @nil).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NOT NULL}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IS NOT NULL}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IS NOT NULL}) - end - end - end - - describe "when relating to a nil Value" do - it "manufactures an IS NULL predicate" do - value = nil.bind(@relation1) - sql = Inequality.new(@attribute1, value).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NOT NULL}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID" IS NOT NULL}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id" IS NOT NULL}) - end - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/predicates/predicates_spec.rb b/spec/engines/sql/unit/predicates/predicates_spec.rb deleted file mode 100644 index e6130cf267dd6..0000000000000 --- a/spec/engines/sql/unit/predicates/predicates_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -require 'spec_helper' - -module Arel - module Predicates - describe Predicate do - before do - @relation = Arel::Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - @operand1 = Arel::Predicates::Equality.new(@attribute1, 1) - @operand2 = Arel::Predicates::Equality.new(@attribute2, "name") - end - - describe "when being combined with another predicate with AND logic" do - describe "#to_sql" do - it "manufactures sql with an AND operation" do - sql = @operand1.and(@operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - (`users`.`id` = 1 AND `users`.`name` = 'name') - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - ("users"."id" = 1 AND "users"."name" = 'name') - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - ("users"."id" = 1 AND "users"."name" = E'name') - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - ("USERS"."ID" = 1 AND "USERS"."NAME" = 'name') - }) - end - end - end - end - - describe "when being combined with another predicate with OR logic" do - describe "#to_sql" do - it "manufactures sql with an OR operation" do - sql = @operand1.or(@operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - (`users`.`id` = 1 OR `users`.`name` = 'name') - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - ("users"."id" = 1 OR "users"."name" = 'name') - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - ("users"."id" = 1 OR "users"."name" = E'name') - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - ("USERS"."ID" = 1 OR "USERS"."NAME" = 'name') - }) - end - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/primitives/attribute_spec.rb b/spec/engines/sql/unit/primitives/attribute_spec.rb deleted file mode 100644 index 9f864dd3a1f62..0000000000000 --- a/spec/engines/sql/unit/primitives/attribute_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'spec_helper' - -module Arel - describe Attribute do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#column' do - it "returns the corresponding column in the relation" do - @attribute.column.should == @relation.column_for(@attribute) - end - end - - describe '#to_sql' do - describe 'for a simple attribute' do - it "manufactures sql with an alias" do - sql = @attribute.to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{"USERS"."ID"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{"users"."id"}) - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/primitives/expression_spec.rb b/spec/engines/sql/unit/primitives/expression_spec.rb deleted file mode 100644 index 3b6a7314a287d..0000000000000 --- a/spec/engines/sql/unit/primitives/expression_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -module Arel - describe Expression do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - it "manufactures sql with the expression and alias" do - sql = Count.new(@attribute, :alias).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{COUNT("USERS"."ID") AS "ALIAS"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{COUNT("users"."id") AS "alias"}) - end - end - end - end -end diff --git a/spec/engines/sql/unit/primitives/literal_spec.rb b/spec/engines/sql/unit/primitives/literal_spec.rb deleted file mode 100644 index 3bf60100f12cb..0000000000000 --- a/spec/engines/sql/unit/primitives/literal_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'spec_helper' - -module Arel - describe SqlLiteral do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "manufactures sql with a literal SQL fragment" do - sql = @relation.project(Count.new(SqlLiteral.new("*"))).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM `users`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "USERS"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "users"}) - end - end - - it "manufactures expressions on literal SQL fragment" do - sql = @relation.project(SqlLiteral.new("2 * credit_limit").sum).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM `users`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM "USERS"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{SELECT SUM(2 * credit_limit) AS sum_id FROM "users"}) - end - end - end - end -end diff --git a/spec/engines/sql/unit/primitives/value_spec.rb b/spec/engines/sql/unit/primitives/value_spec.rb deleted file mode 100644 index 807090e31a193..0000000000000 --- a/spec/engines/sql/unit/primitives/value_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'spec_helper' - -module Arel - describe Value do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "appropriately quotes the value" do - Value.new(1, @relation).to_sql.should be_like('1') - - adapter_is_not :postgresql do - Value.new('asdf', @relation).to_sql.should be_like("'asdf'") - end - - adapter_is :postgresql do - Value.new('asdf', @relation).to_sql.should be_like("E'asdf'") - end - end - end - - describe '#format' do - it "returns the sql of the provided object" do - Value.new(1, @relation).format(@relation[:id]).should == @relation[:id].to_sql - end - end - end -end diff --git a/spec/engines/sql/unit/relations/alias_spec.rb b/spec/engines/sql/unit/relations/alias_spec.rb deleted file mode 100644 index a6fd7ab036f9c..0000000000000 --- a/spec/engines/sql/unit/relations/alias_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'spec_helper' - -module Arel - describe Alias do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - describe 'when there is no ambiguity' do - it 'does not alias table names anywhere a table name can appear' do - sql = @relation \ - .where(@relation[:id].eq(1)) \ - .order(@relation[:id]) \ - .project(@relation[:id]) \ - .group(@relation[:id]) \ - .alias \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id` - FROM `users` - WHERE `users`.`id` = 1 - GROUP BY `users`.`id` - ORDER BY `users`.`id` ASC - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID" - FROM "USERS" - WHERE "USERS"."ID" = 1 - GROUP BY "USERS"."ID" - ORDER BY "USERS"."ID" ASC - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id" - FROM "users" - WHERE "users"."id" = 1 - GROUP BY "users"."id" - ORDER BY "users"."id" ASC - }) - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/delete_spec.rb b/spec/engines/sql/unit/relations/delete_spec.rb deleted file mode 100644 index 302a13c688ef7..0000000000000 --- a/spec/engines/sql/unit/relations/delete_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'spec_helper' - -module Arel - describe Deletion do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql deleting a table relation' do - sql = Deletion.new(@relation).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{DELETE FROM `users`}) - end - - adapter_is :oracle do - sql.should be_like(%Q{DELETE FROM "USERS"}) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{DELETE FROM "users"}) - end - end - - it 'manufactures sql deleting a where relation' do - sql = Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - DELETE - FROM `users` - WHERE `users`.`id` = 1 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - DELETE - FROM "USERS" - WHERE "USERS"."ID" = 1 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - DELETE - FROM "users" - WHERE "users"."id" = 1 - }) - end - end - - it "manufactures sql deleting a ranged relation" do - sql = Deletion.new(@relation.take(1)).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - DELETE - FROM `users` - LIMIT 1 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - DELETE - FROM "USERS" - WHERE ROWNUM <= 1 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - DELETE - FROM "users" - LIMIT 1 - }) - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/from_spec.rb b/spec/engines/sql/unit/relations/from_spec.rb deleted file mode 100644 index 0be3ac0f9ac36..0000000000000 --- a/spec/engines/sql/unit/relations/from_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -require 'spec_helper' - -module Arel - describe Table do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "manufactures a simple select query" do - sql = @relation.from("workers").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM workers - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM workers - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM workers - }) - end - end - end - - describe '#to_sql' do - it "overrides and use last from clause given " do - sql = @relation.from("workers").from("users").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM users - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM users - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM users - }) - end - end - end - - end -end diff --git a/spec/engines/sql/unit/relations/group_spec.rb b/spec/engines/sql/unit/relations/group_spec.rb deleted file mode 100644 index c32091bf08f80..0000000000000 --- a/spec/engines/sql/unit/relations/group_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'spec_helper' - -module Arel - describe Group do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe 'when given a predicate' do - it "manufactures sql with where clause conditions" do - sql = Group.new(@relation, [@attribute]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY `users`.`id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - GROUP BY "USERS"."ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - GROUP BY "users"."id" - }) - end - end - end - - describe 'when given a string' do - it "passes the string through to the where clause" do - sql = Group.new(@relation, ['asdf']).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY asdf - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - GROUP BY asdf - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - GROUP BY asdf - }) - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/having_spec.rb b/spec/engines/sql/unit/relations/having_spec.rb deleted file mode 100644 index 931e8d0a06806..0000000000000 --- a/spec/engines/sql/unit/relations/having_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -require 'spec_helper' - -module Arel - describe Having do - before do - @relation = Table.new(:developers) - end - - describe '#to_sql' do - describe 'when given a predicate' do - it "manufactures sql with where clause conditions" do - sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department`, `developers`.`created_at` - FROM `developers` - GROUP BY `developers`.`department` - HAVING MIN(salary) > 1000 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "DEVELOPERS"."ID", "DEVELOPERS"."NAME", "DEVELOPERS"."SALARY", "DEVELOPERS"."DEPARTMENT", "DEVELOPERS"."CREATED_AT" - FROM "DEVELOPERS" - GROUP BY "DEVELOPERS"."DEPARTMENT" - HAVING MIN(salary) > 1000 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department", "developers"."created_at" - FROM "developers" - GROUP BY "developers"."department" - HAVING MIN(salary) > 1000 - }) - end - end - end - - describe 'when given two predicates' do - it "manufactures sql with where clause conditions joined by AND" do - sql = @relation.group(@relation[:department]).having("MIN(salary) > 1000", "MAX(salary) < 10000").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `developers`.`id`, `developers`.`name`, `developers`.`salary`, `developers`.`department`, `developers`.`created_at` - FROM `developers` - GROUP BY `developers`.`department` - HAVING MIN(salary) > 1000 AND MAX(salary) < 10000 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "DEVELOPERS"."ID", "DEVELOPERS"."NAME", "DEVELOPERS"."SALARY", "DEVELOPERS"."DEPARTMENT", "DEVELOPERS"."CREATED_AT" - FROM "DEVELOPERS" - GROUP BY "DEVELOPERS"."DEPARTMENT" - HAVING MIN(salary) > 1000 AND MAX(salary) < 10000 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "developers"."id", "developers"."name", "developers"."salary", "developers"."department", "developers"."created_at" - FROM "developers" - GROUP BY "developers"."department" - HAVING MIN(salary) > 1000 AND MAX(salary) < 10000 - }) - end - end - end - end - end -end - diff --git a/spec/engines/sql/unit/relations/insert_spec.rb b/spec/engines/sql/unit/relations/insert_spec.rb deleted file mode 100644 index 4b412093e4fc3..0000000000000 --- a/spec/engines/sql/unit/relations/insert_spec.rb +++ /dev/null @@ -1,143 +0,0 @@ -require 'spec_helper' - -module Arel - describe Insert do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql inserting data when given multiple rows' do - pending 'it should insert multiple rows' do - @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) - - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`name`) VALUES ('nick'), ('bryan') - ") - end - end - - it 'manufactures sql inserting data when given multiple values' do - @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") - - adapter_is :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO `users` - (`id`, `name`) VALUES (1, 'nick') - }) - end - - adapter_is :sqlite3 do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("id", "name") VALUES (1, 'nick') - }) - end - - adapter_is :postgresql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("id", "name") VALUES (1, E'nick') - RETURNING "id" - }) - end - - adapter_is :oracle do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "USERS" - ("ID", "NAME") VALUES (1, 'nick') - }) - end - end - - describe 'when given values whose types correspond to the types of the attributes' do - before do - @insertion = Insert.new(@relation, @relation[:name] => "nick") - end - - it 'manufactures sql inserting data' do - adapter_is :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO `users` - (`name`) VALUES ('nick') - }) - end - - adapter_is :sqlite3 do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("name") VALUES ('nick') - }) - end - - adapter_is :postgresql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("name") VALUES (E'nick') - RETURNING "id" - }) - end - - adapter_is :oracle do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "USERS" - ("NAME") VALUES ('nick') - }) - end - end - end - - describe 'when given values whose types differ from from the types of the attributes' do - before do - @insertion = Insert.new(@relation, @relation[:id] => '1-asdf') - end - - it 'manufactures sql inserting data' do - adapter_is :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO `users` - (`id`) VALUES (1) - }) - end - - adapter_is :sqlite3 do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("id") VALUES (1) - }) - end - - adapter_is :postgresql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("id") VALUES (1) - RETURNING "id" - }) - end - - adapter_is :oracle do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "USERS" - ("ID") VALUES (1) - }) - end - - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/join_spec.rb b/spec/engines/sql/unit/relations/join_spec.rb deleted file mode 100644 index cbbcb18244d0f..0000000000000 --- a/spec/engines/sql/unit/relations/join_spec.rb +++ /dev/null @@ -1,180 +0,0 @@ -require 'spec_helper' - -module Arel - describe Join do - before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @predicate1 = @relation1[:id].eq(@relation2[:user_id]) - - @relation3 = Table.new(:users, :as => :super_users) - @relation4 = Table.new(:photos, :as => :super_photos) - - @predicate2 = @relation3[:id].eq(@relation2[:user_id]) - @predicate3 = @relation3[:id].eq(@relation4[:user_id]) - end - - describe '#to_sql' do - - describe 'when joining with another relation' do - it 'manufactures sql joining the two tables on the predicate' do - sql = InnerJoin.new(@relation1, @relation2, @predicate1).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" - FROM "USERS" - INNER JOIN "PHOTOS" ON "USERS"."ID" = "PHOTOS"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" ON "users"."id" = "photos"."user_id" - }) - end - end - - describe 'when joining with another relation with an aliased table' do - it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do - sql = InnerJoin.new(@relation3, @relation2, @predicate2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `super_users`.`id`, `super_users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` `super_users` - INNER JOIN `photos` ON `super_users`.`id` = `photos`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "SUPER_USERS"."ID", "SUPER_USERS"."NAME", "PHOTOS"."ID", "PHOTOS"."USER_ID", "PHOTOS"."CAMERA_ID" - FROM "USERS" "SUPER_USERS" - INNER JOIN "PHOTOS" ON "SUPER_USERS"."ID" = "PHOTOS"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "super_users"."id", "super_users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" "super_users" - INNER JOIN "photos" ON "super_users"."id" = "photos"."user_id" - }) - end - end - end - - describe 'when joining with two relations with aliased tables' do - it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do - sql = InnerJoin.new(@relation3, @relation4, @predicate3).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `super_users`.`id`, `super_users`.`name`, `super_photos`.`id`, `super_photos`.`user_id`, `super_photos`.`camera_id` - FROM `users` `super_users` - INNER JOIN `photos` `super_photos` ON `super_users`.`id` = `super_photos`.`user_id` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "SUPER_USERS"."ID", "SUPER_USERS"."NAME", "SUPER_PHOTOS"."ID", "SUPER_PHOTOS"."USER_ID", "SUPER_PHOTOS"."CAMERA_ID" - FROM "USERS" "SUPER_USERS" - INNER JOIN "PHOTOS" "SUPER_PHOTOS" ON "SUPER_USERS"."ID" = "SUPER_PHOTOS"."USER_ID" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "super_users"."id", "super_users"."name", "super_photos"."id", "super_photos"."user_id", "super_photos"."camera_id" - FROM "users" "super_users" - INNER JOIN "photos" "super_photos" ON "super_users"."id" = "super_photos"."user_id" - }) - end - end - end - - end - - describe 'when joining with a string' do - it "passes the string through to the where clause" do - sql = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - INNER JOIN asdf ON fdsa - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - INNER JOIN asdf ON fdsa - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - INNER JOIN asdf ON fdsa - }) - end - end - - it "passes the string when there are multiple string joins" do - relation = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa") - relation = StringJoin.new(relation, "INNER JOIN lifo ON fifo") - sql = StringJoin.new(relation, "INNER JOIN hatful ON hallow").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - INNER JOIN asdf ON fdsa - INNER JOIN lifo ON fifo - INNER JOIN hatful ON hallow - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - INNER JOIN asdf ON fdsa - INNER JOIN lifo ON fifo - INNER JOIN hatful ON hallow - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - INNER JOIN asdf ON fdsa - INNER JOIN lifo ON fifo - INNER JOIN hatful ON hallow - }) - end - end - - end - - - end - end -end diff --git a/spec/engines/sql/unit/relations/lock_spec.rb b/spec/engines/sql/unit/relations/lock_spec.rb deleted file mode 100644 index 72a8a2e457ce6..0000000000000 --- a/spec/engines/sql/unit/relations/lock_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -require 'spec_helper' - -module Arel - describe Lock do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "manufactures a simple select query lock" do - sql = @relation.lock.to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` FOR UPDATE - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" FOR UPDATE - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" FOR UPDATE - }) - - sql_with_order_by = @relation.order(@relation[:id]).take(1).lock.to_sql - sql_with_order_by.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - WHERE "ID" IN (select * from - (SELECT "ID" FROM "USERS" ORDER BY "USERS"."ID" ASC) - where rownum <= 1) - FOR UPDATE - }) - - end - end - - it "manufactures a select query locking with a given lock" do - sql = @relation.lock("LOCK IN SHARE MODE").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` LOCK IN SHARE MODE - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" LOCK IN SHARE MODE - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" LOCK IN SHARE MODE - }) - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/order_spec.rb b/spec/engines/sql/unit/relations/order_spec.rb deleted file mode 100644 index 59637876bf564..0000000000000 --- a/spec/engines/sql/unit/relations/order_spec.rb +++ /dev/null @@ -1,161 +0,0 @@ -require 'spec_helper' - -module Arel - describe Order do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe "when given an attribute" do - it "manufactures sql with an order clause populated by the attribute" do - sql = Order.new(@relation, [@attribute]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` ASC - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - ORDER BY "USERS"."ID" ASC - }) - - distinct_attributes = ActiveRecord::Base.connection.distinct('"USERS"."NAME"', '"USERS"."ID"') - @relation.project(distinct_attributes).order(@relation[:id]).to_sql.should be_like(%Q{ - SELECT DISTINCT "USERS"."NAME", - FIRST_VALUE("USERS"."ID") OVER (PARTITION BY "USERS"."NAME" ORDER BY "USERS"."ID") AS alias_0__ - FROM "USERS" - ORDER BY alias_0__ - }) - - distinct_attributes = ActiveRecord::Base.connection.distinct('"USERS"."NAME"', '"USERS"."ID" DESC') - @relation.project(distinct_attributes).order('"USERS"."ID" DESC').to_sql.should be_like(%Q{ - SELECT DISTINCT "USERS"."NAME", - FIRST_VALUE("USERS"."ID") OVER (PARTITION BY "USERS"."NAME" ORDER BY "USERS"."ID" DESC) AS alias_0__ - FROM "USERS" - ORDER BY alias_0__ DESC - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY "users"."id" ASC - }) - end - end - end - - describe "when given multiple attributes" do - before do - @another_attribute = @relation[:name] - end - - it "manufactures sql with an order clause populated by comma-separated attributes" do - sql = Order.new(@relation, [@attribute, @another_attribute]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` ASC, `users`.`name` ASC - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - ORDER BY "USERS"."ID" ASC, "USERS"."NAME" ASC - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY "users"."id" ASC, "users"."name" ASC - }) - end - end - end - - describe "when given a string" do - before do - @string = "asdf" - end - - it "passes the string through to the order clause" do - sql = Order.new(@relation, [@string]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY asdf - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - ORDER BY asdf - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY asdf - }) - end - end - end - - describe "when ordering an ordered relation" do - before do - @ordered_relation = Order.new(@relation, [@attribute]) - @another_attribute = @relation[:name] - end - - it "manufactures sql with the order clause of the last ordering preceding the first ordering" do - sql = Order.new(@ordered_relation, [@another_attribute]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`name` ASC, `users`.`id` ASC - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - ORDER BY "USERS"."NAME" ASC, "USERS"."ID" ASC - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY "users"."name" ASC, "users"."id" ASC - }) - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/project_spec.rb b/spec/engines/sql/unit/relations/project_spec.rb deleted file mode 100644 index b5d2d33d4b959..0000000000000 --- a/spec/engines/sql/unit/relations/project_spec.rb +++ /dev/null @@ -1,143 +0,0 @@ -require 'spec_helper' - -module Arel - describe Project do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe 'when given an attribute' do - it "manufactures sql with a limited select clause" do - sql = Project.new(@relation, [@attribute]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id` - FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID" - FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id" - FROM "users" - }) - end - end - end - - describe 'when given a relation' do - before do - @scalar_relation = Project.new(@relation, [@relation[:name]]) - end - - it "manufactures sql with scalar selects" do - sql = Project.new(@relation, [@scalar_relation]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT (SELECT "USERS"."NAME" FROM "USERS") AS "USERS" FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users" - }) - end - end - end - - describe 'when given a string' do - it "passes the string through to the select clause" do - sql = Project.new(@relation, ['asdf']).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT asdf FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT asdf FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT asdf FROM "users" - }) - end - end - end - - describe 'when given an expression' do - it 'manufactures sql with expressions' do - sql = @relation.project(@attribute.count).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT COUNT(`users`.`id`) AS count_id - FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT COUNT("USERS"."ID") AS count_id - FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT COUNT("users"."id") AS count_id - FROM "users" - }) - end - end - - it 'manufactures sql with distinct expressions' do - sql = @relation.project(@attribute.count(true)).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT COUNT(DISTINCT `users`.`id`) AS count_id - FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT COUNT(DISTINCT "USERS"."ID") AS count_id - FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT COUNT(DISTINCT "users"."id") AS count_id - FROM "users" - }) - end - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/skip_spec.rb b/spec/engines/sql/unit/relations/skip_spec.rb deleted file mode 100644 index 41b80d12d8117..0000000000000 --- a/spec/engines/sql/unit/relations/skip_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'spec_helper' - -module Arel - describe Skip do - before do - @relation = Table.new(:users) - @skipped = 4 - end - - describe '#to_sql' do - it "manufactures sql with limit and offset" do - sql = Skip.new(@relation, @skipped).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - OFFSET 4 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - select * from (select raw_sql_.*, rownum raw_rnum_ from - (SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS") raw_sql_) - where raw_rnum_ > 4 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - OFFSET 4 - }) - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/table_spec.rb b/spec/engines/sql/unit/relations/table_spec.rb deleted file mode 100644 index 1a0914006bbdf..0000000000000 --- a/spec/engines/sql/unit/relations/table_spec.rb +++ /dev/null @@ -1,122 +0,0 @@ -require 'spec_helper' - -module Arel - describe Table do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "manufactures a simple select query" do - sql = @relation.to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - }) - end - end - end - - describe '#as' do - it "manufactures a simple select query using aliases" do - sql = @relation.as(:super_users).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `super_users`.`id`, `super_users`.`name` - FROM `users` `super_users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "SUPER_USERS"."ID", "SUPER_USERS"."NAME" - FROM "USERS" "SUPER_USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "super_users"."id", "super_users"."name" - FROM "users" "super_users" - }) - end - end - - it "does not apply alias if it's same as the table name" do - sql = @relation.as(:users).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - }) - end - end - - end - - describe '#column_for' do - it "returns the column corresponding to the attribute" do - @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } - end - end - - describe '#attributes' do - it 'manufactures attributes corresponding to columns in the table' do - @relation.attributes.should == [ - Attribute.new(@relation, :id), - Attribute.new(@relation, :name) - ] - end - - describe '#reset' do - it "reloads columns from the database" do - lambda { @relation.engine.stub!(:columns => []) }.should_not change { @relation.attributes } - lambda { @relation.reset }.should change { @relation.attributes } - end - end - end - - describe '#engine' do - it "defaults to global engine" do - Table.engine = engine = Sql::Engine.new - Table.new(:users).engine.should == engine - end - - it "can be specified" do - Table.new(:users, engine = Sql::Engine.new).engine.should == engine - end - end - end -end diff --git a/spec/engines/sql/unit/relations/take_spec.rb b/spec/engines/sql/unit/relations/take_spec.rb deleted file mode 100644 index ad46190f7e01b..0000000000000 --- a/spec/engines/sql/unit/relations/take_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'spec_helper' - -module Arel - describe Take do - before do - @relation = Table.new(:users) - @taken = 4 - end - - describe '#to_sql' do - it "manufactures sql with limit and offset" do - sql = Take.new(@relation, @taken).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - LIMIT 4 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - WHERE ROWNUM <= 4 - }) - - sql_with_order_by = Take.new(@relation.order(@relation[:id]), @taken).to_sql - sql_with_order_by.should be_like(%Q{ - select * from - (SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - ORDER BY "USERS"."ID" ASC) - where rownum <= 4 - }) - - sql_with_distinct = Take.new(@relation.project('DISTINCT "USERS"."ID"'), @taken).to_sql - sql_with_distinct.should be_like(%Q{ - select * from - (SELECT DISTINCT "USERS"."ID" - FROM "USERS") - where rownum <= 4 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - LIMIT 4 - }) - end - end - - it "manufactures count sql with limit" do - sql = Take.new(@relation.project(@relation[:id].count), @taken).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT COUNT(*) AS count_id - FROM (SELECT 1 FROM `users` LIMIT 4) AS subquery - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT COUNT(*) AS count_id - FROM (SELECT 1 FROM "users" LIMIT 4) AS subquery - }) - end - end - end - end -end diff --git a/spec/engines/sql/unit/relations/update_spec.rb b/spec/engines/sql/unit/relations/update_spec.rb deleted file mode 100644 index cc2ad9913bbbc..0000000000000 --- a/spec/engines/sql/unit/relations/update_spec.rb +++ /dev/null @@ -1,203 +0,0 @@ -require 'spec_helper' - -class User - def self.primary_key - "id" - end -end - -module Arel - describe Update do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "manufactures sql updating attributes when given multiple attributes" do - sql = Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - UPDATE `users` - SET `id` = 1, `name` = 'nick' - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - UPDATE "users" - SET "id" = 1, "name" = 'nick' - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - UPDATE "users" - SET "id" = 1, "name" = E'nick' - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - UPDATE "USERS" - SET "ID" = 1, "NAME" = 'nick' - }) - end - end - - it "manufactures sql updating attributes when given a ranged relation" do - sql = Update.new(@relation.take(1), @relation[:name] => "nick").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - UPDATE `users` - SET `name` = 'nick' - LIMIT 1 - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - UPDATE "users" SET - "name" = 'nick' - WHERE "id" IN (SELECT "id" FROM "users" LIMIT 1) - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - UPDATE "users" SET - "name" = E'nick' - WHERE "id" IN (SELECT "id" FROM "users" LIMIT 1) - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - UPDATE "USERS" SET - "NAME" = 'nick' - WHERE "ID" IN (SELECT "ID" FROM "USERS" WHERE ROWNUM <= 1) - }) - - sql_with_order_by = Update.new(@relation.order(@relation[:id]).take(1), @relation[:name] => "nick").to_sql - sql_with_order_by.should be_like(%Q{ - UPDATE "USERS" SET - "NAME" = 'nick' - WHERE "ID" IN (select * from - (SELECT "ID" FROM "USERS" ORDER BY "USERS"."ID" ASC) - where rownum <= 1) - }) - end - end - - describe 'when given values whose types correspond to the types of the attributes' do - before do - @update = Update.new(@relation, @relation[:name] => "nick") - end - - it 'manufactures sql updating attributes' do - adapter_is :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE `users` - SET `name` = 'nick' - }) - end - - adapter_is :sqlite3 do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "name" = 'nick' - }) - end - - adapter_is :postgresql do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "name" = E'nick' - }) - end - - adapter_is :oracle do - @update.to_sql.should be_like(%Q{ - UPDATE "USERS" - SET "NAME" = 'nick' - }) - end - end - end - - describe 'when given values whose types differ from from the types of the attributes' do - before do - @update = Update.new(@relation, @relation[:id] => '1-asdf') - end - - it 'manufactures sql updating attributes' do - adapter_is :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE `users` - SET `id` = 1 - }) - end - - adapter_is :oracle do - @update.to_sql.should be_like(%Q{ - UPDATE "USERS" - SET "ID" = 1 - }) - end - - adapter_is_not :mysql, :oracle do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "id" = 1 - }) - end - end - end - - describe 'when the relation is a where' do - before do - @update = Update.new( - @relation.where(@relation[:id].eq(1)), - @relation[:name] => "nick" - ) - end - - it 'manufactures sql updating a where relation' do - adapter_is :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE `users` - SET `name` = 'nick' - WHERE `users`.`id` = 1 - }) - end - - adapter_is :sqlite3 do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "name" = 'nick' - WHERE "users"."id" = 1 - }) - end - - adapter_is :postgresql do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "name" = E'nick' - WHERE "users"."id" = 1 - }) - end - - adapter_is :oracle do - @update.to_sql.should be_like(%Q{ - UPDATE "USERS" - SET "NAME" = 'nick' - WHERE "USERS"."ID" = 1 - }) - end - end - end - end - - end -end diff --git a/spec/engines/sql/unit/relations/where_spec.rb b/spec/engines/sql/unit/relations/where_spec.rb deleted file mode 100644 index 69793d63a1a7e..0000000000000 --- a/spec/engines/sql/unit/relations/where_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -require 'spec_helper' - -module Arel - describe Where do - before do - @relation = Table.new(:users) - @predicate = @relation[:id].eq(1) - end - - describe '#to_sql' do - describe 'when given a predicate' do - it "manufactures sql with where clause conditions" do - sql = Where.new(@relation, [@predicate]).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE `users`.`id` = 1 - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - WHERE "USERS"."ID" = 1 - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - WHERE "users"."id" = 1 - }) - end - end - end - - describe 'when given a string' do - it "passes the string through to the where clause" do - sql = Where.new(@relation, 'asdf').to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE asdf - }) - end - - adapter_is :oracle do - sql.should be_like(%Q{ - SELECT "USERS"."ID", "USERS"."NAME" - FROM "USERS" - WHERE asdf - }) - end - - adapter_is_not :mysql, :oracle do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - WHERE asdf - }) - end - end - end - end - end -end diff --git a/spec/arel/insert_manager_spec.rb b/spec/insert_manager_spec.rb similarity index 100% rename from spec/arel/insert_manager_spec.rb rename to spec/insert_manager_spec.rb diff --git a/spec/arel/nodes/count_spec.rb b/spec/nodes/count_spec.rb similarity index 100% rename from spec/arel/nodes/count_spec.rb rename to spec/nodes/count_spec.rb diff --git a/spec/arel/nodes/delete_statement_spec.rb b/spec/nodes/delete_statement_spec.rb similarity index 100% rename from spec/arel/nodes/delete_statement_spec.rb rename to spec/nodes/delete_statement_spec.rb diff --git a/spec/arel/nodes/equality_spec.rb b/spec/nodes/equality_spec.rb similarity index 100% rename from spec/arel/nodes/equality_spec.rb rename to spec/nodes/equality_spec.rb diff --git a/spec/arel/nodes/insert_statement_spec.rb b/spec/nodes/insert_statement_spec.rb similarity index 100% rename from spec/arel/nodes/insert_statement_spec.rb rename to spec/nodes/insert_statement_spec.rb diff --git a/spec/arel/nodes/or_spec.rb b/spec/nodes/or_spec.rb similarity index 100% rename from spec/arel/nodes/or_spec.rb rename to spec/nodes/or_spec.rb diff --git a/spec/arel/nodes/select_core_spec.rb b/spec/nodes/select_core_spec.rb similarity index 100% rename from spec/arel/nodes/select_core_spec.rb rename to spec/nodes/select_core_spec.rb diff --git a/spec/arel/nodes/select_statement_spec.rb b/spec/nodes/select_statement_spec.rb similarity index 100% rename from spec/arel/nodes/select_statement_spec.rb rename to spec/nodes/select_statement_spec.rb diff --git a/spec/arel/nodes/sql_literal_spec.rb b/spec/nodes/sql_literal_spec.rb similarity index 100% rename from spec/arel/nodes/sql_literal_spec.rb rename to spec/nodes/sql_literal_spec.rb diff --git a/spec/arel/nodes/sum_spec.rb b/spec/nodes/sum_spec.rb similarity index 100% rename from spec/arel/nodes/sum_spec.rb rename to spec/nodes/sum_spec.rb diff --git a/spec/arel/nodes/update_statement_spec.rb b/spec/nodes/update_statement_spec.rb similarity index 100% rename from spec/arel/nodes/update_statement_spec.rb rename to spec/nodes/update_statement_spec.rb diff --git a/spec/relations/join_spec.rb b/spec/relations/join_spec.rb deleted file mode 100644 index b4a46fae9722a..0000000000000 --- a/spec/relations/join_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'spec_helper' - -describe "Arel" do - before :all do - @owner = Arel::Model.build do |r| - r.engine Arel::Testing::Engine.new - - r.attribute :id, Arel::Attributes::Integer - end - - @thing = Arel::Model.build do |r| - r.engine Arel::Testing::Engine.new - - r.attribute :id, Arel::Attributes::Integer - r.attribute :owner_id, Arel::Attributes::Integer - r.attribute :name, Arel::Attributes::String - r.attribute :age, Arel::Attributes::Integer - end - end - - describe "Join" do - before :all do - @relation = @thing.join(@owner).on(@thing[:owner_id].eq(@owner[:id])) - @expected = [] - - 3.times do |owner_id| - @owner.insert([owner_id]) - - 8.times do |i| - thing_id = owner_id * 8 + i - age = 2 * thing_id - name = "Name #{thing_id % 6}" - - @thing.insert([thing_id, owner_id, name, age]) - @expected << Arel::Row.new(@relation, [thing_id, owner_id, name, age, owner_id]) - end - end - end - - it_should_behave_like 'A Relation' - end -end diff --git a/spec/relations/relation_spec.rb b/spec/relations/relation_spec.rb deleted file mode 100644 index cfc1c1410b88f..0000000000000 --- a/spec/relations/relation_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require 'spec_helper' - -describe "Arel" do - before :all do - @engine = Arel::Testing::Engine.new - @relation = Arel::Model.build do |r| - r.engine @engine - - r.attribute :id, Arel::Attributes::Integer - r.attribute :name, Arel::Attributes::String - r.attribute :age, Arel::Attributes::Integer - end - end - - describe "Relation" do - before :all do - @expected = (1..20).map { |i| @relation.insert([i, "Name #{i % 6}", 2 * i]) } - end - - it_should_behave_like 'A Relation' - end - - describe "Relation" do - describe "#insert" do - it "inserts the row into the engine" do - @relation.insert([1, 'Foo', 10]) - @engine.rows.should == [[1, 'Foo', 10]] - end - end - end -end diff --git a/spec/arel/select_manager_spec.rb b/spec/select_manager_spec.rb similarity index 100% rename from spec/arel/select_manager_spec.rb rename to spec/select_manager_spec.rb diff --git a/spec/shared/relation_spec.rb b/spec/shared/relation_spec.rb deleted file mode 100644 index a5a22edb7d717..0000000000000 --- a/spec/shared/relation_spec.rb +++ /dev/null @@ -1,255 +0,0 @@ -share_examples_for 'A Relation' do - - before :all do - # The two needed instance variables need to be set in a - # before :all callback. - # @relation is the relation being tested here. - # @expected is an array of the elements that are expected to be in - # the relation. - %w[ @relation @expected ].each do |ivar| - raise "#{ivar} needs to be defined" unless instance_variable_get(ivar) - end - - # There needs to be enough items to be able to run all the tests - raise "@expected needs to have at least 6 items" unless @expected.length >= 6 - end - - before :each do - @expected = @expected.dup - end - - describe "#each" do - it "iterates over the rows in any order" do - @relation.should have_rows(@expected) - end - end - - describe "#where" do - before :all do - @expected = @expected.sort_by { |r| r[@relation[:age]] } - @pivot = @expected[@expected.length / 2] - end - - it "finds rows with an equal to predicate" do - expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } - @relation.where(@relation[:age].eq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with an equal to complement predicate" do - expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } - @relation.where(@relation[:age].eq(@pivot[@relation[:age]]).complement).should have_rows(expected) - end - - it "finds rows with a not eq predicate" do - expected = @expected.select { |r| r[@relation[:age]] != @pivot[@relation[:age]] } - @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with an not eq complement predicate" do - expected = @expected.select { |r| r[@relation[:age]] == @pivot[@relation[:age]] } - @relation.where(@relation[:age].not_eq(@pivot[@relation[:age]]).complement).should have_rows(expected) - end - - it "finds rows with a less than predicate" do - expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } - @relation.where(@relation[:age].lt(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a less than complement predicate" do - expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } - @relation.where(@relation[:age].lt(@pivot[@relation[:age]]).complement).should have_rows(expected) - end - - it "finds rows with a less than or equal to predicate" do - expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } - @relation.where(@relation[:age].lteq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a less than or equal to complement predicate" do - expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } - @relation.where(@relation[:age].lteq(@pivot[@relation[:age]]).complement).should have_rows(expected) - end - - it "finds rows with a greater than predicate" do - expected = @expected.select { |r| r[@relation[:age]] > @pivot[@relation[:age]] } - @relation.where(@relation[:age].gt(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a greater than complement predicate" do - expected = @expected.select { |r| r[@relation[:age]] <= @pivot[@relation[:age]] } - @relation.where(@relation[:age].gt(@pivot[@relation[:age]]).complement).should have_rows(expected) - end - - it "finds rows with a greater than or equal to predicate" do - expected = @expected.select { |r| r[@relation[:age]] >= @pivot[@relation[:age]] } - @relation.where(@relation[:age].gteq(@pivot[@relation[:age]])).should have_rows(expected) - end - - it "finds rows with a greater than or equal to complement predicate" do - expected = @expected.select { |r| r[@relation[:age]] < @pivot[@relation[:age]] } - @relation.where(@relation[:age].gteq(@pivot[@relation[:age]]).complement).should have_rows(expected) - end - - it "finds rows with a matches predicate" do - expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } - @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) - end - - it "finds rows with a matches complement predicate" do - expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } - @relation.where(@relation[:name].matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected) - end - - it "finds rows with a not matches predicate" do - expected = @expected.select { |r| r[@relation[:name]] !~ /#{@pivot[@relation[:name]]}/ } - @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/)).should have_rows(expected) - end - - it "finds rows with a not matches complement predicate" do - expected = @expected.select { |r| r[@relation[:name]] =~ /#{@pivot[@relation[:name]]}/ } - @relation.where(@relation[:name].not_matches(/#{@pivot[@relation[:name]]}/).complement).should have_rows(expected) - end - - it "finds rows with an in predicate" do - expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} - @relation.where(@relation[:age].in(3..20)).should have_rows(expected) - end - - it "finds rows with an in complement predicate" do - expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} - @relation.where(@relation[:age].in(3..20).complement).should have_rows(expected) - end - - it "finds rows with a not in predicate" do - expected = @expected.select {|r| !(r[@relation[:age]] >=3 && r[@relation[:age]] <= 20)} - @relation.where(@relation[:age].not_in(3..20)).should have_rows(expected) - end - - it "finds rows with a not in complement predicate" do - expected = @expected.select {|r| r[@relation[:age]] >=3 && r[@relation[:age]] <= 20} - @relation.where(@relation[:age].not_in(3..20).complement).should have_rows(expected) - end - - it "finds rows with a polyadic predicate of class Any" do - expected = @expected.select {|r| [2,4,8,16].include?(r[@relation[:age]])} - @relation.where(@relation[:age].in_any([2,4], [8, 16])).should have_rows(expected) - end - - it "finds rows with a polyadic predicate of class Any complement" do - expected = @expected.select {|r| ![2,4,8,16].include?(r[@relation[:age]])} - @relation.where(@relation[:age].in_any([2,4], [8, 16]).complement).should have_rows(expected) - end - - it "finds rows with a polyadic predicate of class All" do - expected = @expected.select {|r| r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/} - @relation.where(@relation[:name].matches_all(/Name/, /1/)).should have_rows(expected) - end - - it "finds rows with a polyadic predicate of class All complement" do - expected = @expected.select {|r| !(r[@relation[:name]] =~ /Name/ && r[@relation[:name]] =~ /1/)} - @relation.where(@relation[:name].matches_all(/Name/, /1/).complement).should have_rows(expected) - end - end - - describe "#order" do - describe "by one attribute" do - before :all do - @expected.sort! { |a, b| a[@relation[:age]] <=> b[@relation[:age]]}.map! {|e| e[@relation[:id]]} - end - - it "can be specified as ascending order" do - actual = [] - @relation.order(@relation[:age].asc).each { |r| actual << r[@relation[:id]] } - actual.should == @expected - end - - it "can be specified as descending order" do - actual = [] - @relation.order(@relation[:age].desc).each { |r| actual << r[@relation[:id]] } - actual.should == @expected.reverse - end - end - - describe "by two attributes in two separate calls to #order" do - before :all do - @expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]} - end - - it "can be specified as ascending order" do - actual = [] - @relation.order(@relation[:age].asc).order(@relation[:name].asc).each { |r| actual << r[@relation[:id]] } - actual.should == @expected - end - - it "can be specified as descending order" do - actual = [] - @relation.order(@relation[:age].desc).order(@relation[:name].desc).each { |r| actual << r[@relation[:id]] } - actual.should == @expected.reverse - end - end - - describe "by two attributes in one call to #order" do - before :all do - @expected = @expected.sort_by { |e| [e[@relation[:name]], e[@relation[:age]]]}.map {|e| e[@relation[:id]]} - end - - it "can be specified as ascending order in one call to #order" do - actual = [] - @relation.order(@relation[:name].asc, @relation[:age].asc).each { |r| actual << r[@relation[:id]] } - actual.should == @expected - end - - it "can be specified as descending order in one call to #order" do - actual = [] - @relation.order(@relation[:name].desc, @relation[:age].desc).each { |r| actual << r[@relation[:id]] } - actual.should == @expected.reverse - end - end - end - - describe "#take" do - it "returns a relation" do - @relation.take(3).should be_a(Arel::Relation) - end - - it "returns X items from the collection" do - length = @expected.length - - @relation.take(3).each do |resource| - @expected.delete_if { |r| r.tuple == resource.tuple } - end - - @expected.length.should == length - 3 - end - - it "works with ordering" do - expected = @expected.sort_by { |r| [r[@relation[:age]], r[@relation[:id]]] }.map { |r| r[@relation[:id]] } - actual = @relation.order(@relation[:age].asc, @relation[:id].asc).take(3).map { |r| r[@relation[:id]] } - - actual.should == expected[0,3] - end - end - - describe "#skip" do - it "returns a relation" do - @relation.skip(3).should be_a(Arel::Relation) - end - - it "skips X items from the collection" do - length = @expected.length - - @relation.skip(3).each do |resource| - @expected.delete_if { |r| r.tuple == resource.tuple } - end - - @expected.length.should == 3 - end - - it "works with ordering" do - expected = @expected.sort_by { |r| [r[@relation[:age]], r[@relation[:id]]] }.map { |r| r[@relation[:id]] } - actual = @relation.order(@relation[:age].asc, @relation[:id].asc).skip(3).map { |r| r[@relation[:id]] } - - actual.should == expected[3..-1] - end - end -end diff --git a/spec/sql/christener_spec.rb b/spec/sql/christener_spec.rb deleted file mode 100644 index 895ec2a9b65e0..0000000000000 --- a/spec/sql/christener_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'spec_helper' - -module Arel - module Sql - describe "Christener" do - it "returns the first name" do - christener = Christener.new - table = Table.new 'users' - table2 = Table.new 'pictures' - christener.name_for(table).should == 'users' - christener.name_for(table2).should == 'pictures' - christener.name_for(table).should == 'users' - end - - it "returns a unique name for an alias" do - christener = Christener.new - table = Table.new 'users' - table2 = Table.new 'users', :as => 'friends' - christener.name_for(table).should == 'users' - christener.name_for(table2).should == 'friends' - end - - it "returns a unique name for an alias with same name" do - christener = Christener.new - table = Table.new 'users' - table2 = Table.new 'friends', :as => 'users' - christener.name_for(table).should == 'users' - christener.name_for(table2).should == 'users_2' - end - - it "returns alias name" do - christener = Christener.new - table = Table.new 'users' - aliaz = Alias.new table - - christener.name_for(table).should == 'users' - christener.name_for(aliaz).should == 'users_2' - end - - it "returns alias first" do - christener = Christener.new - table = Table.new 'users' - aliaz = Alias.new table - - christener.name_for(aliaz).should == 'users' - christener.name_for(table).should == 'users_2' - end - - it "returns externalization name" do - christener = Christener.new - table = Table.new 'users' - ext = Externalization.new table - - christener.name_for(table).should == 'users' - christener.name_for(ext).should == 'users_external' - end - - it "returns aliases externalizations and tables" do - christener = Christener.new - table = Table.new 'users' - aliaz = Alias.new table - ext = Externalization.new table - - christener.name_for(table).should == 'users' - christener.name_for(aliaz).should == 'users_2' - christener.name_for(ext).should == 'users_external' - end - end - end -end diff --git a/spec/arel/table_spec.rb b/spec/table_spec.rb similarity index 100% rename from spec/arel/table_spec.rb rename to spec/table_spec.rb diff --git a/spec/arel/update_manager_spec.rb b/spec/update_manager_spec.rb similarity index 100% rename from spec/arel/update_manager_spec.rb rename to spec/update_manager_spec.rb diff --git a/spec/arel/visitors/join_sql_spec.rb b/spec/visitors/join_sql_spec.rb similarity index 100% rename from spec/arel/visitors/join_sql_spec.rb rename to spec/visitors/join_sql_spec.rb diff --git a/spec/arel/visitors/oracle_spec.rb b/spec/visitors/oracle_spec.rb similarity index 100% rename from spec/arel/visitors/oracle_spec.rb rename to spec/visitors/oracle_spec.rb diff --git a/spec/arel/visitors/to_sql_spec.rb b/spec/visitors/to_sql_spec.rb similarity index 100% rename from spec/arel/visitors/to_sql_spec.rb rename to spec/visitors/to_sql_spec.rb From c12b886031ac59dd379f24434c2c14cf41d4082b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 15:23:19 -0700 Subject: [PATCH 0757/1492] removing the v1 rake task --- Rakefile | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Rakefile b/Rakefile index a6f80222c85c8..40fb0afc07257 100644 --- a/Rakefile +++ b/Rakefile @@ -41,18 +41,6 @@ else desc "Run specs with the #{adapter} database adapter" task adapter => "set_env_for_#{adapter}" - - namespace :v1 do - Spec::Rake::SpecTask.new(adapter) do |t| - t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] - t.libs << "#{File.dirname(__FILE__)}/spec" - t.warning = true - t.spec_files = FileList['spec/arel/**/*_spec.rb'] - end - - desc "Run specs with the #{adapter} database adapter" - task adapter => "set_env_for_#{adapter}" - end end end From 6b37b39279d7907c3bb81fae2c1e8830f3037b3f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 15:23:52 -0700 Subject: [PATCH 0758/1492] turning on warnings --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 40fb0afc07257..41b1cac56e2e5 100644 --- a/Rakefile +++ b/Rakefile @@ -35,7 +35,7 @@ else Spec::Rake::SpecTask.new(adapter) do |t| t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] t.libs << "#{File.dirname(__FILE__)}/spec" - # t.warning = true + t.warning = true t.spec_files = FileList['spec/**/*_spec.rb'] end From 116054cca13118873b838d5325d49ffa128af286 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 15:26:39 -0700 Subject: [PATCH 0759/1492] use a real editor --- Rakefile | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Rakefile b/Rakefile index 41b1cac56e2e5..94906ab345143 100644 --- a/Rakefile +++ b/Rakefile @@ -51,11 +51,6 @@ else task :default => :spec end -desc 'Removes trailing whitespace' -task :whitespace do - sh %{find . -name '*.rb' -exec sed -i '' 's/ *$//g' {} \\;} -end - desc "Build pkg/#{gemspec.full_name}.gem" task :build => "gemspec:validate" do sh %{gem build arel.gemspec} From 6549b3c8ed13c1c5bf9d5772d3f02c0557e01e01 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 15:29:20 -0700 Subject: [PATCH 0760/1492] removing tasks that hoe will provide --- Rakefile | 54 ------------------------------------------------------ 1 file changed, 54 deletions(-) diff --git a/Rakefile b/Rakefile index 94906ab345143..00d43503a6721 100644 --- a/Rakefile +++ b/Rakefile @@ -1,31 +1,11 @@ require "rubygems" -def gemspec - @gemspec ||= begin - gemspec_file = File.expand_path('../arel.gemspec', __FILE__) - gemspec = eval(File.read(gemspec_file), binding, gemspec_file) - end -end - begin require "spec/rake/spectask" rescue LoadError desc "Run specs" task(:spec) { $stderr.puts '`gem install rspec` to run specs' } else - desc "Run specs using RCov (uses mysql database adapter)" - Spec::Rake::SpecTask.new(:coverage) do |t| - t.spec_files = - ["spec/connections/mysql_connection.rb"] + - FileList['spec/**/*_spec.rb'] - - t.rcov = true - t.rcov_opts << '--exclude' << "spec,gems" - t.rcov_opts << '--text-summary' - t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse' - t.rcov_opts << '--only-uncovered' - end - namespace :spec do %w[mysql sqlite3 postgresql oracle].each do |adapter| task "set_env_for_#{adapter}" do @@ -50,37 +30,3 @@ else desc "Default task is to run specs" task :default => :spec end - -desc "Build pkg/#{gemspec.full_name}.gem" -task :build => "gemspec:validate" do - sh %{gem build arel.gemspec} - FileUtils.mkdir_p "pkg" - FileUtils.mv gemspec.file_name, "pkg" -end - -desc "Install the latest built gem" -task :install => :build do - sh "gem install --local pkg/#{gemspec.file_name}" -end - -namespace :release do - task :tag do - release_tag = "v#{gemspec.version}" - sh "git tag -a #{release_tag} -m 'Tagging #{release_tag}'" - sh "git push origin #{release_tag}" - end - - task :gem => :build do - sh "gem push pkg/#{gemspec.file_name}" - end -end - -desc "Release the current branch to GitHub and Gemcutter" -task :release => %w(release:tag release:gem) - -namespace :gemspec do - desc 'Validate the gemspec' - task :validate do - gemspec.validate - end -end From 72a857a7822a308498d15064390ed2f8153f4db0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:23:25 -0700 Subject: [PATCH 0761/1492] specs run without an AR connection --- spec/support/fake_record.rb | 85 +++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 spec/support/fake_record.rb diff --git a/spec/support/fake_record.rb b/spec/support/fake_record.rb new file mode 100644 index 0000000000000..eb6aa2c472f8f --- /dev/null +++ b/spec/support/fake_record.rb @@ -0,0 +1,85 @@ +module FakeRecord + class Column < Struct.new(:name, :type) + end + + class Connection + attr_reader :tables + + def initialize + @tables = %w{ users photos developers } + @columns = { + 'users' => [ + Column.new('id', :integer), + Column.new('name', :string) + ] + } + @primary_keys = { + 'users' => 'id' + } + 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 quote thing, column = nil + 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 + + def initialize + @spec = Spec.new('sqlite3') + end + + def connection + Connection.new + end + + def with_connection + yield connection + end + end + + class Base + def self.connection_pool + ConnectionPool.new + end + + def self.connection + connection_pool.connection + end + end +end From c21fcdcf837f43ae61f2be7592d8aab001c51b25 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:26:24 -0700 Subject: [PATCH 0762/1492] deleting lots of unused files --- spec/spec_helper.rb | 21 ++----- spec/support/guards.rb | 28 ---------- spec/support/model.rb | 67 ----------------------- spec/support/schemas/mysql_schema.rb | 26 --------- spec/support/schemas/oracle_schema.rb | 20 ------- spec/support/schemas/postgresql_schema.rb | 26 --------- spec/support/schemas/sqlite3_schema.rb | 26 --------- 7 files changed, 4 insertions(+), 210 deletions(-) delete mode 100644 spec/support/guards.rb delete mode 100644 spec/support/model.rb delete mode 100644 spec/support/schemas/mysql_schema.rb delete mode 100644 spec/support/schemas/oracle_schema.rb delete mode 100644 spec/support/schemas/postgresql_schema.rb delete mode 100644 spec/support/schemas/sqlite3_schema.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4ea3071515017..0031f6903f88f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,27 +5,14 @@ require 'support/matchers/be_like' require 'support/check' -Dir[File.join(File.dirname(__FILE__),'support/shared/*')].each { |f| require f } - -if adapter = ENV['ADAPTER'] - require "support/connections/#{adapter}_connection.rb" -end +require 'support/fake_record' +require 'support/shared/tree_manager_shared' Spec::Runner.configure do |config| config.include Matchers config.include Check - if defined?(ActiveRecord::Base) - tmp = File.expand_path('../../tmp', __FILE__) - - FileUtils.mkdir_p(tmp) - ActiveRecord::Base.logger = Logger.new("#{tmp}/debug.log") - ActiveRecord::Base.establish_connection("unit") - - require "support/schemas/#{ENV['ADAPTER']}_schema.rb" - - config.before do - Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) - end + config.before do + Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base) end end diff --git a/spec/support/guards.rb b/spec/support/guards.rb deleted file mode 100644 index db6075f73ad43..0000000000000 --- a/spec/support/guards.rb +++ /dev/null @@ -1,28 +0,0 @@ -module AdapterGuards - def adapter_is(*names) - names = names.map(&:to_s) - names.each{|name| verify_adapter_name(name)} - yield if names.include? adapter_name - end - - def adapter_is_not(*names) - names = names.map(&:to_s) - names.each{|name| verify_adapter_name(name)} - yield unless names.include? adapter_name - end - - def adapter_name - name = ActiveRecord::Base.configurations["unit"][:adapter] - name = 'oracle' if name == 'oracle_enhanced' - verify_adapter_name(name) - name - end - - def verify_adapter_name(name) - raise "Invalid adapter name: #{name}" unless valid_adapters.include?(name.to_s) - end - - def valid_adapters - %w[mysql postgresql sqlite3 oracle] - end -end diff --git a/spec/support/model.rb b/spec/support/model.rb deleted file mode 100644 index 45fe254d6ff20..0000000000000 --- a/spec/support/model.rb +++ /dev/null @@ -1,67 +0,0 @@ -module Arel - module Testing - class Engine < Arel::Memory::Engine - attr_reader :rows - - def initialize - @rows = [] - end - - def supports(operation) - false - end - - def read(relation) - case relation - when Arel::Take, Arel::Order, Arel::Skip, Arel::Where - relation.eval - else - @rows.dup.map { |r| Row.new(relation, r) } - end - end - - def create(insert) - @rows << insert.record.tuple - insert - end - end - end - - class Model - include Relation - - attr_reader :engine - - def self.build - relation = new - yield relation - relation - end - - def initialize - @attributes = [] - end - - def engine(engine = nil) - @engine = engine if engine - @engine - end - - def attribute(name, type) - @attributes << type.new(self, name) - end - - def attributes - Header.new(@attributes) - end - - def format(attribute, value) - value - end - - def insert(row) - insert = super Arel::Row.new(self, row) - insert.record - end - end -end diff --git a/spec/support/schemas/mysql_schema.rb b/spec/support/schemas/mysql_schema.rb deleted file mode 100644 index a2e913d756fd1..0000000000000 --- a/spec/support/schemas/mysql_schema.rb +++ /dev/null @@ -1,26 +0,0 @@ -sql = <<-SQL - DROP TABLE IF EXISTS users; - CREATE TABLE users ( - id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL - ); - - DROP TABLE IF EXISTS photos; - CREATE TABLE photos ( - id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, - user_id INTEGER NOT NULL, - camera_id INTEGER NOT NULL - ); - DROP TABLE IF EXISTS developers; - CREATE TABLE developers ( - id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255) NOT NULL, - salary INTEGER NOT NULL, - department VARCHAR(255) NOT NULL, - created_at TIMESTAMP NOT NULL - ); -SQL - -sql.split(/;/).select(&:present?).each do |sql_statement| - ActiveRecord::Base.connection.execute sql_statement -end diff --git a/spec/support/schemas/oracle_schema.rb b/spec/support/schemas/oracle_schema.rb deleted file mode 100644 index c8207c8d98a60..0000000000000 --- a/spec/support/schemas/oracle_schema.rb +++ /dev/null @@ -1,20 +0,0 @@ -ActiveRecord::Schema.define do - suppress_messages do - create_table :users, :primary_key_trigger => true, :force => true do |t| - t.string :name, :limit => 255, :null => false - end - - create_table :photos, :primary_key_trigger => true, :force => true do |t| - t.integer :user_id - t.integer :camera_id - end - - create_table :developers, :primary_key_trigger => true, :force => true do |t| - t.string :name, :limit => 255, :null => false - t.integer :salary - t.string :department, :limit => 255, :null => false - t.timestamp :created_at, :null => false - end - - end -end diff --git a/spec/support/schemas/postgresql_schema.rb b/spec/support/schemas/postgresql_schema.rb deleted file mode 100644 index 23a48f5ad8ea4..0000000000000 --- a/spec/support/schemas/postgresql_schema.rb +++ /dev/null @@ -1,26 +0,0 @@ -sql = <<-SQL - DROP TABLE IF EXISTS users; - CREATE TABLE users ( - id SERIAL PRIMARY KEY NOT NULL, - name VARCHAR(255) NOT NULL - ); - - DROP TABLE IF EXISTS photos; - CREATE TABLE photos ( - id SERIAL PRIMARY KEY NOT NULL, - user_id INTEGER NOT NULL, - camera_id INTEGER NOT NULL - ); - DROP TABLE IF EXISTS developers; - CREATE TABLE developers ( - id SERIAL PRIMARY KEY NOT NULL, - name VARCHAR(255) NOT NULL, - salary INTEGER NOT NULL, - department VARCHAR(255) NOT NULL, - created_at TIMESTAMP NOT NULL - ); -SQL - -sql.split(/;/).select(&:present?).each do |sql_statement| - ActiveRecord::Base.connection.execute sql_statement -end diff --git a/spec/support/schemas/sqlite3_schema.rb b/spec/support/schemas/sqlite3_schema.rb deleted file mode 100644 index c1fed70859fe2..0000000000000 --- a/spec/support/schemas/sqlite3_schema.rb +++ /dev/null @@ -1,26 +0,0 @@ -sql = <<-SQL - DROP TABLE IF EXISTS users; - CREATE TABLE users ( - id INTEGER NOT NULL PRIMARY KEY, - name VARCHAR(255) NOT NULL - ); - - DROP TABLE IF EXISTS photos; - CREATE TABLE photos ( - id INTEGER NOT NULL PRIMARY KEY, - user_id INTEGER NOT NULL, - camera_id INTEGER NOT NULL - ); - DROP TABLE IF EXISTS developers; - CREATE TABLE developers ( - id INTEGER NOT NULL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - salary INTEGER NOT NULL, - department VARCHAR(255) NOT NULL, - created_at TIMESTAMP NOT NULL - ); -SQL - -sql.split(/;/).select(&:present?).each do |sql_statement| - ActiveRecord::Base.connection.execute sql_statement -end From ecb0a77c90142e8bb4eb64b1dd2c32de65d56004 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:27:30 -0700 Subject: [PATCH 0763/1492] removing more unused files --- spec/support/connections/mysql_connection.rb | 14 ---------- spec/support/connections/oracle_connection.rb | 17 ----------- .../connections/postgresql_connection.rb | 13 --------- .../support/connections/sqlite3_connection.rb | 24 ---------------- .../matchers/disambiguate_attributes.rb | 28 ------------------- spec/support/matchers/hash_the_same_as.rb | 26 ----------------- spec/support/matchers/have_rows.rb | 18 ------------ 7 files changed, 140 deletions(-) delete mode 100644 spec/support/connections/mysql_connection.rb delete mode 100644 spec/support/connections/oracle_connection.rb delete mode 100644 spec/support/connections/postgresql_connection.rb delete mode 100644 spec/support/connections/sqlite3_connection.rb delete mode 100644 spec/support/matchers/disambiguate_attributes.rb delete mode 100644 spec/support/matchers/hash_the_same_as.rb delete mode 100644 spec/support/matchers/have_rows.rb diff --git a/spec/support/connections/mysql_connection.rb b/spec/support/connections/mysql_connection.rb deleted file mode 100644 index c924c27080cd5..0000000000000 --- a/spec/support/connections/mysql_connection.rb +++ /dev/null @@ -1,14 +0,0 @@ -puts "Using native MySQL" -require "active_record" -require 'logger' - -ENV['ADAPTER'] = 'mysql' - -ActiveRecord::Base.configurations = { - 'unit' => { - :adapter => 'mysql', - :username => 'root', - :encoding => 'utf8', - :database => 'arel_unit', - } -} diff --git a/spec/support/connections/oracle_connection.rb b/spec/support/connections/oracle_connection.rb deleted file mode 100644 index 309d127071304..0000000000000 --- a/spec/support/connections/oracle_connection.rb +++ /dev/null @@ -1,17 +0,0 @@ -puts "Using native Oracle" -require "active_record" -require 'logger' - -ENV['ADAPTER'] = 'oracle' - -# Prepend oracle_enhanced local development directory in front of load path -$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../../../oracle-enhanced/lib" - -ActiveRecord::Base.configurations = { - 'unit' => { - :adapter => 'oracle_enhanced', - :username => 'arel_unit', - :password => 'arel_unit', - :database => 'orcl', - } -} diff --git a/spec/support/connections/postgresql_connection.rb b/spec/support/connections/postgresql_connection.rb deleted file mode 100644 index 692533d10d184..0000000000000 --- a/spec/support/connections/postgresql_connection.rb +++ /dev/null @@ -1,13 +0,0 @@ -puts "Using native PostgreSQL" -require "active_record" -require 'logger' - -ENV['ADAPTER'] = 'postgresql' - -ActiveRecord::Base.configurations = { - 'unit' => { - :adapter => 'postgresql', - :encoding => 'utf8', - :database => 'arel_unit', - } -} diff --git a/spec/support/connections/sqlite3_connection.rb b/spec/support/connections/sqlite3_connection.rb deleted file mode 100644 index 4c8627c795887..0000000000000 --- a/spec/support/connections/sqlite3_connection.rb +++ /dev/null @@ -1,24 +0,0 @@ -puts "Using native SQLite3" -require "active_record" -require 'logger' - -ENV['ADAPTER'] = 'sqlite3' - -db_file = "spec/support/fixtures/fixture_database.sqlite3" - -ActiveRecord::Base.configurations = { - "unit" => { - :adapter => 'sqlite3', - :database => db_file, - :timeout => 5000 - } -} - -unless File.exist?(db_file) - puts "SQLite3 database not found at #{db_file}. Rebuilding it." - require 'fileutils' - FileUtils.mkdir_p(File.dirname(db_file)) - sqlite_command = %Q{sqlite3 "#{db_file}" "create table a (a integer); drop table a;"} - puts "Executing '#{sqlite_command}'" - raise "Seems that there is no sqlite3 executable available" unless system(sqlite_command) -end diff --git a/spec/support/matchers/disambiguate_attributes.rb b/spec/support/matchers/disambiguate_attributes.rb deleted file mode 100644 index cec5924ca1ecd..0000000000000 --- a/spec/support/matchers/disambiguate_attributes.rb +++ /dev/null @@ -1,28 +0,0 @@ -module Matchers - class DisambiguateAttributes - def initialize(attributes) - @attributes = attributes - end - - def matches?(actual) - @actual = actual - attribute1, attribute2 = @attributes - @actual[attribute1].descends_from?(attribute1) && - !@actual[attribute1].descends_from?(attribute2) && - @actual[attribute2].descends_from?(attribute2) - end - - def failure_message - "" - # "expected #{@actual} to disambiguate its attributes" - end - - def negative_failure_message - "expected #{@actual} to not disambiguate its attributes" - end - end - - def disambiguate_attributes(*attributes) - DisambiguateAttributes.new(attributes) - end -end diff --git a/spec/support/matchers/hash_the_same_as.rb b/spec/support/matchers/hash_the_same_as.rb deleted file mode 100644 index ed00d37f281ac..0000000000000 --- a/spec/support/matchers/hash_the_same_as.rb +++ /dev/null @@ -1,26 +0,0 @@ -module Matchers - class HashTheSameAs - def initialize(expected) - @expected = expected - end - - def matches?(actual) - @actual = actual - hash = {} - hash[@expected] = :some_arbitrary_value - hash[@actual] == :some_arbitrary_value - end - - def failure_message - "expected #{@actual} to hash the same as #{@expected}; they must be `eql?` and have the same `#hash` value" - end - - def negative_failure_message - "expected #{@actual} to hash differently than #{@expected}; they must not be `eql?` or have a differing `#hash` values" - end - end - - def hash_the_same_as(expected) - HashTheSameAs.new(expected) - end -end diff --git a/spec/support/matchers/have_rows.rb b/spec/support/matchers/have_rows.rb deleted file mode 100644 index e476d25f4fa0f..0000000000000 --- a/spec/support/matchers/have_rows.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Matchers - def have_rows(expected) - simple_matcher "have rows" do |given, matcher| - found, got, expected = [], [], expected.map { |r| r.tuple } - given.each do |row| - got << row.tuple - found << expected.find { |r| row.tuple == r } - end - - matcher.failure_message = "Expected to get:\n" \ - "#{expected.map {|r| " #{r.inspect}" }.join("\n")}\n" \ - "instead, got:\n" \ - "#{got.map {|r| " #{r.inspect}" }.join("\n")}" - - found.compact.length == expected.length && got.compact.length == expected.length - end - end -end From bcc37d7fadd336fa90ae41afe6d02f9a2cfe571a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:29:47 -0700 Subject: [PATCH 0764/1492] removing unused rake tasks --- Gemfile | 9 --------- Rakefile | 24 +++++------------------- 2 files changed, 5 insertions(+), 28 deletions(-) delete mode 100644 Gemfile diff --git a/Gemfile b/Gemfile deleted file mode 100644 index f63d624186055..0000000000000 --- a/Gemfile +++ /dev/null @@ -1,9 +0,0 @@ -source :rubygems - -gem "activerecord", :path => ENV["RAILS_SOURCE"] || 'vendor/rails' -gem "diff-lcs" -gem "mysql" -gem "pg" -gem "rake" -gem "rspec" -gem "sqlite3-ruby" diff --git a/Rakefile b/Rakefile index 00d43503a6721..50948d2c513ab 100644 --- a/Rakefile +++ b/Rakefile @@ -6,27 +6,13 @@ rescue LoadError desc "Run specs" task(:spec) { $stderr.puts '`gem install rspec` to run specs' } else - namespace :spec do - %w[mysql sqlite3 postgresql oracle].each do |adapter| - task "set_env_for_#{adapter}" do - ENV['ADAPTER'] = adapter - end - - Spec::Rake::SpecTask.new(adapter) do |t| - t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] - t.libs << "#{File.dirname(__FILE__)}/spec" - t.warning = true - t.spec_files = FileList['spec/**/*_spec.rb'] - end - - desc "Run specs with the #{adapter} database adapter" - task adapter => "set_env_for_#{adapter}" - end + Spec::Rake::SpecTask.new do |t| + t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] + t.libs << "spec" + t.warning = true + t.spec_files = FileList['spec/**/*_spec.rb'] end - desc "Run specs with mysql and sqlite3 database adapters (default)" - task :spec => ["spec:sqlite3", "spec:mysql", "spec:postgresql"] - desc "Default task is to run specs" task :default => :spec end From b9e83c96eef1df1647bfa80202d29fb529cf637c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:45:02 -0700 Subject: [PATCH 0765/1492] adding a manifest, converting to Hoe, generating gemspec --- Manifest.txt | 100 ++++++++++++++++++++++++++++++++++++++++ README.markdown | 18 +++++--- Rakefile | 29 ++++++------ arel.gemspec | 50 ++++++++++++-------- doc/CONVENTIONS | 17 ------- doc/TODO | 118 ------------------------------------------------ 6 files changed, 156 insertions(+), 176 deletions(-) create mode 100644 Manifest.txt delete mode 100644 doc/CONVENTIONS delete mode 100644 doc/TODO diff --git a/Manifest.txt b/Manifest.txt new file mode 100644 index 0000000000000..b7e600f1a90ad --- /dev/null +++ b/Manifest.txt @@ -0,0 +1,100 @@ +History.txt +Manifest.txt +README.markdown +Rakefile +arel.gemspec +lib/arel.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/insert_manager.rb +lib/arel/nodes.rb +lib/arel/nodes/and.rb +lib/arel/nodes/assignment.rb +lib/arel/nodes/avg.rb +lib/arel/nodes/between.rb +lib/arel/nodes/binary.rb +lib/arel/nodes/count.rb +lib/arel/nodes/delete_statement.rb +lib/arel/nodes/equality.rb +lib/arel/nodes/exists.rb +lib/arel/nodes/function.rb +lib/arel/nodes/greater_than.rb +lib/arel/nodes/greater_than_or_equal.rb +lib/arel/nodes/group.rb +lib/arel/nodes/grouping.rb +lib/arel/nodes/having.rb +lib/arel/nodes/in.rb +lib/arel/nodes/inner_join.rb +lib/arel/nodes/insert_statement.rb +lib/arel/nodes/join.rb +lib/arel/nodes/less_than.rb +lib/arel/nodes/less_than_or_equal.rb +lib/arel/nodes/lock.rb +lib/arel/nodes/max.rb +lib/arel/nodes/min.rb +lib/arel/nodes/node.rb +lib/arel/nodes/not_equal.rb +lib/arel/nodes/offset.rb +lib/arel/nodes/on.rb +lib/arel/nodes/or.rb +lib/arel/nodes/outer_join.rb +lib/arel/nodes/select_core.rb +lib/arel/nodes/select_statement.rb +lib/arel/nodes/sql_literal.rb +lib/arel/nodes/string_join.rb +lib/arel/nodes/sum.rb +lib/arel/nodes/table_alias.rb +lib/arel/nodes/unqualified_column.rb +lib/arel/nodes/update_statement.rb +lib/arel/nodes/values.rb +lib/arel/relation.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/version.rb +lib/arel/visitors.rb +lib/arel/visitors/dot.rb +lib/arel/visitors/join_sql.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/to_sql.rb +spec/activerecord_compat_spec.rb +spec/attributes/attribute_spec.rb +spec/attributes_spec.rb +spec/crud_spec.rb +spec/delete_manager_spec.rb +spec/insert_manager_spec.rb +spec/nodes/count_spec.rb +spec/nodes/delete_statement_spec.rb +spec/nodes/equality_spec.rb +spec/nodes/insert_statement_spec.rb +spec/nodes/or_spec.rb +spec/nodes/select_core_spec.rb +spec/nodes/select_statement_spec.rb +spec/nodes/sql_literal_spec.rb +spec/nodes/sum_spec.rb +spec/nodes/update_statement_spec.rb +spec/select_manager_spec.rb +spec/spec.opts +spec/spec_helper.rb +spec/support/check.rb +spec/support/fake_record.rb +spec/support/matchers.rb +spec/support/matchers/be_like.rb +spec/support/shared/tree_manager_shared.rb +spec/table_spec.rb +spec/update_manager_spec.rb +spec/visitors/join_sql_spec.rb +spec/visitors/oracle_spec.rb +spec/visitors/to_sql_spec.rb diff --git a/README.markdown b/README.markdown index f28ed1e0a18b6..10d3f0a0214da 100644 --- a/README.markdown +++ b/README.markdown @@ -1,14 +1,18 @@ -## Abstract ## +# ARel + +* http://github.com/rails/arel + +## DESCRIPTION Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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 ## +## Status For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. On the horizon is the use of DataObjects instead. The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc. -## A Gentle Introduction ## +## A Gentle Introduction Generating a query with ARel is simple. For example, in order to produce @@ -29,7 +33,7 @@ In other words, Arel relations implement Ruby's Enumerable interface. Let's have As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). -### More Sophisticated Queries Relations ### +### 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. @@ -85,11 +89,11 @@ Finally, most operations take a block form. For example: This provides a (sometimes) convenient alternative syntax. -### The Crazy Features ### +### 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). -#### Complex Joins #### +#### 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: @@ -124,7 +128,7 @@ Note that you do NOT want to do something like: This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous. -#### Complex Aggregations #### +#### Complex Aggregations My personal favorite feature of Arel, certainly the most difficult to implement, and possibly only of marginal value, is **closure under joining even in the presence of aggregations**. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. Think of this as a preview of the kind of radical functionality that is to come, stuff no other "ORM" is doing. diff --git a/Rakefile b/Rakefile index 50948d2c513ab..893b143866017 100644 --- a/Rakefile +++ b/Rakefile @@ -1,18 +1,19 @@ require "rubygems" +gem 'hoe', '>= 2.1.0' +require 'hoe' -begin - require "spec/rake/spectask" -rescue LoadError - desc "Run specs" - task(:spec) { $stderr.puts '`gem install rspec` to run specs' } -else - Spec::Rake::SpecTask.new do |t| - t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""] - t.libs << "spec" - t.warning = true - t.spec_files = FileList['spec/**/*_spec.rb'] - end +Hoe.plugin :gemspec # install hoe-gemspec - desc "Default task is to run specs" - task :default => :spec +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'] + self.testlib = :rspec end + +desc "Default task is to run specs" +task :default => :spec diff --git a/arel.gemspec b/arel.gemspec index de63a1d120742..a93d922a1bc6a 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,26 +1,36 @@ # -*- encoding: utf-8 -*- -require 'arel/version' Gem::Specification.new do |s| - s.name = "arel" - s.version = Arel::VERSION - s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"] - s.date = %q{2010-06-08} - s.email = "bryan@brynary.com" - s.homepage = "http://github.com/brynary/arel" - s.summary = "Arel is a relational algebra engine for Ruby" - s.description = <<-EOS.strip -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex -of SQL queries and it 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. - EOS - s.rubyforge_project = "arel" + s.name = %q{arel} + s.version = "1.0.1.beta.1.20100924164427" - s.files = Dir['lib/**/*'] - s.test_files = Dir['spec/**/*.rb'] - Dir['spec/support/fixtures/**/*.rb'] + 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 = %q{2010-09-24} + s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} + s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] + s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.markdown"] + s.files = ["History.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/version.rb", "lib/arel/visitors.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.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/to_sql.rb", "spec/activerecord_compat_spec.rb", "spec/attributes/attribute_spec.rb", "spec/attributes_spec.rb", "spec/crud_spec.rb", "spec/delete_manager_spec.rb", "spec/insert_manager_spec.rb", "spec/nodes/count_spec.rb", "spec/nodes/delete_statement_spec.rb", "spec/nodes/equality_spec.rb", "spec/nodes/insert_statement_spec.rb", "spec/nodes/or_spec.rb", "spec/nodes/select_core_spec.rb", "spec/nodes/select_statement_spec.rb", "spec/nodes/sql_literal_spec.rb", "spec/nodes/sum_spec.rb", "spec/nodes/update_statement_spec.rb", "spec/select_manager_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/support/check.rb", "spec/support/fake_record.rb", "spec/support/matchers.rb", "spec/support/matchers/be_like.rb", "spec/support/shared/tree_manager_shared.rb", "spec/table_spec.rb", "spec/update_manager_spec.rb", "spec/visitors/join_sql_spec.rb", "spec/visitors/oracle_spec.rb", "spec/visitors/to_sql_spec.rb"] + s.homepage = %q{http://github.com/rails/arel} + s.rdoc_options = ["--main", "README.markdown"] + s.require_paths = ["lib"] + s.rubyforge_project = %q{arel} + s.rubygems_version = %q{1.3.7} + s.summary = %q{Arel is a Relational Algebra for Ruby} - s.has_rdoc = true - s.extra_rdoc_files = %w[History.txt README.markdown] + if s.respond_to? :specification_version then + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, [">= 2.0.4"]) + s.add_development_dependency(%q, [">= 2.6.0"]) + else + s.add_dependency(%q, [">= 2.0.4"]) + s.add_dependency(%q, [">= 2.6.0"]) + end + else + s.add_dependency(%q, [">= 2.0.4"]) + s.add_dependency(%q, [">= 2.6.0"]) + end end diff --git a/doc/CONVENTIONS b/doc/CONVENTIONS deleted file mode 100644 index c415a527e170b..0000000000000 --- a/doc/CONVENTIONS +++ /dev/null @@ -1,17 +0,0 @@ -This file should ultimately be replaced by a series of tests, something like a lint tool. - -- all describes and its should use single quotes unless they have nested quotes. -- object instantiation in tests for all objects that are not the SUT should be manufactured in a before -- 'should' and other counterfactuals/subjunctive forms should not be used in tests -- no doubles should be used except for behaviorist testing - - behaviorist testing is desirable only when interacting with the database or the session -- when unit testing, always demonstrate behavior by using a real world example (as in, a public use of the API), so as to provide documentation. -- use collect rather than map -- jargon: - - 'obtains' is preferred to 'returns true' - - 'manufactures' -- in tests - - when manufacturing expected values (right-hand-side of should), avoid convenience methods -- construct it by initializing the object directly (Foo.new(...)). This ensures equality expectations in tests are rigorous. - - the SUT should be manufactured inline inside the test, not in a before - - dependencies for the SUT should be manufactured using convenience methods (or whatever is most terse). -- group conceptually related methods in a class within an inline module; immediately include that module. \ No newline at end of file diff --git a/doc/TODO b/doc/TODO deleted file mode 100644 index 61ff24f4a0188..0000000000000 --- a/doc/TODO +++ /dev/null @@ -1,118 +0,0 @@ -todo: -- fix AR again -- blocks for joins -- fix sql insertions -- implement mnesia adapter - -- CLEANUP!!!!! -- rename externalize to derived. -- deal with table tests in algebra -- fix grouping -- audit unit coverage of algebra -- data objects -- remove all explicit aliasing -- scoped writes -- refactor adapter pattern -- break out adapters into sep modules -- projection is by definition distincting? -- union/intersection -- cache expiry on write -- transactions - -done: -- and/or w/ predicates -. Relation <=> Relation -> InnerJoinOperation -. Relation << Relation -> LeftOuterJoinOperation -. InnerJoinOperation.on(*Predicate) -> InnerJoinRelation -. LeftOuterJoinOperation.on(*Predicate) -> LeftOuterJoinRelation -. Relation[Symbol] -> Attribute -. Relation[Range] -> Relation -. Attribute == Attribute -> EqualityPredicate -. Attribute >= Attribute -> GreaterThanOrEqualToPredicate -. Relation.include?(Column) -> Predicate -. Relation.project(*Column) -> ProjectRelation -. Relation.select(*Predicate) -> SelectionRelation -. Relation.order(*Column) -> OrderRelation -. #to_sql -. Remove Builder -. Namespace -. Audit SqlAlchemy for missing features -- Generalized denormalizations on any aggregation (count, yes, but also max, min, average) -- Remove operator overloading of << and <=> for joins. Make it just foo.join(bar) and foo.outer_join(bar). -- Remove operator overloading of == for predicates. make it a.eq(b) (note lack of question mark). -- hookup more predicates (=, <=, =>) -- get some basic aggregations working: users.project(user[:points].max) -- Alias Table Names -- When joining with any sort of aggregation, it needs to be a nested select -- get a value select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count)) -- Session -- sublimate values to deal with the fact that they must be quoted per engine -- clean-up singleton monstrosity -- extract hashing module -- hash custom matcher -- make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what - - session just calls execute, passing in a connection; by default it gets a connection from the relation. -- #formatter is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a formatter (Sql::Relation) ... should it be called predicate formatter? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of - - renamed to #format: operand1.format(operand2) -- rename sql strategies -- need to_sql for ranges - - {:conditions=>{:id=>2..3}} -- nested orderings -- string passthrough - - conditions - - orderings -- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute - - descend on array, along with bind written in terms of it -- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods? -- string passthrough: - :joins=>"INNER JOIN posts ON comments.post_id = posts.id" -- finish pending tests -- test relation, table reset -- test Value, in particular bind. -- test blank checks in relation.rb -- rename active_relation to arel -- mock out database -- fix complex joining cases: -- active record query adapter -- anonymous table names -- Explicitly model recursive structural decomposition / polymorphism -- Explicitly model the namer/externalizer using interpreter jargon -- All Sql Strategies should be accumulations with the top-level relation? -- instance methodify externalize -- test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. -- rename select to where -- rename all ion classes -- joining with LIMIT is like aggregations!! -- blocks for non-joins -- expressions should be class-based, and joins too, anything _sql should be renamed -- implement in memory adapter -- clean up block_given stuff -- reorganize sql tests -- recursive memory operations -- reorganize memory tests -- result sets to attr correlation too -- implement joins in memory -- result sets should be array relations -- fix AR -- insertions for in memory -- cross-engine joins - -icebox: -- #bind in Attribute and Expression should be doing a descend? -- try to make aggegration testing in join spec to be a bit more unit-like -- standardize quoting - - use strings everywhere, not symbols ? -- "unit" test sql strategies - - use real world examples, so they should be like a tutorial. -- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent -- consider this code from has_many: - # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */ - @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } -- lock - - SELECT suchandsuch FOR UPDATE -- joins become subselects in writes: -users.delete().where( - addresses.c.user_id== - select([users.c.id]). - where(users.c.name=='jack') - ) \ No newline at end of file From e958eb8a3aece884f5302d99fae5305105e9d43a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:47:12 -0700 Subject: [PATCH 0766/1492] updating Rakefile with development dependencies --- Rakefile | 3 ++- arel.gemspec | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 893b143866017..05b31cd65d484 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ require "rubygems" gem 'hoe', '>= 2.1.0' require 'hoe' -Hoe.plugin :gemspec # install hoe-gemspec +Hoe.plugin :gemspec # `gem install hoe-gemspec` Hoe.spec 'arel' do developer('Aaron Patterson', 'aaron@tenderlovemaking.com') @@ -12,6 +12,7 @@ Hoe.spec 'arel' do self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] + self.extra_dev_deps << ['rspec', '~> 1.3.0'] self.testlib = :rspec end diff --git a/arel.gemspec b/arel.gemspec index a93d922a1bc6a..69e4769eb8747 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "1.0.1.beta.1.20100924164427" + s.version = "1.0.1.beta.1.20100924164615" 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"] @@ -24,13 +24,16 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, [">= 2.0.4"]) + s.add_development_dependency(%q, ["~> 1.3.0"]) s.add_development_dependency(%q, [">= 2.6.0"]) else s.add_dependency(%q, [">= 2.0.4"]) + s.add_dependency(%q, ["~> 1.3.0"]) s.add_dependency(%q, [">= 2.6.0"]) end else s.add_dependency(%q, [">= 2.0.4"]) + s.add_dependency(%q, ["~> 1.3.0"]) s.add_dependency(%q, [">= 2.6.0"]) end end From 0ef0b424798b26ce10d2cfb8e2d0365450a0fc95 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:48:07 -0700 Subject: [PATCH 0767/1492] removing the version file --- Manifest.txt | 1 - lib/arel.rb | 4 +++- lib/arel/version.rb | 3 --- 3 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 lib/arel/version.rb diff --git a/Manifest.txt b/Manifest.txt index b7e600f1a90ad..69ea0b6d184f7 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -60,7 +60,6 @@ lib/arel/sql_literal.rb lib/arel/table.rb lib/arel/tree_manager.rb lib/arel/update_manager.rb -lib/arel/version.rb lib/arel/visitors.rb lib/arel/visitors/dot.rb lib/arel/visitors/join_sql.rb diff --git a/lib/arel.rb b/lib/arel.rb index afef2019d4b3c..9d29dfe0a994f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,5 @@ require 'arel/crud' -require 'arel/version' require 'arel/expressions' require 'arel/table' require 'arel/attributes' @@ -27,3 +26,6 @@ require 'arel/sql_literal' #### +module Arel + VERSION = '1.0.1.beta.1' +end diff --git a/lib/arel/version.rb b/lib/arel/version.rb deleted file mode 100644 index 9795347874969..0000000000000 --- a/lib/arel/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module Arel - VERSION = '1.0.1.beta.1' -end From b152644d4520c32db1377049ad54e3ab59a236d8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:49:21 -0700 Subject: [PATCH 0768/1492] updating version --- arel.gemspec | 4 ++-- lib/arel.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 69e4769eb8747..c7e83e6c61b86 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "1.0.1.beta.1.20100924164615" + s.version = "2.0.0.dev.20100924164835" 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"] @@ -10,7 +10,7 @@ Gem::Specification.new do |s| s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.markdown"] - s.files = ["History.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/version.rb", "lib/arel/visitors.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.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/to_sql.rb", "spec/activerecord_compat_spec.rb", "spec/attributes/attribute_spec.rb", "spec/attributes_spec.rb", "spec/crud_spec.rb", "spec/delete_manager_spec.rb", "spec/insert_manager_spec.rb", "spec/nodes/count_spec.rb", "spec/nodes/delete_statement_spec.rb", "spec/nodes/equality_spec.rb", "spec/nodes/insert_statement_spec.rb", "spec/nodes/or_spec.rb", "spec/nodes/select_core_spec.rb", "spec/nodes/select_statement_spec.rb", "spec/nodes/sql_literal_spec.rb", "spec/nodes/sum_spec.rb", "spec/nodes/update_statement_spec.rb", "spec/select_manager_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/support/check.rb", "spec/support/fake_record.rb", "spec/support/matchers.rb", "spec/support/matchers/be_like.rb", "spec/support/shared/tree_manager_shared.rb", "spec/table_spec.rb", "spec/update_manager_spec.rb", "spec/visitors/join_sql_spec.rb", "spec/visitors/oracle_spec.rb", "spec/visitors/to_sql_spec.rb"] + s.files = ["History.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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/to_sql.rb", "spec/activerecord_compat_spec.rb", "spec/attributes/attribute_spec.rb", "spec/attributes_spec.rb", "spec/crud_spec.rb", "spec/delete_manager_spec.rb", "spec/insert_manager_spec.rb", "spec/nodes/count_spec.rb", "spec/nodes/delete_statement_spec.rb", "spec/nodes/equality_spec.rb", "spec/nodes/insert_statement_spec.rb", "spec/nodes/or_spec.rb", "spec/nodes/select_core_spec.rb", "spec/nodes/select_statement_spec.rb", "spec/nodes/sql_literal_spec.rb", "spec/nodes/sum_spec.rb", "spec/nodes/update_statement_spec.rb", "spec/select_manager_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/support/check.rb", "spec/support/fake_record.rb", "spec/support/matchers.rb", "spec/support/matchers/be_like.rb", "spec/support/shared/tree_manager_shared.rb", "spec/table_spec.rb", "spec/update_manager_spec.rb", "spec/visitors/join_sql_spec.rb", "spec/visitors/oracle_spec.rb", "spec/visitors/to_sql_spec.rb"] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] diff --git a/lib/arel.rb b/lib/arel.rb index 9d29dfe0a994f..519940c1a5033 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -27,5 +27,5 @@ #### module Arel - VERSION = '1.0.1.beta.1' + VERSION = '2.0.0.dev' end From 136fdd203752cf0abdc37208a5109e36e9218ab7 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Thu, 16 Sep 2010 10:49:49 -0700 Subject: [PATCH 0769/1492] Arel is MIT licensed. --- MIT-LICENSE.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 MIT-LICENSE.txt diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt new file mode 100644 index 0000000000000..52f1ff7a17f7a --- /dev/null +++ b/MIT-LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (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. From ebf7d70685f72fcf616dc4b68584a49ebe15e14f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 16:51:05 -0700 Subject: [PATCH 0770/1492] adding mit license --- Manifest.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Manifest.txt b/Manifest.txt index 69ea0b6d184f7..711dd4bf82fe3 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,4 +1,5 @@ History.txt +MIT-LICENSE.txt Manifest.txt README.markdown Rakefile From 32dec29a46fda8a801c5fb2d0fc972f1b1b24a3c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Sep 2010 17:23:50 -0700 Subject: [PATCH 0771/1492] hoe sets the default task for us --- Rakefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Rakefile b/Rakefile index 05b31cd65d484..a7904be854883 100644 --- a/Rakefile +++ b/Rakefile @@ -15,6 +15,3 @@ Hoe.spec 'arel' do self.extra_dev_deps << ['rspec', '~> 1.3.0'] self.testlib = :rspec end - -desc "Default task is to run specs" -task :default => :spec From a25b9cbc391e7040fbbbccc932339cb57d11e531 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 26 Sep 2010 16:06:37 -0700 Subject: [PATCH 0772/1492] caching quoted values --- lib/arel.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index 519940c1a5033..f3dbb47ea3b82 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -29,3 +29,7 @@ module Arel VERSION = '2.0.0.dev' end + +def sql raw_sql + Arel::Nodes::SqlLiteral.new raw_sql +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5ec811a53acc4..b9379da8cccb5 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -4,8 +4,10 @@ module Arel module Visitors class ToSql def initialize engine - @engine = engine - @connection = nil + @engine = engine + @connection = nil + @quoted_tables = {} + @quoted_columns = {} end def accept object @@ -67,7 +69,7 @@ def visit_Arel_Nodes_Values o def visit_Arel_Nodes_SelectStatement o [ - o.cores.map { |x| visit x }.join, + o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), ("LIMIT #{o.limit}" if o.limit), (visit(o.offset) if o.offset), @@ -262,11 +264,11 @@ def quote value, column = nil end def quote_table_name name - @connection.quote_table_name name + @quoted_tables[name] ||= @connection.quote_table_name(name) end def quote_column_name name - @connection.quote_column_name name + @quoted_columns[name] ||= @connection.quote_column_name(name) end end end From ec998ae9a6aeda09ad64bb94a50ac8b9fccd246d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Sep 2010 11:32:04 -0700 Subject: [PATCH 0773/1492] using the last seen column for quoting --- lib/arel/visitors/to_sql.rb | 5 ++++- spec/insert_manager_spec.rb | 5 ++++- spec/support/fake_record.rb | 5 +++++ spec/visitors/to_sql_spec.rb | 11 ++++++++++- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b9379da8cccb5..deb087b3900b1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -6,11 +6,13 @@ class ToSql def initialize engine @engine = engine @connection = nil + @last_column = [] @quoted_tables = {} @quoted_columns = {} end def accept object + @last_column = [] @engine.connection_pool.with_connection do |conn| @connection = conn visit object @@ -226,6 +228,7 @@ def visit_Arel_Nodes_UnqualifiedColumn o end def visit_Arel_Attributes_Attribute o + @last_column.push o.column join_name = o.relation.table_alias || o.relation.name "#{quote_table_name join_name}.#{quote_column_name o.name}" end @@ -238,7 +241,7 @@ def visit_Fixnum o; o end alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated - def visit_String o; quote(o) end + def visit_String o; quote(o, @last_column.pop) end alias :visit_ActiveSupport_Multibyte_Chars :visit_String alias :visit_BigDecimal :visit_String diff --git a/spec/insert_manager_spec.rb b/spec/insert_manager_spec.rb index 1cd61ae630b9b..9d6045a913329 100644 --- a/spec/insert_manager_spec.rb +++ b/spec/insert_manager_spec.rb @@ -37,7 +37,10 @@ def type; :boolean; end manager = Arel::InsertManager.new Table.engine time = Time.now - manager.insert [[table[:id], time]] + attribute = table[:id] + attribute.column.type = :date + + manager.insert [[attribute, time]] manager.to_sql.should be_like %{ INSERT INTO "users" ("id") VALUES (#{Table.engine.connection.quote time}) } diff --git a/spec/support/fake_record.rb b/spec/support/fake_record.rb index eb6aa2c472f8f..2aba0c10f28cb 100644 --- a/spec/support/fake_record.rb +++ b/spec/support/fake_record.rb @@ -39,6 +39,11 @@ def quote_column_name name 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'" diff --git a/spec/visitors/to_sql_spec.rb b/spec/visitors/to_sql_spec.rb index 25642ee947944..c234a2d58e3c0 100644 --- a/spec/visitors/to_sql_spec.rb +++ b/spec/visitors/to_sql_spec.rb @@ -13,6 +13,12 @@ module Visitors sql = @visitor.accept Nodes::Equality.new(false, false) sql.should 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.should be_like %{ "users"."id" = 1 } + end end it "should visit_DateTime" do @@ -55,7 +61,9 @@ module Visitors end it "should visit_TrueClass" do - @visitor.accept(@attr.eq(true)).should be_like %{ "users"."id" = 't' } + test = @attr.eq(true) + test.left.column.type = :boolean + @visitor.accept(test).should be_like %{ "users"."id" = 't' } end describe "Nodes::In" do @@ -91,6 +99,7 @@ module Visitors describe 'Equality' do it "should escape strings" do test = @attr.eq 'Aaron Patterson' + test.left.column.type = :string @visitor.accept(test).should be_like %{ "users"."id" = 'Aaron Patterson' } From a4f5ccfe579a3ec74e1811117e887ffbea260e9b Mon Sep 17 00:00:00 2001 From: Krekoten' Marjan Date: Mon, 27 Sep 2010 23:04:34 +0300 Subject: [PATCH 0774/1492] 'sqlite3' ==> {:adapter => 'sqlite3'} --- spec/support/fake_record.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/fake_record.rb b/spec/support/fake_record.rb index 2aba0c10f28cb..5040d2d66c45e 100644 --- a/spec/support/fake_record.rb +++ b/spec/support/fake_record.rb @@ -66,7 +66,7 @@ class Spec < Struct.new(:config) attr_reader :spec def initialize - @spec = Spec.new('sqlite3') + @spec = Spec.new(:adapter => 'sqlite3') end def connection From 77fa5fa5f7cc21824edb5b1c1ebccd58f92e982b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Sep 2010 13:12:15 -0700 Subject: [PATCH 0775/1492] to_sql on nodes may be passed an engine --- lib/arel/nodes/binary.rb | 10 ---------- lib/arel/nodes/function.rb | 7 +------ lib/arel/nodes/grouping.rb | 10 ---------- lib/arel/nodes/node.rb | 10 ++++++++++ spec/nodes/equality_spec.rb | 18 ++++++++++++++++++ spec/spec_helper.rb | 2 +- spec/support/fake_record.rb | 15 +++++++-------- 7 files changed, 37 insertions(+), 35 deletions(-) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 090468adfae6f..cfa75909c5927 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -7,16 +7,6 @@ def initialize left, right @left = left @right = 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 - viz = Visitors::ToSql.new Table.engine - viz.accept self - end end end end diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index a1cd13d4d1827..133dd66019f63 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class Function + class Function < Arel::Nodes::Node include Arel::Expression attr_accessor :expressions, :alias @@ -13,11 +13,6 @@ def as aliaz self.alias = SqlLiteral.new(aliaz) self end - - def to_sql - viz = Visitors::ToSql.new Table.engine - viz.accept self - end end end end diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb index 0af1df1f7a6f5..d52671f169d82 100644 --- a/lib/arel/nodes/grouping.rb +++ b/lib/arel/nodes/grouping.rb @@ -6,16 +6,6 @@ class Grouping < Arel::Nodes::Node def initialize expression @expr = expression 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 - viz = Visitors::ToSql.new Table.engine - viz.accept self - end end end end diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index fd5ea410eabda..91c0a32573719 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -15,6 +15,16 @@ def or right 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 + viz = Visitors::ToSql.new engine + viz.accept self + end end end end diff --git a/spec/nodes/equality_spec.rb b/spec/nodes/equality_spec.rb index 81eea4d482a8b..f1ed7a6904df8 100644 --- a/spec/nodes/equality_spec.rb +++ b/spec/nodes/equality_spec.rb @@ -26,6 +26,24 @@ module Nodes check left.right.should == 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 + check engine.connection.quote_count.should == 2 + end + end end describe 'or' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0031f6903f88f..b9fd9db9308d9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -13,6 +13,6 @@ config.include Check config.before do - Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base) + Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new) end end diff --git a/spec/support/fake_record.rb b/spec/support/fake_record.rb index 2aba0c10f28cb..30c49f2b16b67 100644 --- a/spec/support/fake_record.rb +++ b/spec/support/fake_record.rb @@ -63,14 +63,11 @@ class ConnectionPool class Spec < Struct.new(:config) end - attr_reader :spec + attr_reader :spec, :connection def initialize @spec = Spec.new('sqlite3') - end - - def connection - Connection.new + @connection = Connection.new end def with_connection @@ -79,11 +76,13 @@ def with_connection end class Base - def self.connection_pool - ConnectionPool.new + attr_accessor :connection_pool + + def initialize + @connection_pool = ConnectionPool.new end - def self.connection + def connection connection_pool.connection end end From a697744637fdf6e4bb0575189b3611ca17c10990 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Sep 2010 13:19:53 -0700 Subject: [PATCH 0776/1492] requiring date at the top of the visitor --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index deb087b3900b1..274a491f782a6 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -1,4 +1,5 @@ require 'bigdecimal' +require 'date' module Arel module Visitors From 4f037f651980138f0e951f77e16fb7bd64ae4217 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Sep 2010 13:52:50 -0700 Subject: [PATCH 0777/1492] changing method name to be more clear --- lib/arel/table.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 025ef30e55cd4..c541848c99a08 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -36,10 +36,6 @@ def alias end end - def tm - SelectManager.new(@engine, self) - end - def from table SelectManager.new(@engine, table) end @@ -49,7 +45,7 @@ def joins manager end def join relation, klass = Nodes::InnerJoin - return tm unless relation + return select_manager unless relation sm = SelectManager.new(@engine) case relation @@ -62,27 +58,27 @@ def join relation, klass = Nodes::InnerJoin end def group *columns - tm.group(*columns) + select_manager.group(*columns) end def order *expr - tm.order(*expr) + select_manager.order(*expr) end def where condition - tm.where condition + select_manager.where condition end def project *things - tm.project(*things) + select_manager.project(*things) end def take amount - tm.take amount + select_manager.take amount end def having expr - tm.having expr + select_manager.having expr end def columns @@ -98,6 +94,10 @@ def [] name end private + def select_manager + SelectManager.new(@engine, self) + end + def attributes_for columns return nil unless columns From e75f0e5ae5dd225fe44bd3f6c582f86e18d91ceb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Sep 2010 13:59:50 -0700 Subject: [PATCH 0778/1492] these readers should be accessors --- lib/arel/table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index c541848c99a08..ba31e3183b281 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -5,7 +5,7 @@ class Table @engine = nil class << self; attr_accessor :engine; end - attr_reader :name, :engine, :aliases, :table_alias + attr_accessor :name, :engine, :aliases, :table_alias def initialize name, engine = Table.engine @name = name From c66fcc2b151337d337e16ead970db11491d74bbe Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Tue, 28 Sep 2010 16:15:35 +0300 Subject: [PATCH 0779/1492] pass primary key name and value to ActiveRecord adapter insert method necessary for Oracle adapter for RETURNING ... INTO ... clause generation --- lib/arel/select_manager.rb | 12 ++++++++++-- lib/arel/table.rb | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 21b9395120969..77930a6bb1fd5 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -163,9 +163,17 @@ def to_a # :nodoc: # FIXME: this method should go away def insert values im = InsertManager.new @engine - im.into @ctx.froms + table = @ctx.froms + primary_key_name = (primary_key = table.primary_key) && primary_key.name + # 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 im.insert values - @engine.connection.insert im.to_sql + # 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 diff --git a/lib/arel/table.rb b/lib/arel/table.rb index ba31e3183b281..3285037154ee6 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -27,7 +27,11 @@ def initialize name, engine = Table.engine end def primary_key - @primary_key ||= self[@engine.connection.primary_key(name)] + @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 From 6f8c4f183d47bcc36fc30230bb55f90e59a98a37 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Tue, 28 Sep 2010 17:05:34 +0300 Subject: [PATCH 0780/1492] added missing method visit_Arel_Attributes_Decimal as alias for visit_Arel_Attributes_Attribute --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 274a491f782a6..fc821a0ddbfa8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -234,6 +234,7 @@ def visit_Arel_Attributes_Attribute o "#{quote_table_name join_name}.#{quote_column_name o.name}" end alias :visit_Arel_Attributes_Integer :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 From f4c12fcc4aa29081f5fe51fc3294ccef55280cc8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 28 Sep 2010 16:46:06 -0700 Subject: [PATCH 0781/1492] making select manager public --- lib/arel/table.rb | 3 ++- spec/crud_spec.rb | 1 + spec/select_manager_spec.rb | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 3285037154ee6..e71d7d392cdf6 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -97,11 +97,12 @@ def [] name columns.find { |column| column.name == name } end - private def select_manager SelectManager.new(@engine, self) end + private + def attributes_for columns return nil unless columns diff --git a/spec/crud_spec.rb b/spec/crud_spec.rb index 5c038572842ae..3485df6685933 100644 --- a/spec/crud_spec.rb +++ b/spec/crud_spec.rb @@ -32,6 +32,7 @@ def initialize engine = FakeEngine.new it 'should call insert on the connection' do table = Table.new :users fc = FakeCrudder.new + fc.from table fc.insert [[table[:id], 'foo']] fc.engine.calls.find { |method, _| method == :insert diff --git a/spec/select_manager_spec.rb b/spec/select_manager_spec.rb index 7002d937a2fdc..e5b65b4698ab4 100644 --- a/spec/select_manager_spec.rb +++ b/spec/select_manager_spec.rb @@ -27,7 +27,7 @@ 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 execute sql, name = nil + def execute sql, name = nil, *args @executed << sql end alias :update :execute From f0bf1cf7627562c87b6717b6443a56e3060dfda3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 28 Sep 2010 16:57:33 -0700 Subject: [PATCH 0782/1492] refactoring join_sql to return nil if there are no sources --- lib/arel/select_manager.rb | 2 ++ lib/arel/table.rb | 21 ++++++++++----------- spec/select_manager_spec.rb | 5 +++++ spec/table_spec.rb | 7 +++++++ 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 77930a6bb1fd5..adbf1316d733e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -128,6 +128,8 @@ def take limit end def join_sql + return nil unless @ctx.froms + viz = Visitors::JoinSql.new @engine Nodes::SqlLiteral.new viz.accept @ctx end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index e71d7d392cdf6..171d165bc2962 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -49,40 +49,39 @@ def joins manager end def join relation, klass = Nodes::InnerJoin - return select_manager unless relation + return from(self) unless relation - sm = SelectManager.new(@engine) case relation when String, Nodes::SqlLiteral raise if relation.blank? - sm.from Nodes::StringJoin.new(self, relation) + from Nodes::StringJoin.new(self, relation) else - sm.from klass.new(self, relation, nil) + from klass.new(self, relation, nil) end end def group *columns - select_manager.group(*columns) + from(self).group(*columns) end def order *expr - select_manager.order(*expr) + from(self).order(*expr) end def where condition - select_manager.where condition + from(self).where condition end def project *things - select_manager.project(*things) + from(self).project(*things) end def take amount - select_manager.take amount + from(self).take amount end def having expr - select_manager.having expr + from(self).having expr end def columns @@ -98,7 +97,7 @@ def [] name end def select_manager - SelectManager.new(@engine, self) + SelectManager.new(@engine) end private diff --git a/spec/select_manager_spec.rb b/spec/select_manager_spec.rb index e5b65b4698ab4..287657d0c113f 100644 --- a/spec/select_manager_spec.rb +++ b/spec/select_manager_spec.rb @@ -299,6 +299,11 @@ def execute sql, name = nil, *args manager.join_sql.should be_like %{ 'hello' } check manager.joins(manager).should == manager.join_sql end + + it 'returns nil join sql' do + manager = Arel::SelectManager.new Table.engine + manager.join_sql.should be_nil + end end describe 'order_clauses' do diff --git a/spec/table_spec.rb b/spec/table_spec.rb index 15f2e024e0d70..d0ba46ae565be 100644 --- a/spec/table_spec.rb +++ b/spec/table_spec.rb @@ -12,6 +12,13 @@ module Arel end end + describe 'select_manager' do + it 'should return an empty select manager' do + sm = @relation.select_manager + sm.to_sql.should be_like 'SELECT' + end + end + describe 'having' do it 'adds a having clause' do mgr = @relation.having @relation[:id].eq(10) From d68165501fc80bbce34c43eaaf48381bcca27c15 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 28 Sep 2010 17:08:28 -0700 Subject: [PATCH 0783/1492] adding an easy way for sql literal nodes --- lib/arel.rb | 6 ++++-- spec/nodes/sql_literal_spec.rb | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index f3dbb47ea3b82..eb3123fd554cb 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -30,6 +30,8 @@ module Arel VERSION = '2.0.0.dev' end -def sql raw_sql - Arel::Nodes::SqlLiteral.new raw_sql +module Arel + def self.sql raw_sql + Arel::Nodes::SqlLiteral.new raw_sql + end end diff --git a/spec/nodes/sql_literal_spec.rb b/spec/nodes/sql_literal_spec.rb index 390eb708e1000..f5c53d9f29753 100644 --- a/spec/nodes/sql_literal_spec.rb +++ b/spec/nodes/sql_literal_spec.rb @@ -1,6 +1,13 @@ module Arel module Nodes describe 'sql literal' do + describe 'sql' do + it 'makes a sql literal node' do + sql = Arel.sql 'foo' + sql.should be_kind_of Arel::Nodes::SqlLiteral + end + end + describe 'count' do it 'makes a count node' do node = SqlLiteral.new('*').count From 538faf2ebc0e0e52a876f3be59c6219f620c780b Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Wed, 29 Sep 2010 11:56:54 +0300 Subject: [PATCH 0784/1492] added missing require 'spec_helper' in crud_spec.rb --- spec/crud_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/crud_spec.rb b/spec/crud_spec.rb index 3485df6685933..36b2a0b4e4e43 100644 --- a/spec/crud_spec.rb +++ b/spec/crud_spec.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + module Arel class FakeCrudder < SelectManager class FakeEngine From e619462165bfab5bee85f9761df7f48a6b8f30f0 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Wed, 29 Sep 2010 13:10:17 +0300 Subject: [PATCH 0785/1492] use subquery for limit when DISTINCT is used (in Oracle) --- lib/arel/visitors/oracle.rb | 6 ++++-- spec/visitors/oracle_spec.rb | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 659b75f16dcb6..c691ce294eb0b 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -6,7 +6,9 @@ class Oracle < Arel::Visitors::ToSql def visit_Arel_Nodes_SelectStatement o o = order_hacks(o) - if o.limit && o.orders.empty? && !o.offset + # 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 ) @@ -31,7 +33,7 @@ def visit_Arel_Nodes_SelectStatement o eosql end - if o.limit && !o.orders.empty? + if o.limit o = o.dup limit = o.limit o.limit = nil diff --git a/spec/visitors/oracle_spec.rb b/spec/visitors/oracle_spec.rb index cdf0e3427f6bd..93ade3ef3c96a 100644 --- a/spec/visitors/oracle_spec.rb +++ b/spec/visitors/oracle_spec.rb @@ -71,6 +71,16 @@ module Visitors } 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 = 10 + sql = @visitor.accept stmt + sql.should 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 = 10 From 261d284136567edfeb4dbfd9403ebd95e6bdae75 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 12:54:13 -0400 Subject: [PATCH 0786/1492] Add eq_any. --- lib/arel/attributes/attribute.rb | 8 ++++++++ spec/attributes/attribute_spec.rb | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index e1f7fd81d2bba..b5698a3f1db01 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -11,6 +11,14 @@ def eq other Nodes::Equality.new self, other end + def eq_any others + first = Nodes::Equality.new self, others.shift + + Nodes::Grouping.new others.inject(first) { |memo,expr| + Nodes::Or.new(memo, Nodes::Equality.new(self, expr)) + } + end + def in other case other when Arel::SelectManager diff --git a/spec/attributes/attribute_spec.rb b/spec/attributes/attribute_spec.rb index faef096792694..6420028423f9a 100644 --- a/spec/attributes/attribute_spec.rb +++ b/spec/attributes/attribute_spec.rb @@ -142,6 +142,22 @@ module Attributes end end + describe '#eq_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].eq_any([1,2]).should be_kind_of Nodes::Grouping + end + + it 'should generate multiple ORs in sql' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:id].eq_any([1,2]) + mgr.to_sql.should be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 OR "users"."id" = 2) + } + end + end + describe '#in' do it 'can be constructed with a list' do end From 3a994b9949daccc2a64d08234af22fda78e49a17 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 15:43:51 -0400 Subject: [PATCH 0787/1492] Add support for remaining *_any/*_all attribute methods, and add matches/does_not_match/not_in --- lib/arel/attributes/attribute.rb | 133 ++++++++- lib/arel/nodes.rb | 3 + lib/arel/nodes/does_not_match.rb | 6 + lib/arel/nodes/matches.rb | 6 + lib/arel/nodes/not_in.rb | 6 + lib/arel/visitors/to_sql.rb | 14 + spec/attributes/attribute_spec.rb | 434 +++++++++++++++++++++++++++++- 7 files changed, 597 insertions(+), 5 deletions(-) create mode 100644 lib/arel/nodes/does_not_match.rb create mode 100644 lib/arel/nodes/matches.rb create mode 100644 lib/arel/nodes/not_in.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index b5698a3f1db01..25ffe717b2020 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -7,16 +7,24 @@ 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 - first = Nodes::Equality.new self, others.shift + grouping_any :eq, others + end - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::Or.new(memo, Nodes::Equality.new(self, expr)) - } + def eq_all others + grouping_all :eq, others end def in other @@ -36,13 +44,130 @@ def in 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 + Nodes::NotIn.new self, other.to_a.map { |x| x.id } + when Range + if other.exclude_end? + left = Nodes::LessThan.new(self, other.min) + right = Nodes::GreaterThanOrEqual.new(self, other.max) + Nodes::Or.new left, right + else + left = Nodes::LessThan.new(self, other.min) + right = Nodes::GreaterThan.new(self, other.max) + 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 + first = send method_id, others.shift + + Nodes::Grouping.new others.inject(first) { |memo,expr| + Nodes::Or.new(memo, send(method_id, expr)) + } + end + + def grouping_all method_id, others + first = send method_id, others.shift + + Nodes::Grouping.new others.inject(first) { |memo,expr| + Nodes::And.new(memo, send(method_id, expr)) + } + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 6ed05fb31b4aa..0063ed1cd5bd7 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -10,8 +10,11 @@ require 'arel/nodes/greater_than_or_equal' require 'arel/nodes/less_than' require 'arel/nodes/less_than_or_equal' +require 'arel/nodes/matches' +require 'arel/nodes/does_not_match' require 'arel/nodes/in' +require 'arel/nodes/not_in' require 'arel/nodes/lock' require 'arel/nodes/function' require 'arel/nodes/count' diff --git a/lib/arel/nodes/does_not_match.rb b/lib/arel/nodes/does_not_match.rb new file mode 100644 index 0000000000000..b5693df711ad3 --- /dev/null +++ b/lib/arel/nodes/does_not_match.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class DoesNotMatch < Binary + end + end +end diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb new file mode 100644 index 0000000000000..4b9fd34ad117a --- /dev/null +++ b/lib/arel/nodes/matches.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Matches < Binary + end + end +end diff --git a/lib/arel/nodes/not_in.rb b/lib/arel/nodes/not_in.rb new file mode 100644 index 0000000000000..6cb2c6f832bd9 --- /dev/null +++ b/lib/arel/nodes/not_in.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class NotIn < Binary + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index fc821a0ddbfa8..7f9186d28c21d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -161,6 +161,14 @@ 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_StringJoin o "#{visit o.left} #{visit o.right}" end @@ -191,6 +199,12 @@ def visit_Arel_Nodes_In o "#{visit o.left} IN (#{right})" end + def visit_Arel_Nodes_NotIn o + right = o.right + right = right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') + "#{visit o.left} NOT IN (#{right})" + end + def visit_Arel_Nodes_And o "#{visit o.left} AND #{visit o.right}" end diff --git a/spec/attributes/attribute_spec.rb b/spec/attributes/attribute_spec.rb index 6420028423f9a..c6d4fcebd4276 100644 --- a/spec/attributes/attribute_spec.rb +++ b/spec/attributes/attribute_spec.rb @@ -28,6 +28,38 @@ module Attributes 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]).should 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.should 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]).should 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.should 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) @@ -44,6 +76,38 @@ module Attributes end end + describe '#gt_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].gt_any([1,2]).should 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.should 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]).should 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.should 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) @@ -60,6 +124,134 @@ module Attributes end end + describe '#gteq_any' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].gteq_any([1,2]).should 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.should 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]).should 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.should 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).should 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.should 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]).should 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.should 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]).should 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.should 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).should 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.should 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]).should 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.should 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]).should 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.should 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) @@ -140,6 +332,24 @@ module Attributes check equality.right.should == 1 equality.should 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.should 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.should be_like %{ + SELECT "users"."id" FROM "users" WHERE "users"."id" IS NULL + } + end end describe '#eq_any' do @@ -148,7 +358,7 @@ module Attributes relation[:id].eq_any([1,2]).should be_kind_of Nodes::Grouping end - it 'should generate multiple ORs in sql' do + it 'should generate ORs in sql' do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].eq_any([1,2]) @@ -158,6 +368,118 @@ module Attributes end end + describe '#eq_all' do + it 'should create a Grouping node' do + relation = Table.new(:users) + relation[:id].eq_all([1,2]).should 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.should be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2) + } + end + end + + describe '#matches' do + it 'should create a Matches node' do + relation = Table.new(:users) + relation[:name].matches('%bacon%').should 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.should 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%']).should 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.should 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%']).should 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.should 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%').should 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.should 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%']).should 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.should 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%']).should 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.should 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 @@ -168,6 +490,116 @@ module Attributes check node.left.should == attribute check node.right.should == [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.should 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]).should 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.should 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]).should 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.should 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, nil + node = Nodes::NotIn.new attribute, [1,2,3] + check node.left.should == attribute + check node.right.should == [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.should 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]).should 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.should 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]).should 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.should 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]).should 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.should be_like %{ + SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2) + } + end end end From 5ca0c9a45788a14b9f454c93cd24fb0ae12a896b Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 15:50:24 -0400 Subject: [PATCH 0788/1492] Make PostgreSQL play nice with its friends. (matches -> ILIKE instead of LIKE) --- lib/arel/visitors/postgresql.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 87fc3bd60dc39..5e03f40984f41 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -21,6 +21,14 @@ def visit_Arel_Nodes_SelectStatement o end end + 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 using_distinct_on?(o) o.cores.any? do |core| core.projections.any? do |projection| From cf1db3ce28e6c9fcf6fc724f5467e6b6b450f8bf Mon Sep 17 00:00:00 2001 From: Jacob Hodes Date: Thu, 11 Mar 2010 10:14:49 +0800 Subject: [PATCH 0789/1492] tiny correction to readme --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 10d3f0a0214da..ab05e1245a348 100644 --- a/README.markdown +++ b/README.markdown @@ -60,7 +60,7 @@ What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel users.group(users[:name]) # => SELECT * FROM users GROUP BY name -The best property of the Relational Algebra is its "composability", or closure under all operations. For example, to select AND project, just "chain" the method invocations: +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')) \ From 7a625bf74e4e197746b857ae23b1a0fdfd9f3be7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 29 Sep 2010 14:18:18 -0700 Subject: [PATCH 0790/1492] fixing column escape for IN nodes. [resolves:5732] --- lib/arel/visitors/dot.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 13 +++++++------ spec/visitors/to_sql_spec.rb | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index a65a7f73017cc..3d25d5f0121ce 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,6 +28,10 @@ def accept object end private + def visit_Arel_Nodes_Grouping o + visit_edge o, "expr" + end + def visit_Arel_Nodes_TableAlias o visit_edge o, "name" visit_edge o, "relation" @@ -104,6 +108,7 @@ def visit_Arel_Nodes_Equality o alias :visit_Arel_Nodes_GreaterThan :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_GreaterThanOrEqual :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_Assignment :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_In :visit_Arel_Nodes_Equality def visit_String o @node_stack.last.fields << o diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7f9186d28c21d..974f9f5341c99 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -7,13 +7,13 @@ class ToSql def initialize engine @engine = engine @connection = nil - @last_column = [] + @last_column = nil @quoted_tables = {} @quoted_columns = {} end def accept object - @last_column = [] + @last_column = nil @engine.connection_pool.with_connection do |conn| @connection = conn visit object @@ -195,8 +195,9 @@ def visit_Arel_Table o def visit_Arel_Nodes_In o right = o.right - right = right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') - "#{visit o.left} IN (#{right})" + "#{visit o.left} IN (#{ + right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') + })" end def visit_Arel_Nodes_NotIn o @@ -243,7 +244,7 @@ def visit_Arel_Nodes_UnqualifiedColumn o end def visit_Arel_Attributes_Attribute o - @last_column.push o.column + @last_column = o.column join_name = o.relation.table_alias || o.relation.name "#{quote_table_name join_name}.#{quote_column_name o.name}" end @@ -257,7 +258,7 @@ def visit_Fixnum o; o end alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated - def visit_String o; quote(o, @last_column.pop) end + def visit_String o; quote(o, @last_column) end alias :visit_ActiveSupport_Multibyte_Chars :visit_String alias :visit_BigDecimal :visit_String diff --git a/spec/visitors/to_sql_spec.rb b/spec/visitors/to_sql_spec.rb index c234a2d58e3c0..1302d73e1c03c 100644 --- a/spec/visitors/to_sql_spec.rb +++ b/spec/visitors/to_sql_spec.rb @@ -94,6 +94,21 @@ module Visitors "users"."id" >= 1 AND "users"."id" < 3 } end + + it 'uses the same column for escaping values' do + 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) + visitor.expected = @attr.column + lambda { visitor.accept(in_node) }.should_not raise_error + end end describe 'Equality' do From c308de87fa7a48d980b96c01d43045f17ee487ad Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 29 Sep 2010 14:32:52 -0700 Subject: [PATCH 0791/1492] adding better dot file support for our nodes --- lib/arel/nodes/does_not_match.rb | 2 +- lib/arel/nodes/matches.rb | 2 +- lib/arel/nodes/not_in.rb | 2 +- lib/arel/nodes/unqualified_column.rb | 2 ++ lib/arel/visitors/dot.rb | 38 ++++++++++++++++++++++++++-- 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/lib/arel/nodes/does_not_match.rb b/lib/arel/nodes/does_not_match.rb index b5693df711ad3..33bdeab00599d 100644 --- a/lib/arel/nodes/does_not_match.rb +++ b/lib/arel/nodes/does_not_match.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class DoesNotMatch < Binary + class DoesNotMatch < Arel::Nodes::Binary end end end diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb index 4b9fd34ad117a..5ef8ac83023a4 100644 --- a/lib/arel/nodes/matches.rb +++ b/lib/arel/nodes/matches.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class Matches < Binary + class Matches < Arel::Nodes::Binary end end end diff --git a/lib/arel/nodes/not_in.rb b/lib/arel/nodes/not_in.rb index 6cb2c6f832bd9..6c01921a4609f 100644 --- a/lib/arel/nodes/not_in.rb +++ b/lib/arel/nodes/not_in.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class NotIn < Binary + class NotIn < Arel::Nodes::Binary end end end diff --git a/lib/arel/nodes/unqualified_column.rb b/lib/arel/nodes/unqualified_column.rb index 31561fddd4afe..9882cb08e2ec2 100644 --- a/lib/arel/nodes/unqualified_column.rb +++ b/lib/arel/nodes/unqualified_column.rb @@ -1,6 +1,8 @@ module Arel module Nodes class UnqualifiedColumn + attr_accessor :attribute + def initialize attribute @attribute = attribute end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 3d25d5f0121ce..b75385067a9e0 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -38,6 +38,13 @@ def visit_Arel_Nodes_TableAlias o visit_edge o, "columns" end + def visit_Arel_Nodes_Sum o + visit_edge o, "expressions" + visit_edge o, "alias" + end + alias :visit_Arel_Nodes_Max :visit_Arel_Nodes_Sum + alias :visit_Arel_Nodes_Avg :visit_Arel_Nodes_Sum + def visit_Arel_Nodes_Count o visit_edge o, "expressions" visit_edge o, "distinct" @@ -54,10 +61,27 @@ def visit_Arel_Nodes_Values o def visit_Arel_Nodes_StringJoin o visit_edge o, "left" visit_edge o, "right" + end + + def visit_Arel_Nodes_InnerJoin o + visit_edge o, "left" + visit_edge o, "right" visit_edge o, "constraint" end - alias :visit_Arel_Nodes_InnerJoin :visit_Arel_Nodes_StringJoin - alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_StringJoin + 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 visit_Arel_Nodes_UnqualifiedColumn o + visit_edge o, "attribute" + end + + def visit_Arel_Nodes_Offset o + visit_edge o, "value" + end def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" @@ -109,16 +133,26 @@ def visit_Arel_Nodes_Equality o alias :visit_Arel_Nodes_GreaterThanOrEqual :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_Assignment :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_In :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_LessThan :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_LessThanOrEqual :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_Between :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_NotIn :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_DoesNotMatch :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_Matches :visit_Arel_Nodes_Equality 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_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 From c3bfbecff4e38eeeb6ecdf9886222097396fd8e9 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 17:55:45 -0400 Subject: [PATCH 0792/1492] Don't reassign array in ToSql#visit_Arel_Nodes_NotIn --- lib/arel/visitors/to_sql.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 974f9f5341c99..112466548db2f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -202,8 +202,9 @@ def visit_Arel_Nodes_In o def visit_Arel_Nodes_NotIn o right = o.right - right = right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') - "#{visit o.left} NOT IN (#{right})" + "#{visit o.left} NOT IN (#{ + right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') + })" end def visit_Arel_Nodes_And o From 25e86266afa4fa810af7acfb2686194cb2ea5dcc Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 19:07:33 -0400 Subject: [PATCH 0793/1492] Support visiting Arel_Attribute_Float --- lib/arel/visitors/dot.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index b75385067a9e0..655c75aab9e5f 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -117,6 +117,7 @@ def visit_Arel_Attribute o 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 From f5b76c220ed6583628a84fd899fbb24c39c997ee Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 19:10:30 -0400 Subject: [PATCH 0794/1492] In SQL visitor, too. :) --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 112466548db2f..405578f6040e2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -250,6 +250,7 @@ def visit_Arel_Attributes_Attribute o "#{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 From eef61ab909b614ce6f2d100cfb50044c063bc24a Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 29 Sep 2010 20:08:57 -0400 Subject: [PATCH 0795/1492] Support Attribute#asc and Attribute#desc to create orderings --- lib/arel/attributes/attribute.rb | 8 ++++++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/ordering.rb | 19 ++++++++++++++++++ lib/arel/visitors/dot.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 4 ++++ spec/attributes/attribute_spec.rb | 32 +++++++++++++++++++++++++++++++ spec/visitors/to_sql_spec.rb | 9 +++++++++ 7 files changed, 78 insertions(+) create mode 100644 lib/arel/nodes/ordering.rb diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 25ffe717b2020..ba18533590f1c 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -151,6 +151,14 @@ def lteq_all others grouping_all :lteq, others end + def asc + Nodes::Ordering.new self, :asc + end + + def desc + Nodes::Ordering.new self, :desc + end + private def grouping_any method_id, others diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 0063ed1cd5bd7..47cbd64eb5ee3 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -15,6 +15,7 @@ require 'arel/nodes/in' require 'arel/nodes/not_in' +require 'arel/nodes/ordering' require 'arel/nodes/lock' require 'arel/nodes/function' require 'arel/nodes/count' diff --git a/lib/arel/nodes/ordering.rb b/lib/arel/nodes/ordering.rb new file mode 100644 index 0000000000000..d395c8631d0bc --- /dev/null +++ b/lib/arel/nodes/ordering.rb @@ -0,0 +1,19 @@ +module Arel + module Nodes + class Ordering < Arel::Nodes::Node + attr_accessor :expr, :direction + + def initialize expression, direction = :asc + @expr, @direction = expression, direction + end + + def ascending? + direction == :asc + end + + def descending? + direction == :desc + end + end + end +end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 655c75aab9e5f..5202c5127ee86 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -32,6 +32,11 @@ def visit_Arel_Nodes_Grouping o visit_edge o, "expr" end + def visit_Arel_Nodes_Ordering o + visit_edge o, "expr" + visit_edge o, "direction" + end + def visit_Arel_Nodes_TableAlias o visit_edge o, "name" visit_edge o, "relation" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 405578f6040e2..17779b40372c8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -107,6 +107,10 @@ def visit_Arel_Nodes_Grouping o "(#{visit o.expr})" end + def visit_Arel_Nodes_Ordering o + "#{visit o.expr} #{o.descending? ? 'DESC' : 'ASC'}" + end + def visit_Arel_Nodes_Group o visit o.expr end diff --git a/spec/attributes/attribute_spec.rb b/spec/attributes/attribute_spec.rb index c6d4fcebd4276..562781ade9599 100644 --- a/spec/attributes/attribute_spec.rb +++ b/spec/attributes/attribute_spec.rb @@ -601,6 +601,38 @@ module Attributes } end end + + describe '#asc' do + it 'should create an Ordering node' do + relation = Table.new(:users) + relation[:id].asc.should be_kind_of Nodes::Ordering + 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.should be_like %{ + SELECT "users"."id" FROM "users" ORDER BY "users"."id" ASC + } + end + end + + describe '#desc' do + it 'should create an Ordering node' do + relation = Table.new(:users) + relation[:id].desc.should be_kind_of Nodes::Ordering + 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.should be_like %{ + SELECT "users"."id" FROM "users" ORDER BY "users"."id" DESC + } + end + end end describe 'equality' do diff --git a/spec/visitors/to_sql_spec.rb b/spec/visitors/to_sql_spec.rb index 1302d73e1c03c..a2862e4c4f5a3 100644 --- a/spec/visitors/to_sql_spec.rb +++ b/spec/visitors/to_sql_spec.rb @@ -66,6 +66,15 @@ module Visitors @visitor.accept(test).should be_like %{ "users"."id" = 't' } end + describe "Nodes::Ordering" do + it "should know how to visit" do + node = @attr.desc + @visitor.accept(node).should be_like %{ + "users"."id" DESC + } + end + end + describe "Nodes::In" do it "should know how to visit" do node = @attr.in [1, 2, 3] From 9742785d5c0c076056daf346bf4f37a8348fa412 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 3 Oct 2010 14:26:57 -0700 Subject: [PATCH 0796/1492] alias visitor_for to for --- lib/arel/nodes/node.rb | 2 +- lib/arel/visitors.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 91c0a32573719..43bad19488715 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -22,7 +22,7 @@ def and right # # Maybe we should just use `Table.engine`? :'( def to_sql engine = Table.engine - viz = Visitors::ToSql.new engine + viz = Visitors.for engine viz.accept self end end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index deb4a4f991fab..557c3417a6b8a 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -24,5 +24,6 @@ module Visitors def self.visitor_for engine ENGINE_VISITORS[engine] end + class << self; alias :for :visitor_for; end end end From aebc83102b23042f0dc83be1afb35f86ea381cc3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 12 Oct 2010 14:17:26 -0700 Subject: [PATCH 0797/1492] implementing where_sql method --- lib/arel/select_manager.rb | 7 +++++++ lib/arel/visitors.rb | 1 + spec/select_manager_spec.rb | 17 +++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index adbf1316d733e..66227bc0db3ff 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -122,6 +122,13 @@ def wheres Compatibility::Wheres.new @engine, @ctx.wheres end + def where_sql + return if @ctx.wheres.empty? + + viz = Visitors::WhereSql.new @engine + Nodes::SqlLiteral.new viz.accept @ctx + end + def take limit @head.limit = limit self diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 557c3417a6b8a..fc585c39bbf1f 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -3,6 +3,7 @@ require 'arel/visitors/mysql' require 'arel/visitors/oracle' require 'arel/visitors/join_sql' +require 'arel/visitors/where_sql' require 'arel/visitors/order_clauses' require 'arel/visitors/dot' diff --git a/spec/select_manager_spec.rb b/spec/select_manager_spec.rb index 287657d0c113f..b8512eb7411ed 100644 --- a/spec/select_manager_spec.rb +++ b/spec/select_manager_spec.rb @@ -379,6 +379,23 @@ def execute sql, name = nil, *args 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.should 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.should be_nil + end + end + describe 'update' do it 'copies limits' do engine = EngineProxy.new Table.engine From b43ed9d7b9d4aca1d714b1ccfe9789f8f9f7aae4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 12 Oct 2010 14:28:31 -0700 Subject: [PATCH 0798/1492] fixing manifest file --- Manifest.txt | 5 +++++ lib/arel/visitors/where_sql.rb | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 lib/arel/visitors/where_sql.rb diff --git a/Manifest.txt b/Manifest.txt index 711dd4bf82fe3..a14b9aad2b853 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -22,6 +22,7 @@ lib/arel/nodes/between.rb lib/arel/nodes/binary.rb lib/arel/nodes/count.rb lib/arel/nodes/delete_statement.rb +lib/arel/nodes/does_not_match.rb lib/arel/nodes/equality.rb lib/arel/nodes/exists.rb lib/arel/nodes/function.rb @@ -37,13 +38,16 @@ lib/arel/nodes/join.rb lib/arel/nodes/less_than.rb lib/arel/nodes/less_than_or_equal.rb lib/arel/nodes/lock.rb +lib/arel/nodes/matches.rb lib/arel/nodes/max.rb lib/arel/nodes/min.rb lib/arel/nodes/node.rb lib/arel/nodes/not_equal.rb +lib/arel/nodes/not_in.rb lib/arel/nodes/offset.rb lib/arel/nodes/on.rb lib/arel/nodes/or.rb +lib/arel/nodes/ordering.rb lib/arel/nodes/outer_join.rb lib/arel/nodes/select_core.rb lib/arel/nodes/select_statement.rb @@ -69,6 +73,7 @@ lib/arel/visitors/oracle.rb lib/arel/visitors/order_clauses.rb lib/arel/visitors/postgresql.rb lib/arel/visitors/to_sql.rb +lib/arel/visitors/where_sql.rb spec/activerecord_compat_spec.rb spec/attributes/attribute_spec.rb spec/attributes_spec.rb diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb new file mode 100644 index 0000000000000..9816fa7a70c25 --- /dev/null +++ b/lib/arel/visitors/where_sql.rb @@ -0,0 +1,9 @@ +module 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 From d28290386b148d7b1e4ed70e5bb8da7e6819d187 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 13 Oct 2010 09:15:43 -0700 Subject: [PATCH 0799/1492] bumping version --- lib/arel.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/arel.rb b/lib/arel.rb index eb3123fd554cb..9b3da6d225c98 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -27,10 +27,8 @@ #### module Arel - VERSION = '2.0.0.dev' -end + VERSION = '2.0.0' -module Arel def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql end From d3625bbf8f22e9225f6568cd91caaea5cde903bd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 13 Oct 2010 13:23:52 -0700 Subject: [PATCH 0800/1492] add locking support for postgres --- Manifest.txt | 1 + lib/arel/visitors/postgresql.rb | 4 ++++ spec/visitors/postgres_spec.rb | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 spec/visitors/postgres_spec.rb diff --git a/Manifest.txt b/Manifest.txt index a14b9aad2b853..0c74e6932e5ba 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -102,4 +102,5 @@ spec/table_spec.rb spec/update_manager_spec.rb spec/visitors/join_sql_spec.rb spec/visitors/oracle_spec.rb +spec/visitors/postgres_spec.rb spec/visitors/to_sql_spec.rb diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 5e03f40984f41..553ee91bf9a6b 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -2,6 +2,10 @@ module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql private + def visit_Arel_Nodes_Lock o + "FOR UPDATE" + end + def visit_Arel_Nodes_SelectStatement o if !o.orders.empty? && using_distinct_on?(o) subquery = o.dup diff --git a/spec/visitors/postgres_spec.rb b/spec/visitors/postgres_spec.rb new file mode 100644 index 0000000000000..b5174a4c04c01 --- /dev/null +++ b/spec/visitors/postgres_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +module Arel + module Visitors + describe 'the postgres visitor' do + before do + @visitor = PostgreSQL.new Table.engine + end + + it 'should produce a lock value' do + @visitor.accept(Nodes::Lock.new).should be_like %{ + FOR UPDATE + } + end + end + end +end From 3e5186ffd8b708752f5af054074809f7563f1328 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 13 Oct 2010 13:24:22 -0700 Subject: [PATCH 0801/1492] version bump --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 9b3da6d225c98..1a1f4c12ddc52 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -27,7 +27,7 @@ #### module Arel - VERSION = '2.0.0' + VERSION = '2.0.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 3aace4a4716a0aa88cf605a814ea05d4b841edc5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 15 Oct 2010 15:45:55 -0700 Subject: [PATCH 0802/1492] symbols work as sql literals --- lib/arel/select_manager.rb | 2 +- spec/select_manager_spec.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 66227bc0db3ff..7c3c67b477cf6 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -96,7 +96,7 @@ def project *projections # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. @ctx.projections.concat projections.map { |x| - String == x.class ? SqlLiteral.new(x) : x + [Symbol, String].include?(x.class) ? SqlLiteral.new(x.to_s) : x } self end diff --git a/spec/select_manager_spec.rb b/spec/select_manager_spec.rb index b8512eb7411ed..fa289e0d08a13 100644 --- a/spec/select_manager_spec.rb +++ b/spec/select_manager_spec.rb @@ -37,6 +37,18 @@ def execute sql, name = nil, *args describe 'select manager' do 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.should be_like %{ + SELECT id FROM "users" + } + end + end + describe 'order' do it 'accepts symbols' do table = Table.new :users From 3fcfcd7b80ea9cbb164487922a33eca5609602a6 Mon Sep 17 00:00:00 2001 From: Snuggs Date: Sat, 16 Oct 2010 12:28:56 -0400 Subject: [PATCH 0803/1492] Fixed broken tests by removing undefined matcher requirements --- spec/support/matchers.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb index 5f51a686336bb..486e4fe274cc0 100644 --- a/spec/support/matchers.rb +++ b/spec/support/matchers.rb @@ -1,4 +1 @@ require "support/matchers/be_like" -require "support/matchers/disambiguate_attributes" -require "support/matchers/hash_the_same_as" -require "support/matchers/have_rows" From 7959e55ead84be096247d9622404d1c60ca21c88 Mon Sep 17 00:00:00 2001 From: Snuggs Date: Sat, 16 Oct 2010 17:40:45 -0400 Subject: [PATCH 0804/1492] Created syntactic sugar Table(...) method --- History.txt | 6 ++++++ lib/arel/table.rb | 6 +++++- spec/table_spec.rb | 23 ++++++++++++++++++++++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index bcec68b6cfda0..7a664367096c7 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 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 diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 171d165bc2962..76ced079ba8fc 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -1,4 +1,8 @@ -module Arel +def Table(name, engine = Arel::Table.engine) + Arel::Table.new(name, engine) +end + +module Arel class Table include Arel::Crud diff --git a/spec/table_spec.rb b/spec/table_spec.rb index d0ba46ae565be..77a600877e5a9 100644 --- a/spec/table_spec.rb +++ b/spec/table_spec.rb @@ -1,6 +1,27 @@ require 'spec_helper' -module Arel +describe '#Table' do + it 'creates a base relation variable' do + name = :foo + Table(name) == Arel::Table.new(name) + end + + it 'should have a default engine' do + Table(:foo).engine.should == Arel::Table.engine + end + + it 'can take an engine' do + engine = Arel::Table.engine + Table(:foo, engine).engine.should be engine + end + it 'can take an options hash' do + engine = Arel::Table.engine + options = { :engine => engine } + Table(:foo, options).engine.should be engine + end +end + +module Arel describe Table do before do @relation = Table.new(:users) From e1ebe6e949ef3674434bfa90d271a7b74c2ac153 Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Mon, 18 Oct 2010 15:41:21 -0700 Subject: [PATCH 0805/1492] Fisting arel specs -- still needs tree_manager and cleanup --- .autotest | 26 + Rakefile | 6 +- TAGS | 5725 +++++++++++++++++ lib/arel/table.rb | 6 +- spec/nodes/select_core_spec.rb | 21 - spec/spec.opts | 3 - spec/spec_helper.rb | 18 - spec/support/check.rb | 6 - spec/support/matchers.rb | 1 - spec/support/matchers/be_like.rb | 24 - .../attributes/test_attribute.rb | 166 +- .../count_spec.rb => test/nodes/test_count.rb | 4 +- .../nodes/test_delete_statement.rb | 5 +- .../nodes/test_equality.rb | 18 +- .../nodes/test_insert_statement.rb | 10 +- .../nodes/or_spec.rb => test/nodes/test_or.rb | 10 +- test/nodes/test_select_core.rb | 22 + .../nodes/test_select_statement.rb | 5 +- .../nodes/test_sql_literal.rb | 8 +- .../sum_spec.rb => test/nodes/test_sum.rb | 2 +- .../nodes/test_update_statement.rb | 10 +- test/spec_helper.rb | 21 + {spec => test}/support/fake_record.rb | 0 .../test_activerecord_compat.rb | 2 +- .../test_attributes.rb | 12 +- spec/crud_spec.rb => test/test_crud.rb | 6 +- .../test_delete_manager.rb | 29 +- .../test_insert_manager.rb | 45 +- .../test_select_manager.rb | 130 +- spec/table_spec.rb => test/test_table.rb | 84 +- .../test_update_manager.rb | 39 +- .../visitors/test_join_sql.rb | 4 +- .../visitors/test_oracle.rb | 18 +- .../visitors/test_postgres.rb | 2 +- .../visitors/test_to_sql.rb | 24 +- 35 files changed, 6108 insertions(+), 404 deletions(-) create mode 100644 .autotest create mode 100644 TAGS delete mode 100644 spec/nodes/select_core_spec.rb delete mode 100644 spec/spec.opts delete mode 100644 spec/spec_helper.rb delete mode 100644 spec/support/check.rb delete mode 100644 spec/support/matchers.rb delete mode 100644 spec/support/matchers/be_like.rb rename spec/attributes/attribute_spec.rb => test/attributes/test_attribute.rb (79%) rename spec/nodes/count_spec.rb => test/nodes/test_count.rb (69%) rename spec/nodes/delete_statement_spec.rb => test/nodes/test_delete_statement.rb (69%) rename spec/nodes/equality_spec.rb => test/nodes/test_equality.rb (79%) rename spec/nodes/insert_statement_spec.rb => test/nodes/test_insert_statement.rb (56%) rename spec/nodes/or_spec.rb => test/nodes/test_or.rb (59%) create mode 100644 test/nodes/test_select_core.rb rename spec/nodes/select_statement_spec.rb => test/nodes/test_select_statement.rb (65%) rename spec/nodes/sql_literal_spec.rb => test/nodes/test_sql_literal.rb (72%) rename spec/nodes/sum_spec.rb => test/nodes/test_sum.rb (78%) rename spec/nodes/update_statement_spec.rb => test/nodes/test_update_statement.rb (56%) create mode 100644 test/spec_helper.rb rename {spec => test}/support/fake_record.rb (100%) rename spec/activerecord_compat_spec.rb => test/test_activerecord_compat.rb (82%) rename spec/attributes_spec.rb => test/test_attributes.rb (71%) rename spec/crud_spec.rb => test/test_crud.rb (94%) rename spec/delete_manager_spec.rb => test/test_delete_manager.rb (60%) rename spec/insert_manager_spec.rb => test/test_insert_manager.rb (79%) rename spec/select_manager_spec.rb => test/test_select_manager.rb (81%) rename spec/table_spec.rb => test/test_table.rb (60%) rename spec/update_manager_spec.rb => test/test_update_manager.rb (69%) rename spec/visitors/join_sql_spec.rb => test/visitors/test_join_sql.rb (90%) rename spec/visitors/oracle_spec.rb => test/visitors/test_oracle.rb (91%) rename spec/visitors/postgres_spec.rb => test/visitors/test_postgres.rb (81%) rename spec/visitors/to_sql_spec.rb => test/visitors/test_to_sql.rb (82%) diff --git a/.autotest b/.autotest new file mode 100644 index 0000000000000..19ea6ecbe689b --- /dev/null +++ b/.autotest @@ -0,0 +1,26 @@ +# -*- ruby -*- + +# require 'autotest/restart' + +ENV['GEM_PATH'] = "tmp/isolate/ruby-1.8" + +module Autotest::Restart + Autotest.add_hook :updated do |at, *args| + if args.flatten.include? ".autotest" then + warn "Detected change to .autotest, restarting" + cmd = %w(autotest) + cmd << " -v" if $v + cmd += ARGV + + exec(*cmd) + end + end +end + +Autotest.add_hook :initialize do |at| + at.add_exception 'tmp' + at.testlib = "minitest/autorun" + + at.find_directories = ARGV unless ARGV.empty? +end + diff --git a/Rakefile b/Rakefile index a7904be854883..0097cb5ae0f51 100644 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,7 @@ require "rubygems" gem 'hoe', '>= 2.1.0' require 'hoe' +Hoe.plugin :isolate Hoe.plugin :gemspec # `gem install hoe-gemspec` Hoe.spec 'arel' do @@ -13,5 +14,8 @@ Hoe.spec 'arel' do self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] self.extra_dev_deps << ['rspec', '~> 1.3.0'] - self.testlib = :rspec + self.extra_dev_deps << ['ZenTest'] + self.extra_dev_deps << ['minitest'] + self.extra_dev_deps << ['hoe-gemspec'] + self.testlib = :minitest end diff --git a/TAGS b/TAGS new file mode 100644 index 0000000000000..39d7f7e2f45a9 --- /dev/null +++ b/TAGS @@ -0,0 +1,5725 @@ + +fuck_spec.rb ,32 +def check truthinesscheck3,20 + +fuck_spec.rb ~,0 + +lib/arel/attributes/attribute.rb,1878 +module ArelArel1,0 + module AttributesAttributes2,12 + class Attribute < Struct.new :relation, :name, :columnAttribute3,32 + def not_eq othernot_eq6,124 + def not_eq_any othersnot_eq_any10,198 + def not_eq_all othersnot_eq_all14,274 + def eq othereq18,350 + def eq_any otherseq_any22,420 + def eq_all otherseq_all26,488 + def in otherin30,556 + def in_any othersin_any47,1079 + def in_all othersin_all51,1147 + def not_in othernot_in55,1215 + def not_in_any othersnot_in_any74,1823 + def not_in_all othersnot_in_all78,1899 + def matches othermatches82,1975 + def matches_any othersmatches_any86,2049 + def matches_all othersmatches_all90,2127 + def does_not_match otherdoes_not_match94,2205 + def does_not_match_any othersdoes_not_match_any98,2291 + def does_not_match_all othersdoes_not_match_all102,2383 + def gteq rightgteq106,2475 + def gteq_any othersgteq_any110,2557 + def gteq_all othersgteq_all114,2629 + def gt rightgt118,2701 + def gt_any othersgt_any122,2774 + def gt_all othersgt_all126,2842 + def lt rightlt130,2910 + def lt_any otherslt_any134,2980 + def lt_all otherslt_all138,3048 + def lteq rightlteq142,3116 + def lteq_any otherslteq_any146,3195 + def lteq_all otherslteq_all150,3267 + def ascasc154,3339 + def descdesc158,3403 + def grouping_any method_id, othersgrouping_any164,3484 + def grouping_all method_id, othersgrouping_all172,3708 + class String < Attribute; endString181,3941 + class Time < Attribute; endTime182,3976 + class Boolean < Attribute; endBoolean183,4011 + class Decimal < Attribute; endDecimal184,4046 + class Float < Attribute; endFloat185,4081 + class Integer < Attribute; endInteger186,4116 + +lib/arel/attributes.rb,92 +module ArelArel3,37 + module AttributesAttributes4,49 + def self.for columnfor7,152 + +lib/arel/compatibility/wheres.rb,296 +module ArelArel1,0 + module Compatibility # :nodoc:Compatibility2,12 + class Wheres # :nodoc:Wheres3,45 + module Value # :nodoc:Value6,98 + def valuevalue8,158 + def namename12,219 + def initialize engine, collectioninitialize17,282 + def eacheach22,395 + +lib/arel/crud.rb,145 +module ArelArel1,0 + module CrudCrud4,57 + def update valuesupdate6,111 + def insert valuesinsert24,537 + def deletedelete30,670 + +lib/arel/delete_manager.rb,231 +module ArelArel1,0 + class DeleteManager < Arel::TreeManagerDeleteManager2,12 + def initialize engineinitialize3,54 + def from relationfrom8,142 + def where expressionwhere13,216 + def wheres= listwheres=18,294 + +lib/arel/deprecated.rb,21 +module ArelArel1,0 + +lib/arel/expression.rb,57 +module ArelArel1,0 + module ExpressionExpression2,12 + +lib/arel/expressions.rb,216 +module ArelArel1,0 + module ExpressionsExpressions2,12 + def count distinct = falsecount3,33 + def sumsum7,113 + def maximummaximum11,195 + def minimumminimum15,281 + def averageaverage19,367 + +lib/arel/insert_manager.rb,300 +module ArelArel1,0 + class InsertManager < Arel::TreeManagerInsertManager2,12 + def initialize engineinitialize3,54 + def into tableinto8,142 + def columns; @head.columns endcolumns13,210 + def values= val; @head.values = val; endvalues=14,245 + def insert fieldsinsert16,291 + +lib/arel/nodes/and.rb,92 +module ArelArel1,0 + module NodesNodes2,12 + class And < Arel::Nodes::BinaryAnd3,27 + +lib/arel/nodes/assignment.rb,106 +module ArelArel1,0 + module NodesNodes2,12 + class Assignment < Arel::Nodes::BinaryAssignment3,27 + +lib/arel/nodes/avg.rb,94 +module ArelArel1,0 + module NodesNodes2,12 + class Avg < Arel::Nodes::FunctionAvg3,27 + +lib/arel/nodes/between.rb,100 +module ArelArel1,0 + module NodesNodes2,12 + class Between < Arel::Nodes::BinaryBetween3,27 + +lib/arel/nodes/binary.rb,145 +module ArelArel1,0 + module NodesNodes2,12 + class Binary < Arel::Nodes::NodeBinary3,27 + def initialize left, rightinitialize6,99 + +lib/arel/nodes/count.rb,171 +module ArelArel1,0 + module NodesNodes2,12 + class Count < Arel::Nodes::FunctionCount3,27 + def initialize expr, distinct = false, aliaz = nilinitialize7,99 + +lib/arel/nodes/delete_statement.rb,186 +module ArelArel1,0 + module NodesNodes2,12 + class DeleteStatementDeleteStatement3,27 + def initializeinitialize6,93 + def initialize_copy otherinitialize_copy11,168 + +lib/arel/nodes/does_not_match.rb,110 +module ArelArel1,0 + module NodesNodes2,12 + class DoesNotMatch < Arel::Nodes::BinaryDoesNotMatch3,27 + +lib/arel/nodes/equality.rb,144 +module ArelArel1,0 + module NodesNodes2,12 + class Equality < Arel::Nodes::BinaryEquality3,27 + def operator; :== endoperator4,68 + +lib/arel/nodes/exists.rb,125 +module ArelArel1,0 + module NodesNodes2,12 + class ExistsExists3,27 + def initialize select_stmtinitialize6,76 + +lib/arel/nodes/function.rb,185 +module ArelArel1,0 + module NodesNodes2,12 + class Function < Arel::Nodes::NodeFunction3,27 + def initialize expr, aliaz = nilinitialize7,139 + def as aliazas12,246 + +lib/arel/nodes/greater_than.rb,108 +module ArelArel1,0 + module NodesNodes2,12 + class GreaterThan < Arel::Nodes::BinaryGreaterThan3,27 + +lib/arel/nodes/greater_than_or_equal.rb,122 +module ArelArel1,0 + module NodesNodes2,12 + class GreaterThanOrEqual < Arel::Nodes::BinaryGreaterThanOrEqual3,27 + +lib/arel/nodes/group.rb,116 +module ArelArel1,0 + module NodesNodes2,12 + class GroupGroup3,27 + def initialize exprinitialize6,70 + +lib/arel/nodes/grouping.rb,148 +module ArelArel1,0 + module NodesNodes2,12 + class Grouping < Arel::Nodes::NodeGrouping3,27 + def initialize expressioninitialize6,93 + +lib/arel/nodes/having.rb,118 +module ArelArel1,0 + module NodesNodes2,12 + class HavingHaving3,27 + def initialize exprinitialize6,71 + +lib/arel/nodes/in.rb,79 +module ArelArel1,0 + module NodesNodes2,12 + class In < EqualityIn3,27 + +lib/arel/nodes/inner_join.rb,102 +module ArelArel1,0 + module NodesNodes2,12 + class InnerJoin < Arel::Nodes::JoinInnerJoin3,27 + +lib/arel/nodes/insert_statement.rb,187 +module ArelArel1,0 + module NodesNodes2,12 + class InsertStatementInsertStatement3,27 + def initializeinitialize6,103 + def initialize_copy otherinitialize_copy12,206 + +lib/arel/nodes/join.rb,133 +module ArelArel1,0 + module NodesNodes2,12 + class JoinJoin3,27 + def initialize left, right, constraintinitialize6,90 + +lib/arel/nodes/less_than.rb,102 +module ArelArel1,0 + module NodesNodes2,12 + class LessThan < Arel::Nodes::BinaryLessThan3,27 + +lib/arel/nodes/less_than_or_equal.rb,116 +module ArelArel1,0 + module NodesNodes2,12 + class LessThanOrEqual < Arel::Nodes::BinaryLessThanOrEqual3,27 + +lib/arel/nodes/lock.rb,72 +module ArelArel1,0 + module NodesNodes2,12 + class LockLock3,27 + +lib/arel/nodes/matches.rb,100 +module ArelArel1,0 + module NodesNodes2,12 + class Matches < Arel::Nodes::BinaryMatches3,27 + +lib/arel/nodes/max.rb,94 +module ArelArel1,0 + module NodesNodes2,12 + class Max < Arel::Nodes::FunctionMax3,27 + +lib/arel/nodes/min.rb,94 +module ArelArel1,0 + module NodesNodes2,12 + class Min < Arel::Nodes::FunctionMin3,27 + +lib/arel/nodes/node.rb,184 +module ArelArel1,0 + module NodesNodes2,12 + class NodeNode5,79 + def or rightor9,207 + def and rightand15,355 + def to_sql engine = Table.engineto_sql24,684 + +lib/arel/nodes/not_equal.rb,102 +module ArelArel1,0 + module NodesNodes2,12 + class NotEqual < Arel::Nodes::BinaryNotEqual3,27 + +lib/arel/nodes/not_in.rb,96 +module ArelArel1,0 + module NodesNodes2,12 + class NotIn < Arel::Nodes::BinaryNotIn3,27 + +lib/arel/nodes/offset.rb,119 +module ArelArel1,0 + module NodesNodes2,12 + class OffsetOffset3,27 + def initialize valueinitialize6,72 + +lib/arel/nodes/on.rb,110 +module ArelArel1,0 + module NodesNodes2,12 + class OnOn3,27 + def initialize exprinitialize6,67 + +lib/arel/nodes/or.rb,90 +module ArelArel1,0 + module NodesNodes2,12 + class Or < Arel::Nodes::BinaryOr3,27 + +lib/arel/nodes/ordering.rb,247 +module ArelArel1,0 + module NodesNodes2,12 + class Ordering < Arel::Nodes::NodeOrdering3,27 + def initialize expression, direction = :ascinitialize6,105 + def ascending?ascending?10,216 + def descending?descending?14,274 + +lib/arel/nodes/outer_join.rb,102 +module ArelArel1,0 + module NodesNodes2,12 + class OuterJoin < Arel::Nodes::JoinOuterJoin3,27 + +lib/arel/nodes/select_core.rb,177 +module ArelArel1,0 + module NodesNodes2,12 + class SelectCoreSelectCore3,27 + def initializeinitialize7,136 + def initialize_copy otherinitialize_copy15,300 + +lib/arel/nodes/select_statement.rb,212 +module ArelArel1,0 + module NodesNodes2,12 + class SelectStatementSelectStatement3,27 + def initialize cores = [SelectCore.new]initialize7,131 + def initialize_copy otherinitialize_copy15,299 + +lib/arel/nodes/sql_literal.rb,93 +module ArelArel1,0 + module NodesNodes2,12 + class SqlLiteral < StringSqlLiteral3,27 + +lib/arel/nodes/string_join.rb,153 +module ArelArel1,0 + module NodesNodes2,12 + class StringJoin < Arel::Nodes::JoinStringJoin3,27 + def initialize left, rightinitialize6,93 + +lib/arel/nodes/sum.rb,94 +module ArelArel1,0 + module NodesNodes2,12 + class Sum < Arel::Nodes::FunctionSum3,27 + +lib/arel/nodes/table_alias.rb,165 +module ArelArel1,0 + module NodesNodes2,12 + class TableAliasTableAlias3,27 + def initialize name, relationinitialize7,125 + def [] name[]15,343 + +lib/arel/nodes/unqualified_column.rb,203 +module ArelArel1,0 + module NodesNodes2,12 + class UnqualifiedColumnUnqualifiedColumn3,27 + def initialize attributeinitialize6,87 + def columncolumn10,160 + def namename14,214 + +lib/arel/nodes/update_statement.rb,187 +module ArelArel1,0 + module NodesNodes2,12 + class UpdateStatementUpdateStatement3,27 + def initializeinitialize6,119 + def initialize_copy otherinitialize_copy14,264 + +lib/arel/nodes/values.rb,133 +module ArelArel1,0 + module NodesNodes2,12 + class ValuesValues3,27 + def initialize exprs, columns = []initialize6,88 + +lib/arel/nodes.rb,0 + +lib/arel/relation.rb,53 +module ArelArel1,0 + module RelationRelation4,72 + +lib/arel/select_manager.rb,1162 +module ArelArel1,0 + class SelectManager < Arel::TreeManagerSelectManager2,12 + def initialize engine, table = nilinitialize5,78 + def takentaken12,239 + def constraintsconstraints16,280 + def skip amountskip20,327 + def where_clauseswhere_clauses25,414 + def lock locking = truelock31,588 + def lockedlocked38,796 + def on *exprson42,837 + def group *columnsgroup47,936 + def from tablefrom58,1245 + def join relation, klass = Nodes::InnerJoinjoin76,1699 + def having exprhaving88,2009 + def project *projectionsproject95,2154 + def where exprwhere104,2440 + def order *exprorder109,2505 + def ordersorders117,2744 + def whereswheres121,2787 + def where_sqlwhere_sql125,2864 + def take limittake132,3014 + def join_sqljoin_sql137,3079 + def order_clausesorder_clauses144,3227 + def joins managerjoins150,3364 + class Row < Struct.new(:data) # :nodoc:Row154,3418 + def idid155,3462 + def method_missing(name, *args)method_missing159,3505 + def to_a # :nodoc:to_a166,3646 + def insert valuesinsert173,3921 + def collapse exprscollapse189,4729 + +lib/arel/sql/engine.rb,106 +module ArelArel1,0 + module SqlSql2,12 + class EngineEngine3,25 + def self.new thingnew4,42 + +lib/arel/sql_literal.rb,76 +module ArelArel1,0 + class SqlLiteral < Nodes::SqlLiteralSqlLiteral2,12 + +lib/arel/table.rb,822 +module ArelArel1,0 + class TableTable2,12 + def initialize name, engine = Table.engineinitialize10,173 + def primary_keyprimary_key29,755 + def aliasalias37,989 + def from tablefrom43,1108 + def joins managerjoins47,1176 + def join relation, klass = Nodes::InnerJoinjoin51,1217 + def group *columnsgroup63,1521 + def order *exprorder67,1586 + def where conditionwhere71,1645 + def project *thingsproject75,1711 + def take amounttake79,1778 + def having exprhaving83,1836 + def columnscolumns87,1894 + def [] name[]92,2015 + def select_managerselect_manager99,2156 + def attributes_for columnsattributes_for105,2234 + def table_exists?table_exists?113,2415 + def tablestables117,2530 + def self.table_cache engine # :nodoc:table_cache122,2616 + +lib/arel/tree_manager.rb,212 +module ArelArel1,0 + class TreeManagerTreeManager2,12 + def initialize engineinitialize8,114 + def to_dotto_dot13,219 + def to_sqlto_sql17,280 + def initialize_copy otherinitialize_copy21,332 + +lib/arel/update_manager.rb,319 +module ArelArel1,0 + class UpdateManager < Arel::TreeManagerUpdateManager2,12 + def initialize engineinitialize3,54 + def take limittake8,142 + def order *exprorder13,207 + def table tabletable20,302 + def wheres= exprswheres=25,371 + def where exprwhere29,429 + def set valuesset34,495 + +lib/arel/visitors/dot.rb,2083 +module ArelArel1,0 + module VisitorsVisitors2,12 + class DotDot3,30 + class Node # :nodoc:Node4,44 + def initialize name, id, fields = []initialize7,114 + class Edge < Struct.new :name, :from, :to # :nodoc:Edge14,257 + def initializeinitialize17,326 + def accept objectaccept25,483 + def visit_Arel_Nodes_Grouping ovisit_Arel_Nodes_Grouping31,568 + def visit_Arel_Nodes_Ordering ovisit_Arel_Nodes_Ordering35,646 + def visit_Arel_Nodes_TableAlias ovisit_Arel_Nodes_TableAlias40,758 + def visit_Arel_Nodes_Sum ovisit_Arel_Nodes_Sum46,903 + def visit_Arel_Nodes_Count ovisit_Arel_Nodes_Count53,1125 + def visit_Arel_Nodes_On ovisit_Arel_Nodes_On58,1240 + def visit_Arel_Nodes_Values ovisit_Arel_Nodes_Values62,1312 + def visit_Arel_Nodes_StringJoin ovisit_Arel_Nodes_StringJoin66,1395 + def visit_Arel_Nodes_InnerJoin ovisit_Arel_Nodes_InnerJoin71,1505 + def visit_Arel_Nodes_DeleteStatement ovisit_Arel_Nodes_DeleteStatement78,1717 + def visit_Arel_Nodes_UnqualifiedColumn ovisit_Arel_Nodes_UnqualifiedColumn83,1837 + def visit_Arel_Nodes_Offset ovisit_Arel_Nodes_Offset87,1929 + def visit_Arel_Nodes_InsertStatement ovisit_Arel_Nodes_InsertStatement91,2006 + def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore97,2158 + def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement103,2306 + def visit_Arel_Nodes_UpdateStatement ovisit_Arel_Nodes_UpdateStatement110,2484 + def visit_Arel_Table ovisit_Arel_Table116,2635 + def visit_Arel_Attribute ovisit_Arel_Attribute120,2704 + def visit_Arel_Nodes_Equality ovisit_Arel_Nodes_Equality131,3196 + def visit_String ovisit_String149,4292 + def visit_Hash ovisit_Hash165,4879 + def visit_Array ovisit_Array171,5009 + def visit_edge o, methodvisit_edge177,5121 + def visit ovisit181,5209 + def edge nameedge195,5542 + def with_node nodewith_node203,5712 + def quote stringquote213,5889 + def to_dotto_dot217,5959 + +lib/arel/visitors/join_sql.rb,406 +module ArelArel1,0 + module VisitorsVisitors2,12 + class JoinSql < Arel::Visitors::ToSqlJoinSql11,330 + def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore12,372 + def visit_Arel_Nodes_StringJoin ovisit_Arel_Nodes_StringJoin16,489 + def visit_Arel_Nodes_OuterJoin ovisit_Arel_Nodes_OuterJoin23,654 + def visit_Arel_Nodes_InnerJoin ovisit_Arel_Nodes_InnerJoin30,876 + +lib/arel/visitors/mysql.rb,187 +module ArelArel1,0 + module VisitorsVisitors2,12 + class MySQL < Arel::Visitors::ToSqlMySQL3,30 + def visit_Arel_Nodes_UpdateStatement ovisit_Arel_Nodes_UpdateStatement4,70 + +lib/arel/visitors/oracle.rb,301 +module ArelArel1,0 + module VisitorsVisitors2,12 + class Oracle < Arel::Visitors::ToSqlOracle3,30 + def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement6,86 + def visit_Arel_Nodes_Offset ovisit_Arel_Nodes_Offset46,1288 + def order_hacks oorder_hacks52,1439 + +lib/arel/visitors/order_clauses.rb,201 +module ArelArel1,0 + module VisitorsVisitors2,12 + class OrderClauses < Arel::Visitors::ToSqlOrderClauses3,30 + def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement4,77 + +lib/arel/visitors/postgresql.rb,520 +module ArelArel1,0 + module VisitorsVisitors2,12 + class PostgreSQL < Arel::Visitors::ToSqlPostgreSQL3,30 + def visit_Arel_Nodes_Lock ovisit_Arel_Nodes_Lock5,89 + def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement9,155 + def visit_Arel_Nodes_Matches ovisit_Arel_Nodes_Matches28,708 + def visit_Arel_Nodes_DoesNotMatch ovisit_Arel_Nodes_DoesNotMatch32,805 + def using_distinct_on?(o)using_distinct_on?36,911 + def aliased_orders ordersaliased_orders44,1100 + +lib/arel/visitors/to_sql.rb,3412 +module ArelArel4,37 + module VisitorsVisitors5,49 + class ToSqlToSql6,67 + def initialize engineinitialize7,83 + def accept objectaccept15,273 + def visit_Arel_Nodes_DeleteStatement ovisit_Arel_Nodes_DeleteStatement24,471 + def visit_Arel_Nodes_UpdateStatement ovisit_Arel_Nodes_UpdateStatement31,697 + def visit_Arel_Nodes_InsertStatement ovisit_Arel_Nodes_InsertStatement51,1441 + def visit_Arel_Nodes_Exists ovisit_Arel_Nodes_Exists63,1750 + def visit_Arel_Nodes_Values ovisit_Arel_Nodes_Values67,1839 + def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement73,2027 + def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore83,2397 + def visit_Arel_Nodes_Having ovisit_Arel_Nodes_Having93,2821 + def visit_Arel_Nodes_Offset ovisit_Arel_Nodes_Offset97,2901 + def visit_Arel_Nodes_Lock ovisit_Arel_Nodes_Lock103,3077 + def visit_Arel_Nodes_Grouping ovisit_Arel_Nodes_Grouping106,3122 + def visit_Arel_Nodes_Ordering ovisit_Arel_Nodes_Ordering110,3199 + def visit_Arel_Nodes_Group ovisit_Arel_Nodes_Group114,3308 + def visit_Arel_Nodes_Count ovisit_Arel_Nodes_Count118,3375 + def visit_Arel_Nodes_Sum ovisit_Arel_Nodes_Sum124,3576 + def visit_Arel_Nodes_Max ovisit_Arel_Nodes_Max129,3733 + def visit_Arel_Nodes_Min ovisit_Arel_Nodes_Min134,3890 + def visit_Arel_Nodes_Avg ovisit_Arel_Nodes_Avg139,4047 + def visit_Arel_Nodes_TableAlias ovisit_Arel_Nodes_TableAlias144,4204 + def visit_Arel_Nodes_Between ovisit_Arel_Nodes_Between148,4312 + def visit_Arel_Nodes_GreaterThanOrEqual ovisit_Arel_Nodes_GreaterThanOrEqual152,4411 + def visit_Arel_Nodes_GreaterThan ovisit_Arel_Nodes_GreaterThan156,4516 + def visit_Arel_Nodes_LessThanOrEqual ovisit_Arel_Nodes_LessThanOrEqual160,4613 + def visit_Arel_Nodes_LessThan ovisit_Arel_Nodes_LessThan164,4715 + def visit_Arel_Nodes_Matches ovisit_Arel_Nodes_Matches168,4809 + def visit_Arel_Nodes_DoesNotMatch ovisit_Arel_Nodes_DoesNotMatch172,4905 + def visit_Arel_Nodes_StringJoin ovisit_Arel_Nodes_StringJoin176,5010 + def visit_Arel_Nodes_OuterJoin ovisit_Arel_Nodes_OuterJoin180,5104 + def visit_Arel_Nodes_InnerJoin ovisit_Arel_Nodes_InnerJoin184,5235 + def visit_Arel_Nodes_On ovisit_Arel_Nodes_On188,5377 + def visit_Arel_Table ovisit_Arel_Table192,5449 + def visit_Arel_Nodes_In ovisit_Arel_Nodes_In200,5646 + def visit_Arel_Nodes_NotIn ovisit_Arel_Nodes_NotIn207,5828 + def visit_Arel_Nodes_And ovisit_Arel_Nodes_And214,6017 + def visit_Arel_Nodes_Or ovisit_Arel_Nodes_Or218,6108 + def visit_Arel_Nodes_Assignment ovisit_Arel_Nodes_Assignment222,6197 + def visit_Arel_Nodes_Equality ovisit_Arel_Nodes_Equality227,6331 + def visit_Arel_Nodes_NotEqual ovisit_Arel_Nodes_NotEqual237,6533 + def visit_Arel_Nodes_UnqualifiedColumn ovisit_Arel_Nodes_UnqualifiedColumn247,6740 + def visit_Arel_Attributes_Attribute ovisit_Arel_Attributes_Attribute251,6836 + def visit_Fixnum o; o endvisit_Fixnum263,7503 + def visit_String o; quote(o, @last_column) endvisit_String267,7661 + def visit objectvisit284,8259 + def quote value, column = nilquote288,8337 + def quote_table_name namequote_table_name292,8424 + def quote_column_name namequote_column_name296,8535 + +lib/arel/visitors/where_sql.rb,183 +module ArelArel1,0 + module VisitorsVisitors2,12 + class WhereSql < Arel::Visitors::ToSqlWhereSql3,30 + def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore4,73 + +lib/arel/visitors.rb,109 +module ArelArel10,261 + module VisitorsVisitors11,273 + def self.visitor_for enginevisitor_for25,743 + +lib/arel.rb,58 +module ArelArel29,573 + def self.sql raw_sqlsql32,606 + +spec/support/check.rb,54 +module CheckCheck1,0 + def check(*args)check4,154 + +spec/support/matchers/be_like.rb,292 +module MatchersMatchers1,0 + class BeLikeBeLike2,16 + def initialize(expected)initialize3,31 + def matches?(actual)matches?7,119 + def failure_messagefailure_message12,226 + def negative_failure_messagenegative_failure_message16,314 + def be_like(expected)be_like21,419 + +spec/support/matchers.rb,0 + +spec/support/shared/tree_manager_shared.rb,0 + +test/attributes/test_attribute.rb,58 +module ArelArel3,23 + module AttributesAttributes4,35 + +test/nodes/test_count.rb,0 + +test/nodes/test_delete_statement.rb,0 + +test/nodes/test_equality.rb,318 +module ArelArel3,23 + module NodesNodes4,35 + def quote(*args) @quote_count += 1; super; endquote37,995 + def quote_column_name(*args) @quote_count += 1; super; endquote_column_name38,1056 + def quote_table_name(*args) @quote_count += 1; super; endquote_table_name39,1129 + +test/nodes/test_insert_statement.rb,0 + +test/nodes/test_or.rb,48 +module ArelArel3,23 + module NodesNodes4,35 + +test/nodes/test_select_core.rb,0 + +test/nodes/test_select_statement.rb,0 + +test/nodes/test_sql_literal.rb,48 +module ArelArel3,23 + module NodesNodes4,35 + +test/nodes/test_sum.rb,0 + +test/nodes/test_update_statement.rb,0 + +test/spec_helper.rb,108 +class ObjectObject21,441 + def must_be_like othermust_be_like22,454 + def check truthinesscheck27,575 + +test/support/fake_record.rb,742 +module FakeRecordFakeRecord1,0 + class Column < Struct.new(:name, :type)Column2,18 + class ConnectionConnection5,67 + def initializeinitialize8,111 + def primary_key nameprimary_key21,375 + def table_exists? nametable_exists?25,440 + def columns name, message = nilcolumns29,509 + def quote_table_name namequote_table_name33,580 + def quote_column_name namequote_column_name37,644 + def quote thing, column = nilquote41,709 + class ConnectionPoolConnectionPool62,1057 + class Spec < Struct.new(:config)Spec63,1080 + def initializeinitialize68,1162 + def with_connectionwith_connection73,1271 + class BaseBase78,1333 + def initializeinitialize81,1382 + def connectionconnection85,1454 + +test/test_activerecord_compat.rb,22 +module ArelArel3,23 + +test/test_attributes.rb,22 +module ArelArel3,23 + +test/test_crud.rb,319 +module ArelArel3,23 + class FakeCrudder < SelectManagerFakeCrudder4,35 + class FakeEngineFakeEngine5,71 + def initializeinitialize8,152 + def connection; self endconnection15,302 + def method_missing name, *argsmethod_missing17,334 + def initialize engine = FakeEngine.newinitialize27,487 + +test/test_delete_manager.rb,22 +module ArelArel3,23 + +test/test_insert_manager.rb,22 +module ArelArel3,23 + +test/test_select_manager.rb,533 +module ArelArel3,23 + class EngineProxyEngineProxy4,35 + def initialize engineinitialize10,161 + def with_connectionwith_connection18,331 + def connectionconnection22,381 + def quote_table_name thing; @engine.connection.quote_table_name thing endquote_table_name26,420 + def quote_column_name thing; @engine.connection.quote_column_name thing endquote_column_name27,498 + def quote thing, column; @engine.connection.quote thing, column endquote28,578 + def execute sql, name = nil, *argsexecute30,651 + +test/test_table.rb,22 +module ArelArel3,23 + +test/test_update_manager.rb,22 +module ArelArel3,23 + +test/visitors/test_join_sql.rb,54 +module ArelArel3,23 + module VisitorsVisitors4,35 + +test/visitors/test_oracle.rb,54 +module ArelArel3,23 + module VisitorsVisitors4,35 + +test/visitors/test_postgres.rb,54 +module ArelArel3,23 + module VisitorsVisitors4,35 + +test/visitors/test_to_sql.rb,111 +module ArelArel3,23 + module VisitorsVisitors4,35 + def quote value, column = nilquote111,2951 + +tmp/isolate/ruby-1.8/bin/autospec,0 + +tmp/isolate/ruby-1.8/bin/autotest,0 + +tmp/isolate/ruby-1.8/bin/edit_json.rb,0 + +tmp/isolate/ruby-1.8/bin/multigem,0 + +tmp/isolate/ruby-1.8/bin/multiruby,0 + +tmp/isolate/ruby-1.8/bin/multiruby_setup,0 + +tmp/isolate/ruby-1.8/bin/prettify_json.rb,0 + +tmp/isolate/ruby-1.8/bin/rake,0 + +tmp/isolate/ruby-1.8/bin/rubyforge,0 + +tmp/isolate/ruby-1.8/bin/sow,0 + +tmp/isolate/ruby-1.8/bin/spec,0 + +tmp/isolate/ruby-1.8/bin/unit_diff,0 + +tmp/isolate/ruby-1.8/bin/zentest,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/autotest,49 +class DirDir30,630 + def [](*args)[]33,681 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/multigem,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/multiruby,27 +def setenv dirsetenv7,76 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/multiruby_setup,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/unit_diff,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/zentest,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/example1.rb,97 +module SomethingSomething1,0 + class ThingyThingy2,17 + def do_somethingdo_something3,32 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/example2.rb,205 +module TestSomethingTestSomething1,0 + class TestThingyTestThingy2,21 + def test_do_something_normaltest_do_something_normal3,40 + def test_do_something_edgecasetest_do_something_edgecase8,172 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/example_dot_autotest.rb,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/autoupdate.rb,124 +module Autotest::AutoUpdateAutotest1,0 + def self.sleep_time= osleep_time4,89 + def self.update_cmd= oupdate_cmd8,142 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/once.rb,36 +module Autotest::OnceAutotest4,53 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/rcov.rb,143 +module Autotest::RCovAutotest1,0 + def self.command= ocommand4,60 + def self.pattern= opattern8,107 + def self.options= ooptions12,209 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/restart.rb,38 +module Autotest::RestartAutotest1,0 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/timestamp.rb,41 +module Autotest::TimestampAutotest3,16 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest.rb,1582 +class AutotestAutotest60,1839 + def self.add_discovery &procadd_discovery81,2308 + def self.autodiscoverautodiscover110,3363 + def self.runrun123,3602 + def initializeinitialize152,4293 + def runrun191,5559 + def get_to_greenget_to_green220,6065 + def run_testsrun_tests230,6255 + def add_sigint_handleradd_sigint_handler281,7377 + def all_goodall_good300,7833 + def path_to_classname(s)path_to_classname308,7984 + def consolidate_failures(failed)consolidate_failures321,8355 + def find_filesfind_files345,9032 + def find_files_to_test files = find_filesfind_files_to_test376,9867 + def handle_results(results)handle_results398,10485 + def known_filesknown_files413,10891 + def make_test_cmd files_to_testmake_test_cmd423,11098 + def new_hash_of_arraysnew_hash_of_arrays442,11682 + def reorder files_to_testreorder446,11747 + def rerun_all_testsrerun_all_tests465,12260 + def resetreset476,12450 + def rubyruby491,12742 + def test_files_for(filename)test_files_for506,13143 + def wait_for_changeswait_for_changes522,13613 + def files_matching regexpfiles_matching533,13866 + def add_mapping(regexp, prepend = false, &proc)add_mapping549,14401 + def remove_mapping regexpremove_mapping561,14640 + def clear_mappingsclear_mappings573,14935 + def add_exception regexpadd_exception585,15203 + def remove_exception regexpremove_exception596,15470 + def clear_exceptionsclear_exceptions606,15730 + def exceptionsexceptions617,16020 + def hook(name, *args)hook637,16469 + def self.add_hook(name, &block)add_hook655,16834 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/focus.rb,79 +class ModuleModule1,0 + def focus *wantedsfocus2,13 + def blurblur10,214 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/functional_test_matrix.rb,146 +module FunctionalTestMatrixFunctionalTestMatrix70,2558 + def matrix(name, *setups)matrix71,2586 + def action(action, *results)action75,2659 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/multiruby.rb,1231 +module MultirubyMultiruby45,1592 + def self.env name, fallback; ENV[name] || fallback; end # :nodoc:env46,1609 + def self.build_and_installbuild_and_install63,2171 + def self.cleanclean123,4037 + def self.each_scm_build_direach_scm_build_dir138,4346 + def self.matching_versions url, matching=nilmatching_versions153,4651 + def self.fetch_tar vfetch_tar173,5130 + def self.gnu_utils_build inst_dirgnu_utils_build191,5671 + def self.helphelp199,5958 + def self.in_build_dirin_build_dir203,6000 + def self.in_install_dirin_install_dir209,6078 + def self.in_root_dir subdir = ""in_root_dir215,6160 + def self.in_tmp_dirin_tmp_dir221,6272 + def self.in_versions_dirin_versions_dir227,6346 + def self.listlist233,6430 + def self.merge_rubygemsmerge_rubygems242,6574 + def self.mri_latest_tag vmri_latest_tag257,6865 + def self.rake_build inst_dirrake_build261,6937 + def self.rm namerm266,7069 + def self.root_dirroot_dir274,7246 + def self.run base_cmd, log = nilrun286,7517 + def self.setup_dirs download = truesetup_dirs293,7721 + def self.svn_co url, dirsvn_co310,8236 + def self.tagstags317,8443 + def self.updateupdate333,8881 + def self.update_rubygemsupdate_rubygems386,10280 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/unit_diff.rb,309 +class UnitDiffUnitDiff38,1110 + def self.unit_diffunit_diff54,1471 + def parse_input(input, output)parse_input59,1560 + def parse_diff(result)parse_diff120,3125 + def unit_diff(input=ARGF, output=$stdout)unit_diff192,5026 + def diff expect, butwasdiff234,5989 + def massage(data)massage266,6782 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/zentest.rb,1178 +class ModuleModule24,487 + def zentestzentest25,500 +class ZenTestZenTest54,1444 + def missing_methods; raise "Something is wack"; endmissing_methods66,1661 + def initializeinitialize69,1724 + def load_file(file)load_file80,2043 + def get_class(klassname)get_class96,2437 + def get_methods_for(klass, full=false)get_methods_for124,3343 + def get_inherited_methods_for(klass, full)get_inherited_methods_for152,4341 + def is_test_class(klass)is_test_class177,5072 + def convert_class_name(name)convert_class_name187,5447 + def process_class(klassname, full=false)process_class212,6230 + def scan_files(*files)scan_files234,7106 + def add_missing_method(klassname, methodname)add_missing_method323,9409 + def methods_and_tests(klassname, testklassname)methods_and_tests332,9802 + def analyze_impl(klassname)analyze_impl339,10082 + def analyze_test(testklassname)analyze_test370,11412 + def create_method(indentunit, indent, name)create_method425,13430 + def analyzeanalyze439,13885 + def generate_codegenerate_code455,14397 + def resultresult523,16391 + def self.fix(*files)fix530,16572 + def self.autotest(*klasses)autotest542,16910 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/zentest_mapping.rb,225 +module ZenTestMappingZenTestMapping26,742 + def munge namemunge62,1542 + def normal_to_test namenormal_to_test82,2041 + def unmunge nameunmunge86,2099 + def test_to_normal(name, klassname=nil)test_to_normal106,2735 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_autotest.rb,2609 +class AutotestAutotest21,252 + def self.clear_hooksclear_hooks24,314 +class TestAutotest < MiniTest::Unit::TestCaseTestAutotest29,364 + def deny test, msg=nildeny31,411 + def setupsetup41,650 + def test_add_exceptiontest_add_exception63,1314 + def test_add_mappingtest_add_mapping73,1499 + def test_add_mapping_fronttest_add_mapping_front83,1687 + def test_clear_exceptionstest_clear_exceptions93,1889 + def test_clear_mappingtest_clear_mapping103,2050 + def test_consolidate_failures_experimenttest_consolidate_failures_experiment112,2181 + def test_consolidate_failures_greentest_consolidate_failures_green128,2678 + def test_consolidate_failures_multiple_possibilitiestest_consolidate_failures_multiple_possibilities134,2816 + def test_consolidate_failures_nested_classestest_consolidate_failures_nested_classes143,3129 + def test_consolidate_failures_no_matchtest_consolidate_failures_no_match159,3642 + def test_consolidate_failures_redtest_consolidate_failures_red167,4012 + def test_exceptionstest_exceptions173,4241 + def test_exceptions_niltest_exceptions_nil179,4357 + def test_find_files_to_testtest_find_files_to_test185,4503 + def test_find_files_to_test_dunnotest_find_files_to_test_dunno193,4700 + def test_find_files_to_test_libtest_find_files_to_test_lib202,4998 + def test_find_files_to_test_no_changetest_find_files_to_test_no_change207,5141 + def test_find_files_to_test_testtest_find_files_to_test_test225,5670 + def test_reorder_alphatest_reorder_alpha230,5826 + def test_reorder_reversetest_reorder_reverse237,5954 + def test_reorder_randomtest_reorder_random244,6094 + def test_reorder_naturaltest_reorder_natural257,6341 + def test_handle_resultstest_handle_results269,6614 + def test_hook_overlap_returning_falsetest_hook_overlap_returning_false334,8339 + def test_hook_overlap_returning_truetest_hook_overlap_returning_true344,8665 + def test_hook_responsetest_hook_response354,8993 + def test_make_test_cmdtest_make_test_cmd368,9268 + def test_path_to_classnametest_path_to_classname385,9764 + def test_remove_exceptiontest_remove_exception392,10022 + def test_remove_mappingtest_remove_mapping403,10236 + def test_test_files_fortest_test_files_for413,10438 + def test_testlibtest_testlib423,10805 + def util_exceptionsutil_exceptions433,11053 + def util_find_files_to_test(f, expected)util_find_files_to_test437,11127 + def util_mappingsutil_mappings447,11396 + def util_path_to_classname(e,i)util_path_to_classname451,11460 + def util_reset_hooks_returning valutil_reset_hooks_returning455,11545 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_focus.rb,302 +class TestFocus < MiniTest::Unit::TestCaseTestFocus5,63 + def setupsetup6,106 + def teardownteardown10,136 + def test_focustest_focus14,181 + def test_ignore1test_ignore118,217 + def test_ignore2test_ignore222,266 + def test_ignore3test_ignore326,315 + def test_focus2test_focus230,364 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_unit_diff.rb,1575 +class TestUnitDiff < MiniTest::Unit::TestCaseTestUnitDiff12,131 + def setupsetup14,178 + def test_inputtest_input18,222 + def test_input_miniunittest_input_miniunit30,1159 + def test_input_miniunit_multilinetest_input_miniunit_multiline47,1737 + def test_input_mspectest_input_mspec68,2337 + def test_input_mspec_multilinetest_input_mspec_multiline116,4127 + def test_unit_diff_empty # simulates broken pipe at the leasttest_unit_diff_empty147,6005 + def test_parse_diff_anglestest_parse_diff_angles153,6140 + def test_parse_diff_miniunittest_parse_diff_miniunit168,6564 + def test_parse_diff_miniunit_multilinetest_parse_diff_miniunit_multiline181,6978 + def test_parse_diff1test_parse_diff1194,7410 + def test_parse_diff2test_parse_diff2206,7852 + def test_parse_diff3test_parse_diff3223,8327 + def test_parse_diff_suspect_equalstest_parse_diff_suspect_equals234,8761 + def test_parse_diff_NOT_suspect_equalstest_parse_diff_NOT_suspect_equals247,9234 + def test_parse_diff_mspectest_parse_diff_mspec260,9717 + def test_parse_diff_mspec_multilinetest_parse_diff_mspec_multiline273,10138 + def test_unit_diff_anglestest_unit_diff_angles287,10750 + def test_unit_diff1test_unit_diff1295,11226 + def test_unit_diff2test_unit_diff2303,11770 + def test_unit_diff3test_unit_diff3311,12528 + def test_unit_diff_suspect_equalstest_unit_diff_suspect_equals319,12886 + def test_unit_diff_NOT_suspect_equalstest_unit_diff_NOT_suspect_equals328,13529 + def util_unit_diff(header, input, expected, msg=:unit_diff)util_unit_diff336,13957 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_zentest.rb,6301 +class Cls1 # ZenTest SKIPCls117,424 + def meth1; endmeth118,467 + def self.meth2; endmeth219,484 +class TestCls1 # ZenTest SKIPTestCls122,511 + def setup; endsetup23,554 + def teardown; endteardown24,571 + def test_meth1; endtest_meth125,591 + def test_meth2; assert(true, "something"); endtest_meth226,613 +class SuperDuper # ZenTest SKIPSuperDuper29,667 + def self.cls_inherited; endcls_inherited30,710 + def inherited; endinherited31,740 + def overridden; endoverridden32,761 +class LowlyOne < SuperDuper # ZenTest SKIPLowlyOne35,788 + def self.cls_extended; endcls_extended36,831 + def overridden; endoverridden37,860 + def extended; endextended38,882 + def pretty_print; endpretty_print39,902 + def pretty_print_cycle; endpretty_print_cycle40,926 +class Blah0Blah045,1037 + def missingtest; endmissingtest46,1049 + def notmissing1; endnotmissing147,1072 + def notmissing2; endnotmissing248,1095 + def missingimpl; endmissingimpl51,1156 +class TestBlah0TestBlah054,1184 + def setup; endsetup55,1200 + def teardown; endteardown56,1217 + def test_notmissing1test_notmissing158,1238 + def test_notmissing2_ext1test_notmissing2_ext161,1294 + def test_notmissing2_ext2test_notmissing2_ext264,1355 + def test_missingimpl; endtest_missingimpl67,1416 + def test_missingtest; endtest_missingtest68,1444 +class Blah1Blah171,1477 + def missingtest; endmissingtest72,1489 + def notmissing1; endnotmissing173,1512 + def notmissing2; endnotmissing274,1535 +class TestBlah1TestBlah177,1563 + def test_notmissing1; endtest_notmissing178,1579 + def test_notmissing2_ext1; endtest_notmissing2_ext179,1607 + def test_notmissing2_ext2; endtest_notmissing2_ext280,1640 + def test_missingimpl; Blah1.new.missingimpl; endtest_missingimpl81,1673 + def test_integration_blah1; endtest_integration_blah182,1724 + def test_integration_blah2; endtest_integration_blah283,1758 + def test_integration_blah3; endtest_integration_blah384,1792 +module Something2Something287,1831 + class Blah2Blah288,1849 + def missingtest; endmissingtest89,1863 + def notmissing1; endnotmissing190,1888 + def notmissing2; endnotmissing291,1913 +module TestSomething2TestSomething295,1949 + class TestBlah2TestBlah296,1971 + def test_notmissing1; endtest_notmissing197,1989 + def test_notmissing2_ext1; endtest_notmissing2_ext198,2019 + def test_notmissing2_ext2; endtest_notmissing2_ext299,2054 + def test_missingimpl; endtest_missingimpl100,2089 +class TestBlah3TestBlah3105,2150 + def test_missingimpl; endtest_missingimpl106,2166 +class Blah4Blah4109,2221 + def missingtest1; endmissingtest1110,2233 + def missingtest2; endmissingtest2111,2257 +class MyHash5 < HashMyHash5115,2316 + def missingtest1; endmissingtest1117,2351 +module MyModule6MyModule6121,2395 + class MyClass6MyClass6122,2412 + def missingtest1; endmissingtest1124,2445 +module MyModule7; end # in 1.9+ you'll not need thisMyModule7129,2497 +class MyModule7::MyClass7MyModule7130,2550 + def missingtest1; endmissingtest1132,2590 +class MyClass8MyClass8135,2619 + def self.foobar; endfoobar136,2634 + def MyClass8.foobaz; endfoobaz137,2657 +class TestTrueClass; endTestTrueClass140,2689 +class TestZenTest < MiniTest::Unit::TestCaseTestZenTest142,2715 + def setupsetup143,2760 + def util_simple_setuputil_simple_setup150,2891 +class SomethingSomething180,3640 + def self.method4(*args)method4181,3656 + def method2(*args)method2185,3749 +class TestSomething < Test::Unit::TestCaseTestSomething190,3836 + def test_class_method3test_class_method3191,3879 + def test_attribtest_attrib195,3977 + def test_attrib_equalstest_attrib_equals199,4061 + def test_equal_ehtest_equal_eh203,4159 + def test_method1test_method1207,4247 + def test_method1_bangtest_method1_bang211,4333 + def test_method1_ehtest_method1_eh215,4429 + def test_method1_equalstest_method1_equals219,4521 + def test_initializetest_initialize231,4754 + def test_is_test_classtest_is_test_class239,4970 + def test_is_test_class_reversedtest_is_test_class_reversed258,5790 + def test_convert_class_nametest_convert_class_name270,6208 + def test_convert_class_name_reversedtest_convert_class_name_reversed284,6692 + def test_missing_methods_emptytest_missing_methods_empty304,7324 + def test_add_missing_method_normaltest_add_missing_method_normal309,7432 + def test_add_missing_method_duplicatestest_add_missing_method_duplicates315,7644 + def test_analyze_simpletest_analyze_simple323,7978 + def test_create_methodtest_create_method347,8559 + def test_methods_and_teststest_methods_and_tests354,8792 + def test_generate_code_simpletest_generate_code_simple362,9061 + def test_get_class_goodtest_get_class_good372,9252 + def test_get_class_badtest_get_class_bad376,9339 + def test_get_inherited_methods_for_subclasstest_get_inherited_methods_for_subclass380,9418 + def test_get_inherited_methods_for_subclass_fulltest_get_inherited_methods_for_subclass_full387,9630 + def test_get_inherited_methods_for_superclasstest_get_inherited_methods_for_superclass395,9899 + def test_get_inherited_methods_for_superclass_fulltest_get_inherited_methods_for_superclass_full402,10093 + def test_get_methods_for_subclasstest_get_methods_for_subclass409,10325 + def test_get_methods_for_subclass_fulltest_get_methods_for_subclass_full420,10560 + def test_get_methods_for_superclasstest_get_methods_for_superclass432,10841 + def test_resulttest_result442,11078 + def test_load_filetest_load_file453,11274 + def test_scan_filestest_scan_files457,11371 + def test_process_classtest_process_class461,11470 + def test_klasses_equalstest_klasses_equals475,11991 + def util_testcase(*klasses)util_testcase493,12650 + def test_testcase0test_testcase0503,12886 + def test_testcase1test_testcase1510,13113 + def test_testcase2test_testcase2516,13518 + def test_testcase3test_testcase3522,14019 + def test_testcase4test_testcase4528,14272 + def test_testcase5test_testcase5534,14653 + def test_testcase6test_testcase6540,15024 + def test_testcase7test_testcase7546,15451 + def test_testcase8test_testcase8552,15878 + def test_testcase9test_testcase9558,16265 + +tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_zentest_mapping.rb,1456 +class DummyDummy8,116 +class TestZentestMapping < MiniTest::Unit::TestCaseTestZentestMapping13,193 + def setupsetup14,245 + def util_simple_setuputil_simple_setup18,288 +class SomethingSomething45,1050 + def self.method4(*args)method446,1066 + def method2(*args)method250,1159 +class TestSomething < Test::Unit::TestCaseTestSomething55,1246 + def test_class_method3test_class_method356,1289 + def test_attribtest_attrib60,1387 + def test_attrib_equalstest_attrib_equals64,1471 + def test_equal_ehtest_equal_eh68,1569 + def test_method1test_method172,1657 + def test_method1_bangtest_method1_bang76,1743 + def test_method1_ehtest_method1_eh80,1839 + def test_method1_equalstest_method1_equals84,1931 + def test_normal_to_testtest_normal_to_test93,2076 + def test_normal_to_test_clstest_normal_to_test_cls101,2439 + def test_normal_to_test_operatorstest_normal_to_test_operators113,2905 + def test_normal_to_test_overlaptest_normal_to_test_overlap127,3636 + def test_test_to_normaltest_test_to_normal149,4961 + def test_test_to_normal_clstest_test_to_normal_cls161,5431 + def test_test_to_normal_extendedtest_test_to_normal_extended175,5986 + def test_test_to_normal_mappedtest_test_to_normal_mapped191,6659 + def test_test_to_normal_operatorstest_test_to_normal_operators205,7388 + def test_test_to_normal_overlaptest_test_to_normal_overlap219,8067 + def test_to_normal_subsettest_to_normal_subset238,9077 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/bin/sow,0 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/clean.rb,126 +module Hoe::CleanHoe8,102 + def initialize_cleaninitialize_clean17,259 + def define_clean_tasksdefine_clean_tasks25,460 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/debug.rb,80 +module Hoe::DebugHoe10,206 + def define_debug_tasksdefine_debug_tasks30,604 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/deps.rb,272 +module Hoe::DepsHoe13,357 + def define_deps_tasksdefine_deps_tasks22,499 + def get_source_indexget_source_index126,3831 + def get_latest_gemsget_latest_gems159,4721 + def get_gems_by_nameget_gems_by_name166,4867 + def dependent_upon namedependent_upon175,5104 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/flay.rb,121 +module Hoe::FlayHoe8,106 + def initialize_flayinitialize_flay17,286 + def define_flay_tasksdefine_flay_tasks24,418 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/flog.rb,121 +module Hoe::FlogHoe8,101 + def initialize_floginitialize_flog17,281 + def define_flog_tasksdefine_flog_tasks24,413 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/gemcutter.rb,88 +module Hoe::GemcutterHoe3,16 + def define_gemcutter_tasksdefine_gemcutter_tasks4,38 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/inline.rb,83 +module Hoe::InlineHoe20,525 + def define_inline_tasksdefine_inline_tasks24,579 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/newb.rb,75 +module Hoe::NewbHoe8,95 + def define_newb_tasksdefine_newb_tasks10,149 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/package.rb,195 +module Hoe::PackageHoe17,346 + def initialize_packageinitialize_package31,602 + def define_package_tasksdefine_package_tasks39,724 + def install_gem name, version = nilinstall_gem75,1631 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/publish.rb,324 +module Hoe::PublishHoe29,682 + def initialize_publishinitialize_publish85,2247 + def define_publish_tasksdefine_publish_tasks97,2539 + def generate_email full = nilgenerate_email191,5355 + def announcement # :nodoc:announcement211,5862 +class StringString226,6337 + def rdoc_to_markdownrdoc_to_markdown230,6407 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/rake.rb,275 +module RakeRake1,0 + class TaskTask2,12 + def commentcomment11,235 + module TaskManagerTaskManager16,336 + def all_tasksall_tasks19,429 + def self.all_tasksall_tasks26,531 + def self.clear_tasks(*tasks)clear_tasks34,749 + def self.undo(*names)undo53,1217 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/rcov.rb,76 +module Hoe::RCovHoe8,109 + def define_rcov_tasksdefine_rcov_tasks12,161 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/rubyforge.rb,157 +module Hoe::RubyForgeHoe13,257 + def initialize_rubyforgeinitialize_rubyforge14,279 + def define_rubyforge_tasks # :nodoc:define_rubyforge_tasks18,382 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/signing.rb,87 +module Hoe::SigningHoe39,987 + def define_signing_tasksdefine_signing_tasks46,1191 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/test.rb,191 +module Hoe::TestHoe12,325 + def initialize_testinitialize_test52,1097 + def define_test_tasksdefine_test_tasks62,1302 + def make_test_cmd multi = false # :nodoc:make_test_cmd121,2809 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe.rb,1346 +class HoeHoe59,1601 + def self.add_include_dirs(*dirs)add_include_dirs219,5299 + def self.load_pluginsload_plugins231,5551 + def self.normalize_names project # :nodoc:normalize_names255,6227 + def self.plugin *namesplugin266,6513 + def self.pluginsplugins274,6646 + def self.spec name, &blockspec287,6956 + def activate_pluginsactivate_plugins300,7218 + def add_dependenciesadd_dependencies320,7720 + def dependency_targetdependency_target337,8196 + def define_specdefine_spec344,8321 + def developer name, emaildeveloper421,10525 + def initialize name, version = nil # :nodoc:initialize431,10808 + def intuit_valuesintuit_values466,11881 + def load_plugin_tasksload_plugin_tasks496,12847 + def missing namemissing524,13487 + def normalize_deps depsnormalize_deps532,13683 + def paragraphs_of path, *paragraphsparagraphs_of549,14131 + def pluggable!pluggable!559,14431 + def post_initializepost_initialize567,14604 + def require_rubygems_version versionrequire_rubygems_version578,14815 + def require_ruby_version versionrequire_ruby_version585,14996 + def timebomb n, m, finis = '2010-04-01', start = '2009-03-14'timebomb592,15170 + def validate_fieldsvalidate_fields605,15472 + def with_config # :nodoc:with_config615,15713 +class FileFile623,15886 + def self.read_utf pathread_utf625,15960 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/template/bin/file_name.erb,0 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/test/test_hoe.rb,263 +class TestHoe < MiniTest::Unit::TestCaseTestHoe7,114 + def setupsetup8,155 + def test_file_read_utftest_file_read_utf12,201 + def test_possibly_bettertest_possibly_better20,371 + def test_pluginstest_plugins66,1925 + def test_renametest_rename76,2196 + +tmp/isolate/ruby-1.8/gems/hoe-2.6.2/test/test_hoe_gemcutter.rb,142 +class TestHoeGemcutter < MiniTest::Unit::TestCaseTestHoeGemcutter3,56 + def test_gemcutter_tasks_definedtest_gemcutter_tasks_defined6,132 + +tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/lib/hoe/gemspec.rb,115 +class Hoe #:nodoc:Hoe1,0 + module GemspecGemspec7,127 + def define_gemspec_tasksdefine_gemspec_tasks10,176 + +tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/test/fixture_project/lib/fixture_project.rb,40 +class FixtureProjectFixtureProject1,0 + +tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/test/fixture_project/test/test_fixture_project.rb,107 +class TestFixtureProject < Test::Unit::TestCaseTestFixtureProject4,47 + def test_sanitytest_sanity5,95 + +tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/test/test_hoe_gemspec.rb,99 +class TestHoeBundler < Test::Unit::TestCaseTestHoeBundler4,41 + def test_outputtest_output5,85 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/generator2_benchmark.rb,1105 +module JSONJSON21,415 + def self.[](*) end[]22,427 +module Generator2BenchmarkCommonGenerator2BenchmarkCommon25,453 + def setupsetup28,502 + def generic_reset_methodgeneric_reset_method32,595 +module JSONGeneratorCommonJSONGeneratorCommon37,690 + def benchmark_generator_fastbenchmark_generator_fast40,754 + def benchmark_generator_safebenchmark_generator_safe46,892 + def benchmark_generator_prettybenchmark_generator_pretty52,1025 + def benchmark_generator_asciibenchmark_generator_ascii58,1169 +class Generator2BenchmarkExt < Bullshit::RepeatCaseGenerator2BenchmarkExt65,1329 +class Generator2BenchmarkPure < Bullshit::RepeatCaseGenerator2BenchmarkPure91,1777 +class Generator2BenchmarkRails < Bullshit::RepeatCaseGenerator2BenchmarkRails116,2224 + def benchmark_generatorbenchmark_generator140,2674 +class Generator2BenchmarkYajl < Bullshit::RepeatCaseGenerator2BenchmarkYajl147,2794 + def benchmark_generatorbenchmark_generator171,3244 + def benchmark_generator_gem_apibenchmark_generator_gem_api177,3374 + def reset_benchmark_generatorreset_benchmark_generator181,3442 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/generator_benchmark.rb,1095 +module JSONJSON21,415 + def self.[](*) end[]22,427 +module GeneratorBenchmarkCommonGeneratorBenchmarkCommon25,453 + def setupsetup28,501 + def generic_reset_methodgeneric_reset_method34,689 +module JSONGeneratorCommonJSONGeneratorCommon39,798 + def benchmark_generator_fastbenchmark_generator_fast42,861 + def benchmark_generator_safebenchmark_generator_safe48,999 + def benchmark_generator_prettybenchmark_generator_pretty54,1132 + def benchmark_generator_asciibenchmark_generator_ascii60,1276 +class GeneratorBenchmarkExt < Bullshit::RepeatCaseGeneratorBenchmarkExt67,1436 +class GeneratorBenchmarkPure < Bullshit::RepeatCaseGeneratorBenchmarkPure93,1883 +class GeneratorBenchmarkRails < Bullshit::RepeatCaseGeneratorBenchmarkRails118,2329 + def benchmark_generatorbenchmark_generator142,2777 +class GeneratorBenchmarkYajl < Bullshit::RepeatCaseGeneratorBenchmarkYajl149,2897 + def benchmark_generatorbenchmark_generator173,3345 + def benchmark_generator_gem_apibenchmark_generator_gem_api179,3475 + def reset_benchmark_generatorreset_benchmark_generator183,3543 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/ohai.ruby,0 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/parser2_benchmark.rb,1165 +module Parser2BenchmarkCommonParser2BenchmarkCommon26,490 + def setupsetup29,536 + def generic_reset_methodgeneric_reset_method33,632 +class Parser2BenchmarkExt < Bullshit::RepeatCaseParser2BenchmarkExt38,711 + def benchmark_parserbenchmark_parser62,1154 + def benchmark_parser_symbolicbenchmark_parser_symbolic68,1259 +class Parser2BenchmarkPure < Bullshit::RepeatCaseParser2BenchmarkPure75,1411 + def benchmark_parserbenchmark_parser99,1854 + def benchmark_parser_symbolicbenchmark_parser_symbolic105,1959 +class Parser2BenchmarkYAML < Bullshit::RepeatCaseParser2BenchmarkYAML112,2111 + def setupsetup134,2520 + def benchmark_parserbenchmark_parser138,2616 + def generic_reset_methodgeneric_reset_method142,2677 +class Parser2BenchmarkRails < Bullshit::RepeatCaseParser2BenchmarkRails147,2756 + def setupsetup168,3148 + def benchmark_parserbenchmark_parser174,3328 + def generic_reset_methodgeneric_reset_method178,3406 +class Parser2BenchmarkYajl < Bullshit::RepeatCaseParser2BenchmarkYajl183,3485 + def setupsetup204,3877 + def benchmark_parserbenchmark_parser208,3973 + def generic_reset_methodgeneric_reset_method212,4047 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/parser_benchmark.rb,1154 +module ParserBenchmarkCommonParserBenchmarkCommon26,490 + def setupsetup29,535 + def generic_reset_methodgeneric_reset_method35,715 +class ParserBenchmarkExt < Bullshit::RepeatCaseParserBenchmarkExt40,794 + def benchmark_parserbenchmark_parser64,1235 + def benchmark_parser_symbolicbenchmark_parser_symbolic70,1340 +class ParserBenchmarkPure < Bullshit::RepeatCaseParserBenchmarkPure77,1492 + def benchmark_parserbenchmark_parser101,1933 + def benchmark_parser_symbolicbenchmark_parser_symbolic107,2038 +class ParserBenchmarkYAML < Bullshit::RepeatCaseParserBenchmarkYAML114,2190 + def setupsetup136,2598 + def benchmark_parserbenchmark_parser142,2785 + def generic_reset_methodgeneric_reset_method146,2846 +class ParserBenchmarkRails < Bullshit::RepeatCaseParserBenchmarkRails151,2925 + def setupsetup173,3334 + def benchmark_parserbenchmark_parser179,3514 + def generic_reset_methodgeneric_reset_method183,3592 +class ParserBenchmarkYajl < Bullshit::RepeatCaseParserBenchmarkYajl188,3671 + def setupsetup210,4080 + def benchmark_parserbenchmark_parser216,4260 + def generic_reset_methodgeneric_reset_method220,4334 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/bin/edit_json.rb,0 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/bin/prettify_json.rb,33 +def go(s, args = ARGV)go14,435 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/generator/extconf.rb,0 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/generator/generator.c,10729 +static VALUE CEncoding_UTF_8;CEncoding_UTF_84,52 +static ID i_encoding, i_encode;i_encoding5,82 +static ID i_encoding, i_encode;i_encode5,82 +static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mJSON8,122 +static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mExt8,122 +static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mGenerator8,122 +static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,cState8,122 +static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mGeneratorMethods8,122 +static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mObject8,122 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mHash9,196 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mArray9,196 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mFixnum9,196 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mBignum9,196 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mFloat9,196 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mString9,196 + mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mString_Extend9,196 + mTrueClass, mFalseClass, mNilClass, eGeneratorError,mTrueClass10,275 + mTrueClass, mFalseClass, mNilClass, eGeneratorError,mFalseClass10,275 + mTrueClass, mFalseClass, mNilClass, eGeneratorError,mNilClass10,275 + mTrueClass, mFalseClass, mNilClass, eGeneratorError,eGeneratorError10,275 + eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,eNestingError11,341 + eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,CRegexp_MULTILINE11,341 + eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,CJSON_SAFE_STATE_PROTOTYPE11,341 + i_SAFE_STATE_PROTOTYPE;i_SAFE_STATE_PROTOTYPE12,416 +static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_to_s14,454 +static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_to_json14,454 +static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_new14,454 +static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_indent14,454 +static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_space14,454 +static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_space_before14,454 + i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_object_nl15,525 + i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_array_nl15,525 + i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_max_nesting15,525 + i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_allow_nan15,525 + i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_ascii_only15,525 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_pack16,602 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_unpack16,602 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_create_id16,602 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_extend16,602 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_key_p16,602 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_aref16,602 + i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_send16,602 + i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_respond_to_p17,678 + i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_match17,678 + i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_keys17,678 + i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_depth17,678 + i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_dup17,678 +static const char trailingBytesForUTF8[256] = {trailingBytesForUTF848,1911 +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, offsetsFromUTF864,2695 +static unsigned char isLegalUTF8(const UTF8 *source, int length)isLegalUTF877,3308 +static void unicode_escape(char *buf, UTF16 character)unicode_escape104,4383 +static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16unicode_escape_to_buffer116,4789 +static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)convert_UTF8_to_JSON_ASCII125,5084 +static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)convert_UTF8_to_JSON223,9259 +static char *fstrndup(const char *ptr, int len) {fstrndup287,11147 +static FBuffer *fbuffer_alloc()fbuffer_alloc297,11355 +static FBuffer *fbuffer_alloc_with_length(unsigned int initial_length)fbuffer_alloc_with_length305,11535 +static void fbuffer_free(FBuffer *fb)fbuffer_free315,11786 +static void fbuffer_free_only_buffer(FBuffer *fb)fbuffer_free_only_buffer321,11887 +static void fbuffer_clear(FBuffer *fb)fbuffer_clear326,11962 +static void fbuffer_inc_capa(FBuffer *fb, unsigned int requested)fbuffer_inc_capa331,12023 +static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned int len)fbuffer_append348,12431 +static void fbuffer_append_char(FBuffer *fb, char newchr)fbuffer_append_char357,12652 +static void freverse(char *start, char *end)freverse364,12794 +static int fltoa(long number, char *buf)fltoa373,12926 +static void fbuffer_append_long(FBuffer *fb, long number)fbuffer_append_long386,13218 +static FBuffer *fbuffer_dup(FBuffer *fb)fbuffer_dup393,13367 +static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)mHash_to_json427,14153 +static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {mArray_to_json440,14503 +static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)mFixnum_to_json449,14696 +static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)mBignum_to_json459,14891 +static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)mFloat_to_json469,15084 +static VALUE mString_included_s(VALUE self, VALUE modul) {mString_included_s479,15275 +static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)mString_to_json491,15603 +static VALUE mString_to_json_raw_object(VALUE self)mString_to_json_raw_object504,15995 +static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)mString_to_json_raw520,16471 +static VALUE mString_Extend_json_create(VALUE self, VALUE o)mString_Extend_json_create533,16851 +static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)mTrueClass_to_json546,17141 +static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)mFalseClass_to_json556,17317 +static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)mNilClass_to_json565,17450 +static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)mObject_to_json577,17772 +static void State_free(JSON_Generator_State *state)State_free587,18083 +static JSON_Generator_State *State_allocate()State_allocate600,18625 +static VALUE cState_s_allocate(VALUE klass)cState_s_allocate607,18802 +static VALUE cState_configure(VALUE self, VALUE opts)cState_configure619,19080 +static VALUE cState_to_h(VALUE self)cState_to_h704,21711 +static VALUE cState_aref(VALUE self, VALUE name)cState_aref725,22694 +static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_object735,22919 +static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_array784,24729 +static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_string822,26082 +static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_null836,26499 +static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_false841,26645 +static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_true846,26793 +static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_fixnum851,26939 +static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_bignum856,27096 +static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_float862,27296 +static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json879,27943 +static FBuffer *cState_prepare_buffer(VALUE self)cState_prepare_buffer912,29252 +static VALUE fbuffer_to_s(FBuffer *fb)fbuffer_to_s941,30197 +static VALUE cState_partial_generate(VALUE self, VALUE obj)cState_partial_generate949,30355 +static VALUE cState_generate(VALUE self, VALUE obj)cState_generate964,30778 +static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)cState_initialize993,31940 +static VALUE cState_init_copy(VALUE obj, VALUE orig)cState_init_copy1009,32319 +static VALUE cState_from_state_s(VALUE self, VALUE opts)cState_from_state_s1036,33644 +static VALUE cState_indent(VALUE self)cState_indent1055,34188 +static VALUE cState_indent_set(VALUE self, VALUE indent)cState_indent_set1066,34423 +static VALUE cState_space(VALUE self)cState_space1092,35039 +static VALUE cState_space_set(VALUE self, VALUE space)cState_space_set1104,35292 +static VALUE cState_space_before(VALUE self)cState_space_before1129,35894 +static VALUE cState_space_before_set(VALUE self, VALUE space_before)cState_space_before_set1140,36174 +static VALUE cState_object_nl(VALUE self)cState_object_nl1166,36873 +static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)cState_object_nl_set1178,37147 +static VALUE cState_array_nl(VALUE self)cState_array_nl1202,37754 +static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)cState_array_nl_set1213,38009 +static VALUE cState_check_circular_p(VALUE self)cState_check_circular_p1239,38629 +static VALUE cState_max_nesting(VALUE self)cState_max_nesting1251,38923 +static VALUE cState_max_nesting_set(VALUE self, VALUE depth)cState_max_nesting_set1263,39230 +static VALUE cState_allow_nan_p(VALUE self)cState_allow_nan_p1276,39531 +static VALUE cState_ascii_only_p(VALUE self)cState_ascii_only_p1288,39780 +static VALUE cState_depth(VALUE self)cState_depth1299,39996 +static VALUE cState_depth_set(VALUE self, VALUE depth)cState_depth_set1311,40285 +void Init_generator()Init_generator1321,40452 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/generator/generator.h,2756 +#define _GENERATOR_H__GENERATOR_H_2,22 +#define FORCE_UTF8(FORCE_UTF820,264 +#define FORCE_UTF8(FORCE_UTF822,338 +#define option_given_p(option_given_p25,370 +#define RHASH_SIZE(RHASH_SIZE28,465 +#define RFLOAT_VALUE(RFLOAT_VALUE32,549 +#define RARRAY_PTR(RARRAY_PTR36,623 +#define RARRAY_LEN(RARRAY_LEN39,694 +#define RSTRING_PTR(RSTRING_PTR42,766 +#define RSTRING_LEN(RSTRING_LEN45,842 +#define RSTRING_PAIR(RSTRING_PAIR48,899 +typedef struct FBufferStruct {FBufferStruct52,1000 + unsigned int initial_length;initial_length53,1031 + char *ptr;ptr54,1064 + unsigned int len;len55,1079 + unsigned int capa;capa56,1101 +} FBuffer;FBuffer57,1124 +#define FBUFFER_INITIAL_LENGTH FBUFFER_INITIAL_LENGTH59,1136 +#define FBUFFER_PTR(FBUFFER_PTR61,1173 +#define FBUFFER_LEN(FBUFFER_LEN62,1207 +#define FBUFFER_CAPA(FBUFFER_CAPA63,1241 +#define FBUFFER_PAIR(FBUFFER_PAIR64,1277 +#define UNI_STRICT_CONVERSION UNI_STRICT_CONVERSION80,1922 +typedef unsigned long UTF32; /* at least 32 bits */UTF3282,1955 +typedef unsigned short UTF16; /* at least 16 bits */UTF1683,2007 +typedef unsigned char UTF8; /* typically 8 bits */UTF884,2060 +#define UNI_REPLACEMENT_CHAR UNI_REPLACEMENT_CHAR86,2112 +#define UNI_MAX_BMP UNI_MAX_BMP87,2159 +#define UNI_MAX_UTF16 UNI_MAX_UTF1688,2197 +#define UNI_MAX_UTF32 UNI_MAX_UTF3289,2237 +#define UNI_MAX_LEGAL_UTF32 UNI_MAX_LEGAL_UTF3290,2277 +#define UNI_SUR_HIGH_START UNI_SUR_HIGH_START92,2324 +#define UNI_SUR_HIGH_END UNI_SUR_HIGH_END93,2366 +#define UNI_SUR_LOW_START UNI_SUR_LOW_START94,2408 +#define UNI_SUR_LOW_END UNI_SUR_LOW_END95,2450 +static const int halfShift = 10; /* used for shifting by 10 bits */halfShift97,2493 +static const UTF32 halfBase = 0x0010000UL;halfBase99,2563 +static const UTF32 halfMask = 0x3FFUL;halfMask100,2606 +typedef struct JSON_Generator_StateStruct {JSON_Generator_StateStruct110,3023 + char *indent;indent111,3067 + long indent_len;indent_len112,3085 + char *space;space113,3106 + long space_len;space_len114,3123 + char *space_before;space_before115,3143 + long space_before_len;space_before_len116,3167 + char *object_nl;object_nl117,3194 + long object_nl_len;object_nl_len118,3215 + char *array_nl;array_nl119,3239 + long array_nl_len;array_nl_len120,3259 + FBuffer *array_delim;array_delim121,3282 + FBuffer *object_delim;object_delim122,3308 + FBuffer *object_delim2;object_delim2123,3335 + long max_nesting;max_nesting124,3363 + char allow_nan;allow_nan125,3385 + char ascii_only;ascii_only126,3405 + long depth;depth127,3426 +} JSON_Generator_State;JSON_Generator_State128,3442 +#define GET_STATE(GET_STATE130,3467 +#define GENERATE_JSON(GENERATE_JSON134,3619 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/parser/extconf.rb,0 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/parser/parser.c,6242 +static const char digit_values[256] = { digit_values7,57 +static UTF32 unescape_unicode(const unsigned char *p)unescape_unicode24,1171 +static int convert_UTF32_to_UTF8(char *buf, UTF32 ch) convert_UTF32_to_UTF843,1699 +static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,CEncoding_ASCII_8BIT70,2485 +static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,CEncoding_UTF_870,2485 +static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,CEncoding_UTF_16BE70,2485 + CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;CEncoding_UTF_16LE71,2557 + CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;CEncoding_UTF_32BE71,2557 + CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;CEncoding_UTF_32LE71,2557 +static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_encoding72,2621 +static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_encode72,2621 +static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_encode_bang72,2621 +static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_force_encoding72,2621 +static ID i_iconv;i_iconv74,2692 +static VALUE mJSON, mExt, cParser, eParserError, eNestingError;mJSON77,2719 +static VALUE mJSON, mExt, cParser, eParserError, eNestingError;mExt77,2719 +static VALUE mJSON, mExt, cParser, eParserError, eNestingError;cParser77,2719 +static VALUE mJSON, mExt, cParser, eParserError, eNestingError;eParserError77,2719 +static VALUE mJSON, mExt, cParser, eParserError, eNestingError;eNestingError77,2719 +static VALUE CNaN, CInfinity, CMinusInfinity;CNaN78,2783 +static VALUE CNaN, CInfinity, CMinusInfinity;CInfinity78,2783 +static VALUE CNaN, CInfinity, CMinusInfinity;CMinusInfinity78,2783 +static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_json_creatable_p80,2830 +static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_json_create80,2830 +static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_create_id80,2830 +static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_create_additions80,2830 + i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_chr81,2908 + i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_max_nesting81,2908 + i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_allow_nan81,2908 + i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_symbolize_names81,2908 + i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_object_class81,2908 + i_array_class, i_key_p, i_deep_const_get;i_array_class82,2988 + i_array_class, i_key_p, i_deep_const_get;i_key_p82,2988 + i_array_class, i_key_p, i_deep_const_get;i_deep_const_get82,2988 +static const int JSON_object_start = 1;JSON_object_start90,3087 +static const int JSON_object_first_final = 27;JSON_object_first_final91,3127 +static const int JSON_object_error = 0;JSON_object_error92,3174 +static const int JSON_object_en_main = 1;JSON_object_en_main94,3215 +static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_object100,3283 +static const int JSON_value_start = 1;JSON_value_start458,9938 +static const int JSON_value_first_final = 21;JSON_value_first_final459,9977 +static const int JSON_value_error = 0;JSON_value_error460,10023 +static const int JSON_value_en_main = 1;JSON_value_en_main462,10063 +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_value468,10130 +static const int JSON_integer_start = 1;JSON_integer_start767,15654 +static const int JSON_integer_first_final = 5;JSON_integer_first_final768,15695 +static const int JSON_integer_error = 0;JSON_integer_error769,15742 +static const int JSON_integer_en_main = 1;JSON_integer_en_main771,15784 +static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_integer777,15853 +static const int JSON_float_start = 1;JSON_float_start863,17230 +static const int JSON_float_first_final = 10;JSON_float_first_final864,17269 +static const int JSON_float_error = 0;JSON_float_error865,17315 +static const int JSON_float_en_main = 1;JSON_float_en_main867,17355 +static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_float873,17422 +static const int JSON_array_start = 1;JSON_array_start1026,19956 +static const int JSON_array_first_final = 17;JSON_array_first_final1027,19995 +static const int JSON_array_error = 0;JSON_array_error1028,20041 +static const int JSON_array_en_main = 1;JSON_array_en_main1030,20081 +static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_array1036,20148 +static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)json_string_unescape1282,24592 +static const int JSON_string_start = 1;JSON_string_start1354,27107 +static const int JSON_string_first_final = 8;JSON_string_first_final1355,27147 +static const int JSON_string_error = 0;JSON_string_error1356,27193 +static const int JSON_string_en_main = 1;JSON_string_en_main1358,27234 +static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_string1364,27302 +static const int JSON_start = 1;JSON_start1512,29831 +static const int JSON_first_final = 10;JSON_first_final1513,29864 +static const int JSON_error = 0;JSON_error1514,29904 +static const int JSON_en_main = 1;JSON_en_main1516,29938 +static VALUE convert_encoding(VALUE source)convert_encoding1534,30232 +static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)cParser_initialize1608,33622 +static VALUE cParser_parse(VALUE self)cParser_parse1693,36573 +static JSON_Parser *JSON_allocate()JSON_allocate1854,39334 +static void JSON_mark(JSON_Parser *json)JSON_mark1861,39471 +static void JSON_free(JSON_Parser *json)JSON_free1869,39676 +static VALUE cJSON_parser_s_allocate(VALUE klass)cJSON_parser_s_allocate1874,39744 +static VALUE cParser_source(VALUE self)cParser_source1886,40029 +void Init_parser()Init_parser1892,40128 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/parser/parser.h,1278 +#define _PARSER_H__PARSER_H_2,19 +#define FORCE_UTF8(FORCE_UTF812,151 +#define FORCE_UTF8(FORCE_UTF814,225 +#define option_given_p(option_given_p17,257 +typedef unsigned long UTF32; /* at least 32 bits */UTF3221,348 +typedef unsigned short UTF16; /* at least 16 bits */UTF1622,400 +typedef unsigned char UTF8; /* typically 8 bits */UTF823,453 +#define UNI_REPLACEMENT_CHAR UNI_REPLACEMENT_CHAR25,507 +#define UNI_SUR_HIGH_START UNI_SUR_HIGH_START26,554 +#define UNI_SUR_HIGH_END UNI_SUR_HIGH_END27,596 +#define UNI_SUR_LOW_START UNI_SUR_LOW_START28,638 +#define UNI_SUR_LOW_END UNI_SUR_LOW_END29,680 +typedef struct JSON_ParserStruct {JSON_ParserStruct31,723 + VALUE Vsource;Vsource32,758 + char *source;source33,777 + long len;len34,795 + char *memo;memo35,809 + VALUE create_id;create_id36,825 + int max_nesting;max_nesting37,846 + int current_nesting;current_nesting38,867 + int allow_nan;allow_nan39,892 + int parsing_name;parsing_name40,911 + int symbolize_names;symbolize_names41,933 + VALUE object_class;object_class42,958 + VALUE array_class;array_class43,982 +} JSON_Parser;JSON_Parser44,1005 +#define GET_PARSER GET_PARSER46,1021 +#define MinusInfinity MinusInfinity50,1159 +#define EVIL EVIL51,1193 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/install.rb,0 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/add/core.rb,917 +class SymbolSymbol10,244 + def to_json(*a)to_json11,257 + def self.json_create(o)json_create18,366 +class TimeTime23,421 + def self.json_create(object)json_create24,432 + def to_json(*args)to_json35,701 +class DateDate44,884 + def self.json_create(object)json_create45,895 + def to_json(*args)to_json51,1032 +class DateTimeDateTime62,1210 + def self.json_create(object)json_create63,1225 + def to_json(*args)to_json77,1562 +class RangeRange92,1822 + def self.json_create(object)json_create93,1834 + def to_json(*args)to_json97,1894 +class StructStruct105,2047 + def self.json_create(object)json_create106,2060 + def to_json(*args)to_json110,2120 +class ExceptionException120,2348 + def self.json_create(object)json_create121,2364 + def to_json(*args)to_json127,2480 +class RegexpRegexp136,2628 + def self.json_create(object)json_create137,2641 + def to_json(*)to_json141,2713 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/add/rails.rb,238 +class ObjectObject9,223 + def self.json_create(object)json_create10,236 + def to_json(*a)to_json19,414 +class SymbolSymbol31,644 + def to_json(*a)to_json32,657 +module EnumerableEnumerable37,707 + def to_json(*a)to_json38,725 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/common.rb,1256 +module JSONJSON4,40 + def [](object, opts = {})[]12,403 + def parser=(parser) # :nodoc:parser=25,788 + def deep_const_get(path) # :nodoc:deep_const_get35,1220 + def generator=(generator) # :nodoc:generator=51,1665 + class JSONError < StandardError; endJSONError103,3324 + class ParserError < JSONError; endParserError106,3420 + class NestingError < ParserError; endNestingError110,3545 + class CircularDatastructure < NestingError; endCircularDatastructure113,3600 + class GeneratorError < JSONError; endGeneratorError117,3737 + class MissingUnicodeSupport < JSONError; endMissingUnicodeSupport123,3996 + def parse(source, opts = {})parse145,4940 + def parse!(source, opts = {})parse!164,5913 + def generate(obj, opts = nil)generate198,7559 + def fast_generate(obj, opts = nil)fast_generate225,8411 + def pretty_generate(obj, opts = nil)pretty_generate252,9261 + def load(source, proc = nil)load280,10231 + def recurse_proc(result, &proc)recurse_proc293,10566 + def dump(obj, anIO = nil, limit = nil)dump321,11448 + def self.iconv(to, from, string)iconv342,11932 + def j(*objs)j352,12137 + def jj(*objs)jj361,12378 + def JSON(object, *args)JSON374,12844 + def json_creatable?json_creatable?388,13269 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/editor.rb,4459 +module JSONJSON10,198 + module EditorEditor11,210 + def Editor.fetch_icon(name)fetch_icon39,1095 + def Editor.error_dialog(window, text)error_dialog50,1431 + def Editor.question_dialog(window, text)question_dialog69,2055 + def Editor.model2data(iter)model2data83,2516 + def Editor.data2model(data, model = nil, parent = nil)data2model121,3686 + class Gtk::TreeIterGtk156,4714 + def eacheach161,4855 + def recursive_each(&block)recursive_each167,5048 + def remove_subtree(model)remove_subtree176,5268 + def typetype183,5430 + def type=(value)type=189,5588 + def contentcontent195,5745 + def content=(value)content=200,5850 + module MenuExtensionMenuExtension207,6059 + def initialize(treeview)initialize212,6219 + def add_separatoradd_separator224,6507 + def add_item(label, keyval = nil, klass = MenuItem, &callback)add_item231,6786 + def createcreate250,7509 + def method_missing(*a, &b)method_missing254,7571 + class PopUpMenuPopUpMenu261,7748 + def change_node(item)change_node265,7854 + def cut_node(item)cut_node288,8690 + def copy_node(item)copy_node305,9232 + def paste_node_appending(item)paste_node_appending321,9755 + def paste_node_inserting_before(item)paste_node_inserting_before359,11113 + def append_new_node(item)append_new_node388,12209 + def insert_new_node(item)insert_new_node418,13291 + def collapse_expand(item)collapse_expand444,14293 + def createcreate457,14652 + class FileMenuFileMenu485,15739 + def new(item)new490,15901 + def open(item)open496,16080 + def open_location(item)open_location500,16137 + def revert(item)revert505,16284 + def save(item)save512,16448 + def save_as(item)save_as517,16570 + def quit(item)quit522,16706 + def createcreate527,16783 + class EditMenuEditMenu544,17325 + def copy(item)copy548,17426 + def paste(item)paste556,17710 + def find(item)find570,18098 + def find_again(item)find_again590,18612 + def sort(item)sort611,19174 + def createcreate645,20338 + class OptionsMenuOptionsMenu659,20737 + def collapsed_nodes(item)collapsed_nodes663,20834 + def pretty_saving(item)pretty_saving674,21072 + def createcreate682,21221 + class JSONTreeView < Gtk::TreeViewJSONTreeView696,21691 + def initialize(window)initialize701,21876 + def add_columnsadd_columns720,22355 + def unify_key(iter, key)unify_key742,22970 + def cell_edited(cell, path, value)cell_edited755,23362 + def configure_value(value, type)configure_value788,24298 + def add_popup_menuadd_popup_menu807,24804 + def create_node(parent, type, content)create_node817,25091 + def ask_for_hash_pair(parent)ask_for_hash_pair831,25530 + def ask_for_element(parent = nil, default_type = nil, value_text = @content)ask_for_element902,27935 + def ask_for_orderask_for_order964,30073 + def ask_for_find_term(search = nil)ask_for_find_term997,31126 + def expand_collapse(iter)expand_collapse1037,32489 + class MainWindow < Gtk::WindowMainWindow1047,32686 + def initialize(encoding)initialize1050,32740 + def create_menu_barcreate_menu_bar1099,34107 + def changechange1112,34569 + def unchangeunchange1119,34759 + def view_new_model(model)view_new_model1125,34906 + def display_status(text)display_status1133,35109 + def ask_saveask_save1141,35368 + def quitquit1153,35665 + def display_titledisplay_title1163,35887 + def clearclear1171,36129 + def check_pretty_printed(json)check_pretty_printed1177,36241 + def location_open(uri = nil)location_open1185,36564 + def file_open(filename = nil)file_open1195,36890 + def edit(json)edit1202,37145 + def file_savefile_save1211,37359 + def file_save_asfile_save_as1220,37538 + def store_file(path)store_file1226,37706 + def load_file(filename)load_file1247,38490 + def load_location(uri)load_location1264,38997 + def parse_json(json)parse_json1272,39198 + def read_data(filename)read_data1284,39657 + def select_file(message)select_file1296,40034 + def ask_for_locationask_for_location1320,40804 + def start(encoding = 'utf8') # :yield: windowstart1352,41786 + def edit(json, encoding = 'utf8')edit1362,42126 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/ext.rb,45 +module JSONJSON3,23 + module ExtExt6,138 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/pure/generator.rb,2275 +module JSONJSON1,0 + def utf8_to_json(string) # :nodoc:utf8_to_json42,979 + def utf8_to_json_ascii(string) # :nodoc:utf8_to_json_ascii51,1271 + def utf8_to_json(string) # :nodoc:utf8_to_json74,2209 + def utf8_to_json_ascii(string) # :nodoc:utf8_to_json_ascii78,2304 + module PurePure99,3064 + module GeneratorGenerator100,3078 + class StateState103,3246 + def self.from_state(opts)from_state108,3517 + def initialize(opts = {})initialize134,4730 + def check_max_nesting # :nodoc:check_max_nesting170,5922 + def check_circular?check_circular?179,6273 + def allow_nan?allow_nan?185,6456 + def ascii_only?ascii_only?189,6513 + def configure(opts)configure195,6663 + def to_hto_h216,7593 + def generate(obj)generate227,8040 + def [](name)[]236,8341 + module GeneratorMethodsGeneratorMethods241,8409 + module ObjectObject242,8439 + def to_json(*) to_s.to_json endto_json246,8680 + module HashHash249,8735 + def to_json(state = nil, *)to_json255,9080 + def json_shift(state)json_shift263,9266 + def json_transform(state)json_transform268,9400 + module ArrayArray294,10248 + def to_json(state = nil, *)to_json299,10516 + def json_transform(state)json_transform307,10702 + module IntegerInteger328,11358 + def to_json(*) to_s endto_json330,11455 + module FloatFloat333,11502 + def to_json(state = nil, *)to_json335,11595 + module StringString356,12142 + def to_json(state = nil, *args)to_json361,12377 + def to_json(state = nil, *args)to_json378,13032 + module ExtendExtend390,13438 + def json_create(o)json_create394,13645 + def self.included(modul)included400,13801 + def to_json_raw_objectto_json_raw_object408,14170 + def to_json_raw(*args)to_json_raw417,14468 + module TrueClassTrueClass422,14574 + def to_json(*) 'true' endto_json424,14651 + module FalseClassFalseClass427,14700 + def to_json(*) 'false' endto_json429,14780 + module NilClassNilClass432,14830 + def to_json(*) 'null' endto_json434,14905 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/pure/parser.rb,358 +module JSONJSON3,19 + module PurePure4,31 + class Parser < StringScannerParser7,159 + def initialize(source, opts = {})initialize71,3039 + def parseparse129,5496 + def parse_stringparse_string168,6496 + def parse_valueparse_value195,7339 + def parse_arrayparse_array230,8175 + def parse_objectparse_object262,9152 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/pure.rb,323 +module JSONJSON5,80 + def initialize(iconv) # :nodoc:initialize28,1119 + def iconv(string) # :nodoc:iconv32,1203 + def initialize(iconv) # :nodoc:initialize41,1495 + def iconv(string) # :nodoc:iconv45,1579 + def self.swap!(string) # :nodoc:swap60,2032 + module PurePure70,2339 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/version.rb,21 +module JSONJSON1,0 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json.rb,22 +module JSONJSON2,22 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json.rb,1963 + class ArrayArray16,313 + def permutationpermutation17,329 +class TC_JSON < Test::Unit::TestCaseTC_JSON26,498 + def setupsetup29,551 + def test_constructiontest_construction51,1142 + def assert_equal_float(expected, is)assert_equal_float56,1250 + def test_parse_simple_arraystest_parse_simple_arrays60,1348 + def test_parse_simple_objectstest_parse_simple_objects93,2866 + def test_parse_more_complex_arraystest_parse_more_complex_arrays112,3811 + def test_parse_complex_objectstest_parse_complex_objects120,4090 + def test_parse_arraystest_parse_arrays131,4469 + def test_parse_valuestest_parse_values137,4646 + def test_parse_arraytest_parse_array149,5026 + class SubArray < Array; endSubArray161,5491 + class SubArray2 < ArraySubArray2163,5522 + def to_json(*a)to_json164,5548 + def self.json_create(o)json_create171,5680 + def test_parse_array_custom_classtest_parse_array_custom_class177,5768 + def test_parse_objecttest_parse_object183,5923 + class SubHash < HashSubHash190,6158 + class SubHash2 < HashSubHash2193,6188 + def to_json(*a)to_json194,6212 + def self.json_create(o)json_create200,6324 + def test_parse_object_custom_classtest_parse_object_custom_class206,6411 + def test_generation_of_core_subclasses_with_new_to_jsontest_generation_of_core_subclasses_with_new_to_json212,6568 + def test_generation_of_core_subclasses_with_default_to_jsontest_generation_of_core_subclasses_with_default_to_json223,6949 + def test_generation_of_core_subclassestest_generation_of_core_subclasses228,7132 + def test_parser_resettest_parser_reset238,7431 + def test_commentstest_comments244,7569 + def test_backslashtest_backslash284,8521 + def test_wrong_inputstest_wrong_inputs310,9225 + def test_nestingtest_nesting328,10084 + def test_symbolize_namestest_symbolize_names359,11644 + def test_load_dumptest_load_dump366,11908 + def test_big_integerstest_big_integers382,12571 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_addition.rb,845 +class TC_JSONAddition < Test::Unit::TestCaseTC_JSONAddition13,230 + class AA16,291 + def initialize(a)initialize17,301 + def ==(other)==23,365 + def self.json_create(object)json_create27,415 + def to_json(*args)to_json31,484 + class BB39,628 + def self.json_creatable?json_creatable40,638 + def to_json(*args)to_json44,688 + class CC51,799 + def self.json_creatable?json_creatable52,809 + def to_json(*args)to_json56,859 + def test_extended_jsontest_extended_json63,977 + def test_extended_json_disabledtest_extended_json_disabled72,1175 + def test_extended_json_fail1test_extended_json_fail187,1633 + def test_extended_json_fail2test_extended_json_fail294,1813 + def test_raw_stringstest_raw_strings101,1983 + def test_coretest_core122,3500 + def test_utc_datetimetest_utc_datetime151,4475 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_encoding.rb,229 +class TC_JSONEncoding < Test::Unit::TestCaseTC_JSONEncoding12,208 + def setupsetup15,269 + def test_parsetest_parse43,1591 + def test_parse_ascii_8bittest_parse_ascii_8bit51,1852 + def test_generatetest_generate59,2179 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_fixtures.rb,171 +class TC_JSONFixtures < Test::Unit::TestCaseTC_JSONFixtures11,192 + def setupsetup12,237 + def test_passingtest_passing19,533 + def test_failingtest_failing26,677 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_generate.rb,507 +class TC_JSONGenerate < Test::Unit::TestCaseTC_JSONGenerate11,192 + def setupsetup14,253 + def test_generatetest_generate47,801 + def test_generate_prettytest_generate_pretty59,1160 + def test_fast_generatetest_fast_generate75,1568 + def test_statestest_states87,1947 + def test_pretty_statetest_pretty_state105,2434 + def test_safe_statetest_safe_state120,2845 + def test_fast_statetest_fast_state135,3245 + def test_allow_nantest_allow_nan150,3644 + def test_depthtest_depth168,4792 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_rails.rb,911 +class TC_JSONRails < Test::Unit::TestCaseTC_JSONRails13,232 + class AA16,290 + def initialize(a)initialize17,300 + def ==(other)==23,364 + def self.json_create(object)json_create27,414 + def to_json(*args)to_json31,483 + class BB39,627 + def self.json_creatable?json_creatable40,637 + def to_json(*args)to_json44,687 + class CC51,798 + def to_json(*args)to_json52,808 + class DD59,923 + def initializeinitialize60,933 + def ==(other)==66,1000 + def test_extended_jsontest_extended_json71,1056 + def test_extended_json_generic_objecttest_extended_json_generic_object82,1312 + def test_extended_json_disabledtest_extended_json_disabled93,1582 + def test_extended_json_fail1test_extended_json_fail1108,2037 + def test_extended_json_fail2test_extended_json_fail2115,2205 + def test_raw_stringstest_raw_strings122,2436 + def test_symboltest_symbol141,3897 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_unicode.rb,141 +class TC_JSONUnicode < Test::Unit::TestCaseTC_JSONUnicode11,192 + def test_unicodetest_unicode14,252 + def test_charstest_chars55,2176 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tools/fuzz.rb,357 + def to_utf8to_utf86,102 +class FuzzerFuzzer11,161 + def initialize(n, freqs = {})initialize12,174 + def random_stringrandom_string25,464 + def pickpick31,564 + def make_pickmake_pick37,671 + def fuzz(current = nil)fuzz53,959 +class MyState < JSON.stateMyState85,1551 + def initializeinitialize88,1596 + def make_spacesmake_spaces99,1875 + +tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tools/server.rb,159 +class JSONServlet < HTTPServlet::AbstractServletJSONServlet9,105 + def do_GET(req, res)do_GET12,169 +def create_server(err, dir, port)create_server33,648 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/design_rationale.rb,314 +class ThingySpec < MiniTest::SpecThingySpec29,1522 + def setupsetup30,1556 + def test_should_do_the_first_thingtest_should_do_the_first_thing35,1603 +class SubThingySpec < ThingySpecSubThingySpec40,1673 + def setupsetup41,1706 + def test_should_do_the_second_thingtest_should_do_the_second_thing49,1858 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/autorun.rb,0 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/mock.rb,242 +class MockExpectationError < StandardError; endMockExpectationError1,0 +module MiniTestMiniTest3,49 + class MockMock4,65 + def initializeinitialize5,78 + def expect(name, retval, args=[])expect10,183 + def verifyverify22,645 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/spec.rb,918 +class ModuleModule5,45 + def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:infect_an_assertion6,58 + def infect_with_assertions(pos_prefix, neg_prefix,infect_with_assertions25,768 +module KernelKernel52,1656 + def describe desc, &blockdescribe61,1903 +class ModuleModule78,2330 + def classes type = Object # :nodoc:classes79,2343 +class MiniTest::Spec < MiniTest::Unit::TestCaseMiniTest92,2614 + def self.describe_stack # :nodoc:describe_stack94,2700 + def self.current # :nodoc:current98,2764 + def initialize name # :nodoc:initialize102,2819 + def self.nuke_test_methods! # :nodoc:nuke_test_methods107,2894 + def self.define_inheritable_method name, &block # :nodoc:define_inheritable_method113,3048 + def self.before type = :each, &blockbefore129,3513 + def self.after type = :each, &blockafter141,3877 + def self.it desc, &blockit155,4451 +class ObjectObject183,5562 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/unit.rb,4004 +module MiniTestMiniTest6,78 + class Assertion < Exception; endAssertion11,126 + class Skip < Assertion; endSkip16,210 + def self.filter_backtrace bt # :nodoc:filter_backtrace33,872 + module AssertionsAssertions51,1305 + def mu_pp objmu_pp57,1482 + def _assertions= n # :nodoc:_assertions=63,1614 + def _assertions # :nodoc:_assertions67,1679 + def assert test, msg = nilassert74,1794 + def assert_block msg = nilassert_block87,2095 + def assert_empty obj, msg = nilassert_empty95,2269 + def assert_equal exp, act, msg = nilassert_equal106,2538 + def assert_in_delta exp, act, delta = 0.001, msg = nilassert_in_delta117,2856 + def assert_in_epsilon a, b, epsilon = 0.001, msg = nilassert_in_epsilon127,3174 + def assert_includes collection, obj, msg = nilassert_includes134,3352 + def assert_instance_of cls, obj, msg = nilassert_instance_of145,3658 + def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_ofassert_kind_of156,3922 + def assert_match exp, act, msg = nilassert_match166,4200 + def assert_nil obj, msg = nilassert_nil176,4502 + def assert_operator o1, op, o2, msg = nilassert_operator186,4735 + def assert_output stdout = nil, stderr = nilassert_output198,5131 + def assert_raises *expassert_raises212,5458 + def assert_respond_to obj, meth, msg = nilassert_respond_to244,6320 + def assert_same exp, act, msg = nilassert_same254,6581 + def assert_send send_ary, m = nilassert_send268,7006 + def assert_silentassert_silent280,7335 + def assert_throws sym, msg = nilassert_throws289,7470 + def capture_iocapture_io315,8137 + def exception_details e, msgexception_details333,8580 + def flunk msg = nilflunk340,8811 + def message msg = nil, &defaultmessage348,8979 + def pass msg = nilpass364,9306 + def refute test, msg = nilrefute371,9402 + def refute_empty obj, msg = nilrefute_empty379,9563 + def refute_equal exp, act, msg = nilrefute_equal390,9833 + def refute_in_delta exp, act, delta = 0.001, msg = nilrefute_in_delta402,10145 + def refute_in_epsilon a, b, epsilon = 0.001, msg = nilrefute_in_epsilon414,10476 + def refute_includes collection, obj, msg = nilrefute_includes421,10640 + def refute_instance_of cls, obj, msg = nilrefute_instance_of432,10946 + def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_ofrefute_kind_of442,11190 + def refute_match exp, act, msg = nilrefute_match450,11437 + def refute_nil obj, msg = nilrefute_nil460,11743 + def refute_operator o1, op, o2, msg = nilrefute_operator471,12025 + def refute_respond_to obj, meth, msg = nilrefute_respond_to481,12275 + def refute_same exp, act, msg = nilrefute_same490,12524 + def skip msg = nil, bt = callerskip502,12901 + class UnitUnit508,13030 + def self.autorunautorun521,13392 + def self.output= streamoutput534,13762 + def location e # :nodoc:location538,13820 + def puke klass, meth, epuke551,14198 + def initialize # :nodoc:initialize568,14767 + def process_args args = []process_args574,14886 + def run args = []run607,15661 + def status io = @@outstatus657,16772 + def run_test_suites filter = /./run_test_suites665,17009 + class TestCaseTestCase692,17914 + def run runnerrun703,18228 + def initialize name # :nodoc:initialize734,19079 + def self.reset # :nodoc:reset739,19173 + def self.inherited klass # :nodoc:inherited745,19255 + def self.test_ordertest_order754,19524 + def self.test_suites # :nodoc:test_suites758,19577 + def self.test_methods # :nodoc:test_methods762,19677 + def passed?passed?779,20135 + def setup; endsetup786,20264 + def teardown; endteardown791,20362 + module Test # :nodoc:Test799,20504 + module Unit # :nodoc:Unit800,20543 + class TestCase # :nodoc:TestCase801,20582 + def self.inherited x # :nodoc:inherited802,20621 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/test/test_mini_mock.rb,1083 +class TestMiniMock < MiniTest::Unit::TestCaseTestMiniMock6,73 + def setupsetup7,119 + def test_should_create_stub_methodtest_should_create_stub_method12,226 + def test_should_allow_return_value_specificationtest_should_allow_return_value_specification16,295 + def test_should_blow_up_if_not_calledtest_should_blow_up_if_not_called20,396 + def test_should_not_blow_up_if_everything_calledtest_should_not_blow_up_if_everything_called26,478 + def test_should_allow_expectations_to_be_added_after_creationtest_should_allow_expectations_to_be_added_after_creation33,601 + def test_should_not_verify_if_new_expected_method_is_not_calledtest_should_not_verify_if_new_expected_method_is_not_called38,722 + def test_should_not_verify_if_unexpected_method_is_calledtest_should_not_verify_if_unexpected_method_is_called46,885 + def test_should_blow_up_on_wrong_number_of_argumentstest_should_blow_up_on_wrong_number_of_arguments52,1018 + def test_should_blow_up_on_wrong_argumentstest_should_blow_up_on_wrong_arguments62,1214 + def util_verify_badutil_verify_bad72,1382 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/test/test_mini_spec.rb,105 +class TestMeta < MiniTest::Unit::TestCaseTestMeta198,5769 + def test_structuretest_structure199,5811 + +tmp/isolate/ruby-1.8/gems/minitest-1.7.2/test/test_mini_test.rb,9297 +module M; endM7,87 +class E < StandardError; include M; endE8,101 +class TestMiniTest < MiniTest::Unit::TestCaseTestMiniTest10,142 + def assert_report expected = nilassert_report23,881 + def setupsetup42,1467 + def teardownteardown51,1675 + def test_class_puke_with_assertion_failedtest_class_puke_with_assertion_failed56,1797 + def test_class_puke_with_assertion_failed_and_long_backtracetest_class_puke_with_assertion_failed_and_long_backtrace65,2167 + def test_class_puke_with_assertion_failed_and_user_defined_assertionstest_class_puke_with_assertion_failed_and_user_defined_assertions85,3046 + def test_class_puke_with_failure_and_flunk_in_backtracetest_class_puke_with_failure_and_flunk_in_backtrace108,4111 + def test_class_puke_with_flunk_and_user_defined_assertionstest_class_puke_with_flunk_and_user_defined_assertions118,4487 + def test_class_puke_with_non_failure_exceptiontest_class_puke_with_non_failure_exception141,5527 + def test_class_run_test_suitestest_class_run_test_suites148,5794 + def test_somethingtest_something150,5875 + def test_filter_backtracetest_filter_backtrace160,6029 + def test_filter_backtrace_all_unittest_filter_backtrace_all_unit180,6693 + def test_filter_backtrace_unit_startstest_filter_backtrace_unit_starts189,6951 + def test_run_errortest_run_error202,7265 + def test_somethingtest_something204,7334 + def test_errortest_error208,7390 + def test_run_error_teardowntest_run_error_teardown236,7837 + def test_somethingtest_something238,7915 + def teardownteardown242,7971 + def test_run_failing # TODO: add error testtest_run_failing270,8417 + def test_somethingtest_something272,8511 + def test_failuretest_failure276,8567 + def test_run_failing_filteredtest_run_failing_filtered303,8989 + def test_somethingtest_something305,9069 + def test_failuretest_failure309,9125 + def test_run_passingtest_run_passing332,9519 + def test_somethingtest_something334,9590 + def test_run_skiptest_run_skip346,9740 + def test_somethingtest_something348,9808 + def test_skiptest_skip352,9864 + def util_expand_bt btutil_expand_bt379,10254 +class TestMiniTestTestCase < MiniTest::Unit::TestCaseTestMiniTestTestCase388,10411 + def setupsetup389,10465 + def teardownteardown397,10621 + def test_asserttest_assert403,10890 + def test_assert__triggeredtest_assert__triggered409,11012 + def test_assert__triggered_messagetest_assert__triggered_message415,11146 + def test_assert_blocktest_assert_block421,11263 + def test_assert_block_triggeredtest_assert_block_triggered427,11337 + def test_assert_emptytest_assert_empty435,11504 + def test_assert_empty_triggeredtest_assert_empty_triggered441,11585 + def test_assert_equaltest_assert_equal449,11744 + def test_assert_equal_differenttest_assert_equal_different453,11801 + def test_assert_in_deltatest_assert_in_delta459,11928 + def test_assert_in_delta_triggeredtest_assert_in_delta_triggered463,12007 + def test_assert_in_epsilontest_assert_in_epsilon469,12188 + def test_assert_in_epsilon_triggeredtest_assert_in_epsilon_triggered483,12589 + def test_assert_includestest_assert_includes489,12755 + def test_assert_includes_triggeredtest_assert_includes_triggered495,12852 + def test_assert_instance_oftest_assert_instance_of506,13108 + def test_assert_instance_of_triggeredtest_assert_instance_of_triggered510,13187 + def test_assert_kind_oftest_assert_kind_of516,13372 + def test_assert_kind_of_triggeredtest_assert_kind_of_triggered520,13443 + def test_assert_matchtest_assert_match526,13615 + def test_assert_match_objecttest_assert_match_object531,13717 + def pattern.=~(other) true end=~535,13799 + def test_assert_match_object_triggeredtest_assert_match_object_triggered540,13874 + def pattern.=~(other) false end=~544,13966 + def pattern.inspect; "<>" endinspect545,14002 + def test_assert_match_triggeredtest_assert_match_triggered552,14157 + def test_assert_niltest_assert_nil559,14352 + def test_assert_nil_triggeredtest_assert_nil_triggered563,14404 + def test_assert_operatortest_assert_operator569,14529 + def test_assert_operator_triggeredtest_assert_operator_triggered573,14596 + def test_assert_output_bothtest_assert_output_both579,14736 + def test_assert_output_errtest_assert_output_err588,14891 + def test_assert_output_neithertest_assert_output_neither594,14999 + def test_assert_output_outtest_assert_output_out602,15117 + def test_assert_output_triggered_bothtest_assert_output_triggered_both608,15212 + def test_assert_output_triggered_errtest_assert_output_triggered_err617,15446 + def test_assert_output_triggered_outtest_assert_output_triggered_out625,15664 + def test_assert_raisestest_assert_raises633,15869 + def test_assert_raises_skiptest_assert_raises_skip645,16152 + def test_assert_raises_moduletest_assert_raises_module659,16418 + def test_assert_raises_triggered_differenttest_assert_raises_triggered_different665,16506 + def test_assert_raises_triggered_different_msgtest_assert_raises_triggered_different_msg685,17043 + def test_assert_raises_triggered_nonetest_assert_raises_triggered_none706,17599 + def test_assert_raises_triggered_none_msgtest_assert_raises_triggered_none_msg718,17886 + def test_assert_raises_triggered_subclasstest_assert_raises_triggered_subclass730,18189 + def test_assert_respond_totest_assert_respond_to750,18695 + def test_assert_respond_to_triggeredtest_assert_respond_to_triggered754,18773 + def test_assert_sametest_assert_same760,18948 + def test_assert_same_triggeredtest_assert_same_triggered769,19102 + def test_assert_sendtest_assert_send784,19442 + def test_assert_send_badtest_assert_send_bad788,19503 + def test_assert_silenttest_assert_silent794,19644 + def test_assert_silent_triggered_errtest_assert_silent_triggered_err802,19754 + def test_assert_silent_triggered_outtest_assert_silent_triggered_out812,19982 + def test_assert_throwstest_assert_throws820,20176 + def test_assert_throws_differenttest_assert_throws_different826,20266 + def test_assert_throws_unthrowntest_assert_throws_unthrown834,20466 + def test_capture_iotest_capture_io842,20647 + def test_class_asserts_match_refutestest_class_asserts_match_refutes858,20920 + def test_class_inheritedtest_class_inherited876,21639 + def test_class_test_suitestest_class_test_suites884,21837 + def test_flunktest_flunk893,22099 + def test_flunk_messagetest_flunk_message899,22189 + def test_messagetest_message905,22286 + def test_passtest_pass913,22543 + def test_refutetest_refute917,22579 + def test_refute_emptytest_refute_empty923,22704 + def test_refute_empty_triggeredtest_refute_empty_triggered929,22786 + def test_refute_equaltest_refute_equal937,22947 + def test_refute_equal_triggeredtest_refute_equal_triggered941,23013 + def test_refute_in_deltatest_refute_in_delta947,23174 + def test_refute_in_delta_triggeredtest_refute_in_delta_triggered951,23258 + def test_refute_in_epsilontest_refute_in_epsilon957,23434 + def test_refute_in_epsilon_triggeredtest_refute_in_epsilon_triggered961,23508 + def test_refute_includestest_refute_includes968,23688 + def test_refute_includes_triggeredtest_refute_includes_triggered974,23786 + def test_refute_instance_oftest_refute_instance_of985,24044 + def test_refute_instance_of_triggeredtest_refute_instance_of_triggered989,24122 + def test_refute_kind_oftest_refute_kind_of995,24301 + def test_refute_kind_of_triggeredtest_refute_kind_of_triggered999,24371 + def test_refute_matchtest_refute_match1005,24537 + def test_refute_match_objecttest_refute_match_object1010,24639 + def test_refute_match_object_triggeredtest_refute_match_object_triggered1015,24765 + def pattern.=~(other) true end=~1019,24857 + def pattern.inspect; "<>" endinspect1020,24892 + def test_refute_match_triggeredtest_refute_match_triggered1027,25051 + def test_refute_niltest_refute_nil1034,25250 + def test_refute_nil_triggeredtest_refute_nil_triggered1038,25301 + def test_refute_operatortest_refute_operator1044,25432 + def test_refute_operator_triggeredtest_refute_operator_triggered1048,25499 + def test_refute_respond_totest_refute_respond_to1054,25643 + def test_refute_respond_to_triggeredtest_refute_respond_to_triggered1058,25720 + def test_refute_sametest_refute_same1064,25891 + def test_refute_same_triggeredtest_refute_same_triggered1068,25946 + def test_skiptest_skip1074,26104 + def test_test_methods_randomtest_test_methods_random1082,26237 + def test_test1; assert "does not matter" endtest_test11086,26356 + def test_test2; assert "does not matter" endtest_test21087,26407 + def test_test3; assert "does not matter" endtest_test31088,26458 + def test_test_methods_sortedtest_test_methods_sorted1096,26647 + def self.test_order; :sorted endtest_order1100,26766 + def test_test3; assert "does not matter" endtest_test31101,26805 + def test_test2; assert "does not matter" endtest_test21102,26856 + def test_test1; assert "does not matter" endtest_test11103,26907 + def util_assert_triggered expected, klass = MiniTest::Assertionutil_assert_triggered1110,27083 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/bin/rake,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/example/a.c,16 +void a()a3,20 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/example/b.c,16 +void b()b3,20 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/example/main.c,22 +int main ()main6,55 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/jamis.rb,43 +module RDocRDoc1,0 +module PagePage2,12 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/install.rb,47 +def installBIN(from, opfile)installBIN17,389 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/alt_system.rb,296 +module Rake::AltSystemRake31,1229 + def define_module_function(name, &block)define_module_function35,1340 + def repair_command(cmd)repair_command50,1764 + def find_runnable(file)find_runnable70,2260 + def system(cmd, *args)system83,2510 + def backticks(cmd)backticks97,2827 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/classic_namespace.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/clean.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/compositepublisher.rb,166 +module RakeRake3,21 + class CompositePublisherCompositePublisher6,84 + def initializeinitialize7,111 + def add(pub)add12,206 + def uploadupload17,305 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/ftptools.rb,728 +module Rake # :nodoc:Rake11,165 + class FtpFileFtpFile15,316 + def self.datedate18,385 + def self.timetime22,439 + def initialize(path, entry)initialize26,493 + def pathpath33,696 + def directory?directory?37,748 + def modemode41,797 + def symlink?symlink?45,843 + def parse_mode(m)parse_mode51,962 + def determine_time(d1, d2, d3)determine_time59,1107 + class FtpUploaderFtpUploader87,1990 + def connect(path, host, account, password)connect95,2235 + def initialize(path, host, account, password)initialize108,2604 + def makedirs(path)makedirs117,2866 + def upload_files(wildcard)upload_files132,3298 + def closeclose139,3430 + def upload(file)upload146,3598 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/publisher.rb,529 +class CompositePublisherCompositePublisher20,757 + def initializeinitialize21,782 + def add(pub)add26,865 + def uploadupload31,952 +class SshDirPublisherSshDirPublisher38,1089 + def initialize(host, remote_dir, local_dir)initialize39,1111 + def uploadupload45,1237 +class SshFreshDirPublisher < SshDirPublisherSshFreshDirPublisher51,1389 + def uploadupload52,1434 +class SshFilePublisherSshFilePublisher60,1629 + def initialize(host, remote_dir, local_dir, *files)initialize62,1708 + def uploadupload70,1917 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/rubyforgepublisher.rb,144 +module RakeRake5,58 + class RubyForgePublisher < SshDirPublisherRubyForgePublisher7,71 + def initialize(projname, user)initialize10,163 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/sshpublisher.rb,420 +module RakeRake5,64 + class SshDirPublisherSshDirPublisher9,156 + def initialize(host, remote_dir, local_dir)initialize10,180 + def uploadupload16,320 + class SshFreshDirPublisher < SshDirPublisherSshFreshDirPublisher22,483 + def uploadupload23,530 + class SshFilePublisherSshFilePublisher31,739 + def initialize(host, remote_dir, local_dir, *files)initialize33,822 + def uploadupload41,1049 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/sys.rb,924 +module SysSys42,1738 + def install(wildcard, dest_dir, mode)install47,1915 + def run(cmd)run54,2084 + def ruby(*args)ruby60,2222 + def copy(file_name, dest_file)copy65,2341 + def copy_files(wildcard, dest_dir)copy_files71,2539 + def link(file_name, dest_file)link76,2693 + def link_files(wildcard, dest_dir)link_files82,2891 + def symlink(file_name, dest_file)symlink87,3048 + def symlink_files(wildcard, dest_dir)symlink_files93,3258 + def delete(*wildcards)delete100,3550 + def delete_all(*wildcards)delete_all115,3920 + def makedirs(*dirs)makedirs135,4431 + def indir(dir)indir144,4645 + def split_all(path)split_all156,4871 + def log(msg)log164,5117 + def quiet(&block)quiet170,5245 + def verbose(&block)verbose175,5347 + def for_files(*wildcards)for_files180,5471 + def for_matching_files(wildcard, dest_dir)for_matching_files192,5696 + def with_verbose(v)with_verbose201,5947 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/gempackagetask.rb,227 +module RakeRake12,223 + class GemPackageTask < PackageTaskGemPackageTask47,1326 + def initialize(gem_spec)initialize56,1775 + def init(gem)init64,1976 + def definedefine73,2269 + def gem_filegem_file88,2705 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/loaders/makefile.rb,177 +module RakeRake3,21 + class MakefileLoaderMakefileLoader6,94 + def load(fn)load10,194 + def process_line(line)process_line25,531 + def respace(str)respace35,826 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/packagetask.rb,453 +module RakeRake9,155 + class PackageTask < TaskLibPackageTask46,1420 + def initialize(name=nil, version=nil)initialize78,2469 + def init(name, version)init85,2680 + def definedefine99,3040 + def package_namepackage_name159,4719 + def package_dir_pathpackage_dir_path163,4803 + def tgz_filetgz_file167,4876 + def tar_gz_filetar_gz_file171,4930 + def tar_bz2_filetar_bz2_file175,4990 + def zip_filezip_file179,5052 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/rdoctask.rb,542 +module RakeRake6,60 + class RDocTask < TaskLibRDocTask59,1875 + def initialize(name = :rdoc) # :yield: selfinitialize89,2857 + def definedefine111,3514 + def option_listoption_list146,4509 + def quote(str)quote156,4884 + def option_stringoption_string164,4983 + def before_running_rdoc(&block)before_running_rdoc171,5213 + def rdoc_targetrdoc_target177,5310 + def rdoc_task_namerdoc_task_name181,5374 + def clobber_task_nameclobber_task_name190,5518 + def rerdoc_task_namererdoc_task_name199,5689 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/ruby182_test_unit_fix.rb,181 +module TestTest1,0 + module UnitUnit2,12 + module CollectorCollector3,26 + class DirDir4,47 + def collect_file(name, suites, already_gathered)collect_file6,90 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/runtest.rb,98 +module RakeRake6,73 + def run_tests(pattern='test/test*.rb', log_enabled=false)run_tests9,119 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/tasklib.rb,106 +module RakeRake5,37 + class TaskLibTaskLib8,85 + def paste(a,b) # :nodoc:paste18,487 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/testtask.rb,428 +module RakeRake8,109 + class TestTask < TaskLibTestTask37,1076 + def test_files=(list)test_files=76,2447 + def initialize(name=:test)initialize81,2536 + def definedefine97,2938 + def option_list # :nodoc:option_list123,3696 + def file_list # :nodoc:file_list127,3775 + def fix # :nodoc:fix138,4037 + def rake_loader # :nodoc:rake_loader147,4197 + def find_file(fn) # :nodoc:find_file152,4327 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/win32.rb,296 +module RakeRake2,1 + module Win32Win327,175 + class Win32HomeError < RuntimeErrorWin32HomeError11,284 + def windows?windows?16,400 + def rake_system(*cmd)rake_system21,496 + def win32_system_dir #:nodoc:win32_system_dir35,880 + def normalize(path)normalize49,1492 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake.rb,10453 +class ModuleModule48,1655 + def rake_extension(method)rake_extension64,2069 +class StringString77,2407 + def ext(newext='')ext84,2739 + def pathmap_explodepathmap_explode95,3068 + def pathmap_partial(n)pathmap_partial107,3558 + def pathmap_replace(patterns, &block)pathmap_replace123,3994 + def pathmap(spec=nil, &block)pathmap200,6932 +module RakeRake240,8102 + class TaskArgumentError < ArgumentErrorTaskArgumentError245,8240 + class RuleRecursionOverflowError < StandardErrorRuleRecursionOverflowError249,8356 + def initialize(*args)initialize250,8407 + def add_target(target)add_target255,8474 + def messagemessage259,8535 + def applicationapplication269,8789 + def application=(app)application=274,8910 + def original_diroriginal_dir279,9046 + module CloneableCloneable288,9235 + def dupdup291,9364 + def cloneclone302,9661 + class PseudoStatusPseudoStatus311,9891 + def initialize(code=0)initialize313,9940 + def to_ito_i316,10000 + def >>(n)>>319,10044 + def stopped?stopped?322,10082 + def exited?exited?325,10119 + class TaskArgumentsTaskArguments333,10292 + def initialize(names, values, parent=nil)initialize341,10549 + def new_scope(names)new_scope352,10853 + def [](index)[]358,11021 + def with_defaults(defaults)with_defaults365,11222 + def each(&block)each369,11299 + def method_missing(sym, *args, &block)method_missing373,11354 + def to_hashto_hash377,11431 + def to_sto_s381,11468 + def inspectinspect385,11510 + def lookup(name)lookup391,11569 + class InvocationChainInvocationChain409,12058 + def initialize(value, tail)initialize410,12082 + def member?(obj)member?415,12163 + def append(value)append419,12235 + def to_sto_s426,12413 + def self.append(value, chain)append430,12462 + def prefixprefix436,12544 + class EmptyInvocationChainEmptyInvocationChain440,12594 + def member?(obj)member?441,12625 + def append(value)append444,12672 + def to_sto_s447,12747 +module RakeRake458,12883 + class TaskTask469,13397 + def to_sto_s490,13945 + def inspectinspect494,13978 + def sourcessources500,14125 + def sourcesource505,14223 + def initialize(task_name, app)initialize511,14416 + def enhance(deps=nil, &block)enhance525,14787 + def namename532,14978 + def name_with_args # :nodoc:name_with_args537,15068 + def arg_description # :nodoc:arg_description546,15247 + def arg_namesarg_names551,15389 + def reenablereenable557,15534 + def clearclear562,15658 + def clear_prerequisitesclear_prerequisites569,15793 + def clear_actionsclear_actions575,15916 + def invoke(*args)invoke581,16049 + def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:invoke_with_call_chain588,16291 + def invoke_prerequisites(task_args, invocation_chain) # :nodoc:invoke_prerequisites603,16818 + def format_trace_flagsformat_trace_flags612,17146 + def execute(args=nil)execute621,17434 + def needed?needed?642,17939 + def timestamptimestamp648,18111 + def add_description(description)add_description654,18360 + def comment=(description)comment=661,18604 + def add_comment(comment)add_comment667,18783 + def set_arg_names(args)set_arg_names684,19225 + def investigationinvestigation690,19399 + def clearclear715,20390 + def taskstasks720,20483 + def [](task_name)[]728,20817 + def task_defined?(task_name)task_defined?733,20938 + def define_task(*args, &block)define_task740,21242 + def create_rule(*args, &block)create_rule745,21394 + def scope_name(scope, task_name)scope_name752,21655 + class FileTask < TaskFileTask766,22129 + def needed?needed?770,22255 + def timestamptimestamp775,22365 + def out_of_date?(stamp)out_of_date?786,22582 + def scope_name(scope, task_name)scope_name796,22960 + class FileCreationTask < FileTaskFileCreationTask808,23446 + def needed?needed?810,23540 + def timestamptimestamp816,23693 + class MultiTask < TaskMultiTask825,23931 + def invoke_prerequisites(args, invocation_chain)invoke_prerequisites827,23968 +def task(*args, &block)task846,24444 +def file(*args, &block)file864,24795 +def file_create(args, &block)file_create870,24943 +def directory(dir)directory879,25147 +def multitask(args, &block)multitask894,25555 +def namespace(name=nil, &block)namespace909,25923 +def rule(*args, &block)rule920,26128 +def desc(description)desc932,26323 +def import(*fns)import949,26879 +module FileUtilsFileUtils959,27162 + def sh(*cmd, &block)sh988,27954 + def rake_system(*cmd)rake_system1014,28842 + def ruby(*args,&block)ruby1024,29042 + def safe_ln(*args)safe_ln1037,29380 + def split_all(path)split_all1055,29733 +module RakeFileUtilsRakeFileUtils1067,30140 + def verbose(value=nil)verbose1107,31435 + def nowrite(value=nil)nowrite1128,32195 + def when_writing(msg=nil)when_writing1155,32899 + def rake_merge_option(args, defaults)rake_merge_option1164,33085 + def rake_output_message(message)rake_output_message1175,33343 + def rake_check_options(options, *optdecl)rake_check_options1182,33594 +module RakeRake1204,34284 + class FileListFileList1220,35051 + def initialize(*patterns)initialize1295,37711 + def include(*filenames)include1313,38270 + def exclude(*patterns, &block)exclude1347,39421 + def clear_excludeclear_exclude1360,39714 + def ==(array)==1368,39879 + def to_ato_a1373,39968 + def to_aryto_ary1379,40057 + def is_a?(klass)is_a?1384,40119 + def *(other)*1390,40274 + def resolveresolve1401,40477 + def calculate_exclude_regexpcalculate_exclude_regexp1411,40670 + def resolve_add(fn)resolve_add1431,41156 + def resolve_excluderesolve_exclude1441,41317 + def sub(pat, rep)sub1454,41662 + def gsub(pat, rep)gsub1465,41996 + def sub!(pat, rep)sub!1470,42160 + def gsub!(pat, rep)gsub!1476,42332 + def pathmap(spec=nil)pathmap1484,42600 + def ext(newext='')ext1496,42940 + def egrep(pattern, *options)egrep1506,43338 + def existingexisting1526,43874 + def existing!existing!1532,44045 + def partition(&block) # :nodoc:partition1540,44265 + def to_sto_s1550,44541 + def add_matching(pattern)add_matching1556,44632 + def exclude?(fn)exclude?1564,44824 + def import(array)import1580,45261 + def [](*args)[]1589,45451 +module RakeRake1596,45530 + def each_dir_parent(dir) # :nodoc:each_dir_parent1600,45605 +module RakeRake1615,46003 + class DefaultLoaderDefaultLoader1618,46062 + def load(fn)load1619,46084 + class EarlyTimeEarlyTime1625,46233 + def <=>(other)<=>1629,46297 + def to_sto_s1633,46334 +class TimeTime1644,46579 + def <=>(other)<=>1646,46630 +module RakeRake1655,46785 + class NameSpaceNameSpace1661,46975 + def initialize(task_manager, scope_list)initialize1665,47092 + def [](name)[]1671,47262 + def taskstasks1676,47399 + module TaskManagerTaskManager1684,47613 + def initializeinitialize1689,47793 + def create_rule(*args, &block)create_rule1697,47937 + def define_task(task_class, *args, &block)define_task1703,48150 + def intern(task_class, task_name)intern1718,48742 + def [](task_name, scopes=nil)[]1723,48898 + def synthesize_file_task(task_name)synthesize_file_task1731,49165 + def resolve_args(args)resolve_args1738,49422 + def resolve_args_without_dependencies(args)resolve_args_without_dependencies1756,49904 + def resolve_args_with_dependencies(args, hash) # :nodoc:resolve_args_with_dependencies1777,50573 + def enhance_with_matching_rule(task_name, level=0)enhance_with_matching_rule1802,51433 + def taskstasks1818,51959 + def tasks_in_scope(scope)tasks_in_scope1824,52108 + def clearclear1832,52286 + def lookup(task_name, initial_scope=nil)lookup1842,52677 + def lookup_in_scope(name, scope)lookup_in_scope1858,53160 + def current_scopecurrent_scope1872,53490 + def in_namespace(name)in_namespace1878,53654 + def generate_namegenerate_name1891,53892 + def trace_rule(level, message)trace_rule1897,53981 + def attempt_rule(task_name, extensions, block, level)attempt_rule1902,54168 + def make_sources(task_name, extensions)make_sources1924,55032 + class ApplicationApplication1953,55770 + def initializeinitialize1971,56283 + def runrun1997,57168 + def init(app_name='rake')init2006,57348 + def load_rakefileload_rakefile2015,57570 + def top_leveltop_level2022,57727 + def add_loader(ext, loader)add_loader2036,58111 + def optionsoptions2042,58271 + def invoke_task(task_string)invoke_task2048,58410 + def parse_task_string(string)parse_task_string2054,58545 + def standard_exception_handlingstandard_exception_handling2066,58826 + def have_rakefilehave_rakefile2091,59616 + def tty_output?tty_output?2104,59948 + def tty_output=( tty_output_state )tty_output=2109,60061 + def truncate_output?truncate_output?2115,60270 + def display_tasks_and_commentsdisplay_tasks_and_comments2120,60383 + def terminal_widthterminal_width2142,61153 + def dynamic_widthdynamic_width2154,61417 + def dynamic_width_sttydynamic_width_stty2158,61525 + def dynamic_width_tputdynamic_width_tput2162,61607 + def unix?unix?2166,61680 + def windows?windows?2170,61796 + def truncate(string, width)truncate2174,61843 + def display_prerequisitesdisplay_prerequisites2183,62039 + def standard_rake_optionsstandard_rake_options2192,62301 + def handle_optionshandle_options2310,66561 + def rake_require(file_name, paths=$LOAD_PATH, loaded=$")rake_require2339,67468 + def find_rakefile_locationfind_rakefile_location2353,67861 + def raw_load_rakefile # :nodoc:raw_load_rakefile2367,68157 + def glob(path, &block)glob2393,69050 + def system_dirsystem_dir2399,69212 + def standard_system_dir #:nodoc:standard_system_dir2412,69502 + def standard_system_dir #:nodoc:standard_system_dir2416,69591 + def collect_taskscollect_tasks2425,69931 + def add_import(fn)add_import2438,70282 + def load_importsload_imports2443,70390 + def const_warning(const_name)const_warning2457,70767 + def rakefile_locationrakefile_location2468,71194 +class ModuleModule2479,71370 + def const_missing(const_name)const_missing2488,71803 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/capture_stdout.rb,125 +module CaptureStdoutCaptureStdout6,81 + def capture_stdoutcapture_stdout7,102 + def capture_stderrcapture_stderr17,247 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/check_expansion.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/check_no_expansion.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/contrib/test_sys.rb,93 +class TestSys < Test::Unit::TestCaseTestSys7,97 + def test_split_alltest_split_all39,934 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/data/rakelib/test1.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/data/rbext/rakefile.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/filecreation.rb,237 +module FileCreationFileCreation3,21 + def create_timed_files(oldfile, *newfiles)create_timed_files7,96 + def create_dir(dirname)create_dir18,424 + def create_file(name)create_file23,545 + def delete_file(name)delete_file29,688 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/functional.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/in_environment.rb,148 +module InEnvironmentInEnvironment1,0 + def in_environment(settings)in_environment6,172 + def set_env(settings) # :nodoc:set_env14,362 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/rake_test_setup.rb,147 + class Test::Unit::TestCaseTest13,175 +module TestMethodsTestMethods20,253 + def assert_exception(ex, msg=nil, &block)assert_exception21,272 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/reqfile.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/reqfile2.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/session_functional.rb,3026 +module SessionSession16,359 + class AbstractSessionAbstractSession17,374 + def initialize(*args)initialize19,434 +class FunctionalTest < Test::Unit::TestCaseFunctionalTest26,526 + def setupsetup32,642 + def test_rake_defaulttest_rake_default46,1049 + def test_rake_error_on_bad_tasktest_rake_error_on_bad_task52,1181 + def test_env_availabe_at_top_scopetest_env_availabe_at_top_scope58,1335 + def test_env_availabe_at_task_scopetest_env_availabe_at_task_scope64,1498 + def test_multi_desctest_multi_desc70,1675 + def test_long_descriptiontest_long_description83,2008 + def test_rbexttest_rbext93,2308 + def test_systemtest_system100,2438 + def test_system_excludes_rakelib_files_tootest_system_excludes_rakelib_files_too107,2584 + def test_by_default_rakelib_files_are_includetest_by_default_rakelib_files_are_include114,2781 + def test_implicit_systemtest_implicit_system121,2964 + def test_no_systemtest_no_system128,3156 + def test_nosearch_with_rakefile_uses_local_rakefiletest_nosearch_with_rakefile_uses_local_rakefile135,3345 + def test_nosearch_without_rakefile_finds_systemtest_nosearch_without_rakefile_finds_system142,3526 + def test_nosearch_without_rakefile_and_no_system_failstest_nosearch_without_rakefile_and_no_system_fails152,3781 + def test_dry_runtest_dry_run159,4006 + def test_dry_run_bugtest_dry_run_bug168,4348 + def test_trace_bugtest_trace_bug181,4696 + def test_importstest_imports193,4981 + def test_rules_chaining_to_file_tasktest_rules_chaining_to_file_task209,5508 + def test_file_creation_tasktest_file_creation_task220,5784 + def test_dash_f_with_no_arg_foils_rakefile_lookuptest_dash_f_with_no_arg_foils_rakefile_lookup229,6000 + def test_dot_rake_files_can_be_loaded_with_dash_rtest_dot_rake_files_can_be_loaded_with_dash_r234,6136 + def test_can_invoke_task_in_toplevel_namespacetest_can_invoke_task_in_toplevel_namespace239,6272 + def test_can_invoke_task_in_nested_namespacetest_can_invoke_task_in_nested_namespace246,6441 + def test_tasks_can_reference_task_in_same_namespacetest_tasks_can_reference_task_in_same_namespace253,6620 + def test_tasks_can_reference_task_in_other_namespacestest_tasks_can_reference_task_in_other_namespaces260,6805 + def test_anonymous_tasks_can_be_invoked_indirectlytest_anonymous_tasks_can_be_invoked_indirectly267,6991 + def test_rake_namespace_refers_to_topleveltest_rake_namespace_refers_to_toplevel274,7172 + def test_file_task_are_not_scoped_by_namespacestest_file_task_are_not_scoped_by_namespaces281,7351 + def test_rake_returns_status_error_valuestest_rake_returns_status_error_values288,7534 + def test_rake_returns_no_status_error_on_normal_exittest_rake_returns_no_status_error_on_normal_exit295,7692 + def remove_chaining_filesremove_chaining_files304,7873 + def format_commandformat_command311,8032 + def format_command=(fmt_command)format_command=317,8201 + def rake(*option_list)rake322,8291 + def assert_status(expected_status=0)assert_status336,8772 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/shellcommand.rb,0 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_application.rb,4739 +class TestApplication < Test::Unit::TestCaseTestApplication18,307 + def setupsetup23,423 + def test_constant_warningtest_constant_warning28,505 + def test_display_taskstest_display_tasks35,719 + def test_display_tasks_with_long_commentstest_display_tasks_with_long_comments44,1017 + def test_display_tasks_with_task_name_wider_than_tty_displaytest_display_tasks_with_task_name_wider_than_tty_display55,1471 + def test_display_tasks_with_very_long_task_name_to_a_non_tty_shows_name_and_commenttest_display_tasks_with_very_long_task_name_to_a_non_tty_shows_name_and_comment68,2024 + def test_display_tasks_with_long_comments_to_a_non_tty_shows_entire_commenttest_display_tasks_with_long_comments_to_a_non_tty_shows_entire_comment80,2569 + def test_display_tasks_with_long_comments_to_a_non_tty_with_columns_set_truncates_commentstest_display_tasks_with_long_comments_to_a_non_tty_with_columns_set_truncates_comments90,2972 + def test_display_tasks_with_full_descriptionstest_display_tasks_with_full_descriptions102,3505 + def test_finding_rakefiletest_finding_rakefile112,3872 + def test_not_finding_rakefiletest_not_finding_rakefile116,3975 + def test_load_rakefiletest_load_rakefile122,4155 + def test_load_rakefile_from_subdirtest_load_rakefile_from_subdir134,4459 + def test_load_rakefile_not_foundtest_load_rakefile_not_found146,4781 + def test_load_from_system_rakefiletest_load_from_system_rakefile159,5150 + def test_windowstest_windows174,5550 + def test_loading_importstest_loading_imports178,5619 + def test_building_imported_files_on_demandtest_building_imported_files_on_demand188,5848 + def test_handle_options_should_strip_options_from_ARGVtest_handle_options_should_strip_options_from_ARGV200,6219 + def test_good_runtest_good_run213,6480 + def test_display_task_runtest_display_task_run227,6779 + def test_display_prereqstest_display_prereqs240,7146 + def test_bad_runtest_bad_run257,7668 + def test_bad_run_with_tracetest_bad_run_with_trace269,7956 + def test_run_with_bad_optionstest_run_with_bad_options281,8266 +class TestApplicationOptions < Test::Unit::TestCaseTestApplicationOptions295,8614 + def setupsetup299,8713 + def teardownteardown306,8851 + def clear_argvclear_argv312,8968 + def test_default_optionstest_default_options318,9039 + def test_dry_runtest_dry_run337,9615 + def test_describetest_describe346,9817 + def test_describe_with_patterntest_describe_with_pattern354,10007 + def test_executetest_execute362,10213 + def test_execute_and_continuetest_execute_and_continue371,10397 + def test_execute_and_printtest_execute_and_print380,10607 + def test_helptest_help390,10857 + def test_libdirtest_libdir400,11109 + def test_rakefiletest_rakefile408,11259 + def test_rakelibtest_rakelib414,11440 + def test_requiretest_require420,11624 + def test_missing_requiretest_missing_require429,11905 + def test_prereqstest_prereqs438,12141 + def test_quiettest_quiet444,12245 + def test_no_searchtest_no_search451,12383 + def test_silenttest_silent457,12501 + def test_systemtest_system464,12639 + def test_no_systemtest_no_system470,12740 + def test_tracetest_trace476,12849 + def test_trace_rulestest_trace_rules484,13024 + def test_taskstest_tasks490,13123 + def test_verbosetest_verbose501,13416 + def test_versiontest_version508,13556 + def test_classic_namespacetest_classic_namespace516,13750 + def test_bad_optiontest_bad_option527,14131 + def test_task_collectiontest_task_collection541,14582 + def test_default_task_collectiontest_default_task_collection546,14686 + def test_environment_definitiontest_environment_definition551,14786 + def flags(*sets)flags560,14969 + def command_line(*options)command_line570,15190 +class TestTaskArgumentParsing < Test::Unit::TestCaseTestTaskArgumentParsing585,15496 + def setupsetup586,15549 + def test_name_onlytest_name_only590,15603 + def test_empty_argstest_empty_args596,15737 + def test_one_argumenttest_one_argument602,15874 + def test_two_argumentstest_two_arguments608,16021 + def test_can_handle_spaces_between_argstest_can_handle_spaces_between_args614,16180 + def test_keeps_embedded_spacestest_keeps_embedded_spaces620,16389 +class TestTaskArgumentParsing < Test::Unit::TestCaseTestTaskArgumentParsing628,16572 + def test_terminal_width_using_envtest_terminal_width_using_env631,16650 + def test_terminal_width_using_sttytest_terminal_width_using_stty638,16825 + def test_terminal_width_using_tputtest_terminal_width_using_tput649,17105 + def test_terminal_width_using_hardcoded_80test_terminal_width_using_hardcoded_80660,17385 + def test_terminal_width_with_failuretest_terminal_width_with_failure668,17599 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_clean.rb,88 +class TestClean < Test::Unit::TestCaseTestClean6,63 + def test_cleantest_clean8,117 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_definitions.rb,490 +class TestDefinitions < Test::Unit::TestCaseTestDefinitions10,207 + def setupsetup16,330 + def test_tasktest_task20,364 + def test_file_tasktest_file_task29,563 + def check_tasks(n1, n2, n3)check_tasks38,855 + def test_incremental_definitionstest_incremental_definitions50,1216 + def test_missing_dependenciestest_missing_dependencies62,1524 + def test_implicit_file_dependenciestest_implicit_file_dependencies67,1654 + def create_existing_filecreate_existing_file77,1915 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_earlytime.rb,273 +class TestEarlyTime < Test::Unit::TestCaseTestEarlyTime6,57 + def test_createtest_create7,100 + def test_equalitytest_equality18,378 + def test_original_time_compare_is_not_messed_uptest_original_time_compare_is_not_messed_up23,507 + def test_to_stest_to_s32,706 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_extension.rb,597 +class TestExtension < Test::Unit::TestCaseTestExtension8,147 + module RedirectRedirect10,191 + def error_redirecterror_redirect11,209 + class SampleSample22,384 + def duplicate_methodduplicate_method25,420 + def ok_methodok_method31,535 + def duplicate_methodduplicate_method39,666 + def test_methods_actually_existtest_methods_actually_exist46,752 + def test_no_warning_when_defining_ok_methodtest_no_warning_when_defining_ok_method52,866 + def test_extension_complains_when_a_method_that_is_presenttest_extension_complains_when_a_method_that_is_present56,963 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_file_creation_task.rb,456 +class TestFileCreationTask < Test::Unit::TestCaseTestFileCreationTask9,176 + def setupsetup15,301 + def teardownteardown19,335 + def test_file_neededtest_file_needed23,387 + def test_directorytest_directory34,768 + def test_no_retriggers_on_filecreate_tasktest_no_retriggers_on_filecreate_task41,931 + def test_no_retriggers_on_file_tasktest_no_retriggers_on_file_task49,1301 + def test_very_early_timestamptest_very_early_timestamp57,1665 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_file_task.rb,813 +class TestFileTask < Test::Unit::TestCaseTestFileTask10,207 + def setupsetup15,310 + def test_file_needtest_file_need22,420 + def test_file_times_new_depends_on_oldtest_file_times_new_depends_on_old35,859 + def test_file_times_old_depends_on_newtest_file_times_old_depends_on_new44,1211 + def test_file_depends_on_task_depend_on_filetest_file_depends_on_task_depend_on_file56,1726 + def test_existing_file_depends_on_non_existing_filetest_existing_file_depends_on_non_existing_file68,2069 + def ztest_file_deletes_on_failureztest_file_deletes_on_failure79,2464 +class TestDirectoryTask < Test::Unit::TestCaseTestDirectoryTask96,2845 + def setupsetup99,2908 + def teardownteardown103,2965 + def test_directorytest_directory107,3025 + def test_directory_win32test_directory_win32124,3617 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_filelist.rb,3743 +class TestFileList < Test::Unit::TestCaseTestFileList9,119 + def setupsetup14,236 + def teardownteardown18,276 + def test_delgating_methods_do_not_include_to_a_or_to_arytest_delgating_methods_do_not_include_to_a_or_to_ary23,375 + def test_createtest_create30,791 + def test_create_with_argstest_create_with_args35,866 + def test_create_with_blocktest_create_with_block41,1039 + def test_create_with_bracketstest_create_with_brackets46,1155 + def test_create_with_brackets_and_filelisttest_create_with_brackets_and_filelist52,1328 + def test_include_with_another_arraytest_include_with_another_array58,1524 + def test_include_with_another_filelisttest_include_with_another_filelist63,1663 + def test_appendtest_append69,1867 + def test_add_manytest_add_many75,1979 + def test_add_returntest_add_return83,2180 + def test_matchtest_match91,2356 + def test_add_matchingtest_add_matching99,2552 + def test_multiple_patternstest_multiple_patterns108,2756 + def test_square_bracket_patterntest_square_bracket_pattern119,3058 + def test_curly_bracket_patterntest_curly_bracket_pattern127,3263 + def test_rejecttest_reject135,3468 + def test_excludetest_exclude144,3705 + def test_excluding_via_blocktest_excluding_via_block157,4187 + def test_exclude_return_on_createtest_exclude_return_on_create164,4453 + def test_exclude_with_string_return_on_createtest_exclude_with_string_return_on_create170,4658 + def test_default_excludetest_default_exclude176,4934 + def test_uniquetest_unique184,5189 + def test_to_stringtest_to_string192,5388 + def test_to_arraytest_to_array199,5555 + def test_to_s_pendingtest_to_s_pending207,5798 + def test_inspect_pendingtest_inspect_pending216,6079 + def test_subtest_sub225,6395 + def test_claim_to_be_a_kind_of_arraytest_claim_to_be_a_kind_of_array237,6766 + def test_claim_to_be_a_kind_of_filelisttest_claim_to_be_a_kind_of_filelist243,6905 + def test_claim_to_be_a_filelist_instancetest_claim_to_be_a_filelist_instance249,7053 + def test_dont_claim_to_be_an_array_instancetest_dont_claim_to_be_an_array_instance254,7176 + def test_sub!test_sub!259,7299 + def test_sub_with_blocktest_sub_with_block268,7523 + def test_string_exttest_string_ext280,7952 + def test_filelist_exttest_filelist_ext305,8995 + def test_gsubtest_gsub310,9115 + def test_gsub!test_gsub!318,9310 + def test_egrep_with_outputtest_egrep_with_output326,9499 + def test_egrep_with_blocktest_egrep_with_block333,9706 + def test_existingtest_existing346,10084 + def test_existing!test_existing!352,10258 + def test_ignore_specialtest_ignore_special359,10459 + def test_clear_ignore_patternstest_clear_ignore_patterns369,10950 + def test_exclude_with_alternate_file_sepstest_exclude_with_alternate_file_seps380,11292 + def test_add_default_exclude_listtest_add_default_exclude_list390,11574 + def test_basic_array_functionstest_basic_array_functions402,11906 + def test_flattentest_flatten414,12208 + def test_clone_and_duptest_clone_and_dup419,12366 + def test_dup_and_clone_replicate_tainttest_dup_and_clone_replicate_taint429,12586 + def test_duped_items_will_thawtest_duped_items_will_thaw438,12804 + def test_cloned_items_stay_frozentest_cloned_items_stay_frozen446,12963 + def test_array_comparisonstest_array_comparisons455,13142 + def test_array_equalitytest_array_equality468,13461 + def test_enumeration_methodstest_enumeration_methods479,13669 + def test_array_operatorstest_array_operators526,14878 + def test_other_array_returning_methodstest_other_array_returning_methods565,15762 + def test_file_utils_can_use_fileliststest_file_utils_can_use_filelists592,16458 + def create_test_datacreate_test_data602,16741 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_fileutils.rb,1949 +class TestFileUtils < Test::Unit::TestCaseTestFileUtils10,155 + def setupsetup14,244 + def teardownteardown18,309 + def test_rm_one_filetest_rm_one_file23,403 + def test_rm_two_filestest_rm_two_files29,535 + def test_rm_filelisttest_rm_filelist37,753 + def test_lntest_ln45,986 + class BadLinkBadLink52,1224 + def initialize(klass)initialize55,1291 + def cp(*args)cp58,1354 + def ln(*args)ln61,1402 + def test_safe_ln_failover_to_cp_on_standard_errortest_safe_ln_failover_to_cp_on_standard_error67,1501 + def test_safe_ln_failover_to_cp_on_not_implemented_errortest_safe_ln_failover_to_cp_on_not_implemented_error76,1757 + def test_safe_ln_fails_on_script_errortest_safe_ln_fails_on_script_error83,1964 + def test_verbosetest_verbose89,2143 + def test_nowritetest_nowrite100,2358 + def test_file_utils_methods_are_available_at_top_leveltest_file_utils_methods_are_available_at_top_level111,2572 + def test_fileutils_methods_dont_leaktest_fileutils_methods_dont_leak117,2728 + def test_shtest_sh123,2931 + class ShSh132,3287 + def run(*args)run134,3320 + def self.run(*args)run137,3363 + def test_sh_with_a_single_string_argumenttest_sh_with_a_single_string_argument142,3423 + def test_sh_with_multiple_argumentstest_sh_with_multiple_arguments149,3597 + def test_sh_failuretest_sh_failure156,3775 + def test_sh_special_handlingtest_sh_special_handling162,3911 + def test_sh_nooptest_sh_noop179,4324 + def test_sh_bad_optiontest_sh_bad_option184,4450 + def test_sh_verbosetest_sh_verbose191,4645 + def test_sh_no_verbosetest_sh_no_verbose200,4836 + def test_ruby_with_a_single_string_argumenttest_ruby_with_a_single_string_argument209,5006 + def test_ruby_with_multiple_argumentstest_ruby_with_multiple_arguments216,5179 + def test_split_alltest_split_all223,5349 + def redirect_stderrredirect_stderr234,5746 + def windows?windows?243,5884 + def env_varenv_var247,5937 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_ftp.rb,380 +class FakeDateFakeDate8,104 + def self.todaytoday9,119 + def self.nownow12,166 +class TestFtpFile < Test::Unit::TestCaseTestFtpFile18,228 + def setupsetup20,270 + def test_generaltest_general24,369 + def test_far_datetest_far_date37,840 + def test_close_datetest_close_date42,1022 + def test_directorytest_directory47,1208 + def test_symlinktest_symlink53,1388 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_invocation_chain.rb,1052 +class TestAnEmptyInvocationChain < Test::Unit::TestCaseTestAnEmptyInvocationChain8,159 + def setupsetup11,238 + def test_should_be_able_to_add_memberstest_should_be_able_to_add_members15,299 + def test_to_stest_to_s21,409 +class TestAnInvocationChainWithOneMember < Test::Unit::TestCaseTestAnInvocationChainWithOneMember27,543 + def setupsetup30,630 + def test_should_report_first_member_as_a_membertest_should_report_first_member_as_a_member36,757 + def test_should_fail_when_adding_original_membertest_should_fail_when_adding_original_member40,855 + def test_to_stest_to_s48,1093 +class TestAnInvocationChainWithMultipleMember < Test::Unit::TestCaseTestAnInvocationChainWithMultipleMember55,1233 + def setupsetup58,1325 + def test_should_report_first_member_as_a_membertest_should_report_first_member_as_a_member65,1492 + def test_should_report_second_member_as_a_membertest_should_report_second_member_as_a_member69,1590 + def test_should_fail_when_adding_original_membertest_should_fail_when_adding_original_member73,1690 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_makefile_loader.rb,107 +class TestMakefileLoader < Test::Unit::TestCaseTestMakefileLoader7,89 + def test_parsetest_parse10,153 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_multitask.rb,256 +class TestMultiTask < Test::Unit::TestCaseTestMultiTask7,128 + def setupsetup10,187 + def test_running_multitaskstest_running_multitasks15,243 + def test_all_multitasks_wait_on_slow_prerequisitestest_all_multitasks_wait_on_slow_prerequisites27,699 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_namespace.rb,290 +class TestNameSpace < Test::Unit::TestCaseTestNameSpace14,182 + class TMTM17,248 + def test_namespace_creationtest_namespace_creation21,296 + def test_namespace_lookuptest_namespace_lookup27,410 + def test_namespace_reports_tasks_it_ownstest_namespace_reports_tasks_it_owns37,608 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_package_task.rb,552 +class TestPackageTask < Test::Unit::TestCaseTestPackageTask7,100 + def test_createtest_create11,183 + def test_missing_versiontest_missing_version44,1129 + def test_no_versiontest_no_version50,1256 + def test_clonetest_clone55,1388 + class TestGemPackageTask < Test::Unit::TestCaseTestGemPackageTask76,1839 + def test_gem_packagetest_gem_package77,1889 + def test_gem_package_with_current_platformtest_gem_package_with_current_platform90,2257 + def test_gem_package_with_ruby_platformtest_gem_package_with_ruby_platform104,2703 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_pathmap.rb,2419 +class TestPathMap < Test::Unit::TestCaseTestPathMap7,128 + def test_returns_self_with_no_argstest_returns_self_with_no_args10,192 + def test_s_returns_file_separatortest_s_returns_file_separator14,280 + def test_f_returns_basenametest_f_returns_basename21,509 + def test_n_returns_basename_without_extensiontest_n_returns_basename_without_extension27,725 + def test_d_returns_dirnametest_d_returns_dirname35,1054 + def test_9d_returns_partial_dirnametest_9d_returns_partial_dirname42,1322 + def test_x_returns_extensiontest_x_returns_extension52,1833 + def test_X_returns_everything_but_extensiontest_X_returns_everything_but_extension60,2106 + def test_p_returns_entire_pathnametest_p_returns_entire_pathname74,2720 + def test_dash_returns_empty_stringtest_dash_returns_empty_string80,2972 + def test_percent_percent_returns_percenttest_percent_percent_returns_percent85,3114 + def test_undefined_percent_causes_errortest_undefined_percent_causes_error89,3207 + def test_pattern_returns_substitutionstest_pattern_returns_substitutions95,3338 + def test_pattern_can_use_backreferencestest_pattern_can_use_backreferences100,3470 + def test_pattern_with_star_replacement_string_uses_blocktest_pattern_with_star_replacement_string_uses_block104,3589 + def test_pattern_with_no_replacement_nor_block_substitutes_empty_stringtest_pattern_with_no_replacement_nor_block_substitutes_empty_string111,3854 + def test_pattern_works_with_certain_valid_operatorstest_pattern_works_with_certain_valid_operators115,3987 + def test_multiple_patternstest_multiple_patterns123,4338 + def test_partial_directory_selection_works_with_patternstest_partial_directory_selection_works_with_patterns128,4483 + def test_pattern_with_invalid_operatortest_pattern_with_invalid_operator133,4652 + def test_works_with_windows_separatorstest_works_with_windows_separators140,4850 + def test_complex_patternstest_complex_patterns148,5067 +class TestPathMapExplode < Test::Unit::TestCaseTestPathMapExplode163,5778 + def setupsetup164,5826 + def teardownteardown168,5895 + def test_explodetest_explode172,5970 +class TestPathMapPartial < Test::Unit::TestCaseTestPathMapPartial190,6734 + def test_pathmap_partialtest_pathmap_partial191,6782 +class TestFileListPathMap < Test::Unit::TestCaseTestFileListPathMap206,7168 + def test_file_list_supports_pathmaptest_file_list_supports_pathmap207,7217 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_pseudo_status.rb,199 +class PseudoStatusTest < Test::Unit::TestCasePseudoStatusTest9,119 + def test_with_zero_exit_statustest_with_zero_exit_status10,165 + def test_with_99_exit_statustest_with_99_exit_status18,367 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_rake.rb,300 +class TestRake < Test::Unit::TestCaseTestRake6,57 + def test_each_dir_parenttest_each_dir_parent7,95 + def alldirs(fn)alldirs22,597 + def test_can_override_applicationtest_can_override_application28,698 + def test_original_dir_reports_current_dirtest_original_dir_reports_current_dir37,914 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_rdoc_task.rb,1147 +class TestRDocTask < Test::Unit::TestCaseTestRDocTask7,97 + def setupsetup11,179 + def test_tasks_creationtest_tasks_creation15,215 + def test_tasks_creation_with_custom_name_symboltest_tasks_creation_with_custom_name_symbol22,352 + def test_tasks_creation_with_custom_name_stringtest_tasks_creation_with_custom_name_string30,577 + def test_tasks_creation_with_custom_name_hashtest_tasks_creation_with_custom_name_hash38,804 + def test_tasks_creation_with_custom_name_hash_will_use_default_if_an_option_isnt_giventest_tasks_creation_with_custom_name_hash_will_use_default_if_an_option_isnt_given48,1165 + def test_tasks_creation_with_custom_name_hash_raises_exception_if_invalid_option_giventest_tasks_creation_with_custom_name_hash_raises_exception_if_invalid_option_given55,1401 + def test_inline_source_is_enabled_by_defaulttest_inline_source_is_enabled_by_default67,1713 + def test_inline_source_option_is_only_appended_if_option_not_already_giventest_inline_source_option_is_only_appended_if_option_not_already_given72,1851 + def test_inline_source_option_can_be_disabledtest_inline_source_option_can_be_disabled83,2236 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_require.rb,290 +class TestRequire < Test::Unit::TestCaseTestRequire8,159 + def test_can_load_rake_librarytest_can_load_rake_library11,223 + def test_wont_reload_rake_librarytest_wont_reload_rake_library18,387 + def test_throws_error_if_library_not_foundtest_throws_error_if_library_not_found25,563 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_rules.rb,2984 +class TestRules < Test::Unit::TestCaseTestRules10,207 + def setupsetup22,488 + def teardownteardown27,537 + def test_multiple_rules1test_multiple_rules131,632 + def test_multiple_rules2test_multiple_rules243,922 + def test_create_with_sourcetest_create_with_source53,1177 + def test_single_dependenttest_single_dependent64,1434 + def test_rule_can_be_created_by_stringtest_rule_can_be_created_by_string73,1615 + def test_rule_prereqs_can_be_created_by_stringtest_rule_prereqs_can_be_created_by_string82,1808 + def test_plain_strings_as_dependents_refer_to_filestest_plain_strings_as_dependents_refer_to_files91,2007 + def test_file_names_beginning_with_dot_can_be_tricked_into_refering_to_filetest_file_names_beginning_with_dot_can_be_tricked_into_refering_to_file100,2214 + def test_file_names_beginning_with_dot_can_be_wrapped_in_lambdatest_file_names_beginning_with_dot_can_be_wrapped_in_lambda113,2536 + def test_file_names_containing_percent_can_be_wrapped_in_lambdatest_file_names_containing_percent_can_be_wrapped_in_lambda126,2883 + def test_non_extension_rule_name_refers_to_filetest_non_extension_rule_name_refers_to_file139,3233 + def test_pathmap_automatically_applies_to_nametest_pathmap_automatically_applies_to_name152,3521 + def test_plain_strings_are_just_filenamestest_plain_strings_are_just_filenames165,3851 + def test_rule_runs_when_explicit_task_has_no_actionstest_rule_runs_when_explicit_task_has_no_actions178,4178 + def test_close_matches_on_name_do_not_trigger_ruletest_close_matches_on_name_do_not_trigger_rule190,4467 + def test_rule_rebuilds_obj_when_source_is_newertest_rule_rebuilds_obj_when_source_is_newer199,4758 + def test_rule_with_two_sources_runs_if_both_sources_are_presenttest_rule_with_two_sources_runs_if_both_sources_are_present208,4972 + def test_rule_with_two_sources_but_one_missing_does_not_runtest_rule_with_two_sources_but_one_missing_does_not_run217,5241 + def test_rule_with_two_sources_builds_both_sourcestest_rule_with_two_sources_builds_both_sources227,5517 + def test_second_rule_runs_when_first_rule_doesnttest_second_rule_runs_when_first_rule_doesnt243,5843 + def test_second_rule_doest_run_if_first_triggerstest_second_rule_doest_run_if_first_triggers256,6186 + def test_second_rule_doest_run_if_first_triggers_with_reversed_rulestest_second_rule_doest_run_if_first_triggers_with_reversed_rules268,6513 + def test_rule_with_proc_dependent_will_triggertest_rule_with_proc_dependent_will_trigger280,6860 + def test_proc_returning_lists_are_flattened_into_prereqstest_proc_returning_lists_are_flattened_into_prereqs297,7393 + def test_recursive_rules_will_work_as_long_as_they_terminatetest_recursive_rules_will_work_as_long_as_they_terminate319,7959 + def test_recursive_rules_that_dont_terminate_will_overflowtest_recursive_rules_that_dont_terminate_will_overflow330,8346 + def test_rules_with_bad_dependents_will_failtest_rules_with_bad_dependents_will_fail343,8743 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_task_arguments.rb,994 +class TestTaskArguments < Test::Unit::TestCaseTestTaskArguments7,128 + def teardownteardown8,175 + def test_empty_arg_list_is_emptytest_empty_arg_list_is_empty13,241 + def test_multiple_values_in_argstest_multiple_values_in_args18,357 + def test_to_stest_to_s23,537 + def test_enumerable_behaviortest_enumerable_behavior29,711 + def test_named_argstest_named_args34,871 + def test_args_knows_its_namestest_args_knows_its_names43,1085 + def test_extra_names_are_niltest_extra_names_are_nil48,1219 + def test_args_can_reference_env_valuestest_args_can_reference_env_values53,1339 + def test_creating_new_argument_scopestest_creating_new_argument_scopes61,1541 + def test_child_hides_parent_arg_namestest_child_hides_parent_arg_names71,1831 + def test_default_arguments_values_can_be_mergedtest_default_arguments_values_can_be_merged77,2016 + def test_default_arguements_that_dont_match_names_are_ignoredtest_default_arguements_that_dont_match_names_are_ignored84,2271 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_task_manager.rb,1276 +class TaskManagerTaskManager7,88 +class TestTaskManager < Test::Unit::TestCaseTestTaskManager11,139 + def setupsetup14,207 + def test_create_task_managertest_create_task_manager18,252 + def test_define_tasktest_define_task23,344 + def test_name_lookuptest_name_lookup29,479 + def test_namespace_task_createtest_namespace_task_create34,577 + def test_anonymous_namespacetest_anonymous_namespace42,788 + def test_create_filetask_in_namespacetest_create_filetask_in_namespace51,1017 + def test_namespace_yields_same_namespace_as_returnedtest_namespace_yields_same_namespace_as_returned59,1239 + def test_name_lookup_with_implicit_file_taskstest_name_lookup_with_implicit_file_tasks67,1476 + def test_name_lookup_with_nonexistent_tasktest_name_lookup_with_nonexistent_task73,1619 + def test_name_lookup_in_multiple_scopestest_name_lookup_in_multiple_scopes79,1746 + def test_lookup_with_explicit_scopestest_lookup_with_explicit_scopes121,2961 + def test_correctly_scoped_prerequisites_are_invokedtest_correctly_scoped_prerequisites_are_invoked138,3492 +class TestTaskManagerArgumentResolution < Test::Unit::TestCaseTestTaskManagerArgumentResolution153,3873 + def test_good_arg_patternstest_good_arg_patterns154,3936 + def task(*args)task169,4614 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_tasklib.rb,92 +class TestTaskLib < Test::Unit::TestCaseTestTaskLib7,66 + def test_pastetest_paste8,107 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_tasks.rb,3048 +class TestTask < Test::Unit::TestCaseTestTask11,237 + def setupsetup16,337 + def test_createtest_create20,371 + def test_inspecttest_inspect32,644 + def test_invoketest_invoke37,774 + def test_invoke_with_circular_dependenciestest_invoke_with_circular_dependencies47,1078 + def test_dry_run_prevents_actionstest_dry_run_prevents_actions60,1511 + def test_tasks_can_be_tracedtest_tasks_can_be_traced73,1895 + def test_no_double_invoketest_no_double_invoke85,2168 + def test_can_double_invoke_with_reenabletest_can_double_invoke_with_reenable94,2443 + def test_cleartest_clear103,2638 + def test_clear_prerequisitestest_clear_prerequisites110,2825 + def test_clear_actionstest_clear_actions117,3003 + def test_findtest_find123,3132 + def test_definedtest_defined130,3342 + def test_multi_invocationstest_multi_invocations136,3450 + def test_task_listtest_task_list146,3683 + def test_task_gives_name_on_to_stest_task_gives_name_on_to_s152,3809 + def test_symbols_can_be_prerequisitestest_symbols_can_be_prerequisites157,3905 + def test_strings_can_be_prerequisitestest_strings_can_be_prerequisites162,4017 + def test_arrays_can_be_prerequisitestest_arrays_can_be_prerequisites167,4130 + def test_filelists_can_be_prerequisitestest_filelists_can_be_prerequisites172,4254 + def test_investigation_outputtest_investigation_output177,4401 + def test_extended_commentstest_extended_comments188,4697 + def test_multiple_commentstest_multiple_comments204,5196 + def test_settable_commentstest_settable_comments212,5352 +class TestTaskWithArguments < Test::Unit::TestCaseTestTaskWithArguments220,5534 + def setupsetup225,5647 + def test_no_args_giventest_no_args_given229,5681 + def test_args_giventest_args_given234,5762 + def test_name_and_needstest_name_and_needs239,5854 + def test_name_and_explicit_needstest_name_and_explicit_needs246,6018 + def test_name_args_and_explicit_needstest_name_args_and_explicit_needs253,6199 + def test_illegal_keys_in_task_name_hashtest_illegal_keys_in_task_name_hash260,6399 + def test_arg_list_is_empty_if_no_args_giventest_arg_list_is_empty_if_no_args_given266,6543 + def test_tasks_can_access_arguments_as_hashtest_tasks_can_access_arguments_as_hash271,6681 + def test_actions_of_various_arity_are_ok_with_argstest_actions_of_various_arity_are_ok_with_args284,7048 + def test_arguments_are_passed_to_blocktest_arguments_are_passed_to_block305,7511 + def test_extra_parameters_are_ignoredtest_extra_parameters_are_ignored312,7679 + def test_arguments_are_passed_to_all_blockstest_arguments_are_passed_to_all_blocks320,7838 + def test_block_with_no_parameters_is_oktest_block_with_no_parameters_is_ok335,8135 + def test_name_with_argstest_name_with_args340,8224 + def test_named_args_are_passed_to_prereqstest_named_args_are_passed_to_prereqs350,8485 + def test_args_not_passed_if_no_prereq_namestest_args_not_passed_if_no_prereq_names358,8716 + def test_args_not_passed_if_no_arg_namestest_args_not_passed_if_no_arg_names367,8958 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_test_task.rb,452 +class TestTestTask < Test::Unit::TestCaseTestTestTask6,66 + def setupsetup10,148 + def teardownteardown15,205 + def test_no_tasktest_no_task19,259 + def test_defaultstest_defaults23,324 + def test_non_defaultstest_non_defaults33,595 + def test_patterntest_pattern47,981 + def test_env_testtest_env_test54,1126 + def test_test_filestest_test_files62,1302 + def test_both_pattern_and_test_filestest_both_pattern_and_test_files69,1473 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_top_level_functions.rb,719 +class TestTopLevelFunctions < Test::Unit::TestCaseTestTopLevelFunctions15,212 + def setupsetup19,310 + def teardownteardown25,406 + def test_namespacetest_namespace30,466 + def test_importtest_import35,594 + def test_when_writingtest_when_writing42,861 + def test_when_not_writingtest_when_not_writing51,1031 + def test_missing_constants_tasktest_missing_constants_task63,1302 + def test_missing_constants_file_tasktest_missing_constants_file_task68,1444 + def test_missing_constants_file_creation_tasktest_missing_constants_file_creation_task73,1599 + def test_missing_constants_rake_apptest_missing_constants_rake_app78,1779 + def test_missing_other_constanttest_missing_other_constant83,1931 + +tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_win32.rb,660 +class TestWin32 < Test::Unit::TestCaseTestWin329,119 + def test_win32_system_dir_uses_home_if_definedtest_win32_system_dir_uses_home_if_defined15,228 + def test_win32_system_dir_uses_homedrive_homepath_when_no_home_definedtest_win32_system_dir_uses_homedrive_homepath_when_no_home_defined21,412 + def test_win32_system_dir_uses_appdata_when_no_home_or_home_combotest_win32_system_dir_uses_appdata_when_no_home_or_home_combo32,690 + def test_win32_system_dir_fallback_to_userprofile_otherwisetest_win32_system_dir_fallback_to_userprofile_otherwise44,1070 + def test_win32_system_dir_nil_of_no_env_varstest_win32_system_dir_nil_of_no_env_vars57,1437 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/bin/autospec,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/bin/spec,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/diffing_spec.rb,111 + class AnimalAnimal16,275 + def initialize(name,species)initialize17,290 + def inspectinspect21,368 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/failing_implicit_docstrings_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/failure_in_after.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/failure_in_before.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_with_flexmock.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_with_mocha.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_with_rr.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/partial_mock_example.rb,67 +class MockableClassMockableClass1,0 + def self.find idfind2,20 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/pending_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/predicate_example.rb,114 +class BddFrameworkBddFramework1,0 + def intuitive?intuitive?2,19 + def adopted_quickly?adopted_quickly?6,52 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/raising_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/syntax_error_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/team_spec.rb,175 +class TeamTeam1,0 + def initializeinitialize3,34 +class PlayersPlayers8,89 + def initializeinitialize9,103 + def sizesize12,144 + def include? playerinclude?15,179 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/timeout_behaviour.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/custom_formatter.rb,140 +class CustomFormatter < Spec::Runner::Formatter::ProgressBarFormatterCustomFormatter5,217 + def backtrace_line(line)backtrace_line6,287 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/custom_matchers.rb,452 +module AnimalSpecHelperAnimalSpecHelper1,0 + class EatEat2,24 + def initialize(food)initialize3,36 + def matches?(animal)matches?7,93 + def failure_messagefailure_message12,181 + def negative_failure_messagenegative_failure_message16,279 + def eat(food)eat21,392 +module AnimalsAnimals26,437 + class AnimalAnimal27,452 + def eats?(food)eats?28,467 + class Mouse < AnimalMouse33,544 + def foods_i_eatfoods_i_eat34,567 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/dynamic_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/file_accessor.rb,110 +class FileAccessorFileAccessor1,0 + def open_and_handle_with(pathname, processor)open_and_handle_with2,19 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/file_accessor_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/filtered_formatter.rb,209 +class FilteredFormatter < Spec::Runner::Formatter::NestedTextFormatterFilteredFormatter3,55 + def add_example_group(example_group)add_example_group4,126 + def example_passed(example)example_passed13,319 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/filtered_formatter_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/greeter_spec.rb,102 +class GreeterGreeter9,160 + def initialize(person = nil)initialize10,174 + def greetgreet14,233 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/helper_method_example.rb,92 +module HelperMethodExampleHelperMethodExample1,0 + def helper_methodhelper_method3,81 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/implicit_docstrings_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/io_processor.rb,124 +class DataTooShort < StandardError; endDataTooShort1,0 +class IoProcessorIoProcessor3,41 + def process(io)process5,130 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/io_processor_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/mocking_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/multi_threaded_example_group_runner.rb,176 +class MultiThreadedExampleGroupRunner < Spec::Runner::ExampleGroupRunnerMultiThreadedExampleGroupRunner1,0 + def initialize(options, arg)initialize2,73 + def runrun9,195 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/nested_classes_example.rb,269 +class StackExamples < Spec::ExampleGroupStackExamples3,34 +class EmptyStackExamples < StackExamplesEmptyStackExamples10,146 +class AlmostFullStackExamples < StackExamplesAlmostFullStackExamples17,276 +class FullStackExamples < StackExamplesFullStackExamples27,480 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/options_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/options_formatter.rb,206 +class OptionsFormatter < Spec::Runner::Formatter::BaseTextFormatterOptionsFormatter8,314 + def example_started(proxy)example_started9,382 + def example_group_started(proxy)example_group_started15,485 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/partial_mock_example.rb,67 +class MockableClassMockableClass1,0 + def self.find idfind2,20 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/pending_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/predicate_example.rb,114 +class BddFrameworkBddFramework1,0 + def intuitive?intuitive?2,19 + def adopted_quickly?adopted_quickly?6,54 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/shared_example_group_example.rb,356 +module SharedExampleGroupExampleSharedExampleGroupExample1,0 + class OneThingOneThing2,33 + def what_things_dowhat_things_do3,50 + class AnotherThingAnotherThing8,104 + def what_things_dowhat_things_do9,125 + class YetAnotherThingYetAnotherThing14,179 + def what_things_dowhat_things_do15,203 + def helper_methodhelper_method23,396 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/shared_stack_examples.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/simple_matcher_example.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stack.rb,312 +class StackUnderflowError < RuntimeErrorStackUnderflowError1,0 +class StackOverflowError < RuntimeErrorStackOverflowError4,46 +class StackStack7,91 + def initializeinitialize9,106 + def push objectpush13,148 + def poppop18,250 + def peekpeek23,346 + def empty?empty?28,429 + def full?full?32,467 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stack_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stack_spec_with_nested_example_groups.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stubbing_example.rb,73 +class StubbableClassStubbableClass9,215 + def self.find idfind10,236 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/yielding_example.rb,126 +class MessageAppenderMessageAppender1,0 + def initialize(appendage)initialize3,25 + def append_to(message)append_to7,89 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/ruby1.9.compatibility/access_to_constants_spec.rb,460 +module Foo Foo7,228 + module BarBar8,240 + module ModuleInEnclosingModule;endModuleInEnclosingModule10,258 + class ClassInEnclosingModule;end ClassInEnclosingModule11,297 + def method_in_enclosing_module;endmethod_in_enclosing_module12,335 + module ModuleDefinedInGroup;endModuleDefinedInGroup51,1404 + class ClassDefinedInGroup; end ClassDefinedInGroup52,1442 + def method_defined_in_group; endmethod_defined_in_group53,1480 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/step_definitions/running_rspec_steps.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/step_definitions/stubbing_steps.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/support/env.rb,533 +class RspecWorldRspecWorld10,235 + def self.working_dirworking_dir18,434 + def self.spec_commandspec_command22,576 + def self.cmdline_filecmdline_file26,700 + def self.rspec_librspec_lib30,844 + def spec(args)spec34,928 + def cmdline(args)cmdline38,988 + def create_file(file_name, contents)create_file42,1051 + def create_directory(dirname)create_directory47,1199 + def last_stdoutlast_stdout51,1292 + def last_stderrlast_stderr55,1329 + def last_exit_codelast_exit_code59,1366 + def ruby(args)ruby64,1536 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/support/matchers/smart_match.rb,54 + def regexp?regexp?2,49 + def quoted?quoted?6,86 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/init.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/autotest/discover.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/autotest/rspec.rb,393 +class RspecCommandError < StandardError; endRspecCommandError17,394 +class Autotest::Rspec < AutotestAutotest19,440 + def initializeinitialize23,573 + def consolidate_failures(failed)consolidate_failures29,789 + def make_test_cmd(files_to_test)make_test_cmd39,1011 + def normalize(files_to_test)normalize44,1205 + def add_options_if_present # :nodoc:add_options_if_present51,1366 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/flexmock.rb,294 +module SpecSpec9,179 + module AdaptersAdapters10,191 + module MockFrameworkMockFramework11,209 + def setup_mocks_for_rspecsetup_mocks_for_rspec13,272 + def verify_mocks_for_rspecverify_mocks_for_rspec16,342 + def teardown_mocks_for_rspecteardown_mocks_for_rspec19,409 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/mocha.rb,291 +module SpecSpec5,96 + module AdaptersAdapters6,108 + module MockFrameworkMockFramework7,126 + def setup_mocks_for_rspecsetup_mocks_for_rspec14,319 + def verify_mocks_for_rspecverify_mocks_for_rspec17,381 + def teardown_mocks_for_rspecteardown_mocks_for_rspec20,445 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/rr.rb,292 +module SpecSpec7,174 + module AdaptersAdapters8,186 + module MockFrameworkMockFramework9,204 + def setup_mocks_for_rspecsetup_mocks_for_rspec11,275 + def verify_mocks_for_rspecverify_mocks_for_rspec14,350 + def teardown_mocks_for_rspecteardown_mocks_for_rspec17,435 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/rspec.rb,297 +module SpecSpec4,64 + module AdaptersAdapters5,76 + module MockFrameworkMockFramework7,129 + def setup_mocks_for_rspecsetup_mocks_for_rspec9,200 + def verify_mocks_for_rspecverify_mocks_for_rspec12,296 + def teardown_mocks_for_rspecteardown_mocks_for_rspec15,377 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/autorun.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/deprecation.rb,295 +module SpecSpec1,0 + def deprecate(method, alternate_method=nil)deprecate3,28 + def warn(message)warn25,641 + class HashWithDeprecationNotice < HashHashWithDeprecationNotice31,706 + def initialize(method, alternate_method=nil, &block)initialize32,747 + def []=(k,v)[]=35,872 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/dsl/main.rb,240 +module SpecSpec1,0 + module DSLDSL2,12 + module MainMain3,25 + def describe(*args, &block)describe24,982 + def share_examples_for(*args, &block)share_examples_for47,1762 + def share_as(name, &block)share_as78,2698 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/dsl.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/args_and_options.rb,392 +module SpecSpec1,0 + module ExampleExample2,12 + module ArgsAndOptionsArgsAndOptions3,29 + def args_and_options(*args) # :nodoc:args_and_options4,55 + def add_options(args, options={}) # :nodoc:add_options9,192 + def set_location(options, location) # :nodoc:set_location16,388 + module WithOptions # :nodoc:WithOptions20,491 + def optionsoptions21,526 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/before_and_after_hooks.rb,988 +module SpecSpec1,0 + module ExampleExample2,12 + module BeforeAndAfterHooksBeforeAndAfterHooks3,29 + def before_suite_parts # :nodoc:before_suite_parts5,80 + def after_suite_parts # :nodoc:after_suite_parts9,171 + def append_before(scope = :each, &block)append_before19,588 + def prepend_before(scope = :each, &block)prepend_before28,918 + def prepend_after(scope = :each, &block)prepend_after36,1210 + def append_after(scope = :each, &block)append_after45,1541 + def before_each_parts # :nodoc:before_each_parts49,1634 + def after_each_parts # :nodoc:after_each_parts53,1717 + def before_all_parts # :nodoc:before_all_parts57,1798 + def after_all_parts # :nodoc:after_all_parts61,1879 + def before_suite_parts # :nodoc:before_suite_parts65,1958 + def after_suite_parts # :nodoc:after_suite_parts69,2055 + def before_parts(scope)before_parts75,2163 + def after_parts(scope)after_parts83,2349 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/errors.rb,513 +module SpecSpec1,0 + module ExampleExample2,12 + class ExamplePendingError < StandardError; endExamplePendingError3,29 + class NotYetImplementedError < ExamplePendingErrorNotYetImplementedError5,81 + def initializeinitialize7,174 + class PendingExampleFixedError < StandardError; endPendingExampleFixedError12,237 + class NoDescriptionError < ArgumentErrorNoDescriptionError14,294 + def message(kind, location)message16,359 + def initialize(kind, location)initialize20,489 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group.rb,93 +module SpecSpec1,0 + module ExampleExample2,12 + class ExampleGroupExampleGroup5,136 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_factory.rb,747 +module SpecSpec1,0 + module ExampleExample2,12 + class ExampleGroupFactoryExampleGroupFactory4,30 + module ClassMethodsClassMethods5,60 + def resetreset8,133 + def example_group_creation_listenersexample_group_creation_listeners13,233 + def register_example_group(klass)register_example_group17,342 + def create_shared_example_group(*args, &example_group_block) # :nodoc:create_shared_example_group23,524 + def create_example_group(*args, &block)create_example_group27,700 + def register(key, example_group_class)register48,1573 + def default(example_group_class)default53,1744 + def [](key)[]61,2100 + def determine_superclass(opts)determine_superclass67,2186 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_hierarchy.rb,745 +module SpecSpec1,0 + module ExampleExample2,12 + class ExampleGroupHierarchy < ArrayExampleGroupHierarchy3,29 + def initialize(example_group_class)initialize4,69 + def run_before_all(example)run_before_all12,387 + def run_before_each(example)run_before_each16,486 + def run_after_each(example)run_after_each20,587 + def run_after_all(example)run_after_all24,686 + def before_all_partsbefore_all_parts28,783 + def before_each_partsbefore_each_parts32,900 + def after_each_partsafter_each_parts36,1020 + def after_all_partsafter_all_parts40,1145 + def nested_descriptionsnested_descriptions44,1267 + def nested_description_from(example_group)nested_description_from48,1435 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_methods.rb,2412 +module SpecSpec1,0 + module ExampleExample2,12 + module ExampleGroupMethodsExampleGroupMethods4,30 + def build_description_from(*args)build_description_from8,119 + def options # :nodoc:options24,637 + def inherited(klass) # :nodoc:inherited28,700 + def describe(*args, &example_group_block)describe47,1212 + def it_should_behave_like(*shared_example_groups)it_should_behave_like64,1836 + def example(description=nil, options={}, backtrace=nil, &implementation)example72,2148 + def pending_implementationpending_implementation79,2481 + def xexample(description=nil, opts={}, &block)xexample87,2720 + def run(run_options)run94,2916 + def set_description(*args)set_description107,3537 + def notify(reporter) # :nodoc:notify114,3766 + def descriptiondescription118,3882 + def described_typedescribed_type122,4011 + def described_classdescribed_class126,4134 + def description_argsdescription_args130,4248 + def description_parts #:nodoc:description_parts134,4319 + def example_proxies # :nodoc:example_proxies140,4543 + def example_implementations # :nodoc:example_implementations144,4622 + def examples(run_options=nil) #:nodoc:examples148,4717 + def number_of_examples #:nodoc:number_of_examples152,4862 + def example_group_hierarchyexample_group_hierarchy156,4942 + def nested_descriptionsnested_descriptions160,5056 + def include_constants_in(mod)include_constants_in164,5149 + def let(name, &block)let168,5290 + def let!(name, &block)let!175,5456 + def subclass(*args, &example_group_block)subclass182,5569 + def dry_run(examples, run_options)dry_run192,5905 + def run_before_all(run_options)run_before_all199,6117 + def run_examples(success, instance_variables, examples, run_options)run_examples212,6639 + def run_after_all(success, instance_variables, run_options)run_after_all226,7203 + def examples_to_run(run_options)examples_to_run238,7696 + def examples_were_specified?(run_options)examples_were_specified?255,8326 + def method_added(name) # :nodoc:method_added259,8422 + def example_method?(method_name)example_method?263,8568 + def should_method?(method_name)should_method?267,8654 + def include_shared_example_group(shared_example_group)include_shared_example_group273,8833 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_proxy.rb,313 +module SpecSpec1,0 + module ExampleExample2,12 + class ExampleGroupProxyExampleGroupProxy5,179 + def initialize(example_group) # :nodoc:initialize7,208 + def backtracebacktrace41,1699 + def filtered_description(regexp)filtered_description47,1896 + def ==(other) # :nodoc:==56,2279 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_matcher.rb,735 +module SpecSpec1,0 + module ExampleExample2,12 + class ExampleMatcherExampleMatcher3,29 + def initialize(example_group_description, example_name)initialize4,54 + def matches?(specified_examples)matches?9,227 + def matches_literal_example?(specified_example)matches_literal_example?16,477 + def matches_example_not_considering_modules?(specified_example)matches_example_not_considering_modules?20,705 + def example_group_regexexample_group_regex24,955 + def example_group_with_before_all_regexpexample_group_with_before_all_regexp28,1046 + def example_group_regex_not_considering_modulesexample_group_regex_not_considering_modules32,1172 + def example_regexpexample_regexp36,1304 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_methods.rb,1177 +module SpecSpec1,0 + module ExampleExample2,12 + module ExampleMethodsExampleMethods3,29 + def violated(message="")violated8,158 + def descriptiondescription20,502 + def options # :nodoc:options28,760 + def execute(run_options, instance_variables) # :nodoc:execute32,823 + module BlockAliasesBlockAliases59,1668 + def expect(&block)expect69,2058 + def eval_each_fail_fast(blocks) # :nodoc:eval_each_fail_fast73,2128 + def eval_each_fail_slow(blocks) # :nodoc:eval_each_fail_slow77,2239 + def instance_variable_hash # :nodoc:instance_variable_hash89,2550 + def set_instance_variables_from_hash(ivars) # :nodoc:set_instance_variables_from_hash96,2790 + def run_before_eachrun_before_each106,3200 + def run_after_eachrun_after_each111,3348 + def initialize(example_proxy, &implementation)initialize115,3437 + def before_each_examplebefore_each_example126,3669 + def after_each_exampleafter_each_example131,3764 + def described_classdescribed_class138,3904 + def description_argsdescription_args142,3976 + def example_group_hierarchyexample_group_hierarchy146,4050 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_proxy.rb,317 +module SpecSpec1,0 + module ExampleExample2,12 + class ExampleProxyExampleProxy5,178 + def initialize(description=nil, options={}, location=nil) # :nodoc:initialize7,202 + def backtracebacktrace24,839 + def update(description) # :nodoc:update31,1075 + def ==(other) # :nodoc:==36,1174 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/module_reopening_fix.rb,230 +module SpecSpec1,0 + module ExampleExample2,12 + module ModuleReopeningFixModuleReopeningFix26,562 + def child_moduleschild_modules27,592 + def included(mod)included31,657 + def include(mod)include35,721 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/pending.rb,132 +module SpecSpec1,0 + module ExampleExample2,12 + module PendingPending3,29 + def pending(message = "TODO")pending4,48 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/predicate_matchers.rb,264 +module SpecSpec1,0 + module ExampleExample2,12 + module PredicateMatchersPredicateMatchers3,29 + def predicate_matcherspredicate_matchers32,929 + def define_methods_from_predicate_matchers # :nodoc:define_methods_from_predicate_matchers36,1082 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/shared_example_group.rb,693 +module SpecSpec1,0 + module ExampleExample2,12 + class SharedExampleGroup < ModuleSharedExampleGroup3,29 + module ClassMethodsClassMethods4,67 + def register(*args, &block)register5,93 + def find(example_group_description)find11,318 + def clearclear15,461 + def include?(group)include?19,530 + def countcount23,619 + def shared_example_groupsshared_example_groups29,704 + def already_registered?(new_example_group)already_registered?33,791 + def expanded_path(example_group)expanded_path41,1259 + def initialize(*args, &example_group_block)initialize49,1435 + def included(mod) # :nodoc:included54,1578 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/subject.rb,554 +module SpecSpec1,0 + module ExampleExample2,12 + module SubjectSubject3,29 + module ExampleGroupMethodsExampleGroupMethods4,48 + def subject(&block)subject18,662 + def its(attribute, &block)its23,817 + def explicit_subjectexplicit_subject40,1219 + def implicit_subjectimplicit_subject48,1474 + module ExampleMethodsExampleMethods53,1615 + def subjectsubject82,2750 + def should(matcher=nil, message=nil)should96,3219 + def should_not(matcher=nil, message=nil)should_not108,3646 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example.rb,55 +module SpecSpec1,0 + module ExampleExample144,3595 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/errors.rb,136 +module SpecSpec1,0 + module ExpectationsExpectations2,12 + class ExpectationNotMetError < superclassExpectationNotMetError9,328 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/extensions/kernel.rb,156 +module KernelKernel1,0 + def should(matcher=nil, message=nil, &block)should26,676 + def should_not(matcher=nil, message=nil, &block)should_not49,1381 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/extensions.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/fail_with.rb,143 +module SpecSpec1,0 + module ExpectationsExpectations2,12 + def fail_with(message, expected=nil, target=nil) # :nodoc:fail_with11,370 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/handler.rb,472 +module SpecSpec1,0 + module ExpectationsExpectations2,12 + class InvalidMatcherError < ArgumentError; end InvalidMatcherError3,34 + class PositiveExpectationHandler PositiveExpectationHandler5,98 + def self.handle_matcher(actual, matcher, message=nil, &block)handle_matcher6,143 + class NegativeExpectationHandlerNegativeExpectationHandler26,907 + def self.handle_matcher(actual, matcher, message=nil, &block)handle_matcher27,944 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations.rb,66 +module SpecSpec7,173 + module ExpectationsExpectations33,1245 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/extensions/instance_exec.rb,157 +module SpecSpec1,0 + module MatchersMatchers2,12 + module InstanceExecInstanceExec3,30 + def instance_exec(*args, &block)instance_exec12,468 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/autorunner.rb,81 +class Test::Unit::AutoRunnerTest1,0 + def process_args(argv)process_args3,59 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/testcase.rb,363 +module TestTest3,30 + module UnitUnit4,42 + class TestCaseTestCase21,527 + def self.suitesuite25,639 + def self.example_method?(method_name)example_method29,718 + def self.test_method?(method_name)test_method33,838 + def initialize(description, &implementation)initialize43,1100 + def run(ignore_this_argument=nil)run50,1346 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/testresult.rb,65 +class Test::Unit::TestResultTest1,0 + def passed?passed?3,66 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/testsuite_adapter.rb,317 +module TestTest3,31 + module UnitUnit4,43 + class TestSuiteAdapter < TestSuiteTestSuiteAdapter5,57 + def initialize(example_group)initialize8,177 + def namename13,306 + def run(*args)run17,366 + def sizesize22,485 + def delete(example)delete26,552 + def empty?empty?30,621 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/ui/console/testrunner.rb,513 +module TestTest3,43 + module UnitUnit4,55 + module UIUI5,69 + module ConsoleConsole6,83 + class TestRunnerTestRunner7,104 + def started_with_rspec(result)started_with_rspec10,186 + def test_started_with_rspec(name)test_started_with_rspec17,433 + def test_finished_with_rspec(name)test_finished_with_rspec31,918 + def finished_with_rspec(elapsed_time)finished_with_rspec38,1176 + def setup_mediator_with_rspecsetup_mediator_with_rspec47,1498 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be.rb,2015 +module SpecSpec29,430 + module MatchersMatchers30,442 + class Be #:nodoc:Be32,461 + def initialize(*args, &block)initialize35,527 + def matches?(actual)matches?39,601 + def failure_message_for_shouldfailure_message_for_should44,682 + def failure_message_for_should_notfailure_message_for_should_not48,794 + def descriptiondescription52,911 + def args_to_sargs_to_s64,1138 + def parenthesize(string)parenthesize68,1243 + def inspected_argsinspected_args72,1320 + def expected_to_sentenceexpected_to_sentence76,1399 + def args_to_sentenceargs_to_sentence80,1478 + class BeComparedTo < BeBeComparedTo86,1560 + def initialize(operand, operator)initialize88,1589 + def matches?(actual)matches?93,1708 + def failure_message_for_shouldfailure_message_for_should98,1818 + def failure_message_for_should_notfailure_message_for_should_not102,1941 + def descriptiondescription113,2326 + class BePredicate < BeBePredicate119,2437 + def initialize(*args, &block)initialize121,2465 + def matches?(actual)matches?127,2609 + def failure_message_for_shouldfailure_message_for_should142,3117 + def failure_message_for_should_notfailure_message_for_should_not146,3254 + def descriptiondescription150,3390 + def predicatepredicate156,3510 + def present_tense_predicatepresent_tense_predicate160,3578 + def parse_expected(expected)parse_expected164,3661 + def prefix_and_expected(symbol)prefix_and_expected169,3782 + def prefix_to_sentenceprefix_to_sentence174,3896 + class BeSameAs < BeBeSameAs180,3974 + def initialize(*args, &block)initialize182,4005 + def matches?(actual)matches?187,4110 + def failure_message_for_shouldfailure_message_for_should192,4207 + def failure_message_for_should_notfailure_message_for_should_not196,4317 + def descriptiondescription200,4429 + def be(*args)be236,5782 + def be_a(klass)be_a243,5933 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be_close.rb,103 +module SpecSpec1,0 + module MatchersMatchers2,12 + def be_close(expected, delta)be_close12,254 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be_instance_of.rb,114 +module SpecSpec1,0 + module MatchersMatchers2,12 + def be_an_instance_of(expected)be_an_instance_of16,431 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be_kind_of.rb,104 +module SpecSpec1,0 + module MatchersMatchers2,12 + def be_a_kind_of(expected)be_a_kind_of16,393 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/change.rb,835 +module SpecSpec1,0 + module MatchersMatchers2,12 + class Change #:nodoc:Change5,77 + def initialize(receiver=nil, message=nil, &block)initialize6,103 + def matches?(event_proc)matches?12,340 + def raise_block_syntax_errorraise_block_syntax_error27,882 + def evaluate_value_procevaluate_value_proc34,1068 + def failure_message_for_shouldfailure_message_for_should38,1140 + def actual_deltaactual_delta54,1956 + def failure_message_for_should_notfailure_message_for_should_not58,2021 + def by(amount)by62,2186 + def by_at_least(minimum)by_at_least67,2262 + def by_at_most(maximum)by_at_most72,2350 + def to(to)to77,2443 + def from (from)from82,2507 + def descriptiondescription87,2580 + def change(receiver=nil, message=nil, &block)change147,4562 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/compatibility.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/dsl.rb,179 +module SpecSpec1,0 + module MatchersMatchers2,12 + module DSLDSL3,30 + def define(name, &declarations)define5,72 + def create(name, &declarations)create12,282 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/eql.rb,86 +module SpecSpec1,0 + module MatchersMatchers2,12 + def eql(expected)eql15,408 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/equal.rb,142 +module SpecSpec1,0 + module MatchersMatchers2,12 + def equal(expected)equal16,474 + def inspect_object(o)inspect_object22,632 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/errors.rb,115 +module SpecSpec1,0 + module MatchersMatchers2,12 + class MatcherError < StandardError; endMatcherError3,30 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/exist.rb,88 +module SpecSpec1,0 + module MatchersMatchers2,12 + def exist(arg=nil)exist8,129 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/generated_descriptions.rb,246 +module SpecSpec1,0 + module MatchersMatchers2,12 + def self.clear_generated_descriptionclear_generated_description7,115 + def self.generated_descriptiongenerated_description12,224 + def self.last_descriptionlast_description19,386 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/has.rb,414 +module SpecSpec1,0 + module MatchersMatchers2,12 + class HasHas4,35 + def initialize(expected, *args, &block)initialize6,56 + def matches?(actual)matches?10,176 + def failure_message_for_shouldfailure_message_for_should14,283 + def failure_message_for_should_notfailure_message_for_should_not18,428 + def descriptiondescription22,577 + def predicate(sym)predicate28,670 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/have.rb,796 +module SpecSpec1,0 + module MatchersMatchers2,12 + class Have #:nodoc:Have3,30 + def initialize(expected, relativity=:exactly)initialize4,54 + def relativitiesrelativities11,267 + def matches?(collection_owner)matches?19,438 + def not_a_collectionnot_a_collection37,1399 + def failure_message_for_shouldfailure_message_for_should41,1543 + def failure_message_for_should_notfailure_message_for_should_not45,1670 + def descriptiondescription67,2490 + def respond_to?(sym)respond_to?71,2588 + def method_missing(sym, *args, &block)method_missing77,2695 + def relative_expectationrelative_expectation87,3052 + def have(n)have123,4384 + def have_at_least(n)have_at_least136,4649 + def have_at_most(n)have_at_most148,4902 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/include.rb,149 +module SpecSpec1,0 + module MatchersMatchers2,12 + def include(*expected)include19,594 + def helper(actual, *_expected_)helper25,761 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/match.rb,90 +module SpecSpec1,0 + module MatchersMatchers2,12 + def match(expected)match13,324 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/match_array.rb,519 +module SpecSpec1,0 + module MatchersMatchers2,12 + class MatchArray #:nodoc:MatchArray4,31 + def initialize(expected)initialize7,105 + def matches?(actual)matches?11,176 + def failure_message_for_shouldfailure_message_for_should18,439 + def failure_message_for_should_notfailure_message_for_should_not26,921 + def descriptiondescription30,1025 + def safe_sort(array)safe_sort36,1127 + def difference_between_arrays(array_1, array_2)difference_between_arrays40,1242 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/matcher.rb,1031 +module SpecSpec1,0 + module MatchersMatchers2,12 + class MatcherMatcher3,30 + def initialize(name, *expected, &declarations)initialize10,196 + def matches?(actual)matches?27,965 + def match(&block)match46,1419 + def match_unless_raises(exception=Exception, &block)match_unless_raises51,1510 + def failure_message_for_should(&block)failure_message_for_should57,1669 + def failure_message_for_should_not(&block)failure_message_for_should_not62,1818 + def description(&block)description67,1975 + def diffable?diffable?72,2139 + def diffablediffable77,2215 + def chain(method, &block)chain82,2303 + def making_declared_methods_public # :nodoc:making_declared_methods_public93,2507 + def cache_or_call_cached(key, &block)cache_or_call_cached110,3413 + def cache(key, &block)cache114,3522 + def call_cached(key)call_cached118,3593 + def name_to_sentencename_to_sentence122,3718 + def expected_to_sentenceexpected_to_sentence126,3783 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/method_missing.rb,126 +module SpecSpec1,0 + module MatchersMatchers2,12 + def method_missing(sym, *args, &block) # :nodoc:method_missing3,30 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/operator_matcher.rb,914 +module SpecSpec1,0 + module MatchersMatchers2,12 + class OperatorMatcherOperatorMatcher4,31 + def registryregistry6,77 + def register(klass, operator, matcher)register10,138 + def get(klass, operator)get15,277 + def initialize(actual)initialize25,604 + def self.use_custom_matcher_or_delegate(operator)use_custom_matcher_or_delegate29,669 + def fail_with_message(message)fail_with_message43,1147 + def descriptiondescription47,1261 + def eval_match(actual, operator, expected)eval_match53,1363 + class PositiveOperatorMatcher < OperatorMatcher #:nodoc:PositiveOperatorMatcher61,1583 + def __delegate_operator(actual, operator, expected)__delegate_operator62,1644 + class NegativeOperatorMatcher < OperatorMatcher #:nodoc:NegativeOperatorMatcher74,2103 + def __delegate_operator(actual, operator, expected)__delegate_operator75,2164 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/pretty.rb,229 +module SpecSpec1,0 + module MatchersMatchers2,12 + module PrettyPretty3,30 + def split_words(sym)split_words4,48 + def to_sentence(words=[])to_sentence8,117 + def _pretty_print(array)_pretty_print22,451 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/raise_exception.rb,809 +module SpecSpec1,0 + module MatchersMatchers2,12 + class RaiseException #:nodoc:RaiseException3,30 + def initialize(expected_exception_or_message=Exception, expected_message=nil, &block)initialize4,64 + def matches?(given_proc)matches?15,509 + def eval_blockeval_block38,1423 + def verify_messageverify_message48,1646 + def failure_message_for_shouldfailure_message_for_should59,1904 + def failure_message_for_should_notfailure_message_for_should_not63,2053 + def descriptiondescription67,2167 + def expected_exceptionexpected_exception72,2252 + def given_exceptiongiven_exception83,2590 + def negative_expectation?negative_expectation?87,2731 + def raise_exception(exception=Exception, message=nil, &block)raise_exception125,4844 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/respond_to.rb,625 +module SpecSpec1,0 + module MatchersMatchers2,12 + class RespondTo #:nodoc:RespondTo4,35 + def initialize(*names)initialize5,64 + def matches?(actual)matches?11,200 + def failure_message_for_shouldfailure_message_for_should19,463 + def failure_message_for_should_notfailure_message_for_should_not23,651 + def descriptiondescription27,817 + def with(n)with31,902 + def argumentargument36,978 + def matches_arity?(actual, name)matches_arity?43,1079 + def with_aritywith_arity47,1218 + def pp_namespp_names52,1371 + def respond_to(*names)respond_to67,1823 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/satisfy.rb,378 +module SpecSpec1,0 + module MatchersMatchers2,12 + class Satisfy #:nodoc:Satisfy4,35 + def initialize(&block)initialize5,62 + def matches?(actual, &block)matches?9,131 + def failure_message_for_shouldfailure_message_for_should15,268 + def failure_message_for_should_notfailure_message_for_should_not19,363 + def satisfy(&block)satisfy43,1051 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/simple_matcher.rb,513 +module SpecSpec1,0 + module MatchersMatchers2,12 + class SimpleMatcherSimpleMatcher3,30 + def initialize(description, &match_block)initialize6,137 + def matches?(given)matches?12,325 + def descriptiondescription22,541 + def failure_message_for_shouldfailure_message_for_should26,610 + def failure_message_for_should_notfailure_message_for_should_not30,784 + def explanationexplanation34,983 + def simple_matcher(description=nil, &match_block)simple_matcher129,4795 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/throw_symbol.rb,571 +module SpecSpec1,0 + module MatchersMatchers2,12 + class ThrowSymbol #:nodoc:ThrowSymbol4,31 + def initialize(expected_symbol = nil, expected_arg=nil)initialize5,62 + def matches?(given_proc)matches?11,258 + def failure_message_for_shouldfailure_message_for_should40,1250 + def failure_message_for_should_notfailure_message_for_should_not48,1469 + def descriptiondescription56,1679 + def expectedexpected62,1755 + def argsargs66,1873 + def throw_symbol(expected_symbol = nil, expected_arg=nil)throw_symbol96,2972 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/wrap_expectation.rb,120 +module SpecSpec1,0 + module MatchersMatchers2,12 + def wrap_expectation(matcher, &block)wrap_expectation45,1475 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers.rb,65 +module SpecSpec30,960 + module Matchers; endMatchers213,7067 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/argument_expectation.rb,488 +module SpecSpec1,0 + module MocksMocks2,12 + class ArgumentExpectationArgumentExpectation4,32 + def initialize(args, &block)initialize7,93 + def matcher_for(arg)matcher_for22,526 + def is_matcher?(obj)is_matcher?28,782 + def args_match?(given_args)args_match?32,900 + def matchers_block_matches?(given_args)matchers_block_matches?36,1045 + def matchers_match?(given_args)matchers_match?40,1174 + def match_any_args?match_any_args?44,1261 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/argument_matchers.rb,2251 +module SpecSpec1,0 + module MocksMocks2,12 + module ArgumentMatchersArgumentMatchers10,336 + class AnyArgsMatcherAnyArgsMatcher12,365 + def descriptiondescription13,392 + class NoArgsMatcherNoArgsMatcher18,460 + def descriptiondescription19,486 + class AnyArgMatcherAnyArgMatcher24,553 + def initialize(ignore)initialize25,579 + def ==(other)==28,623 + def descriptiondescription32,681 + class RegexpMatcherRegexpMatcher37,749 + def initialize(regexp)initialize38,775 + def ==(value)==42,846 + class BooleanMatcherBooleanMatcher48,979 + def initialize(ignore)initialize49,1006 + def ==(value)==52,1050 + class HashIncludingMatcherHashIncludingMatcher57,1149 + def initialize(expected)initialize58,1182 + def ==(actual)==62,1259 + def descriptiondescription71,1502 + class HashNotIncludingMatcherHashNotIncludingMatcher76,1632 + def initialize(expected)initialize77,1668 + def ==(actual)==81,1745 + def descriptiondescription90,1984 + class DuckTypeMatcherDuckTypeMatcher95,2118 + def initialize(*methods_to_respond_to)initialize96,2146 + def ==(value)==100,2263 + class MatcherMatcherMatcherMatcher105,2379 + def initialize(matcher)initialize106,2406 + def ==(value)==110,2480 + class EqualityProxyEqualityProxy115,2560 + def initialize(given)initialize116,2586 + def ==(expected)==120,2654 + class InstanceOfInstanceOf125,2737 + def initialize(klass)initialize126,2760 + def ==(actual)==130,2836 + class KindOfKindOf135,2926 + def initialize(klass)initialize136,2945 + def ==(actual)==140,3021 + def no_argsno_args149,3251 + def any_argsany_args158,3547 + def anythinganything166,3744 + def duck_type(*args)duck_type182,4241 + def booleanboolean190,4442 + def hash_including(*args)hash_including200,4914 + def hash_not_including(*args)hash_not_including210,5393 + def instance_of(klass)instance_of215,5556 + def kind_of(klass)kind_of222,5726 + def anythingize_lonely_keys(*args)anythingize_lonely_keys230,5860 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/error_generator.rb,1152 +module SpecSpec1,0 + module MocksMocks2,12 + class ErrorGeneratorErrorGenerator3,27 + def initialize(target, name, options={})initialize6,83 + def optsopts12,250 + def raise_unexpected_message_error(sym, *args)raise_unexpected_message_error16,297 + def raise_unexpected_message_args_error(expectation, *args)raise_unexpected_message_args_error20,451 + def raise_expectation_error(sym, expected_received_count, actual_received_count, *args)raise_expectation_error26,814 + def raise_out_of_order_error(sym)raise_out_of_order_error30,1089 + def raise_block_failed_error(sym, detail)raise_block_failed_error34,1203 + def raise_missing_block_error(args_to_yield)raise_missing_block_error38,1352 + def raise_wrong_arity_error(args_to_yield, arity)raise_wrong_arity_error42,1516 + def introintro48,1699 + def __raise(message)__raise62,2002 + def arg_message(*args)arg_message67,2172 + def format_args(*args)format_args71,2256 + def arg_list(*args)arg_list75,2360 + def count_message(count)count_message79,2505 + def pretty_print(count)pretty_print84,2648 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/errors.rb,189 +module SpecSpec1,0 + module MocksMocks2,12 + class MockExpectationError < ExceptionMockExpectationError3,27 + class AmbiguousReturnError < StandardErrorAmbiguousReturnError6,83 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/example_methods.rb,432 +module SpecSpec1,0 + module MocksMocks2,12 + module ExampleMethodsExampleMethods3,27 + def double(*args)double23,764 + def mock(*args)mock28,866 + def stub(*args)stub33,964 + def __declare_double(declared_as, *args) # :nodoc:__declare_double37,1037 + def stub_everything(name = 'stub')stub_everything48,1486 + def allow_message_expectations_on_nilallow_message_expectations_on_nil63,2089 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/extensions/object.rb,24 +class ObjectObject1,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/extensions.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/framework.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/message_expectation.rb,2929 +module SpecSpec1,0 + module MocksMocks2,12 + class BaseExpectationBaseExpectation4,28 + def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={}, &implementation)initialize11,316 + def build_child(expected_from, method_block, expected_received_count, opts={})build_child33,1185 + def expected_argsexpected_args46,1667 + def and_return(*values, &return_block)and_return50,1733 + def and_raise(exception=Exception)and_raise75,2702 + def and_throw(symbol)and_throw79,2794 + def and_yield(*args, &block)and_yield83,2867 + def matches(sym, args)matches99,3290 + def invoke(*args, &block)invoke103,3390 + def called_max_times?called_max_times?137,4465 + def invoke_return_block(*args, &block)invoke_return_block142,4641 + def invoke_method_block(*args)invoke_method_block152,5010 + def invoke_with_yield(&block)invoke_with_yield160,5218 + def eval_block(*args, &block)eval_block174,5716 + def invoke_consecutive_return_block(*args, &block)invoke_consecutive_return_block182,5894 + def clone_args_to_yield(args)clone_args_to_yield188,6093 + def failed_fast?failed_fast?193,6218 + class MessageExpectation < BaseExpectationMessageExpectation198,6281 + def matches_name?(sym)matches_name?200,6329 + def matches_name_but_not_args(sym, args)matches_name_but_not_args204,6389 + def verify_messages_receivedverify_messages_received208,6518 + def expected_messages_received?expected_messages_received?217,6784 + def ignoring_args?ignoring_args?222,6944 + def matches_at_least_count?matches_at_least_count?226,7021 + def matches_at_most_count?matches_at_most_count?230,7138 + def matches_exact_count?matches_exact_count?234,7253 + def similar_messagessimilar_messages238,7354 + def advise(args, block)advise242,7425 + def generate_errorgenerate_error246,7499 + def with(*args, &block)with254,7816 + def exactly(n)exactly259,7936 + def at_least(n)at_least264,8029 + def at_most(n)at_most269,8124 + def times(&block)times274,8217 + def any_number_of_times(&block)any_number_of_times279,8304 + def nevernever285,8445 + def once(&block)once290,8522 + def twice(&block)twice296,8645 + def ordered(&block)ordered302,8769 + def negative_expectation_for?(sym)negative_expectation_for?309,8918 + def set_expected_received_count(relativity, n)set_expected_received_count314,9007 + def clear_actual_received_count!clear_actual_received_count!327,9347 + class NegativeMessageExpectation < MessageExpectationNegativeMessageExpectation333,9447 + def initialize(message, expectation_ordering, expected_from, sym, method_block)initialize334,9505 + def negative_expectation_for?(sym)negative_expectation_for?338,9684 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/methods.rb,687 +module SpecSpec1,0 + module MocksMocks2,12 + module MethodsMethods3,27 + def should_receive(sym, opts={}, &block)should_receive4,46 + def should_not_receive(sym, &block)should_not_receive8,213 + def stub!(sym_or_hash, opts={}, &block)stub!12,360 + def unstub!(message)unstub!22,671 + def stub_chain(*methods)stub_chain43,1479 + def as_null_objectas_null_object63,2116 + def null_object?null_object?67,2194 + def received_message?(sym, *args, &block) #:nodoc:received_message?71,2268 + def rspec_verify #:nodoc:rspec_verify75,2408 + def rspec_reset #:nodoc:rspec_reset79,2479 + def __mock_proxy__mock_proxy85,2561 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/mock.rb,504 +module SpecSpec1,0 + module MocksMocks2,12 + class MockMock3,27 + def initialize(name=nil, stubs_and_options={})initialize10,309 + def ==(other)==25,874 + def inspectinspect29,935 + def to_sto_s33,1048 + def method_missing(sym, *args, &block)method_missing39,1131 + def extract_options(stubs_and_options)extract_options49,1453 + def extract_option(source, target, key, default=nil)extract_option56,1692 + def assign_stubs(stubs)assign_stubs64,1894 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/order_group.rb,346 +module SpecSpec1,0 + module MocksMocks2,12 + class OrderGroupOrderGroup3,27 + def initialize error_generatorinitialize4,48 + def register(expectation)register9,175 + def ready_for?(expectation)ready_for?13,257 + def consumeconsume17,354 + def handle_order_constraint expectationhandle_order_constraint21,413 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/proxy.rb,2917 +module SpecSpec1,0 + module MocksMocks2,12 + class ProxyProxy3,27 + def self.allow_message_expectations_on_nilallow_message_expectations_on_nil10,168 + def initialize(target, name=nil, options={})initialize18,501 + def null_object?null_object?31,976 + def as_null_objectas_null_object35,1047 + def add_message_expectation(expected_from, sym, opts={}, &block) add_message_expectation40,1137 + def build_expectation(expected_from, sym, opts, &block)build_expectation47,1379 + def add_negative_message_expectation(expected_from, sym, &block)add_negative_message_expectation55,1736 + def add_stub(expected_from, sym, opts={}, &implementation)add_stub62,2038 + def remove_stub(message)remove_stub68,2294 + def verify #:nodoc:verify78,2660 + def resetreset84,2752 + def received_message?(sym, *args, &block)received_message?92,2925 + def has_negative_expectation?(sym)has_negative_expectation?96,3054 + def record_message_received(sym, args, block)record_message_received100,3198 + def message_received(sym, *args, &block)message_received104,3310 + def record_stub(stub, sym, args, &block)record_stub121,3989 + def invoke_expectation(expectation, *args, &block)invoke_expectation128,4181 + def record_almost_matching_expectation(expectation, sym, *args, &block)record_almost_matching_expectation132,4291 + def ok_to_invoke_stub?(stub, expectation)ok_to_invoke_stub?139,4562 + def raise_unexpected_message_args_error(expectation, *args)raise_unexpected_message_args_error143,4685 + def raise_unexpected_message_error(sym, *args)raise_unexpected_message_error147,4842 + def find_matching_method_stub(sym, *args)find_matching_method_stub151,4979 + def __add(sym)__add157,5110 + def warn_if_nil_class(sym)warn_if_nil_class162,5243 + def define_expected_method(sym)define_expected_method168,5534 + def target_responds_to?(sym)target_responds_to?187,6187 + def visibility(sym)visibility193,6440 + def munge(sym)munge205,6732 + def clear_expectationsclear_expectations209,6799 + def clear_stubsclear_stubs213,6867 + def clear_proxied_methodsclear_proxied_methods217,6921 + def target_metaclasstarget_metaclass221,6995 + def verify_expectationsverify_expectations225,7069 + def reset_proxied_methodsreset_proxied_methods229,7169 + def reset_proxied_method(sym)reset_proxied_method233,7275 + def proxy_for_nil_class?proxy_for_nil_class?244,7575 + def reset_nil_expectations_warningreset_nil_expectations_warning248,7644 + def find_matching_expectation(sym, *args)find_matching_expectation252,7768 + def almost_matching_expectation(sym, *args, &block)almost_matching_expectation257,8013 + def find_almost_matching_expectation(sym, *args)find_almost_matching_expectation263,8172 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/space.rb,206 +module SpecSpec1,0 + module MocksMocks2,12 + class SpaceSpace3,27 + def add(obj)add4,43 + def verify_allverify_all8,133 + def reset_allreset_all14,240 + def mocksmocks23,382 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks.rb,52 +module SpecSpec4,71 + module MocksMocks198,9045 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/rake/spectask.rb,492 +module SpecSpec8,113 + module RakeRake9,125 + class SpecTask < ::Rake::TaskLibSpecTask57,1883 + def self.attr_accessor(*names)attr_accessor58,1920 + def initialize(name=:spec)initialize126,4596 + def define # :nodoc:define144,5089 + def rcov_option_list # :nodoc:rcov_option_list197,7137 + def spec_option_list # :nodoc:spec_option_list205,7295 + def evaluate(o) # :nodoc:evaluate210,7547 + def spec_file_list # :nodoc:spec_file_list217,7666 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/rake/verify_rcov.rb,159 +module RCovRCov1,0 + class VerifyTask < Rake::TaskLibVerifyTask5,163 + def initialize(name=:verify_rcov)initialize25,856 + def definedefine35,1129 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/ruby.rb,76 +module SpecSpec1,0 + module RubyRuby2,12 + def versionversion4,44 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/backtrace_tweaker.rb,708 +module SpecSpec1,0 + module RunnerRunner2,12 + class BacktraceTweakerBacktraceTweaker3,28 + def initialize(*patterns)initialize4,55 + def clean_up_double_slashes(line)clean_up_double_slashes8,128 + def ignore_patterns(*patterns)ignore_patterns12,208 + def ignored_patternsignored_patterns16,323 + def tweak_backtrace(error)tweak_backtrace20,372 + class NoisyBacktraceTweaker < BacktraceTweakerNoisyBacktraceTweaker35,862 + class QuietBacktraceTweaker < BacktraceTweakerQuietBacktraceTweaker39,1001 + def initialize(*patterns)initialize64,1842 + def ignore_patterns(*patterns)ignore_patterns69,1934 + def ignored_patternsignored_patterns73,2065 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/class_and_arguments_parser.rb,147 +module SpecSpec1,0 + module RunnerRunner2,12 + class ClassAndArgumentsParserClassAndArgumentsParser3,28 + def self.parse(s)parse4,62 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/command_line.rb,151 +module SpecSpec3,37 + module RunnerRunner4,49 + class CommandLineCommandLine5,65 + def self.run(tmp_options=Spec::Runner.options)run6,87 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/configuration.rb,1433 +module SpecSpec1,0 + module RunnerRunner2,12 + class ConfigurationConfiguration3,28 + def mock_with(mock_framework)mock_with33,1164 + def mock_framework # :nodoc:mock_framework42,1384 + def include(*modules_and_options)include79,2921 + def extend(*modules_and_options)extend90,3305 + def append_before(scope = :each, options={}, &proc)append_before100,3859 + def prepend_before(scope = :each, options={}, &proc)prepend_before108,4169 + def prepend_after(scope = :each, options={}, &proc)prepend_after115,4443 + def append_after(scope = :each, options={}, &proc)append_after123,4756 + def predicate_matcherspredicate_matchers137,5194 + def ignore_backtrace_patterns(*patterns)ignore_backtrace_patterns149,5718 + def ignored_backtrace_patterns # :nodoc:ignored_backtrace_patterns154,5867 + def suppress_deprecation_warnings!suppress_deprecation_warnings!158,5968 + def suppress_deprecation_warnings?suppress_deprecation_warnings?162,6066 + def include_or_extend(action, *args)include_or_extend168,6190 + def add_callback(sym, *args, &proc)add_callback178,6619 + def get_type_from_options(options)get_type_from_options184,6863 + def mock_framework_path(framework_name)mock_framework_path188,6970 + def scope_and_options(*args) # :nodoc:scope_and_options192,7085 + def scope_from(*args) # :nodoc:scope_from197,7231 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/differs/default.rb,473 +module SpecSpec4,58 + module ExpectationsExpectations5,70 + module DiffersDiffers6,92 + class DefaultDefault8,171 + def initialize(options)initialize9,193 + def diff_as_string(data_new, data_old)diff_as_string14,354 + def diff_as_object(target,expected)diff_as_object45,1671 + def diff_as_hash(target, expected)diff_as_hash49,1807 + def formatformat81,3054 + def context_linescontext_lines85,3123 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/differs/load-diff-lcs.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/drb_command_line.rb,175 +module SpecSpec3,19 + module RunnerRunner4,31 + class DrbCommandLineDrbCommandLine6,103 + def self.port(options)port8,129 + def self.run(options)run14,388 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/example_group_runner.rb,455 +module SpecSpec1,0 + module RunnerRunner2,12 + class ExampleGroupRunnerExampleGroupRunner3,28 + def initialize(options)initialize4,57 + def load_files(files)load_files8,125 + def runrun19,552 + def prepareprepare31,779 + def finishfinish36,894 + def reporterreporter41,965 + def reversereverse45,1021 + def example_groupsexample_groups49,1075 + def number_of_examplesnumber_of_examples53,1143 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/extensions/kernel.rb,66 +module KernelKernel1,0 + def debugger(steps=1)debugger4,132 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/base_formatter.rb,1014 +module SpecSpec1,0 + module RunnerRunner2,12 + module FormatterFormatter3,28 + class BaseFormatterBaseFormatter5,147 + def initialize(options, output)initialize26,1024 + def start(example_count)start38,1537 + def example_group_started(example_group_proxy)example_group_started47,1867 + def add_example_group(example_group_proxy)add_example_group51,2000 + def example_started(example_proxy)example_started62,2495 + def example_passed(example_proxy)example_passed71,2835 + def example_failed(example_proxy, counter, failure)example_failed85,3362 + def example_pending(example_proxy, message, deprecated_pending_location=nil)example_pending100,4054 + def start_dumpstart_dump105,4329 + def dump_failure(counter, failure)dump_failure116,4838 + def dump_summary(duration, example_count, failure_count, pending_count)dump_summary126,5248 + def dump_pendingdump_pending130,5395 + def closeclose134,5544 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/base_text_formatter.rb,1482 +module SpecSpec4,68 + module RunnerRunner5,80 + module FormatterFormatter6,96 + class BaseTextFormatter < BaseFormatterBaseTextFormatter10,275 + def initialize(options, output)initialize16,625 + def example_group_started(example_group_proxy)example_group_started27,926 + def example_pending(example, message, deprecated_pending_location=nil)example_pending31,1049 + def dump_failure(counter, failure)dump_failure35,1264 + def colorize_failure(message, failure)colorize_failure43,1586 + def colourise(message, failure)colourise47,1718 + def dump_summary(duration, example_count, failure_count, pending_count)dump_summary52,1901 + def dump_pendingdump_pending73,2612 + def closeclose85,3001 + def format_backtrace(backtrace)format_backtrace89,3108 + def colour?colour?96,3289 + def dry_run?dry_run?100,3350 + def autospec?autospec?104,3421 + def backtrace_line(line)backtrace_line108,3522 + def colour(text, colour_code)colour112,3613 + def output_to_file?output_to_file?118,3838 + def output_to_tty?output_to_tty?122,3914 + def green(text); colour(text, "\e[32m"); endgreen130,4066 + def red(text); colour(text, "\e[31m"); endred131,4119 + def yellow(text); colour(text, "\e[33m"); endyellow132,4170 + def blue(text); colour(text, "\e[34m"); endblue133,4224 + def magenta(text)magenta135,4285 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/failing_example_groups_formatter.rb,422 +module SpecSpec3,53 + module RunnerRunner4,65 + module FormatterFormatter5,81 + class FailingExampleGroupsFormatter < BaseTextFormatterFailingExampleGroupsFormatter6,102 + def example_failed(example, counter, failure)example_failed7,164 + def dump_failure(counter, failure)dump_failure16,417 + def dump_summary(duration, example_count, failure_count, pending_count)dump_summary19,473 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/failing_examples_formatter.rb,418 +module SpecSpec3,53 + module RunnerRunner4,65 + module FormatterFormatter5,81 + class FailingExamplesFormatter < BaseTextFormatter FailingExamplesFormatter6,102 + def example_failed(example, counter, failure)example_failed7,165 + def dump_failure(counter, failure)dump_failure12,333 + def dump_summary(duration, example_count, failure_count, pending_count)dump_summary15,389 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/html_formatter.rb,1320 +module SpecSpec5,120 + module RunnerRunner6,132 + module FormatterFormatter7,148 + class HtmlFormatter < BaseTextFormatterHtmlFormatter8,169 + def initialize(options, output)initialize12,304 + def example_group_numberexample_group_number20,535 + def example_numberexample_number25,694 + def start(example_count)start29,768 + def example_group_started(example_group)example_group_started37,952 + def start_dumpstart_dump51,1454 + def example_started(example)example_started57,1579 + def example_passed(example)example_passed61,1660 + def example_failed(example, counter, failure)example_failed67,1883 + def example_pending(example, message, deprecated_pending_location=nil)example_pending86,3106 + def extra_failure_content(failure)extra_failure_content97,3874 + def move_progressmove_progress103,4156 + def percent_donepercent_done108,4326 + def dump_failure(counter, failure)dump_failure116,4539 + def dump_summary(duration, example_count, failure_count, pending_count)dump_summary119,4595 + def html_header html_header135,5444 + def report_headerreport_header168,6214 + def global_scriptsglobal_scripts187,6510 + def global_stylesglobal_styles212,7294 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/nested_text_formatter.rb,596 +module SpecSpec3,53 + module RunnerRunner4,65 + module FormatterFormatter5,81 + class NestedTextFormatter < BaseTextFormatterNestedTextFormatter6,102 + def initialize(options, where)initialize10,178 + def example_group_started(example_group)example_group_started15,287 + def example_failed(example, counter, failure)example_failed27,711 + def example_passed(example)example_passed32,898 + def example_pending(example, message, deprecated_pending_location=nil)example_pending38,1074 + def current_indentationcurrent_indentation44,1304 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/no_op_method_missing.rb,275 +module SpecSpec1,0 + module RunnerRunner2,12 + module FormatterFormatter3,28 + module NOOPMethodMissingNOOPMethodMissing4,49 + def respond_to?(message, include_private = false)respond_to?5,80 + def method_missing(sym, *args)method_missing15,332 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/profile_formatter.rb,414 +module SpecSpec3,56 + module RunnerRunner4,68 + module FormatterFormatter5,84 + class ProfileFormatter < ProgressBarFormatterProfileFormatter6,105 + def initialize(options, where)initialize8,166 + def start(count)start13,272 + def example_started(example)example_started17,362 + def example_passed(example)example_passed21,447 + def start_dumpstart_dump30,663 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/progress_bar_formatter.rb,446 +module SpecSpec4,106 + module RunnerRunner5,118 + module FormatterFormatter6,134 + class ProgressBarFormatter < BaseTextFormatterProgressBarFormatter7,155 + def example_failed(example, counter, failure)example_failed10,243 + def example_passed(example)example_passed15,389 + def example_pending(example, message, deprecated_pending_location=nil)example_pending20,503 + def start_dumpstart_dump26,679 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/silent_formatter.rb,151 +module SpecSpec3,48 + module RunnerRunner4,60 + module FormatterFormatter5,76 + class SilentFormatter < BaseFormatterSilentFormatter6,97 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/snippet_extractor.rb,472 +module SpecSpec1,0 + module RunnerRunner2,12 + module FormatterFormatter3,28 + class SnippetExtractor #:nodoc:SnippetExtractor5,139 + class NullConverter; def convert(code, pre); code; end; end #:nodoc:NullConverter6,177 + def snippet(error)snippet9,430 + def snippet_for(error_line)snippet_for16,784 + def lines_around(file, line)lines_around26,1064 + def post_process(highlighted, offending_line)post_process39,1473 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/specdoc_formatter.rb,471 +module SpecSpec3,53 + module RunnerRunner4,65 + module FormatterFormatter5,81 + class SpecdocFormatter < BaseTextFormatterSpecdocFormatter6,102 + def example_group_started(example_group)example_group_started7,151 + def example_failed(example, counter, failure)example_failed14,328 + def example_passed(example)example_passed19,503 + def example_pending(example, message, deprecated_pending_location=nil)example_pending25,667 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/text_mate_formatter.rb,210 +module SpecSpec3,48 + module RunnerRunner4,60 + module FormatterFormatter5,76 + class TextMateFormatter < HtmlFormatterTextMateFormatter7,157 + def backtrace_line(line)backtrace_line8,203 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/heckle_runner.rb,604 + module SpecSpec7,191 + module RunnerRunner8,205 + class HeckleRunnerHeckleRunner11,337 + def initialize(filter, heckle_class=Heckler)initialize12,362 + def heckle_withheckle_with19,625 + def heckle_method(class_name, method_name)heckle_method27,815 + def heckle_class_or_module(class_or_module_name)heckle_class_or_module33,1033 + def verify_constant(name)verify_constant49,1602 + class Heckler < HeckleHeckler59,1857 + def initialize(klass_name, method_name, rspec_options)initialize60,1886 + def tests_pass?tests_pass?65,2044 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/heckle_runner_unsupported.rb,137 +module SpecSpec1,0 + module RunnerRunner2,12 + class HeckleRunnerHeckleRunner4,120 + def initialize(filter)initialize5,143 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/line_number_query.rb,766 +module SpecSpec1,0 + module RunnerRunner2,12 + class LineNumberQueryLineNumberQuery4,108 + def initialize(run_options)initialize7,165 + def spec_name_for(file, line_number)spec_name_for12,270 + def example_line_for(file, line_number)example_line_for27,718 + def determine_best_match(file, line_number)determine_best_match34,872 + def consider_example_group_for_best_match(example_group, file, line_number)consider_example_group_for_best_match47,1348 + def consider_example_for_best_match(example, example_group, file, line_number)consider_example_for_best_match56,1755 + def is_best_match?(file, line_number, example_file, example_line)is_best_match?66,2170 + def parse_location(location)parse_location72,2410 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/option_parser.rb,745 +module SpecSpec4,39 + module RunnerRunner5,51 + class OptionParser < ::OptionParserOptionParser6,67 + def parse(args, err, out)parse8,127 + def spec_command?spec_command?14,261 + def initialize(err, out)initialize88,6998 + def order!(argv, &blk)order!123,8994 + def invoke_requires(requires)invoke_requires149,9635 + def parse_file_options(option_name, action)parse_file_options155,9760 + def parse_options_file(options_file)parse_options_file181,10520 + def write_options_file(options_file)write_options_file186,10704 + def parse_drbparse_drb195,11053 + def parse_versionparse_version210,11507 + def parse_helpparse_help215,11616 + def stdout?stdout?220,11702 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/options.rb,2495 +module SpecSpec4,38 + module RunnerRunner5,50 + class OptionsOptions6,66 + def initialize(error_stream, output_stream)initialize56,2952 + def add_example_group(example_group)add_example_group80,3668 + def line_number_requested?line_number_requested?84,3763 + def example_lineexample_line88,3829 + def remove_example_group(example_group)remove_example_group92,3954 + def require_ruby_debugrequire_ruby_debug96,4057 + def project_root # :nodoc:project_root101,4179 + def determine_project_root # :nodoc:determine_project_root106,4299 + def add_dir_from_project_root_to_load_path(dir, load_path=$LOAD_PATH) # :nodoc:add_dir_from_project_root_to_load_path117,4668 + def run_examplesrun_examples123,4920 + def before_suite_partsbefore_suite_parts165,6291 + def after_suite_partsafter_suite_parts169,6393 + def examples_run?examples_run?173,6493 + def examples_should_not_be_runexamples_should_not_be_run177,6550 + def mock_frameworkmock_framework181,6638 + def colour=(colour)colour=186,6806 + def parse_diff(format)parse_diff201,7350 + def parse_example(example)parse_example215,7743 + def parse_format(format_arg)parse_format223,7944 + def formattersformatters234,8329 + def load_formatters(format_options, formatters)load_formatters239,8497 + def formatter_optionsformatter_options251,8920 + def which_heckle_runnerwhich_heckle_runner259,9111 + def load_heckle_runner(heckle)load_heckle_runner263,9317 + def number_of_examplesnumber_of_examples269,9524 + def files_to_loadfiles_to_load274,9696 + def dry_run?dry_run?290,10143 + def drb_portdrb_port294,10198 + def define_predicate_matchersdefine_predicate_matchers300,10295 + def plugin_mock_frameworkplugin_mock_framework308,10630 + def ignore_backtrace_patternsignore_backtrace_patterns318,10942 + def examples_should_be_run?examples_should_be_run?322,11086 + def differ_class=(klass)differ_class=327,11245 + def load_class(name, kind, option)load_class333,11409 + def custom_runnercustom_runner351,12030 + def custom_runner?custom_runner?358,12308 + def heckleheckle362,12396 + def sorted_filessorted_files368,12534 + def sortersorter372,12620 + def default_differdefault_differ376,12677 + def set_spec_from_line_numberset_spec_from_line_number381,12826 + def stderr?stderr?401,13572 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/reporter.rb,1320 +module SpecSpec1,0 + module RunnerRunner2,12 + class ReporterReporter3,28 + def initialize(options)initialize6,81 + def example_group_started(example_group)example_group_started16,315 + def example_started(example)example_started23,510 + def example_finished(example, error=nil)example_finished27,618 + def example_failed(example, error)example_failed39,962 + def start(number_of_examples)start48,1284 + def endend53,1421 + def dumpdump58,1544 + class FailureFailure69,1826 + def initialize(group_description, example_description, exception) # :nodoc:initialize70,1846 + def headerheader89,2714 + def pending_fixed? # :nodoc:pending_fixed?99,2988 + def expectation_not_met? # :nodoc:expectation_not_met?103,3106 + def formattersformatters110,3257 + def backtrace_tweakerbacktrace_tweaker114,3317 + def dump_failuresdump_failures118,3393 + def dump_pendingdump_pending126,3605 + def durationduration130,3683 + def example_passed(example)example_passed135,3823 + def example_pending(example, ignore, message="Not Yet Implemented")example_pending153,4557 + def formatter_uses_deprecated_example_pending_method?(formatter)formatter_uses_deprecated_example_pending_method?165,5018 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner.rb,440 +module SpecSpec13,420 + module RunnerRunner14,432 + class ExampleGroupCreationListenerExampleGroupCreationListener16,453 + def register_example_group(klass)register_example_group17,492 + def configuration # :nodoc:configuration25,739 + def configureconfigure40,1210 + def autorun # :nodoc:autorun44,1275 + def options # :nodoc:options48,1351 + def use optionsuse56,1558 + def runrun60,1618 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/stubs/cucumber.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/test/unit.rb,75 +module SpecSpec5,144 + module TestTest6,156 + module UnitUnit7,170 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/version.rb,71 +module Spec # :nodoc:Spec1,0 + module VERSION # :nodoc:VERSION2,22 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/resources/helpers/cmdline.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/autotest_helper.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/autotest_matchers.rb,365 +module SpecSpec1,0 + module MatchersMatchers2,12 + class AutotestMappingMatcherAutotestMappingMatcher3,30 + def initialize(specs)initialize4,63 + def to(file)to8,127 + def matches?(autotest)matches?13,193 + def failure_messagefailure_message19,348 + def prepare(autotest)prepare25,507 + def map_specs(specs)map_specs33,677 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/discover_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/failed_results_re_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/rspec_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/ruby_forker.rb,74 +module RubyForkerRubyForker3,20 + def ruby(args, stderr=nil)ruby6,145 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/dsl/main_spec.rb,266 +module SpecSpec3,23 + module DSLDSL4,35 + module Foo; module Bar; end; endFoo45,1591 + module FooFoo52,1834 + module BarBar53,1855 + def self.next_group_namenext_group_name61,2014 + def group_namegroup_name67,2161 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_class_definition_spec.rb,159 +module SpecSpec3,23 + module ExampleExample4,35 + class ExampleGroupSubclass < ExampleGroupExampleGroupSubclass5,52 + def a_methoda_method21,393 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_factory_spec.rb,178 +module SpecSpec3,23 + module ExampleExample4,35 + def initialize(*args, &block)initialize40,1343 + def shared_example_groupshared_example_group132,5816 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_methods_spec.rb,1398 +module SpecSpec3,23 + module ExampleExample4,35 + def test_any_args(*args)test_any_args164,6322 + def test_somethingtest_something167,6415 + def testtest170,6496 + def testifytestify173,6585 + def should_somethingshould_something176,6677 + def shouldCamelCaseshouldCamelCase187,7071 + def should_any_args(*args)should_any_args190,7159 + def should_somethingshould_something193,7254 + def should_not_somethingshould_not_something196,7337 + def shouldshould199,7428 + def should_notshould_not202,7522 + def test_invalid(foo)test_invalid221,8226 + def testInvalidCamelCase(foo)testInvalidCamelCase224,8310 + def should_invalid(foo)should_invalid233,8645 + def shouldInvalidCamelCase(foo)shouldInvalidCamelCase236,8731 + def should_not_invalid(foo)should_not_invalid239,8825 + def should_validshould_valid242,8915 + def should_validshould_valid252,9234 + def self.specified_examplesspecified_examples576,21084 + def self.to_sto_s579,21174 + def initializeinitialize738,26883 + def countcount741,26957 + class CreatorCreator759,27366 + def self.countcount761,27417 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_proxy_spec.rb,81 +module SpecSpec3,23 + module ExampleExample4,35 + def proxyproxy11,232 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_spec.rb,340 +module SpecSpec3,23 + module ExampleExample4,35 + class ExampleModuleScopingSpec < ExampleGroupExampleModuleScopingSpec5,52 + module FooFoo8,157 + module BarBar9,174 + def self.loaded?; true; endloaded10,193 + class ExampleClassVariablePollutionSpec < ExampleGroupExampleClassVariablePollutionSpec27,549 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_matcher_spec.rb,52 +module SpecSpec3,23 + module ExampleExample4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_methods_spec.rb,446 +class ThingThing3,23 + def initialize(arg=nil)initialize5,54 + def ==(other)==8,113 + def eql?(other)eql?11,157 +module SpecSpec16,208 + module ExampleExample17,220 + module ModuleThatIsReopened; endModuleThatIsReopened19,268 + module Spec::Example::ExampleMethodsSpec21,308 + module ModuleThatIsReopenedModuleThatIsReopened25,399 + def module_that_is_reopened_method; endmodule_that_is_reopened_method26,433 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_proxy_spec.rb,52 +module SpecSpec3,23 + module ExampleExample4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/helper_method_spec.rb,95 +module HelperMethodExampleHelperMethodExample6,138 + def helper_methodhelper_method8,197 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/nested_example_group_spec.rb,80 +module SpecSpec3,23 + module ExampleExample4,35 + def countcount8,119 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/pending_module_spec.rb,51 +module SpecSpec1,0 + module ExampleExample2,12 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/predicate_matcher_spec.rb,131 +module SpecSpec3,23 + module ExampleExample4,35 + class FishFish5,52 + def can_swim?(distance_in_yards)can_swim?6,67 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/shared_example_group_spec.rb,123 +module SpecSpec3,23 + module ExampleExample4,35 + def a_shared_helper_methoda_shared_helper_method234,8656 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/subclassing_example_group_spec.rb,299 +module SpecSpec3,23 + module ExampleExample4,35 + class GrandParentExampleGroup < Spec::Example::ExampleGroupGrandParentExampleGroup5,52 + class ParentExampleGroup < GrandParentExampleGroupParentExampleGroup9,167 + class ChildExampleGroup < ParentExampleGroupChildExampleGroup15,303 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/subject_spec.rb,166 +module SpecSpec3,23 + module ExampleExample4,35 + def described_classdescribed_class56,1729 + def described_classdescribed_class60,1819 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/differs/default_spec.rb,167 +module SpecSpec3,23 + module FixturesFixtures4,35 + class AnimalAnimal5,53 + def initialize(name,species)initialize6,70 + def inspectinspect10,154 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/extensions/kernel_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/fail_with_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/handler_spec.rb,614 +module ExampleExpectationsExampleExpectations3,23 + class ArbitraryMatcherArbitraryMatcher5,53 + def initialize(*args, &block)initialize6,78 + def matches?(target)matches?14,265 + def with(new_value)with19,359 + def failure_messagefailure_message24,435 + def negative_failure_messagenegative_failure_message28,518 + class PositiveOnlyMatcher < ArbitraryMatcherPositiveOnlyMatcher33,618 + def arbitrary_matcher(*args, &block)arbitrary_matcher37,720 + def positive_only_matcher(*args, &block)positive_only_matcher41,808 +module SpecSpec47,908 + module ExpectationsExpectations48,920 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/wrap_expectation_spec.rb,145 +module SpecSpec3,23 + module MatchersMatchers4,35 + def stub_matcherstub_matcher8,134 + def failing_matcherfailing_matcher13,231 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_that_fails.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_that_passes.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_with_errors.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_with_options_hash.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_that_fails.rb,115 +class TestCaseThatFails < Test::Unit::TestCaseTestCaseThatFails6,162 + def test_that_failstest_that_fails7,209 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_that_passes.rb,119 +class TestCaseThatPasses < Test::Unit::TestCaseTestCaseThatPasses6,162 + def test_that_passestest_that_passes7,210 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_with_errors.rb,117 +class TestCaseWithErrors < Test::Unit::TestCaseTestCaseWithErrors6,162 + def test_with_errortest_with_error7,210 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_with_various_names.rb,293 +class TestCaseThatPasses < Test::Unit::TestCaseTestCaseThatPasses6,162 + def test_should_allow_underscoretest_should_allow_underscore7,210 + def testShouldAllowUppercaseLettertestShouldAllowUppercaseLetter11,268 + def testshouldallowlowercaselettertestshouldallowlowercaseletter15,328 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/testsuite_adapter_spec_with_test_unit.rb,101 +module TestTest6,162 + module UnitUnit7,174 + def create_adapter(group)create_adapter9,221 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/spec_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/test_unit_spec_helper.rb,127 +module TestUnitSpecHelperTestUnitSpecHelper4,45 + def resourcesresources7,93 + def run_script(file_name)run_script11,160 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/testcase_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/testsuite_adapter_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_close_spec.rb,54 +module SpecSpec2,22 + module MatchersMatchers3,34 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_instance_of_spec.rb,54 +module SpecSpec3,23 + module MatchersMatchers4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_kind_of_spec.rb,54 +module SpecSpec3,23 + module MatchersMatchers4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_spec.rb,154 + class ArrayDelegate < DelegateClass(Array)ArrayDelegate424,12478 + def initialize(array)initialize425,12525 + def large?large?430,12627 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/change_spec.rb,47 +class SomethingExpectedSomethingExpected4,61 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/compatibility_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/description_generation_spec.rb,209 + def teamteam139,4219 + def playersplayers141,4247 + def matchermatcher149,4358 + def matches?(ignore); true; endmatches?151,4390 + def failure_message; ""; endfailure_message152,4429 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/dsl_spec.rb,78 +module SpecSpec3,23 + module MatchersMatchers4,35 + module DSLDSL5,53 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/eql_spec.rb,54 +module SpecSpec3,23 + module MatchersMatchers4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/equal_spec.rb,102 +module SpecSpec2,22 + module MatchersMatchers3,34 + def inspect_object(o)inspect_object6,83 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/exist_spec.rb,277 +class SubstanceSubstance3,23 + def initialize exists, descriptioninitialize4,39 + def exist?(arg=nil)exist?8,134 + def inspectinspect11,174 +class SubstanceTesterSubstanceTester16,218 + def initialize substanceinitialize18,265 + def should_existshould_exist21,325 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/has_spec.rb,248 + def has_foo?has_foo?16,426 + def o.has_sym?(*args)has_sym32,836 + def has_foo?has_foo?46,1211 + def o.has_sym?(*args)has_sym66,1726 + def o.send(*args); raise "DOH! Library developers shouldn't use #send!" endsend185,6094 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/have_spec.rb,323 + def create_collection_owner_with(n)create_collection_owner_with5,51 + class InflectorInflector20,498 + def self.pluralize(string)pluralize21,522 + def self.pluralize(string)pluralize83,2683 + def itemsitems105,3253 + module SpecSpec344,12702 + module MatchersMatchers345,12716 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/include_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/match_array_spec.rb,189 +class UnsortableObjectUnsortableObject3,23 + def initialize(id)initialize4,46 + def inspectinspect8,87 + def ==(other)==12,121 + class SuperArray < Array; endSuperArray103,2672 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/match_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/matcher_spec.rb,270 +class UnexpectedError < StandardError; endUnexpectedError3,23 +module SpecSpec5,67 + module MatchersMatchers6,79 + def similar?(a, b)similar?198,5809 + def second_wordsecond_word208,6056 + def assert_equal(a,b)assert_equal236,6836 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/matchers_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/operator_matcher_spec.rb,188 + def o.send(*args); raise "DOH! Library developers shouldn't use #send!" endsend173,4385 + def o.send(*args); raise "DOH! Library developers shouldn't use #send!" endsend185,4671 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/raise_exception_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/respond_to_spec.rb,225 + def obj.foo(arg); endfoo20,499 + def obj.foo; endfoo33,861 + def obj.foo(arg, arg2); endfoo41,1097 + def obj.foo(a1, a2); endfoo76,2263 + def obj.foo; endfoo89,2630 + def obj.foo(arg); endfoo97,2868 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/satisfy_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/simple_matcher_spec.rb,54 +module SpecSpec3,23 + module MatchersMatchers4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/throw_symbol_spec.rb,54 +module SpecSpec3,23 + module MatchersMatchers4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/and_yield_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/any_number_of_times_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/argument_expectation_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/argument_matchers_spec.rb,98 +module SpecSpec3,23 + module MocksMocks4,35 + module ArgumentMatchersArgumentMatchers5,50 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/at_least_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/at_most_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_10260_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_10263_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_11545_spec.rb,176 +class LiarLiarPantsOnFireLiarLiarPantsOnFire3,23 + def respond_to?(sym, incl_private=false)respond_to?4,49 + def self.respond_to?(sym, incl_private=false)respond_to8,110 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_15719_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_496_spec.rb,114 +module BugReport496BugReport4963,23 + class BaseClassBaseClass4,43 + class SubClass < BaseClassSubClass7,68 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_600_spec.rb,157 +module BugReport600BugReport6003,23 + class ExampleClassExampleClass4,43 + def self.method_that_uses_define_methodmethod_that_uses_define_method5,64 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_7611_spec.rb,76 +module Bug7611Bug76113,23 + class FooFoo4,38 + class Bar < FooBar7,57 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_7805_spec.rb,28 +module Bug7805Bug78053,23 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_8165_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_8302_spec.rb,141 +module Bug8302Bug83023,23 + class FooFoo4,38 + def Foo.class_method(arg)class_method5,50 + def instance_bar(arg)instance_bar8,91 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_830_spec.rb,105 +module SpecSpec3,23 + module MocksMocks4,35 + class FooFoo6,112 + def self.foofoo7,128 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/double_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/failing_argument_matchers_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/hash_including_matcher_spec.rb,98 +module SpecSpec3,23 + module MocksMocks4,35 + module ArgumentMatchersArgumentMatchers5,50 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/hash_not_including_matcher_spec.rb,98 +module SpecSpec3,23 + module MocksMocks4,35 + module ArgumentMatchersArgumentMatchers5,50 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/mock_ordering_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/mock_space_spec.rb,216 +module SpecSpec4,44 + module MocksMocks5,56 + def rspec_verifyrspec_verify10,171 + def verified?verified?13,241 + def rspec_resetrspec_reset16,301 + def reset?reset?19,367 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/mock_spec.rb,86 +module SpecSpec3,23 + module MocksMocks4,35 + def add_calladd_call498,19498 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/multiple_return_value_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/nil_expectation_warning_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/null_object_mock_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/once_counts_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/options_hash_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/partial_mock_spec.rb,407 +module SpecSpec3,23 + module MocksMocks4,35 + class PartiallyMockedEqualsPartiallyMockedEquals96,3332 + def initialize(val)initialize98,3391 + def ==(other)==102,3461 + class MockableClassMockableClass114,3799 + def public_methodpublic_method115,3825 + def protected_method; endprotected_method120,3933 + def private_method; endprivate_method122,3983 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/partial_mock_using_mocks_directly_spec.rb,99 +module SpecSpec3,23 +module MocksMocks4,35 + def existing_methodexisting_method10,172 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/passing_argument_matchers_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/precise_counts_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/record_messages_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stub_chain_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stub_implementation_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stub_spec.rb,188 +module SpecSpec3,23 + module MocksMocks4,35 + def self.existing_class_methodexisting_class_method8,135 + def existing_instance_methodexisting_instance_method12,219 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stubbed_message_expectations_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/twice_counts_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/unstub_spec.rb,48 +module SpecSpec3,23 + module MocksMocks4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/package/bin_spec_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/rake/spectask_spec.rb,538 +module SpecSpec4,52 + module RakeRake5,64 + class MockTaskMockTask7,79 + def self.taskstasks12,177 + def self.reset_tasksreset_tasks16,237 + def self.task(name)task20,301 + def self.register_task(name, block)register_task24,364 + def initialize(name, &block)initialize28,445 + def self.create_task(name, &block)create_task33,580 + class SpecTaskSpecTask38,666 + def task(name, &block)task39,685 + def system(cmd)system43,768 + def default_ruby_pathdefault_ruby_path48,846 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/class_and_argument_parser_spec.rb,50 +module SpecSpec3,23 + module RunnerRunner4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/command_line_spec.rb,50 +module SpecSpec3,23 + module RunnerRunner4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/configuration_spec.rb,50 +module SpecSpec3,23 + module RunnerRunner4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/drb_command_line_spec.rb,362 +module SpecSpec3,23 + module RunnerRunner4,35 + def self.run(argv, stderr, stdout)run26,693 + def create_dummy_spec_filecreate_dummy_spec_file75,2317 + def run_spec_via_druby(argv)run_spec_via_druby92,2963 + def tty?; true endtty?95,3085 + def with_RSPEC_DRB_set_to(val)with_RSPEC_DRB_set_to116,3739 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/example_group_runner_spec.rb,50 +module SpecSpec3,23 + module RunnerRunner4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/base_formatter_spec.rb,86 +module SpecSpec3,23 + module RunnerRunner4,35 + module FormatterFormatter5,51 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/base_text_formatter_spec.rb,272 +module SpecSpec4,75 + module RunnerRunner5,87 + module FormatterFormatter6,103 + def method_that_class_magenta(message)method_that_class_magenta28,879 + def method_that_class_colourise(message, failure)method_that_class_colourise31,983 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/failing_example_groups_formatter_spec.rb,88 +module SpecSpec4,88 + module RunnerRunner5,100 + module FormatterFormatter6,116 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/failing_examples_formatter_spec.rb,87 +module SpecSpec4,82 + module RunnerRunner5,94 + module FormatterFormatter6,110 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/html_formatter_spec.rb,90 +module SpecSpec8,185 + module RunnerRunner9,197 + module FormatterFormatter10,213 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/nested_text_formatter_spec.rb,820 +module SpecSpec4,77 + module RunnerRunner5,89 + module FormatterFormatter6,105 + def example_group_startedexample_group_started18,627 + def example_group_startedexample_group_started62,1921 + def example_group_startedexample_group_started96,3319 + def example_group_startedexample_group_started135,4930 + def example_group_startedexample_group_started148,5425 + def example_group_startedexample_group_started162,6042 + def make_group(name, parent=::Spec::Example::ExampleGroupDouble)make_group173,6357 + def example_group_startedexample_group_started233,8737 + def have_single_level_example_group_output(expected_output)have_single_level_example_group_output318,11663 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/profile_formatter_spec.rb,87 +module SpecSpec4,73 + module RunnerRunner5,85 + module FormatterFormatter6,101 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/progress_bar_formatter_spec.rb,87 +module SpecSpec4,78 + module RunnerRunner5,90 + module FormatterFormatter6,106 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/snippet_extractor_spec.rb,87 +module SpecSpec4,73 + module RunnerRunner5,85 + module FormatterFormatter6,101 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/specdoc_formatter_spec.rb,432 +module SpecSpec4,73 + module RunnerRunner5,85 + module FormatterFormatter6,101 + def example_group_startedexample_group_started26,796 + def example_group_startedexample_group_started76,3071 + def have_nested_example_group_output(expected_output)have_nested_example_group_output104,4480 + def have_example_group_output(expected_output)have_example_group_output148,6276 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/text_mate_formatter_spec.rb,222 +module SpecSpec8,188 + module RunnerRunner9,200 + module FormatterFormatter10,216 + def produces_html_identical_to_manually_designed_document(opt)produces_html_identical_to_manually_designed_document19,581 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/heckle_runner_spec.rb,196 + module FooFoo5,151 + class BarBar6,164 + def one; endone7,178 + def two; endtwo8,197 + class ZapZap11,225 + def three; endthree12,239 + def four; endfour13,260 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/heckler_spec.rb,82 + def initialize(klass_name, method_name, rspec_options)initialize9,281 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/line_number_query/line_number_query_fixture.rb,59 +class LineNumberQuerySubjectLineNumberQuerySubject23,143 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/line_number_query_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/noisy_backtrace_tweaker_spec.rb,50 +module SpecSpec3,23 + module RunnerRunner4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/option_parser_spec.rb,66 + def parse(args)parse12,273 + def parse(args)parse292,9859 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/options_spec.rb,50 +module SpecSpec4,83 + module RunnerRunner5,95 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/output_one_time_fixture.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/output_one_time_fixture_runner.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/output_one_time_spec.rb,50 +module SpecSpec4,45 + module RunnerRunner5,57 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/quiet_backtrace_tweaker_spec.rb,50 +module SpecSpec3,23 + module RunnerRunner4,35 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/reporter_spec.rb,346 +module SpecSpec3,23 + module RunnerRunner4,35 + def failurefailure21,909 + def create_example_group(text)create_example_group25,1012 + def description_of(example)description_of62,2631 + def example_pending(example_passed_to_method, message_passed_to_method, deprecated_pending_location)example_pending196,8734 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/a_bar.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/a_foo.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/a_spec.rb,0 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/custom_example_group_runner.rb,191 +module CustomCustom1,0 + class ExampleGroupRunnerExampleGroupRunner2,14 + def initialize(options, arg)initialize4,72 + def load_files(files)load_files8,150 + def runrun11,185 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/utf8_encoded.rb,95 +module CustomCustom2,18 + class ExampleUTF8ClassNameVarietàExampleUTF8ClassNameVariet3,32 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner_spec.rb,22 +module SpecSpec3,23 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec_helper.rb,892 +def jruby?jruby?14,261 +module Spec Spec18,305 + module ExampleExample19,319 + class NonStandardError < Exception; endNonStandardError20,336 + module MatchersMatchers23,387 + def failfail24,405 + def fail_with(message)fail_with28,489 + def exception_from(&block)exception_from32,596 + def run_with(options)run_with42,768 + def with_ruby(version)with_ruby46,850 +def with_sandboxed_optionswith_sandboxed_options52,962 +def with_sandboxed_configwith_sandboxed_config67,1273 +module SpecSpec86,1778 + module ExampleExample87,1790 + module ResettableResettable88,1807 + def reset # :nodoc:reset89,1829 + class ExampleGroupExampleGroup96,2001 + class ExampleGroupDouble < ExampleGroupExampleGroupDouble99,2056 + def register_example_group(klass)register_example_group101,2155 + def initialize(proxy=nil, &block)initialize104,2221 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/support/macros.rb,146 +module MacrosMacros1,0 + def treats_method_missing_as_private(options = {:noop => true, :subject => nil})treats_method_missing_as_private2,14 + +tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/support/spec_classes.rb,2133 +module SpecSpec2,56 + module ExpectationsExpectations3,68 + class PersonPerson4,90 + def initialize nameinitialize6,131 + def == other==9,188 + class ClassWithMultiWordPredicateClassWithMultiWordPredicate14,265 + def multi_word_predicate?multi_word_predicate?15,303 + module HelperHelper20,368 + class CollectionWithSizeMethodCollectionWithSizeMethod21,386 + def initialize; @list = []; endinitialize22,423 + def size; @list.size; endsize23,463 + def push(item); @list.push(item); endpush24,497 + class CollectionWithLengthMethodCollectionWithLengthMethod27,554 + def initialize; @list = []; endinitialize28,593 + def length; @list.size; endlength29,633 + def push(item); @list.push(item); endpush30,669 + class CollectionOwnerCollectionOwner33,726 + def initializeinitialize36,854 + def add_to_collection_with_size_method(item)add_to_collection_with_size_method41,1052 + def add_to_collection_with_length_method(item)add_to_collection_with_length_method45,1177 + def items_for(arg)items_for49,1314 + def itemsitems54,1417 + class HandCodedMockHandCodedMock59,1506 + def initialize(return_val)initialize61,1563 + def funny?funny?66,1678 + def hungry?(a, b, c)hungry?71,1763 + def exists?exists?79,1950 + def multi_word_predicate?multi_word_predicate?83,2013 + def rspec_verifyrspec_verify87,2082 + class ClassWithUnqueriedPredicateClassWithUnqueriedPredicate91,2168 + def initialize(foo)initialize93,2235 +module CustomCustom101,2325 + class Formatter < Spec::Runner::Formatter::BaseTextFormatterFormatter103,2393 + def initialize(options, where)initialize106,2494 + class BadFormatter < Spec::Runner::Formatter::BaseTextFormatterBadFormatter112,2590 + def initialize(options, where)initialize115,2684 + class DifferDiffer120,2751 + def initialize(options)initialize122,2791 + def diff_as_object(target, expected)diff_as_object126,2853 +class FakeReporter < Spec::Runner::ReporterFakeReporter132,2922 + +tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/bin/rubyforge,0 + +tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/lib/rubyforge/client.rb,638 +class TimeTime6,136 + def utc(*args)utc12,229 +class Net::HTTPNet20,422 + def use_ssl= flaguse_ssl=22,470 +class RubyForgeRubyForge28,653 + class ClientClient29,669 + def initialize(proxy = nil)initialize32,746 + def post_content(uri, form = {}, headers = {}, userconfig = nil)post_content45,1099 + def get_content(uri, query = {}, headers = {}, userconfig = nil)get_content51,1336 + def execute(request, uri, parameters = {}, headers = {}, userconfig = nil)execute57,1573 + def boundary_data_for(boundary, parameters)boundary_data_for94,2806 + def query_string_for(parameters)query_string_for116,3498 + +tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/lib/rubyforge.rb,991 +class RubyForgeRubyForge12,186 + def initialize(userconfig=nil, autoconfig=nil, opts=nil)initialize29,782 + def login ; endlogin41,1149 + def logout ; endlogout42,1167 + def configure opts = {}configure44,1187 + def forceforce67,1979 + def uriuri71,2023 + def setupsetup80,2262 + def save_autoconfigsave_autoconfig93,2664 + def scrape_configscrape_config99,2782 + def get_via_rest_api(path)get_via_rest_api115,3234 + def scrape_project(project)scrape_project121,3408 + def create_package(group_id, package_name)create_package163,4790 + def post_news(group_id, subject, body)post_news184,5296 + def delete_package(group_id, package_id)delete_package195,5602 + def add_release(group_id, package_id, release_name, *files)add_release206,5998 + def add_file(group_name, package_name, release_name, userfile)add_file263,8084 + def clientclient289,8956 + def run(page, form, extheader={}) # :nodoc:run298,9158 + def lookup(type, val) # :nodoc:lookup306,9442 + +tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/test/test_rubyforge.rb,2410 +class RubyForgeRubyForge7,113 + def save_autoconfigsave_autoconfig11,198 +class RubyForge::FakeClientRubyForge16,261 + def form; endform17,289 + def post_content(*args)post_content19,306 + def get_content(*args)get_content23,363 +class FakeRubyForge < RubyForgeFakeRubyForge28,429 + def run(page, form, extheader={})run32,554 + def scrape_project(proj)scrape_project39,752 +class URI::HTTPURI46,891 + def self.datadata47,907 + def readread51,947 +class TestRubyForge < Test::Unit::TestCaseTestRubyForge56,1019 + def setupsetup57,1062 + def teardownteardown62,1121 + def test_new_with_proxy_uses_a_proxy_classtest_new_with_proxy_uses_a_proxy_class69,1297 + def test_new_with_bad_proxy_uses_normal_httptest_new_with_bad_proxy_uses_normal_http74,1488 + def test_initialize_badtest_initialize_bad79,1679 + def test_setuptest_setup97,2113 + def test_create_packagetest_create_package101,2204 + def test_delete_packagetest_delete_package109,2408 + def test_delete_package_package_nametest_delete_package_package_name114,2506 + def test_delete_package_undefined_package_nametest_delete_package_undefined_package_name119,2624 + def test_delete_package_group_nametest_delete_package_group_name125,2767 + def test_delete_package_undefined_group_nametest_delete_package_undefined_group_name130,2885 + def test_post_newstest_post_news136,3027 + def test_add_release_undefined_package_nametest_add_release_undefined_package_name144,3270 + def test_add_release_undefined_group_nametest_add_release_undefined_group_name150,3426 + def test_lookup_idtest_lookup_id156,3581 + def test_lookup_string_numbertest_lookup_string_number160,3665 + def test_lookup_nametest_lookup_name166,3788 + def test_lookup_undefinedtest_lookup_undefined171,3948 + def test_add_filetest_add_file177,4069 + def test_add_releasetest_add_release194,4623 + def test_add_release_with_a_filetest_add_release_with_a_file199,4731 + def test_add_release_package_nametest_add_release_package_name227,5791 + def test_add_release_group_nametest_add_release_group_name232,5917 + def test_scrape_projecttest_scrape_project238,6038 + def util_new(klass)util_new276,7260 + def util_run(page, form={}, extheader={})util_run302,7994 + def util_add_releaseutil_add_release309,8207 + def util_delete_packageutil_delete_package318,8496 + def make_a_tmp_filemake_a_tmp_file322,8582 + +tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/test/test_rubyforge_client.rb,517 +class RubyForge::FakeAgentRubyForge4,79 + def initialize(*args)initialize9,167 + def request(request, data)request12,198 + def response.read_body; ''; endread_body16,338 + class PostPost20,401 + def initialize(*args)initialize21,414 + def [] key[]26,486 + def []= key, val[]=30,537 + def method_missing(*stuff)method_missing34,600 +class TestRubyForgeClient < Test::Unit::TestCaseTestRubyForgeClient40,677 + def setupsetup41,726 + def test_post_with_paramstest_post_with_params48,960 diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 76ced079ba8fc..171d165bc2962 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -1,8 +1,4 @@ -def Table(name, engine = Arel::Table.engine) - Arel::Table.new(name, engine) -end - -module Arel +module Arel class Table include Arel::Crud diff --git a/spec/nodes/select_core_spec.rb b/spec/nodes/select_core_spec.rb deleted file mode 100644 index d2e87c2c23004..0000000000000 --- a/spec/nodes/select_core_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'spec_helper' - -describe Arel::Nodes::SelectCore do - describe "#clone" do - it "clones froms, projections and wheres" do - core = Arel::Nodes::SelectCore.new - core.instance_variable_set "@froms", %w[a b c] - core.instance_variable_set "@projections", %w[d e f] - core.instance_variable_set "@wheres", %w[g h i] - - [:froms, :projections, :wheres].each do |array_attr| - core.send(array_attr).should_receive(:clone).and_return([array_attr]) - end - - dolly = core.clone - check dolly.froms.should == [:froms] - check dolly.projections.should == [:projections] - check dolly.wheres.should == [:wheres] - end - end -end diff --git a/spec/spec.opts b/spec/spec.opts deleted file mode 100644 index ef88ff877b1fd..0000000000000 --- a/spec/spec.opts +++ /dev/null @@ -1,3 +0,0 @@ ---backtrace ---diff ---color \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index b9fd9db9308d9..0000000000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'rubygems' -require 'spec' -require 'fileutils' -require 'arel' - -require 'support/matchers/be_like' -require 'support/check' -require 'support/fake_record' -require 'support/shared/tree_manager_shared' - -Spec::Runner.configure do |config| - config.include Matchers - config.include Check - - config.before do - Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new) - end -end diff --git a/spec/support/check.rb b/spec/support/check.rb deleted file mode 100644 index c9adce420cefc..0000000000000 --- a/spec/support/check.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Check - # This is used to eliminate Ruby warnings on some RSpec assertion lines - # See: https://rspec.lighthouseapp.com/projects/5645/tickets/504 - def check(*args) - end -end diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb deleted file mode 100644 index 486e4fe274cc0..0000000000000 --- a/spec/support/matchers.rb +++ /dev/null @@ -1 +0,0 @@ -require "support/matchers/be_like" diff --git a/spec/support/matchers/be_like.rb b/spec/support/matchers/be_like.rb deleted file mode 100644 index ca49b9127461f..0000000000000 --- a/spec/support/matchers/be_like.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Matchers - class BeLike - def initialize(expected) - @expected = expected.gsub(/\s+/, ' ').strip - end - - def matches?(actual) - @actual = actual.gsub(/\s+/, ' ').strip - @expected == @actual - end - - def failure_message - "expected\n#{@actual}\nto be like\n#{@expected}" - end - - def negative_failure_message - "expected\n#{@actual}\nto be unlike\n#{@expected}" - end - end - - def be_like(expected) - BeLike.new(expected) - end -end diff --git a/spec/attributes/attribute_spec.rb b/test/attributes/test_attribute.rb similarity index 79% rename from spec/attributes/attribute_spec.rb rename to test/attributes/test_attribute.rb index 562781ade9599..f0341f40705ad 100644 --- a/spec/attributes/attribute_spec.rb +++ b/test/attributes/test_attribute.rb @@ -6,14 +6,14 @@ module Attributes describe '#not_eq' do it 'should create a NotEqual node' do relation = Table.new(:users) - relation[:id].not_eq(10).should be_kind_of Nodes::NotEqual + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" != 10 } end @@ -22,7 +22,7 @@ module Attributes relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].not_eq(nil) - mgr.to_sql.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" IS NOT NULL } end @@ -31,14 +31,14 @@ module Attributes describe '#not_eq_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].not_eq_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" != 1 OR "users"."id" != 2) } end @@ -47,14 +47,14 @@ module Attributes describe '#not_eq_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].not_eq_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" != 1 AND "users"."id" != 2) } end @@ -63,14 +63,14 @@ module Attributes describe '#gt' do it 'should create a GreaterThan node' do relation = Table.new(:users) - relation[:id].gt(10).should be_kind_of Nodes::GreaterThan + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" > 10 } end @@ -79,14 +79,14 @@ module Attributes describe '#gt_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].gt_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" > 1 OR "users"."id" > 2) } end @@ -95,14 +95,14 @@ module Attributes describe '#gt_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].gt_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" > 1 AND "users"."id" > 2) } end @@ -111,14 +111,14 @@ module Attributes describe '#gteq' do it 'should create a GreaterThanOrEqual node' do relation = Table.new(:users) - relation[:id].gteq(10).should be_kind_of Nodes::GreaterThanOrEqual + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" >= 10 } end @@ -127,14 +127,14 @@ module Attributes describe '#gteq_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].gteq_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 1 OR "users"."id" >= 2) } end @@ -143,14 +143,14 @@ module Attributes describe '#gteq_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].gteq_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" >= 1 AND "users"."id" >= 2) } end @@ -159,14 +159,14 @@ module Attributes describe '#lt' do it 'should create a LessThan node' do relation = Table.new(:users) - relation[:id].lt(10).should be_kind_of Nodes::LessThan + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" < 10 } end @@ -175,14 +175,14 @@ module Attributes describe '#lt_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].lt_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" < 1 OR "users"."id" < 2) } end @@ -191,14 +191,14 @@ module Attributes describe '#lt_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].lt_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" < 1 AND "users"."id" < 2) } end @@ -207,14 +207,14 @@ module Attributes describe '#lteq' do it 'should create a LessThanOrEqual node' do relation = Table.new(:users) - relation[:id].lteq(10).should be_kind_of Nodes::LessThanOrEqual + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" <= 10 } end @@ -223,14 +223,14 @@ module Attributes describe '#lteq_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].lteq_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" <= 1 OR "users"."id" <= 2) } end @@ -239,14 +239,14 @@ module Attributes describe '#lteq_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].lteq_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" <= 1 AND "users"."id" <= 2) } end @@ -255,14 +255,14 @@ module Attributes describe '#average' do it 'should create a AVG node' do relation = Table.new(:users) - relation[:id].average.should be_kind_of Nodes::Avg + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT AVG("users"."id") AS avg_id FROM "users" } @@ -272,14 +272,14 @@ module Attributes describe '#maximum' do it 'should create a MAX node' do relation = Table.new(:users) - relation[:id].maximum.should be_kind_of Nodes::Max + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT MAX("users"."id") AS max_id FROM "users" } @@ -289,21 +289,21 @@ module Attributes describe '#minimum' do it 'should create a Min node' do relation = Table.new(:users) - relation[:id].minimum.should be_kind_of Nodes::Min + 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.should be_kind_of Nodes::Sum + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT SUM("users"."id") AS sum_id FROM "users" } @@ -313,14 +313,14 @@ module Attributes describe '#count' do it 'should return a count node' do relation = Table.new(:users) - relation[:id].count.should be_kind_of Nodes::Count + 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.should be_kind_of Nodes::Count - count.distinct.should be_nil + count.must_be_kind_of Nodes::Count + count.distinct.must_be_nil end end @@ -328,16 +328,16 @@ module Attributes it 'should return an equality node' do attribute = Attribute.new nil, nil, nil equality = attribute.eq 1 - check equality.left.should == attribute - check equality.right.should == 1 - equality.should be_kind_of Nodes::Equality + check equality.left.must_equal attribute + check 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 10 } end @@ -346,7 +346,7 @@ module Attributes relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].eq(nil) - mgr.to_sql.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" IS NULL } end @@ -355,14 +355,14 @@ module Attributes describe '#eq_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].eq_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 OR "users"."id" = 2) } end @@ -371,14 +371,14 @@ module Attributes describe '#eq_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].eq_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2) } end @@ -387,14 +387,14 @@ module Attributes describe '#matches' do it 'should create a Matches node' do relation = Table.new(:users) - relation[:name].matches('%bacon%').should be_kind_of Nodes::Matches + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."name" LIKE '%bacon%' } end @@ -403,14 +403,14 @@ module Attributes describe '#matches_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:name].matches_any(['%chunky%','%bacon%']).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."name" LIKE '%chunky%' OR "users"."name" LIKE '%bacon%') } end @@ -419,14 +419,14 @@ module Attributes describe '#matches_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:name].matches_all(['%chunky%','%bacon%']).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."name" LIKE '%chunky%' AND "users"."name" LIKE '%bacon%') } end @@ -435,14 +435,14 @@ module Attributes describe '#does_not_match' do it 'should create a DoesNotMatch node' do relation = Table.new(:users) - relation[:name].does_not_match('%bacon%').should be_kind_of Nodes::DoesNotMatch + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."name" NOT LIKE '%bacon%' } end @@ -451,14 +451,14 @@ module Attributes 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%']).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' OR "users"."name" NOT LIKE '%bacon%') } end @@ -467,14 +467,14 @@ module Attributes 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%']).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' AND "users"."name" NOT LIKE '%bacon%') } end @@ -487,15 +487,15 @@ module Attributes it 'should return an in node' do attribute = Attribute.new nil, nil, nil node = Nodes::In.new attribute, [1,2,3] - check node.left.should == attribute - check node.right.should == [1, 2, 3] + check node.left.must_equal attribute + check 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" IN (1, 2, 3) } end @@ -504,14 +504,14 @@ module Attributes describe '#in_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].in_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) OR "users"."id" IN (3, 4)) } end @@ -520,14 +520,14 @@ module Attributes describe '#in_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].in_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) AND "users"."id" IN (3, 4)) } end @@ -540,15 +540,15 @@ module Attributes it 'should return a NotIn node' do attribute = Attribute.new nil, nil, nil node = Nodes::NotIn.new attribute, [1,2,3] - check node.left.should == attribute - check node.right.should == [1, 2, 3] + check node.left.must_equal attribute + check 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" NOT IN (1, 2, 3) } end @@ -557,14 +557,14 @@ module Attributes describe '#not_in_any' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].not_in_any([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + 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 @@ -573,14 +573,14 @@ module Attributes describe '#not_in_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].not_in_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + 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 @@ -589,14 +589,14 @@ module Attributes describe '#eq_all' do it 'should create a Grouping node' do relation = Table.new(:users) - relation[:id].eq_all([1,2]).should be_kind_of Nodes::Grouping + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" = 1 AND "users"."id" = 2) } end @@ -605,14 +605,14 @@ module Attributes describe '#asc' do it 'should create an Ordering node' do relation = Table.new(:users) - relation[:id].asc.should be_kind_of Nodes::Ordering + relation[:id].asc.must_be_kind_of Nodes::Ordering 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" ORDER BY "users"."id" ASC } end @@ -621,14 +621,14 @@ module Attributes describe '#desc' do it 'should create an Ordering node' do relation = Table.new(:users) - relation[:id].desc.should be_kind_of Nodes::Ordering + relation[:id].desc.must_be_kind_of Nodes::Ordering 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" ORDER BY "users"."id" DESC } end @@ -640,7 +640,7 @@ module Attributes it 'should produce sql' do table = Table.new :users condition = table['id'].eq 1 - condition.to_sql.should == '"users"."id" = 1' + condition.to_sql.must_equal '"users"."id" = 1' end end end diff --git a/spec/nodes/count_spec.rb b/test/nodes/test_count.rb similarity index 69% rename from spec/nodes/count_spec.rb rename to test/nodes/test_count.rb index 185b4d8eb92fc..d65df03313e2f 100644 --- a/spec/nodes/count_spec.rb +++ b/test/nodes/test_count.rb @@ -3,14 +3,14 @@ describe Arel::Nodes::Count do describe 'backwards compatibility' do it 'must be an expression' do - Arel::Nodes::Count.new('foo').should be_kind_of Arel::Expression + 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.should be_like %{ + table[:id].count.as('foo').to_sql.must_be_like %{ COUNT("users"."id") AS foo } end diff --git a/spec/nodes/delete_statement_spec.rb b/test/nodes/test_delete_statement.rb similarity index 69% rename from spec/nodes/delete_statement_spec.rb rename to test/nodes/test_delete_statement.rb index 4d12d184fbc5b..a71da7adae541 100644 --- a/spec/nodes/delete_statement_spec.rb +++ b/test/nodes/test_delete_statement.rb @@ -6,10 +6,9 @@ statement = Arel::Nodes::DeleteStatement.new statement.wheres = %w[a b c] - statement.wheres.should_receive(:clone).and_return([:wheres]) - dolly = statement.clone - dolly.wheres.should == [:wheres] + dolly.wheres.must_equal statement.wheres + dolly.wheres.wont_be_same_as statement.wheres end end end diff --git a/spec/nodes/equality_spec.rb b/test/nodes/test_equality.rb similarity index 79% rename from spec/nodes/equality_spec.rb rename to test/nodes/test_equality.rb index f1ed7a6904df8..513cafd87fd8e 100644 --- a/spec/nodes/equality_spec.rb +++ b/test/nodes/test_equality.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + module Arel module Nodes describe 'equality' do @@ -7,7 +9,7 @@ module Nodes it 'returns :==' do attr = Table.new(:users)[:id] left = attr.eq(10) - check left.operator.should == :== + check left.operator.must_equal :== end end @@ -15,7 +17,7 @@ module Nodes it "should equal left" do attr = Table.new(:users)[:id] left = attr.eq(10) - check left.left.should == left.operand1 + check left.left.must_equal left.operand1 end end @@ -23,7 +25,7 @@ module Nodes it "should equal right" do attr = Table.new(:users)[:id] left = attr.eq(10) - check left.right.should == left.operand2 + check left.right.must_equal left.operand2 end end @@ -41,7 +43,7 @@ def quote_table_name(*args) @quote_count += 1; super; end attr = Table.new(:users)[:id] test = attr.eq(10) test.to_sql engine - check engine.connection.quote_count.should == 2 + check engine.connection.quote_count.must_equal 2 end end end @@ -52,8 +54,8 @@ def quote_table_name(*args) @quote_count += 1; super; end left = attr.eq(10) right = attr.eq(11) node = left.or right - check node.expr.left.should == left - check node.expr.right.should == right + check node.expr.left.must_equal left + check node.expr.right.must_equal right end end @@ -63,8 +65,8 @@ def quote_table_name(*args) @quote_count += 1; super; end left = attr.eq(10) right = attr.eq(11) node = left.and right - check node.left.should == left - check node.right.should == right + check node.left.must_equal left + check node.right.must_equal right end end end diff --git a/spec/nodes/insert_statement_spec.rb b/test/nodes/test_insert_statement.rb similarity index 56% rename from spec/nodes/insert_statement_spec.rb rename to test/nodes/test_insert_statement.rb index 0e2432c021d2b..47f3c27dee61d 100644 --- a/spec/nodes/insert_statement_spec.rb +++ b/test/nodes/test_insert_statement.rb @@ -7,12 +7,12 @@ statement.columns = %w[a b c] statement.values = %w[x y z] - statement.columns.should_receive(:clone).and_return([:columns]) - statement.values.should_receive(:clone).and_return([:values]) - dolly = statement.clone - check dolly.columns.should == [:columns] - check dolly.values.should == [:values] + 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 end diff --git a/spec/nodes/or_spec.rb b/test/nodes/test_or.rb similarity index 59% rename from spec/nodes/or_spec.rb rename to test/nodes/test_or.rb index 88484ff4f74f5..354d803110329 100644 --- a/spec/nodes/or_spec.rb +++ b/test/nodes/test_or.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + module Arel module Nodes describe 'or' do @@ -7,12 +9,12 @@ module Nodes left = attr.eq(10) right = attr.eq(11) node = left.or right - check node.expr.left.should == left - check node.expr.right.should == right + check node.expr.left.must_equal left + check node.expr.right.must_equal right oror = node.or(right) - check oror.expr.left == node - check oror.expr.right == right + check oror.expr.left.must_equal node + check oror.expr.right.must_equal right end end end diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb new file mode 100644 index 0000000000000..0aacf41720d6b --- /dev/null +++ b/test/nodes/test_select_core.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Arel::Nodes::SelectCore do + describe "#clone" do + it "clones froms, projections and wheres" do + 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 + end +end diff --git a/spec/nodes/select_statement_spec.rb b/test/nodes/test_select_statement.rb similarity index 65% rename from spec/nodes/select_statement_spec.rb rename to test/nodes/test_select_statement.rb index 68bde3c4f7ef0..45613bfa4d5f5 100644 --- a/spec/nodes/select_statement_spec.rb +++ b/test/nodes/test_select_statement.rb @@ -5,10 +5,9 @@ it "clones cores" do statement = Arel::Nodes::SelectStatement.new %w[a b c] - statement.cores.map { |x| x.should_receive(:clone).and_return(:f) } - dolly = statement.clone - dolly.cores.should == [:f, :f, :f] + dolly.cores.must_equal statement.cores + dolly.cores.wont_be_same_as statement.cores end end end diff --git a/spec/nodes/sql_literal_spec.rb b/test/nodes/test_sql_literal.rb similarity index 72% rename from spec/nodes/sql_literal_spec.rb rename to test/nodes/test_sql_literal.rb index f5c53d9f29753..3aeab41f0cd74 100644 --- a/spec/nodes/sql_literal_spec.rb +++ b/test/nodes/test_sql_literal.rb @@ -1,10 +1,12 @@ +require 'spec_helper' + module Arel module Nodes describe 'sql literal' do describe 'sql' do it 'makes a sql literal node' do sql = Arel.sql 'foo' - sql.should be_kind_of Arel::Nodes::SqlLiteral + sql.must_be_kind_of Arel::Nodes::SqlLiteral end end @@ -12,13 +14,13 @@ module Nodes it 'makes a count node' do node = SqlLiteral.new('*').count viz = Visitors::ToSql.new Table.engine - viz.accept(node).should be_like %{ COUNT(*) } + viz.accept(node).must_be_like %{ COUNT(*) } end it 'makes a distinct node' do node = SqlLiteral.new('*').count true viz = Visitors::ToSql.new Table.engine - viz.accept(node).should be_like %{ COUNT(DISTINCT *) } + viz.accept(node).must_be_like %{ COUNT(DISTINCT *) } end end end diff --git a/spec/nodes/sum_spec.rb b/test/nodes/test_sum.rb similarity index 78% rename from spec/nodes/sum_spec.rb rename to test/nodes/test_sum.rb index 7691b06590b0e..e6a57e4dd643a 100644 --- a/spec/nodes/sum_spec.rb +++ b/test/nodes/test_sum.rb @@ -4,7 +4,7 @@ describe "as" do it 'should alias the sum' do table = Arel::Table.new :users - table[:id].sum.as('foo').to_sql.should be_like %{ + table[:id].sum.as('foo').to_sql.must_be_like %{ SUM("users"."id") AS foo } end diff --git a/spec/nodes/update_statement_spec.rb b/test/nodes/test_update_statement.rb similarity index 56% rename from spec/nodes/update_statement_spec.rb rename to test/nodes/test_update_statement.rb index 860d1c448aa49..88c147b26842b 100644 --- a/spec/nodes/update_statement_spec.rb +++ b/test/nodes/test_update_statement.rb @@ -7,12 +7,12 @@ statement.wheres = %w[a b c] statement.values = %w[x y z] - statement.wheres.should_receive(:clone).and_return([:wheres]) - statement.values.should_receive(:clone).and_return([:values]) - dolly = statement.clone - check dolly.wheres.should == [:wheres] - check dolly.values.should == [:values] + 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 end diff --git a/test/spec_helper.rb b/test/spec_helper.rb new file mode 100644 index 0000000000000..dd288e0d0dfc6 --- /dev/null +++ b/test/spec_helper.rb @@ -0,0 +1,21 @@ +require 'rubygems' +require 'minitest/autorun' +require 'fileutils' +require 'arel' + +require 'support/fake_record' +Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new) + +# HACK require 'support/shared/tree_manager_shared' + +class Object + def must_be_like other + self.gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip + end + + # TODO: remove + def check truthiness + raise "not truthy" unless truthiness + end +end + diff --git a/spec/support/fake_record.rb b/test/support/fake_record.rb similarity index 100% rename from spec/support/fake_record.rb rename to test/support/fake_record.rb diff --git a/spec/activerecord_compat_spec.rb b/test/test_activerecord_compat.rb similarity index 82% rename from spec/activerecord_compat_spec.rb rename to test/test_activerecord_compat.rb index a7eeb7e5ee7e3..2f1d7cff1299e 100644 --- a/spec/activerecord_compat_spec.rb +++ b/test/test_activerecord_compat.rb @@ -11,7 +11,7 @@ module Arel check manager.wheres.map { |x| x.value - }.join(', ').should == "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'" + }.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'" end end end diff --git a/spec/attributes_spec.rb b/test/test_attributes.rb similarity index 71% rename from spec/attributes_spec.rb rename to test/test_attributes.rb index 8b437dff9b862..4cdb625b179e0 100644 --- a/spec/attributes_spec.rb +++ b/test/test_attributes.rb @@ -6,34 +6,34 @@ module Arel it 'returns the correct constant for strings' do [:string, :text, :binary].each do |type| column = Struct.new(:type).new type - Attributes.for(column).should == Attributes::String + 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).should == Attributes::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).should == Attributes::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).should == Attributes::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).should == Attributes::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).should == Attributes::Time + Attributes.for(column).must_equal Attributes::Time end end end diff --git a/spec/crud_spec.rb b/test/test_crud.rb similarity index 94% rename from spec/crud_spec.rb rename to test/test_crud.rb index 36b2a0b4e4e43..2a0ff651e975d 100644 --- a/spec/crud_spec.rb +++ b/test/test_crud.rb @@ -38,7 +38,7 @@ def initialize engine = FakeEngine.new fc.insert [[table[:id], 'foo']] fc.engine.calls.find { |method, _| method == :insert - }.should_not be_nil + }.wont_be_nil end end @@ -50,7 +50,7 @@ def initialize engine = FakeEngine.new fc.update [[table[:id], 'foo']] fc.engine.calls.find { |method, _| method == :update - }.should_not be_nil + }.wont_be_nil end end @@ -62,7 +62,7 @@ def initialize engine = FakeEngine.new fc.delete fc.engine.calls.find { |method, _| method == :delete - }.should_not be_nil + }.wont_be_nil end end end diff --git a/spec/delete_manager_spec.rb b/test/test_delete_manager.rb similarity index 60% rename from spec/delete_manager_spec.rb rename to test/test_delete_manager.rb index 74496c58c6606..0a41c4d3fc468 100644 --- a/spec/delete_manager_spec.rb +++ b/test/test_delete_manager.rb @@ -13,13 +13,13 @@ module Arel table = Table.new(:users) dm = Arel::DeleteManager.new Table.engine dm.from table - dm.to_sql.should be_like %{ DELETE FROM "users" } + dm.to_sql.must_be_like %{ DELETE FROM "users" } end it 'chains' do table = Table.new(:users) dm = Arel::DeleteManager.new Table.engine - check dm.from(table).should == dm + check dm.from(table).must_equal dm end end @@ -29,25 +29,26 @@ module Arel dm = Arel::DeleteManager.new Table.engine dm.from table dm.where table[:id].eq(10) - dm.to_sql.should be_like %{ DELETE FROM "users" WHERE "users"."id" = 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 - check dm.where(table[:id].eq(10)).should == dm + check dm.where(table[:id].eq(10)).must_equal dm end end - describe "TreeManager" do - subject do - table = Table.new :users - Arel::DeleteManager.new(Table.engine).tap do |manager| - manager.where(table[:id].eq(10)) - end - end - - it_should_behave_like "TreeManager" - end + # HACK + # describe "TreeManager" do + # before do + # table = Table.new :users + # Arel::DeleteManager.new(Table.engine).tap do |manager| + # manager.where(table[:id].eq(10)) + # end + # end + # + # it_should_behave_like "TreeManager" + # end end end diff --git a/spec/insert_manager_spec.rb b/test/test_insert_manager.rb similarity index 79% rename from spec/insert_manager_spec.rb rename to test/test_insert_manager.rb index 9d6045a913329..97ba4d7f765b7 100644 --- a/spec/insert_manager_spec.rb +++ b/test/test_insert_manager.rb @@ -13,12 +13,10 @@ module Arel table = Table.new(:users) manager = Arel::InsertManager.new Table.engine - table[:id].column.extend(Module.new { - def type; :boolean; end - }) + table[:id].column.extend(Module.new { def type; :boolean; end }) manager.insert [[table[:id], false]] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id") VALUES ('f') } end @@ -27,7 +25,7 @@ def type; :boolean; end table = Table.new(:users) manager = Arel::InsertManager.new Table.engine manager.insert [[table[:id], nil]] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id") VALUES (NULL) } end @@ -41,7 +39,7 @@ def type; :boolean; end attribute.column.type = :date manager.insert [[attribute, time]] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id") VALUES (#{Table.engine.connection.quote time}) } end @@ -51,7 +49,7 @@ def type; :boolean; end manager = Arel::InsertManager.new Table.engine manager.into table manager.insert [[table[:id], 1], [table[:name], 'aaron']] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end @@ -60,7 +58,7 @@ def type; :boolean; end table = Table.new(:users) manager = Arel::InsertManager.new Table.engine manager.insert [[table[:id], 1], [table[:name], 'aaron']] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end @@ -74,14 +72,14 @@ def type; :boolean; end describe 'into' do it 'takes an engine' do manager = Arel::InsertManager.new Table.engine - manager.into(Table.new(:users)).should == manager + 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.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" } end @@ -93,7 +91,7 @@ def type; :boolean; end manager = Arel::InsertManager.new Table.engine manager.into table manager.columns << table[:id] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id") } end @@ -106,7 +104,7 @@ def type; :boolean; end manager.into table manager.values = Nodes::Values.new [1] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" VALUES (1) } end @@ -121,21 +119,22 @@ def type; :boolean; end manager.values = Nodes::Values.new [1, 'aaron'] manager.columns << table[:id] manager.columns << table[:name] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end end - describe "TreeManager" do - subject do - table = Table.new(:users) - Arel::InsertManager.new(Table.engine).tap do |manager| - manager.insert [[table[:id], nil]] - end - end - - it_should_behave_like "TreeManager" - end + # HACK + # describe "TreeManager" do + # subject do + # table = Table.new(:users) + # Arel::InsertManager.new(Table.engine).tap do |manager| + # manager.insert [[table[:id], nil]] + # end + # end + # + # it_should_behave_like "TreeManager" + # end end end diff --git a/spec/select_manager_spec.rb b/test/test_select_manager.rb similarity index 81% rename from spec/select_manager_spec.rb rename to test/test_select_manager.rb index fa289e0d08a13..75d06438c262c 100644 --- a/spec/select_manager_spec.rb +++ b/test/test_select_manager.rb @@ -43,7 +43,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.project :id manager.from table - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT id FROM "users" } end @@ -56,7 +56,7 @@ def execute sql, name = nil, *args manager.project SqlLiteral.new '*' manager.from table manager.order :foo - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo } end @@ -68,7 +68,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.group :foo - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } end @@ -82,7 +82,7 @@ def execute sql, name = nil, *args manager.from table manager.from 'users' manager.project table['id'] - manager.to_sql.should be_like 'SELECT "users"."id" FROM users' + manager.to_sql.must_be_like 'SELECT "users"."id" FROM users' end end @@ -91,7 +91,7 @@ def execute sql, name = nil, *args table = Table.new :users mgr = table.from table mgr.having 'foo' - mgr.to_sql.should be_like %{ SELECT FROM "users" HAVING foo } + mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo } end end end @@ -102,8 +102,7 @@ def execute sql, name = nil, *args mgr = table.from table m2 = mgr.clone m2.project "foo" - - check mgr.to_sql.should_not == m2.to_sql + mgr.to_sql.wont_equal m2.to_sql end end @@ -112,7 +111,7 @@ def execute sql, name = nil, *args table = Table.new :users, :engine => Table.engine, :as => 'foo' mgr = table.from table mgr.skip 10 - mgr.to_sql.should be_like %{ SELECT FROM "users" "foo" OFFSET 10 } + mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 } end end @@ -121,13 +120,13 @@ def execute sql, name = nil, *args table = Table.new :users mgr = table.from table mgr.skip 10 - mgr.to_sql.should be_like %{ SELECT FROM "users" OFFSET 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.should be_like %{ SELECT FROM "users" OFFSET 10 } + mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } end end @@ -136,7 +135,7 @@ def execute sql, name = nil, *args table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.take 10 - check manager.taken.should == 10 + check manager.taken.must_equal 10 end end @@ -148,7 +147,7 @@ def execute sql, name = nil, *args manager.from table manager.insert 'VALUES(NULL)' - engine.executed.last.should be_like %{ + engine.executed.last.must_be_like %{ INSERT INTO "users" VALUES(NULL) } end @@ -159,7 +158,7 @@ def execute sql, name = nil, *args it 'adds a lock node' do table = Table.new :users mgr = table.from table - mgr.lock.to_sql.should be_like %{ SELECT FROM "users" } + mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" } end end @@ -169,7 +168,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine order = table[:id] manager.order table[:id] - check manager.orders.should == [order] + check manager.orders.must_equal [order] end end @@ -180,7 +179,7 @@ def execute sql, name = nil, *args manager.project SqlLiteral.new '*' manager.from table manager.order table[:id] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY "users"."id" } end @@ -192,7 +191,7 @@ def execute sql, name = nil, *args manager.project SqlLiteral.new '*' manager.from table manager.order table[:id], table[:name] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY "users"."id", "users"."name" } end @@ -200,7 +199,7 @@ def execute sql, name = nil, *args it 'chains' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - check manager.order(table[:id]).should == manager + check manager.order(table[:id]).must_equal manager end end @@ -213,7 +212,7 @@ def execute sql, name = nil, *args manager.from left manager.join(right).on(predicate, predicate) - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" AND @@ -233,7 +232,7 @@ def execute sql, name = nil, *args predicate, left[:name].eq(right[:name]) ) - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" AND @@ -252,7 +251,7 @@ def execute sql, name = nil, *args manager.from left manager.join(right).on(predicate) - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" @@ -267,7 +266,7 @@ def execute sql, name = nil, *args manager.from left manager.join(right, Nodes::OuterJoin).on(predicate) - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" LEFT OUTER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" @@ -276,7 +275,7 @@ def execute sql, name = nil, *args it 'noops on nil' do manager = Arel::SelectManager.new Table.engine - check manager.join(nil).should == manager + check manager.join(nil).must_equal manager end end @@ -286,10 +285,10 @@ def execute sql, name = nil, *args aliaz = table.alias manager = Arel::SelectManager.new Table.engine manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) - manager.join_sql.should be_like %{ + manager.join_sql.must_be_like %{ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" } - check manager.joins(manager).should == manager.join_sql + check manager.joins(manager).must_equal manager.join_sql end it 'returns outer join sql' do @@ -297,10 +296,10 @@ def execute sql, name = nil, *args aliaz = table.alias manager = Arel::SelectManager.new Table.engine manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) - manager.join_sql.should be_like %{ + manager.join_sql.must_be_like %{ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" } - check manager.joins(manager).should == manager.join_sql + check manager.joins(manager).must_equal manager.join_sql end it 'returns string join sql' do @@ -308,13 +307,13 @@ def execute sql, name = nil, *args aliaz = table.alias manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new(table, 'hello') - manager.join_sql.should be_like %{ 'hello' } - check manager.joins(manager).should == manager.join_sql + manager.join_sql.must_be_like %{ 'hello' } + check manager.joins(manager).must_equal manager.join_sql end it 'returns nil join sql' do manager = Arel::SelectManager.new Table.engine - manager.join_sql.should be_nil + manager.join_sql.must_be_nil end end @@ -325,7 +324,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.order table[:id] - manager.order_clauses.first.should be_like %{ "users"."id" } + manager.order_clauses.first.must_be_like %{ "users"."id" } end end @@ -335,7 +334,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.group table[:id] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY "users"."id" } end @@ -343,7 +342,7 @@ def execute sql, name = nil, *args it 'chains' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - check manager.group(table[:id]).should == manager + check manager.group(table[:id]).must_equal manager end it 'takes multiple args' do @@ -351,7 +350,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.group table[:id], table[:name] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY "users"."id", "users"."name" } end @@ -362,7 +361,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.group 'foo' - manager.to_sql.should be_like %{ SELECT FROM "users" GROUP BY foo } + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } end end @@ -374,7 +373,7 @@ def execute sql, name = nil, *args manager.from table manager.delete - engine.executed.last.should be_like %{ DELETE FROM "users" } + engine.executed.last.must_be_like %{ DELETE FROM "users" } end it "copies where" do @@ -385,7 +384,7 @@ def execute sql, name = nil, *args manager.where table[:id].eq 10 manager.delete - engine.executed.last.should be_like %{ + engine.executed.last.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10 } end @@ -397,14 +396,14 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.where table[:id].eq 10 - manager.where_sql.should be_like %{ WHERE "users"."id" = 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.should be_nil + manager.where_sql.must_be_nil end end @@ -417,7 +416,7 @@ def execute sql, name = nil, *args manager.take 1 manager.update(SqlLiteral.new('foo = bar')) - engine.executed.last.should be_like %{ + engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1) } @@ -431,7 +430,7 @@ def execute sql, name = nil, *args manager.order :foo manager.update(SqlLiteral.new('foo = bar')) - engine.executed.last.should be_like %{ + engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo) } @@ -444,7 +443,7 @@ def execute sql, name = nil, *args manager.from table manager.update(SqlLiteral.new('foo = bar')) - engine.executed.last.should be_like %{ UPDATE "users" SET foo = bar } + engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar } end it 'copies where clauses' do @@ -455,7 +454,7 @@ def execute sql, name = nil, *args manager.from table manager.update(table[:id] => 1) - engine.executed.last.should be_like %{ + engine.executed.last.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 } end @@ -467,7 +466,7 @@ def execute sql, name = nil, *args manager.from table manager.update(table[:id] => 1) - engine.executed.last.should be_like %{ + engine.executed.last.must_be_like %{ UPDATE "users" SET "id" = 1 } end @@ -479,21 +478,21 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new('foo'), Nodes::SqlLiteral.new('bar') - manager.to_sql.should be_like %{ SELECT foo, bar } + manager.to_sql.must_be_like %{ SELECT foo, bar } end it 'takes strings' do table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new('*') - manager.to_sql.should be_like %{ SELECT * } + manager.to_sql.must_be_like %{ SELECT * } end it "takes sql literals" do table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new '*' - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT * } end @@ -507,7 +506,7 @@ def execute sql, name = nil, *args manager.where(table['id'].eq(1)) manager.take 1 - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 1 @@ -518,7 +517,7 @@ def execute sql, name = nil, *args it "chains" do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.take(1).should == manager + manager.take(1).must_equal manager end end @@ -528,7 +527,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from(table).project(table['id']) manager.where(table['id'].eq(1)) - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 1 @@ -539,7 +538,7 @@ def execute sql, name = nil, *args table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.from(table) - manager.project(table['id']).where(table['id'].eq 1).should == manager + manager.project(table['id']).where(table['id'].eq 1).must_equal manager end end @@ -551,9 +550,9 @@ def execute sql, name = nil, *args mgr = left.join(right) mgr.project Nodes::SqlLiteral.new('*') - check mgr.on(predicate).should == mgr + check mgr.on(predicate).must_equal mgr - mgr.to_sql.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT * FROM "users" INNER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" @@ -568,26 +567,27 @@ def execute sql, name = nil, *args manager.from table manager.project table['id'] - manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' + 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 - check manager.from(table).project(table['id']).should == manager - manager.to_sql.should be_like 'SELECT "users"."id" FROM "users"' + check manager.from(table).project(table['id']).must_equal manager + manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"' end end - describe "TreeManager" do - subject do - table = Table.new :users - Arel::SelectManager.new(Table.engine).tap do |manager| - manager.from(table).project(table['id']) - end - end - - it_should_behave_like "TreeManager" - end + # HACK + # describe "TreeManager" do + # subject do + # table = Table.new :users + # Arel::SelectManager.new(Table.engine).tap do |manager| + # manager.from(table).project(table['id']) + # end + # end + # + # it_should_behave_like "TreeManager" + # end end end diff --git a/spec/table_spec.rb b/test/test_table.rb similarity index 60% rename from spec/table_spec.rb rename to test/test_table.rb index 77a600877e5a9..ecb5c1eb79553 100644 --- a/spec/table_spec.rb +++ b/test/test_table.rb @@ -1,27 +1,6 @@ require 'spec_helper' -describe '#Table' do - it 'creates a base relation variable' do - name = :foo - Table(name) == Arel::Table.new(name) - end - - it 'should have a default engine' do - Table(:foo).engine.should == Arel::Table.engine - end - - it 'can take an engine' do - engine = Arel::Table.engine - Table(:foo, engine).engine.should be engine - end - it 'can take an options hash' do - engine = Arel::Table.engine - options = { :engine => engine } - Table(:foo, options).engine.should be engine - end -end - -module Arel +module Arel describe Table do before do @relation = Table.new(:users) @@ -29,21 +8,21 @@ module Arel describe 'primary_key' do it 'should return an attribute' do - check @relation.primary_key.name.should == :id + check @relation.primary_key.name.must_equal :id end end describe 'select_manager' do it 'should return an empty select manager' do sm = @relation.select_manager - sm.to_sql.should be_like 'SELECT' + 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.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING "users"."id" = 10 } end @@ -52,7 +31,7 @@ module Arel describe 'backwards compat' do describe 'joins' do it 'returns nil' do - check @relation.joins(nil).should == nil + check @relation.joins(nil).must_equal nil end end @@ -60,7 +39,7 @@ module Arel it 'noops on nil' do mgr = @relation.join nil - mgr.to_sql.should be_like %{ SELECT FROM "users" } + mgr.to_sql.must_be_like %{ SELECT FROM "users" } end it 'takes a second argument for join type' do @@ -68,7 +47,7 @@ module Arel predicate = @relation[:id].eq(right[:id]) mgr = @relation.join(right, Nodes::OuterJoin).on(predicate) - mgr.to_sql.should be_like %{ + mgr.to_sql.must_be_like %{ SELECT FROM "users" LEFT OUTER JOIN "users" "users_2" ON "users"."id" = "users_2"."id" @@ -80,7 +59,7 @@ module Arel describe 'group' do it 'should create a group' do manager = @relation.group @relation[:id] - manager.to_sql.should be_like %{ + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY "users"."id" } end @@ -88,13 +67,12 @@ module Arel describe 'alias' do it 'should create a node that proxies to a table' do - check @relation.aliases.should == [] + check @relation.aliases.must_equal [] node = @relation.alias - check @relation.aliases.should == [node] - check node.name.should == 'users_2' - check node[:id].relation.should == node - check node[:id].relation.should != node + check @relation.aliases.must_equal [node] + check node.name.must_equal 'users_2' + check node[:id].relation.must_equal node end end @@ -102,30 +80,30 @@ module Arel it 'takes :columns' do columns = Table.engine.connection.columns("users") @relation = Table.new(:users, :columns => columns) - check @relation.columns.first.name.should == :id - check @relation.engine.should == Table.engine + check @relation.columns.first.name.must_equal :id + check @relation.engine.must_equal Table.engine end it 'should accept an engine' do rel = Table.new :users, 'foo' - check rel.engine.should == 'foo' + check rel.engine.must_equal 'foo' end it 'should accept a hash' do rel = Table.new :users, :engine => 'foo' - check rel.engine.should == 'foo' + check rel.engine.must_equal 'foo' end it 'ignores as if it equals name' do rel = Table.new :users, :as => 'users' - rel.table_alias.should be_nil + rel.table_alias.must_be_nil end end describe 'order' do it "should take an order" do manager = @relation.order "foo" - manager.to_sql.should be_like %{ SELECT FROM "users" ORDER BY foo } + manager.to_sql.must_be_like %{ SELECT FROM "users" ORDER BY foo } end end @@ -133,19 +111,19 @@ module Arel it "should add a limit" do manager = @relation.take 1 manager.project SqlLiteral.new '*' - manager.to_sql.should be_like %{ SELECT * FROM "users" LIMIT 1 } + 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.should be_like %{ SELECT * FROM "users" } + 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.should be_like %{ SELECT *, * FROM "users" } + manager.to_sql.must_be_like %{ SELECT *, * FROM "users" } end end @@ -153,8 +131,8 @@ module Arel it "returns a tree manager" do manager = @relation.where @relation[:id].eq 1 manager.project @relation[:id] - manager.should be_kind_of TreeManager - manager.to_sql.should be_like %{ + manager.must_be_kind_of TreeManager + manager.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" = 1 @@ -165,31 +143,31 @@ module Arel describe 'columns' do it 'returns a list of columns' do columns = @relation.columns - check columns.length.should == 2 - columns.map { |x| x.name.to_s }.sort.should == %w{ name id }.sort + check columns.length.must_equal 2 + columns.map { |x| x.name.to_s }.sort.must_equal %w{ name id }.sort end end it "should have a name" do - @relation.name.should == :users + @relation.name.must_equal :users end it "should have an engine" do - @relation.engine.should == Table.engine + @relation.engine.must_equal Table.engine end describe '[]' do - describe 'when given a', Symbol do + describe 'when given a Symbol' do it "manufactures an attribute if the symbol names an attribute within the relation" do column = @relation[:id] - check column.name.should == :id - column.should be_kind_of Attributes::Integer + check column.name.must_equal :id + column.must_be_kind_of Attributes::Integer end end describe 'when table does not exist' do it 'returns nil' do - @relation[:foooo].should be_nil + @relation[:foooo].must_be_nil end end end diff --git a/spec/update_manager_spec.rb b/test/test_update_manager.rb similarity index 69% rename from spec/update_manager_spec.rb rename to test/test_update_manager.rb index 016b6f69b14ca..670f19d621782 100644 --- a/spec/update_manager_spec.rb +++ b/test/test_update_manager.rb @@ -14,7 +14,7 @@ module Arel um = Arel::UpdateManager.new Table.engine um.table table um.set [[table[:name], nil]] - um.to_sql.should be_like %{ UPDATE "users" SET "name" = NULL } + um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL } end it 'takes a string' do @@ -22,7 +22,7 @@ module Arel um = Arel::UpdateManager.new Table.engine um.table table um.set Nodes::SqlLiteral.new "foo = bar" - um.to_sql.should be_like %{ UPDATE "users" SET foo = bar } + um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end it 'takes a list of lists' do @@ -30,7 +30,7 @@ module Arel um = Arel::UpdateManager.new Table.engine um.table table um.set [[table[:id], 1], [table[:name], 'hello']] - um.to_sql.should be_like %{ + um.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1, "name" = 'hello' } end @@ -38,7 +38,7 @@ module Arel it 'chains' do table = Table.new(:users) um = Arel::UpdateManager.new Table.engine - um.set([[table[:id], 1], [table[:name], 'hello']]).should == um + um.set([[table[:id], 1], [table[:name], 'hello']]).must_equal um end end @@ -46,12 +46,12 @@ module Arel it 'generates an update statement' do um = Arel::UpdateManager.new Table.engine um.table Table.new(:users) - um.to_sql.should be_like %{ UPDATE "users" } + um.to_sql.must_be_like %{ UPDATE "users" } end it 'chains' do um = Arel::UpdateManager.new Table.engine - um.table(Table.new(:users)).should == um + um.table(Table.new(:users)).must_equal um end end @@ -61,7 +61,7 @@ module Arel um = Arel::UpdateManager.new Table.engine um.table table um.where table[:id].eq(1) - um.to_sql.should be_like %{ + um.to_sql.must_be_like %{ UPDATE "users" WHERE "users"."id" = 1 } end @@ -70,20 +70,21 @@ module Arel table = Table.new :users um = Arel::UpdateManager.new Table.engine um.table table - um.where(table[:id].eq(1)).should == um + um.where(table[:id].eq(1)).must_equal um end end - describe "TreeManager" do - subject do - table = Table.new :users - Arel::UpdateManager.new(Table.engine).tap do |manager| - manager.table table - manager.where table[:id].eq(1) - end - end - - it_should_behave_like "TreeManager" - end + # HACK + # describe "TreeManager" do + # subject do + # table = Table.new :users + # Arel::UpdateManager.new(Table.engine).tap do |manager| + # manager.table table + # manager.where table[:id].eq(1) + # end + # end + # + # it_should_behave_like "TreeManager" + # end end end diff --git a/spec/visitors/join_sql_spec.rb b/test/visitors/test_join_sql.rb similarity index 90% rename from spec/visitors/join_sql_spec.rb rename to test/visitors/test_join_sql.rb index 9064dae85298e..3dc70d7dd6702 100644 --- a/spec/visitors/join_sql_spec.rb +++ b/test/visitors/test_join_sql.rb @@ -12,7 +12,7 @@ module Visitors t = Table.new :users join = Nodes::InnerJoin.new t, t, Nodes::On.new(t[:id]) j2 = Nodes::InnerJoin.new join, t, Nodes::On.new(t[:id]) - @visitor.accept(j2).should be_like %{ + @visitor.accept(j2).must_be_like %{ INNER JOIN "users" ON "users"."id" INNER JOIN "users" ON "users"."id" } @@ -24,7 +24,7 @@ module Visitors t = Table.new :users join = Nodes::OuterJoin.new t, t, Nodes::On.new(t[:id]) j2 = Nodes::OuterJoin.new join, t, Nodes::On.new(t[:id]) - @visitor.accept(j2).should be_like %{ + @visitor.accept(j2).must_be_like %{ LEFT OUTER JOIN "users" ON "users"."id" LEFT OUTER JOIN "users" ON "users"."id" } diff --git a/spec/visitors/oracle_spec.rb b/test/visitors/test_oracle.rb similarity index 91% rename from spec/visitors/oracle_spec.rb rename to test/visitors/test_oracle.rb index 93ade3ef3c96a..8b5732f287f7a 100644 --- a/spec/visitors/oracle_spec.rb +++ b/test/visitors/test_oracle.rb @@ -14,7 +14,7 @@ module Visitors stmt.cores.first.projections << Nodes::SqlLiteral.new(select) stmt.orders << Nodes::SqlLiteral.new('foo') sql = @visitor.accept(stmt) - sql.should be_like %{ + sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__ } end @@ -28,7 +28,7 @@ module Visitors sql = @visitor.accept(stmt) sql2 = @visitor.accept(stmt) - check sql.should == sql2 + check sql.must_equal sql2 end it 'splits orders with commas' do @@ -38,7 +38,7 @@ module Visitors stmt.cores.first.projections << Nodes::SqlLiteral.new(select) stmt.orders << Nodes::SqlLiteral.new('foo, bar') sql = @visitor.accept(stmt) - sql.should be_like %{ + sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__, alias_1__ } end @@ -49,7 +49,7 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.limit = 10 sql = @visitor.accept stmt - sql.should be_like %{ SELECT WHERE ROWNUM <= 10 } + sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 } end it 'is idempotent' do @@ -58,7 +58,7 @@ module Visitors stmt.limit = 10 sql = @visitor.accept stmt sql2 = @visitor.accept stmt - check sql.should == sql2 + check sql.must_equal sql2 end it 'creates a subquery when there is order_by' do @@ -66,7 +66,7 @@ module Visitors stmt.orders << Nodes::SqlLiteral.new('foo') stmt.limit = 10 sql = @visitor.accept stmt - sql.should be_like %{ + sql.must_be_like %{ SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10 } end @@ -76,7 +76,7 @@ module Visitors stmt.cores.first.projections << Nodes::SqlLiteral.new('DISTINCT id') stmt.limit = 10 sql = @visitor.accept stmt - sql.should be_like %{ + sql.must_be_like %{ SELECT * FROM (SELECT DISTINCT id) WHERE ROWNUM <= 10 } end @@ -86,7 +86,7 @@ module Visitors stmt.limit = 10 stmt.offset = Nodes::Offset.new(10) sql = @visitor.accept stmt - sql.should be_like %{ + sql.must_be_like %{ SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (SELECT ) raw_sql_ @@ -102,7 +102,7 @@ module Visitors stmt.offset = Nodes::Offset.new(10) sql = @visitor.accept stmt sql2 = @visitor.accept stmt - check sql.should == sql2 + check sql.must_equal sql2 end end end diff --git a/spec/visitors/postgres_spec.rb b/test/visitors/test_postgres.rb similarity index 81% rename from spec/visitors/postgres_spec.rb rename to test/visitors/test_postgres.rb index b5174a4c04c01..70b935c185f59 100644 --- a/spec/visitors/postgres_spec.rb +++ b/test/visitors/test_postgres.rb @@ -8,7 +8,7 @@ module Visitors end it 'should produce a lock value' do - @visitor.accept(Nodes::Lock.new).should be_like %{ + @visitor.accept(Nodes::Lock.new).must_be_like %{ FOR UPDATE } end diff --git a/spec/visitors/to_sql_spec.rb b/test/visitors/test_to_sql.rb similarity index 82% rename from spec/visitors/to_sql_spec.rb rename to test/visitors/test_to_sql.rb index a2862e4c4f5a3..f7455d7fa3184 100644 --- a/spec/visitors/to_sql_spec.rb +++ b/test/visitors/test_to_sql.rb @@ -11,13 +11,13 @@ module Visitors describe 'equality' do it 'should handle false' do sql = @visitor.accept Nodes::Equality.new(false, false) - sql.should be_like %{ 'f' = 'f' } + 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.should be_like %{ "users"."id" = 1 } + sql.must_be_like %{ "users"."id" = 1 } end end @@ -43,14 +43,14 @@ module Visitors it "should visit_Arel_Nodes_And" do node = Nodes::And.new @attr.eq(10), @attr.eq(11) - @visitor.accept(node).should be_like %{ + @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).should be_like %{ + @visitor.accept(node).must_be_like %{ "users"."id" = 10 OR "users"."id" = 11 } end @@ -63,13 +63,13 @@ module Visitors it "should visit_TrueClass" do test = @attr.eq(true) test.left.column.type = :boolean - @visitor.accept(test).should be_like %{ "users"."id" = 't' } + @visitor.accept(test).must_be_like %{ "users"."id" = 't' } end describe "Nodes::Ordering" do it "should know how to visit" do node = @attr.desc - @visitor.accept(node).should be_like %{ + @visitor.accept(node).must_be_like %{ "users"."id" DESC } end @@ -78,28 +78,28 @@ module Visitors describe "Nodes::In" do it "should know how to visit" do node = @attr.in [1, 2, 3] - @visitor.accept(node).should be_like %{ + @visitor.accept(node).must_be_like %{ "users"."id" IN (1, 2, 3) } end it "should turn empty right to NULL" do node = @attr.in [] - @visitor.accept(node).should be_like %{ + @visitor.accept(node).must_be_like %{ "users"."id" IN (NULL) } end it 'can handle two dot ranges' do node = @attr.in 1..3 - @visitor.accept(node).should be_like %{ + @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).should be_like %{ + @visitor.accept(node).must_be_like %{ "users"."id" >= 1 AND "users"."id" < 3 } end @@ -116,7 +116,7 @@ def quote value, column = nil in_node = Nodes::In.new @attr, %w{ a b c } visitor = visitor.new(Table.engine) visitor.expected = @attr.column - lambda { visitor.accept(in_node) }.should_not raise_error + visitor.accept(in_node).must_equal %("users"."id" IN ('a', 'b', 'c')) end end @@ -124,7 +124,7 @@ def quote value, column = nil it "should escape strings" do test = @attr.eq 'Aaron Patterson' test.left.column.type = :string - @visitor.accept(test).should be_like %{ + @visitor.accept(test).must_be_like %{ "users"."id" = 'Aaron Patterson' } end From c291d6ce7f88d6884b2a04effbb58cf730c83347 Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Mon, 18 Oct 2010 15:41:41 -0700 Subject: [PATCH 0806/1492] damnit --- TAGS | 5725 ---------------------------------------------------------- 1 file changed, 5725 deletions(-) delete mode 100644 TAGS diff --git a/TAGS b/TAGS deleted file mode 100644 index 39d7f7e2f45a9..0000000000000 --- a/TAGS +++ /dev/null @@ -1,5725 +0,0 @@ - -fuck_spec.rb ,32 -def check truthinesscheck3,20 - -fuck_spec.rb ~,0 - -lib/arel/attributes/attribute.rb,1878 -module ArelArel1,0 - module AttributesAttributes2,12 - class Attribute < Struct.new :relation, :name, :columnAttribute3,32 - def not_eq othernot_eq6,124 - def not_eq_any othersnot_eq_any10,198 - def not_eq_all othersnot_eq_all14,274 - def eq othereq18,350 - def eq_any otherseq_any22,420 - def eq_all otherseq_all26,488 - def in otherin30,556 - def in_any othersin_any47,1079 - def in_all othersin_all51,1147 - def not_in othernot_in55,1215 - def not_in_any othersnot_in_any74,1823 - def not_in_all othersnot_in_all78,1899 - def matches othermatches82,1975 - def matches_any othersmatches_any86,2049 - def matches_all othersmatches_all90,2127 - def does_not_match otherdoes_not_match94,2205 - def does_not_match_any othersdoes_not_match_any98,2291 - def does_not_match_all othersdoes_not_match_all102,2383 - def gteq rightgteq106,2475 - def gteq_any othersgteq_any110,2557 - def gteq_all othersgteq_all114,2629 - def gt rightgt118,2701 - def gt_any othersgt_any122,2774 - def gt_all othersgt_all126,2842 - def lt rightlt130,2910 - def lt_any otherslt_any134,2980 - def lt_all otherslt_all138,3048 - def lteq rightlteq142,3116 - def lteq_any otherslteq_any146,3195 - def lteq_all otherslteq_all150,3267 - def ascasc154,3339 - def descdesc158,3403 - def grouping_any method_id, othersgrouping_any164,3484 - def grouping_all method_id, othersgrouping_all172,3708 - class String < Attribute; endString181,3941 - class Time < Attribute; endTime182,3976 - class Boolean < Attribute; endBoolean183,4011 - class Decimal < Attribute; endDecimal184,4046 - class Float < Attribute; endFloat185,4081 - class Integer < Attribute; endInteger186,4116 - -lib/arel/attributes.rb,92 -module ArelArel3,37 - module AttributesAttributes4,49 - def self.for columnfor7,152 - -lib/arel/compatibility/wheres.rb,296 -module ArelArel1,0 - module Compatibility # :nodoc:Compatibility2,12 - class Wheres # :nodoc:Wheres3,45 - module Value # :nodoc:Value6,98 - def valuevalue8,158 - def namename12,219 - def initialize engine, collectioninitialize17,282 - def eacheach22,395 - -lib/arel/crud.rb,145 -module ArelArel1,0 - module CrudCrud4,57 - def update valuesupdate6,111 - def insert valuesinsert24,537 - def deletedelete30,670 - -lib/arel/delete_manager.rb,231 -module ArelArel1,0 - class DeleteManager < Arel::TreeManagerDeleteManager2,12 - def initialize engineinitialize3,54 - def from relationfrom8,142 - def where expressionwhere13,216 - def wheres= listwheres=18,294 - -lib/arel/deprecated.rb,21 -module ArelArel1,0 - -lib/arel/expression.rb,57 -module ArelArel1,0 - module ExpressionExpression2,12 - -lib/arel/expressions.rb,216 -module ArelArel1,0 - module ExpressionsExpressions2,12 - def count distinct = falsecount3,33 - def sumsum7,113 - def maximummaximum11,195 - def minimumminimum15,281 - def averageaverage19,367 - -lib/arel/insert_manager.rb,300 -module ArelArel1,0 - class InsertManager < Arel::TreeManagerInsertManager2,12 - def initialize engineinitialize3,54 - def into tableinto8,142 - def columns; @head.columns endcolumns13,210 - def values= val; @head.values = val; endvalues=14,245 - def insert fieldsinsert16,291 - -lib/arel/nodes/and.rb,92 -module ArelArel1,0 - module NodesNodes2,12 - class And < Arel::Nodes::BinaryAnd3,27 - -lib/arel/nodes/assignment.rb,106 -module ArelArel1,0 - module NodesNodes2,12 - class Assignment < Arel::Nodes::BinaryAssignment3,27 - -lib/arel/nodes/avg.rb,94 -module ArelArel1,0 - module NodesNodes2,12 - class Avg < Arel::Nodes::FunctionAvg3,27 - -lib/arel/nodes/between.rb,100 -module ArelArel1,0 - module NodesNodes2,12 - class Between < Arel::Nodes::BinaryBetween3,27 - -lib/arel/nodes/binary.rb,145 -module ArelArel1,0 - module NodesNodes2,12 - class Binary < Arel::Nodes::NodeBinary3,27 - def initialize left, rightinitialize6,99 - -lib/arel/nodes/count.rb,171 -module ArelArel1,0 - module NodesNodes2,12 - class Count < Arel::Nodes::FunctionCount3,27 - def initialize expr, distinct = false, aliaz = nilinitialize7,99 - -lib/arel/nodes/delete_statement.rb,186 -module ArelArel1,0 - module NodesNodes2,12 - class DeleteStatementDeleteStatement3,27 - def initializeinitialize6,93 - def initialize_copy otherinitialize_copy11,168 - -lib/arel/nodes/does_not_match.rb,110 -module ArelArel1,0 - module NodesNodes2,12 - class DoesNotMatch < Arel::Nodes::BinaryDoesNotMatch3,27 - -lib/arel/nodes/equality.rb,144 -module ArelArel1,0 - module NodesNodes2,12 - class Equality < Arel::Nodes::BinaryEquality3,27 - def operator; :== endoperator4,68 - -lib/arel/nodes/exists.rb,125 -module ArelArel1,0 - module NodesNodes2,12 - class ExistsExists3,27 - def initialize select_stmtinitialize6,76 - -lib/arel/nodes/function.rb,185 -module ArelArel1,0 - module NodesNodes2,12 - class Function < Arel::Nodes::NodeFunction3,27 - def initialize expr, aliaz = nilinitialize7,139 - def as aliazas12,246 - -lib/arel/nodes/greater_than.rb,108 -module ArelArel1,0 - module NodesNodes2,12 - class GreaterThan < Arel::Nodes::BinaryGreaterThan3,27 - -lib/arel/nodes/greater_than_or_equal.rb,122 -module ArelArel1,0 - module NodesNodes2,12 - class GreaterThanOrEqual < Arel::Nodes::BinaryGreaterThanOrEqual3,27 - -lib/arel/nodes/group.rb,116 -module ArelArel1,0 - module NodesNodes2,12 - class GroupGroup3,27 - def initialize exprinitialize6,70 - -lib/arel/nodes/grouping.rb,148 -module ArelArel1,0 - module NodesNodes2,12 - class Grouping < Arel::Nodes::NodeGrouping3,27 - def initialize expressioninitialize6,93 - -lib/arel/nodes/having.rb,118 -module ArelArel1,0 - module NodesNodes2,12 - class HavingHaving3,27 - def initialize exprinitialize6,71 - -lib/arel/nodes/in.rb,79 -module ArelArel1,0 - module NodesNodes2,12 - class In < EqualityIn3,27 - -lib/arel/nodes/inner_join.rb,102 -module ArelArel1,0 - module NodesNodes2,12 - class InnerJoin < Arel::Nodes::JoinInnerJoin3,27 - -lib/arel/nodes/insert_statement.rb,187 -module ArelArel1,0 - module NodesNodes2,12 - class InsertStatementInsertStatement3,27 - def initializeinitialize6,103 - def initialize_copy otherinitialize_copy12,206 - -lib/arel/nodes/join.rb,133 -module ArelArel1,0 - module NodesNodes2,12 - class JoinJoin3,27 - def initialize left, right, constraintinitialize6,90 - -lib/arel/nodes/less_than.rb,102 -module ArelArel1,0 - module NodesNodes2,12 - class LessThan < Arel::Nodes::BinaryLessThan3,27 - -lib/arel/nodes/less_than_or_equal.rb,116 -module ArelArel1,0 - module NodesNodes2,12 - class LessThanOrEqual < Arel::Nodes::BinaryLessThanOrEqual3,27 - -lib/arel/nodes/lock.rb,72 -module ArelArel1,0 - module NodesNodes2,12 - class LockLock3,27 - -lib/arel/nodes/matches.rb,100 -module ArelArel1,0 - module NodesNodes2,12 - class Matches < Arel::Nodes::BinaryMatches3,27 - -lib/arel/nodes/max.rb,94 -module ArelArel1,0 - module NodesNodes2,12 - class Max < Arel::Nodes::FunctionMax3,27 - -lib/arel/nodes/min.rb,94 -module ArelArel1,0 - module NodesNodes2,12 - class Min < Arel::Nodes::FunctionMin3,27 - -lib/arel/nodes/node.rb,184 -module ArelArel1,0 - module NodesNodes2,12 - class NodeNode5,79 - def or rightor9,207 - def and rightand15,355 - def to_sql engine = Table.engineto_sql24,684 - -lib/arel/nodes/not_equal.rb,102 -module ArelArel1,0 - module NodesNodes2,12 - class NotEqual < Arel::Nodes::BinaryNotEqual3,27 - -lib/arel/nodes/not_in.rb,96 -module ArelArel1,0 - module NodesNodes2,12 - class NotIn < Arel::Nodes::BinaryNotIn3,27 - -lib/arel/nodes/offset.rb,119 -module ArelArel1,0 - module NodesNodes2,12 - class OffsetOffset3,27 - def initialize valueinitialize6,72 - -lib/arel/nodes/on.rb,110 -module ArelArel1,0 - module NodesNodes2,12 - class OnOn3,27 - def initialize exprinitialize6,67 - -lib/arel/nodes/or.rb,90 -module ArelArel1,0 - module NodesNodes2,12 - class Or < Arel::Nodes::BinaryOr3,27 - -lib/arel/nodes/ordering.rb,247 -module ArelArel1,0 - module NodesNodes2,12 - class Ordering < Arel::Nodes::NodeOrdering3,27 - def initialize expression, direction = :ascinitialize6,105 - def ascending?ascending?10,216 - def descending?descending?14,274 - -lib/arel/nodes/outer_join.rb,102 -module ArelArel1,0 - module NodesNodes2,12 - class OuterJoin < Arel::Nodes::JoinOuterJoin3,27 - -lib/arel/nodes/select_core.rb,177 -module ArelArel1,0 - module NodesNodes2,12 - class SelectCoreSelectCore3,27 - def initializeinitialize7,136 - def initialize_copy otherinitialize_copy15,300 - -lib/arel/nodes/select_statement.rb,212 -module ArelArel1,0 - module NodesNodes2,12 - class SelectStatementSelectStatement3,27 - def initialize cores = [SelectCore.new]initialize7,131 - def initialize_copy otherinitialize_copy15,299 - -lib/arel/nodes/sql_literal.rb,93 -module ArelArel1,0 - module NodesNodes2,12 - class SqlLiteral < StringSqlLiteral3,27 - -lib/arel/nodes/string_join.rb,153 -module ArelArel1,0 - module NodesNodes2,12 - class StringJoin < Arel::Nodes::JoinStringJoin3,27 - def initialize left, rightinitialize6,93 - -lib/arel/nodes/sum.rb,94 -module ArelArel1,0 - module NodesNodes2,12 - class Sum < Arel::Nodes::FunctionSum3,27 - -lib/arel/nodes/table_alias.rb,165 -module ArelArel1,0 - module NodesNodes2,12 - class TableAliasTableAlias3,27 - def initialize name, relationinitialize7,125 - def [] name[]15,343 - -lib/arel/nodes/unqualified_column.rb,203 -module ArelArel1,0 - module NodesNodes2,12 - class UnqualifiedColumnUnqualifiedColumn3,27 - def initialize attributeinitialize6,87 - def columncolumn10,160 - def namename14,214 - -lib/arel/nodes/update_statement.rb,187 -module ArelArel1,0 - module NodesNodes2,12 - class UpdateStatementUpdateStatement3,27 - def initializeinitialize6,119 - def initialize_copy otherinitialize_copy14,264 - -lib/arel/nodes/values.rb,133 -module ArelArel1,0 - module NodesNodes2,12 - class ValuesValues3,27 - def initialize exprs, columns = []initialize6,88 - -lib/arel/nodes.rb,0 - -lib/arel/relation.rb,53 -module ArelArel1,0 - module RelationRelation4,72 - -lib/arel/select_manager.rb,1162 -module ArelArel1,0 - class SelectManager < Arel::TreeManagerSelectManager2,12 - def initialize engine, table = nilinitialize5,78 - def takentaken12,239 - def constraintsconstraints16,280 - def skip amountskip20,327 - def where_clauseswhere_clauses25,414 - def lock locking = truelock31,588 - def lockedlocked38,796 - def on *exprson42,837 - def group *columnsgroup47,936 - def from tablefrom58,1245 - def join relation, klass = Nodes::InnerJoinjoin76,1699 - def having exprhaving88,2009 - def project *projectionsproject95,2154 - def where exprwhere104,2440 - def order *exprorder109,2505 - def ordersorders117,2744 - def whereswheres121,2787 - def where_sqlwhere_sql125,2864 - def take limittake132,3014 - def join_sqljoin_sql137,3079 - def order_clausesorder_clauses144,3227 - def joins managerjoins150,3364 - class Row < Struct.new(:data) # :nodoc:Row154,3418 - def idid155,3462 - def method_missing(name, *args)method_missing159,3505 - def to_a # :nodoc:to_a166,3646 - def insert valuesinsert173,3921 - def collapse exprscollapse189,4729 - -lib/arel/sql/engine.rb,106 -module ArelArel1,0 - module SqlSql2,12 - class EngineEngine3,25 - def self.new thingnew4,42 - -lib/arel/sql_literal.rb,76 -module ArelArel1,0 - class SqlLiteral < Nodes::SqlLiteralSqlLiteral2,12 - -lib/arel/table.rb,822 -module ArelArel1,0 - class TableTable2,12 - def initialize name, engine = Table.engineinitialize10,173 - def primary_keyprimary_key29,755 - def aliasalias37,989 - def from tablefrom43,1108 - def joins managerjoins47,1176 - def join relation, klass = Nodes::InnerJoinjoin51,1217 - def group *columnsgroup63,1521 - def order *exprorder67,1586 - def where conditionwhere71,1645 - def project *thingsproject75,1711 - def take amounttake79,1778 - def having exprhaving83,1836 - def columnscolumns87,1894 - def [] name[]92,2015 - def select_managerselect_manager99,2156 - def attributes_for columnsattributes_for105,2234 - def table_exists?table_exists?113,2415 - def tablestables117,2530 - def self.table_cache engine # :nodoc:table_cache122,2616 - -lib/arel/tree_manager.rb,212 -module ArelArel1,0 - class TreeManagerTreeManager2,12 - def initialize engineinitialize8,114 - def to_dotto_dot13,219 - def to_sqlto_sql17,280 - def initialize_copy otherinitialize_copy21,332 - -lib/arel/update_manager.rb,319 -module ArelArel1,0 - class UpdateManager < Arel::TreeManagerUpdateManager2,12 - def initialize engineinitialize3,54 - def take limittake8,142 - def order *exprorder13,207 - def table tabletable20,302 - def wheres= exprswheres=25,371 - def where exprwhere29,429 - def set valuesset34,495 - -lib/arel/visitors/dot.rb,2083 -module ArelArel1,0 - module VisitorsVisitors2,12 - class DotDot3,30 - class Node # :nodoc:Node4,44 - def initialize name, id, fields = []initialize7,114 - class Edge < Struct.new :name, :from, :to # :nodoc:Edge14,257 - def initializeinitialize17,326 - def accept objectaccept25,483 - def visit_Arel_Nodes_Grouping ovisit_Arel_Nodes_Grouping31,568 - def visit_Arel_Nodes_Ordering ovisit_Arel_Nodes_Ordering35,646 - def visit_Arel_Nodes_TableAlias ovisit_Arel_Nodes_TableAlias40,758 - def visit_Arel_Nodes_Sum ovisit_Arel_Nodes_Sum46,903 - def visit_Arel_Nodes_Count ovisit_Arel_Nodes_Count53,1125 - def visit_Arel_Nodes_On ovisit_Arel_Nodes_On58,1240 - def visit_Arel_Nodes_Values ovisit_Arel_Nodes_Values62,1312 - def visit_Arel_Nodes_StringJoin ovisit_Arel_Nodes_StringJoin66,1395 - def visit_Arel_Nodes_InnerJoin ovisit_Arel_Nodes_InnerJoin71,1505 - def visit_Arel_Nodes_DeleteStatement ovisit_Arel_Nodes_DeleteStatement78,1717 - def visit_Arel_Nodes_UnqualifiedColumn ovisit_Arel_Nodes_UnqualifiedColumn83,1837 - def visit_Arel_Nodes_Offset ovisit_Arel_Nodes_Offset87,1929 - def visit_Arel_Nodes_InsertStatement ovisit_Arel_Nodes_InsertStatement91,2006 - def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore97,2158 - def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement103,2306 - def visit_Arel_Nodes_UpdateStatement ovisit_Arel_Nodes_UpdateStatement110,2484 - def visit_Arel_Table ovisit_Arel_Table116,2635 - def visit_Arel_Attribute ovisit_Arel_Attribute120,2704 - def visit_Arel_Nodes_Equality ovisit_Arel_Nodes_Equality131,3196 - def visit_String ovisit_String149,4292 - def visit_Hash ovisit_Hash165,4879 - def visit_Array ovisit_Array171,5009 - def visit_edge o, methodvisit_edge177,5121 - def visit ovisit181,5209 - def edge nameedge195,5542 - def with_node nodewith_node203,5712 - def quote stringquote213,5889 - def to_dotto_dot217,5959 - -lib/arel/visitors/join_sql.rb,406 -module ArelArel1,0 - module VisitorsVisitors2,12 - class JoinSql < Arel::Visitors::ToSqlJoinSql11,330 - def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore12,372 - def visit_Arel_Nodes_StringJoin ovisit_Arel_Nodes_StringJoin16,489 - def visit_Arel_Nodes_OuterJoin ovisit_Arel_Nodes_OuterJoin23,654 - def visit_Arel_Nodes_InnerJoin ovisit_Arel_Nodes_InnerJoin30,876 - -lib/arel/visitors/mysql.rb,187 -module ArelArel1,0 - module VisitorsVisitors2,12 - class MySQL < Arel::Visitors::ToSqlMySQL3,30 - def visit_Arel_Nodes_UpdateStatement ovisit_Arel_Nodes_UpdateStatement4,70 - -lib/arel/visitors/oracle.rb,301 -module ArelArel1,0 - module VisitorsVisitors2,12 - class Oracle < Arel::Visitors::ToSqlOracle3,30 - def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement6,86 - def visit_Arel_Nodes_Offset ovisit_Arel_Nodes_Offset46,1288 - def order_hacks oorder_hacks52,1439 - -lib/arel/visitors/order_clauses.rb,201 -module ArelArel1,0 - module VisitorsVisitors2,12 - class OrderClauses < Arel::Visitors::ToSqlOrderClauses3,30 - def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement4,77 - -lib/arel/visitors/postgresql.rb,520 -module ArelArel1,0 - module VisitorsVisitors2,12 - class PostgreSQL < Arel::Visitors::ToSqlPostgreSQL3,30 - def visit_Arel_Nodes_Lock ovisit_Arel_Nodes_Lock5,89 - def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement9,155 - def visit_Arel_Nodes_Matches ovisit_Arel_Nodes_Matches28,708 - def visit_Arel_Nodes_DoesNotMatch ovisit_Arel_Nodes_DoesNotMatch32,805 - def using_distinct_on?(o)using_distinct_on?36,911 - def aliased_orders ordersaliased_orders44,1100 - -lib/arel/visitors/to_sql.rb,3412 -module ArelArel4,37 - module VisitorsVisitors5,49 - class ToSqlToSql6,67 - def initialize engineinitialize7,83 - def accept objectaccept15,273 - def visit_Arel_Nodes_DeleteStatement ovisit_Arel_Nodes_DeleteStatement24,471 - def visit_Arel_Nodes_UpdateStatement ovisit_Arel_Nodes_UpdateStatement31,697 - def visit_Arel_Nodes_InsertStatement ovisit_Arel_Nodes_InsertStatement51,1441 - def visit_Arel_Nodes_Exists ovisit_Arel_Nodes_Exists63,1750 - def visit_Arel_Nodes_Values ovisit_Arel_Nodes_Values67,1839 - def visit_Arel_Nodes_SelectStatement ovisit_Arel_Nodes_SelectStatement73,2027 - def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore83,2397 - def visit_Arel_Nodes_Having ovisit_Arel_Nodes_Having93,2821 - def visit_Arel_Nodes_Offset ovisit_Arel_Nodes_Offset97,2901 - def visit_Arel_Nodes_Lock ovisit_Arel_Nodes_Lock103,3077 - def visit_Arel_Nodes_Grouping ovisit_Arel_Nodes_Grouping106,3122 - def visit_Arel_Nodes_Ordering ovisit_Arel_Nodes_Ordering110,3199 - def visit_Arel_Nodes_Group ovisit_Arel_Nodes_Group114,3308 - def visit_Arel_Nodes_Count ovisit_Arel_Nodes_Count118,3375 - def visit_Arel_Nodes_Sum ovisit_Arel_Nodes_Sum124,3576 - def visit_Arel_Nodes_Max ovisit_Arel_Nodes_Max129,3733 - def visit_Arel_Nodes_Min ovisit_Arel_Nodes_Min134,3890 - def visit_Arel_Nodes_Avg ovisit_Arel_Nodes_Avg139,4047 - def visit_Arel_Nodes_TableAlias ovisit_Arel_Nodes_TableAlias144,4204 - def visit_Arel_Nodes_Between ovisit_Arel_Nodes_Between148,4312 - def visit_Arel_Nodes_GreaterThanOrEqual ovisit_Arel_Nodes_GreaterThanOrEqual152,4411 - def visit_Arel_Nodes_GreaterThan ovisit_Arel_Nodes_GreaterThan156,4516 - def visit_Arel_Nodes_LessThanOrEqual ovisit_Arel_Nodes_LessThanOrEqual160,4613 - def visit_Arel_Nodes_LessThan ovisit_Arel_Nodes_LessThan164,4715 - def visit_Arel_Nodes_Matches ovisit_Arel_Nodes_Matches168,4809 - def visit_Arel_Nodes_DoesNotMatch ovisit_Arel_Nodes_DoesNotMatch172,4905 - def visit_Arel_Nodes_StringJoin ovisit_Arel_Nodes_StringJoin176,5010 - def visit_Arel_Nodes_OuterJoin ovisit_Arel_Nodes_OuterJoin180,5104 - def visit_Arel_Nodes_InnerJoin ovisit_Arel_Nodes_InnerJoin184,5235 - def visit_Arel_Nodes_On ovisit_Arel_Nodes_On188,5377 - def visit_Arel_Table ovisit_Arel_Table192,5449 - def visit_Arel_Nodes_In ovisit_Arel_Nodes_In200,5646 - def visit_Arel_Nodes_NotIn ovisit_Arel_Nodes_NotIn207,5828 - def visit_Arel_Nodes_And ovisit_Arel_Nodes_And214,6017 - def visit_Arel_Nodes_Or ovisit_Arel_Nodes_Or218,6108 - def visit_Arel_Nodes_Assignment ovisit_Arel_Nodes_Assignment222,6197 - def visit_Arel_Nodes_Equality ovisit_Arel_Nodes_Equality227,6331 - def visit_Arel_Nodes_NotEqual ovisit_Arel_Nodes_NotEqual237,6533 - def visit_Arel_Nodes_UnqualifiedColumn ovisit_Arel_Nodes_UnqualifiedColumn247,6740 - def visit_Arel_Attributes_Attribute ovisit_Arel_Attributes_Attribute251,6836 - def visit_Fixnum o; o endvisit_Fixnum263,7503 - def visit_String o; quote(o, @last_column) endvisit_String267,7661 - def visit objectvisit284,8259 - def quote value, column = nilquote288,8337 - def quote_table_name namequote_table_name292,8424 - def quote_column_name namequote_column_name296,8535 - -lib/arel/visitors/where_sql.rb,183 -module ArelArel1,0 - module VisitorsVisitors2,12 - class WhereSql < Arel::Visitors::ToSqlWhereSql3,30 - def visit_Arel_Nodes_SelectCore ovisit_Arel_Nodes_SelectCore4,73 - -lib/arel/visitors.rb,109 -module ArelArel10,261 - module VisitorsVisitors11,273 - def self.visitor_for enginevisitor_for25,743 - -lib/arel.rb,58 -module ArelArel29,573 - def self.sql raw_sqlsql32,606 - -spec/support/check.rb,54 -module CheckCheck1,0 - def check(*args)check4,154 - -spec/support/matchers/be_like.rb,292 -module MatchersMatchers1,0 - class BeLikeBeLike2,16 - def initialize(expected)initialize3,31 - def matches?(actual)matches?7,119 - def failure_messagefailure_message12,226 - def negative_failure_messagenegative_failure_message16,314 - def be_like(expected)be_like21,419 - -spec/support/matchers.rb,0 - -spec/support/shared/tree_manager_shared.rb,0 - -test/attributes/test_attribute.rb,58 -module ArelArel3,23 - module AttributesAttributes4,35 - -test/nodes/test_count.rb,0 - -test/nodes/test_delete_statement.rb,0 - -test/nodes/test_equality.rb,318 -module ArelArel3,23 - module NodesNodes4,35 - def quote(*args) @quote_count += 1; super; endquote37,995 - def quote_column_name(*args) @quote_count += 1; super; endquote_column_name38,1056 - def quote_table_name(*args) @quote_count += 1; super; endquote_table_name39,1129 - -test/nodes/test_insert_statement.rb,0 - -test/nodes/test_or.rb,48 -module ArelArel3,23 - module NodesNodes4,35 - -test/nodes/test_select_core.rb,0 - -test/nodes/test_select_statement.rb,0 - -test/nodes/test_sql_literal.rb,48 -module ArelArel3,23 - module NodesNodes4,35 - -test/nodes/test_sum.rb,0 - -test/nodes/test_update_statement.rb,0 - -test/spec_helper.rb,108 -class ObjectObject21,441 - def must_be_like othermust_be_like22,454 - def check truthinesscheck27,575 - -test/support/fake_record.rb,742 -module FakeRecordFakeRecord1,0 - class Column < Struct.new(:name, :type)Column2,18 - class ConnectionConnection5,67 - def initializeinitialize8,111 - def primary_key nameprimary_key21,375 - def table_exists? nametable_exists?25,440 - def columns name, message = nilcolumns29,509 - def quote_table_name namequote_table_name33,580 - def quote_column_name namequote_column_name37,644 - def quote thing, column = nilquote41,709 - class ConnectionPoolConnectionPool62,1057 - class Spec < Struct.new(:config)Spec63,1080 - def initializeinitialize68,1162 - def with_connectionwith_connection73,1271 - class BaseBase78,1333 - def initializeinitialize81,1382 - def connectionconnection85,1454 - -test/test_activerecord_compat.rb,22 -module ArelArel3,23 - -test/test_attributes.rb,22 -module ArelArel3,23 - -test/test_crud.rb,319 -module ArelArel3,23 - class FakeCrudder < SelectManagerFakeCrudder4,35 - class FakeEngineFakeEngine5,71 - def initializeinitialize8,152 - def connection; self endconnection15,302 - def method_missing name, *argsmethod_missing17,334 - def initialize engine = FakeEngine.newinitialize27,487 - -test/test_delete_manager.rb,22 -module ArelArel3,23 - -test/test_insert_manager.rb,22 -module ArelArel3,23 - -test/test_select_manager.rb,533 -module ArelArel3,23 - class EngineProxyEngineProxy4,35 - def initialize engineinitialize10,161 - def with_connectionwith_connection18,331 - def connectionconnection22,381 - def quote_table_name thing; @engine.connection.quote_table_name thing endquote_table_name26,420 - def quote_column_name thing; @engine.connection.quote_column_name thing endquote_column_name27,498 - def quote thing, column; @engine.connection.quote thing, column endquote28,578 - def execute sql, name = nil, *argsexecute30,651 - -test/test_table.rb,22 -module ArelArel3,23 - -test/test_update_manager.rb,22 -module ArelArel3,23 - -test/visitors/test_join_sql.rb,54 -module ArelArel3,23 - module VisitorsVisitors4,35 - -test/visitors/test_oracle.rb,54 -module ArelArel3,23 - module VisitorsVisitors4,35 - -test/visitors/test_postgres.rb,54 -module ArelArel3,23 - module VisitorsVisitors4,35 - -test/visitors/test_to_sql.rb,111 -module ArelArel3,23 - module VisitorsVisitors4,35 - def quote value, column = nilquote111,2951 - -tmp/isolate/ruby-1.8/bin/autospec,0 - -tmp/isolate/ruby-1.8/bin/autotest,0 - -tmp/isolate/ruby-1.8/bin/edit_json.rb,0 - -tmp/isolate/ruby-1.8/bin/multigem,0 - -tmp/isolate/ruby-1.8/bin/multiruby,0 - -tmp/isolate/ruby-1.8/bin/multiruby_setup,0 - -tmp/isolate/ruby-1.8/bin/prettify_json.rb,0 - -tmp/isolate/ruby-1.8/bin/rake,0 - -tmp/isolate/ruby-1.8/bin/rubyforge,0 - -tmp/isolate/ruby-1.8/bin/sow,0 - -tmp/isolate/ruby-1.8/bin/spec,0 - -tmp/isolate/ruby-1.8/bin/unit_diff,0 - -tmp/isolate/ruby-1.8/bin/zentest,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/autotest,49 -class DirDir30,630 - def [](*args)[]33,681 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/multigem,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/multiruby,27 -def setenv dirsetenv7,76 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/multiruby_setup,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/unit_diff,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/bin/zentest,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/example1.rb,97 -module SomethingSomething1,0 - class ThingyThingy2,17 - def do_somethingdo_something3,32 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/example2.rb,205 -module TestSomethingTestSomething1,0 - class TestThingyTestThingy2,21 - def test_do_something_normaltest_do_something_normal3,40 - def test_do_something_edgecasetest_do_something_edgecase8,172 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/example_dot_autotest.rb,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/autoupdate.rb,124 -module Autotest::AutoUpdateAutotest1,0 - def self.sleep_time= osleep_time4,89 - def self.update_cmd= oupdate_cmd8,142 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/once.rb,36 -module Autotest::OnceAutotest4,53 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/rcov.rb,143 -module Autotest::RCovAutotest1,0 - def self.command= ocommand4,60 - def self.pattern= opattern8,107 - def self.options= ooptions12,209 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/restart.rb,38 -module Autotest::RestartAutotest1,0 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest/timestamp.rb,41 -module Autotest::TimestampAutotest3,16 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/autotest.rb,1582 -class AutotestAutotest60,1839 - def self.add_discovery &procadd_discovery81,2308 - def self.autodiscoverautodiscover110,3363 - def self.runrun123,3602 - def initializeinitialize152,4293 - def runrun191,5559 - def get_to_greenget_to_green220,6065 - def run_testsrun_tests230,6255 - def add_sigint_handleradd_sigint_handler281,7377 - def all_goodall_good300,7833 - def path_to_classname(s)path_to_classname308,7984 - def consolidate_failures(failed)consolidate_failures321,8355 - def find_filesfind_files345,9032 - def find_files_to_test files = find_filesfind_files_to_test376,9867 - def handle_results(results)handle_results398,10485 - def known_filesknown_files413,10891 - def make_test_cmd files_to_testmake_test_cmd423,11098 - def new_hash_of_arraysnew_hash_of_arrays442,11682 - def reorder files_to_testreorder446,11747 - def rerun_all_testsrerun_all_tests465,12260 - def resetreset476,12450 - def rubyruby491,12742 - def test_files_for(filename)test_files_for506,13143 - def wait_for_changeswait_for_changes522,13613 - def files_matching regexpfiles_matching533,13866 - def add_mapping(regexp, prepend = false, &proc)add_mapping549,14401 - def remove_mapping regexpremove_mapping561,14640 - def clear_mappingsclear_mappings573,14935 - def add_exception regexpadd_exception585,15203 - def remove_exception regexpremove_exception596,15470 - def clear_exceptionsclear_exceptions606,15730 - def exceptionsexceptions617,16020 - def hook(name, *args)hook637,16469 - def self.add_hook(name, &block)add_hook655,16834 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/focus.rb,79 -class ModuleModule1,0 - def focus *wantedsfocus2,13 - def blurblur10,214 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/functional_test_matrix.rb,146 -module FunctionalTestMatrixFunctionalTestMatrix70,2558 - def matrix(name, *setups)matrix71,2586 - def action(action, *results)action75,2659 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/multiruby.rb,1231 -module MultirubyMultiruby45,1592 - def self.env name, fallback; ENV[name] || fallback; end # :nodoc:env46,1609 - def self.build_and_installbuild_and_install63,2171 - def self.cleanclean123,4037 - def self.each_scm_build_direach_scm_build_dir138,4346 - def self.matching_versions url, matching=nilmatching_versions153,4651 - def self.fetch_tar vfetch_tar173,5130 - def self.gnu_utils_build inst_dirgnu_utils_build191,5671 - def self.helphelp199,5958 - def self.in_build_dirin_build_dir203,6000 - def self.in_install_dirin_install_dir209,6078 - def self.in_root_dir subdir = ""in_root_dir215,6160 - def self.in_tmp_dirin_tmp_dir221,6272 - def self.in_versions_dirin_versions_dir227,6346 - def self.listlist233,6430 - def self.merge_rubygemsmerge_rubygems242,6574 - def self.mri_latest_tag vmri_latest_tag257,6865 - def self.rake_build inst_dirrake_build261,6937 - def self.rm namerm266,7069 - def self.root_dirroot_dir274,7246 - def self.run base_cmd, log = nilrun286,7517 - def self.setup_dirs download = truesetup_dirs293,7721 - def self.svn_co url, dirsvn_co310,8236 - def self.tagstags317,8443 - def self.updateupdate333,8881 - def self.update_rubygemsupdate_rubygems386,10280 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/unit_diff.rb,309 -class UnitDiffUnitDiff38,1110 - def self.unit_diffunit_diff54,1471 - def parse_input(input, output)parse_input59,1560 - def parse_diff(result)parse_diff120,3125 - def unit_diff(input=ARGF, output=$stdout)unit_diff192,5026 - def diff expect, butwasdiff234,5989 - def massage(data)massage266,6782 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/zentest.rb,1178 -class ModuleModule24,487 - def zentestzentest25,500 -class ZenTestZenTest54,1444 - def missing_methods; raise "Something is wack"; endmissing_methods66,1661 - def initializeinitialize69,1724 - def load_file(file)load_file80,2043 - def get_class(klassname)get_class96,2437 - def get_methods_for(klass, full=false)get_methods_for124,3343 - def get_inherited_methods_for(klass, full)get_inherited_methods_for152,4341 - def is_test_class(klass)is_test_class177,5072 - def convert_class_name(name)convert_class_name187,5447 - def process_class(klassname, full=false)process_class212,6230 - def scan_files(*files)scan_files234,7106 - def add_missing_method(klassname, methodname)add_missing_method323,9409 - def methods_and_tests(klassname, testklassname)methods_and_tests332,9802 - def analyze_impl(klassname)analyze_impl339,10082 - def analyze_test(testklassname)analyze_test370,11412 - def create_method(indentunit, indent, name)create_method425,13430 - def analyzeanalyze439,13885 - def generate_codegenerate_code455,14397 - def resultresult523,16391 - def self.fix(*files)fix530,16572 - def self.autotest(*klasses)autotest542,16910 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/lib/zentest_mapping.rb,225 -module ZenTestMappingZenTestMapping26,742 - def munge namemunge62,1542 - def normal_to_test namenormal_to_test82,2041 - def unmunge nameunmunge86,2099 - def test_to_normal(name, klassname=nil)test_to_normal106,2735 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_autotest.rb,2609 -class AutotestAutotest21,252 - def self.clear_hooksclear_hooks24,314 -class TestAutotest < MiniTest::Unit::TestCaseTestAutotest29,364 - def deny test, msg=nildeny31,411 - def setupsetup41,650 - def test_add_exceptiontest_add_exception63,1314 - def test_add_mappingtest_add_mapping73,1499 - def test_add_mapping_fronttest_add_mapping_front83,1687 - def test_clear_exceptionstest_clear_exceptions93,1889 - def test_clear_mappingtest_clear_mapping103,2050 - def test_consolidate_failures_experimenttest_consolidate_failures_experiment112,2181 - def test_consolidate_failures_greentest_consolidate_failures_green128,2678 - def test_consolidate_failures_multiple_possibilitiestest_consolidate_failures_multiple_possibilities134,2816 - def test_consolidate_failures_nested_classestest_consolidate_failures_nested_classes143,3129 - def test_consolidate_failures_no_matchtest_consolidate_failures_no_match159,3642 - def test_consolidate_failures_redtest_consolidate_failures_red167,4012 - def test_exceptionstest_exceptions173,4241 - def test_exceptions_niltest_exceptions_nil179,4357 - def test_find_files_to_testtest_find_files_to_test185,4503 - def test_find_files_to_test_dunnotest_find_files_to_test_dunno193,4700 - def test_find_files_to_test_libtest_find_files_to_test_lib202,4998 - def test_find_files_to_test_no_changetest_find_files_to_test_no_change207,5141 - def test_find_files_to_test_testtest_find_files_to_test_test225,5670 - def test_reorder_alphatest_reorder_alpha230,5826 - def test_reorder_reversetest_reorder_reverse237,5954 - def test_reorder_randomtest_reorder_random244,6094 - def test_reorder_naturaltest_reorder_natural257,6341 - def test_handle_resultstest_handle_results269,6614 - def test_hook_overlap_returning_falsetest_hook_overlap_returning_false334,8339 - def test_hook_overlap_returning_truetest_hook_overlap_returning_true344,8665 - def test_hook_responsetest_hook_response354,8993 - def test_make_test_cmdtest_make_test_cmd368,9268 - def test_path_to_classnametest_path_to_classname385,9764 - def test_remove_exceptiontest_remove_exception392,10022 - def test_remove_mappingtest_remove_mapping403,10236 - def test_test_files_fortest_test_files_for413,10438 - def test_testlibtest_testlib423,10805 - def util_exceptionsutil_exceptions433,11053 - def util_find_files_to_test(f, expected)util_find_files_to_test437,11127 - def util_mappingsutil_mappings447,11396 - def util_path_to_classname(e,i)util_path_to_classname451,11460 - def util_reset_hooks_returning valutil_reset_hooks_returning455,11545 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_focus.rb,302 -class TestFocus < MiniTest::Unit::TestCaseTestFocus5,63 - def setupsetup6,106 - def teardownteardown10,136 - def test_focustest_focus14,181 - def test_ignore1test_ignore118,217 - def test_ignore2test_ignore222,266 - def test_ignore3test_ignore326,315 - def test_focus2test_focus230,364 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_unit_diff.rb,1575 -class TestUnitDiff < MiniTest::Unit::TestCaseTestUnitDiff12,131 - def setupsetup14,178 - def test_inputtest_input18,222 - def test_input_miniunittest_input_miniunit30,1159 - def test_input_miniunit_multilinetest_input_miniunit_multiline47,1737 - def test_input_mspectest_input_mspec68,2337 - def test_input_mspec_multilinetest_input_mspec_multiline116,4127 - def test_unit_diff_empty # simulates broken pipe at the leasttest_unit_diff_empty147,6005 - def test_parse_diff_anglestest_parse_diff_angles153,6140 - def test_parse_diff_miniunittest_parse_diff_miniunit168,6564 - def test_parse_diff_miniunit_multilinetest_parse_diff_miniunit_multiline181,6978 - def test_parse_diff1test_parse_diff1194,7410 - def test_parse_diff2test_parse_diff2206,7852 - def test_parse_diff3test_parse_diff3223,8327 - def test_parse_diff_suspect_equalstest_parse_diff_suspect_equals234,8761 - def test_parse_diff_NOT_suspect_equalstest_parse_diff_NOT_suspect_equals247,9234 - def test_parse_diff_mspectest_parse_diff_mspec260,9717 - def test_parse_diff_mspec_multilinetest_parse_diff_mspec_multiline273,10138 - def test_unit_diff_anglestest_unit_diff_angles287,10750 - def test_unit_diff1test_unit_diff1295,11226 - def test_unit_diff2test_unit_diff2303,11770 - def test_unit_diff3test_unit_diff3311,12528 - def test_unit_diff_suspect_equalstest_unit_diff_suspect_equals319,12886 - def test_unit_diff_NOT_suspect_equalstest_unit_diff_NOT_suspect_equals328,13529 - def util_unit_diff(header, input, expected, msg=:unit_diff)util_unit_diff336,13957 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_zentest.rb,6301 -class Cls1 # ZenTest SKIPCls117,424 - def meth1; endmeth118,467 - def self.meth2; endmeth219,484 -class TestCls1 # ZenTest SKIPTestCls122,511 - def setup; endsetup23,554 - def teardown; endteardown24,571 - def test_meth1; endtest_meth125,591 - def test_meth2; assert(true, "something"); endtest_meth226,613 -class SuperDuper # ZenTest SKIPSuperDuper29,667 - def self.cls_inherited; endcls_inherited30,710 - def inherited; endinherited31,740 - def overridden; endoverridden32,761 -class LowlyOne < SuperDuper # ZenTest SKIPLowlyOne35,788 - def self.cls_extended; endcls_extended36,831 - def overridden; endoverridden37,860 - def extended; endextended38,882 - def pretty_print; endpretty_print39,902 - def pretty_print_cycle; endpretty_print_cycle40,926 -class Blah0Blah045,1037 - def missingtest; endmissingtest46,1049 - def notmissing1; endnotmissing147,1072 - def notmissing2; endnotmissing248,1095 - def missingimpl; endmissingimpl51,1156 -class TestBlah0TestBlah054,1184 - def setup; endsetup55,1200 - def teardown; endteardown56,1217 - def test_notmissing1test_notmissing158,1238 - def test_notmissing2_ext1test_notmissing2_ext161,1294 - def test_notmissing2_ext2test_notmissing2_ext264,1355 - def test_missingimpl; endtest_missingimpl67,1416 - def test_missingtest; endtest_missingtest68,1444 -class Blah1Blah171,1477 - def missingtest; endmissingtest72,1489 - def notmissing1; endnotmissing173,1512 - def notmissing2; endnotmissing274,1535 -class TestBlah1TestBlah177,1563 - def test_notmissing1; endtest_notmissing178,1579 - def test_notmissing2_ext1; endtest_notmissing2_ext179,1607 - def test_notmissing2_ext2; endtest_notmissing2_ext280,1640 - def test_missingimpl; Blah1.new.missingimpl; endtest_missingimpl81,1673 - def test_integration_blah1; endtest_integration_blah182,1724 - def test_integration_blah2; endtest_integration_blah283,1758 - def test_integration_blah3; endtest_integration_blah384,1792 -module Something2Something287,1831 - class Blah2Blah288,1849 - def missingtest; endmissingtest89,1863 - def notmissing1; endnotmissing190,1888 - def notmissing2; endnotmissing291,1913 -module TestSomething2TestSomething295,1949 - class TestBlah2TestBlah296,1971 - def test_notmissing1; endtest_notmissing197,1989 - def test_notmissing2_ext1; endtest_notmissing2_ext198,2019 - def test_notmissing2_ext2; endtest_notmissing2_ext299,2054 - def test_missingimpl; endtest_missingimpl100,2089 -class TestBlah3TestBlah3105,2150 - def test_missingimpl; endtest_missingimpl106,2166 -class Blah4Blah4109,2221 - def missingtest1; endmissingtest1110,2233 - def missingtest2; endmissingtest2111,2257 -class MyHash5 < HashMyHash5115,2316 - def missingtest1; endmissingtest1117,2351 -module MyModule6MyModule6121,2395 - class MyClass6MyClass6122,2412 - def missingtest1; endmissingtest1124,2445 -module MyModule7; end # in 1.9+ you'll not need thisMyModule7129,2497 -class MyModule7::MyClass7MyModule7130,2550 - def missingtest1; endmissingtest1132,2590 -class MyClass8MyClass8135,2619 - def self.foobar; endfoobar136,2634 - def MyClass8.foobaz; endfoobaz137,2657 -class TestTrueClass; endTestTrueClass140,2689 -class TestZenTest < MiniTest::Unit::TestCaseTestZenTest142,2715 - def setupsetup143,2760 - def util_simple_setuputil_simple_setup150,2891 -class SomethingSomething180,3640 - def self.method4(*args)method4181,3656 - def method2(*args)method2185,3749 -class TestSomething < Test::Unit::TestCaseTestSomething190,3836 - def test_class_method3test_class_method3191,3879 - def test_attribtest_attrib195,3977 - def test_attrib_equalstest_attrib_equals199,4061 - def test_equal_ehtest_equal_eh203,4159 - def test_method1test_method1207,4247 - def test_method1_bangtest_method1_bang211,4333 - def test_method1_ehtest_method1_eh215,4429 - def test_method1_equalstest_method1_equals219,4521 - def test_initializetest_initialize231,4754 - def test_is_test_classtest_is_test_class239,4970 - def test_is_test_class_reversedtest_is_test_class_reversed258,5790 - def test_convert_class_nametest_convert_class_name270,6208 - def test_convert_class_name_reversedtest_convert_class_name_reversed284,6692 - def test_missing_methods_emptytest_missing_methods_empty304,7324 - def test_add_missing_method_normaltest_add_missing_method_normal309,7432 - def test_add_missing_method_duplicatestest_add_missing_method_duplicates315,7644 - def test_analyze_simpletest_analyze_simple323,7978 - def test_create_methodtest_create_method347,8559 - def test_methods_and_teststest_methods_and_tests354,8792 - def test_generate_code_simpletest_generate_code_simple362,9061 - def test_get_class_goodtest_get_class_good372,9252 - def test_get_class_badtest_get_class_bad376,9339 - def test_get_inherited_methods_for_subclasstest_get_inherited_methods_for_subclass380,9418 - def test_get_inherited_methods_for_subclass_fulltest_get_inherited_methods_for_subclass_full387,9630 - def test_get_inherited_methods_for_superclasstest_get_inherited_methods_for_superclass395,9899 - def test_get_inherited_methods_for_superclass_fulltest_get_inherited_methods_for_superclass_full402,10093 - def test_get_methods_for_subclasstest_get_methods_for_subclass409,10325 - def test_get_methods_for_subclass_fulltest_get_methods_for_subclass_full420,10560 - def test_get_methods_for_superclasstest_get_methods_for_superclass432,10841 - def test_resulttest_result442,11078 - def test_load_filetest_load_file453,11274 - def test_scan_filestest_scan_files457,11371 - def test_process_classtest_process_class461,11470 - def test_klasses_equalstest_klasses_equals475,11991 - def util_testcase(*klasses)util_testcase493,12650 - def test_testcase0test_testcase0503,12886 - def test_testcase1test_testcase1510,13113 - def test_testcase2test_testcase2516,13518 - def test_testcase3test_testcase3522,14019 - def test_testcase4test_testcase4528,14272 - def test_testcase5test_testcase5534,14653 - def test_testcase6test_testcase6540,15024 - def test_testcase7test_testcase7546,15451 - def test_testcase8test_testcase8552,15878 - def test_testcase9test_testcase9558,16265 - -tmp/isolate/ruby-1.8/gems/ZenTest-4.4.0/test/test_zentest_mapping.rb,1456 -class DummyDummy8,116 -class TestZentestMapping < MiniTest::Unit::TestCaseTestZentestMapping13,193 - def setupsetup14,245 - def util_simple_setuputil_simple_setup18,288 -class SomethingSomething45,1050 - def self.method4(*args)method446,1066 - def method2(*args)method250,1159 -class TestSomething < Test::Unit::TestCaseTestSomething55,1246 - def test_class_method3test_class_method356,1289 - def test_attribtest_attrib60,1387 - def test_attrib_equalstest_attrib_equals64,1471 - def test_equal_ehtest_equal_eh68,1569 - def test_method1test_method172,1657 - def test_method1_bangtest_method1_bang76,1743 - def test_method1_ehtest_method1_eh80,1839 - def test_method1_equalstest_method1_equals84,1931 - def test_normal_to_testtest_normal_to_test93,2076 - def test_normal_to_test_clstest_normal_to_test_cls101,2439 - def test_normal_to_test_operatorstest_normal_to_test_operators113,2905 - def test_normal_to_test_overlaptest_normal_to_test_overlap127,3636 - def test_test_to_normaltest_test_to_normal149,4961 - def test_test_to_normal_clstest_test_to_normal_cls161,5431 - def test_test_to_normal_extendedtest_test_to_normal_extended175,5986 - def test_test_to_normal_mappedtest_test_to_normal_mapped191,6659 - def test_test_to_normal_operatorstest_test_to_normal_operators205,7388 - def test_test_to_normal_overlaptest_test_to_normal_overlap219,8067 - def test_to_normal_subsettest_to_normal_subset238,9077 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/bin/sow,0 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/clean.rb,126 -module Hoe::CleanHoe8,102 - def initialize_cleaninitialize_clean17,259 - def define_clean_tasksdefine_clean_tasks25,460 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/debug.rb,80 -module Hoe::DebugHoe10,206 - def define_debug_tasksdefine_debug_tasks30,604 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/deps.rb,272 -module Hoe::DepsHoe13,357 - def define_deps_tasksdefine_deps_tasks22,499 - def get_source_indexget_source_index126,3831 - def get_latest_gemsget_latest_gems159,4721 - def get_gems_by_nameget_gems_by_name166,4867 - def dependent_upon namedependent_upon175,5104 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/flay.rb,121 -module Hoe::FlayHoe8,106 - def initialize_flayinitialize_flay17,286 - def define_flay_tasksdefine_flay_tasks24,418 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/flog.rb,121 -module Hoe::FlogHoe8,101 - def initialize_floginitialize_flog17,281 - def define_flog_tasksdefine_flog_tasks24,413 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/gemcutter.rb,88 -module Hoe::GemcutterHoe3,16 - def define_gemcutter_tasksdefine_gemcutter_tasks4,38 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/inline.rb,83 -module Hoe::InlineHoe20,525 - def define_inline_tasksdefine_inline_tasks24,579 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/newb.rb,75 -module Hoe::NewbHoe8,95 - def define_newb_tasksdefine_newb_tasks10,149 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/package.rb,195 -module Hoe::PackageHoe17,346 - def initialize_packageinitialize_package31,602 - def define_package_tasksdefine_package_tasks39,724 - def install_gem name, version = nilinstall_gem75,1631 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/publish.rb,324 -module Hoe::PublishHoe29,682 - def initialize_publishinitialize_publish85,2247 - def define_publish_tasksdefine_publish_tasks97,2539 - def generate_email full = nilgenerate_email191,5355 - def announcement # :nodoc:announcement211,5862 -class StringString226,6337 - def rdoc_to_markdownrdoc_to_markdown230,6407 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/rake.rb,275 -module RakeRake1,0 - class TaskTask2,12 - def commentcomment11,235 - module TaskManagerTaskManager16,336 - def all_tasksall_tasks19,429 - def self.all_tasksall_tasks26,531 - def self.clear_tasks(*tasks)clear_tasks34,749 - def self.undo(*names)undo53,1217 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/rcov.rb,76 -module Hoe::RCovHoe8,109 - def define_rcov_tasksdefine_rcov_tasks12,161 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/rubyforge.rb,157 -module Hoe::RubyForgeHoe13,257 - def initialize_rubyforgeinitialize_rubyforge14,279 - def define_rubyforge_tasks # :nodoc:define_rubyforge_tasks18,382 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/signing.rb,87 -module Hoe::SigningHoe39,987 - def define_signing_tasksdefine_signing_tasks46,1191 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe/test.rb,191 -module Hoe::TestHoe12,325 - def initialize_testinitialize_test52,1097 - def define_test_tasksdefine_test_tasks62,1302 - def make_test_cmd multi = false # :nodoc:make_test_cmd121,2809 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/lib/hoe.rb,1346 -class HoeHoe59,1601 - def self.add_include_dirs(*dirs)add_include_dirs219,5299 - def self.load_pluginsload_plugins231,5551 - def self.normalize_names project # :nodoc:normalize_names255,6227 - def self.plugin *namesplugin266,6513 - def self.pluginsplugins274,6646 - def self.spec name, &blockspec287,6956 - def activate_pluginsactivate_plugins300,7218 - def add_dependenciesadd_dependencies320,7720 - def dependency_targetdependency_target337,8196 - def define_specdefine_spec344,8321 - def developer name, emaildeveloper421,10525 - def initialize name, version = nil # :nodoc:initialize431,10808 - def intuit_valuesintuit_values466,11881 - def load_plugin_tasksload_plugin_tasks496,12847 - def missing namemissing524,13487 - def normalize_deps depsnormalize_deps532,13683 - def paragraphs_of path, *paragraphsparagraphs_of549,14131 - def pluggable!pluggable!559,14431 - def post_initializepost_initialize567,14604 - def require_rubygems_version versionrequire_rubygems_version578,14815 - def require_ruby_version versionrequire_ruby_version585,14996 - def timebomb n, m, finis = '2010-04-01', start = '2009-03-14'timebomb592,15170 - def validate_fieldsvalidate_fields605,15472 - def with_config # :nodoc:with_config615,15713 -class FileFile623,15886 - def self.read_utf pathread_utf625,15960 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/template/bin/file_name.erb,0 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/test/test_hoe.rb,263 -class TestHoe < MiniTest::Unit::TestCaseTestHoe7,114 - def setupsetup8,155 - def test_file_read_utftest_file_read_utf12,201 - def test_possibly_bettertest_possibly_better20,371 - def test_pluginstest_plugins66,1925 - def test_renametest_rename76,2196 - -tmp/isolate/ruby-1.8/gems/hoe-2.6.2/test/test_hoe_gemcutter.rb,142 -class TestHoeGemcutter < MiniTest::Unit::TestCaseTestHoeGemcutter3,56 - def test_gemcutter_tasks_definedtest_gemcutter_tasks_defined6,132 - -tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/lib/hoe/gemspec.rb,115 -class Hoe #:nodoc:Hoe1,0 - module GemspecGemspec7,127 - def define_gemspec_tasksdefine_gemspec_tasks10,176 - -tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/test/fixture_project/lib/fixture_project.rb,40 -class FixtureProjectFixtureProject1,0 - -tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/test/fixture_project/test/test_fixture_project.rb,107 -class TestFixtureProject < Test::Unit::TestCaseTestFixtureProject4,47 - def test_sanitytest_sanity5,95 - -tmp/isolate/ruby-1.8/gems/hoe-gemspec-1.0.0/test/test_hoe_gemspec.rb,99 -class TestHoeBundler < Test::Unit::TestCaseTestHoeBundler4,41 - def test_outputtest_output5,85 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/generator2_benchmark.rb,1105 -module JSONJSON21,415 - def self.[](*) end[]22,427 -module Generator2BenchmarkCommonGenerator2BenchmarkCommon25,453 - def setupsetup28,502 - def generic_reset_methodgeneric_reset_method32,595 -module JSONGeneratorCommonJSONGeneratorCommon37,690 - def benchmark_generator_fastbenchmark_generator_fast40,754 - def benchmark_generator_safebenchmark_generator_safe46,892 - def benchmark_generator_prettybenchmark_generator_pretty52,1025 - def benchmark_generator_asciibenchmark_generator_ascii58,1169 -class Generator2BenchmarkExt < Bullshit::RepeatCaseGenerator2BenchmarkExt65,1329 -class Generator2BenchmarkPure < Bullshit::RepeatCaseGenerator2BenchmarkPure91,1777 -class Generator2BenchmarkRails < Bullshit::RepeatCaseGenerator2BenchmarkRails116,2224 - def benchmark_generatorbenchmark_generator140,2674 -class Generator2BenchmarkYajl < Bullshit::RepeatCaseGenerator2BenchmarkYajl147,2794 - def benchmark_generatorbenchmark_generator171,3244 - def benchmark_generator_gem_apibenchmark_generator_gem_api177,3374 - def reset_benchmark_generatorreset_benchmark_generator181,3442 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/generator_benchmark.rb,1095 -module JSONJSON21,415 - def self.[](*) end[]22,427 -module GeneratorBenchmarkCommonGeneratorBenchmarkCommon25,453 - def setupsetup28,501 - def generic_reset_methodgeneric_reset_method34,689 -module JSONGeneratorCommonJSONGeneratorCommon39,798 - def benchmark_generator_fastbenchmark_generator_fast42,861 - def benchmark_generator_safebenchmark_generator_safe48,999 - def benchmark_generator_prettybenchmark_generator_pretty54,1132 - def benchmark_generator_asciibenchmark_generator_ascii60,1276 -class GeneratorBenchmarkExt < Bullshit::RepeatCaseGeneratorBenchmarkExt67,1436 -class GeneratorBenchmarkPure < Bullshit::RepeatCaseGeneratorBenchmarkPure93,1883 -class GeneratorBenchmarkRails < Bullshit::RepeatCaseGeneratorBenchmarkRails118,2329 - def benchmark_generatorbenchmark_generator142,2777 -class GeneratorBenchmarkYajl < Bullshit::RepeatCaseGeneratorBenchmarkYajl149,2897 - def benchmark_generatorbenchmark_generator173,3345 - def benchmark_generator_gem_apibenchmark_generator_gem_api179,3475 - def reset_benchmark_generatorreset_benchmark_generator183,3543 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/ohai.ruby,0 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/parser2_benchmark.rb,1165 -module Parser2BenchmarkCommonParser2BenchmarkCommon26,490 - def setupsetup29,536 - def generic_reset_methodgeneric_reset_method33,632 -class Parser2BenchmarkExt < Bullshit::RepeatCaseParser2BenchmarkExt38,711 - def benchmark_parserbenchmark_parser62,1154 - def benchmark_parser_symbolicbenchmark_parser_symbolic68,1259 -class Parser2BenchmarkPure < Bullshit::RepeatCaseParser2BenchmarkPure75,1411 - def benchmark_parserbenchmark_parser99,1854 - def benchmark_parser_symbolicbenchmark_parser_symbolic105,1959 -class Parser2BenchmarkYAML < Bullshit::RepeatCaseParser2BenchmarkYAML112,2111 - def setupsetup134,2520 - def benchmark_parserbenchmark_parser138,2616 - def generic_reset_methodgeneric_reset_method142,2677 -class Parser2BenchmarkRails < Bullshit::RepeatCaseParser2BenchmarkRails147,2756 - def setupsetup168,3148 - def benchmark_parserbenchmark_parser174,3328 - def generic_reset_methodgeneric_reset_method178,3406 -class Parser2BenchmarkYajl < Bullshit::RepeatCaseParser2BenchmarkYajl183,3485 - def setupsetup204,3877 - def benchmark_parserbenchmark_parser208,3973 - def generic_reset_methodgeneric_reset_method212,4047 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/benchmarks/parser_benchmark.rb,1154 -module ParserBenchmarkCommonParserBenchmarkCommon26,490 - def setupsetup29,535 - def generic_reset_methodgeneric_reset_method35,715 -class ParserBenchmarkExt < Bullshit::RepeatCaseParserBenchmarkExt40,794 - def benchmark_parserbenchmark_parser64,1235 - def benchmark_parser_symbolicbenchmark_parser_symbolic70,1340 -class ParserBenchmarkPure < Bullshit::RepeatCaseParserBenchmarkPure77,1492 - def benchmark_parserbenchmark_parser101,1933 - def benchmark_parser_symbolicbenchmark_parser_symbolic107,2038 -class ParserBenchmarkYAML < Bullshit::RepeatCaseParserBenchmarkYAML114,2190 - def setupsetup136,2598 - def benchmark_parserbenchmark_parser142,2785 - def generic_reset_methodgeneric_reset_method146,2846 -class ParserBenchmarkRails < Bullshit::RepeatCaseParserBenchmarkRails151,2925 - def setupsetup173,3334 - def benchmark_parserbenchmark_parser179,3514 - def generic_reset_methodgeneric_reset_method183,3592 -class ParserBenchmarkYajl < Bullshit::RepeatCaseParserBenchmarkYajl188,3671 - def setupsetup210,4080 - def benchmark_parserbenchmark_parser216,4260 - def generic_reset_methodgeneric_reset_method220,4334 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/bin/edit_json.rb,0 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/bin/prettify_json.rb,33 -def go(s, args = ARGV)go14,435 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/generator/extconf.rb,0 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/generator/generator.c,10729 -static VALUE CEncoding_UTF_8;CEncoding_UTF_84,52 -static ID i_encoding, i_encode;i_encoding5,82 -static ID i_encoding, i_encode;i_encode5,82 -static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mJSON8,122 -static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mExt8,122 -static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mGenerator8,122 -static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,cState8,122 -static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mGeneratorMethods8,122 -static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,mObject8,122 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mHash9,196 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mArray9,196 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mFixnum9,196 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mBignum9,196 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mFloat9,196 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mString9,196 - mHash, mArray, mFixnum, mBignum, mFloat, mString, mString_Extend,mString_Extend9,196 - mTrueClass, mFalseClass, mNilClass, eGeneratorError,mTrueClass10,275 - mTrueClass, mFalseClass, mNilClass, eGeneratorError,mFalseClass10,275 - mTrueClass, mFalseClass, mNilClass, eGeneratorError,mNilClass10,275 - mTrueClass, mFalseClass, mNilClass, eGeneratorError,eGeneratorError10,275 - eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,eNestingError11,341 - eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,CRegexp_MULTILINE11,341 - eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,CJSON_SAFE_STATE_PROTOTYPE11,341 - i_SAFE_STATE_PROTOTYPE;i_SAFE_STATE_PROTOTYPE12,416 -static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_to_s14,454 -static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_to_json14,454 -static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_new14,454 -static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_indent14,454 -static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_space14,454 -static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,i_space_before14,454 - i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_object_nl15,525 - i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_array_nl15,525 - i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_max_nesting15,525 - i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_allow_nan15,525 - i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,i_ascii_only15,525 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_pack16,602 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_unpack16,602 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_create_id16,602 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_extend16,602 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_key_p16,602 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_aref16,602 - i_pack, i_unpack, i_create_id, i_extend, i_key_p, i_aref, i_send,i_send16,602 - i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_respond_to_p17,678 - i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_match17,678 - i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_keys17,678 - i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_depth17,678 - i_respond_to_p, i_match, i_keys, i_depth, i_dup;i_dup17,678 -static const char trailingBytesForUTF8[256] = {trailingBytesForUTF848,1911 -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, offsetsFromUTF864,2695 -static unsigned char isLegalUTF8(const UTF8 *source, int length)isLegalUTF877,3308 -static void unicode_escape(char *buf, UTF16 character)unicode_escape104,4383 -static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16unicode_escape_to_buffer116,4789 -static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)convert_UTF8_to_JSON_ASCII125,5084 -static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)convert_UTF8_to_JSON223,9259 -static char *fstrndup(const char *ptr, int len) {fstrndup287,11147 -static FBuffer *fbuffer_alloc()fbuffer_alloc297,11355 -static FBuffer *fbuffer_alloc_with_length(unsigned int initial_length)fbuffer_alloc_with_length305,11535 -static void fbuffer_free(FBuffer *fb)fbuffer_free315,11786 -static void fbuffer_free_only_buffer(FBuffer *fb)fbuffer_free_only_buffer321,11887 -static void fbuffer_clear(FBuffer *fb)fbuffer_clear326,11962 -static void fbuffer_inc_capa(FBuffer *fb, unsigned int requested)fbuffer_inc_capa331,12023 -static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned int len)fbuffer_append348,12431 -static void fbuffer_append_char(FBuffer *fb, char newchr)fbuffer_append_char357,12652 -static void freverse(char *start, char *end)freverse364,12794 -static int fltoa(long number, char *buf)fltoa373,12926 -static void fbuffer_append_long(FBuffer *fb, long number)fbuffer_append_long386,13218 -static FBuffer *fbuffer_dup(FBuffer *fb)fbuffer_dup393,13367 -static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)mHash_to_json427,14153 -static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {mArray_to_json440,14503 -static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)mFixnum_to_json449,14696 -static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)mBignum_to_json459,14891 -static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)mFloat_to_json469,15084 -static VALUE mString_included_s(VALUE self, VALUE modul) {mString_included_s479,15275 -static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)mString_to_json491,15603 -static VALUE mString_to_json_raw_object(VALUE self)mString_to_json_raw_object504,15995 -static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self)mString_to_json_raw520,16471 -static VALUE mString_Extend_json_create(VALUE self, VALUE o)mString_Extend_json_create533,16851 -static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)mTrueClass_to_json546,17141 -static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)mFalseClass_to_json556,17317 -static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)mNilClass_to_json565,17450 -static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)mObject_to_json577,17772 -static void State_free(JSON_Generator_State *state)State_free587,18083 -static JSON_Generator_State *State_allocate()State_allocate600,18625 -static VALUE cState_s_allocate(VALUE klass)cState_s_allocate607,18802 -static VALUE cState_configure(VALUE self, VALUE opts)cState_configure619,19080 -static VALUE cState_to_h(VALUE self)cState_to_h704,21711 -static VALUE cState_aref(VALUE self, VALUE name)cState_aref725,22694 -static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_object735,22919 -static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_array784,24729 -static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_string822,26082 -static void generate_json_null(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_null836,26499 -static void generate_json_false(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_false841,26645 -static void generate_json_true(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_true846,26793 -static void generate_json_fixnum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_fixnum851,26939 -static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_bignum856,27096 -static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json_float862,27296 -static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)generate_json879,27943 -static FBuffer *cState_prepare_buffer(VALUE self)cState_prepare_buffer912,29252 -static VALUE fbuffer_to_s(FBuffer *fb)fbuffer_to_s941,30197 -static VALUE cState_partial_generate(VALUE self, VALUE obj)cState_partial_generate949,30355 -static VALUE cState_generate(VALUE self, VALUE obj)cState_generate964,30778 -static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)cState_initialize993,31940 -static VALUE cState_init_copy(VALUE obj, VALUE orig)cState_init_copy1009,32319 -static VALUE cState_from_state_s(VALUE self, VALUE opts)cState_from_state_s1036,33644 -static VALUE cState_indent(VALUE self)cState_indent1055,34188 -static VALUE cState_indent_set(VALUE self, VALUE indent)cState_indent_set1066,34423 -static VALUE cState_space(VALUE self)cState_space1092,35039 -static VALUE cState_space_set(VALUE self, VALUE space)cState_space_set1104,35292 -static VALUE cState_space_before(VALUE self)cState_space_before1129,35894 -static VALUE cState_space_before_set(VALUE self, VALUE space_before)cState_space_before_set1140,36174 -static VALUE cState_object_nl(VALUE self)cState_object_nl1166,36873 -static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)cState_object_nl_set1178,37147 -static VALUE cState_array_nl(VALUE self)cState_array_nl1202,37754 -static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)cState_array_nl_set1213,38009 -static VALUE cState_check_circular_p(VALUE self)cState_check_circular_p1239,38629 -static VALUE cState_max_nesting(VALUE self)cState_max_nesting1251,38923 -static VALUE cState_max_nesting_set(VALUE self, VALUE depth)cState_max_nesting_set1263,39230 -static VALUE cState_allow_nan_p(VALUE self)cState_allow_nan_p1276,39531 -static VALUE cState_ascii_only_p(VALUE self)cState_ascii_only_p1288,39780 -static VALUE cState_depth(VALUE self)cState_depth1299,39996 -static VALUE cState_depth_set(VALUE self, VALUE depth)cState_depth_set1311,40285 -void Init_generator()Init_generator1321,40452 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/generator/generator.h,2756 -#define _GENERATOR_H__GENERATOR_H_2,22 -#define FORCE_UTF8(FORCE_UTF820,264 -#define FORCE_UTF8(FORCE_UTF822,338 -#define option_given_p(option_given_p25,370 -#define RHASH_SIZE(RHASH_SIZE28,465 -#define RFLOAT_VALUE(RFLOAT_VALUE32,549 -#define RARRAY_PTR(RARRAY_PTR36,623 -#define RARRAY_LEN(RARRAY_LEN39,694 -#define RSTRING_PTR(RSTRING_PTR42,766 -#define RSTRING_LEN(RSTRING_LEN45,842 -#define RSTRING_PAIR(RSTRING_PAIR48,899 -typedef struct FBufferStruct {FBufferStruct52,1000 - unsigned int initial_length;initial_length53,1031 - char *ptr;ptr54,1064 - unsigned int len;len55,1079 - unsigned int capa;capa56,1101 -} FBuffer;FBuffer57,1124 -#define FBUFFER_INITIAL_LENGTH FBUFFER_INITIAL_LENGTH59,1136 -#define FBUFFER_PTR(FBUFFER_PTR61,1173 -#define FBUFFER_LEN(FBUFFER_LEN62,1207 -#define FBUFFER_CAPA(FBUFFER_CAPA63,1241 -#define FBUFFER_PAIR(FBUFFER_PAIR64,1277 -#define UNI_STRICT_CONVERSION UNI_STRICT_CONVERSION80,1922 -typedef unsigned long UTF32; /* at least 32 bits */UTF3282,1955 -typedef unsigned short UTF16; /* at least 16 bits */UTF1683,2007 -typedef unsigned char UTF8; /* typically 8 bits */UTF884,2060 -#define UNI_REPLACEMENT_CHAR UNI_REPLACEMENT_CHAR86,2112 -#define UNI_MAX_BMP UNI_MAX_BMP87,2159 -#define UNI_MAX_UTF16 UNI_MAX_UTF1688,2197 -#define UNI_MAX_UTF32 UNI_MAX_UTF3289,2237 -#define UNI_MAX_LEGAL_UTF32 UNI_MAX_LEGAL_UTF3290,2277 -#define UNI_SUR_HIGH_START UNI_SUR_HIGH_START92,2324 -#define UNI_SUR_HIGH_END UNI_SUR_HIGH_END93,2366 -#define UNI_SUR_LOW_START UNI_SUR_LOW_START94,2408 -#define UNI_SUR_LOW_END UNI_SUR_LOW_END95,2450 -static const int halfShift = 10; /* used for shifting by 10 bits */halfShift97,2493 -static const UTF32 halfBase = 0x0010000UL;halfBase99,2563 -static const UTF32 halfMask = 0x3FFUL;halfMask100,2606 -typedef struct JSON_Generator_StateStruct {JSON_Generator_StateStruct110,3023 - char *indent;indent111,3067 - long indent_len;indent_len112,3085 - char *space;space113,3106 - long space_len;space_len114,3123 - char *space_before;space_before115,3143 - long space_before_len;space_before_len116,3167 - char *object_nl;object_nl117,3194 - long object_nl_len;object_nl_len118,3215 - char *array_nl;array_nl119,3239 - long array_nl_len;array_nl_len120,3259 - FBuffer *array_delim;array_delim121,3282 - FBuffer *object_delim;object_delim122,3308 - FBuffer *object_delim2;object_delim2123,3335 - long max_nesting;max_nesting124,3363 - char allow_nan;allow_nan125,3385 - char ascii_only;ascii_only126,3405 - long depth;depth127,3426 -} JSON_Generator_State;JSON_Generator_State128,3442 -#define GET_STATE(GET_STATE130,3467 -#define GENERATE_JSON(GENERATE_JSON134,3619 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/parser/extconf.rb,0 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/parser/parser.c,6242 -static const char digit_values[256] = { digit_values7,57 -static UTF32 unescape_unicode(const unsigned char *p)unescape_unicode24,1171 -static int convert_UTF32_to_UTF8(char *buf, UTF32 ch) convert_UTF32_to_UTF843,1699 -static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,CEncoding_ASCII_8BIT70,2485 -static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,CEncoding_UTF_870,2485 -static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,CEncoding_UTF_16BE70,2485 - CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;CEncoding_UTF_16LE71,2557 - CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;CEncoding_UTF_32BE71,2557 - CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;CEncoding_UTF_32LE71,2557 -static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_encoding72,2621 -static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_encode72,2621 -static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_encode_bang72,2621 -static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;i_force_encoding72,2621 -static ID i_iconv;i_iconv74,2692 -static VALUE mJSON, mExt, cParser, eParserError, eNestingError;mJSON77,2719 -static VALUE mJSON, mExt, cParser, eParserError, eNestingError;mExt77,2719 -static VALUE mJSON, mExt, cParser, eParserError, eNestingError;cParser77,2719 -static VALUE mJSON, mExt, cParser, eParserError, eNestingError;eParserError77,2719 -static VALUE mJSON, mExt, cParser, eParserError, eNestingError;eNestingError77,2719 -static VALUE CNaN, CInfinity, CMinusInfinity;CNaN78,2783 -static VALUE CNaN, CInfinity, CMinusInfinity;CInfinity78,2783 -static VALUE CNaN, CInfinity, CMinusInfinity;CMinusInfinity78,2783 -static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_json_creatable_p80,2830 -static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_json_create80,2830 -static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_create_id80,2830 -static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,i_create_additions80,2830 - i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_chr81,2908 - i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_max_nesting81,2908 - i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_allow_nan81,2908 - i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_symbolize_names81,2908 - i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,i_object_class81,2908 - i_array_class, i_key_p, i_deep_const_get;i_array_class82,2988 - i_array_class, i_key_p, i_deep_const_get;i_key_p82,2988 - i_array_class, i_key_p, i_deep_const_get;i_deep_const_get82,2988 -static const int JSON_object_start = 1;JSON_object_start90,3087 -static const int JSON_object_first_final = 27;JSON_object_first_final91,3127 -static const int JSON_object_error = 0;JSON_object_error92,3174 -static const int JSON_object_en_main = 1;JSON_object_en_main94,3215 -static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_object100,3283 -static const int JSON_value_start = 1;JSON_value_start458,9938 -static const int JSON_value_first_final = 21;JSON_value_first_final459,9977 -static const int JSON_value_error = 0;JSON_value_error460,10023 -static const int JSON_value_en_main = 1;JSON_value_en_main462,10063 -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_value468,10130 -static const int JSON_integer_start = 1;JSON_integer_start767,15654 -static const int JSON_integer_first_final = 5;JSON_integer_first_final768,15695 -static const int JSON_integer_error = 0;JSON_integer_error769,15742 -static const int JSON_integer_en_main = 1;JSON_integer_en_main771,15784 -static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_integer777,15853 -static const int JSON_float_start = 1;JSON_float_start863,17230 -static const int JSON_float_first_final = 10;JSON_float_first_final864,17269 -static const int JSON_float_error = 0;JSON_float_error865,17315 -static const int JSON_float_en_main = 1;JSON_float_en_main867,17355 -static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_float873,17422 -static const int JSON_array_start = 1;JSON_array_start1026,19956 -static const int JSON_array_first_final = 17;JSON_array_first_final1027,19995 -static const int JSON_array_error = 0;JSON_array_error1028,20041 -static const int JSON_array_en_main = 1;JSON_array_en_main1030,20081 -static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_array1036,20148 -static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)json_string_unescape1282,24592 -static const int JSON_string_start = 1;JSON_string_start1354,27107 -static const int JSON_string_first_final = 8;JSON_string_first_final1355,27147 -static const int JSON_string_error = 0;JSON_string_error1356,27193 -static const int JSON_string_en_main = 1;JSON_string_en_main1358,27234 -static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)JSON_parse_string1364,27302 -static const int JSON_start = 1;JSON_start1512,29831 -static const int JSON_first_final = 10;JSON_first_final1513,29864 -static const int JSON_error = 0;JSON_error1514,29904 -static const int JSON_en_main = 1;JSON_en_main1516,29938 -static VALUE convert_encoding(VALUE source)convert_encoding1534,30232 -static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)cParser_initialize1608,33622 -static VALUE cParser_parse(VALUE self)cParser_parse1693,36573 -static JSON_Parser *JSON_allocate()JSON_allocate1854,39334 -static void JSON_mark(JSON_Parser *json)JSON_mark1861,39471 -static void JSON_free(JSON_Parser *json)JSON_free1869,39676 -static VALUE cJSON_parser_s_allocate(VALUE klass)cJSON_parser_s_allocate1874,39744 -static VALUE cParser_source(VALUE self)cParser_source1886,40029 -void Init_parser()Init_parser1892,40128 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/ext/json/ext/parser/parser.h,1278 -#define _PARSER_H__PARSER_H_2,19 -#define FORCE_UTF8(FORCE_UTF812,151 -#define FORCE_UTF8(FORCE_UTF814,225 -#define option_given_p(option_given_p17,257 -typedef unsigned long UTF32; /* at least 32 bits */UTF3221,348 -typedef unsigned short UTF16; /* at least 16 bits */UTF1622,400 -typedef unsigned char UTF8; /* typically 8 bits */UTF823,453 -#define UNI_REPLACEMENT_CHAR UNI_REPLACEMENT_CHAR25,507 -#define UNI_SUR_HIGH_START UNI_SUR_HIGH_START26,554 -#define UNI_SUR_HIGH_END UNI_SUR_HIGH_END27,596 -#define UNI_SUR_LOW_START UNI_SUR_LOW_START28,638 -#define UNI_SUR_LOW_END UNI_SUR_LOW_END29,680 -typedef struct JSON_ParserStruct {JSON_ParserStruct31,723 - VALUE Vsource;Vsource32,758 - char *source;source33,777 - long len;len34,795 - char *memo;memo35,809 - VALUE create_id;create_id36,825 - int max_nesting;max_nesting37,846 - int current_nesting;current_nesting38,867 - int allow_nan;allow_nan39,892 - int parsing_name;parsing_name40,911 - int symbolize_names;symbolize_names41,933 - VALUE object_class;object_class42,958 - VALUE array_class;array_class43,982 -} JSON_Parser;JSON_Parser44,1005 -#define GET_PARSER GET_PARSER46,1021 -#define MinusInfinity MinusInfinity50,1159 -#define EVIL EVIL51,1193 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/install.rb,0 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/add/core.rb,917 -class SymbolSymbol10,244 - def to_json(*a)to_json11,257 - def self.json_create(o)json_create18,366 -class TimeTime23,421 - def self.json_create(object)json_create24,432 - def to_json(*args)to_json35,701 -class DateDate44,884 - def self.json_create(object)json_create45,895 - def to_json(*args)to_json51,1032 -class DateTimeDateTime62,1210 - def self.json_create(object)json_create63,1225 - def to_json(*args)to_json77,1562 -class RangeRange92,1822 - def self.json_create(object)json_create93,1834 - def to_json(*args)to_json97,1894 -class StructStruct105,2047 - def self.json_create(object)json_create106,2060 - def to_json(*args)to_json110,2120 -class ExceptionException120,2348 - def self.json_create(object)json_create121,2364 - def to_json(*args)to_json127,2480 -class RegexpRegexp136,2628 - def self.json_create(object)json_create137,2641 - def to_json(*)to_json141,2713 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/add/rails.rb,238 -class ObjectObject9,223 - def self.json_create(object)json_create10,236 - def to_json(*a)to_json19,414 -class SymbolSymbol31,644 - def to_json(*a)to_json32,657 -module EnumerableEnumerable37,707 - def to_json(*a)to_json38,725 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/common.rb,1256 -module JSONJSON4,40 - def [](object, opts = {})[]12,403 - def parser=(parser) # :nodoc:parser=25,788 - def deep_const_get(path) # :nodoc:deep_const_get35,1220 - def generator=(generator) # :nodoc:generator=51,1665 - class JSONError < StandardError; endJSONError103,3324 - class ParserError < JSONError; endParserError106,3420 - class NestingError < ParserError; endNestingError110,3545 - class CircularDatastructure < NestingError; endCircularDatastructure113,3600 - class GeneratorError < JSONError; endGeneratorError117,3737 - class MissingUnicodeSupport < JSONError; endMissingUnicodeSupport123,3996 - def parse(source, opts = {})parse145,4940 - def parse!(source, opts = {})parse!164,5913 - def generate(obj, opts = nil)generate198,7559 - def fast_generate(obj, opts = nil)fast_generate225,8411 - def pretty_generate(obj, opts = nil)pretty_generate252,9261 - def load(source, proc = nil)load280,10231 - def recurse_proc(result, &proc)recurse_proc293,10566 - def dump(obj, anIO = nil, limit = nil)dump321,11448 - def self.iconv(to, from, string)iconv342,11932 - def j(*objs)j352,12137 - def jj(*objs)jj361,12378 - def JSON(object, *args)JSON374,12844 - def json_creatable?json_creatable?388,13269 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/editor.rb,4459 -module JSONJSON10,198 - module EditorEditor11,210 - def Editor.fetch_icon(name)fetch_icon39,1095 - def Editor.error_dialog(window, text)error_dialog50,1431 - def Editor.question_dialog(window, text)question_dialog69,2055 - def Editor.model2data(iter)model2data83,2516 - def Editor.data2model(data, model = nil, parent = nil)data2model121,3686 - class Gtk::TreeIterGtk156,4714 - def eacheach161,4855 - def recursive_each(&block)recursive_each167,5048 - def remove_subtree(model)remove_subtree176,5268 - def typetype183,5430 - def type=(value)type=189,5588 - def contentcontent195,5745 - def content=(value)content=200,5850 - module MenuExtensionMenuExtension207,6059 - def initialize(treeview)initialize212,6219 - def add_separatoradd_separator224,6507 - def add_item(label, keyval = nil, klass = MenuItem, &callback)add_item231,6786 - def createcreate250,7509 - def method_missing(*a, &b)method_missing254,7571 - class PopUpMenuPopUpMenu261,7748 - def change_node(item)change_node265,7854 - def cut_node(item)cut_node288,8690 - def copy_node(item)copy_node305,9232 - def paste_node_appending(item)paste_node_appending321,9755 - def paste_node_inserting_before(item)paste_node_inserting_before359,11113 - def append_new_node(item)append_new_node388,12209 - def insert_new_node(item)insert_new_node418,13291 - def collapse_expand(item)collapse_expand444,14293 - def createcreate457,14652 - class FileMenuFileMenu485,15739 - def new(item)new490,15901 - def open(item)open496,16080 - def open_location(item)open_location500,16137 - def revert(item)revert505,16284 - def save(item)save512,16448 - def save_as(item)save_as517,16570 - def quit(item)quit522,16706 - def createcreate527,16783 - class EditMenuEditMenu544,17325 - def copy(item)copy548,17426 - def paste(item)paste556,17710 - def find(item)find570,18098 - def find_again(item)find_again590,18612 - def sort(item)sort611,19174 - def createcreate645,20338 - class OptionsMenuOptionsMenu659,20737 - def collapsed_nodes(item)collapsed_nodes663,20834 - def pretty_saving(item)pretty_saving674,21072 - def createcreate682,21221 - class JSONTreeView < Gtk::TreeViewJSONTreeView696,21691 - def initialize(window)initialize701,21876 - def add_columnsadd_columns720,22355 - def unify_key(iter, key)unify_key742,22970 - def cell_edited(cell, path, value)cell_edited755,23362 - def configure_value(value, type)configure_value788,24298 - def add_popup_menuadd_popup_menu807,24804 - def create_node(parent, type, content)create_node817,25091 - def ask_for_hash_pair(parent)ask_for_hash_pair831,25530 - def ask_for_element(parent = nil, default_type = nil, value_text = @content)ask_for_element902,27935 - def ask_for_orderask_for_order964,30073 - def ask_for_find_term(search = nil)ask_for_find_term997,31126 - def expand_collapse(iter)expand_collapse1037,32489 - class MainWindow < Gtk::WindowMainWindow1047,32686 - def initialize(encoding)initialize1050,32740 - def create_menu_barcreate_menu_bar1099,34107 - def changechange1112,34569 - def unchangeunchange1119,34759 - def view_new_model(model)view_new_model1125,34906 - def display_status(text)display_status1133,35109 - def ask_saveask_save1141,35368 - def quitquit1153,35665 - def display_titledisplay_title1163,35887 - def clearclear1171,36129 - def check_pretty_printed(json)check_pretty_printed1177,36241 - def location_open(uri = nil)location_open1185,36564 - def file_open(filename = nil)file_open1195,36890 - def edit(json)edit1202,37145 - def file_savefile_save1211,37359 - def file_save_asfile_save_as1220,37538 - def store_file(path)store_file1226,37706 - def load_file(filename)load_file1247,38490 - def load_location(uri)load_location1264,38997 - def parse_json(json)parse_json1272,39198 - def read_data(filename)read_data1284,39657 - def select_file(message)select_file1296,40034 - def ask_for_locationask_for_location1320,40804 - def start(encoding = 'utf8') # :yield: windowstart1352,41786 - def edit(json, encoding = 'utf8')edit1362,42126 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/ext.rb,45 -module JSONJSON3,23 - module ExtExt6,138 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/pure/generator.rb,2275 -module JSONJSON1,0 - def utf8_to_json(string) # :nodoc:utf8_to_json42,979 - def utf8_to_json_ascii(string) # :nodoc:utf8_to_json_ascii51,1271 - def utf8_to_json(string) # :nodoc:utf8_to_json74,2209 - def utf8_to_json_ascii(string) # :nodoc:utf8_to_json_ascii78,2304 - module PurePure99,3064 - module GeneratorGenerator100,3078 - class StateState103,3246 - def self.from_state(opts)from_state108,3517 - def initialize(opts = {})initialize134,4730 - def check_max_nesting # :nodoc:check_max_nesting170,5922 - def check_circular?check_circular?179,6273 - def allow_nan?allow_nan?185,6456 - def ascii_only?ascii_only?189,6513 - def configure(opts)configure195,6663 - def to_hto_h216,7593 - def generate(obj)generate227,8040 - def [](name)[]236,8341 - module GeneratorMethodsGeneratorMethods241,8409 - module ObjectObject242,8439 - def to_json(*) to_s.to_json endto_json246,8680 - module HashHash249,8735 - def to_json(state = nil, *)to_json255,9080 - def json_shift(state)json_shift263,9266 - def json_transform(state)json_transform268,9400 - module ArrayArray294,10248 - def to_json(state = nil, *)to_json299,10516 - def json_transform(state)json_transform307,10702 - module IntegerInteger328,11358 - def to_json(*) to_s endto_json330,11455 - module FloatFloat333,11502 - def to_json(state = nil, *)to_json335,11595 - module StringString356,12142 - def to_json(state = nil, *args)to_json361,12377 - def to_json(state = nil, *args)to_json378,13032 - module ExtendExtend390,13438 - def json_create(o)json_create394,13645 - def self.included(modul)included400,13801 - def to_json_raw_objectto_json_raw_object408,14170 - def to_json_raw(*args)to_json_raw417,14468 - module TrueClassTrueClass422,14574 - def to_json(*) 'true' endto_json424,14651 - module FalseClassFalseClass427,14700 - def to_json(*) 'false' endto_json429,14780 - module NilClassNilClass432,14830 - def to_json(*) 'null' endto_json434,14905 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/pure/parser.rb,358 -module JSONJSON3,19 - module PurePure4,31 - class Parser < StringScannerParser7,159 - def initialize(source, opts = {})initialize71,3039 - def parseparse129,5496 - def parse_stringparse_string168,6496 - def parse_valueparse_value195,7339 - def parse_arrayparse_array230,8175 - def parse_objectparse_object262,9152 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/pure.rb,323 -module JSONJSON5,80 - def initialize(iconv) # :nodoc:initialize28,1119 - def iconv(string) # :nodoc:iconv32,1203 - def initialize(iconv) # :nodoc:initialize41,1495 - def iconv(string) # :nodoc:iconv45,1579 - def self.swap!(string) # :nodoc:swap60,2032 - module PurePure70,2339 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json/version.rb,21 -module JSONJSON1,0 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/lib/json.rb,22 -module JSONJSON2,22 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json.rb,1963 - class ArrayArray16,313 - def permutationpermutation17,329 -class TC_JSON < Test::Unit::TestCaseTC_JSON26,498 - def setupsetup29,551 - def test_constructiontest_construction51,1142 - def assert_equal_float(expected, is)assert_equal_float56,1250 - def test_parse_simple_arraystest_parse_simple_arrays60,1348 - def test_parse_simple_objectstest_parse_simple_objects93,2866 - def test_parse_more_complex_arraystest_parse_more_complex_arrays112,3811 - def test_parse_complex_objectstest_parse_complex_objects120,4090 - def test_parse_arraystest_parse_arrays131,4469 - def test_parse_valuestest_parse_values137,4646 - def test_parse_arraytest_parse_array149,5026 - class SubArray < Array; endSubArray161,5491 - class SubArray2 < ArraySubArray2163,5522 - def to_json(*a)to_json164,5548 - def self.json_create(o)json_create171,5680 - def test_parse_array_custom_classtest_parse_array_custom_class177,5768 - def test_parse_objecttest_parse_object183,5923 - class SubHash < HashSubHash190,6158 - class SubHash2 < HashSubHash2193,6188 - def to_json(*a)to_json194,6212 - def self.json_create(o)json_create200,6324 - def test_parse_object_custom_classtest_parse_object_custom_class206,6411 - def test_generation_of_core_subclasses_with_new_to_jsontest_generation_of_core_subclasses_with_new_to_json212,6568 - def test_generation_of_core_subclasses_with_default_to_jsontest_generation_of_core_subclasses_with_default_to_json223,6949 - def test_generation_of_core_subclassestest_generation_of_core_subclasses228,7132 - def test_parser_resettest_parser_reset238,7431 - def test_commentstest_comments244,7569 - def test_backslashtest_backslash284,8521 - def test_wrong_inputstest_wrong_inputs310,9225 - def test_nestingtest_nesting328,10084 - def test_symbolize_namestest_symbolize_names359,11644 - def test_load_dumptest_load_dump366,11908 - def test_big_integerstest_big_integers382,12571 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_addition.rb,845 -class TC_JSONAddition < Test::Unit::TestCaseTC_JSONAddition13,230 - class AA16,291 - def initialize(a)initialize17,301 - def ==(other)==23,365 - def self.json_create(object)json_create27,415 - def to_json(*args)to_json31,484 - class BB39,628 - def self.json_creatable?json_creatable40,638 - def to_json(*args)to_json44,688 - class CC51,799 - def self.json_creatable?json_creatable52,809 - def to_json(*args)to_json56,859 - def test_extended_jsontest_extended_json63,977 - def test_extended_json_disabledtest_extended_json_disabled72,1175 - def test_extended_json_fail1test_extended_json_fail187,1633 - def test_extended_json_fail2test_extended_json_fail294,1813 - def test_raw_stringstest_raw_strings101,1983 - def test_coretest_core122,3500 - def test_utc_datetimetest_utc_datetime151,4475 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_encoding.rb,229 -class TC_JSONEncoding < Test::Unit::TestCaseTC_JSONEncoding12,208 - def setupsetup15,269 - def test_parsetest_parse43,1591 - def test_parse_ascii_8bittest_parse_ascii_8bit51,1852 - def test_generatetest_generate59,2179 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_fixtures.rb,171 -class TC_JSONFixtures < Test::Unit::TestCaseTC_JSONFixtures11,192 - def setupsetup12,237 - def test_passingtest_passing19,533 - def test_failingtest_failing26,677 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_generate.rb,507 -class TC_JSONGenerate < Test::Unit::TestCaseTC_JSONGenerate11,192 - def setupsetup14,253 - def test_generatetest_generate47,801 - def test_generate_prettytest_generate_pretty59,1160 - def test_fast_generatetest_fast_generate75,1568 - def test_statestest_states87,1947 - def test_pretty_statetest_pretty_state105,2434 - def test_safe_statetest_safe_state120,2845 - def test_fast_statetest_fast_state135,3245 - def test_allow_nantest_allow_nan150,3644 - def test_depthtest_depth168,4792 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_rails.rb,911 -class TC_JSONRails < Test::Unit::TestCaseTC_JSONRails13,232 - class AA16,290 - def initialize(a)initialize17,300 - def ==(other)==23,364 - def self.json_create(object)json_create27,414 - def to_json(*args)to_json31,483 - class BB39,627 - def self.json_creatable?json_creatable40,637 - def to_json(*args)to_json44,687 - class CC51,798 - def to_json(*args)to_json52,808 - class DD59,923 - def initializeinitialize60,933 - def ==(other)==66,1000 - def test_extended_jsontest_extended_json71,1056 - def test_extended_json_generic_objecttest_extended_json_generic_object82,1312 - def test_extended_json_disabledtest_extended_json_disabled93,1582 - def test_extended_json_fail1test_extended_json_fail1108,2037 - def test_extended_json_fail2test_extended_json_fail2115,2205 - def test_raw_stringstest_raw_strings122,2436 - def test_symboltest_symbol141,3897 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tests/test_json_unicode.rb,141 -class TC_JSONUnicode < Test::Unit::TestCaseTC_JSONUnicode11,192 - def test_unicodetest_unicode14,252 - def test_charstest_chars55,2176 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tools/fuzz.rb,357 - def to_utf8to_utf86,102 -class FuzzerFuzzer11,161 - def initialize(n, freqs = {})initialize12,174 - def random_stringrandom_string25,464 - def pickpick31,564 - def make_pickmake_pick37,671 - def fuzz(current = nil)fuzz53,959 -class MyState < JSON.stateMyState85,1551 - def initializeinitialize88,1596 - def make_spacesmake_spaces99,1875 - -tmp/isolate/ruby-1.8/gems/json_pure-1.4.6/tools/server.rb,159 -class JSONServlet < HTTPServlet::AbstractServletJSONServlet9,105 - def do_GET(req, res)do_GET12,169 -def create_server(err, dir, port)create_server33,648 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/design_rationale.rb,314 -class ThingySpec < MiniTest::SpecThingySpec29,1522 - def setupsetup30,1556 - def test_should_do_the_first_thingtest_should_do_the_first_thing35,1603 -class SubThingySpec < ThingySpecSubThingySpec40,1673 - def setupsetup41,1706 - def test_should_do_the_second_thingtest_should_do_the_second_thing49,1858 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/autorun.rb,0 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/mock.rb,242 -class MockExpectationError < StandardError; endMockExpectationError1,0 -module MiniTestMiniTest3,49 - class MockMock4,65 - def initializeinitialize5,78 - def expect(name, retval, args=[])expect10,183 - def verifyverify22,645 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/spec.rb,918 -class ModuleModule5,45 - def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:infect_an_assertion6,58 - def infect_with_assertions(pos_prefix, neg_prefix,infect_with_assertions25,768 -module KernelKernel52,1656 - def describe desc, &blockdescribe61,1903 -class ModuleModule78,2330 - def classes type = Object # :nodoc:classes79,2343 -class MiniTest::Spec < MiniTest::Unit::TestCaseMiniTest92,2614 - def self.describe_stack # :nodoc:describe_stack94,2700 - def self.current # :nodoc:current98,2764 - def initialize name # :nodoc:initialize102,2819 - def self.nuke_test_methods! # :nodoc:nuke_test_methods107,2894 - def self.define_inheritable_method name, &block # :nodoc:define_inheritable_method113,3048 - def self.before type = :each, &blockbefore129,3513 - def self.after type = :each, &blockafter141,3877 - def self.it desc, &blockit155,4451 -class ObjectObject183,5562 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/lib/minitest/unit.rb,4004 -module MiniTestMiniTest6,78 - class Assertion < Exception; endAssertion11,126 - class Skip < Assertion; endSkip16,210 - def self.filter_backtrace bt # :nodoc:filter_backtrace33,872 - module AssertionsAssertions51,1305 - def mu_pp objmu_pp57,1482 - def _assertions= n # :nodoc:_assertions=63,1614 - def _assertions # :nodoc:_assertions67,1679 - def assert test, msg = nilassert74,1794 - def assert_block msg = nilassert_block87,2095 - def assert_empty obj, msg = nilassert_empty95,2269 - def assert_equal exp, act, msg = nilassert_equal106,2538 - def assert_in_delta exp, act, delta = 0.001, msg = nilassert_in_delta117,2856 - def assert_in_epsilon a, b, epsilon = 0.001, msg = nilassert_in_epsilon127,3174 - def assert_includes collection, obj, msg = nilassert_includes134,3352 - def assert_instance_of cls, obj, msg = nilassert_instance_of145,3658 - def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_ofassert_kind_of156,3922 - def assert_match exp, act, msg = nilassert_match166,4200 - def assert_nil obj, msg = nilassert_nil176,4502 - def assert_operator o1, op, o2, msg = nilassert_operator186,4735 - def assert_output stdout = nil, stderr = nilassert_output198,5131 - def assert_raises *expassert_raises212,5458 - def assert_respond_to obj, meth, msg = nilassert_respond_to244,6320 - def assert_same exp, act, msg = nilassert_same254,6581 - def assert_send send_ary, m = nilassert_send268,7006 - def assert_silentassert_silent280,7335 - def assert_throws sym, msg = nilassert_throws289,7470 - def capture_iocapture_io315,8137 - def exception_details e, msgexception_details333,8580 - def flunk msg = nilflunk340,8811 - def message msg = nil, &defaultmessage348,8979 - def pass msg = nilpass364,9306 - def refute test, msg = nilrefute371,9402 - def refute_empty obj, msg = nilrefute_empty379,9563 - def refute_equal exp, act, msg = nilrefute_equal390,9833 - def refute_in_delta exp, act, delta = 0.001, msg = nilrefute_in_delta402,10145 - def refute_in_epsilon a, b, epsilon = 0.001, msg = nilrefute_in_epsilon414,10476 - def refute_includes collection, obj, msg = nilrefute_includes421,10640 - def refute_instance_of cls, obj, msg = nilrefute_instance_of432,10946 - def refute_kind_of cls, obj, msg = nil # TODO: merge with instance_ofrefute_kind_of442,11190 - def refute_match exp, act, msg = nilrefute_match450,11437 - def refute_nil obj, msg = nilrefute_nil460,11743 - def refute_operator o1, op, o2, msg = nilrefute_operator471,12025 - def refute_respond_to obj, meth, msg = nilrefute_respond_to481,12275 - def refute_same exp, act, msg = nilrefute_same490,12524 - def skip msg = nil, bt = callerskip502,12901 - class UnitUnit508,13030 - def self.autorunautorun521,13392 - def self.output= streamoutput534,13762 - def location e # :nodoc:location538,13820 - def puke klass, meth, epuke551,14198 - def initialize # :nodoc:initialize568,14767 - def process_args args = []process_args574,14886 - def run args = []run607,15661 - def status io = @@outstatus657,16772 - def run_test_suites filter = /./run_test_suites665,17009 - class TestCaseTestCase692,17914 - def run runnerrun703,18228 - def initialize name # :nodoc:initialize734,19079 - def self.reset # :nodoc:reset739,19173 - def self.inherited klass # :nodoc:inherited745,19255 - def self.test_ordertest_order754,19524 - def self.test_suites # :nodoc:test_suites758,19577 - def self.test_methods # :nodoc:test_methods762,19677 - def passed?passed?779,20135 - def setup; endsetup786,20264 - def teardown; endteardown791,20362 - module Test # :nodoc:Test799,20504 - module Unit # :nodoc:Unit800,20543 - class TestCase # :nodoc:TestCase801,20582 - def self.inherited x # :nodoc:inherited802,20621 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/test/test_mini_mock.rb,1083 -class TestMiniMock < MiniTest::Unit::TestCaseTestMiniMock6,73 - def setupsetup7,119 - def test_should_create_stub_methodtest_should_create_stub_method12,226 - def test_should_allow_return_value_specificationtest_should_allow_return_value_specification16,295 - def test_should_blow_up_if_not_calledtest_should_blow_up_if_not_called20,396 - def test_should_not_blow_up_if_everything_calledtest_should_not_blow_up_if_everything_called26,478 - def test_should_allow_expectations_to_be_added_after_creationtest_should_allow_expectations_to_be_added_after_creation33,601 - def test_should_not_verify_if_new_expected_method_is_not_calledtest_should_not_verify_if_new_expected_method_is_not_called38,722 - def test_should_not_verify_if_unexpected_method_is_calledtest_should_not_verify_if_unexpected_method_is_called46,885 - def test_should_blow_up_on_wrong_number_of_argumentstest_should_blow_up_on_wrong_number_of_arguments52,1018 - def test_should_blow_up_on_wrong_argumentstest_should_blow_up_on_wrong_arguments62,1214 - def util_verify_badutil_verify_bad72,1382 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/test/test_mini_spec.rb,105 -class TestMeta < MiniTest::Unit::TestCaseTestMeta198,5769 - def test_structuretest_structure199,5811 - -tmp/isolate/ruby-1.8/gems/minitest-1.7.2/test/test_mini_test.rb,9297 -module M; endM7,87 -class E < StandardError; include M; endE8,101 -class TestMiniTest < MiniTest::Unit::TestCaseTestMiniTest10,142 - def assert_report expected = nilassert_report23,881 - def setupsetup42,1467 - def teardownteardown51,1675 - def test_class_puke_with_assertion_failedtest_class_puke_with_assertion_failed56,1797 - def test_class_puke_with_assertion_failed_and_long_backtracetest_class_puke_with_assertion_failed_and_long_backtrace65,2167 - def test_class_puke_with_assertion_failed_and_user_defined_assertionstest_class_puke_with_assertion_failed_and_user_defined_assertions85,3046 - def test_class_puke_with_failure_and_flunk_in_backtracetest_class_puke_with_failure_and_flunk_in_backtrace108,4111 - def test_class_puke_with_flunk_and_user_defined_assertionstest_class_puke_with_flunk_and_user_defined_assertions118,4487 - def test_class_puke_with_non_failure_exceptiontest_class_puke_with_non_failure_exception141,5527 - def test_class_run_test_suitestest_class_run_test_suites148,5794 - def test_somethingtest_something150,5875 - def test_filter_backtracetest_filter_backtrace160,6029 - def test_filter_backtrace_all_unittest_filter_backtrace_all_unit180,6693 - def test_filter_backtrace_unit_startstest_filter_backtrace_unit_starts189,6951 - def test_run_errortest_run_error202,7265 - def test_somethingtest_something204,7334 - def test_errortest_error208,7390 - def test_run_error_teardowntest_run_error_teardown236,7837 - def test_somethingtest_something238,7915 - def teardownteardown242,7971 - def test_run_failing # TODO: add error testtest_run_failing270,8417 - def test_somethingtest_something272,8511 - def test_failuretest_failure276,8567 - def test_run_failing_filteredtest_run_failing_filtered303,8989 - def test_somethingtest_something305,9069 - def test_failuretest_failure309,9125 - def test_run_passingtest_run_passing332,9519 - def test_somethingtest_something334,9590 - def test_run_skiptest_run_skip346,9740 - def test_somethingtest_something348,9808 - def test_skiptest_skip352,9864 - def util_expand_bt btutil_expand_bt379,10254 -class TestMiniTestTestCase < MiniTest::Unit::TestCaseTestMiniTestTestCase388,10411 - def setupsetup389,10465 - def teardownteardown397,10621 - def test_asserttest_assert403,10890 - def test_assert__triggeredtest_assert__triggered409,11012 - def test_assert__triggered_messagetest_assert__triggered_message415,11146 - def test_assert_blocktest_assert_block421,11263 - def test_assert_block_triggeredtest_assert_block_triggered427,11337 - def test_assert_emptytest_assert_empty435,11504 - def test_assert_empty_triggeredtest_assert_empty_triggered441,11585 - def test_assert_equaltest_assert_equal449,11744 - def test_assert_equal_differenttest_assert_equal_different453,11801 - def test_assert_in_deltatest_assert_in_delta459,11928 - def test_assert_in_delta_triggeredtest_assert_in_delta_triggered463,12007 - def test_assert_in_epsilontest_assert_in_epsilon469,12188 - def test_assert_in_epsilon_triggeredtest_assert_in_epsilon_triggered483,12589 - def test_assert_includestest_assert_includes489,12755 - def test_assert_includes_triggeredtest_assert_includes_triggered495,12852 - def test_assert_instance_oftest_assert_instance_of506,13108 - def test_assert_instance_of_triggeredtest_assert_instance_of_triggered510,13187 - def test_assert_kind_oftest_assert_kind_of516,13372 - def test_assert_kind_of_triggeredtest_assert_kind_of_triggered520,13443 - def test_assert_matchtest_assert_match526,13615 - def test_assert_match_objecttest_assert_match_object531,13717 - def pattern.=~(other) true end=~535,13799 - def test_assert_match_object_triggeredtest_assert_match_object_triggered540,13874 - def pattern.=~(other) false end=~544,13966 - def pattern.inspect; "<>" endinspect545,14002 - def test_assert_match_triggeredtest_assert_match_triggered552,14157 - def test_assert_niltest_assert_nil559,14352 - def test_assert_nil_triggeredtest_assert_nil_triggered563,14404 - def test_assert_operatortest_assert_operator569,14529 - def test_assert_operator_triggeredtest_assert_operator_triggered573,14596 - def test_assert_output_bothtest_assert_output_both579,14736 - def test_assert_output_errtest_assert_output_err588,14891 - def test_assert_output_neithertest_assert_output_neither594,14999 - def test_assert_output_outtest_assert_output_out602,15117 - def test_assert_output_triggered_bothtest_assert_output_triggered_both608,15212 - def test_assert_output_triggered_errtest_assert_output_triggered_err617,15446 - def test_assert_output_triggered_outtest_assert_output_triggered_out625,15664 - def test_assert_raisestest_assert_raises633,15869 - def test_assert_raises_skiptest_assert_raises_skip645,16152 - def test_assert_raises_moduletest_assert_raises_module659,16418 - def test_assert_raises_triggered_differenttest_assert_raises_triggered_different665,16506 - def test_assert_raises_triggered_different_msgtest_assert_raises_triggered_different_msg685,17043 - def test_assert_raises_triggered_nonetest_assert_raises_triggered_none706,17599 - def test_assert_raises_triggered_none_msgtest_assert_raises_triggered_none_msg718,17886 - def test_assert_raises_triggered_subclasstest_assert_raises_triggered_subclass730,18189 - def test_assert_respond_totest_assert_respond_to750,18695 - def test_assert_respond_to_triggeredtest_assert_respond_to_triggered754,18773 - def test_assert_sametest_assert_same760,18948 - def test_assert_same_triggeredtest_assert_same_triggered769,19102 - def test_assert_sendtest_assert_send784,19442 - def test_assert_send_badtest_assert_send_bad788,19503 - def test_assert_silenttest_assert_silent794,19644 - def test_assert_silent_triggered_errtest_assert_silent_triggered_err802,19754 - def test_assert_silent_triggered_outtest_assert_silent_triggered_out812,19982 - def test_assert_throwstest_assert_throws820,20176 - def test_assert_throws_differenttest_assert_throws_different826,20266 - def test_assert_throws_unthrowntest_assert_throws_unthrown834,20466 - def test_capture_iotest_capture_io842,20647 - def test_class_asserts_match_refutestest_class_asserts_match_refutes858,20920 - def test_class_inheritedtest_class_inherited876,21639 - def test_class_test_suitestest_class_test_suites884,21837 - def test_flunktest_flunk893,22099 - def test_flunk_messagetest_flunk_message899,22189 - def test_messagetest_message905,22286 - def test_passtest_pass913,22543 - def test_refutetest_refute917,22579 - def test_refute_emptytest_refute_empty923,22704 - def test_refute_empty_triggeredtest_refute_empty_triggered929,22786 - def test_refute_equaltest_refute_equal937,22947 - def test_refute_equal_triggeredtest_refute_equal_triggered941,23013 - def test_refute_in_deltatest_refute_in_delta947,23174 - def test_refute_in_delta_triggeredtest_refute_in_delta_triggered951,23258 - def test_refute_in_epsilontest_refute_in_epsilon957,23434 - def test_refute_in_epsilon_triggeredtest_refute_in_epsilon_triggered961,23508 - def test_refute_includestest_refute_includes968,23688 - def test_refute_includes_triggeredtest_refute_includes_triggered974,23786 - def test_refute_instance_oftest_refute_instance_of985,24044 - def test_refute_instance_of_triggeredtest_refute_instance_of_triggered989,24122 - def test_refute_kind_oftest_refute_kind_of995,24301 - def test_refute_kind_of_triggeredtest_refute_kind_of_triggered999,24371 - def test_refute_matchtest_refute_match1005,24537 - def test_refute_match_objecttest_refute_match_object1010,24639 - def test_refute_match_object_triggeredtest_refute_match_object_triggered1015,24765 - def pattern.=~(other) true end=~1019,24857 - def pattern.inspect; "<>" endinspect1020,24892 - def test_refute_match_triggeredtest_refute_match_triggered1027,25051 - def test_refute_niltest_refute_nil1034,25250 - def test_refute_nil_triggeredtest_refute_nil_triggered1038,25301 - def test_refute_operatortest_refute_operator1044,25432 - def test_refute_operator_triggeredtest_refute_operator_triggered1048,25499 - def test_refute_respond_totest_refute_respond_to1054,25643 - def test_refute_respond_to_triggeredtest_refute_respond_to_triggered1058,25720 - def test_refute_sametest_refute_same1064,25891 - def test_refute_same_triggeredtest_refute_same_triggered1068,25946 - def test_skiptest_skip1074,26104 - def test_test_methods_randomtest_test_methods_random1082,26237 - def test_test1; assert "does not matter" endtest_test11086,26356 - def test_test2; assert "does not matter" endtest_test21087,26407 - def test_test3; assert "does not matter" endtest_test31088,26458 - def test_test_methods_sortedtest_test_methods_sorted1096,26647 - def self.test_order; :sorted endtest_order1100,26766 - def test_test3; assert "does not matter" endtest_test31101,26805 - def test_test2; assert "does not matter" endtest_test21102,26856 - def test_test1; assert "does not matter" endtest_test11103,26907 - def util_assert_triggered expected, klass = MiniTest::Assertionutil_assert_triggered1110,27083 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/bin/rake,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/example/a.c,16 -void a()a3,20 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/example/b.c,16 -void b()b3,20 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/example/main.c,22 -int main ()main6,55 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/doc/jamis.rb,43 -module RDocRDoc1,0 -module PagePage2,12 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/install.rb,47 -def installBIN(from, opfile)installBIN17,389 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/alt_system.rb,296 -module Rake::AltSystemRake31,1229 - def define_module_function(name, &block)define_module_function35,1340 - def repair_command(cmd)repair_command50,1764 - def find_runnable(file)find_runnable70,2260 - def system(cmd, *args)system83,2510 - def backticks(cmd)backticks97,2827 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/classic_namespace.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/clean.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/compositepublisher.rb,166 -module RakeRake3,21 - class CompositePublisherCompositePublisher6,84 - def initializeinitialize7,111 - def add(pub)add12,206 - def uploadupload17,305 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/ftptools.rb,728 -module Rake # :nodoc:Rake11,165 - class FtpFileFtpFile15,316 - def self.datedate18,385 - def self.timetime22,439 - def initialize(path, entry)initialize26,493 - def pathpath33,696 - def directory?directory?37,748 - def modemode41,797 - def symlink?symlink?45,843 - def parse_mode(m)parse_mode51,962 - def determine_time(d1, d2, d3)determine_time59,1107 - class FtpUploaderFtpUploader87,1990 - def connect(path, host, account, password)connect95,2235 - def initialize(path, host, account, password)initialize108,2604 - def makedirs(path)makedirs117,2866 - def upload_files(wildcard)upload_files132,3298 - def closeclose139,3430 - def upload(file)upload146,3598 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/publisher.rb,529 -class CompositePublisherCompositePublisher20,757 - def initializeinitialize21,782 - def add(pub)add26,865 - def uploadupload31,952 -class SshDirPublisherSshDirPublisher38,1089 - def initialize(host, remote_dir, local_dir)initialize39,1111 - def uploadupload45,1237 -class SshFreshDirPublisher < SshDirPublisherSshFreshDirPublisher51,1389 - def uploadupload52,1434 -class SshFilePublisherSshFilePublisher60,1629 - def initialize(host, remote_dir, local_dir, *files)initialize62,1708 - def uploadupload70,1917 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/rubyforgepublisher.rb,144 -module RakeRake5,58 - class RubyForgePublisher < SshDirPublisherRubyForgePublisher7,71 - def initialize(projname, user)initialize10,163 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/sshpublisher.rb,420 -module RakeRake5,64 - class SshDirPublisherSshDirPublisher9,156 - def initialize(host, remote_dir, local_dir)initialize10,180 - def uploadupload16,320 - class SshFreshDirPublisher < SshDirPublisherSshFreshDirPublisher22,483 - def uploadupload23,530 - class SshFilePublisherSshFilePublisher31,739 - def initialize(host, remote_dir, local_dir, *files)initialize33,822 - def uploadupload41,1049 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/contrib/sys.rb,924 -module SysSys42,1738 - def install(wildcard, dest_dir, mode)install47,1915 - def run(cmd)run54,2084 - def ruby(*args)ruby60,2222 - def copy(file_name, dest_file)copy65,2341 - def copy_files(wildcard, dest_dir)copy_files71,2539 - def link(file_name, dest_file)link76,2693 - def link_files(wildcard, dest_dir)link_files82,2891 - def symlink(file_name, dest_file)symlink87,3048 - def symlink_files(wildcard, dest_dir)symlink_files93,3258 - def delete(*wildcards)delete100,3550 - def delete_all(*wildcards)delete_all115,3920 - def makedirs(*dirs)makedirs135,4431 - def indir(dir)indir144,4645 - def split_all(path)split_all156,4871 - def log(msg)log164,5117 - def quiet(&block)quiet170,5245 - def verbose(&block)verbose175,5347 - def for_files(*wildcards)for_files180,5471 - def for_matching_files(wildcard, dest_dir)for_matching_files192,5696 - def with_verbose(v)with_verbose201,5947 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/gempackagetask.rb,227 -module RakeRake12,223 - class GemPackageTask < PackageTaskGemPackageTask47,1326 - def initialize(gem_spec)initialize56,1775 - def init(gem)init64,1976 - def definedefine73,2269 - def gem_filegem_file88,2705 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/loaders/makefile.rb,177 -module RakeRake3,21 - class MakefileLoaderMakefileLoader6,94 - def load(fn)load10,194 - def process_line(line)process_line25,531 - def respace(str)respace35,826 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/packagetask.rb,453 -module RakeRake9,155 - class PackageTask < TaskLibPackageTask46,1420 - def initialize(name=nil, version=nil)initialize78,2469 - def init(name, version)init85,2680 - def definedefine99,3040 - def package_namepackage_name159,4719 - def package_dir_pathpackage_dir_path163,4803 - def tgz_filetgz_file167,4876 - def tar_gz_filetar_gz_file171,4930 - def tar_bz2_filetar_bz2_file175,4990 - def zip_filezip_file179,5052 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/rdoctask.rb,542 -module RakeRake6,60 - class RDocTask < TaskLibRDocTask59,1875 - def initialize(name = :rdoc) # :yield: selfinitialize89,2857 - def definedefine111,3514 - def option_listoption_list146,4509 - def quote(str)quote156,4884 - def option_stringoption_string164,4983 - def before_running_rdoc(&block)before_running_rdoc171,5213 - def rdoc_targetrdoc_target177,5310 - def rdoc_task_namerdoc_task_name181,5374 - def clobber_task_nameclobber_task_name190,5518 - def rerdoc_task_namererdoc_task_name199,5689 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/ruby182_test_unit_fix.rb,181 -module TestTest1,0 - module UnitUnit2,12 - module CollectorCollector3,26 - class DirDir4,47 - def collect_file(name, suites, already_gathered)collect_file6,90 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/runtest.rb,98 -module RakeRake6,73 - def run_tests(pattern='test/test*.rb', log_enabled=false)run_tests9,119 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/tasklib.rb,106 -module RakeRake5,37 - class TaskLibTaskLib8,85 - def paste(a,b) # :nodoc:paste18,487 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/testtask.rb,428 -module RakeRake8,109 - class TestTask < TaskLibTestTask37,1076 - def test_files=(list)test_files=76,2447 - def initialize(name=:test)initialize81,2536 - def definedefine97,2938 - def option_list # :nodoc:option_list123,3696 - def file_list # :nodoc:file_list127,3775 - def fix # :nodoc:fix138,4037 - def rake_loader # :nodoc:rake_loader147,4197 - def find_file(fn) # :nodoc:find_file152,4327 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake/win32.rb,296 -module RakeRake2,1 - module Win32Win327,175 - class Win32HomeError < RuntimeErrorWin32HomeError11,284 - def windows?windows?16,400 - def rake_system(*cmd)rake_system21,496 - def win32_system_dir #:nodoc:win32_system_dir35,880 - def normalize(path)normalize49,1492 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/lib/rake.rb,10453 -class ModuleModule48,1655 - def rake_extension(method)rake_extension64,2069 -class StringString77,2407 - def ext(newext='')ext84,2739 - def pathmap_explodepathmap_explode95,3068 - def pathmap_partial(n)pathmap_partial107,3558 - def pathmap_replace(patterns, &block)pathmap_replace123,3994 - def pathmap(spec=nil, &block)pathmap200,6932 -module RakeRake240,8102 - class TaskArgumentError < ArgumentErrorTaskArgumentError245,8240 - class RuleRecursionOverflowError < StandardErrorRuleRecursionOverflowError249,8356 - def initialize(*args)initialize250,8407 - def add_target(target)add_target255,8474 - def messagemessage259,8535 - def applicationapplication269,8789 - def application=(app)application=274,8910 - def original_diroriginal_dir279,9046 - module CloneableCloneable288,9235 - def dupdup291,9364 - def cloneclone302,9661 - class PseudoStatusPseudoStatus311,9891 - def initialize(code=0)initialize313,9940 - def to_ito_i316,10000 - def >>(n)>>319,10044 - def stopped?stopped?322,10082 - def exited?exited?325,10119 - class TaskArgumentsTaskArguments333,10292 - def initialize(names, values, parent=nil)initialize341,10549 - def new_scope(names)new_scope352,10853 - def [](index)[]358,11021 - def with_defaults(defaults)with_defaults365,11222 - def each(&block)each369,11299 - def method_missing(sym, *args, &block)method_missing373,11354 - def to_hashto_hash377,11431 - def to_sto_s381,11468 - def inspectinspect385,11510 - def lookup(name)lookup391,11569 - class InvocationChainInvocationChain409,12058 - def initialize(value, tail)initialize410,12082 - def member?(obj)member?415,12163 - def append(value)append419,12235 - def to_sto_s426,12413 - def self.append(value, chain)append430,12462 - def prefixprefix436,12544 - class EmptyInvocationChainEmptyInvocationChain440,12594 - def member?(obj)member?441,12625 - def append(value)append444,12672 - def to_sto_s447,12747 -module RakeRake458,12883 - class TaskTask469,13397 - def to_sto_s490,13945 - def inspectinspect494,13978 - def sourcessources500,14125 - def sourcesource505,14223 - def initialize(task_name, app)initialize511,14416 - def enhance(deps=nil, &block)enhance525,14787 - def namename532,14978 - def name_with_args # :nodoc:name_with_args537,15068 - def arg_description # :nodoc:arg_description546,15247 - def arg_namesarg_names551,15389 - def reenablereenable557,15534 - def clearclear562,15658 - def clear_prerequisitesclear_prerequisites569,15793 - def clear_actionsclear_actions575,15916 - def invoke(*args)invoke581,16049 - def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:invoke_with_call_chain588,16291 - def invoke_prerequisites(task_args, invocation_chain) # :nodoc:invoke_prerequisites603,16818 - def format_trace_flagsformat_trace_flags612,17146 - def execute(args=nil)execute621,17434 - def needed?needed?642,17939 - def timestamptimestamp648,18111 - def add_description(description)add_description654,18360 - def comment=(description)comment=661,18604 - def add_comment(comment)add_comment667,18783 - def set_arg_names(args)set_arg_names684,19225 - def investigationinvestigation690,19399 - def clearclear715,20390 - def taskstasks720,20483 - def [](task_name)[]728,20817 - def task_defined?(task_name)task_defined?733,20938 - def define_task(*args, &block)define_task740,21242 - def create_rule(*args, &block)create_rule745,21394 - def scope_name(scope, task_name)scope_name752,21655 - class FileTask < TaskFileTask766,22129 - def needed?needed?770,22255 - def timestamptimestamp775,22365 - def out_of_date?(stamp)out_of_date?786,22582 - def scope_name(scope, task_name)scope_name796,22960 - class FileCreationTask < FileTaskFileCreationTask808,23446 - def needed?needed?810,23540 - def timestamptimestamp816,23693 - class MultiTask < TaskMultiTask825,23931 - def invoke_prerequisites(args, invocation_chain)invoke_prerequisites827,23968 -def task(*args, &block)task846,24444 -def file(*args, &block)file864,24795 -def file_create(args, &block)file_create870,24943 -def directory(dir)directory879,25147 -def multitask(args, &block)multitask894,25555 -def namespace(name=nil, &block)namespace909,25923 -def rule(*args, &block)rule920,26128 -def desc(description)desc932,26323 -def import(*fns)import949,26879 -module FileUtilsFileUtils959,27162 - def sh(*cmd, &block)sh988,27954 - def rake_system(*cmd)rake_system1014,28842 - def ruby(*args,&block)ruby1024,29042 - def safe_ln(*args)safe_ln1037,29380 - def split_all(path)split_all1055,29733 -module RakeFileUtilsRakeFileUtils1067,30140 - def verbose(value=nil)verbose1107,31435 - def nowrite(value=nil)nowrite1128,32195 - def when_writing(msg=nil)when_writing1155,32899 - def rake_merge_option(args, defaults)rake_merge_option1164,33085 - def rake_output_message(message)rake_output_message1175,33343 - def rake_check_options(options, *optdecl)rake_check_options1182,33594 -module RakeRake1204,34284 - class FileListFileList1220,35051 - def initialize(*patterns)initialize1295,37711 - def include(*filenames)include1313,38270 - def exclude(*patterns, &block)exclude1347,39421 - def clear_excludeclear_exclude1360,39714 - def ==(array)==1368,39879 - def to_ato_a1373,39968 - def to_aryto_ary1379,40057 - def is_a?(klass)is_a?1384,40119 - def *(other)*1390,40274 - def resolveresolve1401,40477 - def calculate_exclude_regexpcalculate_exclude_regexp1411,40670 - def resolve_add(fn)resolve_add1431,41156 - def resolve_excluderesolve_exclude1441,41317 - def sub(pat, rep)sub1454,41662 - def gsub(pat, rep)gsub1465,41996 - def sub!(pat, rep)sub!1470,42160 - def gsub!(pat, rep)gsub!1476,42332 - def pathmap(spec=nil)pathmap1484,42600 - def ext(newext='')ext1496,42940 - def egrep(pattern, *options)egrep1506,43338 - def existingexisting1526,43874 - def existing!existing!1532,44045 - def partition(&block) # :nodoc:partition1540,44265 - def to_sto_s1550,44541 - def add_matching(pattern)add_matching1556,44632 - def exclude?(fn)exclude?1564,44824 - def import(array)import1580,45261 - def [](*args)[]1589,45451 -module RakeRake1596,45530 - def each_dir_parent(dir) # :nodoc:each_dir_parent1600,45605 -module RakeRake1615,46003 - class DefaultLoaderDefaultLoader1618,46062 - def load(fn)load1619,46084 - class EarlyTimeEarlyTime1625,46233 - def <=>(other)<=>1629,46297 - def to_sto_s1633,46334 -class TimeTime1644,46579 - def <=>(other)<=>1646,46630 -module RakeRake1655,46785 - class NameSpaceNameSpace1661,46975 - def initialize(task_manager, scope_list)initialize1665,47092 - def [](name)[]1671,47262 - def taskstasks1676,47399 - module TaskManagerTaskManager1684,47613 - def initializeinitialize1689,47793 - def create_rule(*args, &block)create_rule1697,47937 - def define_task(task_class, *args, &block)define_task1703,48150 - def intern(task_class, task_name)intern1718,48742 - def [](task_name, scopes=nil)[]1723,48898 - def synthesize_file_task(task_name)synthesize_file_task1731,49165 - def resolve_args(args)resolve_args1738,49422 - def resolve_args_without_dependencies(args)resolve_args_without_dependencies1756,49904 - def resolve_args_with_dependencies(args, hash) # :nodoc:resolve_args_with_dependencies1777,50573 - def enhance_with_matching_rule(task_name, level=0)enhance_with_matching_rule1802,51433 - def taskstasks1818,51959 - def tasks_in_scope(scope)tasks_in_scope1824,52108 - def clearclear1832,52286 - def lookup(task_name, initial_scope=nil)lookup1842,52677 - def lookup_in_scope(name, scope)lookup_in_scope1858,53160 - def current_scopecurrent_scope1872,53490 - def in_namespace(name)in_namespace1878,53654 - def generate_namegenerate_name1891,53892 - def trace_rule(level, message)trace_rule1897,53981 - def attempt_rule(task_name, extensions, block, level)attempt_rule1902,54168 - def make_sources(task_name, extensions)make_sources1924,55032 - class ApplicationApplication1953,55770 - def initializeinitialize1971,56283 - def runrun1997,57168 - def init(app_name='rake')init2006,57348 - def load_rakefileload_rakefile2015,57570 - def top_leveltop_level2022,57727 - def add_loader(ext, loader)add_loader2036,58111 - def optionsoptions2042,58271 - def invoke_task(task_string)invoke_task2048,58410 - def parse_task_string(string)parse_task_string2054,58545 - def standard_exception_handlingstandard_exception_handling2066,58826 - def have_rakefilehave_rakefile2091,59616 - def tty_output?tty_output?2104,59948 - def tty_output=( tty_output_state )tty_output=2109,60061 - def truncate_output?truncate_output?2115,60270 - def display_tasks_and_commentsdisplay_tasks_and_comments2120,60383 - def terminal_widthterminal_width2142,61153 - def dynamic_widthdynamic_width2154,61417 - def dynamic_width_sttydynamic_width_stty2158,61525 - def dynamic_width_tputdynamic_width_tput2162,61607 - def unix?unix?2166,61680 - def windows?windows?2170,61796 - def truncate(string, width)truncate2174,61843 - def display_prerequisitesdisplay_prerequisites2183,62039 - def standard_rake_optionsstandard_rake_options2192,62301 - def handle_optionshandle_options2310,66561 - def rake_require(file_name, paths=$LOAD_PATH, loaded=$")rake_require2339,67468 - def find_rakefile_locationfind_rakefile_location2353,67861 - def raw_load_rakefile # :nodoc:raw_load_rakefile2367,68157 - def glob(path, &block)glob2393,69050 - def system_dirsystem_dir2399,69212 - def standard_system_dir #:nodoc:standard_system_dir2412,69502 - def standard_system_dir #:nodoc:standard_system_dir2416,69591 - def collect_taskscollect_tasks2425,69931 - def add_import(fn)add_import2438,70282 - def load_importsload_imports2443,70390 - def const_warning(const_name)const_warning2457,70767 - def rakefile_locationrakefile_location2468,71194 -class ModuleModule2479,71370 - def const_missing(const_name)const_missing2488,71803 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/capture_stdout.rb,125 -module CaptureStdoutCaptureStdout6,81 - def capture_stdoutcapture_stdout7,102 - def capture_stderrcapture_stderr17,247 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/check_expansion.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/check_no_expansion.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/contrib/test_sys.rb,93 -class TestSys < Test::Unit::TestCaseTestSys7,97 - def test_split_alltest_split_all39,934 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/data/rakelib/test1.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/data/rbext/rakefile.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/filecreation.rb,237 -module FileCreationFileCreation3,21 - def create_timed_files(oldfile, *newfiles)create_timed_files7,96 - def create_dir(dirname)create_dir18,424 - def create_file(name)create_file23,545 - def delete_file(name)delete_file29,688 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/functional.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/in_environment.rb,148 -module InEnvironmentInEnvironment1,0 - def in_environment(settings)in_environment6,172 - def set_env(settings) # :nodoc:set_env14,362 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/rake_test_setup.rb,147 - class Test::Unit::TestCaseTest13,175 -module TestMethodsTestMethods20,253 - def assert_exception(ex, msg=nil, &block)assert_exception21,272 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/reqfile.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/reqfile2.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/session_functional.rb,3026 -module SessionSession16,359 - class AbstractSessionAbstractSession17,374 - def initialize(*args)initialize19,434 -class FunctionalTest < Test::Unit::TestCaseFunctionalTest26,526 - def setupsetup32,642 - def test_rake_defaulttest_rake_default46,1049 - def test_rake_error_on_bad_tasktest_rake_error_on_bad_task52,1181 - def test_env_availabe_at_top_scopetest_env_availabe_at_top_scope58,1335 - def test_env_availabe_at_task_scopetest_env_availabe_at_task_scope64,1498 - def test_multi_desctest_multi_desc70,1675 - def test_long_descriptiontest_long_description83,2008 - def test_rbexttest_rbext93,2308 - def test_systemtest_system100,2438 - def test_system_excludes_rakelib_files_tootest_system_excludes_rakelib_files_too107,2584 - def test_by_default_rakelib_files_are_includetest_by_default_rakelib_files_are_include114,2781 - def test_implicit_systemtest_implicit_system121,2964 - def test_no_systemtest_no_system128,3156 - def test_nosearch_with_rakefile_uses_local_rakefiletest_nosearch_with_rakefile_uses_local_rakefile135,3345 - def test_nosearch_without_rakefile_finds_systemtest_nosearch_without_rakefile_finds_system142,3526 - def test_nosearch_without_rakefile_and_no_system_failstest_nosearch_without_rakefile_and_no_system_fails152,3781 - def test_dry_runtest_dry_run159,4006 - def test_dry_run_bugtest_dry_run_bug168,4348 - def test_trace_bugtest_trace_bug181,4696 - def test_importstest_imports193,4981 - def test_rules_chaining_to_file_tasktest_rules_chaining_to_file_task209,5508 - def test_file_creation_tasktest_file_creation_task220,5784 - def test_dash_f_with_no_arg_foils_rakefile_lookuptest_dash_f_with_no_arg_foils_rakefile_lookup229,6000 - def test_dot_rake_files_can_be_loaded_with_dash_rtest_dot_rake_files_can_be_loaded_with_dash_r234,6136 - def test_can_invoke_task_in_toplevel_namespacetest_can_invoke_task_in_toplevel_namespace239,6272 - def test_can_invoke_task_in_nested_namespacetest_can_invoke_task_in_nested_namespace246,6441 - def test_tasks_can_reference_task_in_same_namespacetest_tasks_can_reference_task_in_same_namespace253,6620 - def test_tasks_can_reference_task_in_other_namespacestest_tasks_can_reference_task_in_other_namespaces260,6805 - def test_anonymous_tasks_can_be_invoked_indirectlytest_anonymous_tasks_can_be_invoked_indirectly267,6991 - def test_rake_namespace_refers_to_topleveltest_rake_namespace_refers_to_toplevel274,7172 - def test_file_task_are_not_scoped_by_namespacestest_file_task_are_not_scoped_by_namespaces281,7351 - def test_rake_returns_status_error_valuestest_rake_returns_status_error_values288,7534 - def test_rake_returns_no_status_error_on_normal_exittest_rake_returns_no_status_error_on_normal_exit295,7692 - def remove_chaining_filesremove_chaining_files304,7873 - def format_commandformat_command311,8032 - def format_command=(fmt_command)format_command=317,8201 - def rake(*option_list)rake322,8291 - def assert_status(expected_status=0)assert_status336,8772 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/shellcommand.rb,0 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_application.rb,4739 -class TestApplication < Test::Unit::TestCaseTestApplication18,307 - def setupsetup23,423 - def test_constant_warningtest_constant_warning28,505 - def test_display_taskstest_display_tasks35,719 - def test_display_tasks_with_long_commentstest_display_tasks_with_long_comments44,1017 - def test_display_tasks_with_task_name_wider_than_tty_displaytest_display_tasks_with_task_name_wider_than_tty_display55,1471 - def test_display_tasks_with_very_long_task_name_to_a_non_tty_shows_name_and_commenttest_display_tasks_with_very_long_task_name_to_a_non_tty_shows_name_and_comment68,2024 - def test_display_tasks_with_long_comments_to_a_non_tty_shows_entire_commenttest_display_tasks_with_long_comments_to_a_non_tty_shows_entire_comment80,2569 - def test_display_tasks_with_long_comments_to_a_non_tty_with_columns_set_truncates_commentstest_display_tasks_with_long_comments_to_a_non_tty_with_columns_set_truncates_comments90,2972 - def test_display_tasks_with_full_descriptionstest_display_tasks_with_full_descriptions102,3505 - def test_finding_rakefiletest_finding_rakefile112,3872 - def test_not_finding_rakefiletest_not_finding_rakefile116,3975 - def test_load_rakefiletest_load_rakefile122,4155 - def test_load_rakefile_from_subdirtest_load_rakefile_from_subdir134,4459 - def test_load_rakefile_not_foundtest_load_rakefile_not_found146,4781 - def test_load_from_system_rakefiletest_load_from_system_rakefile159,5150 - def test_windowstest_windows174,5550 - def test_loading_importstest_loading_imports178,5619 - def test_building_imported_files_on_demandtest_building_imported_files_on_demand188,5848 - def test_handle_options_should_strip_options_from_ARGVtest_handle_options_should_strip_options_from_ARGV200,6219 - def test_good_runtest_good_run213,6480 - def test_display_task_runtest_display_task_run227,6779 - def test_display_prereqstest_display_prereqs240,7146 - def test_bad_runtest_bad_run257,7668 - def test_bad_run_with_tracetest_bad_run_with_trace269,7956 - def test_run_with_bad_optionstest_run_with_bad_options281,8266 -class TestApplicationOptions < Test::Unit::TestCaseTestApplicationOptions295,8614 - def setupsetup299,8713 - def teardownteardown306,8851 - def clear_argvclear_argv312,8968 - def test_default_optionstest_default_options318,9039 - def test_dry_runtest_dry_run337,9615 - def test_describetest_describe346,9817 - def test_describe_with_patterntest_describe_with_pattern354,10007 - def test_executetest_execute362,10213 - def test_execute_and_continuetest_execute_and_continue371,10397 - def test_execute_and_printtest_execute_and_print380,10607 - def test_helptest_help390,10857 - def test_libdirtest_libdir400,11109 - def test_rakefiletest_rakefile408,11259 - def test_rakelibtest_rakelib414,11440 - def test_requiretest_require420,11624 - def test_missing_requiretest_missing_require429,11905 - def test_prereqstest_prereqs438,12141 - def test_quiettest_quiet444,12245 - def test_no_searchtest_no_search451,12383 - def test_silenttest_silent457,12501 - def test_systemtest_system464,12639 - def test_no_systemtest_no_system470,12740 - def test_tracetest_trace476,12849 - def test_trace_rulestest_trace_rules484,13024 - def test_taskstest_tasks490,13123 - def test_verbosetest_verbose501,13416 - def test_versiontest_version508,13556 - def test_classic_namespacetest_classic_namespace516,13750 - def test_bad_optiontest_bad_option527,14131 - def test_task_collectiontest_task_collection541,14582 - def test_default_task_collectiontest_default_task_collection546,14686 - def test_environment_definitiontest_environment_definition551,14786 - def flags(*sets)flags560,14969 - def command_line(*options)command_line570,15190 -class TestTaskArgumentParsing < Test::Unit::TestCaseTestTaskArgumentParsing585,15496 - def setupsetup586,15549 - def test_name_onlytest_name_only590,15603 - def test_empty_argstest_empty_args596,15737 - def test_one_argumenttest_one_argument602,15874 - def test_two_argumentstest_two_arguments608,16021 - def test_can_handle_spaces_between_argstest_can_handle_spaces_between_args614,16180 - def test_keeps_embedded_spacestest_keeps_embedded_spaces620,16389 -class TestTaskArgumentParsing < Test::Unit::TestCaseTestTaskArgumentParsing628,16572 - def test_terminal_width_using_envtest_terminal_width_using_env631,16650 - def test_terminal_width_using_sttytest_terminal_width_using_stty638,16825 - def test_terminal_width_using_tputtest_terminal_width_using_tput649,17105 - def test_terminal_width_using_hardcoded_80test_terminal_width_using_hardcoded_80660,17385 - def test_terminal_width_with_failuretest_terminal_width_with_failure668,17599 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_clean.rb,88 -class TestClean < Test::Unit::TestCaseTestClean6,63 - def test_cleantest_clean8,117 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_definitions.rb,490 -class TestDefinitions < Test::Unit::TestCaseTestDefinitions10,207 - def setupsetup16,330 - def test_tasktest_task20,364 - def test_file_tasktest_file_task29,563 - def check_tasks(n1, n2, n3)check_tasks38,855 - def test_incremental_definitionstest_incremental_definitions50,1216 - def test_missing_dependenciestest_missing_dependencies62,1524 - def test_implicit_file_dependenciestest_implicit_file_dependencies67,1654 - def create_existing_filecreate_existing_file77,1915 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_earlytime.rb,273 -class TestEarlyTime < Test::Unit::TestCaseTestEarlyTime6,57 - def test_createtest_create7,100 - def test_equalitytest_equality18,378 - def test_original_time_compare_is_not_messed_uptest_original_time_compare_is_not_messed_up23,507 - def test_to_stest_to_s32,706 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_extension.rb,597 -class TestExtension < Test::Unit::TestCaseTestExtension8,147 - module RedirectRedirect10,191 - def error_redirecterror_redirect11,209 - class SampleSample22,384 - def duplicate_methodduplicate_method25,420 - def ok_methodok_method31,535 - def duplicate_methodduplicate_method39,666 - def test_methods_actually_existtest_methods_actually_exist46,752 - def test_no_warning_when_defining_ok_methodtest_no_warning_when_defining_ok_method52,866 - def test_extension_complains_when_a_method_that_is_presenttest_extension_complains_when_a_method_that_is_present56,963 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_file_creation_task.rb,456 -class TestFileCreationTask < Test::Unit::TestCaseTestFileCreationTask9,176 - def setupsetup15,301 - def teardownteardown19,335 - def test_file_neededtest_file_needed23,387 - def test_directorytest_directory34,768 - def test_no_retriggers_on_filecreate_tasktest_no_retriggers_on_filecreate_task41,931 - def test_no_retriggers_on_file_tasktest_no_retriggers_on_file_task49,1301 - def test_very_early_timestamptest_very_early_timestamp57,1665 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_file_task.rb,813 -class TestFileTask < Test::Unit::TestCaseTestFileTask10,207 - def setupsetup15,310 - def test_file_needtest_file_need22,420 - def test_file_times_new_depends_on_oldtest_file_times_new_depends_on_old35,859 - def test_file_times_old_depends_on_newtest_file_times_old_depends_on_new44,1211 - def test_file_depends_on_task_depend_on_filetest_file_depends_on_task_depend_on_file56,1726 - def test_existing_file_depends_on_non_existing_filetest_existing_file_depends_on_non_existing_file68,2069 - def ztest_file_deletes_on_failureztest_file_deletes_on_failure79,2464 -class TestDirectoryTask < Test::Unit::TestCaseTestDirectoryTask96,2845 - def setupsetup99,2908 - def teardownteardown103,2965 - def test_directorytest_directory107,3025 - def test_directory_win32test_directory_win32124,3617 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_filelist.rb,3743 -class TestFileList < Test::Unit::TestCaseTestFileList9,119 - def setupsetup14,236 - def teardownteardown18,276 - def test_delgating_methods_do_not_include_to_a_or_to_arytest_delgating_methods_do_not_include_to_a_or_to_ary23,375 - def test_createtest_create30,791 - def test_create_with_argstest_create_with_args35,866 - def test_create_with_blocktest_create_with_block41,1039 - def test_create_with_bracketstest_create_with_brackets46,1155 - def test_create_with_brackets_and_filelisttest_create_with_brackets_and_filelist52,1328 - def test_include_with_another_arraytest_include_with_another_array58,1524 - def test_include_with_another_filelisttest_include_with_another_filelist63,1663 - def test_appendtest_append69,1867 - def test_add_manytest_add_many75,1979 - def test_add_returntest_add_return83,2180 - def test_matchtest_match91,2356 - def test_add_matchingtest_add_matching99,2552 - def test_multiple_patternstest_multiple_patterns108,2756 - def test_square_bracket_patterntest_square_bracket_pattern119,3058 - def test_curly_bracket_patterntest_curly_bracket_pattern127,3263 - def test_rejecttest_reject135,3468 - def test_excludetest_exclude144,3705 - def test_excluding_via_blocktest_excluding_via_block157,4187 - def test_exclude_return_on_createtest_exclude_return_on_create164,4453 - def test_exclude_with_string_return_on_createtest_exclude_with_string_return_on_create170,4658 - def test_default_excludetest_default_exclude176,4934 - def test_uniquetest_unique184,5189 - def test_to_stringtest_to_string192,5388 - def test_to_arraytest_to_array199,5555 - def test_to_s_pendingtest_to_s_pending207,5798 - def test_inspect_pendingtest_inspect_pending216,6079 - def test_subtest_sub225,6395 - def test_claim_to_be_a_kind_of_arraytest_claim_to_be_a_kind_of_array237,6766 - def test_claim_to_be_a_kind_of_filelisttest_claim_to_be_a_kind_of_filelist243,6905 - def test_claim_to_be_a_filelist_instancetest_claim_to_be_a_filelist_instance249,7053 - def test_dont_claim_to_be_an_array_instancetest_dont_claim_to_be_an_array_instance254,7176 - def test_sub!test_sub!259,7299 - def test_sub_with_blocktest_sub_with_block268,7523 - def test_string_exttest_string_ext280,7952 - def test_filelist_exttest_filelist_ext305,8995 - def test_gsubtest_gsub310,9115 - def test_gsub!test_gsub!318,9310 - def test_egrep_with_outputtest_egrep_with_output326,9499 - def test_egrep_with_blocktest_egrep_with_block333,9706 - def test_existingtest_existing346,10084 - def test_existing!test_existing!352,10258 - def test_ignore_specialtest_ignore_special359,10459 - def test_clear_ignore_patternstest_clear_ignore_patterns369,10950 - def test_exclude_with_alternate_file_sepstest_exclude_with_alternate_file_seps380,11292 - def test_add_default_exclude_listtest_add_default_exclude_list390,11574 - def test_basic_array_functionstest_basic_array_functions402,11906 - def test_flattentest_flatten414,12208 - def test_clone_and_duptest_clone_and_dup419,12366 - def test_dup_and_clone_replicate_tainttest_dup_and_clone_replicate_taint429,12586 - def test_duped_items_will_thawtest_duped_items_will_thaw438,12804 - def test_cloned_items_stay_frozentest_cloned_items_stay_frozen446,12963 - def test_array_comparisonstest_array_comparisons455,13142 - def test_array_equalitytest_array_equality468,13461 - def test_enumeration_methodstest_enumeration_methods479,13669 - def test_array_operatorstest_array_operators526,14878 - def test_other_array_returning_methodstest_other_array_returning_methods565,15762 - def test_file_utils_can_use_fileliststest_file_utils_can_use_filelists592,16458 - def create_test_datacreate_test_data602,16741 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_fileutils.rb,1949 -class TestFileUtils < Test::Unit::TestCaseTestFileUtils10,155 - def setupsetup14,244 - def teardownteardown18,309 - def test_rm_one_filetest_rm_one_file23,403 - def test_rm_two_filestest_rm_two_files29,535 - def test_rm_filelisttest_rm_filelist37,753 - def test_lntest_ln45,986 - class BadLinkBadLink52,1224 - def initialize(klass)initialize55,1291 - def cp(*args)cp58,1354 - def ln(*args)ln61,1402 - def test_safe_ln_failover_to_cp_on_standard_errortest_safe_ln_failover_to_cp_on_standard_error67,1501 - def test_safe_ln_failover_to_cp_on_not_implemented_errortest_safe_ln_failover_to_cp_on_not_implemented_error76,1757 - def test_safe_ln_fails_on_script_errortest_safe_ln_fails_on_script_error83,1964 - def test_verbosetest_verbose89,2143 - def test_nowritetest_nowrite100,2358 - def test_file_utils_methods_are_available_at_top_leveltest_file_utils_methods_are_available_at_top_level111,2572 - def test_fileutils_methods_dont_leaktest_fileutils_methods_dont_leak117,2728 - def test_shtest_sh123,2931 - class ShSh132,3287 - def run(*args)run134,3320 - def self.run(*args)run137,3363 - def test_sh_with_a_single_string_argumenttest_sh_with_a_single_string_argument142,3423 - def test_sh_with_multiple_argumentstest_sh_with_multiple_arguments149,3597 - def test_sh_failuretest_sh_failure156,3775 - def test_sh_special_handlingtest_sh_special_handling162,3911 - def test_sh_nooptest_sh_noop179,4324 - def test_sh_bad_optiontest_sh_bad_option184,4450 - def test_sh_verbosetest_sh_verbose191,4645 - def test_sh_no_verbosetest_sh_no_verbose200,4836 - def test_ruby_with_a_single_string_argumenttest_ruby_with_a_single_string_argument209,5006 - def test_ruby_with_multiple_argumentstest_ruby_with_multiple_arguments216,5179 - def test_split_alltest_split_all223,5349 - def redirect_stderrredirect_stderr234,5746 - def windows?windows?243,5884 - def env_varenv_var247,5937 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_ftp.rb,380 -class FakeDateFakeDate8,104 - def self.todaytoday9,119 - def self.nownow12,166 -class TestFtpFile < Test::Unit::TestCaseTestFtpFile18,228 - def setupsetup20,270 - def test_generaltest_general24,369 - def test_far_datetest_far_date37,840 - def test_close_datetest_close_date42,1022 - def test_directorytest_directory47,1208 - def test_symlinktest_symlink53,1388 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_invocation_chain.rb,1052 -class TestAnEmptyInvocationChain < Test::Unit::TestCaseTestAnEmptyInvocationChain8,159 - def setupsetup11,238 - def test_should_be_able_to_add_memberstest_should_be_able_to_add_members15,299 - def test_to_stest_to_s21,409 -class TestAnInvocationChainWithOneMember < Test::Unit::TestCaseTestAnInvocationChainWithOneMember27,543 - def setupsetup30,630 - def test_should_report_first_member_as_a_membertest_should_report_first_member_as_a_member36,757 - def test_should_fail_when_adding_original_membertest_should_fail_when_adding_original_member40,855 - def test_to_stest_to_s48,1093 -class TestAnInvocationChainWithMultipleMember < Test::Unit::TestCaseTestAnInvocationChainWithMultipleMember55,1233 - def setupsetup58,1325 - def test_should_report_first_member_as_a_membertest_should_report_first_member_as_a_member65,1492 - def test_should_report_second_member_as_a_membertest_should_report_second_member_as_a_member69,1590 - def test_should_fail_when_adding_original_membertest_should_fail_when_adding_original_member73,1690 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_makefile_loader.rb,107 -class TestMakefileLoader < Test::Unit::TestCaseTestMakefileLoader7,89 - def test_parsetest_parse10,153 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_multitask.rb,256 -class TestMultiTask < Test::Unit::TestCaseTestMultiTask7,128 - def setupsetup10,187 - def test_running_multitaskstest_running_multitasks15,243 - def test_all_multitasks_wait_on_slow_prerequisitestest_all_multitasks_wait_on_slow_prerequisites27,699 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_namespace.rb,290 -class TestNameSpace < Test::Unit::TestCaseTestNameSpace14,182 - class TMTM17,248 - def test_namespace_creationtest_namespace_creation21,296 - def test_namespace_lookuptest_namespace_lookup27,410 - def test_namespace_reports_tasks_it_ownstest_namespace_reports_tasks_it_owns37,608 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_package_task.rb,552 -class TestPackageTask < Test::Unit::TestCaseTestPackageTask7,100 - def test_createtest_create11,183 - def test_missing_versiontest_missing_version44,1129 - def test_no_versiontest_no_version50,1256 - def test_clonetest_clone55,1388 - class TestGemPackageTask < Test::Unit::TestCaseTestGemPackageTask76,1839 - def test_gem_packagetest_gem_package77,1889 - def test_gem_package_with_current_platformtest_gem_package_with_current_platform90,2257 - def test_gem_package_with_ruby_platformtest_gem_package_with_ruby_platform104,2703 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_pathmap.rb,2419 -class TestPathMap < Test::Unit::TestCaseTestPathMap7,128 - def test_returns_self_with_no_argstest_returns_self_with_no_args10,192 - def test_s_returns_file_separatortest_s_returns_file_separator14,280 - def test_f_returns_basenametest_f_returns_basename21,509 - def test_n_returns_basename_without_extensiontest_n_returns_basename_without_extension27,725 - def test_d_returns_dirnametest_d_returns_dirname35,1054 - def test_9d_returns_partial_dirnametest_9d_returns_partial_dirname42,1322 - def test_x_returns_extensiontest_x_returns_extension52,1833 - def test_X_returns_everything_but_extensiontest_X_returns_everything_but_extension60,2106 - def test_p_returns_entire_pathnametest_p_returns_entire_pathname74,2720 - def test_dash_returns_empty_stringtest_dash_returns_empty_string80,2972 - def test_percent_percent_returns_percenttest_percent_percent_returns_percent85,3114 - def test_undefined_percent_causes_errortest_undefined_percent_causes_error89,3207 - def test_pattern_returns_substitutionstest_pattern_returns_substitutions95,3338 - def test_pattern_can_use_backreferencestest_pattern_can_use_backreferences100,3470 - def test_pattern_with_star_replacement_string_uses_blocktest_pattern_with_star_replacement_string_uses_block104,3589 - def test_pattern_with_no_replacement_nor_block_substitutes_empty_stringtest_pattern_with_no_replacement_nor_block_substitutes_empty_string111,3854 - def test_pattern_works_with_certain_valid_operatorstest_pattern_works_with_certain_valid_operators115,3987 - def test_multiple_patternstest_multiple_patterns123,4338 - def test_partial_directory_selection_works_with_patternstest_partial_directory_selection_works_with_patterns128,4483 - def test_pattern_with_invalid_operatortest_pattern_with_invalid_operator133,4652 - def test_works_with_windows_separatorstest_works_with_windows_separators140,4850 - def test_complex_patternstest_complex_patterns148,5067 -class TestPathMapExplode < Test::Unit::TestCaseTestPathMapExplode163,5778 - def setupsetup164,5826 - def teardownteardown168,5895 - def test_explodetest_explode172,5970 -class TestPathMapPartial < Test::Unit::TestCaseTestPathMapPartial190,6734 - def test_pathmap_partialtest_pathmap_partial191,6782 -class TestFileListPathMap < Test::Unit::TestCaseTestFileListPathMap206,7168 - def test_file_list_supports_pathmaptest_file_list_supports_pathmap207,7217 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_pseudo_status.rb,199 -class PseudoStatusTest < Test::Unit::TestCasePseudoStatusTest9,119 - def test_with_zero_exit_statustest_with_zero_exit_status10,165 - def test_with_99_exit_statustest_with_99_exit_status18,367 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_rake.rb,300 -class TestRake < Test::Unit::TestCaseTestRake6,57 - def test_each_dir_parenttest_each_dir_parent7,95 - def alldirs(fn)alldirs22,597 - def test_can_override_applicationtest_can_override_application28,698 - def test_original_dir_reports_current_dirtest_original_dir_reports_current_dir37,914 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_rdoc_task.rb,1147 -class TestRDocTask < Test::Unit::TestCaseTestRDocTask7,97 - def setupsetup11,179 - def test_tasks_creationtest_tasks_creation15,215 - def test_tasks_creation_with_custom_name_symboltest_tasks_creation_with_custom_name_symbol22,352 - def test_tasks_creation_with_custom_name_stringtest_tasks_creation_with_custom_name_string30,577 - def test_tasks_creation_with_custom_name_hashtest_tasks_creation_with_custom_name_hash38,804 - def test_tasks_creation_with_custom_name_hash_will_use_default_if_an_option_isnt_giventest_tasks_creation_with_custom_name_hash_will_use_default_if_an_option_isnt_given48,1165 - def test_tasks_creation_with_custom_name_hash_raises_exception_if_invalid_option_giventest_tasks_creation_with_custom_name_hash_raises_exception_if_invalid_option_given55,1401 - def test_inline_source_is_enabled_by_defaulttest_inline_source_is_enabled_by_default67,1713 - def test_inline_source_option_is_only_appended_if_option_not_already_giventest_inline_source_option_is_only_appended_if_option_not_already_given72,1851 - def test_inline_source_option_can_be_disabledtest_inline_source_option_can_be_disabled83,2236 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_require.rb,290 -class TestRequire < Test::Unit::TestCaseTestRequire8,159 - def test_can_load_rake_librarytest_can_load_rake_library11,223 - def test_wont_reload_rake_librarytest_wont_reload_rake_library18,387 - def test_throws_error_if_library_not_foundtest_throws_error_if_library_not_found25,563 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_rules.rb,2984 -class TestRules < Test::Unit::TestCaseTestRules10,207 - def setupsetup22,488 - def teardownteardown27,537 - def test_multiple_rules1test_multiple_rules131,632 - def test_multiple_rules2test_multiple_rules243,922 - def test_create_with_sourcetest_create_with_source53,1177 - def test_single_dependenttest_single_dependent64,1434 - def test_rule_can_be_created_by_stringtest_rule_can_be_created_by_string73,1615 - def test_rule_prereqs_can_be_created_by_stringtest_rule_prereqs_can_be_created_by_string82,1808 - def test_plain_strings_as_dependents_refer_to_filestest_plain_strings_as_dependents_refer_to_files91,2007 - def test_file_names_beginning_with_dot_can_be_tricked_into_refering_to_filetest_file_names_beginning_with_dot_can_be_tricked_into_refering_to_file100,2214 - def test_file_names_beginning_with_dot_can_be_wrapped_in_lambdatest_file_names_beginning_with_dot_can_be_wrapped_in_lambda113,2536 - def test_file_names_containing_percent_can_be_wrapped_in_lambdatest_file_names_containing_percent_can_be_wrapped_in_lambda126,2883 - def test_non_extension_rule_name_refers_to_filetest_non_extension_rule_name_refers_to_file139,3233 - def test_pathmap_automatically_applies_to_nametest_pathmap_automatically_applies_to_name152,3521 - def test_plain_strings_are_just_filenamestest_plain_strings_are_just_filenames165,3851 - def test_rule_runs_when_explicit_task_has_no_actionstest_rule_runs_when_explicit_task_has_no_actions178,4178 - def test_close_matches_on_name_do_not_trigger_ruletest_close_matches_on_name_do_not_trigger_rule190,4467 - def test_rule_rebuilds_obj_when_source_is_newertest_rule_rebuilds_obj_when_source_is_newer199,4758 - def test_rule_with_two_sources_runs_if_both_sources_are_presenttest_rule_with_two_sources_runs_if_both_sources_are_present208,4972 - def test_rule_with_two_sources_but_one_missing_does_not_runtest_rule_with_two_sources_but_one_missing_does_not_run217,5241 - def test_rule_with_two_sources_builds_both_sourcestest_rule_with_two_sources_builds_both_sources227,5517 - def test_second_rule_runs_when_first_rule_doesnttest_second_rule_runs_when_first_rule_doesnt243,5843 - def test_second_rule_doest_run_if_first_triggerstest_second_rule_doest_run_if_first_triggers256,6186 - def test_second_rule_doest_run_if_first_triggers_with_reversed_rulestest_second_rule_doest_run_if_first_triggers_with_reversed_rules268,6513 - def test_rule_with_proc_dependent_will_triggertest_rule_with_proc_dependent_will_trigger280,6860 - def test_proc_returning_lists_are_flattened_into_prereqstest_proc_returning_lists_are_flattened_into_prereqs297,7393 - def test_recursive_rules_will_work_as_long_as_they_terminatetest_recursive_rules_will_work_as_long_as_they_terminate319,7959 - def test_recursive_rules_that_dont_terminate_will_overflowtest_recursive_rules_that_dont_terminate_will_overflow330,8346 - def test_rules_with_bad_dependents_will_failtest_rules_with_bad_dependents_will_fail343,8743 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_task_arguments.rb,994 -class TestTaskArguments < Test::Unit::TestCaseTestTaskArguments7,128 - def teardownteardown8,175 - def test_empty_arg_list_is_emptytest_empty_arg_list_is_empty13,241 - def test_multiple_values_in_argstest_multiple_values_in_args18,357 - def test_to_stest_to_s23,537 - def test_enumerable_behaviortest_enumerable_behavior29,711 - def test_named_argstest_named_args34,871 - def test_args_knows_its_namestest_args_knows_its_names43,1085 - def test_extra_names_are_niltest_extra_names_are_nil48,1219 - def test_args_can_reference_env_valuestest_args_can_reference_env_values53,1339 - def test_creating_new_argument_scopestest_creating_new_argument_scopes61,1541 - def test_child_hides_parent_arg_namestest_child_hides_parent_arg_names71,1831 - def test_default_arguments_values_can_be_mergedtest_default_arguments_values_can_be_merged77,2016 - def test_default_arguements_that_dont_match_names_are_ignoredtest_default_arguements_that_dont_match_names_are_ignored84,2271 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_task_manager.rb,1276 -class TaskManagerTaskManager7,88 -class TestTaskManager < Test::Unit::TestCaseTestTaskManager11,139 - def setupsetup14,207 - def test_create_task_managertest_create_task_manager18,252 - def test_define_tasktest_define_task23,344 - def test_name_lookuptest_name_lookup29,479 - def test_namespace_task_createtest_namespace_task_create34,577 - def test_anonymous_namespacetest_anonymous_namespace42,788 - def test_create_filetask_in_namespacetest_create_filetask_in_namespace51,1017 - def test_namespace_yields_same_namespace_as_returnedtest_namespace_yields_same_namespace_as_returned59,1239 - def test_name_lookup_with_implicit_file_taskstest_name_lookup_with_implicit_file_tasks67,1476 - def test_name_lookup_with_nonexistent_tasktest_name_lookup_with_nonexistent_task73,1619 - def test_name_lookup_in_multiple_scopestest_name_lookup_in_multiple_scopes79,1746 - def test_lookup_with_explicit_scopestest_lookup_with_explicit_scopes121,2961 - def test_correctly_scoped_prerequisites_are_invokedtest_correctly_scoped_prerequisites_are_invoked138,3492 -class TestTaskManagerArgumentResolution < Test::Unit::TestCaseTestTaskManagerArgumentResolution153,3873 - def test_good_arg_patternstest_good_arg_patterns154,3936 - def task(*args)task169,4614 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_tasklib.rb,92 -class TestTaskLib < Test::Unit::TestCaseTestTaskLib7,66 - def test_pastetest_paste8,107 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_tasks.rb,3048 -class TestTask < Test::Unit::TestCaseTestTask11,237 - def setupsetup16,337 - def test_createtest_create20,371 - def test_inspecttest_inspect32,644 - def test_invoketest_invoke37,774 - def test_invoke_with_circular_dependenciestest_invoke_with_circular_dependencies47,1078 - def test_dry_run_prevents_actionstest_dry_run_prevents_actions60,1511 - def test_tasks_can_be_tracedtest_tasks_can_be_traced73,1895 - def test_no_double_invoketest_no_double_invoke85,2168 - def test_can_double_invoke_with_reenabletest_can_double_invoke_with_reenable94,2443 - def test_cleartest_clear103,2638 - def test_clear_prerequisitestest_clear_prerequisites110,2825 - def test_clear_actionstest_clear_actions117,3003 - def test_findtest_find123,3132 - def test_definedtest_defined130,3342 - def test_multi_invocationstest_multi_invocations136,3450 - def test_task_listtest_task_list146,3683 - def test_task_gives_name_on_to_stest_task_gives_name_on_to_s152,3809 - def test_symbols_can_be_prerequisitestest_symbols_can_be_prerequisites157,3905 - def test_strings_can_be_prerequisitestest_strings_can_be_prerequisites162,4017 - def test_arrays_can_be_prerequisitestest_arrays_can_be_prerequisites167,4130 - def test_filelists_can_be_prerequisitestest_filelists_can_be_prerequisites172,4254 - def test_investigation_outputtest_investigation_output177,4401 - def test_extended_commentstest_extended_comments188,4697 - def test_multiple_commentstest_multiple_comments204,5196 - def test_settable_commentstest_settable_comments212,5352 -class TestTaskWithArguments < Test::Unit::TestCaseTestTaskWithArguments220,5534 - def setupsetup225,5647 - def test_no_args_giventest_no_args_given229,5681 - def test_args_giventest_args_given234,5762 - def test_name_and_needstest_name_and_needs239,5854 - def test_name_and_explicit_needstest_name_and_explicit_needs246,6018 - def test_name_args_and_explicit_needstest_name_args_and_explicit_needs253,6199 - def test_illegal_keys_in_task_name_hashtest_illegal_keys_in_task_name_hash260,6399 - def test_arg_list_is_empty_if_no_args_giventest_arg_list_is_empty_if_no_args_given266,6543 - def test_tasks_can_access_arguments_as_hashtest_tasks_can_access_arguments_as_hash271,6681 - def test_actions_of_various_arity_are_ok_with_argstest_actions_of_various_arity_are_ok_with_args284,7048 - def test_arguments_are_passed_to_blocktest_arguments_are_passed_to_block305,7511 - def test_extra_parameters_are_ignoredtest_extra_parameters_are_ignored312,7679 - def test_arguments_are_passed_to_all_blockstest_arguments_are_passed_to_all_blocks320,7838 - def test_block_with_no_parameters_is_oktest_block_with_no_parameters_is_ok335,8135 - def test_name_with_argstest_name_with_args340,8224 - def test_named_args_are_passed_to_prereqstest_named_args_are_passed_to_prereqs350,8485 - def test_args_not_passed_if_no_prereq_namestest_args_not_passed_if_no_prereq_names358,8716 - def test_args_not_passed_if_no_arg_namestest_args_not_passed_if_no_arg_names367,8958 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_test_task.rb,452 -class TestTestTask < Test::Unit::TestCaseTestTestTask6,66 - def setupsetup10,148 - def teardownteardown15,205 - def test_no_tasktest_no_task19,259 - def test_defaultstest_defaults23,324 - def test_non_defaultstest_non_defaults33,595 - def test_patterntest_pattern47,981 - def test_env_testtest_env_test54,1126 - def test_test_filestest_test_files62,1302 - def test_both_pattern_and_test_filestest_both_pattern_and_test_files69,1473 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_top_level_functions.rb,719 -class TestTopLevelFunctions < Test::Unit::TestCaseTestTopLevelFunctions15,212 - def setupsetup19,310 - def teardownteardown25,406 - def test_namespacetest_namespace30,466 - def test_importtest_import35,594 - def test_when_writingtest_when_writing42,861 - def test_when_not_writingtest_when_not_writing51,1031 - def test_missing_constants_tasktest_missing_constants_task63,1302 - def test_missing_constants_file_tasktest_missing_constants_file_task68,1444 - def test_missing_constants_file_creation_tasktest_missing_constants_file_creation_task73,1599 - def test_missing_constants_rake_apptest_missing_constants_rake_app78,1779 - def test_missing_other_constanttest_missing_other_constant83,1931 - -tmp/isolate/ruby-1.8/gems/rake-0.8.7/test/test_win32.rb,660 -class TestWin32 < Test::Unit::TestCaseTestWin329,119 - def test_win32_system_dir_uses_home_if_definedtest_win32_system_dir_uses_home_if_defined15,228 - def test_win32_system_dir_uses_homedrive_homepath_when_no_home_definedtest_win32_system_dir_uses_homedrive_homepath_when_no_home_defined21,412 - def test_win32_system_dir_uses_appdata_when_no_home_or_home_combotest_win32_system_dir_uses_appdata_when_no_home_or_home_combo32,690 - def test_win32_system_dir_fallback_to_userprofile_otherwisetest_win32_system_dir_fallback_to_userprofile_otherwise44,1070 - def test_win32_system_dir_nil_of_no_env_varstest_win32_system_dir_nil_of_no_env_vars57,1437 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/bin/autospec,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/bin/spec,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/diffing_spec.rb,111 - class AnimalAnimal16,275 - def initialize(name,species)initialize17,290 - def inspectinspect21,368 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/failing_implicit_docstrings_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/failure_in_after.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/failure_in_before.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_with_flexmock.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_with_mocha.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/mocking_with_rr.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/partial_mock_example.rb,67 -class MockableClassMockableClass1,0 - def self.find idfind2,20 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/pending_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/predicate_example.rb,114 -class BddFrameworkBddFramework1,0 - def intuitive?intuitive?2,19 - def adopted_quickly?adopted_quickly?6,52 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/raising_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/syntax_error_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/team_spec.rb,175 -class TeamTeam1,0 - def initializeinitialize3,34 -class PlayersPlayers8,89 - def initializeinitialize9,103 - def sizesize12,144 - def include? playerinclude?15,179 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/failing/timeout_behaviour.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/custom_formatter.rb,140 -class CustomFormatter < Spec::Runner::Formatter::ProgressBarFormatterCustomFormatter5,217 - def backtrace_line(line)backtrace_line6,287 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/custom_matchers.rb,452 -module AnimalSpecHelperAnimalSpecHelper1,0 - class EatEat2,24 - def initialize(food)initialize3,36 - def matches?(animal)matches?7,93 - def failure_messagefailure_message12,181 - def negative_failure_messagenegative_failure_message16,279 - def eat(food)eat21,392 -module AnimalsAnimals26,437 - class AnimalAnimal27,452 - def eats?(food)eats?28,467 - class Mouse < AnimalMouse33,544 - def foods_i_eatfoods_i_eat34,567 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/dynamic_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/file_accessor.rb,110 -class FileAccessorFileAccessor1,0 - def open_and_handle_with(pathname, processor)open_and_handle_with2,19 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/file_accessor_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/filtered_formatter.rb,209 -class FilteredFormatter < Spec::Runner::Formatter::NestedTextFormatterFilteredFormatter3,55 - def add_example_group(example_group)add_example_group4,126 - def example_passed(example)example_passed13,319 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/filtered_formatter_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/greeter_spec.rb,102 -class GreeterGreeter9,160 - def initialize(person = nil)initialize10,174 - def greetgreet14,233 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/helper_method_example.rb,92 -module HelperMethodExampleHelperMethodExample1,0 - def helper_methodhelper_method3,81 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/implicit_docstrings_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/io_processor.rb,124 -class DataTooShort < StandardError; endDataTooShort1,0 -class IoProcessorIoProcessor3,41 - def process(io)process5,130 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/io_processor_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/mocking_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/multi_threaded_example_group_runner.rb,176 -class MultiThreadedExampleGroupRunner < Spec::Runner::ExampleGroupRunnerMultiThreadedExampleGroupRunner1,0 - def initialize(options, arg)initialize2,73 - def runrun9,195 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/nested_classes_example.rb,269 -class StackExamples < Spec::ExampleGroupStackExamples3,34 -class EmptyStackExamples < StackExamplesEmptyStackExamples10,146 -class AlmostFullStackExamples < StackExamplesAlmostFullStackExamples17,276 -class FullStackExamples < StackExamplesFullStackExamples27,480 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/options_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/options_formatter.rb,206 -class OptionsFormatter < Spec::Runner::Formatter::BaseTextFormatterOptionsFormatter8,314 - def example_started(proxy)example_started9,382 - def example_group_started(proxy)example_group_started15,485 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/partial_mock_example.rb,67 -class MockableClassMockableClass1,0 - def self.find idfind2,20 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/pending_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/predicate_example.rb,114 -class BddFrameworkBddFramework1,0 - def intuitive?intuitive?2,19 - def adopted_quickly?adopted_quickly?6,54 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/shared_example_group_example.rb,356 -module SharedExampleGroupExampleSharedExampleGroupExample1,0 - class OneThingOneThing2,33 - def what_things_dowhat_things_do3,50 - class AnotherThingAnotherThing8,104 - def what_things_dowhat_things_do9,125 - class YetAnotherThingYetAnotherThing14,179 - def what_things_dowhat_things_do15,203 - def helper_methodhelper_method23,396 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/shared_stack_examples.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/simple_matcher_example.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stack.rb,312 -class StackUnderflowError < RuntimeErrorStackUnderflowError1,0 -class StackOverflowError < RuntimeErrorStackOverflowError4,46 -class StackStack7,91 - def initializeinitialize9,106 - def push objectpush13,148 - def poppop18,250 - def peekpeek23,346 - def empty?empty?28,429 - def full?full?32,467 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stack_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stack_spec_with_nested_example_groups.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/stubbing_example.rb,73 -class StubbableClassStubbableClass9,215 - def self.find idfind10,236 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/passing/yielding_example.rb,126 -class MessageAppenderMessageAppender1,0 - def initialize(appendage)initialize3,25 - def append_to(message)append_to7,89 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/examples/ruby1.9.compatibility/access_to_constants_spec.rb,460 -module Foo Foo7,228 - module BarBar8,240 - module ModuleInEnclosingModule;endModuleInEnclosingModule10,258 - class ClassInEnclosingModule;end ClassInEnclosingModule11,297 - def method_in_enclosing_module;endmethod_in_enclosing_module12,335 - module ModuleDefinedInGroup;endModuleDefinedInGroup51,1404 - class ClassDefinedInGroup; end ClassDefinedInGroup52,1442 - def method_defined_in_group; endmethod_defined_in_group53,1480 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/step_definitions/running_rspec_steps.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/step_definitions/stubbing_steps.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/support/env.rb,533 -class RspecWorldRspecWorld10,235 - def self.working_dirworking_dir18,434 - def self.spec_commandspec_command22,576 - def self.cmdline_filecmdline_file26,700 - def self.rspec_librspec_lib30,844 - def spec(args)spec34,928 - def cmdline(args)cmdline38,988 - def create_file(file_name, contents)create_file42,1051 - def create_directory(dirname)create_directory47,1199 - def last_stdoutlast_stdout51,1292 - def last_stderrlast_stderr55,1329 - def last_exit_codelast_exit_code59,1366 - def ruby(args)ruby64,1536 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/features/support/matchers/smart_match.rb,54 - def regexp?regexp?2,49 - def quoted?quoted?6,86 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/init.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/autotest/discover.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/autotest/rspec.rb,393 -class RspecCommandError < StandardError; endRspecCommandError17,394 -class Autotest::Rspec < AutotestAutotest19,440 - def initializeinitialize23,573 - def consolidate_failures(failed)consolidate_failures29,789 - def make_test_cmd(files_to_test)make_test_cmd39,1011 - def normalize(files_to_test)normalize44,1205 - def add_options_if_present # :nodoc:add_options_if_present51,1366 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/flexmock.rb,294 -module SpecSpec9,179 - module AdaptersAdapters10,191 - module MockFrameworkMockFramework11,209 - def setup_mocks_for_rspecsetup_mocks_for_rspec13,272 - def verify_mocks_for_rspecverify_mocks_for_rspec16,342 - def teardown_mocks_for_rspecteardown_mocks_for_rspec19,409 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/mocha.rb,291 -module SpecSpec5,96 - module AdaptersAdapters6,108 - module MockFrameworkMockFramework7,126 - def setup_mocks_for_rspecsetup_mocks_for_rspec14,319 - def verify_mocks_for_rspecverify_mocks_for_rspec17,381 - def teardown_mocks_for_rspecteardown_mocks_for_rspec20,445 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/rr.rb,292 -module SpecSpec7,174 - module AdaptersAdapters8,186 - module MockFrameworkMockFramework9,204 - def setup_mocks_for_rspecsetup_mocks_for_rspec11,275 - def verify_mocks_for_rspecverify_mocks_for_rspec14,350 - def teardown_mocks_for_rspecteardown_mocks_for_rspec17,435 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/adapters/mock_frameworks/rspec.rb,297 -module SpecSpec4,64 - module AdaptersAdapters5,76 - module MockFrameworkMockFramework7,129 - def setup_mocks_for_rspecsetup_mocks_for_rspec9,200 - def verify_mocks_for_rspecverify_mocks_for_rspec12,296 - def teardown_mocks_for_rspecteardown_mocks_for_rspec15,377 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/autorun.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/deprecation.rb,295 -module SpecSpec1,0 - def deprecate(method, alternate_method=nil)deprecate3,28 - def warn(message)warn25,641 - class HashWithDeprecationNotice < HashHashWithDeprecationNotice31,706 - def initialize(method, alternate_method=nil, &block)initialize32,747 - def []=(k,v)[]=35,872 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/dsl/main.rb,240 -module SpecSpec1,0 - module DSLDSL2,12 - module MainMain3,25 - def describe(*args, &block)describe24,982 - def share_examples_for(*args, &block)share_examples_for47,1762 - def share_as(name, &block)share_as78,2698 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/dsl.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/args_and_options.rb,392 -module SpecSpec1,0 - module ExampleExample2,12 - module ArgsAndOptionsArgsAndOptions3,29 - def args_and_options(*args) # :nodoc:args_and_options4,55 - def add_options(args, options={}) # :nodoc:add_options9,192 - def set_location(options, location) # :nodoc:set_location16,388 - module WithOptions # :nodoc:WithOptions20,491 - def optionsoptions21,526 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/before_and_after_hooks.rb,988 -module SpecSpec1,0 - module ExampleExample2,12 - module BeforeAndAfterHooksBeforeAndAfterHooks3,29 - def before_suite_parts # :nodoc:before_suite_parts5,80 - def after_suite_parts # :nodoc:after_suite_parts9,171 - def append_before(scope = :each, &block)append_before19,588 - def prepend_before(scope = :each, &block)prepend_before28,918 - def prepend_after(scope = :each, &block)prepend_after36,1210 - def append_after(scope = :each, &block)append_after45,1541 - def before_each_parts # :nodoc:before_each_parts49,1634 - def after_each_parts # :nodoc:after_each_parts53,1717 - def before_all_parts # :nodoc:before_all_parts57,1798 - def after_all_parts # :nodoc:after_all_parts61,1879 - def before_suite_parts # :nodoc:before_suite_parts65,1958 - def after_suite_parts # :nodoc:after_suite_parts69,2055 - def before_parts(scope)before_parts75,2163 - def after_parts(scope)after_parts83,2349 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/errors.rb,513 -module SpecSpec1,0 - module ExampleExample2,12 - class ExamplePendingError < StandardError; endExamplePendingError3,29 - class NotYetImplementedError < ExamplePendingErrorNotYetImplementedError5,81 - def initializeinitialize7,174 - class PendingExampleFixedError < StandardError; endPendingExampleFixedError12,237 - class NoDescriptionError < ArgumentErrorNoDescriptionError14,294 - def message(kind, location)message16,359 - def initialize(kind, location)initialize20,489 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group.rb,93 -module SpecSpec1,0 - module ExampleExample2,12 - class ExampleGroupExampleGroup5,136 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_factory.rb,747 -module SpecSpec1,0 - module ExampleExample2,12 - class ExampleGroupFactoryExampleGroupFactory4,30 - module ClassMethodsClassMethods5,60 - def resetreset8,133 - def example_group_creation_listenersexample_group_creation_listeners13,233 - def register_example_group(klass)register_example_group17,342 - def create_shared_example_group(*args, &example_group_block) # :nodoc:create_shared_example_group23,524 - def create_example_group(*args, &block)create_example_group27,700 - def register(key, example_group_class)register48,1573 - def default(example_group_class)default53,1744 - def [](key)[]61,2100 - def determine_superclass(opts)determine_superclass67,2186 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_hierarchy.rb,745 -module SpecSpec1,0 - module ExampleExample2,12 - class ExampleGroupHierarchy < ArrayExampleGroupHierarchy3,29 - def initialize(example_group_class)initialize4,69 - def run_before_all(example)run_before_all12,387 - def run_before_each(example)run_before_each16,486 - def run_after_each(example)run_after_each20,587 - def run_after_all(example)run_after_all24,686 - def before_all_partsbefore_all_parts28,783 - def before_each_partsbefore_each_parts32,900 - def after_each_partsafter_each_parts36,1020 - def after_all_partsafter_all_parts40,1145 - def nested_descriptionsnested_descriptions44,1267 - def nested_description_from(example_group)nested_description_from48,1435 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_methods.rb,2412 -module SpecSpec1,0 - module ExampleExample2,12 - module ExampleGroupMethodsExampleGroupMethods4,30 - def build_description_from(*args)build_description_from8,119 - def options # :nodoc:options24,637 - def inherited(klass) # :nodoc:inherited28,700 - def describe(*args, &example_group_block)describe47,1212 - def it_should_behave_like(*shared_example_groups)it_should_behave_like64,1836 - def example(description=nil, options={}, backtrace=nil, &implementation)example72,2148 - def pending_implementationpending_implementation79,2481 - def xexample(description=nil, opts={}, &block)xexample87,2720 - def run(run_options)run94,2916 - def set_description(*args)set_description107,3537 - def notify(reporter) # :nodoc:notify114,3766 - def descriptiondescription118,3882 - def described_typedescribed_type122,4011 - def described_classdescribed_class126,4134 - def description_argsdescription_args130,4248 - def description_parts #:nodoc:description_parts134,4319 - def example_proxies # :nodoc:example_proxies140,4543 - def example_implementations # :nodoc:example_implementations144,4622 - def examples(run_options=nil) #:nodoc:examples148,4717 - def number_of_examples #:nodoc:number_of_examples152,4862 - def example_group_hierarchyexample_group_hierarchy156,4942 - def nested_descriptionsnested_descriptions160,5056 - def include_constants_in(mod)include_constants_in164,5149 - def let(name, &block)let168,5290 - def let!(name, &block)let!175,5456 - def subclass(*args, &example_group_block)subclass182,5569 - def dry_run(examples, run_options)dry_run192,5905 - def run_before_all(run_options)run_before_all199,6117 - def run_examples(success, instance_variables, examples, run_options)run_examples212,6639 - def run_after_all(success, instance_variables, run_options)run_after_all226,7203 - def examples_to_run(run_options)examples_to_run238,7696 - def examples_were_specified?(run_options)examples_were_specified?255,8326 - def method_added(name) # :nodoc:method_added259,8422 - def example_method?(method_name)example_method?263,8568 - def should_method?(method_name)should_method?267,8654 - def include_shared_example_group(shared_example_group)include_shared_example_group273,8833 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_group_proxy.rb,313 -module SpecSpec1,0 - module ExampleExample2,12 - class ExampleGroupProxyExampleGroupProxy5,179 - def initialize(example_group) # :nodoc:initialize7,208 - def backtracebacktrace41,1699 - def filtered_description(regexp)filtered_description47,1896 - def ==(other) # :nodoc:==56,2279 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_matcher.rb,735 -module SpecSpec1,0 - module ExampleExample2,12 - class ExampleMatcherExampleMatcher3,29 - def initialize(example_group_description, example_name)initialize4,54 - def matches?(specified_examples)matches?9,227 - def matches_literal_example?(specified_example)matches_literal_example?16,477 - def matches_example_not_considering_modules?(specified_example)matches_example_not_considering_modules?20,705 - def example_group_regexexample_group_regex24,955 - def example_group_with_before_all_regexpexample_group_with_before_all_regexp28,1046 - def example_group_regex_not_considering_modulesexample_group_regex_not_considering_modules32,1172 - def example_regexpexample_regexp36,1304 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_methods.rb,1177 -module SpecSpec1,0 - module ExampleExample2,12 - module ExampleMethodsExampleMethods3,29 - def violated(message="")violated8,158 - def descriptiondescription20,502 - def options # :nodoc:options28,760 - def execute(run_options, instance_variables) # :nodoc:execute32,823 - module BlockAliasesBlockAliases59,1668 - def expect(&block)expect69,2058 - def eval_each_fail_fast(blocks) # :nodoc:eval_each_fail_fast73,2128 - def eval_each_fail_slow(blocks) # :nodoc:eval_each_fail_slow77,2239 - def instance_variable_hash # :nodoc:instance_variable_hash89,2550 - def set_instance_variables_from_hash(ivars) # :nodoc:set_instance_variables_from_hash96,2790 - def run_before_eachrun_before_each106,3200 - def run_after_eachrun_after_each111,3348 - def initialize(example_proxy, &implementation)initialize115,3437 - def before_each_examplebefore_each_example126,3669 - def after_each_exampleafter_each_example131,3764 - def described_classdescribed_class138,3904 - def description_argsdescription_args142,3976 - def example_group_hierarchyexample_group_hierarchy146,4050 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/example_proxy.rb,317 -module SpecSpec1,0 - module ExampleExample2,12 - class ExampleProxyExampleProxy5,178 - def initialize(description=nil, options={}, location=nil) # :nodoc:initialize7,202 - def backtracebacktrace24,839 - def update(description) # :nodoc:update31,1075 - def ==(other) # :nodoc:==36,1174 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/module_reopening_fix.rb,230 -module SpecSpec1,0 - module ExampleExample2,12 - module ModuleReopeningFixModuleReopeningFix26,562 - def child_moduleschild_modules27,592 - def included(mod)included31,657 - def include(mod)include35,721 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/pending.rb,132 -module SpecSpec1,0 - module ExampleExample2,12 - module PendingPending3,29 - def pending(message = "TODO")pending4,48 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/predicate_matchers.rb,264 -module SpecSpec1,0 - module ExampleExample2,12 - module PredicateMatchersPredicateMatchers3,29 - def predicate_matcherspredicate_matchers32,929 - def define_methods_from_predicate_matchers # :nodoc:define_methods_from_predicate_matchers36,1082 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/shared_example_group.rb,693 -module SpecSpec1,0 - module ExampleExample2,12 - class SharedExampleGroup < ModuleSharedExampleGroup3,29 - module ClassMethodsClassMethods4,67 - def register(*args, &block)register5,93 - def find(example_group_description)find11,318 - def clearclear15,461 - def include?(group)include?19,530 - def countcount23,619 - def shared_example_groupsshared_example_groups29,704 - def already_registered?(new_example_group)already_registered?33,791 - def expanded_path(example_group)expanded_path41,1259 - def initialize(*args, &example_group_block)initialize49,1435 - def included(mod) # :nodoc:included54,1578 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example/subject.rb,554 -module SpecSpec1,0 - module ExampleExample2,12 - module SubjectSubject3,29 - module ExampleGroupMethodsExampleGroupMethods4,48 - def subject(&block)subject18,662 - def its(attribute, &block)its23,817 - def explicit_subjectexplicit_subject40,1219 - def implicit_subjectimplicit_subject48,1474 - module ExampleMethodsExampleMethods53,1615 - def subjectsubject82,2750 - def should(matcher=nil, message=nil)should96,3219 - def should_not(matcher=nil, message=nil)should_not108,3646 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/example.rb,55 -module SpecSpec1,0 - module ExampleExample144,3595 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/errors.rb,136 -module SpecSpec1,0 - module ExpectationsExpectations2,12 - class ExpectationNotMetError < superclassExpectationNotMetError9,328 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/extensions/kernel.rb,156 -module KernelKernel1,0 - def should(matcher=nil, message=nil, &block)should26,676 - def should_not(matcher=nil, message=nil, &block)should_not49,1381 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/extensions.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/fail_with.rb,143 -module SpecSpec1,0 - module ExpectationsExpectations2,12 - def fail_with(message, expected=nil, target=nil) # :nodoc:fail_with11,370 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations/handler.rb,472 -module SpecSpec1,0 - module ExpectationsExpectations2,12 - class InvalidMatcherError < ArgumentError; end InvalidMatcherError3,34 - class PositiveExpectationHandler PositiveExpectationHandler5,98 - def self.handle_matcher(actual, matcher, message=nil, &block)handle_matcher6,143 - class NegativeExpectationHandlerNegativeExpectationHandler26,907 - def self.handle_matcher(actual, matcher, message=nil, &block)handle_matcher27,944 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/expectations.rb,66 -module SpecSpec7,173 - module ExpectationsExpectations33,1245 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/extensions/instance_exec.rb,157 -module SpecSpec1,0 - module MatchersMatchers2,12 - module InstanceExecInstanceExec3,30 - def instance_exec(*args, &block)instance_exec12,468 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/autorunner.rb,81 -class Test::Unit::AutoRunnerTest1,0 - def process_args(argv)process_args3,59 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/testcase.rb,363 -module TestTest3,30 - module UnitUnit4,42 - class TestCaseTestCase21,527 - def self.suitesuite25,639 - def self.example_method?(method_name)example_method29,718 - def self.test_method?(method_name)test_method33,838 - def initialize(description, &implementation)initialize43,1100 - def run(ignore_this_argument=nil)run50,1346 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/testresult.rb,65 -class Test::Unit::TestResultTest1,0 - def passed?passed?3,66 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/testsuite_adapter.rb,317 -module TestTest3,31 - module UnitUnit4,43 - class TestSuiteAdapter < TestSuiteTestSuiteAdapter5,57 - def initialize(example_group)initialize8,177 - def namename13,306 - def run(*args)run17,366 - def sizesize22,485 - def delete(example)delete26,552 - def empty?empty?30,621 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test/unit/ui/console/testrunner.rb,513 -module TestTest3,43 - module UnitUnit4,55 - module UIUI5,69 - module ConsoleConsole6,83 - class TestRunnerTestRunner7,104 - def started_with_rspec(result)started_with_rspec10,186 - def test_started_with_rspec(name)test_started_with_rspec17,433 - def test_finished_with_rspec(name)test_finished_with_rspec31,918 - def finished_with_rspec(elapsed_time)finished_with_rspec38,1176 - def setup_mediator_with_rspecsetup_mediator_with_rspec47,1498 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/interop/test.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be.rb,2015 -module SpecSpec29,430 - module MatchersMatchers30,442 - class Be #:nodoc:Be32,461 - def initialize(*args, &block)initialize35,527 - def matches?(actual)matches?39,601 - def failure_message_for_shouldfailure_message_for_should44,682 - def failure_message_for_should_notfailure_message_for_should_not48,794 - def descriptiondescription52,911 - def args_to_sargs_to_s64,1138 - def parenthesize(string)parenthesize68,1243 - def inspected_argsinspected_args72,1320 - def expected_to_sentenceexpected_to_sentence76,1399 - def args_to_sentenceargs_to_sentence80,1478 - class BeComparedTo < BeBeComparedTo86,1560 - def initialize(operand, operator)initialize88,1589 - def matches?(actual)matches?93,1708 - def failure_message_for_shouldfailure_message_for_should98,1818 - def failure_message_for_should_notfailure_message_for_should_not102,1941 - def descriptiondescription113,2326 - class BePredicate < BeBePredicate119,2437 - def initialize(*args, &block)initialize121,2465 - def matches?(actual)matches?127,2609 - def failure_message_for_shouldfailure_message_for_should142,3117 - def failure_message_for_should_notfailure_message_for_should_not146,3254 - def descriptiondescription150,3390 - def predicatepredicate156,3510 - def present_tense_predicatepresent_tense_predicate160,3578 - def parse_expected(expected)parse_expected164,3661 - def prefix_and_expected(symbol)prefix_and_expected169,3782 - def prefix_to_sentenceprefix_to_sentence174,3896 - class BeSameAs < BeBeSameAs180,3974 - def initialize(*args, &block)initialize182,4005 - def matches?(actual)matches?187,4110 - def failure_message_for_shouldfailure_message_for_should192,4207 - def failure_message_for_should_notfailure_message_for_should_not196,4317 - def descriptiondescription200,4429 - def be(*args)be236,5782 - def be_a(klass)be_a243,5933 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be_close.rb,103 -module SpecSpec1,0 - module MatchersMatchers2,12 - def be_close(expected, delta)be_close12,254 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be_instance_of.rb,114 -module SpecSpec1,0 - module MatchersMatchers2,12 - def be_an_instance_of(expected)be_an_instance_of16,431 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/be_kind_of.rb,104 -module SpecSpec1,0 - module MatchersMatchers2,12 - def be_a_kind_of(expected)be_a_kind_of16,393 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/change.rb,835 -module SpecSpec1,0 - module MatchersMatchers2,12 - class Change #:nodoc:Change5,77 - def initialize(receiver=nil, message=nil, &block)initialize6,103 - def matches?(event_proc)matches?12,340 - def raise_block_syntax_errorraise_block_syntax_error27,882 - def evaluate_value_procevaluate_value_proc34,1068 - def failure_message_for_shouldfailure_message_for_should38,1140 - def actual_deltaactual_delta54,1956 - def failure_message_for_should_notfailure_message_for_should_not58,2021 - def by(amount)by62,2186 - def by_at_least(minimum)by_at_least67,2262 - def by_at_most(maximum)by_at_most72,2350 - def to(to)to77,2443 - def from (from)from82,2507 - def descriptiondescription87,2580 - def change(receiver=nil, message=nil, &block)change147,4562 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/compatibility.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/dsl.rb,179 -module SpecSpec1,0 - module MatchersMatchers2,12 - module DSLDSL3,30 - def define(name, &declarations)define5,72 - def create(name, &declarations)create12,282 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/eql.rb,86 -module SpecSpec1,0 - module MatchersMatchers2,12 - def eql(expected)eql15,408 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/equal.rb,142 -module SpecSpec1,0 - module MatchersMatchers2,12 - def equal(expected)equal16,474 - def inspect_object(o)inspect_object22,632 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/errors.rb,115 -module SpecSpec1,0 - module MatchersMatchers2,12 - class MatcherError < StandardError; endMatcherError3,30 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/exist.rb,88 -module SpecSpec1,0 - module MatchersMatchers2,12 - def exist(arg=nil)exist8,129 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/generated_descriptions.rb,246 -module SpecSpec1,0 - module MatchersMatchers2,12 - def self.clear_generated_descriptionclear_generated_description7,115 - def self.generated_descriptiongenerated_description12,224 - def self.last_descriptionlast_description19,386 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/has.rb,414 -module SpecSpec1,0 - module MatchersMatchers2,12 - class HasHas4,35 - def initialize(expected, *args, &block)initialize6,56 - def matches?(actual)matches?10,176 - def failure_message_for_shouldfailure_message_for_should14,283 - def failure_message_for_should_notfailure_message_for_should_not18,428 - def descriptiondescription22,577 - def predicate(sym)predicate28,670 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/have.rb,796 -module SpecSpec1,0 - module MatchersMatchers2,12 - class Have #:nodoc:Have3,30 - def initialize(expected, relativity=:exactly)initialize4,54 - def relativitiesrelativities11,267 - def matches?(collection_owner)matches?19,438 - def not_a_collectionnot_a_collection37,1399 - def failure_message_for_shouldfailure_message_for_should41,1543 - def failure_message_for_should_notfailure_message_for_should_not45,1670 - def descriptiondescription67,2490 - def respond_to?(sym)respond_to?71,2588 - def method_missing(sym, *args, &block)method_missing77,2695 - def relative_expectationrelative_expectation87,3052 - def have(n)have123,4384 - def have_at_least(n)have_at_least136,4649 - def have_at_most(n)have_at_most148,4902 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/include.rb,149 -module SpecSpec1,0 - module MatchersMatchers2,12 - def include(*expected)include19,594 - def helper(actual, *_expected_)helper25,761 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/match.rb,90 -module SpecSpec1,0 - module MatchersMatchers2,12 - def match(expected)match13,324 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/match_array.rb,519 -module SpecSpec1,0 - module MatchersMatchers2,12 - class MatchArray #:nodoc:MatchArray4,31 - def initialize(expected)initialize7,105 - def matches?(actual)matches?11,176 - def failure_message_for_shouldfailure_message_for_should18,439 - def failure_message_for_should_notfailure_message_for_should_not26,921 - def descriptiondescription30,1025 - def safe_sort(array)safe_sort36,1127 - def difference_between_arrays(array_1, array_2)difference_between_arrays40,1242 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/matcher.rb,1031 -module SpecSpec1,0 - module MatchersMatchers2,12 - class MatcherMatcher3,30 - def initialize(name, *expected, &declarations)initialize10,196 - def matches?(actual)matches?27,965 - def match(&block)match46,1419 - def match_unless_raises(exception=Exception, &block)match_unless_raises51,1510 - def failure_message_for_should(&block)failure_message_for_should57,1669 - def failure_message_for_should_not(&block)failure_message_for_should_not62,1818 - def description(&block)description67,1975 - def diffable?diffable?72,2139 - def diffablediffable77,2215 - def chain(method, &block)chain82,2303 - def making_declared_methods_public # :nodoc:making_declared_methods_public93,2507 - def cache_or_call_cached(key, &block)cache_or_call_cached110,3413 - def cache(key, &block)cache114,3522 - def call_cached(key)call_cached118,3593 - def name_to_sentencename_to_sentence122,3718 - def expected_to_sentenceexpected_to_sentence126,3783 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/method_missing.rb,126 -module SpecSpec1,0 - module MatchersMatchers2,12 - def method_missing(sym, *args, &block) # :nodoc:method_missing3,30 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/operator_matcher.rb,914 -module SpecSpec1,0 - module MatchersMatchers2,12 - class OperatorMatcherOperatorMatcher4,31 - def registryregistry6,77 - def register(klass, operator, matcher)register10,138 - def get(klass, operator)get15,277 - def initialize(actual)initialize25,604 - def self.use_custom_matcher_or_delegate(operator)use_custom_matcher_or_delegate29,669 - def fail_with_message(message)fail_with_message43,1147 - def descriptiondescription47,1261 - def eval_match(actual, operator, expected)eval_match53,1363 - class PositiveOperatorMatcher < OperatorMatcher #:nodoc:PositiveOperatorMatcher61,1583 - def __delegate_operator(actual, operator, expected)__delegate_operator62,1644 - class NegativeOperatorMatcher < OperatorMatcher #:nodoc:NegativeOperatorMatcher74,2103 - def __delegate_operator(actual, operator, expected)__delegate_operator75,2164 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/pretty.rb,229 -module SpecSpec1,0 - module MatchersMatchers2,12 - module PrettyPretty3,30 - def split_words(sym)split_words4,48 - def to_sentence(words=[])to_sentence8,117 - def _pretty_print(array)_pretty_print22,451 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/raise_exception.rb,809 -module SpecSpec1,0 - module MatchersMatchers2,12 - class RaiseException #:nodoc:RaiseException3,30 - def initialize(expected_exception_or_message=Exception, expected_message=nil, &block)initialize4,64 - def matches?(given_proc)matches?15,509 - def eval_blockeval_block38,1423 - def verify_messageverify_message48,1646 - def failure_message_for_shouldfailure_message_for_should59,1904 - def failure_message_for_should_notfailure_message_for_should_not63,2053 - def descriptiondescription67,2167 - def expected_exceptionexpected_exception72,2252 - def given_exceptiongiven_exception83,2590 - def negative_expectation?negative_expectation?87,2731 - def raise_exception(exception=Exception, message=nil, &block)raise_exception125,4844 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/respond_to.rb,625 -module SpecSpec1,0 - module MatchersMatchers2,12 - class RespondTo #:nodoc:RespondTo4,35 - def initialize(*names)initialize5,64 - def matches?(actual)matches?11,200 - def failure_message_for_shouldfailure_message_for_should19,463 - def failure_message_for_should_notfailure_message_for_should_not23,651 - def descriptiondescription27,817 - def with(n)with31,902 - def argumentargument36,978 - def matches_arity?(actual, name)matches_arity?43,1079 - def with_aritywith_arity47,1218 - def pp_namespp_names52,1371 - def respond_to(*names)respond_to67,1823 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/satisfy.rb,378 -module SpecSpec1,0 - module MatchersMatchers2,12 - class Satisfy #:nodoc:Satisfy4,35 - def initialize(&block)initialize5,62 - def matches?(actual, &block)matches?9,131 - def failure_message_for_shouldfailure_message_for_should15,268 - def failure_message_for_should_notfailure_message_for_should_not19,363 - def satisfy(&block)satisfy43,1051 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/simple_matcher.rb,513 -module SpecSpec1,0 - module MatchersMatchers2,12 - class SimpleMatcherSimpleMatcher3,30 - def initialize(description, &match_block)initialize6,137 - def matches?(given)matches?12,325 - def descriptiondescription22,541 - def failure_message_for_shouldfailure_message_for_should26,610 - def failure_message_for_should_notfailure_message_for_should_not30,784 - def explanationexplanation34,983 - def simple_matcher(description=nil, &match_block)simple_matcher129,4795 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/throw_symbol.rb,571 -module SpecSpec1,0 - module MatchersMatchers2,12 - class ThrowSymbol #:nodoc:ThrowSymbol4,31 - def initialize(expected_symbol = nil, expected_arg=nil)initialize5,62 - def matches?(given_proc)matches?11,258 - def failure_message_for_shouldfailure_message_for_should40,1250 - def failure_message_for_should_notfailure_message_for_should_not48,1469 - def descriptiondescription56,1679 - def expectedexpected62,1755 - def argsargs66,1873 - def throw_symbol(expected_symbol = nil, expected_arg=nil)throw_symbol96,2972 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers/wrap_expectation.rb,120 -module SpecSpec1,0 - module MatchersMatchers2,12 - def wrap_expectation(matcher, &block)wrap_expectation45,1475 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/matchers.rb,65 -module SpecSpec30,960 - module Matchers; endMatchers213,7067 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/argument_expectation.rb,488 -module SpecSpec1,0 - module MocksMocks2,12 - class ArgumentExpectationArgumentExpectation4,32 - def initialize(args, &block)initialize7,93 - def matcher_for(arg)matcher_for22,526 - def is_matcher?(obj)is_matcher?28,782 - def args_match?(given_args)args_match?32,900 - def matchers_block_matches?(given_args)matchers_block_matches?36,1045 - def matchers_match?(given_args)matchers_match?40,1174 - def match_any_args?match_any_args?44,1261 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/argument_matchers.rb,2251 -module SpecSpec1,0 - module MocksMocks2,12 - module ArgumentMatchersArgumentMatchers10,336 - class AnyArgsMatcherAnyArgsMatcher12,365 - def descriptiondescription13,392 - class NoArgsMatcherNoArgsMatcher18,460 - def descriptiondescription19,486 - class AnyArgMatcherAnyArgMatcher24,553 - def initialize(ignore)initialize25,579 - def ==(other)==28,623 - def descriptiondescription32,681 - class RegexpMatcherRegexpMatcher37,749 - def initialize(regexp)initialize38,775 - def ==(value)==42,846 - class BooleanMatcherBooleanMatcher48,979 - def initialize(ignore)initialize49,1006 - def ==(value)==52,1050 - class HashIncludingMatcherHashIncludingMatcher57,1149 - def initialize(expected)initialize58,1182 - def ==(actual)==62,1259 - def descriptiondescription71,1502 - class HashNotIncludingMatcherHashNotIncludingMatcher76,1632 - def initialize(expected)initialize77,1668 - def ==(actual)==81,1745 - def descriptiondescription90,1984 - class DuckTypeMatcherDuckTypeMatcher95,2118 - def initialize(*methods_to_respond_to)initialize96,2146 - def ==(value)==100,2263 - class MatcherMatcherMatcherMatcher105,2379 - def initialize(matcher)initialize106,2406 - def ==(value)==110,2480 - class EqualityProxyEqualityProxy115,2560 - def initialize(given)initialize116,2586 - def ==(expected)==120,2654 - class InstanceOfInstanceOf125,2737 - def initialize(klass)initialize126,2760 - def ==(actual)==130,2836 - class KindOfKindOf135,2926 - def initialize(klass)initialize136,2945 - def ==(actual)==140,3021 - def no_argsno_args149,3251 - def any_argsany_args158,3547 - def anythinganything166,3744 - def duck_type(*args)duck_type182,4241 - def booleanboolean190,4442 - def hash_including(*args)hash_including200,4914 - def hash_not_including(*args)hash_not_including210,5393 - def instance_of(klass)instance_of215,5556 - def kind_of(klass)kind_of222,5726 - def anythingize_lonely_keys(*args)anythingize_lonely_keys230,5860 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/error_generator.rb,1152 -module SpecSpec1,0 - module MocksMocks2,12 - class ErrorGeneratorErrorGenerator3,27 - def initialize(target, name, options={})initialize6,83 - def optsopts12,250 - def raise_unexpected_message_error(sym, *args)raise_unexpected_message_error16,297 - def raise_unexpected_message_args_error(expectation, *args)raise_unexpected_message_args_error20,451 - def raise_expectation_error(sym, expected_received_count, actual_received_count, *args)raise_expectation_error26,814 - def raise_out_of_order_error(sym)raise_out_of_order_error30,1089 - def raise_block_failed_error(sym, detail)raise_block_failed_error34,1203 - def raise_missing_block_error(args_to_yield)raise_missing_block_error38,1352 - def raise_wrong_arity_error(args_to_yield, arity)raise_wrong_arity_error42,1516 - def introintro48,1699 - def __raise(message)__raise62,2002 - def arg_message(*args)arg_message67,2172 - def format_args(*args)format_args71,2256 - def arg_list(*args)arg_list75,2360 - def count_message(count)count_message79,2505 - def pretty_print(count)pretty_print84,2648 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/errors.rb,189 -module SpecSpec1,0 - module MocksMocks2,12 - class MockExpectationError < ExceptionMockExpectationError3,27 - class AmbiguousReturnError < StandardErrorAmbiguousReturnError6,83 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/example_methods.rb,432 -module SpecSpec1,0 - module MocksMocks2,12 - module ExampleMethodsExampleMethods3,27 - def double(*args)double23,764 - def mock(*args)mock28,866 - def stub(*args)stub33,964 - def __declare_double(declared_as, *args) # :nodoc:__declare_double37,1037 - def stub_everything(name = 'stub')stub_everything48,1486 - def allow_message_expectations_on_nilallow_message_expectations_on_nil63,2089 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/extensions/object.rb,24 -class ObjectObject1,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/extensions.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/framework.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/message_expectation.rb,2929 -module SpecSpec1,0 - module MocksMocks2,12 - class BaseExpectationBaseExpectation4,28 - def initialize(error_generator, expectation_ordering, expected_from, sym, method_block, expected_received_count=1, opts={}, &implementation)initialize11,316 - def build_child(expected_from, method_block, expected_received_count, opts={})build_child33,1185 - def expected_argsexpected_args46,1667 - def and_return(*values, &return_block)and_return50,1733 - def and_raise(exception=Exception)and_raise75,2702 - def and_throw(symbol)and_throw79,2794 - def and_yield(*args, &block)and_yield83,2867 - def matches(sym, args)matches99,3290 - def invoke(*args, &block)invoke103,3390 - def called_max_times?called_max_times?137,4465 - def invoke_return_block(*args, &block)invoke_return_block142,4641 - def invoke_method_block(*args)invoke_method_block152,5010 - def invoke_with_yield(&block)invoke_with_yield160,5218 - def eval_block(*args, &block)eval_block174,5716 - def invoke_consecutive_return_block(*args, &block)invoke_consecutive_return_block182,5894 - def clone_args_to_yield(args)clone_args_to_yield188,6093 - def failed_fast?failed_fast?193,6218 - class MessageExpectation < BaseExpectationMessageExpectation198,6281 - def matches_name?(sym)matches_name?200,6329 - def matches_name_but_not_args(sym, args)matches_name_but_not_args204,6389 - def verify_messages_receivedverify_messages_received208,6518 - def expected_messages_received?expected_messages_received?217,6784 - def ignoring_args?ignoring_args?222,6944 - def matches_at_least_count?matches_at_least_count?226,7021 - def matches_at_most_count?matches_at_most_count?230,7138 - def matches_exact_count?matches_exact_count?234,7253 - def similar_messagessimilar_messages238,7354 - def advise(args, block)advise242,7425 - def generate_errorgenerate_error246,7499 - def with(*args, &block)with254,7816 - def exactly(n)exactly259,7936 - def at_least(n)at_least264,8029 - def at_most(n)at_most269,8124 - def times(&block)times274,8217 - def any_number_of_times(&block)any_number_of_times279,8304 - def nevernever285,8445 - def once(&block)once290,8522 - def twice(&block)twice296,8645 - def ordered(&block)ordered302,8769 - def negative_expectation_for?(sym)negative_expectation_for?309,8918 - def set_expected_received_count(relativity, n)set_expected_received_count314,9007 - def clear_actual_received_count!clear_actual_received_count!327,9347 - class NegativeMessageExpectation < MessageExpectationNegativeMessageExpectation333,9447 - def initialize(message, expectation_ordering, expected_from, sym, method_block)initialize334,9505 - def negative_expectation_for?(sym)negative_expectation_for?338,9684 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/methods.rb,687 -module SpecSpec1,0 - module MocksMocks2,12 - module MethodsMethods3,27 - def should_receive(sym, opts={}, &block)should_receive4,46 - def should_not_receive(sym, &block)should_not_receive8,213 - def stub!(sym_or_hash, opts={}, &block)stub!12,360 - def unstub!(message)unstub!22,671 - def stub_chain(*methods)stub_chain43,1479 - def as_null_objectas_null_object63,2116 - def null_object?null_object?67,2194 - def received_message?(sym, *args, &block) #:nodoc:received_message?71,2268 - def rspec_verify #:nodoc:rspec_verify75,2408 - def rspec_reset #:nodoc:rspec_reset79,2479 - def __mock_proxy__mock_proxy85,2561 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/mock.rb,504 -module SpecSpec1,0 - module MocksMocks2,12 - class MockMock3,27 - def initialize(name=nil, stubs_and_options={})initialize10,309 - def ==(other)==25,874 - def inspectinspect29,935 - def to_sto_s33,1048 - def method_missing(sym, *args, &block)method_missing39,1131 - def extract_options(stubs_and_options)extract_options49,1453 - def extract_option(source, target, key, default=nil)extract_option56,1692 - def assign_stubs(stubs)assign_stubs64,1894 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/order_group.rb,346 -module SpecSpec1,0 - module MocksMocks2,12 - class OrderGroupOrderGroup3,27 - def initialize error_generatorinitialize4,48 - def register(expectation)register9,175 - def ready_for?(expectation)ready_for?13,257 - def consumeconsume17,354 - def handle_order_constraint expectationhandle_order_constraint21,413 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/proxy.rb,2917 -module SpecSpec1,0 - module MocksMocks2,12 - class ProxyProxy3,27 - def self.allow_message_expectations_on_nilallow_message_expectations_on_nil10,168 - def initialize(target, name=nil, options={})initialize18,501 - def null_object?null_object?31,976 - def as_null_objectas_null_object35,1047 - def add_message_expectation(expected_from, sym, opts={}, &block) add_message_expectation40,1137 - def build_expectation(expected_from, sym, opts, &block)build_expectation47,1379 - def add_negative_message_expectation(expected_from, sym, &block)add_negative_message_expectation55,1736 - def add_stub(expected_from, sym, opts={}, &implementation)add_stub62,2038 - def remove_stub(message)remove_stub68,2294 - def verify #:nodoc:verify78,2660 - def resetreset84,2752 - def received_message?(sym, *args, &block)received_message?92,2925 - def has_negative_expectation?(sym)has_negative_expectation?96,3054 - def record_message_received(sym, args, block)record_message_received100,3198 - def message_received(sym, *args, &block)message_received104,3310 - def record_stub(stub, sym, args, &block)record_stub121,3989 - def invoke_expectation(expectation, *args, &block)invoke_expectation128,4181 - def record_almost_matching_expectation(expectation, sym, *args, &block)record_almost_matching_expectation132,4291 - def ok_to_invoke_stub?(stub, expectation)ok_to_invoke_stub?139,4562 - def raise_unexpected_message_args_error(expectation, *args)raise_unexpected_message_args_error143,4685 - def raise_unexpected_message_error(sym, *args)raise_unexpected_message_error147,4842 - def find_matching_method_stub(sym, *args)find_matching_method_stub151,4979 - def __add(sym)__add157,5110 - def warn_if_nil_class(sym)warn_if_nil_class162,5243 - def define_expected_method(sym)define_expected_method168,5534 - def target_responds_to?(sym)target_responds_to?187,6187 - def visibility(sym)visibility193,6440 - def munge(sym)munge205,6732 - def clear_expectationsclear_expectations209,6799 - def clear_stubsclear_stubs213,6867 - def clear_proxied_methodsclear_proxied_methods217,6921 - def target_metaclasstarget_metaclass221,6995 - def verify_expectationsverify_expectations225,7069 - def reset_proxied_methodsreset_proxied_methods229,7169 - def reset_proxied_method(sym)reset_proxied_method233,7275 - def proxy_for_nil_class?proxy_for_nil_class?244,7575 - def reset_nil_expectations_warningreset_nil_expectations_warning248,7644 - def find_matching_expectation(sym, *args)find_matching_expectation252,7768 - def almost_matching_expectation(sym, *args, &block)almost_matching_expectation257,8013 - def find_almost_matching_expectation(sym, *args)find_almost_matching_expectation263,8172 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks/space.rb,206 -module SpecSpec1,0 - module MocksMocks2,12 - class SpaceSpace3,27 - def add(obj)add4,43 - def verify_allverify_all8,133 - def reset_allreset_all14,240 - def mocksmocks23,382 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/mocks.rb,52 -module SpecSpec4,71 - module MocksMocks198,9045 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/rake/spectask.rb,492 -module SpecSpec8,113 - module RakeRake9,125 - class SpecTask < ::Rake::TaskLibSpecTask57,1883 - def self.attr_accessor(*names)attr_accessor58,1920 - def initialize(name=:spec)initialize126,4596 - def define # :nodoc:define144,5089 - def rcov_option_list # :nodoc:rcov_option_list197,7137 - def spec_option_list # :nodoc:spec_option_list205,7295 - def evaluate(o) # :nodoc:evaluate210,7547 - def spec_file_list # :nodoc:spec_file_list217,7666 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/rake/verify_rcov.rb,159 -module RCovRCov1,0 - class VerifyTask < Rake::TaskLibVerifyTask5,163 - def initialize(name=:verify_rcov)initialize25,856 - def definedefine35,1129 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/ruby.rb,76 -module SpecSpec1,0 - module RubyRuby2,12 - def versionversion4,44 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/backtrace_tweaker.rb,708 -module SpecSpec1,0 - module RunnerRunner2,12 - class BacktraceTweakerBacktraceTweaker3,28 - def initialize(*patterns)initialize4,55 - def clean_up_double_slashes(line)clean_up_double_slashes8,128 - def ignore_patterns(*patterns)ignore_patterns12,208 - def ignored_patternsignored_patterns16,323 - def tweak_backtrace(error)tweak_backtrace20,372 - class NoisyBacktraceTweaker < BacktraceTweakerNoisyBacktraceTweaker35,862 - class QuietBacktraceTweaker < BacktraceTweakerQuietBacktraceTweaker39,1001 - def initialize(*patterns)initialize64,1842 - def ignore_patterns(*patterns)ignore_patterns69,1934 - def ignored_patternsignored_patterns73,2065 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/class_and_arguments_parser.rb,147 -module SpecSpec1,0 - module RunnerRunner2,12 - class ClassAndArgumentsParserClassAndArgumentsParser3,28 - def self.parse(s)parse4,62 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/command_line.rb,151 -module SpecSpec3,37 - module RunnerRunner4,49 - class CommandLineCommandLine5,65 - def self.run(tmp_options=Spec::Runner.options)run6,87 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/configuration.rb,1433 -module SpecSpec1,0 - module RunnerRunner2,12 - class ConfigurationConfiguration3,28 - def mock_with(mock_framework)mock_with33,1164 - def mock_framework # :nodoc:mock_framework42,1384 - def include(*modules_and_options)include79,2921 - def extend(*modules_and_options)extend90,3305 - def append_before(scope = :each, options={}, &proc)append_before100,3859 - def prepend_before(scope = :each, options={}, &proc)prepend_before108,4169 - def prepend_after(scope = :each, options={}, &proc)prepend_after115,4443 - def append_after(scope = :each, options={}, &proc)append_after123,4756 - def predicate_matcherspredicate_matchers137,5194 - def ignore_backtrace_patterns(*patterns)ignore_backtrace_patterns149,5718 - def ignored_backtrace_patterns # :nodoc:ignored_backtrace_patterns154,5867 - def suppress_deprecation_warnings!suppress_deprecation_warnings!158,5968 - def suppress_deprecation_warnings?suppress_deprecation_warnings?162,6066 - def include_or_extend(action, *args)include_or_extend168,6190 - def add_callback(sym, *args, &proc)add_callback178,6619 - def get_type_from_options(options)get_type_from_options184,6863 - def mock_framework_path(framework_name)mock_framework_path188,6970 - def scope_and_options(*args) # :nodoc:scope_and_options192,7085 - def scope_from(*args) # :nodoc:scope_from197,7231 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/differs/default.rb,473 -module SpecSpec4,58 - module ExpectationsExpectations5,70 - module DiffersDiffers6,92 - class DefaultDefault8,171 - def initialize(options)initialize9,193 - def diff_as_string(data_new, data_old)diff_as_string14,354 - def diff_as_object(target,expected)diff_as_object45,1671 - def diff_as_hash(target, expected)diff_as_hash49,1807 - def formatformat81,3054 - def context_linescontext_lines85,3123 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/differs/load-diff-lcs.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/drb_command_line.rb,175 -module SpecSpec3,19 - module RunnerRunner4,31 - class DrbCommandLineDrbCommandLine6,103 - def self.port(options)port8,129 - def self.run(options)run14,388 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/example_group_runner.rb,455 -module SpecSpec1,0 - module RunnerRunner2,12 - class ExampleGroupRunnerExampleGroupRunner3,28 - def initialize(options)initialize4,57 - def load_files(files)load_files8,125 - def runrun19,552 - def prepareprepare31,779 - def finishfinish36,894 - def reporterreporter41,965 - def reversereverse45,1021 - def example_groupsexample_groups49,1075 - def number_of_examplesnumber_of_examples53,1143 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/extensions/kernel.rb,66 -module KernelKernel1,0 - def debugger(steps=1)debugger4,132 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/base_formatter.rb,1014 -module SpecSpec1,0 - module RunnerRunner2,12 - module FormatterFormatter3,28 - class BaseFormatterBaseFormatter5,147 - def initialize(options, output)initialize26,1024 - def start(example_count)start38,1537 - def example_group_started(example_group_proxy)example_group_started47,1867 - def add_example_group(example_group_proxy)add_example_group51,2000 - def example_started(example_proxy)example_started62,2495 - def example_passed(example_proxy)example_passed71,2835 - def example_failed(example_proxy, counter, failure)example_failed85,3362 - def example_pending(example_proxy, message, deprecated_pending_location=nil)example_pending100,4054 - def start_dumpstart_dump105,4329 - def dump_failure(counter, failure)dump_failure116,4838 - def dump_summary(duration, example_count, failure_count, pending_count)dump_summary126,5248 - def dump_pendingdump_pending130,5395 - def closeclose134,5544 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/base_text_formatter.rb,1482 -module SpecSpec4,68 - module RunnerRunner5,80 - module FormatterFormatter6,96 - class BaseTextFormatter < BaseFormatterBaseTextFormatter10,275 - def initialize(options, output)initialize16,625 - def example_group_started(example_group_proxy)example_group_started27,926 - def example_pending(example, message, deprecated_pending_location=nil)example_pending31,1049 - def dump_failure(counter, failure)dump_failure35,1264 - def colorize_failure(message, failure)colorize_failure43,1586 - def colourise(message, failure)colourise47,1718 - def dump_summary(duration, example_count, failure_count, pending_count)dump_summary52,1901 - def dump_pendingdump_pending73,2612 - def closeclose85,3001 - def format_backtrace(backtrace)format_backtrace89,3108 - def colour?colour?96,3289 - def dry_run?dry_run?100,3350 - def autospec?autospec?104,3421 - def backtrace_line(line)backtrace_line108,3522 - def colour(text, colour_code)colour112,3613 - def output_to_file?output_to_file?118,3838 - def output_to_tty?output_to_tty?122,3914 - def green(text); colour(text, "\e[32m"); endgreen130,4066 - def red(text); colour(text, "\e[31m"); endred131,4119 - def yellow(text); colour(text, "\e[33m"); endyellow132,4170 - def blue(text); colour(text, "\e[34m"); endblue133,4224 - def magenta(text)magenta135,4285 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/failing_example_groups_formatter.rb,422 -module SpecSpec3,53 - module RunnerRunner4,65 - module FormatterFormatter5,81 - class FailingExampleGroupsFormatter < BaseTextFormatterFailingExampleGroupsFormatter6,102 - def example_failed(example, counter, failure)example_failed7,164 - def dump_failure(counter, failure)dump_failure16,417 - def dump_summary(duration, example_count, failure_count, pending_count)dump_summary19,473 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/failing_examples_formatter.rb,418 -module SpecSpec3,53 - module RunnerRunner4,65 - module FormatterFormatter5,81 - class FailingExamplesFormatter < BaseTextFormatter FailingExamplesFormatter6,102 - def example_failed(example, counter, failure)example_failed7,165 - def dump_failure(counter, failure)dump_failure12,333 - def dump_summary(duration, example_count, failure_count, pending_count)dump_summary15,389 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/html_formatter.rb,1320 -module SpecSpec5,120 - module RunnerRunner6,132 - module FormatterFormatter7,148 - class HtmlFormatter < BaseTextFormatterHtmlFormatter8,169 - def initialize(options, output)initialize12,304 - def example_group_numberexample_group_number20,535 - def example_numberexample_number25,694 - def start(example_count)start29,768 - def example_group_started(example_group)example_group_started37,952 - def start_dumpstart_dump51,1454 - def example_started(example)example_started57,1579 - def example_passed(example)example_passed61,1660 - def example_failed(example, counter, failure)example_failed67,1883 - def example_pending(example, message, deprecated_pending_location=nil)example_pending86,3106 - def extra_failure_content(failure)extra_failure_content97,3874 - def move_progressmove_progress103,4156 - def percent_donepercent_done108,4326 - def dump_failure(counter, failure)dump_failure116,4539 - def dump_summary(duration, example_count, failure_count, pending_count)dump_summary119,4595 - def html_header html_header135,5444 - def report_headerreport_header168,6214 - def global_scriptsglobal_scripts187,6510 - def global_stylesglobal_styles212,7294 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/nested_text_formatter.rb,596 -module SpecSpec3,53 - module RunnerRunner4,65 - module FormatterFormatter5,81 - class NestedTextFormatter < BaseTextFormatterNestedTextFormatter6,102 - def initialize(options, where)initialize10,178 - def example_group_started(example_group)example_group_started15,287 - def example_failed(example, counter, failure)example_failed27,711 - def example_passed(example)example_passed32,898 - def example_pending(example, message, deprecated_pending_location=nil)example_pending38,1074 - def current_indentationcurrent_indentation44,1304 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/no_op_method_missing.rb,275 -module SpecSpec1,0 - module RunnerRunner2,12 - module FormatterFormatter3,28 - module NOOPMethodMissingNOOPMethodMissing4,49 - def respond_to?(message, include_private = false)respond_to?5,80 - def method_missing(sym, *args)method_missing15,332 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/profile_formatter.rb,414 -module SpecSpec3,56 - module RunnerRunner4,68 - module FormatterFormatter5,84 - class ProfileFormatter < ProgressBarFormatterProfileFormatter6,105 - def initialize(options, where)initialize8,166 - def start(count)start13,272 - def example_started(example)example_started17,362 - def example_passed(example)example_passed21,447 - def start_dumpstart_dump30,663 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/progress_bar_formatter.rb,446 -module SpecSpec4,106 - module RunnerRunner5,118 - module FormatterFormatter6,134 - class ProgressBarFormatter < BaseTextFormatterProgressBarFormatter7,155 - def example_failed(example, counter, failure)example_failed10,243 - def example_passed(example)example_passed15,389 - def example_pending(example, message, deprecated_pending_location=nil)example_pending20,503 - def start_dumpstart_dump26,679 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/silent_formatter.rb,151 -module SpecSpec3,48 - module RunnerRunner4,60 - module FormatterFormatter5,76 - class SilentFormatter < BaseFormatterSilentFormatter6,97 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/snippet_extractor.rb,472 -module SpecSpec1,0 - module RunnerRunner2,12 - module FormatterFormatter3,28 - class SnippetExtractor #:nodoc:SnippetExtractor5,139 - class NullConverter; def convert(code, pre); code; end; end #:nodoc:NullConverter6,177 - def snippet(error)snippet9,430 - def snippet_for(error_line)snippet_for16,784 - def lines_around(file, line)lines_around26,1064 - def post_process(highlighted, offending_line)post_process39,1473 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/specdoc_formatter.rb,471 -module SpecSpec3,53 - module RunnerRunner4,65 - module FormatterFormatter5,81 - class SpecdocFormatter < BaseTextFormatterSpecdocFormatter6,102 - def example_group_started(example_group)example_group_started7,151 - def example_failed(example, counter, failure)example_failed14,328 - def example_passed(example)example_passed19,503 - def example_pending(example, message, deprecated_pending_location=nil)example_pending25,667 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/formatter/text_mate_formatter.rb,210 -module SpecSpec3,48 - module RunnerRunner4,60 - module FormatterFormatter5,76 - class TextMateFormatter < HtmlFormatterTextMateFormatter7,157 - def backtrace_line(line)backtrace_line8,203 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/heckle_runner.rb,604 - module SpecSpec7,191 - module RunnerRunner8,205 - class HeckleRunnerHeckleRunner11,337 - def initialize(filter, heckle_class=Heckler)initialize12,362 - def heckle_withheckle_with19,625 - def heckle_method(class_name, method_name)heckle_method27,815 - def heckle_class_or_module(class_or_module_name)heckle_class_or_module33,1033 - def verify_constant(name)verify_constant49,1602 - class Heckler < HeckleHeckler59,1857 - def initialize(klass_name, method_name, rspec_options)initialize60,1886 - def tests_pass?tests_pass?65,2044 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/heckle_runner_unsupported.rb,137 -module SpecSpec1,0 - module RunnerRunner2,12 - class HeckleRunnerHeckleRunner4,120 - def initialize(filter)initialize5,143 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/line_number_query.rb,766 -module SpecSpec1,0 - module RunnerRunner2,12 - class LineNumberQueryLineNumberQuery4,108 - def initialize(run_options)initialize7,165 - def spec_name_for(file, line_number)spec_name_for12,270 - def example_line_for(file, line_number)example_line_for27,718 - def determine_best_match(file, line_number)determine_best_match34,872 - def consider_example_group_for_best_match(example_group, file, line_number)consider_example_group_for_best_match47,1348 - def consider_example_for_best_match(example, example_group, file, line_number)consider_example_for_best_match56,1755 - def is_best_match?(file, line_number, example_file, example_line)is_best_match?66,2170 - def parse_location(location)parse_location72,2410 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/option_parser.rb,745 -module SpecSpec4,39 - module RunnerRunner5,51 - class OptionParser < ::OptionParserOptionParser6,67 - def parse(args, err, out)parse8,127 - def spec_command?spec_command?14,261 - def initialize(err, out)initialize88,6998 - def order!(argv, &blk)order!123,8994 - def invoke_requires(requires)invoke_requires149,9635 - def parse_file_options(option_name, action)parse_file_options155,9760 - def parse_options_file(options_file)parse_options_file181,10520 - def write_options_file(options_file)write_options_file186,10704 - def parse_drbparse_drb195,11053 - def parse_versionparse_version210,11507 - def parse_helpparse_help215,11616 - def stdout?stdout?220,11702 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/options.rb,2495 -module SpecSpec4,38 - module RunnerRunner5,50 - class OptionsOptions6,66 - def initialize(error_stream, output_stream)initialize56,2952 - def add_example_group(example_group)add_example_group80,3668 - def line_number_requested?line_number_requested?84,3763 - def example_lineexample_line88,3829 - def remove_example_group(example_group)remove_example_group92,3954 - def require_ruby_debugrequire_ruby_debug96,4057 - def project_root # :nodoc:project_root101,4179 - def determine_project_root # :nodoc:determine_project_root106,4299 - def add_dir_from_project_root_to_load_path(dir, load_path=$LOAD_PATH) # :nodoc:add_dir_from_project_root_to_load_path117,4668 - def run_examplesrun_examples123,4920 - def before_suite_partsbefore_suite_parts165,6291 - def after_suite_partsafter_suite_parts169,6393 - def examples_run?examples_run?173,6493 - def examples_should_not_be_runexamples_should_not_be_run177,6550 - def mock_frameworkmock_framework181,6638 - def colour=(colour)colour=186,6806 - def parse_diff(format)parse_diff201,7350 - def parse_example(example)parse_example215,7743 - def parse_format(format_arg)parse_format223,7944 - def formattersformatters234,8329 - def load_formatters(format_options, formatters)load_formatters239,8497 - def formatter_optionsformatter_options251,8920 - def which_heckle_runnerwhich_heckle_runner259,9111 - def load_heckle_runner(heckle)load_heckle_runner263,9317 - def number_of_examplesnumber_of_examples269,9524 - def files_to_loadfiles_to_load274,9696 - def dry_run?dry_run?290,10143 - def drb_portdrb_port294,10198 - def define_predicate_matchersdefine_predicate_matchers300,10295 - def plugin_mock_frameworkplugin_mock_framework308,10630 - def ignore_backtrace_patternsignore_backtrace_patterns318,10942 - def examples_should_be_run?examples_should_be_run?322,11086 - def differ_class=(klass)differ_class=327,11245 - def load_class(name, kind, option)load_class333,11409 - def custom_runnercustom_runner351,12030 - def custom_runner?custom_runner?358,12308 - def heckleheckle362,12396 - def sorted_filessorted_files368,12534 - def sortersorter372,12620 - def default_differdefault_differ376,12677 - def set_spec_from_line_numberset_spec_from_line_number381,12826 - def stderr?stderr?401,13572 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner/reporter.rb,1320 -module SpecSpec1,0 - module RunnerRunner2,12 - class ReporterReporter3,28 - def initialize(options)initialize6,81 - def example_group_started(example_group)example_group_started16,315 - def example_started(example)example_started23,510 - def example_finished(example, error=nil)example_finished27,618 - def example_failed(example, error)example_failed39,962 - def start(number_of_examples)start48,1284 - def endend53,1421 - def dumpdump58,1544 - class FailureFailure69,1826 - def initialize(group_description, example_description, exception) # :nodoc:initialize70,1846 - def headerheader89,2714 - def pending_fixed? # :nodoc:pending_fixed?99,2988 - def expectation_not_met? # :nodoc:expectation_not_met?103,3106 - def formattersformatters110,3257 - def backtrace_tweakerbacktrace_tweaker114,3317 - def dump_failuresdump_failures118,3393 - def dump_pendingdump_pending126,3605 - def durationduration130,3683 - def example_passed(example)example_passed135,3823 - def example_pending(example, ignore, message="Not Yet Implemented")example_pending153,4557 - def formatter_uses_deprecated_example_pending_method?(formatter)formatter_uses_deprecated_example_pending_method?165,5018 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/runner.rb,440 -module SpecSpec13,420 - module RunnerRunner14,432 - class ExampleGroupCreationListenerExampleGroupCreationListener16,453 - def register_example_group(klass)register_example_group17,492 - def configuration # :nodoc:configuration25,739 - def configureconfigure40,1210 - def autorun # :nodoc:autorun44,1275 - def options # :nodoc:options48,1351 - def use optionsuse56,1558 - def runrun60,1618 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/stubs/cucumber.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/test/unit.rb,75 -module SpecSpec5,144 - module TestTest6,156 - module UnitUnit7,170 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec/version.rb,71 -module Spec # :nodoc:Spec1,0 - module VERSION # :nodoc:VERSION2,22 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/lib/spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/resources/helpers/cmdline.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/autotest_helper.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/autotest_matchers.rb,365 -module SpecSpec1,0 - module MatchersMatchers2,12 - class AutotestMappingMatcherAutotestMappingMatcher3,30 - def initialize(specs)initialize4,63 - def to(file)to8,127 - def matches?(autotest)matches?13,193 - def failure_messagefailure_message19,348 - def prepare(autotest)prepare25,507 - def map_specs(specs)map_specs33,677 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/discover_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/failed_results_re_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/autotest/rspec_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/ruby_forker.rb,74 -module RubyForkerRubyForker3,20 - def ruby(args, stderr=nil)ruby6,145 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/dsl/main_spec.rb,266 -module SpecSpec3,23 - module DSLDSL4,35 - module Foo; module Bar; end; endFoo45,1591 - module FooFoo52,1834 - module BarBar53,1855 - def self.next_group_namenext_group_name61,2014 - def group_namegroup_name67,2161 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_class_definition_spec.rb,159 -module SpecSpec3,23 - module ExampleExample4,35 - class ExampleGroupSubclass < ExampleGroupExampleGroupSubclass5,52 - def a_methoda_method21,393 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_factory_spec.rb,178 -module SpecSpec3,23 - module ExampleExample4,35 - def initialize(*args, &block)initialize40,1343 - def shared_example_groupshared_example_group132,5816 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_methods_spec.rb,1398 -module SpecSpec3,23 - module ExampleExample4,35 - def test_any_args(*args)test_any_args164,6322 - def test_somethingtest_something167,6415 - def testtest170,6496 - def testifytestify173,6585 - def should_somethingshould_something176,6677 - def shouldCamelCaseshouldCamelCase187,7071 - def should_any_args(*args)should_any_args190,7159 - def should_somethingshould_something193,7254 - def should_not_somethingshould_not_something196,7337 - def shouldshould199,7428 - def should_notshould_not202,7522 - def test_invalid(foo)test_invalid221,8226 - def testInvalidCamelCase(foo)testInvalidCamelCase224,8310 - def should_invalid(foo)should_invalid233,8645 - def shouldInvalidCamelCase(foo)shouldInvalidCamelCase236,8731 - def should_not_invalid(foo)should_not_invalid239,8825 - def should_validshould_valid242,8915 - def should_validshould_valid252,9234 - def self.specified_examplesspecified_examples576,21084 - def self.to_sto_s579,21174 - def initializeinitialize738,26883 - def countcount741,26957 - class CreatorCreator759,27366 - def self.countcount761,27417 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_proxy_spec.rb,81 -module SpecSpec3,23 - module ExampleExample4,35 - def proxyproxy11,232 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_group_spec.rb,340 -module SpecSpec3,23 - module ExampleExample4,35 - class ExampleModuleScopingSpec < ExampleGroupExampleModuleScopingSpec5,52 - module FooFoo8,157 - module BarBar9,174 - def self.loaded?; true; endloaded10,193 - class ExampleClassVariablePollutionSpec < ExampleGroupExampleClassVariablePollutionSpec27,549 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_matcher_spec.rb,52 -module SpecSpec3,23 - module ExampleExample4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_methods_spec.rb,446 -class ThingThing3,23 - def initialize(arg=nil)initialize5,54 - def ==(other)==8,113 - def eql?(other)eql?11,157 -module SpecSpec16,208 - module ExampleExample17,220 - module ModuleThatIsReopened; endModuleThatIsReopened19,268 - module Spec::Example::ExampleMethodsSpec21,308 - module ModuleThatIsReopenedModuleThatIsReopened25,399 - def module_that_is_reopened_method; endmodule_that_is_reopened_method26,433 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/example_proxy_spec.rb,52 -module SpecSpec3,23 - module ExampleExample4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/helper_method_spec.rb,95 -module HelperMethodExampleHelperMethodExample6,138 - def helper_methodhelper_method8,197 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/nested_example_group_spec.rb,80 -module SpecSpec3,23 - module ExampleExample4,35 - def countcount8,119 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/pending_module_spec.rb,51 -module SpecSpec1,0 - module ExampleExample2,12 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/predicate_matcher_spec.rb,131 -module SpecSpec3,23 - module ExampleExample4,35 - class FishFish5,52 - def can_swim?(distance_in_yards)can_swim?6,67 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/shared_example_group_spec.rb,123 -module SpecSpec3,23 - module ExampleExample4,35 - def a_shared_helper_methoda_shared_helper_method234,8656 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/subclassing_example_group_spec.rb,299 -module SpecSpec3,23 - module ExampleExample4,35 - class GrandParentExampleGroup < Spec::Example::ExampleGroupGrandParentExampleGroup5,52 - class ParentExampleGroup < GrandParentExampleGroupParentExampleGroup9,167 - class ChildExampleGroup < ParentExampleGroupChildExampleGroup15,303 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/example/subject_spec.rb,166 -module SpecSpec3,23 - module ExampleExample4,35 - def described_classdescribed_class56,1729 - def described_classdescribed_class60,1819 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/differs/default_spec.rb,167 -module SpecSpec3,23 - module FixturesFixtures4,35 - class AnimalAnimal5,53 - def initialize(name,species)initialize6,70 - def inspectinspect10,154 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/extensions/kernel_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/fail_with_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/handler_spec.rb,614 -module ExampleExpectationsExampleExpectations3,23 - class ArbitraryMatcherArbitraryMatcher5,53 - def initialize(*args, &block)initialize6,78 - def matches?(target)matches?14,265 - def with(new_value)with19,359 - def failure_messagefailure_message24,435 - def negative_failure_messagenegative_failure_message28,518 - class PositiveOnlyMatcher < ArbitraryMatcherPositiveOnlyMatcher33,618 - def arbitrary_matcher(*args, &block)arbitrary_matcher37,720 - def positive_only_matcher(*args, &block)positive_only_matcher41,808 -module SpecSpec47,908 - module ExpectationsExpectations48,920 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/expectations/wrap_expectation_spec.rb,145 -module SpecSpec3,23 - module MatchersMatchers4,35 - def stub_matcherstub_matcher8,134 - def failing_matcherfailing_matcher13,231 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_that_fails.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_that_passes.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_with_errors.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/spec_with_options_hash.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_that_fails.rb,115 -class TestCaseThatFails < Test::Unit::TestCaseTestCaseThatFails6,162 - def test_that_failstest_that_fails7,209 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_that_passes.rb,119 -class TestCaseThatPasses < Test::Unit::TestCaseTestCaseThatPasses6,162 - def test_that_passestest_that_passes7,210 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_with_errors.rb,117 -class TestCaseWithErrors < Test::Unit::TestCaseTestCaseWithErrors6,162 - def test_with_errortest_with_error7,210 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/test_case_with_various_names.rb,293 -class TestCaseThatPasses < Test::Unit::TestCaseTestCaseThatPasses6,162 - def test_should_allow_underscoretest_should_allow_underscore7,210 - def testShouldAllowUppercaseLettertestShouldAllowUppercaseLetter11,268 - def testshouldallowlowercaselettertestshouldallowlowercaseletter15,328 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/resources/testsuite_adapter_spec_with_test_unit.rb,101 -module TestTest6,162 - module UnitUnit7,174 - def create_adapter(group)create_adapter9,221 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/spec_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/test_unit_spec_helper.rb,127 -module TestUnitSpecHelperTestUnitSpecHelper4,45 - def resourcesresources7,93 - def run_script(file_name)run_script11,160 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/testcase_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/interop/test/unit/testsuite_adapter_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_close_spec.rb,54 -module SpecSpec2,22 - module MatchersMatchers3,34 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_instance_of_spec.rb,54 -module SpecSpec3,23 - module MatchersMatchers4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_kind_of_spec.rb,54 -module SpecSpec3,23 - module MatchersMatchers4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/be_spec.rb,154 - class ArrayDelegate < DelegateClass(Array)ArrayDelegate424,12478 - def initialize(array)initialize425,12525 - def large?large?430,12627 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/change_spec.rb,47 -class SomethingExpectedSomethingExpected4,61 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/compatibility_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/description_generation_spec.rb,209 - def teamteam139,4219 - def playersplayers141,4247 - def matchermatcher149,4358 - def matches?(ignore); true; endmatches?151,4390 - def failure_message; ""; endfailure_message152,4429 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/dsl_spec.rb,78 -module SpecSpec3,23 - module MatchersMatchers4,35 - module DSLDSL5,53 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/eql_spec.rb,54 -module SpecSpec3,23 - module MatchersMatchers4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/equal_spec.rb,102 -module SpecSpec2,22 - module MatchersMatchers3,34 - def inspect_object(o)inspect_object6,83 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/exist_spec.rb,277 -class SubstanceSubstance3,23 - def initialize exists, descriptioninitialize4,39 - def exist?(arg=nil)exist?8,134 - def inspectinspect11,174 -class SubstanceTesterSubstanceTester16,218 - def initialize substanceinitialize18,265 - def should_existshould_exist21,325 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/has_spec.rb,248 - def has_foo?has_foo?16,426 - def o.has_sym?(*args)has_sym32,836 - def has_foo?has_foo?46,1211 - def o.has_sym?(*args)has_sym66,1726 - def o.send(*args); raise "DOH! Library developers shouldn't use #send!" endsend185,6094 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/have_spec.rb,323 - def create_collection_owner_with(n)create_collection_owner_with5,51 - class InflectorInflector20,498 - def self.pluralize(string)pluralize21,522 - def self.pluralize(string)pluralize83,2683 - def itemsitems105,3253 - module SpecSpec344,12702 - module MatchersMatchers345,12716 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/include_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/match_array_spec.rb,189 -class UnsortableObjectUnsortableObject3,23 - def initialize(id)initialize4,46 - def inspectinspect8,87 - def ==(other)==12,121 - class SuperArray < Array; endSuperArray103,2672 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/match_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/matcher_spec.rb,270 -class UnexpectedError < StandardError; endUnexpectedError3,23 -module SpecSpec5,67 - module MatchersMatchers6,79 - def similar?(a, b)similar?198,5809 - def second_wordsecond_word208,6056 - def assert_equal(a,b)assert_equal236,6836 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/matchers_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/operator_matcher_spec.rb,188 - def o.send(*args); raise "DOH! Library developers shouldn't use #send!" endsend173,4385 - def o.send(*args); raise "DOH! Library developers shouldn't use #send!" endsend185,4671 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/raise_exception_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/respond_to_spec.rb,225 - def obj.foo(arg); endfoo20,499 - def obj.foo; endfoo33,861 - def obj.foo(arg, arg2); endfoo41,1097 - def obj.foo(a1, a2); endfoo76,2263 - def obj.foo; endfoo89,2630 - def obj.foo(arg); endfoo97,2868 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/satisfy_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/simple_matcher_spec.rb,54 -module SpecSpec3,23 - module MatchersMatchers4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/matchers/throw_symbol_spec.rb,54 -module SpecSpec3,23 - module MatchersMatchers4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/and_yield_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/any_number_of_times_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/argument_expectation_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/argument_matchers_spec.rb,98 -module SpecSpec3,23 - module MocksMocks4,35 - module ArgumentMatchersArgumentMatchers5,50 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/at_least_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/at_most_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_10260_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_10263_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_11545_spec.rb,176 -class LiarLiarPantsOnFireLiarLiarPantsOnFire3,23 - def respond_to?(sym, incl_private=false)respond_to?4,49 - def self.respond_to?(sym, incl_private=false)respond_to8,110 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_15719_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_496_spec.rb,114 -module BugReport496BugReport4963,23 - class BaseClassBaseClass4,43 - class SubClass < BaseClassSubClass7,68 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_600_spec.rb,157 -module BugReport600BugReport6003,23 - class ExampleClassExampleClass4,43 - def self.method_that_uses_define_methodmethod_that_uses_define_method5,64 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_7611_spec.rb,76 -module Bug7611Bug76113,23 - class FooFoo4,38 - class Bar < FooBar7,57 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_7805_spec.rb,28 -module Bug7805Bug78053,23 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_8165_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_8302_spec.rb,141 -module Bug8302Bug83023,23 - class FooFoo4,38 - def Foo.class_method(arg)class_method5,50 - def instance_bar(arg)instance_bar8,91 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/bug_report_830_spec.rb,105 -module SpecSpec3,23 - module MocksMocks4,35 - class FooFoo6,112 - def self.foofoo7,128 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/double_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/failing_argument_matchers_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/hash_including_matcher_spec.rb,98 -module SpecSpec3,23 - module MocksMocks4,35 - module ArgumentMatchersArgumentMatchers5,50 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/hash_not_including_matcher_spec.rb,98 -module SpecSpec3,23 - module MocksMocks4,35 - module ArgumentMatchersArgumentMatchers5,50 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/mock_ordering_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/mock_space_spec.rb,216 -module SpecSpec4,44 - module MocksMocks5,56 - def rspec_verifyrspec_verify10,171 - def verified?verified?13,241 - def rspec_resetrspec_reset16,301 - def reset?reset?19,367 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/mock_spec.rb,86 -module SpecSpec3,23 - module MocksMocks4,35 - def add_calladd_call498,19498 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/multiple_return_value_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/nil_expectation_warning_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/null_object_mock_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/once_counts_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/options_hash_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/partial_mock_spec.rb,407 -module SpecSpec3,23 - module MocksMocks4,35 - class PartiallyMockedEqualsPartiallyMockedEquals96,3332 - def initialize(val)initialize98,3391 - def ==(other)==102,3461 - class MockableClassMockableClass114,3799 - def public_methodpublic_method115,3825 - def protected_method; endprotected_method120,3933 - def private_method; endprivate_method122,3983 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/partial_mock_using_mocks_directly_spec.rb,99 -module SpecSpec3,23 -module MocksMocks4,35 - def existing_methodexisting_method10,172 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/passing_argument_matchers_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/precise_counts_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/record_messages_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stub_chain_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stub_implementation_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stub_spec.rb,188 -module SpecSpec3,23 - module MocksMocks4,35 - def self.existing_class_methodexisting_class_method8,135 - def existing_instance_methodexisting_instance_method12,219 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/stubbed_message_expectations_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/twice_counts_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/mocks/unstub_spec.rb,48 -module SpecSpec3,23 - module MocksMocks4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/package/bin_spec_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/rake/spectask_spec.rb,538 -module SpecSpec4,52 - module RakeRake5,64 - class MockTaskMockTask7,79 - def self.taskstasks12,177 - def self.reset_tasksreset_tasks16,237 - def self.task(name)task20,301 - def self.register_task(name, block)register_task24,364 - def initialize(name, &block)initialize28,445 - def self.create_task(name, &block)create_task33,580 - class SpecTaskSpecTask38,666 - def task(name, &block)task39,685 - def system(cmd)system43,768 - def default_ruby_pathdefault_ruby_path48,846 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/class_and_argument_parser_spec.rb,50 -module SpecSpec3,23 - module RunnerRunner4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/command_line_spec.rb,50 -module SpecSpec3,23 - module RunnerRunner4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/configuration_spec.rb,50 -module SpecSpec3,23 - module RunnerRunner4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/drb_command_line_spec.rb,362 -module SpecSpec3,23 - module RunnerRunner4,35 - def self.run(argv, stderr, stdout)run26,693 - def create_dummy_spec_filecreate_dummy_spec_file75,2317 - def run_spec_via_druby(argv)run_spec_via_druby92,2963 - def tty?; true endtty?95,3085 - def with_RSPEC_DRB_set_to(val)with_RSPEC_DRB_set_to116,3739 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/example_group_runner_spec.rb,50 -module SpecSpec3,23 - module RunnerRunner4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/base_formatter_spec.rb,86 -module SpecSpec3,23 - module RunnerRunner4,35 - module FormatterFormatter5,51 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/base_text_formatter_spec.rb,272 -module SpecSpec4,75 - module RunnerRunner5,87 - module FormatterFormatter6,103 - def method_that_class_magenta(message)method_that_class_magenta28,879 - def method_that_class_colourise(message, failure)method_that_class_colourise31,983 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/failing_example_groups_formatter_spec.rb,88 -module SpecSpec4,88 - module RunnerRunner5,100 - module FormatterFormatter6,116 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/failing_examples_formatter_spec.rb,87 -module SpecSpec4,82 - module RunnerRunner5,94 - module FormatterFormatter6,110 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/html_formatter_spec.rb,90 -module SpecSpec8,185 - module RunnerRunner9,197 - module FormatterFormatter10,213 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/nested_text_formatter_spec.rb,820 -module SpecSpec4,77 - module RunnerRunner5,89 - module FormatterFormatter6,105 - def example_group_startedexample_group_started18,627 - def example_group_startedexample_group_started62,1921 - def example_group_startedexample_group_started96,3319 - def example_group_startedexample_group_started135,4930 - def example_group_startedexample_group_started148,5425 - def example_group_startedexample_group_started162,6042 - def make_group(name, parent=::Spec::Example::ExampleGroupDouble)make_group173,6357 - def example_group_startedexample_group_started233,8737 - def have_single_level_example_group_output(expected_output)have_single_level_example_group_output318,11663 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/profile_formatter_spec.rb,87 -module SpecSpec4,73 - module RunnerRunner5,85 - module FormatterFormatter6,101 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/progress_bar_formatter_spec.rb,87 -module SpecSpec4,78 - module RunnerRunner5,90 - module FormatterFormatter6,106 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/snippet_extractor_spec.rb,87 -module SpecSpec4,73 - module RunnerRunner5,85 - module FormatterFormatter6,101 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/specdoc_formatter_spec.rb,432 -module SpecSpec4,73 - module RunnerRunner5,85 - module FormatterFormatter6,101 - def example_group_startedexample_group_started26,796 - def example_group_startedexample_group_started76,3071 - def have_nested_example_group_output(expected_output)have_nested_example_group_output104,4480 - def have_example_group_output(expected_output)have_example_group_output148,6276 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/formatter/text_mate_formatter_spec.rb,222 -module SpecSpec8,188 - module RunnerRunner9,200 - module FormatterFormatter10,216 - def produces_html_identical_to_manually_designed_document(opt)produces_html_identical_to_manually_designed_document19,581 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/heckle_runner_spec.rb,196 - module FooFoo5,151 - class BarBar6,164 - def one; endone7,178 - def two; endtwo8,197 - class ZapZap11,225 - def three; endthree12,239 - def four; endfour13,260 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/heckler_spec.rb,82 - def initialize(klass_name, method_name, rspec_options)initialize9,281 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/line_number_query/line_number_query_fixture.rb,59 -class LineNumberQuerySubjectLineNumberQuerySubject23,143 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/line_number_query_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/noisy_backtrace_tweaker_spec.rb,50 -module SpecSpec3,23 - module RunnerRunner4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/option_parser_spec.rb,66 - def parse(args)parse12,273 - def parse(args)parse292,9859 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/options_spec.rb,50 -module SpecSpec4,83 - module RunnerRunner5,95 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/output_one_time_fixture.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/output_one_time_fixture_runner.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/output_one_time_spec.rb,50 -module SpecSpec4,45 - module RunnerRunner5,57 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/quiet_backtrace_tweaker_spec.rb,50 -module SpecSpec3,23 - module RunnerRunner4,35 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/reporter_spec.rb,346 -module SpecSpec3,23 - module RunnerRunner4,35 - def failurefailure21,909 - def create_example_group(text)create_example_group25,1012 - def description_of(example)description_of62,2631 - def example_pending(example_passed_to_method, message_passed_to_method, deprecated_pending_location)example_pending196,8734 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/a_bar.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/a_foo.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/a_spec.rb,0 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/custom_example_group_runner.rb,191 -module CustomCustom1,0 - class ExampleGroupRunnerExampleGroupRunner2,14 - def initialize(options, arg)initialize4,72 - def load_files(files)load_files8,150 - def runrun11,185 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner/resources/utf8_encoded.rb,95 -module CustomCustom2,18 - class ExampleUTF8ClassNameVarietàExampleUTF8ClassNameVariet3,32 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec/runner_spec.rb,22 -module SpecSpec3,23 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/spec_helper.rb,892 -def jruby?jruby?14,261 -module Spec Spec18,305 - module ExampleExample19,319 - class NonStandardError < Exception; endNonStandardError20,336 - module MatchersMatchers23,387 - def failfail24,405 - def fail_with(message)fail_with28,489 - def exception_from(&block)exception_from32,596 - def run_with(options)run_with42,768 - def with_ruby(version)with_ruby46,850 -def with_sandboxed_optionswith_sandboxed_options52,962 -def with_sandboxed_configwith_sandboxed_config67,1273 -module SpecSpec86,1778 - module ExampleExample87,1790 - module ResettableResettable88,1807 - def reset # :nodoc:reset89,1829 - class ExampleGroupExampleGroup96,2001 - class ExampleGroupDouble < ExampleGroupExampleGroupDouble99,2056 - def register_example_group(klass)register_example_group101,2155 - def initialize(proxy=nil, &block)initialize104,2221 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/support/macros.rb,146 -module MacrosMacros1,0 - def treats_method_missing_as_private(options = {:noop => true, :subject => nil})treats_method_missing_as_private2,14 - -tmp/isolate/ruby-1.8/gems/rspec-1.3.1/spec/support/spec_classes.rb,2133 -module SpecSpec2,56 - module ExpectationsExpectations3,68 - class PersonPerson4,90 - def initialize nameinitialize6,131 - def == other==9,188 - class ClassWithMultiWordPredicateClassWithMultiWordPredicate14,265 - def multi_word_predicate?multi_word_predicate?15,303 - module HelperHelper20,368 - class CollectionWithSizeMethodCollectionWithSizeMethod21,386 - def initialize; @list = []; endinitialize22,423 - def size; @list.size; endsize23,463 - def push(item); @list.push(item); endpush24,497 - class CollectionWithLengthMethodCollectionWithLengthMethod27,554 - def initialize; @list = []; endinitialize28,593 - def length; @list.size; endlength29,633 - def push(item); @list.push(item); endpush30,669 - class CollectionOwnerCollectionOwner33,726 - def initializeinitialize36,854 - def add_to_collection_with_size_method(item)add_to_collection_with_size_method41,1052 - def add_to_collection_with_length_method(item)add_to_collection_with_length_method45,1177 - def items_for(arg)items_for49,1314 - def itemsitems54,1417 - class HandCodedMockHandCodedMock59,1506 - def initialize(return_val)initialize61,1563 - def funny?funny?66,1678 - def hungry?(a, b, c)hungry?71,1763 - def exists?exists?79,1950 - def multi_word_predicate?multi_word_predicate?83,2013 - def rspec_verifyrspec_verify87,2082 - class ClassWithUnqueriedPredicateClassWithUnqueriedPredicate91,2168 - def initialize(foo)initialize93,2235 -module CustomCustom101,2325 - class Formatter < Spec::Runner::Formatter::BaseTextFormatterFormatter103,2393 - def initialize(options, where)initialize106,2494 - class BadFormatter < Spec::Runner::Formatter::BaseTextFormatterBadFormatter112,2590 - def initialize(options, where)initialize115,2684 - class DifferDiffer120,2751 - def initialize(options)initialize122,2791 - def diff_as_object(target, expected)diff_as_object126,2853 -class FakeReporter < Spec::Runner::ReporterFakeReporter132,2922 - -tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/bin/rubyforge,0 - -tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/lib/rubyforge/client.rb,638 -class TimeTime6,136 - def utc(*args)utc12,229 -class Net::HTTPNet20,422 - def use_ssl= flaguse_ssl=22,470 -class RubyForgeRubyForge28,653 - class ClientClient29,669 - def initialize(proxy = nil)initialize32,746 - def post_content(uri, form = {}, headers = {}, userconfig = nil)post_content45,1099 - def get_content(uri, query = {}, headers = {}, userconfig = nil)get_content51,1336 - def execute(request, uri, parameters = {}, headers = {}, userconfig = nil)execute57,1573 - def boundary_data_for(boundary, parameters)boundary_data_for94,2806 - def query_string_for(parameters)query_string_for116,3498 - -tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/lib/rubyforge.rb,991 -class RubyForgeRubyForge12,186 - def initialize(userconfig=nil, autoconfig=nil, opts=nil)initialize29,782 - def login ; endlogin41,1149 - def logout ; endlogout42,1167 - def configure opts = {}configure44,1187 - def forceforce67,1979 - def uriuri71,2023 - def setupsetup80,2262 - def save_autoconfigsave_autoconfig93,2664 - def scrape_configscrape_config99,2782 - def get_via_rest_api(path)get_via_rest_api115,3234 - def scrape_project(project)scrape_project121,3408 - def create_package(group_id, package_name)create_package163,4790 - def post_news(group_id, subject, body)post_news184,5296 - def delete_package(group_id, package_id)delete_package195,5602 - def add_release(group_id, package_id, release_name, *files)add_release206,5998 - def add_file(group_name, package_name, release_name, userfile)add_file263,8084 - def clientclient289,8956 - def run(page, form, extheader={}) # :nodoc:run298,9158 - def lookup(type, val) # :nodoc:lookup306,9442 - -tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/test/test_rubyforge.rb,2410 -class RubyForgeRubyForge7,113 - def save_autoconfigsave_autoconfig11,198 -class RubyForge::FakeClientRubyForge16,261 - def form; endform17,289 - def post_content(*args)post_content19,306 - def get_content(*args)get_content23,363 -class FakeRubyForge < RubyForgeFakeRubyForge28,429 - def run(page, form, extheader={})run32,554 - def scrape_project(proj)scrape_project39,752 -class URI::HTTPURI46,891 - def self.datadata47,907 - def readread51,947 -class TestRubyForge < Test::Unit::TestCaseTestRubyForge56,1019 - def setupsetup57,1062 - def teardownteardown62,1121 - def test_new_with_proxy_uses_a_proxy_classtest_new_with_proxy_uses_a_proxy_class69,1297 - def test_new_with_bad_proxy_uses_normal_httptest_new_with_bad_proxy_uses_normal_http74,1488 - def test_initialize_badtest_initialize_bad79,1679 - def test_setuptest_setup97,2113 - def test_create_packagetest_create_package101,2204 - def test_delete_packagetest_delete_package109,2408 - def test_delete_package_package_nametest_delete_package_package_name114,2506 - def test_delete_package_undefined_package_nametest_delete_package_undefined_package_name119,2624 - def test_delete_package_group_nametest_delete_package_group_name125,2767 - def test_delete_package_undefined_group_nametest_delete_package_undefined_group_name130,2885 - def test_post_newstest_post_news136,3027 - def test_add_release_undefined_package_nametest_add_release_undefined_package_name144,3270 - def test_add_release_undefined_group_nametest_add_release_undefined_group_name150,3426 - def test_lookup_idtest_lookup_id156,3581 - def test_lookup_string_numbertest_lookup_string_number160,3665 - def test_lookup_nametest_lookup_name166,3788 - def test_lookup_undefinedtest_lookup_undefined171,3948 - def test_add_filetest_add_file177,4069 - def test_add_releasetest_add_release194,4623 - def test_add_release_with_a_filetest_add_release_with_a_file199,4731 - def test_add_release_package_nametest_add_release_package_name227,5791 - def test_add_release_group_nametest_add_release_group_name232,5917 - def test_scrape_projecttest_scrape_project238,6038 - def util_new(klass)util_new276,7260 - def util_run(page, form={}, extheader={})util_run302,7994 - def util_add_releaseutil_add_release309,8207 - def util_delete_packageutil_delete_package318,8496 - def make_a_tmp_filemake_a_tmp_file322,8582 - -tmp/isolate/ruby-1.8/gems/rubyforge-2.0.4/test/test_rubyforge_client.rb,517 -class RubyForge::FakeAgentRubyForge4,79 - def initialize(*args)initialize9,167 - def request(request, data)request12,198 - def response.read_body; ''; endread_body16,338 - class PostPost20,401 - def initialize(*args)initialize21,414 - def [] key[]26,486 - def []= key, val[]=30,537 - def method_missing(*stuff)method_missing34,600 -class TestRubyForgeClient < Test::Unit::TestCaseTestRubyForgeClient40,677 - def setupsetup41,726 - def test_post_with_paramstest_post_with_params48,960 From 7aacb3afdf305a796ded658ab90e9cd623c7f906 Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Mon, 18 Oct 2010 16:27:17 -0700 Subject: [PATCH 0807/1492] Removed TreeManagerShared and related tests. They sucked --- spec/support/shared/tree_manager_shared.rb | 9 --------- test/spec_helper.rb | 3 --- test/test_delete_manager.rb | 12 ------------ test/test_insert_manager.rb | 12 ------------ test/test_select_manager.rb | 12 ------------ test/test_update_manager.rb | 13 ------------- 6 files changed, 61 deletions(-) delete mode 100644 spec/support/shared/tree_manager_shared.rb diff --git a/spec/support/shared/tree_manager_shared.rb b/spec/support/shared/tree_manager_shared.rb deleted file mode 100644 index 48b561e1fb9aa..0000000000000 --- a/spec/support/shared/tree_manager_shared.rb +++ /dev/null @@ -1,9 +0,0 @@ -shared_examples_for "TreeManager" do - describe "clone" do - it "clones the insert statement" do - subject.instance_variable_get("@head").should_receive(:clone).and_return(:foo) # TODO: ick. - dolly = subject.clone - dolly.instance_variable_get("@head").should == :foo - end - end -end diff --git a/test/spec_helper.rb b/test/spec_helper.rb index dd288e0d0dfc6..128988e7f2347 100644 --- a/test/spec_helper.rb +++ b/test/spec_helper.rb @@ -6,8 +6,6 @@ require 'support/fake_record' Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new) -# HACK require 'support/shared/tree_manager_shared' - class Object def must_be_like other self.gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip @@ -18,4 +16,3 @@ def check truthiness raise "not truthy" unless truthiness end end - diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index 0a41c4d3fc468..163eadbf73e31 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -38,17 +38,5 @@ module Arel check dm.where(table[:id].eq(10)).must_equal dm end end - - # HACK - # describe "TreeManager" do - # before do - # table = Table.new :users - # Arel::DeleteManager.new(Table.engine).tap do |manager| - # manager.where(table[:id].eq(10)) - # end - # end - # - # it_should_behave_like "TreeManager" - # end end end diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 97ba4d7f765b7..203f18a0accfa 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -124,17 +124,5 @@ module Arel } end end - - # HACK - # describe "TreeManager" do - # subject do - # table = Table.new(:users) - # Arel::InsertManager.new(Table.engine).tap do |manager| - # manager.insert [[table[:id], nil]] - # end - # end - # - # it_should_behave_like "TreeManager" - # end end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 75d06438c262c..f714471dc7fe0 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -577,17 +577,5 @@ def execute sql, name = nil, *args manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"' end end - - # HACK - # describe "TreeManager" do - # subject do - # table = Table.new :users - # Arel::SelectManager.new(Table.engine).tap do |manager| - # manager.from(table).project(table['id']) - # end - # end - # - # it_should_behave_like "TreeManager" - # end end end diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 670f19d621782..3a7a446c074dc 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -73,18 +73,5 @@ module Arel um.where(table[:id].eq(1)).must_equal um end end - - # HACK - # describe "TreeManager" do - # subject do - # table = Table.new :users - # Arel::UpdateManager.new(Table.engine).tap do |manager| - # manager.table table - # manager.where table[:id].eq(1) - # end - # end - # - # it_should_behave_like "TreeManager" - # end end end From 31f61b822d28a3cdb56e35c73c5102e5e39f81a5 Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Mon, 18 Oct 2010 16:34:44 -0700 Subject: [PATCH 0808/1492] Renamed spec_helper to test_helper --- test/attributes/test_attribute.rb | 2 +- test/nodes/test_count.rb | 2 +- test/nodes/test_delete_statement.rb | 2 +- test/nodes/test_equality.rb | 2 +- test/nodes/test_insert_statement.rb | 2 +- test/nodes/test_or.rb | 2 +- test/nodes/test_select_core.rb | 2 +- test/nodes/test_select_statement.rb | 2 +- test/nodes/test_sql_literal.rb | 2 +- test/nodes/test_sum.rb | 2 +- test/nodes/test_update_statement.rb | 2 +- test/test_activerecord_compat.rb | 2 +- test/test_attributes.rb | 2 +- test/test_crud.rb | 2 +- test/test_delete_manager.rb | 2 +- test/{spec_helper.rb => test_helper.rb} | 0 test/test_insert_manager.rb | 2 +- test/test_select_manager.rb | 2 +- test/test_table.rb | 2 +- test/test_update_manager.rb | 2 +- test/visitors/test_join_sql.rb | 2 +- test/visitors/test_oracle.rb | 2 +- test/visitors/test_postgres.rb | 2 +- test/visitors/test_to_sql.rb | 2 +- 24 files changed, 23 insertions(+), 23 deletions(-) rename test/{spec_helper.rb => test_helper.rb} (100%) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index f0341f40705ad..6e707abb0394b 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Attributes diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index d65df03313e2f..01afb4bce4334 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::Count do describe 'backwards compatibility' do diff --git a/test/nodes/test_delete_statement.rb b/test/nodes/test_delete_statement.rb index a71da7adae541..d56cadad38621 100644 --- a/test/nodes/test_delete_statement.rb +++ b/test/nodes/test_delete_statement.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::DeleteStatement do describe "#clone" do diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb index 513cafd87fd8e..7ea8bb6c4dec1 100644 --- a/test/nodes/test_equality.rb +++ b/test/nodes/test_equality.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Nodes diff --git a/test/nodes/test_insert_statement.rb b/test/nodes/test_insert_statement.rb index 47f3c27dee61d..29029aff68383 100644 --- a/test/nodes/test_insert_statement.rb +++ b/test/nodes/test_insert_statement.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::InsertStatement do describe "#clone" do diff --git a/test/nodes/test_or.rb b/test/nodes/test_or.rb index 354d803110329..2dea665ecad79 100644 --- a/test/nodes/test_or.rb +++ b/test/nodes/test_or.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Nodes diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index 0aacf41720d6b..c43e620c71634 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::SelectCore do describe "#clone" do diff --git a/test/nodes/test_select_statement.rb b/test/nodes/test_select_statement.rb index 45613bfa4d5f5..1a21adecebb8a 100644 --- a/test/nodes/test_select_statement.rb +++ b/test/nodes/test_select_statement.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::SelectStatement do describe "#clone" do diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index 3aeab41f0cd74..f8f7e9e90d71b 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Nodes diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb index e6a57e4dd643a..6e1070427f9b5 100644 --- a/test/nodes/test_sum.rb +++ b/test/nodes/test_sum.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::Sum do describe "as" do diff --git a/test/nodes/test_update_statement.rb b/test/nodes/test_update_statement.rb index 88c147b26842b..3856d0821abc8 100644 --- a/test/nodes/test_update_statement.rb +++ b/test/nodes/test_update_statement.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' describe Arel::Nodes::UpdateStatement do describe "#clone" do diff --git a/test/test_activerecord_compat.rb b/test/test_activerecord_compat.rb index 2f1d7cff1299e..b70887e36c479 100644 --- a/test/test_activerecord_compat.rb +++ b/test/test_activerecord_compat.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel describe 'activerecord compatibility' do diff --git a/test/test_attributes.rb b/test/test_attributes.rb index 4cdb625b179e0..c716a0b1f3c1f 100644 --- a/test/test_attributes.rb +++ b/test/test_attributes.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel describe 'Attributes' do diff --git a/test/test_crud.rb b/test/test_crud.rb index 2a0ff651e975d..03063c8b6e562 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel class FakeCrudder < SelectManager diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index 163eadbf73e31..881d0e2bb1df1 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel describe 'delete manager' do diff --git a/test/spec_helper.rb b/test/test_helper.rb similarity index 100% rename from test/spec_helper.rb rename to test/test_helper.rb diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 203f18a0accfa..960cf9a54f570 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel describe 'insert manager' do diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index f714471dc7fe0..7f0ae7da3f345 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel class EngineProxy diff --git a/test/test_table.rb b/test/test_table.rb index ecb5c1eb79553..99ca0594f998d 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel describe Table do diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 3a7a446c074dc..7004ff4879d30 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel describe 'update manager' do diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index 3dc70d7dd6702..b79d9432c1abb 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Visitors diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 8b5732f287f7a..e7c61c3f8821b 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Visitors diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 70b935c185f59..de079b2014944 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Visitors diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index f7455d7fa3184..299d3094afd1a 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'test_helper' module Arel module Visitors From a2cee877ec890962d302f24caf99b6ae1de4801f Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Mon, 18 Oct 2010 16:36:49 -0700 Subject: [PATCH 0809/1492] got rid of retarded check method. down with rspec --- test/attributes/test_attribute.rb | 12 ++++++------ test/nodes/test_equality.rb | 16 ++++++++-------- test/nodes/test_or.rb | 8 ++++---- test/test_activerecord_compat.rb | 2 +- test/test_delete_manager.rb | 4 ++-- test/test_helper.rb | 5 ----- test/test_select_manager.rb | 20 ++++++++++---------- test/test_table.rb | 24 ++++++++++++------------ test/visitors/test_oracle.rb | 6 +++--- 9 files changed, 46 insertions(+), 51 deletions(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 6e707abb0394b..3ac8766724120 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -328,8 +328,8 @@ module Attributes it 'should return an equality node' do attribute = Attribute.new nil, nil, nil equality = attribute.eq 1 - check equality.left.must_equal attribute - check equality.right.must_equal 1 + equality.left.must_equal attribute + equality.right.must_equal 1 equality.must_be_kind_of Nodes::Equality end @@ -487,8 +487,8 @@ module Attributes it 'should return an in node' do attribute = Attribute.new nil, nil, nil node = Nodes::In.new attribute, [1,2,3] - check node.left.must_equal attribute - check node.right.must_equal [1, 2, 3] + node.left.must_equal attribute + node.right.must_equal [1, 2, 3] end it 'should generate IN in sql' do @@ -540,8 +540,8 @@ module Attributes it 'should return a NotIn node' do attribute = Attribute.new nil, nil, nil node = Nodes::NotIn.new attribute, [1,2,3] - check node.left.must_equal attribute - check node.right.must_equal [1, 2, 3] + node.left.must_equal attribute + node.right.must_equal [1, 2, 3] end it 'should generate NOT IN in sql' do diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb index 7ea8bb6c4dec1..e902dfa532d8c 100644 --- a/test/nodes/test_equality.rb +++ b/test/nodes/test_equality.rb @@ -9,7 +9,7 @@ module Nodes it 'returns :==' do attr = Table.new(:users)[:id] left = attr.eq(10) - check left.operator.must_equal :== + left.operator.must_equal :== end end @@ -17,7 +17,7 @@ module Nodes it "should equal left" do attr = Table.new(:users)[:id] left = attr.eq(10) - check left.left.must_equal left.operand1 + left.left.must_equal left.operand1 end end @@ -25,7 +25,7 @@ module Nodes it "should equal right" do attr = Table.new(:users)[:id] left = attr.eq(10) - check left.right.must_equal left.operand2 + left.right.must_equal left.operand2 end end @@ -43,7 +43,7 @@ def quote_table_name(*args) @quote_count += 1; super; end attr = Table.new(:users)[:id] test = attr.eq(10) test.to_sql engine - check engine.connection.quote_count.must_equal 2 + engine.connection.quote_count.must_equal 2 end end end @@ -54,8 +54,8 @@ def quote_table_name(*args) @quote_count += 1; super; end left = attr.eq(10) right = attr.eq(11) node = left.or right - check node.expr.left.must_equal left - check node.expr.right.must_equal right + node.expr.left.must_equal left + node.expr.right.must_equal right end end @@ -65,8 +65,8 @@ def quote_table_name(*args) @quote_count += 1; super; end left = attr.eq(10) right = attr.eq(11) node = left.and right - check node.left.must_equal left - check node.right.must_equal right + node.left.must_equal left + node.right.must_equal right end end end diff --git a/test/nodes/test_or.rb b/test/nodes/test_or.rb index 2dea665ecad79..0f2a767a12ff6 100644 --- a/test/nodes/test_or.rb +++ b/test/nodes/test_or.rb @@ -9,12 +9,12 @@ module Nodes left = attr.eq(10) right = attr.eq(11) node = left.or right - check node.expr.left.must_equal left - check node.expr.right.must_equal right + node.expr.left.must_equal left + node.expr.right.must_equal right oror = node.or(right) - check oror.expr.left.must_equal node - check oror.expr.right.must_equal right + oror.expr.left.must_equal node + oror.expr.right.must_equal right end end end diff --git a/test/test_activerecord_compat.rb b/test/test_activerecord_compat.rb index b70887e36c479..74a59adbd660e 100644 --- a/test/test_activerecord_compat.rb +++ b/test/test_activerecord_compat.rb @@ -9,7 +9,7 @@ module Arel manager.where table[:id].eq 1 manager.where table[:name].eq 'Aaron' - check manager.wheres.map { |x| + manager.wheres.map { |x| x.value }.join(', ').must_equal "\"users\".\"id\" = 1, \"users\".\"name\" = 'Aaron'" end diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index 881d0e2bb1df1..6fd438a0b251e 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -19,7 +19,7 @@ module Arel it 'chains' do table = Table.new(:users) dm = Arel::DeleteManager.new Table.engine - check dm.from(table).must_equal dm + dm.from(table).must_equal dm end end @@ -35,7 +35,7 @@ module Arel it 'chains' do table = Table.new(:users) dm = Arel::DeleteManager.new Table.engine - check dm.where(table[:id].eq(10)).must_equal dm + dm.where(table[:id].eq(10)).must_equal dm end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 128988e7f2347..3f9ac22447c84 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -10,9 +10,4 @@ class Object def must_be_like other self.gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip end - - # TODO: remove - def check truthiness - raise "not truthy" unless truthiness - end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7f0ae7da3f345..6b667926ab712 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -135,7 +135,7 @@ def execute sql, name = nil, *args table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.take 10 - check manager.taken.must_equal 10 + manager.taken.must_equal 10 end end @@ -168,7 +168,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine order = table[:id] manager.order table[:id] - check manager.orders.must_equal [order] + manager.orders.must_equal [order] end end @@ -199,7 +199,7 @@ def execute sql, name = nil, *args it 'chains' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - check manager.order(table[:id]).must_equal manager + manager.order(table[:id]).must_equal manager end end @@ -275,7 +275,7 @@ def execute sql, name = nil, *args it 'noops on nil' do manager = Arel::SelectManager.new Table.engine - check manager.join(nil).must_equal manager + manager.join(nil).must_equal manager end end @@ -288,7 +288,7 @@ def execute sql, name = nil, *args manager.join_sql.must_be_like %{ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" } - check manager.joins(manager).must_equal manager.join_sql + manager.joins(manager).must_equal manager.join_sql end it 'returns outer join sql' do @@ -299,7 +299,7 @@ def execute sql, name = nil, *args manager.join_sql.must_be_like %{ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" } - check manager.joins(manager).must_equal manager.join_sql + manager.joins(manager).must_equal manager.join_sql end it 'returns string join sql' do @@ -308,7 +308,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new(table, 'hello') manager.join_sql.must_be_like %{ 'hello' } - check manager.joins(manager).must_equal manager.join_sql + manager.joins(manager).must_equal manager.join_sql end it 'returns nil join sql' do @@ -342,7 +342,7 @@ def execute sql, name = nil, *args it 'chains' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - check manager.group(table[:id]).must_equal manager + manager.group(table[:id]).must_equal manager end it 'takes multiple args' do @@ -550,7 +550,7 @@ def execute sql, name = nil, *args mgr = left.join(right) mgr.project Nodes::SqlLiteral.new('*') - check mgr.on(predicate).must_equal mgr + mgr.on(predicate).must_equal mgr mgr.to_sql.must_be_like %{ SELECT * FROM "users" @@ -573,7 +573,7 @@ def execute sql, name = nil, *args it "chains" do table = Table.new :users manager = Arel::SelectManager.new Table.engine - check manager.from(table).project(table['id']).must_equal manager + manager.from(table).project(table['id']).must_equal manager manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"' end end diff --git a/test/test_table.rb b/test/test_table.rb index 99ca0594f998d..9a67ec3478a13 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -8,7 +8,7 @@ module Arel describe 'primary_key' do it 'should return an attribute' do - check @relation.primary_key.name.must_equal :id + @relation.primary_key.name.must_equal :id end end @@ -31,7 +31,7 @@ module Arel describe 'backwards compat' do describe 'joins' do it 'returns nil' do - check @relation.joins(nil).must_equal nil + @relation.joins(nil).must_equal nil end end @@ -67,12 +67,12 @@ module Arel describe 'alias' do it 'should create a node that proxies to a table' do - check @relation.aliases.must_equal [] + @relation.aliases.must_equal [] node = @relation.alias - check @relation.aliases.must_equal [node] - check node.name.must_equal 'users_2' - check node[:id].relation.must_equal node + @relation.aliases.must_equal [node] + node.name.must_equal 'users_2' + node[:id].relation.must_equal node end end @@ -80,18 +80,18 @@ module Arel it 'takes :columns' do columns = Table.engine.connection.columns("users") @relation = Table.new(:users, :columns => columns) - check @relation.columns.first.name.must_equal :id - check @relation.engine.must_equal Table.engine + @relation.columns.first.name.must_equal :id + @relation.engine.must_equal Table.engine end it 'should accept an engine' do rel = Table.new :users, 'foo' - check rel.engine.must_equal 'foo' + rel.engine.must_equal 'foo' end it 'should accept a hash' do rel = Table.new :users, :engine => 'foo' - check rel.engine.must_equal 'foo' + rel.engine.must_equal 'foo' end it 'ignores as if it equals name' do @@ -143,7 +143,7 @@ module Arel describe 'columns' do it 'returns a list of columns' do columns = @relation.columns - check columns.length.must_equal 2 + columns.length.must_equal 2 columns.map { |x| x.name.to_s }.sort.must_equal %w{ name id }.sort end end @@ -160,7 +160,7 @@ module Arel describe 'when given a Symbol' do it "manufactures an attribute if the symbol names an attribute within the relation" do column = @relation[:id] - check column.name.must_equal :id + column.name.must_equal :id column.must_be_kind_of Attributes::Integer end end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index e7c61c3f8821b..578a44918595e 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -28,7 +28,7 @@ module Visitors sql = @visitor.accept(stmt) sql2 = @visitor.accept(stmt) - check sql.must_equal sql2 + sql.must_equal sql2 end it 'splits orders with commas' do @@ -58,7 +58,7 @@ module Visitors stmt.limit = 10 sql = @visitor.accept stmt sql2 = @visitor.accept stmt - check sql.must_equal sql2 + sql.must_equal sql2 end it 'creates a subquery when there is order_by' do @@ -102,7 +102,7 @@ module Visitors stmt.offset = Nodes::Offset.new(10) sql = @visitor.accept stmt sql2 = @visitor.accept stmt - check sql.must_equal sql2 + sql.must_equal sql2 end end end From 2d05a01ea2a5062f6b75bc855d6d5046c0e9652c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 18 Oct 2010 16:49:43 -0700 Subject: [PATCH 0810/1492] cleaning up Rakefile --- Rakefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Rakefile b/Rakefile index 0097cb5ae0f51..f9670c051bf9c 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ require "rubygems" gem 'hoe', '>= 2.1.0' require 'hoe' -Hoe.plugin :isolate +Hoe.plugin :minitest Hoe.plugin :gemspec # `gem install hoe-gemspec` Hoe.spec 'arel' do @@ -13,9 +13,5 @@ Hoe.spec 'arel' do self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] - self.extra_dev_deps << ['rspec', '~> 1.3.0'] - self.extra_dev_deps << ['ZenTest'] - self.extra_dev_deps << ['minitest'] self.extra_dev_deps << ['hoe-gemspec'] - self.testlib = :minitest end From ab4d6668b462970b7fbb97a0a6257897577bc1c6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 18 Oct 2010 16:49:51 -0700 Subject: [PATCH 0811/1492] fisting manifest --- Manifest.txt | 56 ++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 0c74e6932e5ba..2b4828a471168 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,3 +1,4 @@ +.autotest History.txt MIT-LICENSE.txt Manifest.txt @@ -74,33 +75,28 @@ lib/arel/visitors/order_clauses.rb lib/arel/visitors/postgresql.rb lib/arel/visitors/to_sql.rb lib/arel/visitors/where_sql.rb -spec/activerecord_compat_spec.rb -spec/attributes/attribute_spec.rb -spec/attributes_spec.rb -spec/crud_spec.rb -spec/delete_manager_spec.rb -spec/insert_manager_spec.rb -spec/nodes/count_spec.rb -spec/nodes/delete_statement_spec.rb -spec/nodes/equality_spec.rb -spec/nodes/insert_statement_spec.rb -spec/nodes/or_spec.rb -spec/nodes/select_core_spec.rb -spec/nodes/select_statement_spec.rb -spec/nodes/sql_literal_spec.rb -spec/nodes/sum_spec.rb -spec/nodes/update_statement_spec.rb -spec/select_manager_spec.rb -spec/spec.opts -spec/spec_helper.rb -spec/support/check.rb -spec/support/fake_record.rb -spec/support/matchers.rb -spec/support/matchers/be_like.rb -spec/support/shared/tree_manager_shared.rb -spec/table_spec.rb -spec/update_manager_spec.rb -spec/visitors/join_sql_spec.rb -spec/visitors/oracle_spec.rb -spec/visitors/postgres_spec.rb -spec/visitors/to_sql_spec.rb +test/attributes/test_attribute.rb +test/nodes/test_count.rb +test/nodes/test_delete_statement.rb +test/nodes/test_equality.rb +test/nodes/test_insert_statement.rb +test/nodes/test_or.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_update_statement.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_helper.rb +test/test_insert_manager.rb +test/test_select_manager.rb +test/test_table.rb +test/test_update_manager.rb +test/visitors/test_join_sql.rb +test/visitors/test_oracle.rb +test/visitors/test_postgres.rb +test/visitors/test_to_sql.rb From 15f2b27c6d003676089379d5dbf8230408e2e6db Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 18 Oct 2010 16:54:50 -0700 Subject: [PATCH 0812/1492] renaming test_helper to helper so that it is not double required --- test/attributes/test_attribute.rb | 2 +- test/{test_helper.rb => helper.rb} | 0 test/nodes/test_count.rb | 2 +- test/nodes/test_delete_statement.rb | 2 +- test/nodes/test_equality.rb | 2 +- test/nodes/test_insert_statement.rb | 2 +- test/nodes/test_or.rb | 2 +- test/nodes/test_select_core.rb | 2 +- test/nodes/test_select_statement.rb | 2 +- test/nodes/test_sql_literal.rb | 2 +- test/nodes/test_sum.rb | 2 +- test/nodes/test_update_statement.rb | 2 +- test/test_activerecord_compat.rb | 2 +- test/test_attributes.rb | 2 +- test/test_crud.rb | 2 +- test/test_delete_manager.rb | 2 +- test/test_insert_manager.rb | 2 +- test/test_select_manager.rb | 2 +- test/test_table.rb | 2 +- test/test_update_manager.rb | 2 +- test/visitors/test_join_sql.rb | 2 +- test/visitors/test_oracle.rb | 2 +- test/visitors/test_postgres.rb | 2 +- test/visitors/test_to_sql.rb | 2 +- 24 files changed, 23 insertions(+), 23 deletions(-) rename test/{test_helper.rb => helper.rb} (100%) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 3ac8766724120..06954c242be7f 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Attributes diff --git a/test/test_helper.rb b/test/helper.rb similarity index 100% rename from test/test_helper.rb rename to test/helper.rb diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index 01afb4bce4334..afa423e8f5357 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::Count do describe 'backwards compatibility' do diff --git a/test/nodes/test_delete_statement.rb b/test/nodes/test_delete_statement.rb index d56cadad38621..299bdd38eefe8 100644 --- a/test/nodes/test_delete_statement.rb +++ b/test/nodes/test_delete_statement.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::DeleteStatement do describe "#clone" do diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb index e902dfa532d8c..fb022f615f16e 100644 --- a/test/nodes/test_equality.rb +++ b/test/nodes/test_equality.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Nodes diff --git a/test/nodes/test_insert_statement.rb b/test/nodes/test_insert_statement.rb index 29029aff68383..ef37e5c871a84 100644 --- a/test/nodes/test_insert_statement.rb +++ b/test/nodes/test_insert_statement.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::InsertStatement do describe "#clone" do diff --git a/test/nodes/test_or.rb b/test/nodes/test_or.rb index 0f2a767a12ff6..88115669d1d24 100644 --- a/test/nodes/test_or.rb +++ b/test/nodes/test_or.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Nodes diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index c43e620c71634..884d86e21fd15 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::SelectCore do describe "#clone" do diff --git a/test/nodes/test_select_statement.rb b/test/nodes/test_select_statement.rb index 1a21adecebb8a..8bbf7d174c725 100644 --- a/test/nodes/test_select_statement.rb +++ b/test/nodes/test_select_statement.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::SelectStatement do describe "#clone" do diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index f8f7e9e90d71b..5cf91cef0c3f4 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Nodes diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb index 6e1070427f9b5..50f5c0f4b567e 100644 --- a/test/nodes/test_sum.rb +++ b/test/nodes/test_sum.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::Sum do describe "as" do diff --git a/test/nodes/test_update_statement.rb b/test/nodes/test_update_statement.rb index 3856d0821abc8..8920e977b539e 100644 --- a/test/nodes/test_update_statement.rb +++ b/test/nodes/test_update_statement.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' describe Arel::Nodes::UpdateStatement do describe "#clone" do diff --git a/test/test_activerecord_compat.rb b/test/test_activerecord_compat.rb index 74a59adbd660e..d8812096100f3 100644 --- a/test/test_activerecord_compat.rb +++ b/test/test_activerecord_compat.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel describe 'activerecord compatibility' do diff --git a/test/test_attributes.rb b/test/test_attributes.rb index c716a0b1f3c1f..8fc9327b0fad7 100644 --- a/test/test_attributes.rb +++ b/test/test_attributes.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel describe 'Attributes' do diff --git a/test/test_crud.rb b/test/test_crud.rb index 03063c8b6e562..582f0ec072a8c 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel class FakeCrudder < SelectManager diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index 6fd438a0b251e..fd12c5acd2fec 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel describe 'delete manager' do diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 960cf9a54f570..3094408a41a26 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel describe 'insert manager' do diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 6b667926ab712..ee5ead70771e9 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel class EngineProxy diff --git a/test/test_table.rb b/test/test_table.rb index 9a67ec3478a13..9a275402cb4fc 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel describe Table do diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 7004ff4879d30..5823845ba0235 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel describe 'update manager' do diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index b79d9432c1abb..8253fe5ab4cf6 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Visitors diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 578a44918595e..db277088f1579 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Visitors diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index de079b2014944..618745c35d1db 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Visitors diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 299d3094afd1a..b133e8b64e818 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require 'helper' module Arel module Visitors From aca9b5b04a583d862ef71daa48121d72be4fa2e5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 19 Oct 2010 10:05:51 -0700 Subject: [PATCH 0813/1492] removing irrelevant docs, updating relevant docs --- README.markdown | 106 ++++-------------------------------------------- 1 file changed, 7 insertions(+), 99 deletions(-) diff --git a/README.markdown b/README.markdown index ab05e1245a348..b71879e4e3878 100644 --- a/README.markdown +++ b/README.markdown @@ -8,9 +8,7 @@ Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex o ## Status -For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. On the horizon is the use of DataObjects instead. - -The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc. +For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. ## A Gentle Introduction @@ -20,19 +18,10 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: - users = Table(:users) + users = Arel::Table.new(:users) + users.project(Arel.sql('*')) users.to_sql -In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: - - users.each { |user| ... } - -In other words, Arel relations implement Ruby's Enumerable interface. Let's have a look at a concrete example: - - users.first # => { users[:id] => 1, users[:name] => 'bob' } - -As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). - ### 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. @@ -75,19 +64,11 @@ Of course, many of the operators take multiple arguments, so the last example ca users.where(users[:name].eq('bob'), users[:age].lt(25)) -The `OR` operator is not yet supported. It will work like this: +The `OR` operator works like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) -The `AND` operator will behave similarly. - -Finally, most operations take a block form. For example: - - Table(:users) \ - .where { |u| u[:id].eq(1) } \ - .project { |u| u[:id] } - -This provides a (sometimes) convenient alternative syntax. +The `AND` operator behaves similarly. ### The Crazy Features @@ -97,11 +78,11 @@ The examples above are fairly simple and other libraries match or come close to 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 = Table(:comments) + comments = Arel::Table.new(:comments) And this table has the following attributes: - comments.attributes # => [comments[:id], comments[:body], comments[:parent_id]] + 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: @@ -110,77 +91,4 @@ The `parent_id` column is a foreign key from the `comments` table to itself. Now 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 -The call to `#alias` is actually optional: Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Explicit aliasing is more common, however. When you want to extract specific slices of data, aliased tables are a necessity. For example to get just certain columns from the row, treat a row like a hash: - - comments_with_replies.first[replies[:body]] - This will return the first comment's reply's body. - -If you don't need to extract the data later (for example, you're simply doing a join to find comments that have replies, you don't care what the content of the replies are), the block form may be preferable: - - comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } - # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id - -Note that you do NOT want to do something like: - - comments.join(comments, comments[:parent_id].eq(comments[:id])) - # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id - -This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous. - -#### Complex Aggregations - -My personal favorite feature of Arel, certainly the most difficult to implement, and possibly only of marginal value, is **closure under joining even in the presence of aggregations**. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. Think of this as a preview of the kind of radical functionality that is to come, stuff no other "ORM" is doing. - -The easiest way to introduce this is in SQL. Your task is to get all users and the **count** of their associated photos. Let's start from the inside out: - - SELECT count(*) - FROM photos - GROUP BY user_id - -Now, we'd like to join this with the user table. Naively, you might try to do this: - - SELECT users.*, count(photos.id) - FROM users - LEFT OUTER JOIN photos - ON users.id = photos.user_id - GROUP BY photos.user_id - -Of course, this has a slightly different meaning than our intended query. This is actually a fairly advanced topic in SQL so let's see why this doesn't work *step by step*. Suppose we have these records in our `users` table: - - mysql> select * from users; - +------+--------+ - | id | name | - +------+--------+ - | 1 | hai | - | 2 | bai | - | 3 | dumpty | - +------+--------+ - -And these in the photos table: - - mysql> select * from photos; - +------+---------+-----------+ - | id | user_id | camera_id | - +------+---------+-----------+ - | 1 | 1 | 1 | - | 2 | 1 | 1 | - | 3 | 1 | 1 | - +------+---------+-----------+ - -If we perform the above, incorrect query, we get the following: - - mysql> select users.*, count(photos.id) from users left outer join photos on users.id = photos.user_id limit 3 group by user_id; - +------+------+------------------+ - | id | name | count(photos.id) | - +------+------+------------------+ - | 2 | bai | 0 | - | 1 | hai | 3 | - +------+------+------------------+ - -As you can see, we're completely missing data for user with id 3. `dumpty` has no photos, neither does `bai`. But strangely `bai` appeared and `dumpty` didn't! The reason is that the `GROUP BY` clause is aggregating on both tables, not just the `photos` table. All users without photos have a `photos.id` of `null` (thanks to the left outer join). These are rolled up together and an arbitrary user wins. In this case, `bai` not `dumpty`. - - SELECT users.*, photos_aggregation.cnt - FROM users - LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation - ON photos_aggregation.user_id = users.id From 6cd43f5044e169c5044cd337f7f101c9ee18712d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 19 Oct 2010 11:42:02 -0700 Subject: [PATCH 0814/1492] adding a base class visitor --- lib/arel/visitors.rb | 1 + lib/arel/visitors/to_sql.rb | 12 ++---------- lib/arel/visitors/visitor.rb | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 lib/arel/visitors/visitor.rb diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index fc585c39bbf1f..01c6647039c4c 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -1,3 +1,4 @@ +require 'arel/visitors/visitor' require 'arel/visitors/to_sql' require 'arel/visitors/postgresql' require 'arel/visitors/mysql' diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 17779b40372c8..e68890004a2cd 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -3,7 +3,7 @@ module Arel module Visitors - class ToSql + class ToSql < Arel::Visitors::Visitor def initialize engine @engine = engine @connection = nil @@ -16,7 +16,7 @@ def accept object @last_column = nil @engine.connection_pool.with_connection do |conn| @connection = conn - visit object + super end end @@ -277,14 +277,6 @@ def visit_String o; quote(o, @last_column) end alias :visit_Time :visit_String alias :visit_TrueClass :visit_String - DISPATCH = Hash.new do |hash, klass| - hash[klass] = "visit_#{klass.name.gsub('::', '_')}" - end - - def visit object - send DISPATCH[object.class], object - end - def quote value, column = nil @connection.quote value, column end diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb new file mode 100644 index 0000000000000..510d50399be27 --- /dev/null +++ b/lib/arel/visitors/visitor.rb @@ -0,0 +1,19 @@ +module 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 visit object + send DISPATCH[object.class], object + end + end + end +end From 1d30f5cdae81e30df493ed9bb686b5621e7c3664 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 19 Oct 2010 11:42:41 -0700 Subject: [PATCH 0815/1492] updating gemspec and manifest --- Manifest.txt | 3 ++- arel.gemspec | 26 +++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 2b4828a471168..200bb5f5c0b5f 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -74,8 +74,10 @@ lib/arel/visitors/oracle.rb lib/arel/visitors/order_clauses.rb lib/arel/visitors/postgresql.rb lib/arel/visitors/to_sql.rb +lib/arel/visitors/visitor.rb lib/arel/visitors/where_sql.rb test/attributes/test_attribute.rb +test/helper.rb test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_equality.rb @@ -91,7 +93,6 @@ test/test_activerecord_compat.rb test/test_attributes.rb test/test_crud.rb test/test_delete_manager.rb -test/test_helper.rb test/test_insert_manager.rb test/test_select_manager.rb test/test_table.rb diff --git a/arel.gemspec b/arel.gemspec index c7e83e6c61b86..fdec832d0e947 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,21 +2,22 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.0.dev.20100924164835" + s.version = "2.0.1.20101019114225" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2010-09-24} + s.date = %q{2010-10-19} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] - s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.markdown"] - s.files = ["History.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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/to_sql.rb", "spec/activerecord_compat_spec.rb", "spec/attributes/attribute_spec.rb", "spec/attributes_spec.rb", "spec/crud_spec.rb", "spec/delete_manager_spec.rb", "spec/insert_manager_spec.rb", "spec/nodes/count_spec.rb", "spec/nodes/delete_statement_spec.rb", "spec/nodes/equality_spec.rb", "spec/nodes/insert_statement_spec.rb", "spec/nodes/or_spec.rb", "spec/nodes/select_core_spec.rb", "spec/nodes/select_statement_spec.rb", "spec/nodes/sql_literal_spec.rb", "spec/nodes/sum_spec.rb", "spec/nodes/update_statement_spec.rb", "spec/select_manager_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/support/check.rb", "spec/support/fake_record.rb", "spec/support/matchers.rb", "spec/support/matchers/be_like.rb", "spec/support/shared/tree_manager_shared.rb", "spec/table_spec.rb", "spec/update_manager_spec.rb", "spec/visitors/join_sql_spec.rb", "spec/visitors/oracle_spec.rb", "spec/visitors/to_sql_spec.rb"] + s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] + s.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_to_sql.rb"] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} s.rubygems_version = %q{1.3.7} s.summary = %q{Arel is a Relational Algebra for Ruby} + s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_to_sql.rb"] if s.respond_to? :specification_version then current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION @@ -24,16 +25,19 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, [">= 2.0.4"]) - s.add_development_dependency(%q, ["~> 1.3.0"]) - s.add_development_dependency(%q, [">= 2.6.0"]) + s.add_development_dependency(%q, [">= 1.7.2"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 2.6.2"]) else s.add_dependency(%q, [">= 2.0.4"]) - s.add_dependency(%q, ["~> 1.3.0"]) - s.add_dependency(%q, [">= 2.6.0"]) + s.add_dependency(%q, [">= 1.7.2"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2.6.2"]) end else s.add_dependency(%q, [">= 2.0.4"]) - s.add_dependency(%q, ["~> 1.3.0"]) - s.add_dependency(%q, [">= 2.6.0"]) + s.add_dependency(%q, [">= 1.7.2"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2.6.2"]) end end From 691c9d2d9643211bcc2d24f68ef05f0418a157e6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 19 Oct 2010 11:47:00 -0700 Subject: [PATCH 0816/1492] doing a little cleanup on the visitors --- lib/arel/visitors/dot.rb | 6 +++--- lib/arel/visitors/join_sql.rb | 2 ++ lib/arel/visitors/mysql.rb | 2 ++ lib/arel/visitors/order_clauses.rb | 2 ++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 5202c5127ee86..2ce8b6814f736 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -1,6 +1,6 @@ module Arel module Visitors - class Dot + class Dot < Arel::Visitors::Visitor class Node # :nodoc: attr_accessor :name, :id, :fields @@ -23,7 +23,7 @@ def initialize end def accept object - visit object + super to_dot end @@ -188,7 +188,7 @@ def visit o @seen[node.id] = node @nodes << node with_node node do - send "visit_#{o.class.name.gsub('::', '_')}", o + super end end diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 49625e850def1..d3fb18d3c67b4 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -9,6 +9,8 @@ module Visitors # This visitor is used in SelectManager#join_sql and is for backwards # compatibility with Arel V1.0 class JoinSql < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_SelectCore o [o.froms].grep(Nodes::Join).map { |x| visit x }.join ', ' end diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 455122359185c..0c94ee1b27475 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -1,6 +1,8 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_UpdateStatement o [ "UPDATE #{visit o.relation}", diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb index 9326897f687c5..11dbfdad2ae14 100644 --- a/lib/arel/visitors/order_clauses.rb +++ b/lib/arel/visitors/order_clauses.rb @@ -1,6 +1,8 @@ module Arel module Visitors class OrderClauses < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_SelectStatement o o.orders.map { |x| visit x } end From 4041d7d33ad3f0acb0b04ed51da3ae29123250cb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 20 Oct 2010 09:23:36 -0700 Subject: [PATCH 0817/1492] removing unused variables --- test/test_select_manager.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index ee5ead70771e9..50f04a1a58b54 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -132,7 +132,6 @@ def execute sql, name = nil, *args describe 'taken' do it 'should return limit' do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.take 10 manager.taken.must_equal 10 @@ -304,7 +303,6 @@ def execute sql, name = nil, *args it 'returns string join sql' do table = Table.new :users - aliaz = table.alias manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new(table, 'hello') manager.join_sql.must_be_like %{ 'hello' } @@ -320,7 +318,6 @@ def execute sql, name = nil, *args describe 'order_clauses' do it 'returns order clauses as a list' do table = Table.new :users - aliaz = table.alias manager = Arel::SelectManager.new Table.engine manager.from table manager.order table[:id] @@ -474,7 +471,6 @@ def execute sql, name = nil, *args describe 'project' do it 'takes multiple args' do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new('foo'), Nodes::SqlLiteral.new('bar') @@ -482,14 +478,12 @@ def execute sql, name = nil, *args end it 'takes strings' do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new('*') manager.to_sql.must_be_like %{ SELECT * } end it "takes sql literals" do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new '*' manager.to_sql.must_be_like %{ @@ -515,7 +509,6 @@ def execute sql, name = nil, *args end it "chains" do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.take(1).must_equal manager end From e42506f9ea58511246f638e81002947ee3c36b18 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 20 Oct 2010 17:16:18 -0700 Subject: [PATCH 0818/1492] adding default limits when there is an offset for sqlite and mysql [#5316 state:resolved] --- Manifest.txt | 3 +++ lib/arel/table.rb | 4 ++++ lib/arel/visitors.rb | 3 +++ lib/arel/visitors/mysql.rb | 7 +++++++ lib/arel/visitors/sqlite.rb | 11 +++++++++++ test/support/fake_record.rb | 2 +- test/test_table.rb | 7 +++++++ test/visitors/test_mysql.rb | 21 +++++++++++++++++++++ test/visitors/test_sqlite.rb | 18 ++++++++++++++++++ 9 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 lib/arel/visitors/sqlite.rb create mode 100644 test/visitors/test_mysql.rb create mode 100644 test/visitors/test_sqlite.rb diff --git a/Manifest.txt b/Manifest.txt index 200bb5f5c0b5f..1ea5768f06b70 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -73,6 +73,7 @@ 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 @@ -98,6 +99,8 @@ test/test_select_manager.rb test/test_table.rb test/test_update_manager.rb test/visitors/test_join_sql.rb +test/visitors/test_mysql.rb test/visitors/test_oracle.rb test/visitors/test_postgres.rb +test/visitors/test_sqlite.rb test/visitors/test_to_sql.rb diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 171d165bc2962..61210dae767bc 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -80,6 +80,10 @@ def take amount from(self).take amount end + def skip amount + from(self).skip amount + end + def having expr from(self).having expr end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 01c6647039c4c..5d4c6084b225e 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -1,5 +1,6 @@ require 'arel/visitors/visitor' require 'arel/visitors/to_sql' +require 'arel/visitors/sqlite' require 'arel/visitors/postgresql' require 'arel/visitors/mysql' require 'arel/visitors/oracle' @@ -15,6 +16,8 @@ module Visitors 'mysql' => Arel::Visitors::MySQL, 'mysql2' => Arel::Visitors::MySQL, 'oracle_enhanced' => Arel::Visitors::Oracle, + 'sqlite' => Arel::Visitors::SQLite, + 'sqlite3' => Arel::Visitors::SQLite, } ENGINE_VISITORS = Hash.new do |hash, engine| diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 0c94ee1b27475..594fd5504ad1a 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,6 +2,13 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql private + ### + # :'( + # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 + def visit_Arel_Nodes_SelectStatement o + o.limit = 18446744073709551615 if o.offset && !o.limit + super + end def visit_Arel_Nodes_UpdateStatement o [ diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb new file mode 100644 index 0000000000000..c45160851d17f --- /dev/null +++ b/lib/arel/visitors/sqlite.rb @@ -0,0 +1,11 @@ +module Arel + module Visitors + class SQLite < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_SelectStatement o + o.limit = -1 if o.offset && !o.limit + super + end + end + end +end diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index ef3cc6a291981..e0f9685c050e9 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -66,7 +66,7 @@ class Spec < Struct.new(:config) attr_reader :spec, :connection def initialize - @spec = Spec.new(:adapter => 'sqlite3') + @spec = Spec.new(:adapter => 'america') @connection = Connection.new end diff --git a/test/test_table.rb b/test/test_table.rb index 9a275402cb4fc..d34383922c2bf 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -6,6 +6,13 @@ module Arel @relation = Table.new(:users) 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 'primary_key' do it 'should return an attribute' do @relation.primary_key.name.must_equal :id diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb new file mode 100644 index 0000000000000..1d38161caf0d7 --- /dev/null +++ b/test/visitors/test_mysql.rb @@ -0,0 +1,21 @@ +require 'helper' + +module Arel + module Visitors + describe 'the mysql visitor' do + before do + @visitor = MySQL.new Table.engine + 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 LIMIT 18446744073709551615 OFFSET 1" + end + end + end +end diff --git a/test/visitors/test_sqlite.rb b/test/visitors/test_sqlite.rb new file mode 100644 index 0000000000000..fb8392c504718 --- /dev/null +++ b/test/visitors/test_sqlite.rb @@ -0,0 +1,18 @@ +require 'helper' + +module Arel + module Visitors + describe 'the sqlite visitor' do + before do + @visitor = SQLite.new Table.engine + 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 + end + end +end From c66f025a8ebfd1d75ac6c5082df5cb4176f3a7bf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 20 Oct 2010 17:16:45 -0700 Subject: [PATCH 0819/1492] updating gemspec --- arel.gemspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index fdec832d0e947..2549936888655 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,22 +2,22 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.1.20101019114225" + s.version = "2.0.1.20101020171639" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2010-10-19} + s.date = %q{2010-10-20} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_to_sql.rb"] + s.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} s.rubygems_version = %q{1.3.7} s.summary = %q{Arel is a Relational Algebra for Ruby} - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_to_sql.rb"] + s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.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 current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION From ec6ac6654ed7eb678bb0b8f58fe3e7d9b932e297 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Thu, 21 Oct 2010 11:22:48 +0300 Subject: [PATCH 0820/1492] generate correct select if only offset is present (in Oracle) --- lib/arel/visitors/oracle.rb | 14 ++++++++++++++ test/visitors/test_oracle.rb | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index c691ce294eb0b..212c18ada435d 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -40,6 +40,20 @@ def visit_Arel_Nodes_SelectStatement o return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{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 diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index db277088f1579..d2a73ea8c54ed 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -105,6 +105,22 @@ module Visitors 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 end end From 0e8388bc2bba07d9b29fb716c2ba774360ad6aa4 Mon Sep 17 00:00:00 2001 From: rugek Date: Tue, 26 Oct 2010 14:35:31 +0800 Subject: [PATCH 0821/1492] Added Bignum to visitor --- lib/arel/visitors/to_sql.rb | 1 + test/visitors/test_to_sql.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index e68890004a2cd..f52ce101c056d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -263,6 +263,7 @@ def visit_Arel_Attributes_Attribute o def visit_Fixnum o; o end alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated + alias :visit_Bignum :visit_Fixnum def visit_String o; quote(o, @last_column) end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b133e8b64e818..d7cf71961a29b 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -29,6 +29,10 @@ module Visitors @visitor.accept 2.14 end + it "should visit_Bignum" do + @visitor.accept 8787878092 + end + it "should visit_Hash" do @visitor.accept({:a => 1}) end From 01e7ceef453e3dc976dc0d12002bb6d4a66f1252 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 27 Oct 2010 21:43:20 +0800 Subject: [PATCH 0822/1492] Refactor predication methods to be available to SqlLiterals as well. --- lib/arel.rb | 1 + lib/arel/attributes/attribute.rb | 175 +----------------------------- lib/arel/nodes/sql_literal.rb | 1 + lib/arel/predications.rb | 177 +++++++++++++++++++++++++++++++ test/nodes/test_sql_literal.rb | 24 +++++ 5 files changed, 204 insertions(+), 174 deletions(-) create mode 100644 lib/arel/predications.rb diff --git a/lib/arel.rb b/lib/arel.rb index 1a1f4c12ddc52..bcf71c05ddc4b 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,6 +1,7 @@ require 'arel/crud' require 'arel/expressions' +require 'arel/predications' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index ba18533590f1c..e027a65a74e53 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -2,180 +2,7 @@ module Arel module Attributes class Attribute < Struct.new :relation, :name, :column include Arel::Expressions - - 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 - Nodes::In.new self, other.to_a.map { |x| x.id } - when Range - if other.exclude_end? - left = Nodes::GreaterThanOrEqual.new(self, other.min) - right = Nodes::LessThan.new(self, other.max + 1) - Nodes::And.new left, right - else - Nodes::Between.new(self, Nodes::And.new(other.min, other.max)) - 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 - Nodes::NotIn.new self, other.to_a.map { |x| x.id } - when Range - if other.exclude_end? - left = Nodes::LessThan.new(self, other.min) - right = Nodes::GreaterThanOrEqual.new(self, other.max) - Nodes::Or.new left, right - else - left = Nodes::LessThan.new(self, other.min) - right = Nodes::GreaterThan.new(self, other.max) - 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 - - def asc - Nodes::Ordering.new self, :asc - end - - def desc - Nodes::Ordering.new self, :desc - end - - private - - def grouping_any method_id, others - first = send method_id, others.shift - - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::Or.new(memo, send(method_id, expr)) - } - end - - def grouping_all method_id, others - first = send method_id, others.shift - - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::And.new(memo, send(method_id, expr)) - } - end + include Arel::Predications end class String < Attribute; end diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index e5918620d93f9..c76a16daf18f8 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -2,6 +2,7 @@ module Arel module Nodes class SqlLiteral < String include Arel::Expressions + include Arel::Predications end end end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb new file mode 100644 index 0000000000000..8a8960f0b1880 --- /dev/null +++ b/lib/arel/predications.rb @@ -0,0 +1,177 @@ +module 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 + Nodes::In.new self, other.to_a.map { |x| x.id } + when Range + if other.exclude_end? + left = Nodes::GreaterThanOrEqual.new(self, other.min) + right = Nodes::LessThan.new(self, other.max + 1) + Nodes::And.new left, right + else + Nodes::Between.new(self, Nodes::And.new(other.min, other.max)) + 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 + Nodes::NotIn.new self, other.to_a.map { |x| x.id } + when Range + if other.exclude_end? + left = Nodes::LessThan.new(self, other.min) + right = Nodes::GreaterThanOrEqual.new(self, other.max) + Nodes::Or.new left, right + else + left = Nodes::LessThan.new(self, other.min) + right = Nodes::GreaterThan.new(self, other.max) + 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 + + def asc + Nodes::Ordering.new self, :asc + end + + def desc + Nodes::Ordering.new self, :desc + end + + private + + def grouping_any method_id, others + first = send method_id, others.shift + + Nodes::Grouping.new others.inject(first) { |memo,expr| + Nodes::Or.new(memo, send(method_id, expr)) + } + end + + def grouping_all method_id, others + first = send method_id, others.shift + + Nodes::Grouping.new others.inject(first) { |memo,expr| + Nodes::And.new(memo, send(method_id, expr)) + } + end + end +end \ No newline at end of file diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index 5cf91cef0c3f4..d280d6d92845f 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -23,6 +23,30 @@ module Nodes viz.accept(node).must_be_like %{ COUNT(DISTINCT *) } end end + + describe 'equality' do + it 'makes an equality node' do + node = SqlLiteral.new('foo').eq(1) + viz = Visitors::ToSql.new Table.engine + viz.accept(node).must_be_like %{ foo = 1 } + 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]) + viz = Visitors::ToSql.new Table.engine + viz.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]) + viz = Visitors::ToSql.new Table.engine + viz.accept(node).must_be_like %{ (foo = 1 AND foo = 2) } + end + end end end end From afb6f9c5c1de606c10eca6967010eaa4bfde263b Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 3 Nov 2010 20:32:23 +0800 Subject: [PATCH 0823/1492] Add ToSql NilClass visitor --- lib/arel/visitors/to_sql.rb | 1 + test/visitors/test_to_sql.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f52ce101c056d..1412797fb5f09 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -277,6 +277,7 @@ def visit_String o; quote(o, @last_column) end alias :visit_Symbol :visit_String alias :visit_Time :visit_String alias :visit_TrueClass :visit_String + alias :visit_NilClass :visit_String def quote value, column = nil @connection.quote value, column diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index d7cf71961a29b..a6042ef9c3654 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -45,6 +45,10 @@ module Visitors @visitor.accept Date.today end + it "should visit_NilClass" do + @visitor.accept(nil).must_be_like "NULL" + end + it "should visit_Arel_Nodes_And" do node = Nodes::And.new @attr.eq(10), @attr.eq(11) @visitor.accept(node).must_be_like %{ From d9d9944b37b959c6b6f00d4f38048cc541a56ad8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 4 Nov 2010 10:25:55 -0700 Subject: [PATCH 0824/1492] updating the development dependencies --- Rakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index f9670c051bf9c..f9f71b4f5aec5 100644 --- a/Rakefile +++ b/Rakefile @@ -13,5 +13,6 @@ Hoe.spec 'arel' do self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] - self.extra_dev_deps << ['hoe-gemspec'] + self.extra_dev_deps << [ 'hoe', '>= 2.1.0' ] + self.extra_dev_deps << [ 'minitest', '>= 1.6.0' ] end From 424e39d6883e5ab53a0f2c5d27508b36b1fb5879 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 14:05:10 -0700 Subject: [PATCH 0825/1492] adding proper columns to our fake table --- test/support/fake_record.rb | 4 +++- test/test_insert_manager.rb | 11 ++++------- test/test_table.rb | 4 ++-- test/visitors/test_to_sql.rb | 13 ++++++------- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index e0f9685c050e9..376ed40f2d7ef 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -10,7 +10,9 @@ def initialize @columns = { 'users' => [ Column.new('id', :integer), - Column.new('name', :string) + Column.new('name', :string), + Column.new('bool', :boolean), + Column.new('created_at', :date), ] } @primary_keys = { diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 3094408a41a26..0a1b1fcf5a1f4 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -13,11 +13,9 @@ module Arel table = Table.new(:users) manager = Arel::InsertManager.new Table.engine - table[:id].column.extend(Module.new { def type; :boolean; end }) - - manager.insert [[table[:id], false]] + manager.insert [[table[:bool], false]] manager.to_sql.must_be_like %{ - INSERT INTO "users" ("id") VALUES ('f') + INSERT INTO "users" ("bool") VALUES ('f') } end @@ -35,12 +33,11 @@ module Arel manager = Arel::InsertManager.new Table.engine time = Time.now - attribute = table[:id] - attribute.column.type = :date + attribute = table[:created_at] manager.insert [[attribute, time]] manager.to_sql.must_be_like %{ - INSERT INTO "users" ("id") VALUES (#{Table.engine.connection.quote time}) + INSERT INTO "users" ("created_at") VALUES (#{Table.engine.connection.quote time}) } end diff --git a/test/test_table.rb b/test/test_table.rb index d34383922c2bf..0dbb3f8dd183a 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -150,8 +150,8 @@ module Arel describe 'columns' do it 'returns a list of columns' do columns = @relation.columns - columns.length.must_equal 2 - columns.map { |x| x.name.to_s }.sort.must_equal %w{ name id }.sort + columns.length.must_equal 4 + columns.map { |x| x.name.to_s }.sort.must_equal %w{ created_at bool name id }.sort end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index a6042ef9c3654..8723332005f92 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -69,9 +69,8 @@ module Visitors end it "should visit_TrueClass" do - test = @attr.eq(true) - test.left.column.type = :boolean - @visitor.accept(test).must_be_like %{ "users"."id" = 't' } + test = Table.new(:users)[:bool].eq(true) + @visitor.accept(test).must_be_like %{ "users"."bool" = 't' } end describe "Nodes::Ordering" do @@ -113,6 +112,7 @@ module Visitors end it 'uses the same column for escaping values' do + @attr = Table.new(:users)[:name] visitor = Class.new(ToSql) do attr_accessor :expected @@ -124,16 +124,15 @@ def quote value, column = nil in_node = Nodes::In.new @attr, %w{ a b c } visitor = visitor.new(Table.engine) visitor.expected = @attr.column - visitor.accept(in_node).must_equal %("users"."id" IN ('a', 'b', 'c')) + visitor.accept(in_node).must_equal %("users"."name" IN ('a', 'b', 'c')) end end describe 'Equality' do it "should escape strings" do - test = @attr.eq 'Aaron Patterson' - test.left.column.type = :string + test = Table.new(:users)[:name].eq 'Aaron Patterson' @visitor.accept(test).must_be_like %{ - "users"."id" = 'Aaron Patterson' + "users"."name" = 'Aaron Patterson' } end end From a1a01e2bb301a7a4ae5c5cdcc27ece9f7edf6c66 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 14:09:09 -0700 Subject: [PATCH 0826/1492] renaming @head to @ast --- lib/arel/crud.rb | 4 ++-- lib/arel/delete_manager.rb | 8 ++++---- lib/arel/insert_manager.rb | 16 ++++++++-------- lib/arel/select_manager.rb | 20 ++++++++++---------- lib/arel/tree_manager.rb | 7 ++++--- lib/arel/update_manager.rb | 16 ++++++++-------- test/test_select_manager.rb | 9 +++++++++ 7 files changed, 45 insertions(+), 35 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 640189fbe96af..b3199e6d38116 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -13,8 +13,8 @@ def update values end um.table relation um.set values - um.take @head.limit - um.order(*@head.orders) + um.take @ast.limit + um.order(*@ast.orders) um.wheres = @ctx.wheres @engine.connection.update um.to_sql, 'AREL' diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index 4759f116f1919..3aab248c23080 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -2,21 +2,21 @@ module Arel class DeleteManager < Arel::TreeManager def initialize engine super - @head = Nodes::DeleteStatement.new + @ast = Nodes::DeleteStatement.new end def from relation - @head.relation = relation + @ast.relation = relation self end def where expression - @head.wheres << expression + @ast.wheres << expression self end def wheres= list - @head.wheres = list + @ast.wheres = list end end end diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index 175947554239b..f62f36369b8ed 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -2,32 +2,32 @@ module Arel class InsertManager < Arel::TreeManager def initialize engine super - @head = Nodes::InsertStatement.new + @ast = Nodes::InsertStatement.new end def into table - @head.relation = table + @ast.relation = table self end - def columns; @head.columns end - def values= val; @head.values = val; end + def columns; @ast.columns end + def values= val; @ast.values = val; end def insert fields return if fields.empty? if String === fields - @head.values = SqlLiteral.new(fields) + @ast.values = SqlLiteral.new(fields) else - @head.relation ||= fields.first.first.relation + @ast.relation ||= fields.first.first.relation values = [] fields.each do |column, value| - @head.columns << column + @ast.columns << column values << value end - @head.values = Nodes::Values.new values, @head.columns + @ast.values = Nodes::Values.new values, @ast.columns end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 7c3c67b477cf6..f2520f38d73bf 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -4,13 +4,13 @@ class SelectManager < Arel::TreeManager def initialize engine, table = nil super(engine) - @head = Nodes::SelectStatement.new - @ctx = @head.cores.last + @ast = Nodes::SelectStatement.new + @ctx = @ast.cores.last from table end def taken - @head.limit + @ast.limit end def constraints @@ -18,7 +18,7 @@ def constraints end def skip amount - @head.offset = Nodes::Offset.new(amount) + @ast.offset = Nodes::Offset.new(amount) self end @@ -31,12 +31,12 @@ def where_clauses def lock locking = true # FIXME: do we even need to store this? If locking is +false+ shouldn't # we just remove the node from the AST? - @head.lock = Nodes::Lock.new + @ast.lock = Nodes::Lock.new self end def locked - @head.lock + @ast.lock end def on *exprs @@ -108,14 +108,14 @@ def where expr def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically - @head.orders.concat expr.map { |x| + @ast.orders.concat expr.map { |x| String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x } self end def orders - @head.orders + @ast.orders end def wheres @@ -130,7 +130,7 @@ def where_sql end def take limit - @head.limit = limit + @ast.limit = limit self end @@ -142,7 +142,7 @@ def join_sql end def order_clauses - Visitors::OrderClauses.new(@engine).accept(@head).map { |x| + Visitors::OrderClauses.new(@engine).accept(@ast).map { |x| Nodes::SqlLiteral.new x } end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 077458fe18b11..ca87def8d66ca 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -4,6 +4,7 @@ class TreeManager include Arel::Relation attr_accessor :visitor + attr_reader :ast def initialize engine @engine = engine @@ -11,16 +12,16 @@ def initialize engine end def to_dot - Visitors::Dot.new.accept @head + Visitors::Dot.new.accept @ast end def to_sql - @visitor.accept @head + @visitor.accept @ast end def initialize_copy other super - @head = @head.clone + @ast = @ast.clone end end end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 3f6a48375103a..c0fb4fbd5f675 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -2,40 +2,40 @@ module Arel class UpdateManager < Arel::TreeManager def initialize engine super - @head = Nodes::UpdateStatement.new + @ast = Nodes::UpdateStatement.new end def take limit - @head.limit = limit + @ast.limit = limit self end def order *expr - @head.orders = expr + @ast.orders = expr self end ### # UPDATE +table+ def table table - @head.relation = table + @ast.relation = table self end def wheres= exprs - @head.wheres = exprs + @ast.wheres = exprs end def where expr - @head.wheres << expr + @ast.wheres << expr self end def set values if String === values - @head.values = [values] + @ast.values = [values] else - @head.values = values.map { |column,value| + @ast.values = values.map { |column,value| Nodes::Assignment.new( Nodes::UnqualifiedColumn.new(column), value diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 50f04a1a58b54..ebec92b1da242 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -130,6 +130,15 @@ def execute sql, name = nil, *args 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 + end + describe 'taken' do it 'should return limit' do manager = Arel::SelectManager.new Table.engine From 22a38c6a86bc6323f7aa1fd3179a9f8ed7591267 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 14:28:36 -0700 Subject: [PATCH 0827/1492] mysql selects from dual on empty from statements --- lib/arel/visitors/mysql.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 1 + test/visitors/test_mysql.rb | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 594fd5504ad1a..afffd37f9b6a0 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -10,6 +10,11 @@ def visit_Arel_Nodes_SelectStatement o 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}", diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 1412797fb5f09..3c96b3e259ea3 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -48,6 +48,7 @@ def visit_Arel_Nodes_UpdateStatement o ("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}", diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 1d38161caf0d7..871d662d4b59d 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -14,7 +14,13 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) sql = @visitor.accept(stmt) - sql.must_be_like "SELECT LIMIT 18446744073709551615 OFFSET 1" + sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1" + end + + it 'uses DUAL for empty from' do + stmt = Nodes::SelectStatement.new + sql = @visitor.accept(stmt) + sql.must_be_like "SELECT FROM DUAL" end end end From dbd0140974ed768705f3680d5d6e47a56305b965 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 5 Nov 2010 16:33:26 -0700 Subject: [PATCH 0828/1492] arel more nicely supports EXISTS queries --- lib/arel/nodes/exists.rb | 8 ++------ lib/arel/select_manager.rb | 6 ++++++ lib/arel/tree_manager.rb | 2 +- lib/arel/visitors/to_sql.rb | 3 ++- test/test_select_manager.rb | 28 ++++++++++++++++++++++------ 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/arel/nodes/exists.rb b/lib/arel/nodes/exists.rb index 167a345006cb4..18ba8403b44fa 100644 --- a/lib/arel/nodes/exists.rb +++ b/lib/arel/nodes/exists.rb @@ -1,11 +1,7 @@ module Arel module Nodes - class Exists - attr_reader :select_stmt - - def initialize select_stmt - @select_stmt = select_stmt - end + class Exists < Arel::Nodes::Function + alias :select_stmt :expressions end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f2520f38d73bf..f6738bf26f92f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -22,6 +22,12 @@ def skip amount self end + ### + # Produces an Arel::Nodes::Exists node + def exists + Arel::Nodes::Exists.new @ast + end + def where_clauses #warn "where_clauses is deprecated" if $VERBOSE to_sql = Visitors::ToSql.new @engine diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index ca87def8d66ca..6176f8a2509c5 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -4,7 +4,7 @@ class TreeManager include Arel::Relation attr_accessor :visitor - attr_reader :ast + attr_reader :ast, :engine def initialize engine @engine = engine diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 3c96b3e259ea3..b6af47cc57817 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -62,7 +62,8 @@ def visit_Arel_Nodes_InsertStatement o end def visit_Arel_Nodes_Exists o - "EXISTS (#{visit o.select_stmt})" + "EXISTS (#{visit o.select_stmt})#{ + o.alias ? " AS #{visit o.alias}" : ''}" end def visit_Arel_Nodes_Values o diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index ebec92b1da242..d63bec009339e 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -56,9 +56,7 @@ def execute sql, name = nil, *args manager.project SqlLiteral.new '*' manager.from table manager.order :foo - manager.to_sql.must_be_like %{ - SELECT * FROM "users" ORDER BY foo - } + manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo } end end @@ -68,9 +66,7 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from table manager.group :foo - manager.to_sql.must_be_like %{ - SELECT FROM "users" GROUP BY foo - } + manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } end end @@ -130,6 +126,26 @@ def execute sql, name = nil, *args 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 'ast' do it 'should return the ast' do table = Table.new :users From 64b8765c22222821911f0018e30b03f80112a1f1 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Sat, 6 Nov 2010 19:11:23 +0200 Subject: [PATCH 0829/1492] fix order_hacks method for Oracle when complex functions are used in order by --- lib/arel/visitors/oracle.rb | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 212c18ada435d..bb6ebd4ab85f8 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -70,7 +70,23 @@ def order_hacks o /DISTINCT.*FIRST_VALUE/ === projection end end - orders = o.orders.map { |x| visit x }.join(', ').split(',') + # FIXME: previous version with join and split broke ORDER BY clause + # if it contained functions with several arguments (separated by ','). + # Currently splitting is done only if there is no function calls + # + # orders = o.orders.map { |x| visit x }.join(', ').split(',') + orders = o.orders.map do |x| + string = visit x + # if there is function call + if string.include?('(') + string + # if no function call then comma splits several ORDER BY columns + elsif string.include?(',') + string.split(',') + else + string + end + end.flatten o.orders = [] orders.each_with_index do |order, i| o.orders << From 2bf0b217545527b5eb85a11e297d0ff2dfc676e3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 11 Nov 2010 10:52:51 -0600 Subject: [PATCH 0830/1492] support stringinquirer string --- lib/arel/visitors/to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b6af47cc57817..f9d252f980ed7 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -280,6 +280,7 @@ def visit_String o; quote(o, @last_column) end alias :visit_Time :visit_String alias :visit_TrueClass :visit_String alias :visit_NilClass :visit_String + alias :visit_ActiveSupport_StringInquirer :visit_String def quote value, column = nil @connection.quote value, column From 8cf194bbc91a87cae8772b9942ff18351dab7133 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 11 Nov 2010 10:54:55 -0600 Subject: [PATCH 0831/1492] updating changelog --- History.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/History.txt b/History.txt index 7a664367096c7..e5513ecb01788 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,15 @@ +== 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 From 66a73cfd320f84c15fe064d70fafd14c0ab629cf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 11 Nov 2010 10:55:47 -0600 Subject: [PATCH 0832/1492] updating manifest / gemspec --- Manifest.txt | 1 + arel.gemspec | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 1ea5768f06b70..89b6d37c0bb09 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -59,6 +59,7 @@ lib/arel/nodes/table_alias.rb lib/arel/nodes/unqualified_column.rb lib/arel/nodes/update_statement.rb lib/arel/nodes/values.rb +lib/arel/predications.rb lib/arel/relation.rb lib/arel/select_manager.rb lib/arel/sql/engine.rb diff --git a/arel.gemspec b/arel.gemspec index 2549936888655..bf72905ef63c7 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,15 +2,15 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.1.20101020171639" + s.version = "2.0.1.20101111105523" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2010-10-20} + s.date = %q{2010-11-11} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/predications.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] @@ -25,19 +25,22 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, [">= 2.0.4"]) - s.add_development_dependency(%q, [">= 1.7.2"]) - s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 2.0.0.beta"]) + s.add_development_dependency(%q, [">= 2.1.0"]) + s.add_development_dependency(%q, [">= 1.6.0"]) s.add_development_dependency(%q, [">= 2.6.2"]) else s.add_dependency(%q, [">= 2.0.4"]) - s.add_dependency(%q, [">= 1.7.2"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2.0.0.beta"]) + s.add_dependency(%q, [">= 2.1.0"]) + s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.6.2"]) end else s.add_dependency(%q, [">= 2.0.4"]) - s.add_dependency(%q, [">= 1.7.2"]) - s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 2.0.0.beta"]) + s.add_dependency(%q, [">= 2.1.0"]) + s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.6.2"]) end end From fd7c508fcc62d61162a201636d3a2b595c2e8ccd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 11 Nov 2010 10:57:08 -0600 Subject: [PATCH 0833/1492] terrorist version bump --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index bcf71c05ddc4b..8592cead48ebd 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -28,7 +28,7 @@ #### module Arel - VERSION = '2.0.1' + VERSION = '2.0.2' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From ee30881b5aa0a545e6624bd343ae2646061e7107 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 11 Nov 2010 11:11:10 -0600 Subject: [PATCH 0834/1492] bumping gemspec version --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index bf72905ef63c7..5f6aca97efc8c 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.1.20101111105523" + s.version = "2.0.2.20101111111102" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] From 237e580c4920b2414ef1bb72c14250688b479b9e Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Tue, 16 Nov 2010 12:45:29 +0200 Subject: [PATCH 0835/1492] fix one more time order_hacks method for Oracle correctly split order string by commas ignoring commas which separate function arguments --- lib/arel/visitors/oracle.rb | 25 +++++++++++++++++-------- test/visitors/test_oracle.rb | 12 ++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index bb6ebd4ab85f8..00572213e64a0 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -70,19 +70,14 @@ def order_hacks o /DISTINCT.*FIRST_VALUE/ === projection end end - # FIXME: previous version with join and split broke ORDER BY clause + # Previous version with join and split broke ORDER BY clause # if it contained functions with several arguments (separated by ','). - # Currently splitting is done only if there is no function calls # # orders = o.orders.map { |x| visit x }.join(', ').split(',') orders = o.orders.map do |x| string = visit x - # if there is function call - if string.include?('(') - string - # if no function call then comma splits several ORDER BY columns - elsif string.include?(',') - string.split(',') + if string.include?(',') + split_order_string(string) else string end @@ -94,6 +89,20 @@ def order_hacks o 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| + array[i] ||= "" + array[i] << part + i += 1 if array[i].count('(') == array[i].count(')') + end + array + end + end end end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index d2a73ea8c54ed..2c9bba15d8b1b 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -43,6 +43,18 @@ module Visitors } 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 From 206ec83ced0097a97f431a8fe20d4fcbd8fdd4d5 Mon Sep 17 00:00:00 2001 From: Raimonds Simanovskis Date: Tue, 16 Nov 2010 13:53:06 +0200 Subject: [PATCH 0836/1492] small additional fix for order_hacks method for Oracle --- lib/arel/visitors/oracle.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 00572213e64a0..ecb157f8bce9d 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -96,8 +96,12 @@ def split_order_string(string) array = [] i = 0 string.split(',').each do |part| - array[i] ||= "" - array[i] << 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 From f0139a16c263ba62e7e45d462a4fff411ebf2523 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Nov 2010 08:09:26 -0800 Subject: [PATCH 0837/1492] returning undefined for unknown column types --- lib/arel/attributes.rb | 2 +- lib/arel/attributes/attribute.rb | 13 +++++++------ test/test_attributes.rb | 5 +++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/arel/attributes.rb b/lib/arel/attributes.rb index a7fb00293b130..92cc041f83035 100644 --- a/lib/arel/attributes.rb +++ b/lib/arel/attributes.rb @@ -13,7 +13,7 @@ def self.for column when :date, :datetime, :timestamp, :time then Time when :boolean then Boolean else - raise NotImplementedError, "Column type `#{column.type}` is not currently handled" + Undefined end end end diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index e027a65a74e53..5cbe194b41ece 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -5,12 +5,13 @@ class Attribute < Struct.new :relation, :name, :column include Arel::Predications 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 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 diff --git a/test/test_attributes.rb b/test/test_attributes.rb index 8fc9327b0fad7..3654e78314400 100644 --- a/test/test_attributes.rb +++ b/test/test_attributes.rb @@ -3,6 +3,11 @@ module Arel describe 'Attributes' do 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 From ac38fcae4997d4cf6480820542ac2a4a1801b014 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Nov 2010 08:15:58 -0800 Subject: [PATCH 0838/1492] added a visitor for Class objects --- History.txt | 7 +++++++ lib/arel/visitors/to_sql.rb | 1 + test/visitors/test_to_sql.rb | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/History.txt b/History.txt index e5513ecb01788..c7086686bf57e 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,10 @@ +== 2.0.3 + +* Bug fixes + + * Fixing Oracle support + * Added a visitor for "Class" objects + == 2.0.2 * Bug fixes diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f9d252f980ed7..528c5f6cedaad 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -281,6 +281,7 @@ def visit_String o; quote(o, @last_column) end alias :visit_TrueClass :visit_String alias :visit_NilClass :visit_String alias :visit_ActiveSupport_StringInquirer :visit_String + alias :visit_Class :visit_String def quote value, column = nil @connection.quote value, column diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 8723332005f92..8715531bdac07 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -21,6 +21,10 @@ module Visitors end end + it "should visit_Class" do + @visitor.accept(DateTime).must_equal "'DateTime'" + end + it "should visit_DateTime" do @visitor.accept DateTime.now end From 4fdae4aac54f100698a4fd48961a60864fda21a9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Nov 2010 08:19:28 -0800 Subject: [PATCH 0839/1492] terrorist version bump --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 8592cead48ebd..f75326c9a347b 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -28,7 +28,7 @@ #### module Arel - VERSION = '2.0.2' + VERSION = '2.0.3' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From f127338049f7317c238da71fc21b4f318c115a6c Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Wed, 17 Nov 2010 08:26:48 +0800 Subject: [PATCH 0840/1492] Let table_exists? find tables in @@table_cache even if symbols are passed as their names --- lib/arel/table.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 61210dae767bc..83d0951453e34 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -8,7 +8,7 @@ class << self; attr_accessor :engine; end attr_accessor :name, :engine, :aliases, :table_alias def initialize name, engine = Table.engine - @name = name + @name = name.to_s @engine = engine @columns = nil @aliases = [] @@ -22,7 +22,7 @@ def initialize name, 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.to_s + @table_alias = engine[:as] unless engine[:as].to_s == name end end From 9ef7afda3beaab7979490665fe2648639ab91e1c Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Wed, 17 Nov 2010 08:47:34 +0800 Subject: [PATCH 0841/1492] Fix a bit the initialization of Table --- lib/arel/table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 83d0951453e34..fe12427d1bd1a 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -22,7 +22,7 @@ def initialize name, 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 + @table_alias = engine[:as] unless engine[:as].to_s == @name end end From 56ce36fb775173199da3eb142aa1f729aeed956f Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Wed, 17 Nov 2010 10:10:07 +0800 Subject: [PATCH 0842/1492] Write a test for checking the presence of table names in the cache --- .gitignore | 3 ++- test/test_table.rb | 13 ++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 30bd888ba613e..93a12f1c3d634 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ spec/support/fixtures/*database* *.DS_Store debug.log pkg -.bundle \ No newline at end of file +.bundle +*.swp diff --git a/test/test_table.rb b/test/test_table.rb index 0dbb3f8dd183a..2802ef9144139 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -156,7 +156,7 @@ module Arel end it "should have a name" do - @relation.name.must_equal :users + @relation.name.must_equal 'users' end it "should have an engine" do @@ -179,4 +179,15 @@ module Arel end end end + + describe Table do + describe 'when checking existence of a table' do + it 'should be precent in the table cache despite the class of its name' do + [ 'users', :users ].each do |name| + relation = Table.new name + relation.send(:tables).key?(relation.name).must_equal true + end + end + end + end end From 120751d2d482119f688c44d20bda78e7f4abc8f6 Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Wed, 17 Nov 2010 10:19:29 +0800 Subject: [PATCH 0843/1492] Fix typos in the description of the test --- test/test_table.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_table.rb b/test/test_table.rb index 2802ef9144139..c2d7f5e98fb02 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -181,8 +181,8 @@ module Arel end describe Table do - describe 'when checking existence of a table' do - it 'should be precent in the table cache despite the class of its name' do + describe 'when checking the existence of a table' do + it 'should be present in the table cache despite the class of its name' do [ 'users', :users ].each do |name| relation = Table.new name relation.send(:tables).key?(relation.name).must_equal true From 7c9845e770b2dd2c9875a43e9258c47a74ce1bed Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Nov 2010 20:53:35 -0800 Subject: [PATCH 0844/1492] do not use private methods --- test/test_table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_table.rb b/test/test_table.rb index c2d7f5e98fb02..8d37a8eaff7d6 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -185,7 +185,7 @@ module Arel it 'should be present in the table cache despite the class of its name' do [ 'users', :users ].each do |name| relation = Table.new name - relation.send(:tables).key?(relation.name).must_equal true + Table.table_cache(relation.engine).key?(relation.name).must_equal true end end end From 35f25f643cca00c192d971234942d5a0d0e07cc0 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 17 Nov 2010 22:18:25 +0800 Subject: [PATCH 0845/1492] Added tests for Nodes::NotIn. --- test/visitors/test_to_sql.rb | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 8715531bdac07..b84730eeb491a 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -132,6 +132,52 @@ def quote value, column = nil 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 turn empty right to NULL" do + node = @attr.not_in [] + @visitor.accept(node).must_be_like %{ + "users"."id" NOT IN (NULL) + } + 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 '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) + visitor.expected = @attr.column + 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' From 9244e2ddbd5dbfb32f892bdfc23a928aa06999a5 Mon Sep 17 00:00:00 2001 From: Rolf Timmermans Date: Wed, 17 Nov 2010 22:23:33 +0800 Subject: [PATCH 0846/1492] Fixed Ruby 1.8 performance regression for Nodes::In and Nodes::NotIn queries with very wide ranges that was caused by using Range#min and Range#max rather than Range#begin and Range#end. Ruby 1.8 uses Enumerable#min and Enumerable#max in Ranges, which calls to_a internally. It is not necessary to enumerate the range in order to construct the predicates. At the same time, an off-by-one error (failing test) with exclusive-end Ranges in Nodes::NotIn queries was fixed. --- lib/arel/predications.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 8a8960f0b1880..03cbb7aa3f05e 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -30,11 +30,11 @@ def in other Nodes::In.new self, other.to_a.map { |x| x.id } when Range if other.exclude_end? - left = Nodes::GreaterThanOrEqual.new(self, other.min) - right = Nodes::LessThan.new(self, other.max + 1) + 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.min, other.max)) + Nodes::Between.new(self, Nodes::And.new(other.begin, other.end)) end else Nodes::In.new self, other @@ -55,12 +55,12 @@ def not_in other Nodes::NotIn.new self, other.to_a.map { |x| x.id } when Range if other.exclude_end? - left = Nodes::LessThan.new(self, other.min) - right = Nodes::GreaterThanOrEqual.new(self, other.max) + 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.min) - right = Nodes::GreaterThan.new(self, other.max) + left = Nodes::LessThan.new(self, other.begin) + right = Nodes::GreaterThan.new(self, other.end) Nodes::Or.new left, right end else From 49bc292484dcf601b9fa34a4160879d026dcfa18 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 08:38:35 -0800 Subject: [PATCH 0847/1492] updating changelog --- History.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/History.txt b/History.txt index c7086686bf57e..dce98b061b3df 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 2.0.4 + +* Bug fixes + + * Speed improvements for Range queries. Thanks Rolf Timmermans! + == 2.0.3 * Bug fixes From e55880325ed13b2ea259e362ae4ebafe6b367270 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 08:47:24 -0800 Subject: [PATCH 0848/1492] adding the git plugin --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index f9f71b4f5aec5..5590e694f1091 100644 --- a/Rakefile +++ b/Rakefile @@ -4,6 +4,7 @@ require 'hoe' Hoe.plugin :minitest Hoe.plugin :gemspec # `gem install hoe-gemspec` +Hoe.plugin :git # `gem install hoe-git` Hoe.spec 'arel' do developer('Aaron Patterson', 'aaron@tenderlovemaking.com') From 83a0222b75308e6c9881856947e4d1089f513195 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 17 Nov 2010 08:49:32 -0800 Subject: [PATCH 0849/1492] terrorist version bump --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index f75326c9a347b..7b505abaf5a06 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -28,7 +28,7 @@ #### module Arel - VERSION = '2.0.3' + VERSION = '2.0.4' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 43b0b628dad3966f3234317b4ae48bfd5547eb51 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 19 Nov 2010 08:11:43 -0800 Subject: [PATCH 0850/1492] updating the gemspec --- arel.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 5f6aca97efc8c..ab7046b8ef1d1 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.2.20101111111102" + s.version = "2.0.4.20101119081136" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2010-11-11} + s.date = %q{2010-11-19} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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"] From 3e928ee400d083e7391474c61c8fcef74f0c848a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Nov 2010 14:28:34 -0800 Subject: [PATCH 0851/1492] mysql will lock for update --- History.txt | 6 ++++++ lib/arel/visitors/mysql.rb | 4 ++++ test/visitors/test_mysql.rb | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/History.txt b/History.txt index dce98b061b3df..af20f9d635d4a 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 2.0.5 (unreleased) + +* Bug fixes + + * #lock will lock SELECT statements "FOR UPDATE" on mysql + == 2.0.4 * Bug fixes diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index afffd37f9b6a0..143b4d36f4aba 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,6 +2,10 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql private + def visit_Arel_Nodes_Lock o + "FOR UPDATE" + end + ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 871d662d4b59d..8606dc39d4ab9 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -22,6 +22,13 @@ module Visitors sql = @visitor.accept(stmt) sql.must_be_like "SELECT FROM DUAL" end + + it 'uses FOR UPDATE when locking' do + stmt = Nodes::SelectStatement.new + stmt.lock = Nodes::Lock.new + sql = @visitor.accept(stmt) + sql.must_be_like "SELECT FROM DUAL FOR UPDATE" + end end end end From 76932b99d60b28f93c88c9a95873ba8524c9e370 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 16:24:41 -0800 Subject: [PATCH 0852/1492] adding a "not" factory method for creating Not nodes --- History.txt | 1 + Manifest.txt | 2 ++ lib/arel/nodes.rb | 1 + lib/arel/nodes/node.rb | 7 +++++++ lib/arel/nodes/not.rb | 11 +++++++++++ lib/arel/visitors/to_sql.rb | 4 ++++ test/nodes/test_not.rb | 20 ++++++++++++++++++++ test/visitors/test_to_sql.rb | 5 +++++ 8 files changed, 51 insertions(+) create mode 100644 lib/arel/nodes/not.rb create mode 100644 test/nodes/test_not.rb diff --git a/History.txt b/History.txt index af20f9d635d4a..328fe6ba8bf7f 100644 --- a/History.txt +++ b/History.txt @@ -3,6 +3,7 @@ * Bug fixes * #lock will lock SELECT statements "FOR UPDATE" on mysql + * Nodes::Node#not factory method added for creating Nodes::Not nodes == 2.0.4 diff --git a/Manifest.txt b/Manifest.txt index 89b6d37c0bb09..c9cd045b75558 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -43,6 +43,7 @@ lib/arel/nodes/matches.rb lib/arel/nodes/max.rb lib/arel/nodes/min.rb lib/arel/nodes/node.rb +lib/arel/nodes/not.rb lib/arel/nodes/not_equal.rb lib/arel/nodes/not_in.rb lib/arel/nodes/offset.rb @@ -84,6 +85,7 @@ test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_equality.rb test/nodes/test_insert_statement.rb +test/nodes/test_not.rb test/nodes/test_or.rb test/nodes/test_select_core.rb test/nodes/test_select_statement.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 47cbd64eb5ee3..2affd01fa8389 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -6,6 +6,7 @@ require 'arel/nodes/assignment' require 'arel/nodes/or' require 'arel/nodes/and' +require 'arel/nodes/not' require 'arel/nodes/greater_than' require 'arel/nodes/greater_than_or_equal' require 'arel/nodes/less_than' diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 43bad19488715..841b954db9ee5 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -3,6 +3,13 @@ module Nodes ### # Abstract base class for all AST nodes class Node + ### + # 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. diff --git a/lib/arel/nodes/not.rb b/lib/arel/nodes/not.rb new file mode 100644 index 0000000000000..d463ae9d08605 --- /dev/null +++ b/lib/arel/nodes/not.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Not < Arel::Nodes::Node + attr_reader :expr + + def initialize expr + @expr = expr + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 528c5f6cedaad..bbc1eb3105533 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -191,6 +191,10 @@ 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}" diff --git a/test/nodes/test_not.rb b/test/nodes/test_not.rb new file mode 100644 index 0000000000000..7dffdea0c8bd0 --- /dev/null +++ b/test/nodes/test_not.rb @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'not' do + describe '#not' do + it 'makes a NOT 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 + + knot = node.or(right).not + end + end + end + end +end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b84730eeb491a..89f3f60de27e3 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -33,6 +33,11 @@ module Visitors @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 visit_Bignum" do @visitor.accept 8787878092 end From 6667cfb995a49bffe66231a7ffc5a78ca7f5140f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 23 Nov 2010 18:22:42 -0800 Subject: [PATCH 0853/1492] adding an AS node --- History.txt | 1 + Manifest.txt | 2 ++ lib/arel/nodes.rb | 1 + lib/arel/nodes/as.rb | 6 ++++++ lib/arel/predications.rb | 6 +++++- lib/arel/visitors/to_sql.rb | 4 ++++ test/nodes/test_as.rb | 16 ++++++++++++++++ test/visitors/test_to_sql.rb | 6 ++++++ 8 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/as.rb create mode 100644 test/nodes/test_as.rb diff --git a/History.txt b/History.txt index 328fe6ba8bf7f..5e7ce2ee681c5 100644 --- a/History.txt +++ b/History.txt @@ -4,6 +4,7 @@ * #lock will lock SELECT statements "FOR UPDATE" on mysql * Nodes::Node#not factory method added for creating Nodes::Not nodes + * Added an As node == 2.0.4 diff --git a/Manifest.txt b/Manifest.txt index c9cd045b75558..91de70ff107b3 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -17,6 +17,7 @@ lib/arel/expressions.rb lib/arel/insert_manager.rb lib/arel/nodes.rb lib/arel/nodes/and.rb +lib/arel/nodes/as.rb lib/arel/nodes/assignment.rb lib/arel/nodes/avg.rb lib/arel/nodes/between.rb @@ -81,6 +82,7 @@ lib/arel/visitors/visitor.rb lib/arel/visitors/where_sql.rb test/attributes/test_attribute.rb test/helper.rb +test/nodes/test_as.rb test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_equality.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 2affd01fa8389..95dcc0480ecb4 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -6,6 +6,7 @@ require 'arel/nodes/assignment' require 'arel/nodes/or' require 'arel/nodes/and' +require 'arel/nodes/as' require 'arel/nodes/not' require 'arel/nodes/greater_than' require 'arel/nodes/greater_than_or_equal' diff --git a/lib/arel/nodes/as.rb b/lib/arel/nodes/as.rb new file mode 100644 index 0000000000000..9009fe12f4654 --- /dev/null +++ b/lib/arel/nodes/as.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class As < Arel::Nodes::Binary + end + end +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 03cbb7aa3f05e..5a5c3d449563e 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,5 +1,9 @@ module Arel module Predications + def as other + Nodes::As.new self, other + end + def not_eq other Nodes::NotEqual.new self, other end @@ -174,4 +178,4 @@ def grouping_all method_id, others } end end -end \ No newline at end of file +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index bbc1eb3105533..ae90c0c4b69b4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -250,6 +250,10 @@ def visit_Arel_Nodes_NotEqual o 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 diff --git a/test/nodes/test_as.rb b/test/nodes/test_as.rb new file mode 100644 index 0000000000000..8585fbc963dbb --- /dev/null +++ b/test/nodes/test_as.rb @@ -0,0 +1,16 @@ +require 'helper' + +module Arel + module Nodes + describe 'As' do + describe '#as' do + it 'makes an AS node' do + attr = Table.new(:users)[:id] + as = attr.as(Arel.sql('foo')) + assert_equal attr, as.left + assert_equal 'foo', as.right + end + end + end + end +end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 89f3f60de27e3..037fca9931e37 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -38,6 +38,12 @@ module Visitors sql.must_be_like "NOT foo" 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 From f092ae544f58255508242a5308c456d9b8a13b0c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 24 Nov 2010 12:01:05 -0800 Subject: [PATCH 0854/1492] make table aliases cheaper to allocate --- lib/arel/nodes/table_alias.rb | 8 ++------ lib/arel/table.rb | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 7ec1fad272277..60da7b19f3833 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -1,20 +1,16 @@ module Arel module Nodes class TableAlias - attr_reader :name, :relation, :columns + attr_reader :name, :relation alias :table_alias :name def initialize name, relation @name = name @relation = relation - @columns = relation.columns.map { |column| - column.dup.tap { |col| col.relation = self } - } end def [] name - name = name.to_sym - columns.find { |column| column.name == name } + Attribute.new self, name end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index fe12427d1bd1a..6f29a02e562fd 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -34,8 +34,8 @@ def primary_key end end - def alias - Nodes::TableAlias.new("#{name}_2", self).tap do |node| + def alias name = "#{self.name}_2" + Nodes::TableAlias.new(name, self).tap do |node| @aliases << node end end From c86c37e5f32ca76fa7aa77e62018e368dbb37a54 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 14:11:28 -0800 Subject: [PATCH 0855/1492] mostly implemented depth-first traversal --- lib/arel/nodes/node.rb | 7 +++ lib/arel/visitors.rb | 1 + lib/arel/visitors/depth_first.rb | 75 ++++++++++++++++++++++++++++++ test/visitors/test_depth_first.rb | 76 +++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 lib/arel/visitors/depth_first.rb create mode 100644 test/visitors/test_depth_first.rb diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 841b954db9ee5..90c63f0be9023 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -3,6 +3,8 @@ module Nodes ### # Abstract base class for all AST nodes class Node + include Enumerable + ### # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. @@ -32,6 +34,11 @@ def to_sql engine = Table.engine viz = Visitors.for engine viz.accept self end + + # Iterate through AST, nodes will be yielded depth-first + def each &block + Visitors::DepthFirst.new(block).accept self + end end end end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 5d4c6084b225e..2b0a06d5340f4 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -1,4 +1,5 @@ require 'arel/visitors/visitor' +require 'arel/visitors/depth_first' require 'arel/visitors/to_sql' require 'arel/visitors/sqlite' require 'arel/visitors/postgresql' diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb new file mode 100644 index 0000000000000..19796b6e72367 --- /dev/null +++ b/lib/arel/visitors/depth_first.rb @@ -0,0 +1,75 @@ +module Arel + module Visitors + class DepthFirst < Arel::Visitors::Visitor + def initialize block = nil + @block = block || Proc.new + end + + private + + def binary o + visit o.left + visit o.right + @block.call o + end + alias :visit_Arel_Nodes_And :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_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 + + def visit_Arel_Attribute o + visit o.relation + visit o.name + @block.call o + 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 visit_Arel_Table o + visit o.name + @block.call o + end + + def terminal o + @block.call o + end + alias :visit_Arel_Nodes_SqlLiteral :terminal + alias :visit_Arel_SqlLiteral :terminal + alias :visit_BigDecimal :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_Array o + o.each { |i| visit i } + @block.call o + end + + def visit_Hash o + o.each { |k,v| visit(k); visit(v) } + @block.call o + end + end + end +end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb new file mode 100644 index 0000000000000..eff60576fc36b --- /dev/null +++ b/test/visitors/test_depth_first.rb @@ -0,0 +1,76 @@ +require '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 + + [ + Arel::Nodes::And, + 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, + ].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 + + [ + 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 + end + end +end From 20cd623aba6cc0c1b08b7d6fcf277633cfe236d4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 14:15:58 -0800 Subject: [PATCH 0856/1492] update statement supported --- lib/arel/visitors/depth_first.rb | 9 +++++++++ test/visitors/test_depth_first.rb | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 19796b6e72367..8ff4b4d16248d 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -61,6 +61,15 @@ def terminal o alias :visit_Time :terminal alias :visit_TrueClass :terminal + def visit_Arel_Nodes_UpdateStatement o + visit o.relation + visit o.values + visit o.wheres + visit o.orders + visit o.limit + @block.call o + end + def visit_Array o o.each { |i| visit i } @block.call o diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index eff60576fc36b..fd91dd5fb9964 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -71,6 +71,19 @@ def test_hash @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 end end end From 61e0280b5d5cd36a5340ba8478d0bc1c9c5fea41 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 14:23:58 -0800 Subject: [PATCH 0857/1492] adding select core --- lib/arel/visitors/depth_first.rb | 9 +++++++++ test/visitors/test_depth_first.rb | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 8ff4b4d16248d..5c89ef96b36c5 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -61,6 +61,15 @@ def terminal o alias :visit_Time :terminal alias :visit_TrueClass :terminal + def visit_Arel_Nodes_SelectCore o + visit o.projections + visit o.froms + visit o.wheres + visit o.groups + visit o.having + @block.call o + end + def visit_Arel_Nodes_UpdateStatement o visit o.relation visit o.values diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index fd91dd5fb9964..a318583e26a50 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -84,6 +84,24 @@ def test_update_statement 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.having = :e + + @visitor.accept core + assert_equal [ + :a, core.projections, + :b, + :c, core.wheres, + :d, core.groups, + :e, + core], @collector.calls + end end end end From 4b91cbc688b2fdc09a4a67a018c6bcb773934ea1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 14:26:53 -0800 Subject: [PATCH 0858/1492] adding select statement support --- lib/arel/visitors/depth_first.rb | 9 +++++++++ test/visitors/test_depth_first.rb | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 5c89ef96b36c5..534f9edaf55ae 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -70,6 +70,15 @@ def visit_Arel_Nodes_SelectCore o @block.call o end + def visit_Arel_Nodes_SelectStatement o + visit o.cores + visit o.orders + visit o.limit + visit o.lock + visit o.offset + @block.call o + end + def visit_Arel_Nodes_UpdateStatement o visit o.relation visit o.values diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index a318583e26a50..04c5096f5b10b 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -102,6 +102,24 @@ def test_select_core :e, 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 end end end From ad16c18cc3a7db4b56611b9244140f0b495a1214 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 14:30:06 -0800 Subject: [PATCH 0859/1492] insert statements supported --- lib/arel/nodes/insert_statement.rb | 2 +- lib/arel/nodes/select_statement.rb | 2 +- lib/arel/visitors/depth_first.rb | 7 +++++++ test/visitors/test_depth_first.rb | 10 ++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index a5e1a0bb9bc50..37c12f011a98f 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class InsertStatement + class InsertStatement < Arel::Nodes::Node attr_accessor :relation, :columns, :values def initialize diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 371fd7bf21465..6881a667474cb 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class SelectStatement + class SelectStatement < Arel::Nodes::Node attr_reader :cores attr_accessor :limit, :orders, :lock, :offset diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 534f9edaf55ae..d6d3984ce2054 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -61,6 +61,13 @@ def terminal o alias :visit_Time :terminal alias :visit_TrueClass :terminal + def visit_Arel_Nodes_InsertStatement o + visit o.relation + visit o.columns + visit o.values + @block.call o + end + def visit_Arel_Nodes_SelectCore o visit o.projections visit o.froms diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 04c5096f5b10b..32778f7d4b96f 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -120,6 +120,16 @@ def test_select_statement :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 end end end From 963ca860d579a507effbe818da0c89bf443f33c9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 14:38:45 -0800 Subject: [PATCH 0860/1492] adding unary node --- lib/arel/nodes.rb | 1 + lib/arel/nodes/group.rb | 7 +------ lib/arel/nodes/grouping.rb | 7 +------ lib/arel/nodes/having.rb | 7 +------ lib/arel/nodes/offset.rb | 8 ++------ lib/arel/nodes/ordering.rb | 9 +++++---- lib/arel/nodes/unary.rb | 11 +++++++++++ lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_depth_first.rb | 3 +++ 9 files changed, 26 insertions(+), 29 deletions(-) create mode 100644 lib/arel/nodes/unary.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 95dcc0480ecb4..c454152d0d98b 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,4 +1,5 @@ require 'arel/nodes/node' +require 'arel/nodes/unary' require 'arel/nodes/binary' require 'arel/nodes/equality' require 'arel/nodes/between' diff --git a/lib/arel/nodes/group.rb b/lib/arel/nodes/group.rb index 57a7c579da2a0..a7fa6f170dd03 100644 --- a/lib/arel/nodes/group.rb +++ b/lib/arel/nodes/group.rb @@ -1,11 +1,6 @@ module Arel module Nodes - class Group - attr_accessor :expr - - def initialize expr - @expr = expr - end + class Group < Arel::Nodes::Unary end end end diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb index d52671f169d82..18adeae97f28f 100644 --- a/lib/arel/nodes/grouping.rb +++ b/lib/arel/nodes/grouping.rb @@ -1,11 +1,6 @@ module Arel module Nodes - class Grouping < Arel::Nodes::Node - attr_accessor :expr - - def initialize expression - @expr = expression - end + class Grouping < Arel::Nodes::Unary end end end diff --git a/lib/arel/nodes/having.rb b/lib/arel/nodes/having.rb index 1944a843919c3..6972c58ddabaf 100644 --- a/lib/arel/nodes/having.rb +++ b/lib/arel/nodes/having.rb @@ -1,11 +1,6 @@ module Arel module Nodes - class Having - attr_accessor :expr - - def initialize expr - @expr = expr - end + class Having < Arel::Nodes::Unary end end end diff --git a/lib/arel/nodes/offset.rb b/lib/arel/nodes/offset.rb index baa4068d935c0..d93e46aa1fde0 100644 --- a/lib/arel/nodes/offset.rb +++ b/lib/arel/nodes/offset.rb @@ -1,11 +1,7 @@ module Arel module Nodes - class Offset - attr_accessor :value - - def initialize value - @value = value - end + class Offset < Arel::Nodes::Unary + alias :value :expr end end end diff --git a/lib/arel/nodes/ordering.rb b/lib/arel/nodes/ordering.rb index d395c8631d0bc..0a3621cf5434c 100644 --- a/lib/arel/nodes/ordering.rb +++ b/lib/arel/nodes/ordering.rb @@ -1,10 +1,11 @@ module Arel module Nodes - class Ordering < Arel::Nodes::Node - attr_accessor :expr, :direction + class Ordering < Arel::Nodes::Binary + alias :expr :left + alias :direction :right - def initialize expression, direction = :asc - @expr, @direction = expression, direction + def initialize expr, direction = :asc + super end def ascending? diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb new file mode 100644 index 0000000000000..edda89e1f0717 --- /dev/null +++ b/lib/arel/nodes/unary.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class Unary < Arel::Nodes::Node + attr_accessor :expr + + def initialize expr + @expr = expr + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ae90c0c4b69b4..abec5317cad97 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -97,7 +97,7 @@ def visit_Arel_Nodes_Having o end def visit_Arel_Nodes_Offset o - "OFFSET #{visit o.value}" + "OFFSET #{visit o.expr}" end # FIXME: this does nothing on SQLLite3, but should do things on other diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 32778f7d4b96f..8d637c7d75269 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -130,6 +130,9 @@ def test_insert_statement @visitor.accept stmt assert_equal [:a, :b, stmt.columns, :c, stmt], @collector.calls end + + def test_offset + end end end end From 039947e5ac9c9a2e19282e3548ab7a1f30cbbc3a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 15:17:59 -0800 Subject: [PATCH 0861/1492] updating nodes and depth first visitor --- Manifest.txt | 3 ++ lib/arel/nodes/delete_statement.rb | 14 ++--- lib/arel/nodes/lock.rb | 2 +- lib/arel/nodes/not.rb | 7 +-- lib/arel/nodes/on.rb | 7 +-- lib/arel/nodes/table_alias.rb | 10 ++-- lib/arel/nodes/unqualified_column.rb | 13 ++--- lib/arel/nodes/values.rb | 10 ++-- lib/arel/visitors/depth_first.rb | 77 +++++++++++++++++++++++----- test/visitors/test_depth_first.rb | 65 +++++++++++++++++++++-- 10 files changed, 154 insertions(+), 54 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 91de70ff107b3..dbb44e5755074 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -58,6 +58,7 @@ lib/arel/nodes/sql_literal.rb lib/arel/nodes/string_join.rb lib/arel/nodes/sum.rb lib/arel/nodes/table_alias.rb +lib/arel/nodes/unary.rb lib/arel/nodes/unqualified_column.rb lib/arel/nodes/update_statement.rb lib/arel/nodes/values.rb @@ -70,6 +71,7 @@ lib/arel/table.rb lib/arel/tree_manager.rb lib/arel/update_manager.rb lib/arel/visitors.rb +lib/arel/visitors/depth_first.rb lib/arel/visitors/dot.rb lib/arel/visitors/join_sql.rb lib/arel/visitors/mysql.rb @@ -103,6 +105,7 @@ test/test_insert_manager.rb test/test_select_manager.rb test/test_table.rb test/test_update_manager.rb +test/visitors/test_depth_first.rb test/visitors/test_join_sql.rb test/visitors/test_mysql.rb test/visitors/test_oracle.rb diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index 610d69e460391..3bac8225ec905 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -1,16 +1,18 @@ module Arel module Nodes - class DeleteStatement - attr_accessor :relation, :wheres + class DeleteStatement < Arel::Nodes::Binary + alias :relation :left + alias :relation= :left= + alias :wheres :right + alias :wheres= :right= - def initialize - @from = nil - @wheres = [] + def initialize relation = nil, wheres = [] + super end def initialize_copy other super - @wheres = @wheres.clone + @right = @right.clone end end end diff --git a/lib/arel/nodes/lock.rb b/lib/arel/nodes/lock.rb index 3c7a72273f215..e5fb258e26572 100644 --- a/lib/arel/nodes/lock.rb +++ b/lib/arel/nodes/lock.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class Lock + class Lock < Arel::Nodes::Node end end end diff --git a/lib/arel/nodes/not.rb b/lib/arel/nodes/not.rb index d463ae9d08605..de138435bbf95 100644 --- a/lib/arel/nodes/not.rb +++ b/lib/arel/nodes/not.rb @@ -1,11 +1,6 @@ module Arel module Nodes - class Not < Arel::Nodes::Node - attr_reader :expr - - def initialize expr - @expr = expr - end + class Not < Arel::Nodes::Unary end end end diff --git a/lib/arel/nodes/on.rb b/lib/arel/nodes/on.rb index 4cc76b70dbcfc..953d64f9f1dd8 100644 --- a/lib/arel/nodes/on.rb +++ b/lib/arel/nodes/on.rb @@ -1,11 +1,6 @@ module Arel module Nodes - class On - attr_accessor :expr - - def initialize expr - @expr = expr - end + class On < Arel::Nodes::Unary end end end diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 60da7b19f3833..723b025883790 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -1,14 +1,10 @@ module Arel module Nodes - class TableAlias - attr_reader :name, :relation + class TableAlias < Arel::Nodes::Binary + alias :name :left + alias :relation :right alias :table_alias :name - def initialize name, relation - @name = name - @relation = relation - end - def [] name Attribute.new self, name end diff --git a/lib/arel/nodes/unqualified_column.rb b/lib/arel/nodes/unqualified_column.rb index 9882cb08e2ec2..f7ba653c1195a 100644 --- a/lib/arel/nodes/unqualified_column.rb +++ b/lib/arel/nodes/unqualified_column.rb @@ -1,18 +1,15 @@ module Arel module Nodes - class UnqualifiedColumn - attr_accessor :attribute - - def initialize attribute - @attribute = attribute - end + class UnqualifiedColumn < Arel::Nodes::Unary + alias :attribute :expr + alias :attribute= :expr= def column - @attribute.column + @expr.column end def name - @attribute.name + @expr.name end end end diff --git a/lib/arel/nodes/values.rb b/lib/arel/nodes/values.rb index 4c7ca76360638..814e843dab849 100644 --- a/lib/arel/nodes/values.rb +++ b/lib/arel/nodes/values.rb @@ -1,11 +1,13 @@ module Arel module Nodes - class Values - attr_accessor :expressions, :columns + class Values < Arel::Nodes::Binary + alias :expressions :left + alias :expressions= :left= + alias :columns :right + alias :columns= :right= def initialize exprs, columns = [] - @expressions = exprs - @columns = columns + super end end end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index d6d3984ce2054..3d34ff139e385 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -7,14 +7,55 @@ def initialize block = nil private + def unary o + visit o.expr + @block.call o + end + alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Grouping :unary + alias :visit_Arel_Nodes_Having :unary + alias :visit_Arel_Nodes_Not :unary + alias :visit_Arel_Nodes_Offset :unary + alias :visit_Arel_Nodes_On :unary + alias :visit_Arel_Nodes_UnqualifiedColumn :unary + + def function o + visit o.expressions + visit o.alias + @block.call o + 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_Count o + visit o.expressions + visit o.alias + visit o.distinct + @block.call o + end + + def join o + visit o.left + visit o.right + visit o.constraint + @block.call o + end + alias :visit_Arel_Nodes_InnerJoin :join + alias :visit_Arel_Nodes_OuterJoin :join + def binary o visit o.left visit o.right @block.call o end alias :visit_Arel_Nodes_And :binary + 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 @@ -26,6 +67,10 @@ def binary o alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary + alias :visit_Arel_Nodes_Ordering :binary + alias :visit_Arel_Nodes_StringJoin :binary + alias :visit_Arel_Nodes_TableAlias :binary + alias :visit_Arel_Nodes_Values :binary def visit_Arel_Attribute o visit o.relation @@ -38,6 +83,7 @@ def visit_Arel_Attribute o 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 @@ -47,19 +93,24 @@ def visit_Arel_Table o def terminal o @block.call o end - alias :visit_Arel_Nodes_SqlLiteral :terminal - alias :visit_Arel_SqlLiteral :terminal - alias :visit_BigDecimal :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 + alias :visit_ActiveSupport_Multibyte_Chars :terminal + alias :visit_ActiveSupport_StringInquirer :terminal + alias :visit_Arel_Nodes_Lock :terminal + alias :visit_Arel_Nodes_SqlLiteral :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 diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 8d637c7d75269..2f7c832bde2b0 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -14,6 +14,62 @@ def setup @visitor = Visitors::DepthFirst.new @collector end + # unary ops + [ + Arel::Nodes::Not, + Arel::Nodes::Group, + Arel::Nodes::On, + Arel::Nodes::Grouping, + Arel::Nodes::Offset, + Arel::Nodes::Having, + Arel::Nodes::UnqualifiedColumn, + ].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, func], @collector.calls + end + end + + def test_lock + lock = Nodes::Lock.new + @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, :c + @visitor.accept join + assert_equal [:a, :b, :c, join], @collector.calls + end + + def test_outer_join + join = Nodes::OuterJoin.new :a, :b, :c + @visitor.accept join + assert_equal [:a, :b, :c, join], @collector.calls + end + [ Arel::Nodes::And, Arel::Nodes::Assignment, @@ -29,6 +85,12 @@ def setup Arel::Nodes::NotEqual, Arel::Nodes::NotIn, Arel::Nodes::Or, + Arel::Nodes::StringJoin, + Arel::Nodes::TableAlias, + Arel::Nodes::Values, + Arel::Nodes::As, + Arel::Nodes::DeleteStatement, + Arel::Nodes::Ordering, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do binary = klass.new(:a, :b) @@ -130,9 +192,6 @@ def test_insert_statement @visitor.accept stmt assert_equal [:a, :b, stmt.columns, :c, stmt], @collector.calls end - - def test_offset - end end end end From f83affa41e67f4100f1851ed1a13fd5c912b4e1e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 15:19:13 -0800 Subject: [PATCH 0862/1492] refactor block.call out of each visit method --- lib/arel/visitors/depth_first.rb | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 3d34ff139e385..46171dc5bd5c3 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -7,9 +7,13 @@ def initialize block = nil private + def visit o + super + @block.call o + end + def unary o visit o.expr - @block.call o end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary @@ -22,7 +26,6 @@ def unary o def function o visit o.expressions visit o.alias - @block.call o end alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Exists :function @@ -34,14 +37,12 @@ def visit_Arel_Nodes_Count o visit o.expressions visit o.alias visit o.distinct - @block.call o end def join o visit o.left visit o.right visit o.constraint - @block.call o end alias :visit_Arel_Nodes_InnerJoin :join alias :visit_Arel_Nodes_OuterJoin :join @@ -49,7 +50,6 @@ def join o def binary o visit o.left visit o.right - @block.call o end alias :visit_Arel_Nodes_And :binary alias :visit_Arel_Nodes_As :binary @@ -75,7 +75,6 @@ def binary o def visit_Arel_Attribute o visit o.relation visit o.name - @block.call o end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute @@ -87,11 +86,9 @@ def visit_Arel_Attribute o def visit_Arel_Table o visit o.name - @block.call o end def terminal o - @block.call o end alias :visit_ActiveSupport_Multibyte_Chars :terminal alias :visit_ActiveSupport_StringInquirer :terminal @@ -116,7 +113,6 @@ def visit_Arel_Nodes_InsertStatement o visit o.relation visit o.columns visit o.values - @block.call o end def visit_Arel_Nodes_SelectCore o @@ -125,7 +121,6 @@ def visit_Arel_Nodes_SelectCore o visit o.wheres visit o.groups visit o.having - @block.call o end def visit_Arel_Nodes_SelectStatement o @@ -134,7 +129,6 @@ def visit_Arel_Nodes_SelectStatement o visit o.limit visit o.lock visit o.offset - @block.call o end def visit_Arel_Nodes_UpdateStatement o @@ -143,17 +137,14 @@ def visit_Arel_Nodes_UpdateStatement o visit o.wheres visit o.orders visit o.limit - @block.call o end def visit_Array o o.each { |i| visit i } - @block.call o end def visit_Hash o o.each { |k,v| visit(k); visit(v) } - @block.call o end end end From 44faa8e7fcfd328c3f2e4b90b3abad7af841bd03 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 15:23:58 -0800 Subject: [PATCH 0863/1492] adding ancestor test --- Manifest.txt | 1 + lib/arel/nodes/join.rb | 2 +- lib/arel/nodes/select_core.rb | 2 +- lib/arel/nodes/update_statement.rb | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index dbb44e5755074..b67d3b24e8201 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -89,6 +89,7 @@ test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_equality.rb test/nodes/test_insert_statement.rb +test/nodes/test_node.rb test/nodes/test_not.rb test/nodes/test_or.rb test/nodes/test_select_core.rb diff --git a/lib/arel/nodes/join.rb b/lib/arel/nodes/join.rb index 6dede632c5d0f..07f8c98e85887 100644 --- a/lib/arel/nodes/join.rb +++ b/lib/arel/nodes/join.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class Join + class Join < Arel::Nodes::Node attr_accessor :left, :right, :constraint def initialize left, right, constraint diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 42e590ce36925..acc6bb9815d8c 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class SelectCore + class SelectCore < Arel::Nodes::Node attr_accessor :froms, :projections, :wheres, :groups attr_accessor :having diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 6f21187eb1690..288e9f467681f 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class UpdateStatement + class UpdateStatement < Arel::Nodes::Node attr_accessor :relation, :wheres, :values, :orders, :limit def initialize From ae4c814f537416345332b07bcaeaa199b75aa706 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 15:24:38 -0800 Subject: [PATCH 0864/1492] fixing warnings --- test/nodes/test_not.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nodes/test_not.rb b/test/nodes/test_not.rb index 7dffdea0c8bd0..d02a9bad74e38 100644 --- a/test/nodes/test_not.rb +++ b/test/nodes/test_not.rb @@ -12,7 +12,7 @@ module Nodes node.expr.left.must_equal left node.expr.right.must_equal right - knot = node.or(right).not + node.or(right).not end end end From f68b7c4e7e25415c41308a5c37f1096a524b6d09 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 15:31:28 -0800 Subject: [PATCH 0865/1492] base class works with visitor --- History.txt | 5 +++++ lib/arel/nodes/node.rb | 2 ++ lib/arel/visitors/depth_first.rb | 1 + test/visitors/test_depth_first.rb | 6 ++++++ 4 files changed, 14 insertions(+) diff --git a/History.txt b/History.txt index 5e7ce2ee681c5..e981c2612654d 100644 --- a/History.txt +++ b/History.txt @@ -1,5 +1,10 @@ == 2.0.5 (unreleased) +* 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 diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 90c63f0be9023..634e580a8fa95 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -37,6 +37,8 @@ def to_sql engine = Table.engine # Iterate through AST, nodes will be yielded depth-first def each &block + return enum_for(:each) unless block_given? + Visitors::DepthFirst.new(block).accept self end end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 46171dc5bd5c3..00f18727f03ed 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -93,6 +93,7 @@ def terminal o 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_SqlLiteral :terminal alias :visit_BigDecimal :terminal diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 2f7c832bde2b0..4015d72254a1a 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -192,6 +192,12 @@ def test_insert_statement @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 From e02a914fb0b8b7baac1b231badeba49e991a03b9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 29 Nov 2010 15:44:02 -0800 Subject: [PATCH 0866/1492] adding a convenience alias to Node --- lib/arel.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/arel.rb b/lib/arel.rb index 7b505abaf5a06..cf4460d463ad8 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,6 +21,7 @@ require 'arel/delete_manager' require 'arel/nodes' + #### these are deprecated require 'arel/deprecated' require 'arel/sql/engine' @@ -33,4 +34,6 @@ module Arel def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql end + ## Convenience Alias + Node = Arel::Nodes::Node end From f62a7267c551d216297bec9f0496738b8e27dcae Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 11:06:09 -0800 Subject: [PATCH 0867/1492] adding deprecated support for walking ancestor trees --- History.txt | 5 +++++ lib/arel/visitors/visitor.rb | 7 +++++++ test/visitors/test_to_sql.rb | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/History.txt b/History.txt index e981c2612654d..2f8934fcb920d 100644 --- a/History.txt +++ b/History.txt @@ -11,6 +11,11 @@ * 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 diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 510d50399be27..b0d16ffe4ee0c 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -13,6 +13,13 @@ def accept object def visit object send DISPATCH[object.class], object + rescue NoMethodError + warn "visiting #{object.class} via superclass, this will be removed in arel 2.2.0" if $VERBOSE + superklass = object.class.ancestors.find { |klass| + respond_to?(DISPATCH[klass], true) + } + DISPATCH[object.class] = DISPATCH[superklass] + retry end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 037fca9931e37..1c5c8eac0c6aa 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -21,6 +21,11 @@ module Visitors 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 From 809f1e3865e84250997f2bef94c1995a99959d8c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 11:08:14 -0800 Subject: [PATCH 0868/1492] fixing tests in 1.9 --- lib/arel/visitors/visitor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index b0d16ffe4ee0c..8cea42028e63b 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -8,7 +8,7 @@ def accept object private DISPATCH = Hash.new do |hash, klass| - hash[klass] = "visit_#{klass.name.gsub('::', '_')}" + hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" end def visit object From 58cbd16bb70105872ea8d938edaa31c328485088 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 11:09:56 -0800 Subject: [PATCH 0869/1492] terrorist version bump --- History.txt | 2 +- lib/arel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 2f8934fcb920d..3676246f37264 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 2.0.5 (unreleased) +== 2.0.5 11/30/2010 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index cf4460d463ad8..d1878c64b0d1f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -29,7 +29,7 @@ #### module Arel - VERSION = '2.0.4' + VERSION = '2.0.5' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From e91d393fab7d6d192ada0f51b743a2e9bca30d2a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 11:10:30 -0800 Subject: [PATCH 0870/1492] adding node test --- test/nodes/test_node.rb | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 test/nodes/test_node.rb diff --git a/test/nodes/test_node.rb b/test/nodes/test_node.rb new file mode 100644 index 0000000000000..71d2098a60e6b --- /dev/null +++ b/test/nodes/test_node.rb @@ -0,0 +1,33 @@ +require 'helper' + +module Arel + class TestNode < MiniTest::Unit::TestCase + def test_all_nodes_are_nodes + Nodes.constants.map { |k| + Nodes.const_get(k) + }.grep(Class).each do |klass| + next if Nodes::SqlLiteral == klass + 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 From 7cdc6c79510babbb5a2769f957076346a21a09c1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 11:11:27 -0800 Subject: [PATCH 0871/1492] removing rubyforge plugin --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index 5590e694f1091..7e3e4b31c8a0a 100644 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,7 @@ require "rubygems" gem 'hoe', '>= 2.1.0' require 'hoe' +Hoe.plugins.delete :rubyforge Hoe.plugin :minitest Hoe.plugin :gemspec # `gem install hoe-gemspec` Hoe.plugin :git # `gem install hoe-git` From 624280171cb1e82ddfd5525a6d677a60693190b3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 11:12:02 -0800 Subject: [PATCH 0872/1492] bumping gemspec --- arel.gemspec | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index ab7046b8ef1d1..2e52ae4a19625 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,43 +2,40 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.4.20101119081136" + s.version = "2.0.5.20101130111154" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2010-11-19} + s.date = %q{2010-11-30} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/predications.rb", "lib/arel/relation.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/dot.rb", "lib/arel/visitors/join_sql.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/as.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.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/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_join_sql.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} s.rubygems_version = %q{1.3.7} s.summary = %q{Arel is a Relational Algebra for Ruby} - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_or.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_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_join_sql.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.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.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_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_join_sql.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 current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, [">= 2.0.4"]) - s.add_development_dependency(%q, [">= 2.0.0.beta"]) + s.add_development_dependency(%q, [">= 2.0.0"]) s.add_development_dependency(%q, [">= 2.1.0"]) s.add_development_dependency(%q, [">= 1.6.0"]) s.add_development_dependency(%q, [">= 2.6.2"]) else - s.add_dependency(%q, [">= 2.0.4"]) - s.add_dependency(%q, [">= 2.0.0.beta"]) + s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.6.2"]) end else - s.add_dependency(%q, [">= 2.0.4"]) - s.add_dependency(%q, [">= 2.0.0.beta"]) + s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.6.2"]) From 288eefd4b13fe5177782049e58445c15d5e02708 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 30 Nov 2010 16:57:55 -0800 Subject: [PATCH 0873/1492] deprecating the "joins" method --- lib/arel/select_manager.rb | 4 ++++ lib/arel/table.rb | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f6738bf26f92f..08cfd41e7f203 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -154,6 +154,10 @@ def order_clauses end def joins manager + if $VERBOSE + warn "joins is deprecated and will be removed in 2.2" + warn "please remove your call to joins from #{caller.first}" + end manager.join_sql end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 6f29a02e562fd..aa23a7d60196b 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -45,6 +45,10 @@ def from table end def joins manager + if $VERBOSE + warn "joins is deprecated and will be removed in 2.2" + warn "please remove your call to joins from #{caller.first}" + end nil end From c9fe1b3e2b6124bf5c6df27b89d9efa1e58fdd9c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:04:57 -0800 Subject: [PATCH 0874/1492] rails 3.0.x will not let us have nice things --- lib/arel/nodes/node.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 634e580a8fa95..4e182d2850f81 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -3,8 +3,6 @@ module Nodes ### # Abstract base class for all AST nodes class Node - include Enumerable - ### # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. From b68bf40ecc611a75f3b204fada4471e9af92ce40 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:11:30 -0800 Subject: [PATCH 0875/1492] make sure we raise type errors with unknown classes --- History.txt | 6 ++++++ lib/arel/visitors/visitor.rb | 1 + test/visitors/test_depth_first.rb | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/History.txt b/History.txt index 3676246f37264..fa08015903cfd 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 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 diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 8cea42028e63b..055acf9765977 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -18,6 +18,7 @@ def visit object 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 diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 4015d72254a1a..1bee0328cfea6 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -14,6 +14,13 @@ def setup @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, From 3446b72ede5232f6cc3b87bf2a9af7cb4ac7f500 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:12:02 -0800 Subject: [PATCH 0876/1492] bumping version --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index d1878c64b0d1f..6c9f51d03a5bd 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -29,7 +29,7 @@ #### module Arel - VERSION = '2.0.5' + VERSION = '2.0.6' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From a1662156b3abb8830f7245bd6e398cf2ca1291d4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:19:09 -0800 Subject: [PATCH 0877/1492] we actually want enumerable in Node --- History.txt | 6 ++++++ lib/arel/nodes/node.rb | 2 ++ 2 files changed, 8 insertions(+) diff --git a/History.txt b/History.txt index fa08015903cfd..b77563e0b5a00 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 2.1.0 (unreleased) + +* Enhancements + + * AST is now Enumerable + == 2.0.6 12/01/2010 * Bug Fixes diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 4e182d2850f81..634e580a8fa95 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -3,6 +3,8 @@ module Nodes ### # Abstract base class for all AST nodes class Node + include Enumerable + ### # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. From 5c81359785706f013c2d8b60f93086654ad3d69e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:19:38 -0800 Subject: [PATCH 0878/1492] adding enumerable, making beta gem --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 6c9f51d03a5bd..70949646c0f07 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -29,7 +29,7 @@ #### module Arel - VERSION = '2.0.6' + VERSION = '2.1.0.beta' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 67e5f45edff26d4d52b6d6f2345dac277de2ebb4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:20:12 -0800 Subject: [PATCH 0879/1492] bumping gemspec --- arel.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 2e52ae4a19625..594a7a108de07 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.5.20101130111154" + s.version = "2.1.0.beta.20101201091952" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + 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 = %q{2010-11-30} + s.date = %q{2010-12-01} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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"] From 01a44c5feab86c9865ca6158f57267ac14e58aaf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:29:57 -0800 Subject: [PATCH 0880/1492] moving master to 2.0.7.beta until rails dependencies are cleared up --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 70949646c0f07..6a8d9571d14d2 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -29,7 +29,7 @@ #### module Arel - VERSION = '2.1.0.beta' + VERSION = '2.0.7.beta' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 39ccb8049c87b1fde1b85c6a0d84e0f72e92bac1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 1 Dec 2010 09:30:18 -0800 Subject: [PATCH 0881/1492] bumping generated gemspec --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 594a7a108de07..c7ec979042d9c 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.0.beta.20101201091952" + s.version = "2.0.7.beta.20101201093009" 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"] From baa660f62b4fae9197d7b4b6e4bbcf4059d106a8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 2 Dec 2010 14:01:08 -0800 Subject: [PATCH 0882/1492] deprecating "insert" --- History.txt | 5 +++++ lib/arel/crud.rb | 16 +++++++++++++--- lib/arel/table.rb | 4 ++++ test/helper.rb | 2 +- test/test_table.rb | 12 ++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/History.txt b/History.txt index b77563e0b5a00..e794edb132c73 100644 --- a/History.txt +++ b/History.txt @@ -4,6 +4,11 @@ * AST is now Enumerable +* Deprecations + + * Calls to `insert` are deprecated. Please use `compile_insert` then call + `to_sql` on the resulting object and execute that SQL. + == 2.0.6 12/01/2010 * Bug Fixes diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index b3199e6d38116..8de008c09eb95 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -20,11 +20,21 @@ def update values @engine.connection.update um.to_sql, 'AREL' end - # FIXME: this method should go away - def insert values + def compile_insert values im = InsertManager.new @engine im.insert values - @engine.connection.insert im.to_sql + im + 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 2.2.0. Please +switch to `compile_insert` + eowarn + end + @engine.connection.insert compile_insert(values).to_sql end def delete diff --git a/lib/arel/table.rb b/lib/arel/table.rb index aa23a7d60196b..ca811debee158 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -108,6 +108,10 @@ def select_manager SelectManager.new(@engine) end + def insert_manager + InsertManager.new(@engine) + end + private def attributes_for columns diff --git a/test/helper.rb b/test/helper.rb index 3f9ac22447c84..f13596f9ec84b 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -8,6 +8,6 @@ class Object def must_be_like other - self.gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip + gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip end end diff --git a/test/test_table.rb b/test/test_table.rb index 8d37a8eaff7d6..b9998174a1bb5 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -6,6 +6,18 @@ module Arel @relation = Table.new(:users) 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 From a8521641d5d7630bba7620ce42fe7456eeff0398 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 2 Dec 2010 14:31:37 -0800 Subject: [PATCH 0883/1492] deprecating the update method in favor of compile_update --- History.txt | 3 +++ lib/arel/crud.rb | 15 +++++++++++++-- test/test_crud.rb | 6 ++---- test/test_select_manager.rb | 23 ++++++++++------------- test/test_table.rb | 6 ------ 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/History.txt b/History.txt index e794edb132c73..ddfced9666d7f 100644 --- a/History.txt +++ b/History.txt @@ -9,6 +9,9 @@ * 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. + == 2.0.6 12/01/2010 * Bug Fixes diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 8de008c09eb95..06883d9ac6c3a 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -2,8 +2,7 @@ module Arel ### # FIXME hopefully we can remove this module Crud - # FIXME: this method should go away - def update values + def compile_update values um = UpdateManager.new @engine if Nodes::SqlLiteral === values @@ -16,7 +15,19 @@ def update values um.take @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 2.2.0. Please +switch to `compile_update` + eowarn + end + um = compile_update values @engine.connection.update um.to_sql, 'AREL' end diff --git a/test/test_crud.rb b/test/test_crud.rb index 582f0ec072a8c..0a727bce0a534 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -47,10 +47,8 @@ def initialize engine = FakeEngine.new table = Table.new :users fc = FakeCrudder.new fc.from table - fc.update [[table[:id], 'foo']] - fc.engine.calls.find { |method, _| - method == :update - }.wont_be_nil + stmt = fc.compile_update [[table[:id], 'foo']] + assert_instance_of Arel::UpdateManager, stmt end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index d63bec009339e..ee4341c1ce565 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -312,7 +312,6 @@ def execute sql, name = nil, *args manager.join_sql.must_be_like %{ INNER JOIN "users" "users_2" "users"."id" = "users_2"."id" } - manager.joins(manager).must_equal manager.join_sql end it 'returns outer join sql' do @@ -323,7 +322,6 @@ def execute sql, name = nil, *args manager.join_sql.must_be_like %{ LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id" } - manager.joins(manager).must_equal manager.join_sql end it 'returns string join sql' do @@ -331,7 +329,6 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new(table, 'hello') manager.join_sql.must_be_like %{ 'hello' } - manager.joins(manager).must_equal manager.join_sql end it 'returns nil join sql' do @@ -436,9 +433,9 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new engine manager.from table manager.take 1 - manager.update(SqlLiteral.new('foo = bar')) + stmt = manager.compile_update(SqlLiteral.new('foo = bar')) - engine.executed.last.must_be_like %{ + stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1) } @@ -450,9 +447,9 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new engine manager.from table manager.order :foo - manager.update(SqlLiteral.new('foo = bar')) + stmt = manager.compile_update(SqlLiteral.new('foo = bar')) - engine.executed.last.must_be_like %{ + stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo) } @@ -463,9 +460,9 @@ def execute sql, name = nil, *args table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - manager.update(SqlLiteral.new('foo = bar')) + stmt = manager.compile_update(SqlLiteral.new('foo = bar')) - engine.executed.last.must_be_like %{ UPDATE "users" SET foo = bar } + stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end it 'copies where clauses' do @@ -474,9 +471,9 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new engine manager.where table[:id].eq 10 manager.from table - manager.update(table[:id] => 1) + stmt = manager.compile_update(table[:id] => 1) - engine.executed.last.must_be_like %{ + stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 } end @@ -486,9 +483,9 @@ def execute sql, name = nil, *args table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - manager.update(table[:id] => 1) + stmt = manager.compile_update(table[:id] => 1) - engine.executed.last.must_be_like %{ + stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 } end diff --git a/test/test_table.rb b/test/test_table.rb index b9998174a1bb5..93cdde8f684ba 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -48,12 +48,6 @@ module Arel end describe 'backwards compat' do - describe 'joins' do - it 'returns nil' do - @relation.joins(nil).must_equal nil - end - end - describe 'join' do it 'noops on nil' do mgr = @relation.join nil From 9e05f7e01be3840b1a66bbda0292f97740f6947e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 2 Dec 2010 15:45:00 -0800 Subject: [PATCH 0884/1492] deprecating the "delete" method in favor of compile_delete --- History.txt | 3 +++ lib/arel/crud.rb | 14 ++++++++++++-- test/test_crud.rb | 6 ++---- test/test_select_manager.rb | 8 ++++---- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/History.txt b/History.txt index ddfced9666d7f..1c4f122e2b34a 100644 --- a/History.txt +++ b/History.txt @@ -12,6 +12,9 @@ * 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. + == 2.0.6 12/01/2010 * Bug Fixes diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 06883d9ac6c3a..ade1b9f424e18 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -48,11 +48,21 @@ def insert values @engine.connection.insert compile_insert(values).to_sql end - def delete + def compile_delete dm = DeleteManager.new @engine dm.wheres = @ctx.wheres dm.from @ctx.froms - @engine.connection.delete dm.to_sql, 'AREL' + dm + end + + def delete + if $VERBOSE + warn <<-eowarn +delete (#{caller.first}) is deprecated and will be removed in ARel 2.2.0. Please +switch to `compile_delete` + eowarn + end + @engine.connection.delete compile_delete.to_sql, 'AREL' end end end diff --git a/test/test_crud.rb b/test/test_crud.rb index 0a727bce0a534..ebe5d68908751 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -57,10 +57,8 @@ def initialize engine = FakeEngine.new table = Table.new :users fc = FakeCrudder.new fc.from table - fc.delete - fc.engine.calls.find { |method, _| - method == :delete - }.wont_be_nil + stmt = fc.compile_delete + assert_instance_of Arel::DeleteManager, stmt end end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index ee4341c1ce565..0ecc78ce83c22 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -390,9 +390,9 @@ def execute sql, name = nil, *args table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - manager.delete + stmt = manager.compile_delete - engine.executed.last.must_be_like %{ DELETE FROM "users" } + stmt.to_sql.must_be_like %{ DELETE FROM "users" } end it "copies where" do @@ -401,9 +401,9 @@ def execute sql, name = nil, *args manager = Arel::SelectManager.new engine manager.from table manager.where table[:id].eq 10 - manager.delete + stmt = manager.compile_delete - engine.executed.last.must_be_like %{ + stmt.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10 } end From e95aba8d1dfbd68b4bc2969f48e353b8de9bf323 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 2 Dec 2010 16:26:17 -0800 Subject: [PATCH 0885/1492] renaming variable --- lib/arel/visitors/to_sql.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index abec5317cad97..9694ed4cb878c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -67,8 +67,8 @@ def visit_Arel_Nodes_Exists o end def visit_Arel_Nodes_Values o - "VALUES (#{o.expressions.zip(o.columns).map { |value, column| - quote(value, column && column.column) + "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| + quote(value, attr && attr.column) }.join ', '})" end From dbc1f65244ac0b75f746ea91289f2e36ced435a6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 3 Dec 2010 08:55:14 -0800 Subject: [PATCH 0886/1492] starting the column cache --- lib/arel/visitors/to_sql.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9694ed4cb878c..b8a991b965e69 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -10,6 +10,7 @@ def initialize engine @last_column = nil @quoted_tables = {} @quoted_columns = {} + @column_cache = {} end def accept object @@ -66,9 +67,17 @@ def visit_Arel_Nodes_Exists o o.alias ? " AS #{visit o.alias}" : ''}" end + def column_for relation, name + name = name.to_s + table = relation.name + + columns = @connection.columns(table, "#{table} Columns") + columns.find { |col| col.name.to_s == name } + end + def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| - quote(value, attr && attr.column) + quote(value, attr && column_for(attr.relation, attr.name)) }.join ', '})" end From 40603729cc1d9a8e636a887446d051390d15fcd8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 3 Dec 2010 15:24:30 -0800 Subject: [PATCH 0887/1492] attributes do not need a column member --- lib/arel/attributes/attribute.rb | 2 +- lib/arel/nodes/unqualified_column.rb | 4 +++ lib/arel/select_manager.rb | 4 +-- lib/arel/table.rb | 14 ++++++----- lib/arel/visitors/join_sql.rb | 2 +- lib/arel/visitors/to_sql.rb | 37 +++++++++++++++++++++------- lib/arel/visitors/visitor.rb | 3 ++- test/attributes/test_attribute.rb | 6 ++--- test/test_select_manager.rb | 7 ++++++ test/test_table.rb | 7 ------ test/visitors/test_join_sql.rb | 3 ++- test/visitors/test_to_sql.rb | 10 +++++--- 12 files changed, 65 insertions(+), 34 deletions(-) diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 5cbe194b41ece..9a42e5a4da40a 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -1,6 +1,6 @@ module Arel module Attributes - class Attribute < Struct.new :relation, :name, :column + class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications end diff --git a/lib/arel/nodes/unqualified_column.rb b/lib/arel/nodes/unqualified_column.rb index f7ba653c1195a..2820dba9d2266 100644 --- a/lib/arel/nodes/unqualified_column.rb +++ b/lib/arel/nodes/unqualified_column.rb @@ -4,6 +4,10 @@ class UnqualifiedColumn < Arel::Nodes::Unary alias :attribute :expr alias :attribute= :expr= + def relation + @expr.relation + end + def column @expr.column end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 08cfd41e7f203..2bc7dbf1ec629 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -143,8 +143,8 @@ def take limit def join_sql return nil unless @ctx.froms - viz = Visitors::JoinSql.new @engine - Nodes::SqlLiteral.new viz.accept @ctx + sql = @visitor.dup.extend(Visitors::JoinSql).accept @ctx + Nodes::SqlLiteral.new sql end def order_clauses diff --git a/lib/arel/table.rb b/lib/arel/table.rb index ca811debee158..c2db388fd40f4 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -17,7 +17,6 @@ def initialize name, engine = Table.engine if Hash === engine @engine = engine[:engine] || Table.engine - @columns = attributes_for engine[:columns] # 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 @@ -93,15 +92,18 @@ def having expr end def columns + if $VERBOSE + warn <<-eowarn +(#{caller.first}) Arel::Table#columns is deprecated and will be removed in +Arel 2.2.0 with no replacement. + eowarn + end @columns ||= attributes_for @engine.connection.columns(@name, "#{@name} Columns") end def [] name - return nil unless table_exists? - - name = name.to_sym - columns.find { |column| column.name == name } + ::Arel::Attribute.new self, name.to_sym end def select_manager @@ -118,7 +120,7 @@ def attributes_for columns return nil unless columns columns.map do |column| - Attributes.for(column).new self, column.name.to_sym, column + Attributes.for(column).new self, column.name.to_sym end end diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index d3fb18d3c67b4..7ba2bde540e8c 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -8,7 +8,7 @@ module Visitors # # This visitor is used in SelectManager#join_sql and is for backwards # compatibility with Arel V1.0 - class JoinSql < Arel::Visitors::ToSql + module JoinSql private def visit_Arel_Nodes_SelectCore o diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b8a991b965e69..8db90c376a0c6 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -10,7 +10,8 @@ def initialize engine @last_column = nil @quoted_tables = {} @quoted_columns = {} - @column_cache = {} + @column_cache = Hash.new { |h,k| h[k] = {} } + @table_exists = {} end def accept object @@ -67,17 +68,35 @@ def visit_Arel_Nodes_Exists o o.alias ? " AS #{visit o.alias}" : ''}" end - def column_for relation, name - name = name.to_s - table = relation.name + def table_exists? name + return true if @table_exists.key? name + if @connection.table_exists?(name) + @table_exists[name] = true + else + false + end + end + + def column_for attr + name = attr.name.to_sym + table = attr.relation.name + + return nil unless table_exists? table + + # If we don't have this column cached, get a list of columns and + # cache them for this table + unless @column_cache.key? table + #$stderr.puts "MISS: #{self.class.name} #{object_id} #{table.inspect} : #{name.inspect}" + columns = @connection.columns(table, "#{table}(#{name}) Columns") + @column_cache[table] = Hash[columns.map { |c| [c.name.to_sym, c] }] + end - columns = @connection.columns(table, "#{table} Columns") - columns.find { |col| col.name.to_s == name } + @column_cache[table][name] end def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| - quote(value, attr && column_for(attr.relation, attr.name)) + quote(value, attr && column_for(attr)) }.join ', '})" end @@ -235,7 +254,7 @@ def visit_Arel_Nodes_Or o end def visit_Arel_Nodes_Assignment o - right = quote(o.right, o.left.column) + right = quote(o.right, column_for(o.left)) "#{visit o.left} = #{right}" end @@ -268,7 +287,7 @@ def visit_Arel_Nodes_UnqualifiedColumn o end def visit_Arel_Attributes_Attribute o - @last_column = o.column + @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 diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 055acf9765977..85359f3e673b6 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -13,7 +13,8 @@ def accept object def visit object send DISPATCH[object.class], object - rescue NoMethodError + rescue NoMethodError => e + raise e if respond_to?(DISPATCH[object.class], true) warn "visiting #{object.class} via superclass, this will be removed in arel 2.2.0" if $VERBOSE superklass = object.class.ancestors.find { |klass| respond_to?(DISPATCH[klass], true) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 06954c242be7f..df7dc6962106d 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -326,7 +326,7 @@ module Attributes describe '#eq' do it 'should return an equality node' do - attribute = Attribute.new nil, nil, nil + attribute = Attribute.new nil, nil equality = attribute.eq 1 equality.left.must_equal attribute equality.right.must_equal 1 @@ -485,7 +485,7 @@ module Attributes end it 'should return an in node' do - attribute = Attribute.new nil, nil, nil + 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] @@ -538,7 +538,7 @@ module Attributes end it 'should return a NotIn node' do - attribute = Attribute.new nil, nil, nil + 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] diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 0ecc78ce83c22..db2b306916225 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -26,6 +26,13 @@ def connection 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 table_exists? name + @engine.connection.table_exists? name + end def execute sql, name = nil, *args @executed << sql diff --git a/test/test_table.rb b/test/test_table.rb index 93cdde8f684ba..bb7bd255fd31c 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -174,13 +174,6 @@ module Arel it "manufactures an attribute if the symbol names an attribute within the relation" do column = @relation[:id] column.name.must_equal :id - column.must_be_kind_of Attributes::Integer - end - end - - describe 'when table does not exist' do - it 'returns nil' do - @relation[:foooo].must_be_nil end end end diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index 8253fe5ab4cf6..181ef6c570a85 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -4,7 +4,8 @@ module Arel module Visitors describe 'the join_sql visitor' do before do - @visitor = JoinSql.new Table.engine + @visitor = ToSql.new Table.engine + @visitor.extend(JoinSql) end describe 'inner join' do diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 1c5c8eac0c6aa..04d5e2d39f769 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -84,7 +84,7 @@ module Visitors end it "should visit visit_Arel_Attributes_Time" do - attr = Attributes::Time.new(@attr.relation, @attr.name, @attr.column) + attr = Attributes::Time.new(@attr.relation, @attr.name) @visitor.accept attr end @@ -143,7 +143,9 @@ def quote value, column = nil end in_node = Nodes::In.new @attr, %w{ a b c } visitor = visitor.new(Table.engine) - visitor.expected = @attr.column + 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 @@ -189,7 +191,9 @@ def quote value, column = nil end in_node = Nodes::NotIn.new @attr, %w{ a b c } visitor = visitor.new(Table.engine) - visitor.expected = @attr.column + 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 From 8a5680e4a75eb6ac877c1c9687a99e021cbba74e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 3 Dec 2010 16:01:36 -0800 Subject: [PATCH 0888/1492] declawing connection from the Table class --- lib/arel/table.rb | 18 ++++++++---------- lib/arel/visitors/to_sql.rb | 9 +++++---- test/test_select_manager.rb | 4 ++++ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index c2db388fd40f4..79c9b60945f3a 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -94,8 +94,8 @@ def having expr def columns if $VERBOSE warn <<-eowarn -(#{caller.first}) Arel::Table#columns is deprecated and will be removed in -Arel 2.2.0 with no replacement. +(#{caller.first}) Arel::Table#columns is deprecated and will be removed in +Arel 2.2.0 with no replacement. PEW PEW PEW!!! eowarn end @columns ||= @@ -124,16 +124,14 @@ def attributes_for columns end end - def table_exists? - @table_exists ||= tables.key?(@name) || engine.connection.table_exists?(name) - end - - def tables - self.class.table_cache(@engine) - 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 2.2.0 with no replacement. PEW PEW PEW!!! + eowarn + end @@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }] end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8db90c376a0c6..082196ef2b06d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -70,11 +70,12 @@ def visit_Arel_Nodes_Exists o def table_exists? name return true if @table_exists.key? name - if @connection.table_exists?(name) - @table_exists[name] = true - else - false + + @connection.tables.each do |table| + @table_exists[table] = true end + + @table_exists.key? name end def column_for attr diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index db2b306916225..826832c5ab5f3 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -34,6 +34,10 @@ def table_exists? name @engine.connection.table_exists? name end + def tables + @engine.connection.tables + end + def execute sql, name = nil, *args @executed << sql end From 7b3e8d67943c091d24ee4e4129a9b1892b7c7e6f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 3 Dec 2010 16:04:36 -0800 Subject: [PATCH 0889/1492] adding deprecated methods to History --- History.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/History.txt b/History.txt index 1c4f122e2b34a..59fce7f4d450c 100644 --- a/History.txt +++ b/History.txt @@ -15,6 +15,15 @@ * 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 2.2.0 with no + replacement. + + * Arel::Table#columns is deprecated and will be removed in 2.2.0 with no + replacement. + + * Arel::Table.table_cache is deprecated and will be removed in 2.2.0 with no + replacement. + == 2.0.6 12/01/2010 * Bug Fixes From ac6296ab8f9d38dbfa8149eb0c6e16d6957dd519 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 3 Dec 2010 16:07:28 -0800 Subject: [PATCH 0890/1492] only break backwards compatibility in major releases --- History.txt | 6 +++--- lib/arel/crud.rb | 6 +++--- lib/arel/select_manager.rb | 2 +- lib/arel/table.rb | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/History.txt b/History.txt index 59fce7f4d450c..d3172f41626af 100644 --- a/History.txt +++ b/History.txt @@ -15,13 +15,13 @@ * 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 2.2.0 with no + * 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 2.2.0 with no + * 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 2.2.0 with no + * Arel::Table.table_cache is deprecated and will be removed in 3.0.0 with no replacement. == 2.0.6 12/01/2010 diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index ade1b9f424e18..ec58734456e06 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -22,7 +22,7 @@ def compile_update values def update values if $VERBOSE warn <<-eowarn -update (#{caller.first}) is deprecated and will be removed in ARel 2.2.0. Please +update (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please switch to `compile_update` eowarn end @@ -41,7 +41,7 @@ def compile_insert values def insert values if $VERBOSE warn <<-eowarn -insert (#{caller.first}) is deprecated and will be removed in ARel 2.2.0. Please +insert (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please switch to `compile_insert` eowarn end @@ -58,7 +58,7 @@ def compile_delete def delete if $VERBOSE warn <<-eowarn -delete (#{caller.first}) is deprecated and will be removed in ARel 2.2.0. Please +delete (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please switch to `compile_delete` eowarn end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 2bc7dbf1ec629..de12402e9f1d1 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -155,7 +155,7 @@ def order_clauses def joins manager if $VERBOSE - warn "joins is deprecated and will be removed in 2.2" + warn "joins is deprecated and will be removed in 3.0.0" warn "please remove your call to joins from #{caller.first}" end manager.join_sql diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 79c9b60945f3a..e7a626a4c6764 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -45,7 +45,7 @@ def from table def joins manager if $VERBOSE - warn "joins is deprecated and will be removed in 2.2" + warn "joins is deprecated and will be removed in 3.0.0" warn "please remove your call to joins from #{caller.first}" end nil @@ -95,7 +95,7 @@ def columns if $VERBOSE warn <<-eowarn (#{caller.first}) Arel::Table#columns is deprecated and will be removed in -Arel 2.2.0 with no replacement. PEW PEW PEW!!! +Arel 3.0.0 with no replacement. PEW PEW PEW!!! eowarn end @columns ||= @@ -129,7 +129,7 @@ def self.table_cache engine # :nodoc: if $VERBOSE warn <<-eowarn (#{caller.first}) Arel::Table.table_cache is deprecated and will be removed in -Arel 2.2.0 with no replacement. PEW PEW PEW!!! +Arel 3.0.0 with no replacement. PEW PEW PEW!!! eowarn end @@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }] From 516ae526b34333073df7a9835952d5d499197fdd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 09:36:02 -0800 Subject: [PATCH 0891/1492] adding a test for the dot visitor --- Manifest.txt | 1 + lib/arel/nodes/node.rb | 2 +- lib/arel/visitors/dot.rb | 11 +++++++++-- test/visitors/test_dot.rb | 27 +++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 test/visitors/test_dot.rb diff --git a/Manifest.txt b/Manifest.txt index b67d3b24e8201..095d3c276e67c 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -107,6 +107,7 @@ test/test_select_manager.rb test/test_table.rb test/test_update_manager.rb test/visitors/test_depth_first.rb +test/visitors/test_dot.rb test/visitors/test_join_sql.rb test/visitors/test_mysql.rb test/visitors/test_oracle.rb diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 4e182d2850f81..404ad22ece3e9 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -7,7 +7,7 @@ class Node # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. def not - Nodes::Not.new self + Nodes::Not.new Nodes::Grouping.new self end ### diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 2ce8b6814f736..c515cbe220535 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -84,9 +84,16 @@ def visit_Arel_Nodes_UnqualifiedColumn o visit_edge o, "attribute" end - def visit_Arel_Nodes_Offset o - visit_edge o, "value" + 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_Not :unary + alias :visit_Arel_Nodes_Offset :unary + alias :visit_Arel_Nodes_On :unary + alias :visit_Arel_Nodes_UnqualifiedColumn :unary def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb new file mode 100644 index 0000000000000..19a554ce42581 --- /dev/null +++ b/test/visitors/test_dot.rb @@ -0,0 +1,27 @@ +require 'helper' + +module Arel + module Visitors + class TestDot < MiniTest::Unit::TestCase + def setup + @visitor = Visitors::Dot.new + end + + # unary ops + [ + Arel::Nodes::Not, + Arel::Nodes::Group, + Arel::Nodes::On, + Arel::Nodes::Grouping, + Arel::Nodes::Offset, + Arel::Nodes::Having, + Arel::Nodes::UnqualifiedColumn, + ].each do |klass| + define_method("test_#{klass.name.gsub('::', '_')}") do + op = klass.new(:a) + @visitor.accept op + end + end + end + end +end From c28fe4cbbb1121394c6bb14403350723f9ecce4c Mon Sep 17 00:00:00 2001 From: Ryan Rempel Date: Sat, 4 Dec 2010 12:08:19 -0600 Subject: [PATCH 0892/1492] Make "not" apply to the whole sub-expression when generating sql. --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index abec5317cad97..2713621a54ca9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -192,7 +192,7 @@ def visit_Arel_Nodes_On o end def visit_Arel_Nodes_Not o - "NOT #{visit o.expr}" + "NOT (#{visit o.expr})" end def visit_Arel_Table o diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 1c5c8eac0c6aa..5cbaaac501514 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -40,7 +40,13 @@ module Visitors it "should visit_Not" do sql = @visitor.accept Nodes::Not.new(Arel.sql("foo")) - sql.must_be_like "NOT 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 From 4bec8c8e9e21c87a6beb22423fefbd23a7f8fb99 Mon Sep 17 00:00:00 2001 From: Ryan Rempel Date: Sat, 4 Dec 2010 12:08:19 -0600 Subject: [PATCH 0893/1492] Make "not" apply to the whole sub-expression when generating sql. --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 082196ef2b06d..35a0d9746fb1c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -221,7 +221,7 @@ def visit_Arel_Nodes_On o end def visit_Arel_Nodes_Not o - "NOT #{visit o.expr}" + "NOT (#{visit o.expr})" end def visit_Arel_Table o diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 04d5e2d39f769..bae291d87cf5d 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -40,7 +40,13 @@ module Visitors it "should visit_Not" do sql = @visitor.accept Nodes::Not.new(Arel.sql("foo")) - sql.must_be_like "NOT 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 From 13d22766902af1d6f709b85a73e089b7afbb9dbf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 20:16:16 -0800 Subject: [PATCH 0894/1492] consolidating dot visitor methods --- lib/arel/visitors/dot.rb | 12 ------------ lib/arel/visitors/to_sql.rb | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index c515cbe220535..eab5e4afdc340 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,10 +28,6 @@ def accept object end private - def visit_Arel_Nodes_Grouping o - visit_edge o, "expr" - end - def visit_Arel_Nodes_Ordering o visit_edge o, "expr" visit_edge o, "direction" @@ -55,10 +51,6 @@ def visit_Arel_Nodes_Count o visit_edge o, "distinct" end - def visit_Arel_Nodes_On o - visit_edge o, "expr" - end - def visit_Arel_Nodes_Values o visit_edge o, "expressions" end @@ -80,10 +72,6 @@ def visit_Arel_Nodes_DeleteStatement o visit_edge o, "wheres" end - def visit_Arel_Nodes_UnqualifiedColumn o - visit_edge o, "attribute" - end - def unary o visit_edge o, "expr" end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 35a0d9746fb1c..bd0d664b4417f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -105,7 +105,7 @@ def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), (visit(o.offset) if o.offset), (visit(o.lock) if o.lock), ].compact.join ' ' From 4018b5d66a810a34273d4b198688896f6f7459f3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 20:26:08 -0800 Subject: [PATCH 0895/1492] quoting limit nodes --- lib/arel/visitors/mysql.rb | 2 +- lib/arel/visitors/postgresql.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_mysql.rb | 6 ++++++ test/visitors/test_postgres.rb | 8 ++++++++ test/visitors/test_to_sql.rb | 6 ++++++ 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 143b4d36f4aba..ace8fb0979714 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -25,7 +25,7 @@ def visit_Arel_Nodes_UpdateStatement o ("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?), - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), ].compact.join ' ' end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 553ee91bf9a6b..01fbda75b941c 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -17,7 +17,7 @@ def visit_Arel_Nodes_SelectStatement o [ "SELECT * FROM (#{sql}) AS id_list", "ORDER BY #{aliased_orders(o.orders).join(', ')}", - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), (visit(o.offset) if o.offset), ].compact.join ' ' else diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2713621a54ca9..2fb464b265e7e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -76,7 +76,7 @@ def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), (visit(o.offset) if o.offset), (visit(o.lock) if o.lock), ].compact.join ' ' diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 8606dc39d4ab9..135348580d1b3 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -17,6 +17,12 @@ module Visitors sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1" end + it "should escape LIMIT" do + sc = Arel::Nodes::UpdateStatement.new + sc.limit = "omg" + assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + end + it 'uses DUAL for empty from' do stmt = Nodes::SelectStatement.new sql = @visitor.accept(stmt) diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 618745c35d1db..b98f78ca12b42 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -12,6 +12,14 @@ module Visitors FOR UPDATE } end + + it "should escape LIMIT" do + sc = Arel::Nodes::SelectStatement.new + sc.limit = "omg" + sc.cores.first.projections << 'DISTINCT ON' + sc.orders << "xyz" + assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 5cbaaac501514..b9d6c78e62156 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -30,6 +30,12 @@ module Visitors @visitor.accept(DateTime).must_equal "'DateTime'" end + it "should escape LIMIT" do + sc = Arel::Nodes::SelectStatement.new + sc.limit = "omg" + assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + end + it "should visit_DateTime" do @visitor.accept DateTime.now end From 0c205386f33a6c287de3449bcd9a12b5d85cc08e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 20:28:33 -0800 Subject: [PATCH 0896/1492] limit members of the AST are visited --- History.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/History.txt b/History.txt index fa08015903cfd..f1161cac29bf3 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 2.0.7 (unreleased) + +* Bug Fixes + + * Limit members are visited + == 2.0.6 12/01/2010 * Bug Fixes From 54d62de817f19dfaa206584516ecaedbdbbaea98 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Tue, 7 Dec 2010 10:05:25 +0100 Subject: [PATCH 0897/1492] tests for passing a subquery to #in and #not_in --- test/visitors/test_to_sql.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index bae291d87cf5d..3c9fc95a0bddf 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -137,6 +137,15 @@ module Visitors } 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 @@ -185,6 +194,15 @@ def quote value, column = nil } 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 From 1135c2c0884bfddffa39b784d71cd3fb22bd8988 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Tue, 7 Dec 2010 10:05:42 +0100 Subject: [PATCH 0898/1492] implementation for passing a subquery to #in and #not_in --- lib/arel/predications.rb | 4 ++-- lib/arel/visitors/to_sql.rb | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 5a5c3d449563e..dec4392f0ff74 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -31,7 +31,7 @@ def eq_all others def in other case other when Arel::SelectManager - Nodes::In.new self, other.to_a.map { |x| x.id } + Arel::Nodes::In.new(self, other) when Range if other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, other.begin) @@ -56,7 +56,7 @@ def in_all others def not_in other case other when Arel::SelectManager - Nodes::NotIn.new self, other.to_a.map { |x| x.id } + Arel::Nodes::NotIn.new(self, other) when Range if other.exclude_end? left = Nodes::LessThan.new(self, other.begin) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 35a0d9746fb1c..f4c529bf92725 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -101,6 +101,10 @@ def visit_Arel_Nodes_Values o }.join ', '})" end + def visit_Arel_SelectManager o + o.to_sql + end + def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, @@ -233,17 +237,11 @@ def visit_Arel_Table o end def visit_Arel_Nodes_In o - right = o.right - "#{visit o.left} IN (#{ - right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') - })" + "#{visit o.left} IN (#{visit o.right})" end def visit_Arel_Nodes_NotIn o - right = o.right - "#{visit o.left} NOT IN (#{ - right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') - })" + "#{visit o.left} NOT IN (#{visit o.right})" end def visit_Arel_Nodes_And o @@ -320,6 +318,10 @@ def visit_String o; quote(o, @last_column) end alias :visit_ActiveSupport_StringInquirer :visit_String alias :visit_Class :visit_String + def visit_Array o + o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') + end + def quote value, column = nil @connection.quote value, column end From b9d2cd97888f76cf7c15fd1a7167c638950071c1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 10:46:30 -0800 Subject: [PATCH 0899/1492] refactoring where, fixing subselect --- lib/arel/delete_manager.rb | 6 +----- lib/arel/predications.rb | 4 ++-- lib/arel/select_manager.rb | 5 ----- lib/arel/tree_manager.rb | 9 +++++++++ lib/arel/update_manager.rb | 1 + lib/arel/visitors/to_sql.rb | 4 ---- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index 3aab248c23080..b4c61f708f423 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -3,6 +3,7 @@ class DeleteManager < Arel::TreeManager def initialize engine super @ast = Nodes::DeleteStatement.new + @ctx = @ast end def from relation @@ -10,11 +11,6 @@ def from relation self end - def where expression - @ast.wheres << expression - self - end - def wheres= list @ast.wheres = list end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index dec4392f0ff74..23e68e99f115d 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -31,7 +31,7 @@ def eq_all others def in other case other when Arel::SelectManager - Arel::Nodes::In.new(self, other) + Arel::Nodes::In.new(self, other.ast) when Range if other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, other.begin) @@ -56,7 +56,7 @@ def in_all others def not_in other case other when Arel::SelectManager - Arel::Nodes::NotIn.new(self, other) + Arel::Nodes::NotIn.new(self, other.ast) when Range if other.exclude_end? left = Nodes::LessThan.new(self, other.begin) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index de12402e9f1d1..07de9fe224877 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -107,11 +107,6 @@ def project *projections self end - def where expr - @ctx.wheres << expr - self - end - def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 6176f8a2509c5..2fa770a0e3457 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -9,6 +9,7 @@ class TreeManager def initialize engine @engine = engine @visitor = Visitors.visitor_for @engine + @ctx = nil end def to_dot @@ -23,5 +24,13 @@ 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 diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index c0fb4fbd5f675..821dce7d81a43 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -3,6 +3,7 @@ class UpdateManager < Arel::TreeManager def initialize engine super @ast = Nodes::UpdateStatement.new + @ctx = @ast end def take limit diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5446298189030..b71f8219bfe61 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -101,10 +101,6 @@ def visit_Arel_Nodes_Values o }.join ', '})" end - def visit_Arel_SelectManager o - o.to_sql - end - def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, From 40105685957e377c263cfdd59178d3efc3a64181 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 20:26:08 -0800 Subject: [PATCH 0900/1492] quoting limit nodes --- lib/arel/visitors/mysql.rb | 2 +- lib/arel/visitors/postgresql.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_mysql.rb | 6 ++++++ test/visitors/test_postgres.rb | 8 ++++++++ test/visitors/test_to_sql.rb | 6 ++++++ 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 143b4d36f4aba..ace8fb0979714 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -25,7 +25,7 @@ def visit_Arel_Nodes_UpdateStatement o ("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?), - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), ].compact.join ' ' end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 553ee91bf9a6b..01fbda75b941c 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -17,7 +17,7 @@ def visit_Arel_Nodes_SelectStatement o [ "SELECT * FROM (#{sql}) AS id_list", "ORDER BY #{aliased_orders(o.orders).join(', ')}", - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), (visit(o.offset) if o.offset), ].compact.join ' ' else diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2713621a54ca9..2fb464b265e7e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -76,7 +76,7 @@ def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), - ("LIMIT #{o.limit}" if o.limit), + ("LIMIT #{visit o.limit}" if o.limit), (visit(o.offset) if o.offset), (visit(o.lock) if o.lock), ].compact.join ' ' diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 8606dc39d4ab9..135348580d1b3 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -17,6 +17,12 @@ module Visitors sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1" end + it "should escape LIMIT" do + sc = Arel::Nodes::UpdateStatement.new + sc.limit = "omg" + assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + end + it 'uses DUAL for empty from' do stmt = Nodes::SelectStatement.new sql = @visitor.accept(stmt) diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 618745c35d1db..b98f78ca12b42 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -12,6 +12,14 @@ module Visitors FOR UPDATE } end + + it "should escape LIMIT" do + sc = Arel::Nodes::SelectStatement.new + sc.limit = "omg" + sc.cores.first.projections << 'DISTINCT ON' + sc.orders << "xyz" + assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 5cbaaac501514..b9d6c78e62156 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -30,6 +30,12 @@ module Visitors @visitor.accept(DateTime).must_equal "'DateTime'" end + it "should escape LIMIT" do + sc = Arel::Nodes::SelectStatement.new + sc.limit = "omg" + assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + end + it "should visit_DateTime" do @visitor.accept DateTime.now end From c480b6fa27d0e9be910ea32deda8949f631e9d59 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 20:28:33 -0800 Subject: [PATCH 0901/1492] limit members of the AST are visited --- History.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/History.txt b/History.txt index fa08015903cfd..f1161cac29bf3 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 2.0.7 (unreleased) + +* Bug Fixes + + * Limit members are visited + == 2.0.6 12/01/2010 * Bug Fixes From 1c0d8c980c3b528ce2aeb0a528590822a31b5ef2 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Tue, 7 Dec 2010 10:05:25 +0100 Subject: [PATCH 0902/1492] tests for passing a subquery to #in and #not_in --- test/visitors/test_to_sql.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b9d6c78e62156..e08dc89793b0e 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -143,6 +143,15 @@ module Visitors } 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 @@ -189,6 +198,15 @@ def quote value, column = nil } 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 From 16ee8f66bcc527406e44c28a441e8f25481c5a0d Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Tue, 7 Dec 2010 10:05:42 +0100 Subject: [PATCH 0903/1492] implementation for passing a subquery to #in and #not_in --- lib/arel/predications.rb | 4 ++-- lib/arel/visitors/to_sql.rb | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 5a5c3d449563e..dec4392f0ff74 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -31,7 +31,7 @@ def eq_all others def in other case other when Arel::SelectManager - Nodes::In.new self, other.to_a.map { |x| x.id } + Arel::Nodes::In.new(self, other) when Range if other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, other.begin) @@ -56,7 +56,7 @@ def in_all others def not_in other case other when Arel::SelectManager - Nodes::NotIn.new self, other.to_a.map { |x| x.id } + Arel::Nodes::NotIn.new(self, other) when Range if other.exclude_end? left = Nodes::LessThan.new(self, other.begin) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2fb464b265e7e..6fc206c12c788 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -72,6 +72,10 @@ def visit_Arel_Nodes_Values o }.join ', '})" end + def visit_Arel_SelectManager o + o.to_sql + end + def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, @@ -204,17 +208,11 @@ def visit_Arel_Table o end def visit_Arel_Nodes_In o - right = o.right - "#{visit o.left} IN (#{ - right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') - })" + "#{visit o.left} IN (#{visit o.right})" end def visit_Arel_Nodes_NotIn o - right = o.right - "#{visit o.left} NOT IN (#{ - right.empty? ? 'NULL' : right.map { |x| visit x }.join(', ') - })" + "#{visit o.left} NOT IN (#{visit o.right})" end def visit_Arel_Nodes_And o @@ -291,6 +289,10 @@ def visit_String o; quote(o, @last_column) end alias :visit_ActiveSupport_StringInquirer :visit_String alias :visit_Class :visit_String + def visit_Array o + o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') + end + def quote value, column = nil @connection.quote value, column end From 4147f4bbf8c47379e795acfe0b65d6260e23a197 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 10:46:30 -0800 Subject: [PATCH 0904/1492] refactoring where, fixing subselect --- lib/arel/delete_manager.rb | 6 +----- lib/arel/predications.rb | 4 ++-- lib/arel/select_manager.rb | 5 ----- lib/arel/tree_manager.rb | 9 +++++++++ lib/arel/update_manager.rb | 1 + lib/arel/visitors/to_sql.rb | 4 ---- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index 3aab248c23080..b4c61f708f423 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -3,6 +3,7 @@ class DeleteManager < Arel::TreeManager def initialize engine super @ast = Nodes::DeleteStatement.new + @ctx = @ast end def from relation @@ -10,11 +11,6 @@ def from relation self end - def where expression - @ast.wheres << expression - self - end - def wheres= list @ast.wheres = list end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index dec4392f0ff74..23e68e99f115d 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -31,7 +31,7 @@ def eq_all others def in other case other when Arel::SelectManager - Arel::Nodes::In.new(self, other) + Arel::Nodes::In.new(self, other.ast) when Range if other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, other.begin) @@ -56,7 +56,7 @@ def in_all others def not_in other case other when Arel::SelectManager - Arel::Nodes::NotIn.new(self, other) + Arel::Nodes::NotIn.new(self, other.ast) when Range if other.exclude_end? left = Nodes::LessThan.new(self, other.begin) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 08cfd41e7f203..10d23378aeb4b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -107,11 +107,6 @@ def project *projections self end - def where expr - @ctx.wheres << expr - self - end - def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 6176f8a2509c5..2fa770a0e3457 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -9,6 +9,7 @@ class TreeManager def initialize engine @engine = engine @visitor = Visitors.visitor_for @engine + @ctx = nil end def to_dot @@ -23,5 +24,13 @@ 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 diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index c0fb4fbd5f675..821dce7d81a43 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -3,6 +3,7 @@ class UpdateManager < Arel::TreeManager def initialize engine super @ast = Nodes::UpdateStatement.new + @ctx = @ast end def take limit diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 6fc206c12c788..a2105d704334d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -72,10 +72,6 @@ def visit_Arel_Nodes_Values o }.join ', '})" end - def visit_Arel_SelectManager o - o.to_sql - end - def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, From ee3c55c84996ad2565762fa1f472259460d7d731 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 6 Dec 2010 20:16:16 -0800 Subject: [PATCH 0905/1492] consolidating dot visitor methods --- lib/arel/visitors/dot.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index c515cbe220535..eab5e4afdc340 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,10 +28,6 @@ def accept object end private - def visit_Arel_Nodes_Grouping o - visit_edge o, "expr" - end - def visit_Arel_Nodes_Ordering o visit_edge o, "expr" visit_edge o, "direction" @@ -55,10 +51,6 @@ def visit_Arel_Nodes_Count o visit_edge o, "distinct" end - def visit_Arel_Nodes_On o - visit_edge o, "expr" - end - def visit_Arel_Nodes_Values o visit_edge o, "expressions" end @@ -80,10 +72,6 @@ def visit_Arel_Nodes_DeleteStatement o visit_edge o, "wheres" end - def visit_Arel_Nodes_UnqualifiedColumn o - visit_edge o, "attribute" - end - def unary o visit_edge o, "expr" end From 89194f5976d09a62f967e550daeda41ac0b9de48 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 11:44:32 -0800 Subject: [PATCH 0906/1492] adding a join factory method on the select manager --- Manifest.txt | 1 + lib/arel.rb | 1 + lib/arel/factory_methods.rb | 9 +++++++++ lib/arel/nodes/string_join.rb | 4 ++-- lib/arel/table.rb | 7 ++++--- lib/arel/tree_manager.rb | 1 + test/test_select_manager.rb | 18 ++++++++++++++++++ test/test_table.rb | 16 ++++++++++++++++ 8 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 lib/arel/factory_methods.rb diff --git a/Manifest.txt b/Manifest.txt index 095d3c276e67c..e60978a947ae6 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -14,6 +14,7 @@ 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/nodes.rb lib/arel/nodes/and.rb diff --git a/lib/arel.rb b/lib/arel.rb index 6a8d9571d14d2..3d0648263b14e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,4 +1,5 @@ require 'arel/crud' +require 'arel/factory_methods' require 'arel/expressions' require 'arel/predications' diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb new file mode 100644 index 0000000000000..23d668c8e558a --- /dev/null +++ b/lib/arel/factory_methods.rb @@ -0,0 +1,9 @@ +module Arel + ### + # Methods for creating various nodes + module FactoryMethods + def create_join from, to, on = nil, klass = Nodes::InnerJoin + klass.new(from, to, on) + end + end +end diff --git a/lib/arel/nodes/string_join.rb b/lib/arel/nodes/string_join.rb index ea7912f92b506..b24e91b6b89c8 100644 --- a/lib/arel/nodes/string_join.rb +++ b/lib/arel/nodes/string_join.rb @@ -3,8 +3,8 @@ module Nodes class StringJoin < Arel::Nodes::Join undef :constraint - def initialize left, right - super(left, right, nil) + def initialize left, right, on = nil + super end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index e7a626a4c6764..ceb81705b35d9 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -1,6 +1,7 @@ module Arel class Table include Arel::Crud + include Arel::FactoryMethods @engine = nil class << self; attr_accessor :engine; end @@ -57,10 +58,10 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral raise if relation.blank? - from Nodes::StringJoin.new(self, relation) - else - from klass.new(self, relation, nil) + klass = Nodes::StringJoin end + + from create_join(self, relation, nil, klass) end def group *columns diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 2fa770a0e3457..5722baca77969 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -2,6 +2,7 @@ module Arel class TreeManager # FIXME: Remove this. include Arel::Relation + include Arel::FactoryMethods attr_accessor :visitor attr_reader :ast, :engine diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 826832c5ab5f3..2b88022ca31d9 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -277,6 +277,24 @@ def execute sql, name = nil, *args end end + it 'should create join nodes' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', 'baz' + assert_kind_of Arel::Nodes::InnerJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + assert_equal 'baz', join.constraint + end + + it 'should create join nodes with a klass' do + relation = Arel::SelectManager.new Table.engine + join = relation.create_join 'foo', 'bar', 'baz', Arel::Nodes::OuterJoin + assert_kind_of Arel::Nodes::OuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + assert_equal 'baz', join.constraint + end + describe 'join' do it 'responds to join' do left = Table.new :users diff --git a/test/test_table.rb b/test/test_table.rb index bb7bd255fd31c..7d773b2e2ba34 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -6,6 +6,22 @@ module Arel @relation = Table.new(:users) end + it 'should create join nodes' do + join = @relation.create_join 'foo', 'bar', 'baz' + assert_kind_of Arel::Nodes::InnerJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + assert_equal 'baz', join.constraint + end + + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', 'baz', Arel::Nodes::OuterJoin + assert_kind_of Arel::Nodes::OuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + assert_equal 'baz', join.constraint + end + it 'should return an insert manager' do im = @relation.compile_insert 'VALUES(NULL)' assert_kind_of Arel::InsertManager, im From 9a5b5e533600de7421700fd8f1498bfa0ce42a9c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 14:20:30 -0800 Subject: [PATCH 0907/1492] converting froms to from --- lib/arel/nodes/select_core.rb | 9 ++++++--- lib/arel/visitors/to_sql.rb | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index acc6bb9815d8c..e2293f68a2d84 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,11 +1,14 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node - attr_accessor :froms, :projections, :wheres, :groups + attr_accessor :from, :projections, :wheres, :groups attr_accessor :having + alias :froms= :from= + alias :froms :from + def initialize - @froms = nil + @from = nil @projections = [] @wheres = [] @groups = [] @@ -14,7 +17,7 @@ def initialize def initialize_copy other super - @froms = @froms.clone if @froms + @from = @from.clone if @from @projections = @projections.clone @wheres = @wheres.clone @group = @groups.clone diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b71f8219bfe61..9f581ee470995 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -114,7 +114,7 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_SelectCore o [ "SELECT #{o.projections.map { |x| visit x }.join ', '}", - ("FROM #{visit o.froms}" if o.froms), + ("FROM #{visit o.from}" if o.from), ("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), From 79657a3512335d5de77fd7d1443cad3b00e2816b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 14:59:13 -0800 Subject: [PATCH 0908/1492] creating string join nodes --- lib/arel/factory_methods.rb | 4 ++++ test/test_table.rb | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 23d668c8e558a..8fcb78069f322 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -5,5 +5,9 @@ module FactoryMethods def create_join from, to, on = nil, klass = Nodes::InnerJoin klass.new(from, to, on) end + + def create_string_join from, to + create_join from, to, nil, Nodes::StringJoin + end end end diff --git a/test/test_table.rb b/test/test_table.rb index 7d773b2e2ba34..65454d402b4f8 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -6,6 +6,13 @@ module Arel @relation = Table.new(:users) end + it 'should create join nodes' do + join = @relation.create_string_join 'foo', 'bar' + assert_kind_of Arel::Nodes::StringJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should create join nodes' do join = @relation.create_join 'foo', 'bar', 'baz' assert_kind_of Arel::Nodes::InnerJoin, join From dfc66f44218aa2ef2bd768000fd6e83b4fd8c96a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 15:00:00 -0800 Subject: [PATCH 0909/1492] renaming froms to from --- lib/arel/select_manager.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 07de9fe224877..bbe41ac4f19ce 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -66,8 +66,8 @@ def from table # FIXME: this is a hack to support # test_with_two_tables_in_from_without_getting_double_quoted # from the AR tests. - if @ctx.froms - source = @ctx.froms + if @ctx.from + source = @ctx.from if Nodes::SqlLiteral === table && Nodes::Join === source source.left = table @@ -75,7 +75,7 @@ def from table end end - @ctx.froms = table + @ctx.from = table self end From 8f6752ef6e4c5ab0aaafad8c543f9925a7b33774 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 15:05:51 -0800 Subject: [PATCH 0910/1492] get from values out of the select manager --- lib/arel/select_manager.rb | 4 ++++ test/test_select_manager.rb | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index bbe41ac4f19ce..30495fc8d03ef 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -79,6 +79,10 @@ def from table self end + def froms + @ast.cores.map { |x| x.from }.compact + end + def join relation, klass = Nodes::InnerJoin return self unless relation diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 2b88022ca31d9..672b5ea78d791 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -277,6 +277,11 @@ def execute sql, name = nil, *args end end + it 'should hand back froms' do + relation = Arel::SelectManager.new Table.engine + assert_equal [], relation.froms + end + it 'should create join nodes' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', 'baz' From af5dd388cc1d5f58ac2f010730a301e0c7d7e6e6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 7 Dec 2010 15:11:22 -0800 Subject: [PATCH 0911/1492] just return a blank string if the base from is not a join --- lib/arel/visitors/join_sql.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 7ba2bde540e8c..427f2bb726426 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -12,7 +12,8 @@ module JoinSql private def visit_Arel_Nodes_SelectCore o - [o.froms].grep(Nodes::Join).map { |x| visit x }.join ', ' + return '' unless Nodes::Join === o.from + visit o.from end def visit_Arel_Nodes_StringJoin o From 99774f8ed3c4f356d318b38ade568ae0d9456de7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Dec 2010 10:05:09 -0800 Subject: [PATCH 0912/1492] caches should be connection specific --- lib/arel/visitors/to_sql.rb | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9f581ee470995..308a5bf40003e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -10,8 +10,14 @@ def initialize engine @last_column = nil @quoted_tables = {} @quoted_columns = {} - @column_cache = Hash.new { |h,k| h[k] = {} } - @table_exists = {} + @column_cache = Hash.new { |h,conn| + h[conn] = Hash.new { |conn_h,column| + conn_h[column] = {} + } + } + @table_exists = Hash.new { |h,conn| + h[conn] = {} + } end def accept object @@ -69,13 +75,17 @@ def visit_Arel_Nodes_Exists o end def table_exists? name - return true if @table_exists.key? name + return true if table_exists.key? name @connection.tables.each do |table| - @table_exists[table] = true + table_exists[table] = true end - @table_exists.key? name + table_exists.key? name + end + + def table_exists + @table_exists[@connection] end def column_for attr @@ -86,13 +96,16 @@ def column_for attr # If we don't have this column cached, get a list of columns and # cache them for this table - unless @column_cache.key? table - #$stderr.puts "MISS: #{self.class.name} #{object_id} #{table.inspect} : #{name.inspect}" + unless column_cache.key? table columns = @connection.columns(table, "#{table}(#{name}) Columns") - @column_cache[table] = Hash[columns.map { |c| [c.name.to_sym, c] }] + column_cache[table] = Hash[columns.map { |c| [c.name.to_sym, c] }] end - @column_cache[table][name] + column_cache[table][name] + end + + def column_cache + @column_cache[@connection] end def visit_Arel_Nodes_Values o From 11e29a32af658ee0956b1237fea1033698a457e8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Dec 2010 14:48:28 -0800 Subject: [PATCH 0913/1492] AND nodes are now n-ary --- lib/arel/nodes/and.rb | 17 +++++++++++++++++ lib/arel/nodes/node.rb | 2 +- lib/arel/select_manager.rb | 14 ++++++-------- lib/arel/visitors/to_sql.rb | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb index 80f420b4f1e6e..b087a10930bff 100644 --- a/lib/arel/nodes/and.rb +++ b/lib/arel/nodes/and.rb @@ -1,6 +1,23 @@ module Arel module Nodes class And < Arel::Nodes::Binary + 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 end end end diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 567221aab2a4c..ff788e90d2260 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -22,7 +22,7 @@ def or right ### # Factory method to create an Nodes::And node. def and right - Nodes::And.new self, right + Nodes::And.new [self, right] end # FIXME: this method should go away. I don't like people calling diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 30495fc8d03ef..40e197910bc0e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -198,14 +198,12 @@ def insert values def collapse exprs return exprs.first if exprs.length == 1 - right = exprs.pop - left = exprs.pop - - right = Nodes::SqlLiteral.new(right) if String === right - - right = Nodes::And.new left, right - exprs.reverse.inject(right) { |memo,expr| - Nodes::And.new(expr, memo) + Nodes::And.new exprs.compact.map { |expr| + if String === expr + Arel.sql(expr) + else + expr + end } end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 308a5bf40003e..5767fbae8d9f1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -254,7 +254,7 @@ def visit_Arel_Nodes_NotIn o end def visit_Arel_Nodes_And o - "#{visit o.left} AND #{visit o.right}" + o.children.map { |x| visit x }.join ' AND ' end def visit_Arel_Nodes_Or o From 6be1a71464f1e6833330b6cf9e239fd21b54c625 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Dec 2010 14:52:11 -0800 Subject: [PATCH 0914/1492] stop using deprecated AND usage --- lib/arel/predications.rb | 6 +++--- test/visitors/test_depth_first.rb | 12 +++++++++++- test/visitors/test_to_sql.rb | 4 ++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 23e68e99f115d..58f02a2b53bb8 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -36,9 +36,9 @@ def in other if other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, other.begin) right = Nodes::LessThan.new(self, other.end) - Nodes::And.new left, right + Nodes::And.new [left, right] else - Nodes::Between.new(self, Nodes::And.new(other.begin, other.end)) + Nodes::Between.new(self, Nodes::And.new([other.begin, other.end])) end else Nodes::In.new self, other @@ -174,7 +174,7 @@ def grouping_all method_id, others first = send method_id, others.shift Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::And.new(memo, send(method_id, expr)) + Nodes::And.new([memo, send(method_id, expr)]) } end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 1bee0328cfea6..1f1c7ab36175a 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -78,7 +78,6 @@ def test_outer_join end [ - Arel::Nodes::And, Arel::Nodes::Assignment, Arel::Nodes::Between, Arel::Nodes::DoesNotMatch, @@ -106,6 +105,17 @@ def test_outer_join end end + # N-ary + [ + Arel::Nodes::And, + ].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 + [ Arel::Attributes::Integer, Arel::Attributes::Float, diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index c49d2a6bdf87b..80384d3c289e8 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -50,7 +50,7 @@ module Visitors end it "should apply Not to the whole expression" do - node = Nodes::And.new @attr.eq(10), @attr.eq(11) + 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 @@ -82,7 +82,7 @@ module Visitors end it "should visit_Arel_Nodes_And" do - node = Nodes::And.new @attr.eq(10), @attr.eq(11) + node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] @visitor.accept(node).must_be_like %{ "users"."id" = 10 AND "users"."id" = 11 } From 1d4cfb98954ac602c22245992c15be06feb55c08 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Dec 2010 14:52:55 -0800 Subject: [PATCH 0915/1492] updating changelog --- History.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/History.txt b/History.txt index 25c7fba1e676d..6094c7f6cab0a 100644 --- a/History.txt +++ b/History.txt @@ -3,6 +3,7 @@ * Enhancements * AST is now Enumerable + * AND nodes are now n-ary nodes * Deprecations @@ -24,6 +25,8 @@ * 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. + == 2.0.7 (unreleased) * Bug Fixes From 30a0a9c23bc875eaca0c4b525696ed3ea074ba74 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Dec 2010 15:42:29 -0800 Subject: [PATCH 0916/1492] adding a factory method for and nodes --- lib/arel/factory_methods.rb | 4 ++++ lib/arel/select_manager.rb | 2 +- test/test_select_manager.rb | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 8fcb78069f322..e45cc21170ef9 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -9,5 +9,9 @@ def create_join from, to, on = nil, klass = Nodes::InnerJoin def create_string_join from, to create_join from, to, nil, Nodes::StringJoin end + + def create_and clauses + Nodes::And.new clauses + end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 40e197910bc0e..f8b3089a82eb0 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -198,7 +198,7 @@ def insert values def collapse exprs return exprs.first if exprs.length == 1 - Nodes::And.new exprs.compact.map { |expr| + create_and exprs.compact.map { |expr| if String === expr Arel.sql(expr) else diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 672b5ea78d791..dec1c2d8c7c1c 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -282,6 +282,14 @@ def execute sql, name = nil, *args 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 join nodes' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', 'baz' From a84c34fa08596c563226f3df216e3adf8868f112 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Dec 2010 15:52:12 -0800 Subject: [PATCH 0917/1492] refactor SelectManager to use the create_join factory method --- lib/arel/select_manager.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f8b3089a82eb0..09491c988b569 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -89,10 +89,10 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral raise if relation.blank? - from Nodes::StringJoin.new(@ctx.froms, relation) - else - from klass.new(@ctx.froms, relation, nil) + klass = Nodes::StringJoin end + + from create_join(@ctx.froms, relation, nil, klass) end def having expr From 2d320e366a586fa9869080950e4c27f4aad55a5a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Dec 2010 09:16:41 -0800 Subject: [PATCH 0918/1492] testing nary nodes in the depth first visitor --- lib/arel/select_manager.rb | 2 +- lib/arel/visitors/depth_first.rb | 6 +++++- lib/arel/visitors/dot.rb | 8 +++++++- test/visitors/test_depth_first.rb | 4 ++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 09491c988b569..372b6aae6f78a 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -92,7 +92,7 @@ def join relation, klass = Nodes::InnerJoin klass = Nodes::StringJoin end - from create_join(@ctx.froms, relation, nil, klass) + from create_join(@ctx.from, relation, nil, klass) end def having expr diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 00f18727f03ed..49133653c5e52 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -47,11 +47,15 @@ def join o alias :visit_Arel_Nodes_InnerJoin :join alias :visit_Arel_Nodes_OuterJoin :join + 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_And :binary alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index eab5e4afdc340..4f80f31421fb5 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -123,11 +123,17 @@ def visit_Arel_Attribute o 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 visit_Arel_Nodes_Equality o visit_edge o, "left" visit_edge o, "right" end - alias :visit_Arel_Nodes_And :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_Or :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_NotEqual :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_GreaterThan :visit_Arel_Nodes_Equality diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 1f1c7ab36175a..7d7324f62793d 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -110,9 +110,9 @@ def test_outer_join Arel::Nodes::And, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do - binary = klass.new([:a, :b]) + binary = klass.new([:a, :b, :c]) @visitor.accept binary - assert_equal [:a, :b, binary], @collector.calls + assert_equal [:a, :b, :c, binary], @collector.calls end end From 99ae19edd38e5cbb87e827dd28607d3b1cbbb0b7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 10 Dec 2010 14:45:38 -0800 Subject: [PATCH 0919/1492] factory method for creating ON nodes --- lib/arel/factory_methods.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index e45cc21170ef9..c9b6c3b791c6b 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -13,5 +13,9 @@ def create_string_join from, to def create_and clauses Nodes::And.new clauses end + + def create_on expr + Nodes::On.new expr + end end end From 761b0d98f7374c50f1256ff2b4c25c6c843dba4b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 Dec 2010 13:20:45 -0800 Subject: [PATCH 0920/1492] deprecating SelectManager#insert --- lib/arel/select_manager.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 372b6aae6f78a..1100c29f20ad5 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -180,13 +180,22 @@ def to_a # :nodoc: # FIXME: this method should go away def insert values - im = InsertManager.new @engine + if $VERBOSE + warn <<-eowarn +insert (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please +switch to `compile_insert` + eowarn + end + + im = compile_insert(values) table = @ctx.froms - primary_key_name = (primary_key = table.primary_key) && primary_key.name + + 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 - im.insert values # 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 From 99816bf8cc452b1c64ea76d510306f00d22122fd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 Dec 2010 13:29:33 -0800 Subject: [PATCH 0921/1492] deprecating Arel::Table#primary_key --- History.txt | 3 +++ lib/arel/table.rb | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/History.txt b/History.txt index 6094c7f6cab0a..d16baa5b305d5 100644 --- a/History.txt +++ b/History.txt @@ -27,6 +27,9 @@ * 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. + == 2.0.7 (unreleased) * Bug Fixes diff --git a/lib/arel/table.rb b/lib/arel/table.rb index ceb81705b35d9..a68705fedf4b6 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -27,6 +27,12 @@ def initialize name, engine = Table.engine end def primary_key + if $VERBOSE + warn <<-eowarn +primary_key (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please +switch to `compile_insert` + eowarn + end @primary_key ||= begin primary_key_name = @engine.connection.primary_key(name) # some tables might be without primary key From 1c77cf2cc4d00097a52edf7ae6fa0de519273cc0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 Dec 2010 13:30:11 -0800 Subject: [PATCH 0922/1492] fixing deprecation notice --- lib/arel/table.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index a68705fedf4b6..bfc667bf2b4b6 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -29,8 +29,7 @@ def initialize name, engine = Table.engine def primary_key if $VERBOSE warn <<-eowarn -primary_key (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please -switch to `compile_insert` +primary_key (#{caller.first}) is deprecated and will be removed in ARel 3.0.0 eowarn end @primary_key ||= begin From f694d9e7c332cf4d9bce6742b440bf97308cefb5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 13 Dec 2010 22:16:29 -0800 Subject: [PATCH 0923/1492] adding tests for factory methods --- test/test_factory_methods.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/test_factory_methods.rb diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb new file mode 100644 index 0000000000000..89b10236d1416 --- /dev/null +++ b/test/test_factory_methods.rb @@ -0,0 +1,27 @@ +require '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, :three + assert_kind_of Nodes::Join, join + assert_equal :three, join.constraint + end + + def test_create_on + on = @factory.create_on :one + assert_instance_of Nodes::On, on + assert_equal :one, on.expr + end + end + end +end From 87c022bc98c57027f534d5e667cfc0344b5b40f0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 08:47:57 -0800 Subject: [PATCH 0924/1492] removing tests of deprecated methods --- test/test_crud.rb | 6 ++---- test/test_table.rb | 32 -------------------------------- 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/test/test_crud.rb b/test/test_crud.rb index ebe5d68908751..fe3e4f2e02342 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -35,10 +35,8 @@ def initialize engine = FakeEngine.new table = Table.new :users fc = FakeCrudder.new fc.from table - fc.insert [[table[:id], 'foo']] - fc.engine.calls.find { |method, _| - method == :insert - }.wont_be_nil + im = fc.compile_insert [[table[:id], 'foo']] + assert_instance_of Arel::InsertManager, im end end diff --git a/test/test_table.rb b/test/test_table.rb index 65454d402b4f8..42362b563eca2 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -48,12 +48,6 @@ module Arel end end - describe 'primary_key' do - it 'should return an attribute' do - @relation.primary_key.name.must_equal :id - end - end - describe 'select_manager' do it 'should return an empty select manager' do sm = @relation.select_manager @@ -113,13 +107,6 @@ module Arel end describe 'new' do - it 'takes :columns' do - columns = Table.engine.connection.columns("users") - @relation = Table.new(:users, :columns => columns) - @relation.columns.first.name.must_equal :id - @relation.engine.must_equal Table.engine - end - it 'should accept an engine' do rel = Table.new :users, 'foo' rel.engine.must_equal 'foo' @@ -176,14 +163,6 @@ module Arel end end - describe 'columns' do - it 'returns a list of columns' do - columns = @relation.columns - columns.length.must_equal 4 - columns.map { |x| x.name.to_s }.sort.must_equal %w{ created_at bool name id }.sort - end - end - it "should have a name" do @relation.name.must_equal 'users' end @@ -201,15 +180,4 @@ module Arel end end end - - describe Table do - describe 'when checking the existence of a table' do - it 'should be present in the table cache despite the class of its name' do - [ 'users', :users ].each do |name| - relation = Table.new name - Table.table_cache(relation.engine).key?(relation.name).must_equal true - end - end - end - end end From 9653da3c7963834eb9ed93bf24837147fa9b0461 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 09:43:19 -0800 Subject: [PATCH 0925/1492] adding a join source node --- Manifest.txt | 2 ++ lib/arel/factory_methods.rb | 6 +++--- lib/arel/nodes.rb | 1 + lib/arel/nodes/join.rb | 12 ++++++------ lib/arel/nodes/join_source.rb | 20 ++++++++++++++++++++ lib/arel/nodes/select_core.rb | 22 +++++++++++++++------- lib/arel/nodes/string_join.rb | 5 ----- lib/arel/select_manager.rb | 19 +++++++++---------- lib/arel/table.rb | 2 +- lib/arel/visitors/depth_first.rb | 10 ++-------- lib/arel/visitors/dot.rb | 4 ++-- lib/arel/visitors/join_sql.rb | 17 +---------------- lib/arel/visitors/to_sql.rb | 16 +++++++++++++--- test/test_factory_methods.rb | 4 ++-- test/test_select_manager.rb | 10 ++++------ test/test_table.rb | 6 ++---- test/visitors/test_depth_first.rb | 8 ++++---- test/visitors/test_join_sql.rb | 13 +++++++------ 18 files changed, 94 insertions(+), 83 deletions(-) create mode 100644 lib/arel/nodes/join_source.rb diff --git a/Manifest.txt b/Manifest.txt index e60978a947ae6..3735d854817b5 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -38,6 +38,7 @@ lib/arel/nodes/in.rb lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb lib/arel/nodes/join.rb +lib/arel/nodes/join_source.rb lib/arel/nodes/less_than.rb lib/arel/nodes/less_than_or_equal.rb lib/arel/nodes/lock.rb @@ -103,6 +104,7 @@ 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 diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index c9b6c3b791c6b..85862c24c17a9 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -2,12 +2,12 @@ module Arel ### # Methods for creating various nodes module FactoryMethods - def create_join from, to, on = nil, klass = Nodes::InnerJoin - klass.new(from, to, on) + def create_join to, constraint = nil, klass = Nodes::InnerJoin + klass.new(to, constraint) end def create_string_join from, to - create_join from, to, nil, Nodes::StringJoin + create_join from, to, Nodes::StringJoin end def create_and clauses diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index c454152d0d98b..4cc93d7de4b56 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -15,6 +15,7 @@ require 'arel/nodes/less_than_or_equal' require 'arel/nodes/matches' require 'arel/nodes/does_not_match' +require 'arel/nodes/join_source' require 'arel/nodes/in' require 'arel/nodes/not_in' diff --git a/lib/arel/nodes/join.rb b/lib/arel/nodes/join.rb index 07f8c98e85887..d3307fe0e0748 100644 --- a/lib/arel/nodes/join.rb +++ b/lib/arel/nodes/join.rb @@ -1,12 +1,12 @@ module Arel module Nodes - class Join < Arel::Nodes::Node - attr_accessor :left, :right, :constraint + class Join < Arel::Nodes::Binary - def initialize left, right, constraint - @left = left - @right = right - @constraint = constraint + alias :single_source :left + alias :constraint :right + + def initialize single_source, constraint + super end end end diff --git a/lib/arel/nodes/join_source.rb b/lib/arel/nodes/join_source.rb new file mode 100644 index 0000000000000..7b739c19ada6a --- /dev/null +++ b/lib/arel/nodes/join_source.rb @@ -0,0 +1,20 @@ +module 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 initialize_copy other + super + @left = @left.clone if @left + @right = @right.clone if @right + end + end + end +end diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index e2293f68a2d84..bd1930364d0d5 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,23 +1,31 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node - attr_accessor :from, :projections, :wheres, :groups - attr_accessor :having - - alias :froms= :from= - alias :froms :from + attr_accessor :projections, :wheres, :groups + attr_accessor :having, :source def initialize - @from = nil + @source = JoinSource.new nil @projections = [] @wheres = [] @groups = [] @having = nil end + def from + @source.left + end + + def from= value + @source.left = value + end + + alias :froms= :from= + alias :froms :from + def initialize_copy other super - @from = @from.clone if @from + @source = @source.clone if @source @projections = @projections.clone @wheres = @wheres.clone @group = @groups.clone diff --git a/lib/arel/nodes/string_join.rb b/lib/arel/nodes/string_join.rb index b24e91b6b89c8..b5420e2dfcbc1 100644 --- a/lib/arel/nodes/string_join.rb +++ b/lib/arel/nodes/string_join.rb @@ -1,11 +1,6 @@ module Arel module Nodes class StringJoin < Arel::Nodes::Join - undef :constraint - - def initialize left, right, on = nil - super - end end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 1100c29f20ad5..ec1264c3c27b6 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -46,7 +46,7 @@ def locked end def on *exprs - @ctx.froms.constraint = Nodes::On.new(collapse(exprs)) + @ctx.source.right.last.right = Nodes::On.new(collapse(exprs)) self end @@ -66,16 +66,14 @@ def from table # FIXME: this is a hack to support # test_with_two_tables_in_from_without_getting_double_quoted # from the AR tests. - if @ctx.from - source = @ctx.from - if Nodes::SqlLiteral === table && Nodes::Join === source - source.left = table - table = source - end + case table + when Nodes::SqlLiteral, Arel::Table + @ctx.source.left = table + when Nodes::Join + @ctx.source.right << table end - @ctx.from = table self end @@ -92,7 +90,8 @@ def join relation, klass = Nodes::InnerJoin klass = Nodes::StringJoin end - from create_join(@ctx.from, relation, nil, klass) + @ctx.source.right << create_join(relation, nil, klass) + self end def having expr @@ -140,7 +139,7 @@ def take limit end def join_sql - return nil unless @ctx.froms + return nil if @ctx.source.right.empty? sql = @visitor.dup.extend(Visitors::JoinSql).accept @ctx Nodes::SqlLiteral.new sql diff --git a/lib/arel/table.rb b/lib/arel/table.rb index bfc667bf2b4b6..a13fd9fa5bd78 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -66,7 +66,7 @@ def join relation, klass = Nodes::InnerJoin klass = Nodes::StringJoin end - from create_join(self, relation, nil, klass) + from(self).join(relation, klass) end def group *columns diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 49133653c5e52..9979c8313eeb9 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -39,14 +39,6 @@ def visit_Arel_Nodes_Count o visit o.distinct end - def join o - visit o.left - visit o.right - visit o.constraint - end - alias :visit_Arel_Nodes_InnerJoin :join - alias :visit_Arel_Nodes_OuterJoin :join - def nary o o.children.each { |child| visit child } end @@ -65,6 +57,7 @@ def binary o alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :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 @@ -72,6 +65,7 @@ def binary o alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_Ordering :binary + alias :visit_Arel_Nodes_OuterJoin :binary alias :visit_Arel_Nodes_StringJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 4f80f31421fb5..c525a64a89d32 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -36,7 +36,6 @@ def visit_Arel_Nodes_Ordering o def visit_Arel_Nodes_TableAlias o visit_edge o, "name" visit_edge o, "relation" - visit_edge o, "columns" end def visit_Arel_Nodes_Sum o @@ -90,7 +89,7 @@ def visit_Arel_Nodes_InsertStatement o end def visit_Arel_Nodes_SelectCore o - visit_edge o, "froms" + visit_edge o, "source" visit_edge o, "projections" visit_edge o, "wheres" end @@ -146,6 +145,7 @@ def visit_Arel_Nodes_Equality o alias :visit_Arel_Nodes_NotIn :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_DoesNotMatch :visit_Arel_Nodes_Equality alias :visit_Arel_Nodes_Matches :visit_Arel_Nodes_Equality + alias :visit_Arel_Nodes_JoinSource :visit_Arel_Nodes_Equality def visit_String o @node_stack.last.fields << o diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 427f2bb726426..8c31934cd0f68 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -12,8 +12,7 @@ module JoinSql private def visit_Arel_Nodes_SelectCore o - return '' unless Nodes::Join === o.from - visit o.from + o.source.right.map { |j| visit j }.join ' ' end def visit_Arel_Nodes_StringJoin o @@ -22,20 +21,6 @@ def visit_Arel_Nodes_StringJoin o visit(o.right) ].compact.join ' ' end - - def visit_Arel_Nodes_OuterJoin o - [ - (visit o.left if Nodes::Join === o.left), - "LEFT OUTER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" - ].compact.join ' ' - end - - def visit_Arel_Nodes_InnerJoin o - [ - (visit o.left if Nodes::Join === o.left), - "INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" - ].compact.join ' ' - end end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5767fbae8d9f1..b83bf2f6e71c7 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -127,7 +127,7 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_SelectCore o [ "SELECT #{o.projections.map { |x| visit x }.join ', '}", - ("FROM #{visit o.from}" if o.from), + visit(o.source), ("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), @@ -217,16 +217,26 @@ def visit_Arel_Nodes_DoesNotMatch o "#{visit o.left} NOT LIKE #{visit o.right}" end + def visit_Arel_Nodes_JoinSource o + return unless o.left || !o.right.empty? + + [ + "FROM", + (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} #{visit o.right}" end def visit_Arel_Nodes_OuterJoin o - "#{visit o.left} LEFT OUTER JOIN #{visit o.right} #{visit o.constraint}" + "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" end def visit_Arel_Nodes_InnerJoin o - "#{visit o.left} INNER JOIN #{visit o.right} #{visit o.constraint if o.constraint}" + "INNER JOIN #{visit o.left} #{visit o.right if o.right}" end def visit_Arel_Nodes_On o diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index 89b10236d1416..c40615564ff99 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -12,9 +12,9 @@ def setup end def test_create_join - join = @factory.create_join :one, :two, :three + join = @factory.create_join :one, :two assert_kind_of Nodes::Join, join - assert_equal :three, join.constraint + assert_equal :two, join.constraint end def test_create_on diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index dec1c2d8c7c1c..761ebdaee397e 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -292,20 +292,18 @@ def execute sql, name = nil, *args it 'should create join nodes' do relation = Arel::SelectManager.new Table.engine - join = relation.create_join 'foo', 'bar', 'baz' + join = relation.create_join 'foo', 'bar' assert_kind_of Arel::Nodes::InnerJoin, join assert_equal 'foo', join.left assert_equal 'bar', join.right - assert_equal 'baz', join.constraint end it 'should create join nodes with a klass' do relation = Arel::SelectManager.new Table.engine - join = relation.create_join 'foo', 'bar', 'baz', Arel::Nodes::OuterJoin + 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 - assert_equal 'baz', join.constraint end describe 'join' do @@ -350,7 +348,7 @@ def execute sql, name = nil, *args table = Table.new :users aliaz = table.alias manager = Arel::SelectManager.new Table.engine - manager.from Nodes::InnerJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) + 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" } @@ -360,7 +358,7 @@ def execute sql, name = nil, *args table = Table.new :users aliaz = table.alias manager = Arel::SelectManager.new Table.engine - manager.from Nodes::OuterJoin.new(table, aliaz, table[:id].eq(aliaz[:id])) + 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" } diff --git a/test/test_table.rb b/test/test_table.rb index 42362b563eca2..54f8b04b79431 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -14,19 +14,17 @@ module Arel end it 'should create join nodes' do - join = @relation.create_join 'foo', 'bar', 'baz' + join = @relation.create_join 'foo', 'bar' assert_kind_of Arel::Nodes::InnerJoin, join assert_equal 'foo', join.left assert_equal 'bar', join.right - assert_equal 'baz', join.constraint end it 'should create join nodes with a klass' do - join = @relation.create_join 'foo', 'bar', 'baz', Arel::Nodes::OuterJoin + 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 - assert_equal 'baz', join.constraint end it 'should return an insert manager' do diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 7d7324f62793d..23b011c2eb5f6 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -66,15 +66,15 @@ def test_count end def test_inner_join - join = Nodes::InnerJoin.new :a, :b, :c + join = Nodes::InnerJoin.new :a, :b @visitor.accept join - assert_equal [:a, :b, :c, join], @collector.calls + assert_equal [:a, :b, join], @collector.calls end def test_outer_join - join = Nodes::OuterJoin.new :a, :b, :c + join = Nodes::OuterJoin.new :a, :b @visitor.accept join - assert_equal [:a, :b, :c, join], @collector.calls + assert_equal [:a, :b, join], @collector.calls end [ diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index 181ef6c570a85..b0eba172e6148 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -11,9 +11,9 @@ module Visitors describe 'inner join' do it 'should visit left if left is a join' do t = Table.new :users - join = Nodes::InnerJoin.new t, t, Nodes::On.new(t[:id]) - j2 = Nodes::InnerJoin.new join, t, Nodes::On.new(t[:id]) - @visitor.accept(j2).must_be_like %{ + 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" } @@ -23,9 +23,10 @@ module Visitors describe 'outer join' do it 'should visit left if left is a join' do t = Table.new :users - join = Nodes::OuterJoin.new t, t, Nodes::On.new(t[:id]) - j2 = Nodes::OuterJoin.new join, t, Nodes::On.new(t[:id]) - @visitor.accept(j2).must_be_like %{ + 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" } From ed2e23c6b981b0a681ebe698ee107493a0e0dff3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 10:22:39 -0800 Subject: [PATCH 0926/1492] fixing create_string_join factory method --- lib/arel/factory_methods.rb | 4 ++-- lib/arel/nodes/inner_join.rb | 4 ++++ lib/arel/nodes/select_statement.rb | 1 + lib/arel/visitors/to_sql.rb | 2 +- test/test_table.rb | 3 +-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 85862c24c17a9..4899adfdc8ce2 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -6,8 +6,8 @@ def create_join to, constraint = nil, klass = Nodes::InnerJoin klass.new(to, constraint) end - def create_string_join from, to - create_join from, to, Nodes::StringJoin + def create_string_join to + create_join to, nil, Nodes::StringJoin end def create_and clauses diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index bf10eeac18684..d09d9e819b548 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -1,6 +1,10 @@ module Arel module Nodes class InnerJoin < Arel::Nodes::Join + def initialize left, right + raise if right == Arel::Nodes::StringJoin + super + end end end end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 6881a667474cb..c9a0cde4e00f9 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -5,6 +5,7 @@ class SelectStatement < Arel::Nodes::Node attr_accessor :limit, :orders, :lock, :offset def initialize cores = [SelectCore.new] + #puts caller @cores = cores @orders = [] @limit = nil diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b83bf2f6e71c7..8ceb839a6b187 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -228,7 +228,7 @@ def visit_Arel_Nodes_JoinSource o end def visit_Arel_Nodes_StringJoin o - "#{visit o.left} #{visit o.right}" + visit o.left end def visit_Arel_Nodes_OuterJoin o diff --git a/test/test_table.rb b/test/test_table.rb index 54f8b04b79431..129d7ba736ebc 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -7,10 +7,9 @@ module Arel end it 'should create join nodes' do - join = @relation.create_string_join 'foo', 'bar' + join = @relation.create_string_join 'foo' assert_kind_of Arel::Nodes::StringJoin, join assert_equal 'foo', join.left - assert_equal 'bar', join.right end it 'should create join nodes' do From 3a9b9a2d4948c943ca0e6fd35393da5846d95b82 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 10:26:18 -0800 Subject: [PATCH 0927/1492] removing test code. :-( --- lib/arel/nodes/inner_join.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index d09d9e819b548..bf10eeac18684 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -1,10 +1,6 @@ module Arel module Nodes class InnerJoin < Arel::Nodes::Join - def initialize left, right - raise if right == Arel::Nodes::StringJoin - super - end end end end From 7c48c8360e1b4e90f2a0c5ef15590355c4bf0856 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 10:38:55 -0800 Subject: [PATCH 0928/1492] select core should visit the source node --- lib/arel/visitors/depth_first.rb | 3 ++- test/visitors/test_depth_first.rb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 9979c8313eeb9..5ebd1296dd140 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -57,6 +57,7 @@ def binary o 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_InnerJoin :binary alias :visit_Arel_Nodes_LessThan :binary alias :visit_Arel_Nodes_LessThanOrEqual :binary @@ -116,7 +117,7 @@ def visit_Arel_Nodes_InsertStatement o def visit_Arel_Nodes_SelectCore o visit o.projections - visit o.froms + visit o.source visit o.wheres visit o.groups visit o.having diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 23b011c2eb5f6..34931c783e617 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -97,6 +97,7 @@ def test_outer_join Arel::Nodes::As, Arel::Nodes::DeleteStatement, Arel::Nodes::Ordering, + Arel::Nodes::JoinSource, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do binary = klass.new(:a, :b) From 24d598fad1a80c3ec1875588be577a37f9e4f9f9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 11:04:08 -0800 Subject: [PATCH 0929/1492] string join should be a unary op --- lib/arel/nodes/string_join.rb | 3 +++ lib/arel/visitors/depth_first.rb | 5 ++++- lib/arel/visitors/join_sql.rb | 7 ------- test/test_select_manager.rb | 2 +- test/visitors/test_depth_first.rb | 5 +++-- test/visitors/test_join_sql.rb | 5 +++++ 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/arel/nodes/string_join.rb b/lib/arel/nodes/string_join.rb index b5420e2dfcbc1..7fb0033c0f0cd 100644 --- a/lib/arel/nodes/string_join.rb +++ b/lib/arel/nodes/string_join.rb @@ -1,6 +1,9 @@ module Arel module Nodes class StringJoin < Arel::Nodes::Join + def initialize left, right = nil + super + end end end end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 5ebd1296dd140..eec356af4cf6a 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -67,10 +67,13 @@ def binary o alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_Ordering :binary alias :visit_Arel_Nodes_OuterJoin :binary - alias :visit_Arel_Nodes_StringJoin :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 diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 8c31934cd0f68..1cdd7eb5ca0d6 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -14,13 +14,6 @@ module JoinSql def visit_Arel_Nodes_SelectCore o o.source.right.map { |j| visit j }.join ' ' end - - def visit_Arel_Nodes_StringJoin o - [ - (visit o.left if Nodes::Join === o.left), - visit(o.right) - ].compact.join ' ' - end end end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 761ebdaee397e..15153d3523401 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -367,7 +367,7 @@ def execute sql, name = nil, *args it 'returns string join sql' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.from Nodes::StringJoin.new(table, 'hello') + manager.from Nodes::StringJoin.new('hello') manager.join_sql.must_be_like %{ 'hello' } end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 34931c783e617..4bce4681835f5 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -29,6 +29,7 @@ def test_raises_with_object Arel::Nodes::Grouping, Arel::Nodes::Offset, Arel::Nodes::Having, + Arel::Nodes::StringJoin, Arel::Nodes::UnqualifiedColumn, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do @@ -91,7 +92,6 @@ def test_outer_join Arel::Nodes::NotEqual, Arel::Nodes::NotIn, Arel::Nodes::Or, - Arel::Nodes::StringJoin, Arel::Nodes::TableAlias, Arel::Nodes::Values, Arel::Nodes::As, @@ -176,7 +176,8 @@ def test_select_core @visitor.accept core assert_equal [ :a, core.projections, - :b, + :b, [], + core.source, :c, core.wheres, :d, core.groups, :e, diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index b0eba172e6148..b672f88ecf61c 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -8,6 +8,11 @@ module Visitors @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 From fe35956bf7b51bc533850449bd9135cc269da2ac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 14:56:15 -0800 Subject: [PATCH 0930/1492] adding join_sources so we can access the join sources of the select core --- lib/arel/select_manager.rb | 4 ++++ test/test_select_manager.rb | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index ec1264c3c27b6..37f06f6a9fbd4 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -151,6 +151,10 @@ def order_clauses } end + def join_sources + @ctx.source.right + end + def joins manager if $VERBOSE warn "joins is deprecated and will be removed in 3.0.0" diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 15153d3523401..3bfb3a529e237 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -47,6 +47,12 @@ def execute sql, name = nil, *args 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 From fef5e012c90812dd9f1bb0de3e35497e106f8408 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 16:24:36 -0800 Subject: [PATCH 0931/1492] adding factory methods to node base class --- lib/arel/nodes/node.rb | 1 + lib/arel/nodes/table_alias.rb | 2 +- test/nodes/test_node.rb | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index ff788e90d2260..711fa34b6d4a4 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -3,6 +3,7 @@ module Nodes ### # Abstract base class for all AST nodes class Node + include Arel::FactoryMethods include Enumerable ### diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 723b025883790..4f4d5e29e9f40 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -6,7 +6,7 @@ class TableAlias < Arel::Nodes::Binary alias :table_alias :name def [] name - Attribute.new self, name + Attribute.new(self, name) end end end diff --git a/test/nodes/test_node.rb b/test/nodes/test_node.rb index 71d2098a60e6b..ffa3f273ea45a 100644 --- a/test/nodes/test_node.rb +++ b/test/nodes/test_node.rb @@ -2,6 +2,10 @@ 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) From e55763a29d922bf4b5c483b9d3dadb1dba3bc683 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 18:09:04 -0800 Subject: [PATCH 0932/1492] remove some nodes --- lib/arel/nodes/as.rb | 6 ------ lib/arel/nodes/assignment.rb | 6 ------ lib/arel/nodes/between.rb | 6 ------ lib/arel/nodes/not_equal.rb | 6 ------ lib/arel/nodes/or.rb | 6 ------ 5 files changed, 30 deletions(-) delete mode 100644 lib/arel/nodes/as.rb delete mode 100644 lib/arel/nodes/assignment.rb delete mode 100644 lib/arel/nodes/between.rb delete mode 100644 lib/arel/nodes/not_equal.rb delete mode 100644 lib/arel/nodes/or.rb diff --git a/lib/arel/nodes/as.rb b/lib/arel/nodes/as.rb deleted file mode 100644 index 9009fe12f4654..0000000000000 --- a/lib/arel/nodes/as.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class As < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/assignment.rb b/lib/arel/nodes/assignment.rb deleted file mode 100644 index 693bd5afe6645..0000000000000 --- a/lib/arel/nodes/assignment.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Assignment < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/between.rb b/lib/arel/nodes/between.rb deleted file mode 100644 index 2e7596cdae06e..0000000000000 --- a/lib/arel/nodes/between.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Between < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/not_equal.rb b/lib/arel/nodes/not_equal.rb deleted file mode 100644 index 7f892940cb825..0000000000000 --- a/lib/arel/nodes/not_equal.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class NotEqual < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/or.rb b/lib/arel/nodes/or.rb deleted file mode 100644 index bdf7f6d9b3692..0000000000000 --- a/lib/arel/nodes/or.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Or < Arel::Nodes::Binary - end - end -end From a7507d845a3b560895bbb0df3ce94fa033caa141 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 18:13:06 -0800 Subject: [PATCH 0933/1492] removing more nodes! --- Manifest.txt | 10 ---------- lib/arel/nodes.rb | 11 +---------- lib/arel/nodes/and.rb | 2 +- lib/arel/nodes/binary.rb | 15 +++++++++++++++ lib/arel/nodes/greater_than.rb | 6 ------ lib/arel/nodes/greater_than_or_equal.rb | 6 ------ lib/arel/nodes/less_than.rb | 6 ------ lib/arel/nodes/less_than_or_equal.rb | 6 ------ lib/arel/nodes/matches.rb | 6 ------ 9 files changed, 17 insertions(+), 51 deletions(-) delete mode 100644 lib/arel/nodes/greater_than.rb delete mode 100644 lib/arel/nodes/greater_than_or_equal.rb delete mode 100644 lib/arel/nodes/less_than.rb delete mode 100644 lib/arel/nodes/less_than_or_equal.rb delete mode 100644 lib/arel/nodes/matches.rb diff --git a/Manifest.txt b/Manifest.txt index 3735d854817b5..7d9010e7835c5 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -18,10 +18,7 @@ lib/arel/factory_methods.rb lib/arel/insert_manager.rb lib/arel/nodes.rb lib/arel/nodes/and.rb -lib/arel/nodes/as.rb -lib/arel/nodes/assignment.rb lib/arel/nodes/avg.rb -lib/arel/nodes/between.rb lib/arel/nodes/binary.rb lib/arel/nodes/count.rb lib/arel/nodes/delete_statement.rb @@ -29,8 +26,6 @@ lib/arel/nodes/does_not_match.rb lib/arel/nodes/equality.rb lib/arel/nodes/exists.rb lib/arel/nodes/function.rb -lib/arel/nodes/greater_than.rb -lib/arel/nodes/greater_than_or_equal.rb lib/arel/nodes/group.rb lib/arel/nodes/grouping.rb lib/arel/nodes/having.rb @@ -39,19 +34,14 @@ lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb lib/arel/nodes/join.rb lib/arel/nodes/join_source.rb -lib/arel/nodes/less_than.rb -lib/arel/nodes/less_than_or_equal.rb lib/arel/nodes/lock.rb -lib/arel/nodes/matches.rb lib/arel/nodes/max.rb lib/arel/nodes/min.rb lib/arel/nodes/node.rb lib/arel/nodes/not.rb -lib/arel/nodes/not_equal.rb lib/arel/nodes/not_in.rb lib/arel/nodes/offset.rb lib/arel/nodes/on.rb -lib/arel/nodes/or.rb lib/arel/nodes/ordering.rb lib/arel/nodes/outer_join.rb lib/arel/nodes/select_core.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 4cc93d7de4b56..ef1db0cfa23f8 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -2,18 +2,9 @@ require 'arel/nodes/unary' require 'arel/nodes/binary' require 'arel/nodes/equality' -require 'arel/nodes/between' -require 'arel/nodes/not_equal' -require 'arel/nodes/assignment' -require 'arel/nodes/or' require 'arel/nodes/and' -require 'arel/nodes/as' + require 'arel/nodes/not' -require 'arel/nodes/greater_than' -require 'arel/nodes/greater_than_or_equal' -require 'arel/nodes/less_than' -require 'arel/nodes/less_than_or_equal' -require 'arel/nodes/matches' require 'arel/nodes/does_not_match' require 'arel/nodes/join_source' diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb index b087a10930bff..b4443c3d2760e 100644 --- a/lib/arel/nodes/and.rb +++ b/lib/arel/nodes/and.rb @@ -1,6 +1,6 @@ module Arel module Nodes - class And < Arel::Nodes::Binary + class And < Arel::Nodes::Node attr_reader :children def initialize children, right = nil diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index cfa75909c5927..43979f6f2e25f 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -8,5 +8,20 @@ def initialize left, right @right = right end end + + %w{ + Between + NotEqual + Assignment + Or + As + GreaterThan + GreaterThanOrEqual + LessThan + LessThanOrEqual + Matches + }.each do |name| + const_set(name, Class.new(Binary)) + end end end diff --git a/lib/arel/nodes/greater_than.rb b/lib/arel/nodes/greater_than.rb deleted file mode 100644 index 2e03cc2e186e0..0000000000000 --- a/lib/arel/nodes/greater_than.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class GreaterThan < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/greater_than_or_equal.rb b/lib/arel/nodes/greater_than_or_equal.rb deleted file mode 100644 index a8cfaab04e6f3..0000000000000 --- a/lib/arel/nodes/greater_than_or_equal.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class GreaterThanOrEqual < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/less_than.rb b/lib/arel/nodes/less_than.rb deleted file mode 100644 index cfaf716c42289..0000000000000 --- a/lib/arel/nodes/less_than.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class LessThan < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/less_than_or_equal.rb b/lib/arel/nodes/less_than_or_equal.rb deleted file mode 100644 index 55449d12f120a..0000000000000 --- a/lib/arel/nodes/less_than_or_equal.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class LessThanOrEqual < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb deleted file mode 100644 index 5ef8ac83023a4..0000000000000 --- a/lib/arel/nodes/matches.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Matches < Arel::Nodes::Binary - end - end -end From ef46276acda7db7b33ee8b84a39cd7d10c3e2628 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 20:31:49 -0800 Subject: [PATCH 0934/1492] cleaning up more nodes --- Manifest.txt | 3 --- lib/arel/nodes.rb | 8 +++----- lib/arel/nodes/binary.rb | 9 +++++++++ lib/arel/nodes/does_not_match.rb | 6 ------ lib/arel/nodes/join.rb | 13 ------------- lib/arel/nodes/join_source.rb | 6 ------ lib/arel/nodes/not_in.rb | 6 ------ test/test_factory_methods.rb | 2 +- 8 files changed, 13 insertions(+), 40 deletions(-) delete mode 100644 lib/arel/nodes/does_not_match.rb delete mode 100644 lib/arel/nodes/join.rb delete mode 100644 lib/arel/nodes/not_in.rb diff --git a/Manifest.txt b/Manifest.txt index 7d9010e7835c5..82c2c4f61a21f 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -22,7 +22,6 @@ lib/arel/nodes/avg.rb lib/arel/nodes/binary.rb lib/arel/nodes/count.rb lib/arel/nodes/delete_statement.rb -lib/arel/nodes/does_not_match.rb lib/arel/nodes/equality.rb lib/arel/nodes/exists.rb lib/arel/nodes/function.rb @@ -32,14 +31,12 @@ lib/arel/nodes/having.rb lib/arel/nodes/in.rb lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb -lib/arel/nodes/join.rb lib/arel/nodes/join_source.rb lib/arel/nodes/lock.rb lib/arel/nodes/max.rb lib/arel/nodes/min.rb lib/arel/nodes/node.rb lib/arel/nodes/not.rb -lib/arel/nodes/not_in.rb lib/arel/nodes/offset.rb lib/arel/nodes/on.rb lib/arel/nodes/ordering.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index ef1db0cfa23f8..83977c356abdc 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,17 +1,16 @@ require 'arel/nodes/node' require 'arel/nodes/unary' require 'arel/nodes/binary' + require 'arel/nodes/equality' require 'arel/nodes/and' +require 'arel/nodes/in' +require 'arel/nodes/lock' require 'arel/nodes/not' -require 'arel/nodes/does_not_match' require 'arel/nodes/join_source' -require 'arel/nodes/in' -require 'arel/nodes/not_in' require 'arel/nodes/ordering' -require 'arel/nodes/lock' require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/values' @@ -30,7 +29,6 @@ require 'arel/nodes/delete_statement' require 'arel/nodes/unqualified_column' require 'arel/nodes/table_alias' -require 'arel/nodes/join' require 'arel/nodes/group' require 'arel/nodes/grouping' require 'arel/nodes/inner_join' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 43979f6f2e25f..1285af9447dc8 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -7,6 +7,12 @@ 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 end %w{ @@ -20,6 +26,9 @@ def initialize left, right LessThan LessThanOrEqual Matches + DoesNotMatch + NotIn + Join }.each do |name| const_set(name, Class.new(Binary)) end diff --git a/lib/arel/nodes/does_not_match.rb b/lib/arel/nodes/does_not_match.rb deleted file mode 100644 index 33bdeab00599d..0000000000000 --- a/lib/arel/nodes/does_not_match.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class DoesNotMatch < Arel::Nodes::Binary - end - end -end diff --git a/lib/arel/nodes/join.rb b/lib/arel/nodes/join.rb deleted file mode 100644 index d3307fe0e0748..0000000000000 --- a/lib/arel/nodes/join.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Nodes - class Join < Arel::Nodes::Binary - - alias :single_source :left - alias :constraint :right - - def initialize single_source, constraint - super - end - end - end -end diff --git a/lib/arel/nodes/join_source.rb b/lib/arel/nodes/join_source.rb index 7b739c19ada6a..c57ad0e930d96 100644 --- a/lib/arel/nodes/join_source.rb +++ b/lib/arel/nodes/join_source.rb @@ -9,12 +9,6 @@ class JoinSource < Arel::Nodes::Binary def initialize single_source, joinop = [] super end - - def initialize_copy other - super - @left = @left.clone if @left - @right = @right.clone if @right - end end end end diff --git a/lib/arel/nodes/not_in.rb b/lib/arel/nodes/not_in.rb deleted file mode 100644 index 6c01921a4609f..0000000000000 --- a/lib/arel/nodes/not_in.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class NotIn < Arel::Nodes::Binary - end - end -end diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index c40615564ff99..6506d3c47298a 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -14,7 +14,7 @@ def setup def test_create_join join = @factory.create_join :one, :two assert_kind_of Nodes::Join, join - assert_equal :two, join.constraint + assert_equal :two, join.right end def test_create_on From d4bfaf2b82934e8611824c15cbf855d3d02418b5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 20:53:19 -0800 Subject: [PATCH 0935/1492] cleaning up more nodes --- Manifest.txt | 6 ------ lib/arel/nodes.rb | 10 +++------- lib/arel/nodes/group.rb | 6 ------ lib/arel/nodes/grouping.rb | 6 ------ lib/arel/nodes/having.rb | 6 ------ lib/arel/nodes/not.rb | 6 ------ lib/arel/nodes/offset.rb | 7 ------- lib/arel/nodes/on.rb | 6 ------ lib/arel/nodes/unary.rb | 12 ++++++++++++ lib/arel/visitors/oracle.rb | 4 ++-- 10 files changed, 17 insertions(+), 52 deletions(-) delete mode 100644 lib/arel/nodes/group.rb delete mode 100644 lib/arel/nodes/grouping.rb delete mode 100644 lib/arel/nodes/having.rb delete mode 100644 lib/arel/nodes/not.rb delete mode 100644 lib/arel/nodes/offset.rb delete mode 100644 lib/arel/nodes/on.rb diff --git a/Manifest.txt b/Manifest.txt index 82c2c4f61a21f..0dcd1eb2b8753 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -25,9 +25,6 @@ lib/arel/nodes/delete_statement.rb lib/arel/nodes/equality.rb lib/arel/nodes/exists.rb lib/arel/nodes/function.rb -lib/arel/nodes/group.rb -lib/arel/nodes/grouping.rb -lib/arel/nodes/having.rb lib/arel/nodes/in.rb lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb @@ -36,9 +33,6 @@ lib/arel/nodes/lock.rb lib/arel/nodes/max.rb lib/arel/nodes/min.rb lib/arel/nodes/node.rb -lib/arel/nodes/not.rb -lib/arel/nodes/offset.rb -lib/arel/nodes/on.rb lib/arel/nodes/ordering.rb lib/arel/nodes/outer_join.rb lib/arel/nodes/select_core.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 83977c356abdc..9af6ad9ce30f7 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,5 +1,8 @@ require 'arel/nodes/node' + require 'arel/nodes/unary' +require 'arel/nodes/unqualified_column' + require 'arel/nodes/binary' require 'arel/nodes/equality' @@ -7,31 +10,24 @@ require 'arel/nodes/in' require 'arel/nodes/lock' -require 'arel/nodes/not' require 'arel/nodes/join_source' require 'arel/nodes/ordering' require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/values' -require 'arel/nodes/offset' require 'arel/nodes/sum' require 'arel/nodes/exists' require 'arel/nodes/max' require 'arel/nodes/min' require 'arel/nodes/avg' -require 'arel/nodes/having' require 'arel/nodes/sql_literal' require 'arel/nodes/select_core' require 'arel/nodes/select_statement' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' require 'arel/nodes/delete_statement' -require 'arel/nodes/unqualified_column' require 'arel/nodes/table_alias' -require 'arel/nodes/group' -require 'arel/nodes/grouping' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' require 'arel/nodes/string_join' -require 'arel/nodes/on' diff --git a/lib/arel/nodes/group.rb b/lib/arel/nodes/group.rb deleted file mode 100644 index a7fa6f170dd03..0000000000000 --- a/lib/arel/nodes/group.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Group < Arel::Nodes::Unary - end - end -end diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb deleted file mode 100644 index 18adeae97f28f..0000000000000 --- a/lib/arel/nodes/grouping.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Grouping < Arel::Nodes::Unary - end - end -end diff --git a/lib/arel/nodes/having.rb b/lib/arel/nodes/having.rb deleted file mode 100644 index 6972c58ddabaf..0000000000000 --- a/lib/arel/nodes/having.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Having < Arel::Nodes::Unary - end - end -end diff --git a/lib/arel/nodes/not.rb b/lib/arel/nodes/not.rb deleted file mode 100644 index de138435bbf95..0000000000000 --- a/lib/arel/nodes/not.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Not < Arel::Nodes::Unary - end - end -end diff --git a/lib/arel/nodes/offset.rb b/lib/arel/nodes/offset.rb deleted file mode 100644 index d93e46aa1fde0..0000000000000 --- a/lib/arel/nodes/offset.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - module Nodes - class Offset < Arel::Nodes::Unary - alias :value :expr - end - end -end diff --git a/lib/arel/nodes/on.rb b/lib/arel/nodes/on.rb deleted file mode 100644 index 953d64f9f1dd8..0000000000000 --- a/lib/arel/nodes/on.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class On < Arel::Nodes::Unary - end - end -end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index edda89e1f0717..f679017597d88 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -2,10 +2,22 @@ module Arel module Nodes class Unary < Arel::Nodes::Node attr_accessor :expr + alias :value :expr def initialize expr @expr = expr end end + + %w{ + Not + Group + Grouping + Offset + Having + On + }.each do |name| + const_set(name, Class.new(Unary)) + end end end diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index ecb157f8bce9d..63dfc6788c2a7 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -27,7 +27,7 @@ def visit_Arel_Nodes_SelectStatement o SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ - WHERE rownum <= #{offset.value.to_i + limit} + WHERE rownum <= #{offset.expr.to_i + limit} ) WHERE #{visit offset} eosql @@ -58,7 +58,7 @@ def visit_Arel_Nodes_SelectStatement o end def visit_Arel_Nodes_Offset o - "raw_rnum_ > #{visit o.value}" + "raw_rnum_ > #{visit o.expr}" end ### From 494a96542927348776e85e8ae52a01ad75ced872 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 21:06:16 -0800 Subject: [PATCH 0936/1492] cleaning up more nodes --- Manifest.txt | 5 ----- lib/arel/nodes.rb | 40 ++++++++++++++++++++----------------- lib/arel/nodes/avg.rb | 6 ------ lib/arel/nodes/binary.rb | 21 ++++++++++++------- lib/arel/nodes/exists.rb | 7 ------- lib/arel/nodes/function.rb | 10 ++++++++++ lib/arel/nodes/max.rb | 6 ------ lib/arel/nodes/min.rb | 6 ------ lib/arel/nodes/sum.rb | 6 ------ lib/arel/visitors/to_sql.rb | 2 +- 10 files changed, 47 insertions(+), 62 deletions(-) delete mode 100644 lib/arel/nodes/avg.rb delete mode 100644 lib/arel/nodes/exists.rb delete mode 100644 lib/arel/nodes/max.rb delete mode 100644 lib/arel/nodes/min.rb delete mode 100644 lib/arel/nodes/sum.rb diff --git a/Manifest.txt b/Manifest.txt index 0dcd1eb2b8753..4b6e08319f7ee 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -18,20 +18,16 @@ lib/arel/factory_methods.rb lib/arel/insert_manager.rb lib/arel/nodes.rb lib/arel/nodes/and.rb -lib/arel/nodes/avg.rb lib/arel/nodes/binary.rb lib/arel/nodes/count.rb lib/arel/nodes/delete_statement.rb lib/arel/nodes/equality.rb -lib/arel/nodes/exists.rb lib/arel/nodes/function.rb lib/arel/nodes/in.rb lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb lib/arel/nodes/join_source.rb lib/arel/nodes/lock.rb -lib/arel/nodes/max.rb -lib/arel/nodes/min.rb lib/arel/nodes/node.rb lib/arel/nodes/ordering.rb lib/arel/nodes/outer_join.rb @@ -39,7 +35,6 @@ 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/sum.rb lib/arel/nodes/table_alias.rb lib/arel/nodes/unary.rb lib/arel/nodes/unqualified_column.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 9af6ad9ce30f7..c43134bb506e6 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,33 +1,37 @@ +# node require 'arel/nodes/node' +require 'arel/nodes/lock' +require 'arel/nodes/select_statement' +require 'arel/nodes/select_core' +require 'arel/nodes/insert_statement' +require 'arel/nodes/update_statement' +# unary require 'arel/nodes/unary' require 'arel/nodes/unqualified_column' +# binary require 'arel/nodes/binary' - require 'arel/nodes/equality' -require 'arel/nodes/and' -require 'arel/nodes/in' -require 'arel/nodes/lock' - +require 'arel/nodes/in' # Why is this subclassed from equality? require 'arel/nodes/join_source' - require 'arel/nodes/ordering' +require 'arel/nodes/delete_statement' +require 'arel/nodes/table_alias' + +# 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/values' -require 'arel/nodes/sum' -require 'arel/nodes/exists' -require 'arel/nodes/max' -require 'arel/nodes/min' -require 'arel/nodes/avg' -require 'arel/nodes/sql_literal' -require 'arel/nodes/select_core' -require 'arel/nodes/select_statement' -require 'arel/nodes/insert_statement' -require 'arel/nodes/update_statement' -require 'arel/nodes/delete_statement' -require 'arel/nodes/table_alias' + +# joins require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' require 'arel/nodes/string_join' + +require 'arel/nodes/sql_literal' diff --git a/lib/arel/nodes/avg.rb b/lib/arel/nodes/avg.rb deleted file mode 100644 index 8fc86fc21e862..0000000000000 --- a/lib/arel/nodes/avg.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Avg < Arel::Nodes::Function - end - end -end diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 1285af9447dc8..eb873c75e16fd 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -16,21 +16,28 @@ def initialize_copy other end %w{ - Between - NotEqual - Assignment - Or As + Assignment + Between + DoesNotMatch GreaterThan GreaterThanOrEqual + Join LessThan LessThanOrEqual Matches - DoesNotMatch + NotEqual NotIn - Join + Or }.each do |name| - const_set(name, Class.new(Binary)) + const_set name, Class.new(Binary) end + + #%w{ + # InnerJoin + # OuterJoin + #}.each do |name| + # Nodes.const_set name, Class.new(Join) + #end end end diff --git a/lib/arel/nodes/exists.rb b/lib/arel/nodes/exists.rb deleted file mode 100644 index 18ba8403b44fa..0000000000000 --- a/lib/arel/nodes/exists.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - module Nodes - class Exists < Arel::Nodes::Function - alias :select_stmt :expressions - end - end -end diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 133dd66019f63..e4e45bff31604 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -14,5 +14,15 @@ def as aliaz self end end + + %w{ + Sum + Exists + Max + Min + Avg + }.each do |name| + const_set(name, Class.new(Function)) + end end end diff --git a/lib/arel/nodes/max.rb b/lib/arel/nodes/max.rb deleted file mode 100644 index 5af611b0d682d..0000000000000 --- a/lib/arel/nodes/max.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Max < Arel::Nodes::Function - end - end -end diff --git a/lib/arel/nodes/min.rb b/lib/arel/nodes/min.rb deleted file mode 100644 index bdc137185824f..0000000000000 --- a/lib/arel/nodes/min.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Min < Arel::Nodes::Function - end - end -end diff --git a/lib/arel/nodes/sum.rb b/lib/arel/nodes/sum.rb deleted file mode 100644 index 3e043b733090d..0000000000000 --- a/lib/arel/nodes/sum.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Sum < Arel::Nodes::Function - end - end -end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8ceb839a6b187..5efcbf009d9a2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -70,7 +70,7 @@ def visit_Arel_Nodes_InsertStatement o end def visit_Arel_Nodes_Exists o - "EXISTS (#{visit o.select_stmt})#{ + "EXISTS (#{visit o.expressions})#{ o.alias ? " AS #{visit o.alias}" : ''}" end From 1b6ab96a1c96a9a51f0804ae6c0cf02f96440aa5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Dec 2010 21:08:01 -0800 Subject: [PATCH 0937/1492] removing commented out code --- lib/arel/nodes/binary.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index eb873c75e16fd..0d025541991eb 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -32,12 +32,5 @@ def initialize_copy other }.each do |name| const_set name, Class.new(Binary) end - - #%w{ - # InnerJoin - # OuterJoin - #}.each do |name| - # Nodes.const_set name, Class.new(Join) - #end end end From 5709718acd507e5c1c815ed84b016e6a28800a08 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Dec 2010 14:44:22 -0800 Subject: [PATCH 0938/1492] fix join dot visitors --- lib/arel/visitors/dot.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index c525a64a89d32..cfd231020d429 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -56,13 +56,11 @@ def visit_Arel_Nodes_Values o def visit_Arel_Nodes_StringJoin o visit_edge o, "left" - visit_edge o, "right" end def visit_Arel_Nodes_InnerJoin o visit_edge o, "left" visit_edge o, "right" - visit_edge o, "constraint" end alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin From 3b36a912b940921a3f1e548e59fec74300749ebc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Dec 2010 14:54:33 -0800 Subject: [PATCH 0939/1492] make our caching per connection pool, not per connection --- lib/arel/visitors/to_sql.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5efcbf009d9a2..d959782620574 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -7,22 +7,24 @@ class ToSql < Arel::Visitors::Visitor def initialize engine @engine = engine @connection = nil + @pool = nil @last_column = nil @quoted_tables = {} @quoted_columns = {} - @column_cache = Hash.new { |h,conn| - h[conn] = Hash.new { |conn_h,column| + @column_cache = Hash.new { |h,pool| + h[pool] = Hash.new { |conn_h,column| conn_h[column] = {} } } - @table_exists = Hash.new { |h,conn| - h[conn] = {} + @table_exists = Hash.new { |h,pool| + h[pool] = {} } end def accept object @last_column = nil - @engine.connection_pool.with_connection do |conn| + @pool = @engine.connection_pool + @pool.with_connection do |conn| @connection = conn super end @@ -85,7 +87,7 @@ def table_exists? name end def table_exists - @table_exists[@connection] + @table_exists[@pool] end def column_for attr @@ -105,7 +107,7 @@ def column_for attr end def column_cache - @column_cache[@connection] + @column_cache[@pool] end def visit_Arel_Nodes_Values o From a75ed569346c98c27c9ab1ec9c91332ffd4892b3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Dec 2010 10:51:28 -0800 Subject: [PATCH 0940/1492] fixing typo, thanks @devwout --- lib/arel/nodes/select_core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index bd1930364d0d5..8eb7c0d3e7859 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -28,7 +28,7 @@ def initialize_copy other @source = @source.clone if @source @projections = @projections.clone @wheres = @wheres.clone - @group = @groups.clone + @groups = @groups.clone @having = @having.clone if @having end end From 162e1d8df332f170b9dafdc91f60ee2cb359c1e5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 22 Dec 2010 18:02:56 -0800 Subject: [PATCH 0941/1492] sql literals may be used as column attributes --- History.txt | 1 + lib/arel.rb | 4 ++++ lib/arel/table.rb | 2 +- lib/arel/visitors/to_sql.rb | 45 +++++++++++++++++++----------------- test/visitors/test_to_sql.rb | 9 +++++++- 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/History.txt b/History.txt index d16baa5b305d5..3984a7aa44e8a 100644 --- a/History.txt +++ b/History.txt @@ -4,6 +4,7 @@ * AST is now Enumerable * AND nodes are now n-ary nodes + * SQL Literals may be used as Attribute names * Deprecations diff --git a/lib/arel.rb b/lib/arel.rb index 3d0648263b14e..32fc8d9bc08ff 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -35,6 +35,10 @@ module Arel def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql end + + def self.star + sql '*' + end ## Convenience Alias Node = Arel::Nodes::Node end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index a13fd9fa5bd78..d1d1e40e11692 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -109,7 +109,7 @@ def columns end def [] name - ::Arel::Attribute.new self, name.to_sym + ::Arel::Attribute.new self, name end def select_manager diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d959782620574..7669fd67ab6d0 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -318,26 +318,29 @@ def visit_Arel_Attributes_Attribute o alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute - def visit_Fixnum o; o end - alias :visit_Arel_Nodes_SqlLiteral :visit_Fixnum - alias :visit_Arel_SqlLiteral :visit_Fixnum # This is deprecated - alias :visit_Bignum :visit_Fixnum - - def visit_String o; quote(o, @last_column) end - - alias :visit_ActiveSupport_Multibyte_Chars :visit_String - alias :visit_BigDecimal :visit_String - alias :visit_Date :visit_String - alias :visit_DateTime :visit_String - alias :visit_FalseClass :visit_String - alias :visit_Float :visit_String - alias :visit_Hash :visit_String - alias :visit_Symbol :visit_String - alias :visit_Time :visit_String - alias :visit_TrueClass :visit_String - alias :visit_NilClass :visit_String - alias :visit_ActiveSupport_StringInquirer :visit_String - alias :visit_Class :visit_String + def literal o; o end + + 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_Array o o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') @@ -352,7 +355,7 @@ def quote_table_name name end def quote_column_name name - @quoted_columns[name] ||= @connection.quote_column_name(name) + @quoted_columns[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.quote_column_name(name) end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 80384d3c289e8..530bd73f6df1e 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -5,7 +5,14 @@ module Visitors describe 'the to_sql visitor' do before do @visitor = ToSql.new Table.engine - @attr = Table.new(:users)[:id] + @table = Table.new(:users) + @attr = @table[:id] + end + + it 'should not quote sql literals' do + node = @table[Arel.star] + sql = @visitor.accept node + sql.must_be_like '"users".*' end describe 'equality' do From 963c9308147613012c8bdd9832aec360c2023418 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 24 Dec 2010 15:48:33 -0700 Subject: [PATCH 0942/1492] requiring that the primary key be set on the UpdateManager so that databases which do not support UPDATE with LIMIT will work --- lib/arel/crud.rb | 2 +- lib/arel/nodes/update_statement.rb | 6 ++++-- lib/arel/update_manager.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 17 ++++++++++++++--- test/test_select_manager.rb | 2 ++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index ec58734456e06..e6b1cd96758c2 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -6,7 +6,7 @@ def compile_update values um = UpdateManager.new @engine if Nodes::SqlLiteral === values - relation = @ctx.froms + relation = @ctx.from else relation = values.first.first.relation end diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index 288e9f467681f..c08f1b2c5e450 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -2,13 +2,15 @@ module 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 + @orders = [] + @limit = nil + @key = nil end def initialize_copy other diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 821dce7d81a43..cf24dbac925f6 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -11,6 +11,10 @@ def take limit self end + def key= key + @ast.key = key + end + def order *expr @ast.orders = expr self diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7669fd67ab6d0..f25c0ee69ff69 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -42,20 +42,31 @@ 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 3.0.0. Please set the primary +key on UpdateManager using UpdateManager#key= +eowarn + key = o.relation.primary_key + end + + wheres = o.wheres stmt = Nodes::SelectStatement.new core = stmt.cores.first core.froms = o.relation - core.projections = [o.relation.primary_key] + core.projections = [key] stmt.limit = o.limit stmt.orders = o.orders - wheres = [Nodes::In.new(o.relation.primary_key, [stmt])] + wheres = [Nodes::In.new(key, [stmt])] 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?) + ("WHERE #{wheres.map { |x| visit x }.join ' AND '}" unless wheres.empty?), ].compact.join ' ' end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 3bfb3a529e237..7c8da972e114d 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -480,6 +480,7 @@ def test_join_sources 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 @@ -494,6 +495,7 @@ def test_join_sources 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 From 32386f88601ab9c6d4a1a292ed087b896a25fd1f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 12:14:30 -0700 Subject: [PATCH 0943/1492] testing binary ops in the dot visitor --- lib/arel/select_manager.rb | 3 ++- lib/arel/visitors/dot.rb | 30 ++++++++++++++++-------------- test/visitors/test_dot.rb | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 37f06f6a9fbd4..55700ab92d5bb 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -9,9 +9,10 @@ def initialize engine, table = nil from table end - def taken + def limit @ast.limit end + alias :taken :limit def constraints @ctx.wheres diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index cfd231020d429..4bb45bc70753d 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -127,23 +127,25 @@ def nary o end alias :visit_Arel_Nodes_And :nary - def visit_Arel_Nodes_Equality o + def binary o visit_edge o, "left" visit_edge o, "right" end - alias :visit_Arel_Nodes_Or :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_NotEqual :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_GreaterThan :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_GreaterThanOrEqual :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_Assignment :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_In :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_LessThan :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_LessThanOrEqual :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_Between :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_NotIn :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_DoesNotMatch :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_Matches :visit_Arel_Nodes_Equality - alias :visit_Arel_Nodes_JoinSource :visit_Arel_Nodes_Equality + 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 def visit_String o @node_stack.last.fields << o diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 19a554ce42581..de6dd87c4c711 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -22,6 +22,34 @@ def setup @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::Ordering, + 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 From cefad1e2139c4bba6e45f3281a6d54394aaeb366 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 26 Dec 2010 19:56:07 -0700 Subject: [PATCH 0944/1492] adding deprecation warning for where_clauses --- History.txt | 3 +++ lib/arel/factory_methods.rb | 4 ++++ lib/arel/select_manager.rb | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index 3984a7aa44e8a..726e246a64c8b 100644 --- a/History.txt +++ b/History.txt @@ -31,6 +31,9 @@ * 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. + == 2.0.7 (unreleased) * Bug Fixes diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 4899adfdc8ce2..09b82c05555e1 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -17,5 +17,9 @@ def create_and clauses def create_on expr Nodes::On.new expr end + + def grouping expr + Nodes::Grouping.new expr + end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 55700ab92d5bb..274633c9db24e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -30,7 +30,9 @@ def exists end def where_clauses - #warn "where_clauses is deprecated" if $VERBOSE + if $VERBOSE + warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" + end to_sql = Visitors::ToSql.new @engine @ctx.wheres.map { |c| to_sql.accept c } end From 1a246f71616cf246a75ef6cbdb56032e43d4e643 Mon Sep 17 00:00:00 2001 From: Viacheslav Petrenko Date: Mon, 27 Dec 2010 18:16:18 +0200 Subject: [PATCH 0945/1492] Patched Arel v2.0.6 to support MSSQL SQL queries. Based on work of James Abley (https://github.com/jabley/arel). --- lib/arel/nodes.rb | 2 ++ lib/arel/nodes/limit.rb | 7 +++++++ lib/arel/nodes/select_core.rb | 3 ++- lib/arel/nodes/top.rb | 6 ++++++ lib/arel/select_manager.rb | 5 +++-- lib/arel/visitors.rb | 3 +++ lib/arel/visitors/mssql.rb | 16 ++++++++++++++++ lib/arel/visitors/mysql.rb | 2 +- lib/arel/visitors/sqlite.rb | 2 +- lib/arel/visitors/to_sql.rb | 15 +++++++++++++-- test/visitors/test_mssql.rb | 18 ++++++++++++++++++ test/visitors/test_to_sql.rb | 2 +- 12 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 lib/arel/nodes/limit.rb create mode 100644 lib/arel/nodes/top.rb create mode 100644 lib/arel/visitors/mssql.rb create mode 100644 test/visitors/test_mssql.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index c454152d0d98b..db2f22750ae1a 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -24,6 +24,8 @@ require 'arel/nodes/count' require 'arel/nodes/values' require 'arel/nodes/offset' +require 'arel/nodes/limit' +require 'arel/nodes/top' require 'arel/nodes/sum' require 'arel/nodes/exists' require 'arel/nodes/max' diff --git a/lib/arel/nodes/limit.rb b/lib/arel/nodes/limit.rb new file mode 100644 index 0000000000000..68ea95daf50eb --- /dev/null +++ b/lib/arel/nodes/limit.rb @@ -0,0 +1,7 @@ +module Arel + module Nodes + class Limit < Arel::Nodes::Unary + end + end +end + diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index acc6bb9815d8c..501a2aaf7c0ea 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,10 +1,11 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node - attr_accessor :froms, :projections, :wheres, :groups + attr_accessor :top, :froms, :projections, :wheres, :groups attr_accessor :having def initialize + @top = nil @froms = nil @projections = [] @wheres = [] diff --git a/lib/arel/nodes/top.rb b/lib/arel/nodes/top.rb new file mode 100644 index 0000000000000..56e2e97e8dd69 --- /dev/null +++ b/lib/arel/nodes/top.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Top < Arel::Nodes::Unary + end + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 10d23378aeb4b..cb656d5340f6f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -10,7 +10,7 @@ def initialize engine, table = nil end def taken - @ast.limit + @ast.limit && @ast.limit.expr end def constraints @@ -131,7 +131,8 @@ def where_sql end def take limit - @ast.limit = limit + @ast.limit = Nodes::Limit.new(limit) + @ctx.top = Nodes::Top.new(limit) self end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 2b0a06d5340f4..8410b2b912eaa 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -4,6 +4,7 @@ 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' @@ -16,6 +17,8 @@ module 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, diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb new file mode 100644 index 0000000000000..9b0e77c19bc84 --- /dev/null +++ b/lib/arel/visitors/mssql.rb @@ -0,0 +1,16 @@ +module Arel + module Visitors + class MSSQL < Arel::Visitors::ToSql + private + + def visit_Arel_Nodes_Limit o + "" + end + + def visit_Arel_Nodes_Top o + "TOP #{visit o.expr}" + end + + end + end +end diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index ace8fb0979714..b37d76f710dd8 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -10,7 +10,7 @@ def visit_Arel_Nodes_Lock o # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 def visit_Arel_Nodes_SelectStatement o - o.limit = 18446744073709551615 if o.offset && !o.limit + o.limit = Arel::Nodes::Limit.new(18446744073709551615) if o.offset && !o.limit super end diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index c45160851d17f..237ae913bbb49 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -3,7 +3,7 @@ module Visitors class SQLite < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o - o.limit = -1 if o.offset && !o.limit + o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a2105d704334d..7435e41561764 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -76,7 +76,7 @@ def visit_Arel_Nodes_SelectStatement o [ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?), - ("LIMIT #{visit o.limit}" if o.limit), + (visit(o.limit) if o.limit), (visit(o.offset) if o.offset), (visit(o.lock) if o.lock), ].compact.join ' ' @@ -84,7 +84,9 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_SelectCore o [ - "SELECT #{o.projections.map { |x| visit x }.join ', '}", + "SELECT", + (visit(o.top) if o.top), + "#{o.projections.map { |x| visit x }.join ', '}", ("FROM #{visit o.froms}" if o.froms), ("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?), @@ -100,6 +102,15 @@ 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 + # FIXME: this does nothing on SQLLite3, but should do things on other # databases. def visit_Arel_Nodes_Lock o diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb new file mode 100644 index 0000000000000..b658e46828e7e --- /dev/null +++ b/test/visitors/test_mssql.rb @@ -0,0 +1,18 @@ +require 'helper' + +module Arel + module Visitors + describe 'the mssql visitor' do + before do + @visitor = MSSQL.new Table.engine + end + + it 'uses TOP to limit results' do + stmt = Nodes::SelectStatement.new + stmt.cores.last.top = Nodes::Top.new(1) + sql = @visitor.accept(stmt) + sql.must_be_like "SELECT TOP 1" + end + end + end +end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index e08dc89793b0e..33783f7d234bd 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -32,7 +32,7 @@ module Visitors it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new - sc.limit = "omg" + sc.limit = Arel::Nodes::Limit.new("omg") assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) end From 1215c28311aab325c55c083d15cbf3e16599d502 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 10:19:31 -0800 Subject: [PATCH 0946/1492] updating history --- History.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/History.txt b/History.txt index f1161cac29bf3..b604fcfc00cc2 100644 --- a/History.txt +++ b/History.txt @@ -3,6 +3,7 @@ * Bug Fixes * Limit members are visited + * Fixing MSSQL TOP support == 2.0.6 12/01/2010 From 4c83fa0b0d20306c47669395c916c8df195e104c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 10:31:58 -0800 Subject: [PATCH 0947/1492] limit and top files are not needed --- lib/arel/nodes/limit.rb | 7 ------- lib/arel/nodes/top.rb | 6 ------ 2 files changed, 13 deletions(-) delete mode 100644 lib/arel/nodes/limit.rb delete mode 100644 lib/arel/nodes/top.rb diff --git a/lib/arel/nodes/limit.rb b/lib/arel/nodes/limit.rb deleted file mode 100644 index 68ea95daf50eb..0000000000000 --- a/lib/arel/nodes/limit.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - module Nodes - class Limit < Arel::Nodes::Unary - end - end -end - diff --git a/lib/arel/nodes/top.rb b/lib/arel/nodes/top.rb deleted file mode 100644 index 56e2e97e8dd69..0000000000000 --- a/lib/arel/nodes/top.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Top < Arel::Nodes::Unary - end - end -end From 824726be706a288f7b67160e1b2f021c10ec7668 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 10:36:49 -0800 Subject: [PATCH 0948/1492] fisting mergefail --- lib/arel/visitors/to_sql.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9830e559d5a6e..4eae5a9ae56da 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -368,10 +368,6 @@ def visit_Array o o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') end - def visit_Array o - o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') - end - def quote value, column = nil @connection.quote value, column end From 957f4c02ddccd243b965e60351bc0a0083e4887d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 11:12:46 -0800 Subject: [PATCH 0949/1492] top and limit can be visited --- lib/arel/visitors/depth_first.rb | 2 ++ lib/arel/visitors/dot.rb | 2 ++ test/visitors/test_depth_first.rb | 2 ++ test/visitors/test_dot.rb | 2 ++ 4 files changed, 8 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index eec356af4cf6a..ed95cad472b10 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -18,9 +18,11 @@ def unary o 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 def function o diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 4bb45bc70753d..3c4fe12d1f470 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -75,9 +75,11 @@ def unary o 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 def visit_Arel_Nodes_InsertStatement o diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 4bce4681835f5..306605b7c6887 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -31,6 +31,8 @@ def test_raises_with_object 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) diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index de6dd87c4c711..3c7da8958a668 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -16,6 +16,8 @@ def setup Arel::Nodes::Offset, 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) From 90be95a0aba12787882d9821d9a4d5f00781beb6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 12:20:13 -0800 Subject: [PATCH 0950/1492] fisting lots of oracle errors --- lib/arel/visitors/oracle.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 63dfc6788c2a7..5808d7a5119d3 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -10,7 +10,7 @@ def visit_Arel_Nodes_SelectStatement o # 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 + Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) o.limit = nil return super @@ -18,7 +18,7 @@ def visit_Arel_Nodes_SelectStatement o if o.limit && o.offset o = o.dup - limit = o.limit.to_i + limit = o.limit.expr.to_i offset = o.offset o.limit = nil o.offset = nil @@ -35,9 +35,9 @@ def visit_Arel_Nodes_SelectStatement o if o.limit o = o.dup - limit = o.limit + limit = o.limit.expr o.limit = nil - return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{limit}" + return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}" end if o.offset From 4acbe3864f5e5c4c8c70c5f58fbd5c09617d1662 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 12:20:13 -0800 Subject: [PATCH 0951/1492] fisting lots of oracle errors --- lib/arel/visitors/oracle.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index ecb157f8bce9d..fa943b2904b6f 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -10,7 +10,7 @@ def visit_Arel_Nodes_SelectStatement o # 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 + Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) o.limit = nil return super @@ -18,7 +18,7 @@ def visit_Arel_Nodes_SelectStatement o if o.limit && o.offset o = o.dup - limit = o.limit.to_i + limit = o.limit.expr.to_i offset = o.offset o.limit = nil o.offset = nil @@ -35,9 +35,9 @@ def visit_Arel_Nodes_SelectStatement o if o.limit o = o.dup - limit = o.limit + limit = o.limit.expr o.limit = nil - return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{limit}" + return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}" end if o.offset From b035def39a8b4966fd33779bd5a2a9d0c9a33e66 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 13:39:56 -0800 Subject: [PATCH 0952/1492] fixing tests for oracle visitor --- lib/arel/visitors/visitor.rb | 3 ++- test/visitors/test_oracle.rb | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 055acf9765977..85359f3e673b6 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -13,7 +13,8 @@ def accept object def visit object send DISPATCH[object.class], object - rescue NoMethodError + rescue NoMethodError => e + raise e if respond_to?(DISPATCH[object.class], true) warn "visiting #{object.class} via superclass, this will be removed in arel 2.2.0" if $VERBOSE superklass = object.class.ancestors.find { |klass| respond_to?(DISPATCH[klass], true) diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 2c9bba15d8b1b..c6fcb7134c8fd 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -59,7 +59,7 @@ module Visitors describe 'limit' do it 'adds a rownum clause' do stmt = Nodes::SelectStatement.new - stmt.limit = 10 + stmt.limit = Nodes::Limit.new(10) sql = @visitor.accept stmt sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 } end @@ -67,7 +67,7 @@ module Visitors it 'is idempotent' do stmt = Nodes::SelectStatement.new stmt.orders << Nodes::SqlLiteral.new('foo') - stmt.limit = 10 + stmt.limit = Nodes::Limit.new(10) sql = @visitor.accept stmt sql2 = @visitor.accept stmt sql.must_equal sql2 @@ -76,7 +76,7 @@ module Visitors it 'creates a subquery when there is order_by' do stmt = Nodes::SelectStatement.new stmt.orders << Nodes::SqlLiteral.new('foo') - stmt.limit = 10 + stmt.limit = Nodes::Limit.new(10) sql = @visitor.accept stmt sql.must_be_like %{ SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10 @@ -86,7 +86,7 @@ module Visitors it 'creates a subquery when there is DISTINCT' do stmt = Nodes::SelectStatement.new stmt.cores.first.projections << Nodes::SqlLiteral.new('DISTINCT id') - stmt.limit = 10 + stmt.limit = Arel::Nodes::Limit.new(10) sql = @visitor.accept stmt sql.must_be_like %{ SELECT * FROM (SELECT DISTINCT id) WHERE ROWNUM <= 10 @@ -95,7 +95,7 @@ module Visitors it 'creates a different subquery when there is an offset' do stmt = Nodes::SelectStatement.new - stmt.limit = 10 + stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(10) sql = @visitor.accept stmt sql.must_be_like %{ @@ -110,7 +110,7 @@ module Visitors it 'is idempotent with different subquery' do stmt = Nodes::SelectStatement.new - stmt.limit = 10 + stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(10) sql = @visitor.accept stmt sql2 = @visitor.accept stmt From fd24494797461d487bacc277b4ff32392c64906d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 14:29:38 -0800 Subject: [PATCH 0953/1492] we do not need to modify the AST --- lib/arel/visitors/oracle.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index fa943b2904b6f..87b8f10ef4bfb 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -12,7 +12,6 @@ def visit_Arel_Nodes_SelectStatement o o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) - o.limit = nil return super end @@ -20,7 +19,6 @@ def visit_Arel_Nodes_SelectStatement o o = o.dup limit = o.limit.expr.to_i offset = o.offset - o.limit = nil o.offset = nil sql = super(o) return <<-eosql @@ -36,7 +34,6 @@ def visit_Arel_Nodes_SelectStatement o if o.limit o = o.dup limit = o.limit.expr - o.limit = nil return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}" end @@ -57,6 +54,10 @@ def visit_Arel_Nodes_SelectStatement o super end + def visit_Arel_Nodes_Limit o + '' + end + def visit_Arel_Nodes_Offset o "raw_rnum_ > #{visit o.value}" end From 8bc0fce00b9f64e328c18e98f82780e29dc5f554 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Tue, 4 Jan 2011 07:11:34 +0800 Subject: [PATCH 0954/1492] Allow HAVING to take multiple conditions, like WHERE --- lib/arel/select_manager.rb | 20 ++++++++++++-------- test/test_select_manager.rb | 17 ++++++++++++++++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 3e0d4038d7bb6..b4103144fec92 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -97,10 +97,8 @@ def join relation, klass = Nodes::InnerJoin self end - def having expr - expr = Nodes::SqlLiteral.new(expr) if String === expr - - @ctx.having = Nodes::Having.new(expr) + def having *exprs + @ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having)) self end @@ -211,16 +209,22 @@ def insert values end private - def collapse exprs - return exprs.first if exprs.length == 1 - - create_and exprs.compact.map { |expr| + 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7c8da972e114d..271a8ae0b0c6b 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -99,13 +99,28 @@ def test_join_sources end end - describe '#having' do + 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 end From a78fe3b50253ef3d0f00e06ee328ee45bfe23321 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 15:40:56 -0800 Subject: [PATCH 0955/1492] should return nil instead of empty string --- lib/arel/visitors/oracle.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 87b8f10ef4bfb..3c8c816feb79e 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -55,7 +55,6 @@ def visit_Arel_Nodes_SelectStatement o end def visit_Arel_Nodes_Limit o - '' end def visit_Arel_Nodes_Offset o From ef29263428eb2aa1fdc2b6b020f0d153fd17b5f3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 15:44:16 -0800 Subject: [PATCH 0956/1492] making sure limit is correctly copied to update manager --- lib/arel/crud.rb | 2 +- lib/arel/update_manager.rb | 2 +- test/test_update_manager.rb | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index b3199e6d38116..50d6f727731da 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -13,7 +13,7 @@ def update values end um.table relation um.set values - um.take @ast.limit + um.take @ast.limit.expr if @ast.limit um.order(*@ast.orders) um.wheres = @ctx.wheres diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 821dce7d81a43..d92c8b9a03b51 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -7,7 +7,7 @@ def initialize engine end def take limit - @ast.limit = limit + @ast.limit = Nodes::Limit.new(limit) if limit self end diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 5823845ba0235..62a2eccaf594a 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -8,6 +8,15 @@ module Arel end 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) From f5e09790550fcb7d413d495be25f8fe74a571850 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 3 Jan 2011 16:19:57 -0800 Subject: [PATCH 0957/1492] adding better tests surrounding limits in adapter visitors --- lib/arel/visitors/mysql.rb | 2 +- lib/arel/visitors/postgresql.rb | 2 +- test/visitors/test_mysql.rb | 4 ++-- test/visitors/test_postgres.rb | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index b37d76f710dd8..e90161eee49aa 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -25,7 +25,7 @@ def visit_Arel_Nodes_UpdateStatement o ("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?), - ("LIMIT #{visit o.limit}" if o.limit), + (visit(o.limit) if o.limit), ].compact.join ' ' end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 01fbda75b941c..0e82a703ca09d 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -17,7 +17,7 @@ def visit_Arel_Nodes_SelectStatement o [ "SELECT * FROM (#{sql}) AS id_list", "ORDER BY #{aliased_orders(o.orders).join(', ')}", - ("LIMIT #{visit o.limit}" if o.limit), + (visit(o.limit) if o.limit), (visit(o.offset) if o.offset), ].compact.join ' ' else diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 135348580d1b3..c3b79ca667b43 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -19,8 +19,8 @@ module Visitors it "should escape LIMIT" do sc = Arel::Nodes::UpdateStatement.new - sc.limit = "omg" - assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + sc.limit = Nodes::Limit.new("omg") + assert_equal("UPDATE NULL LIMIT 'omg'", @visitor.accept(sc)) end it 'uses DUAL for empty from' do diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index b98f78ca12b42..6e8f399b6b295 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -15,10 +15,12 @@ module Visitors it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new - sc.limit = "omg" + sc.limit = Nodes::Limit.new("omg") sc.cores.first.projections << 'DISTINCT ON' sc.orders << "xyz" - assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + sql = @visitor.accept(sc) + assert_match(/LIMIT 'omg'/, sql) + assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit' end end end From f64d067ee40f387f80ef25aa56a002c018b4be4e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 4 Jan 2011 19:53:37 -0800 Subject: [PATCH 0958/1492] visiting via superclass is OK, since module definitions help delegate --- lib/arel/visitors/visitor.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 85359f3e673b6..c9cdf34adb615 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -15,7 +15,6 @@ def visit object send DISPATCH[object.class], object rescue NoMethodError => e raise e if respond_to?(DISPATCH[object.class], true) - warn "visiting #{object.class} via superclass, this will be removed in arel 2.2.0" if $VERBOSE superklass = object.class.ancestors.find { |klass| respond_to?(DISPATCH[klass], true) } From f0c4e3713d72a18a4100f85e263014f6e56bfad3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 4 Jan 2011 20:27:34 -0800 Subject: [PATCH 0959/1492] Added Arel::Nodes::NamedFunction for representing generic SQL functions --- History.txt | 1 + Manifest.txt | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/count.rb | 3 --- lib/arel/nodes/function.rb | 3 ++- lib/arel/nodes/named_function.rb | 12 ++++++++++++ lib/arel/visitors/depth_first.rb | 8 ++++++++ lib/arel/visitors/dot.rb | 25 ++++++++++++++++++------- lib/arel/visitors/to_sql.rb | 6 ++++++ test/nodes/test_named_function.rb | 13 +++++++++++++ test/nodes/test_node.rb | 1 + test/visitors/test_depth_first.rb | 8 +++++++- test/visitors/test_dot.rb | 19 +++++++++++++++++++ test/visitors/test_to_sql.rb | 10 ++++++++++ 14 files changed, 102 insertions(+), 12 deletions(-) create mode 100644 lib/arel/nodes/named_function.rb create mode 100644 test/nodes/test_named_function.rb diff --git a/History.txt b/History.txt index d3018542366d5..51e950512f850 100644 --- a/History.txt +++ b/History.txt @@ -5,6 +5,7 @@ * 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 * Deprecations diff --git a/Manifest.txt b/Manifest.txt index 4b6e08319f7ee..8ecf21693e017 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -28,6 +28,7 @@ lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb lib/arel/nodes/join_source.rb lib/arel/nodes/lock.rb +lib/arel/nodes/named_function.rb lib/arel/nodes/node.rb lib/arel/nodes/ordering.rb lib/arel/nodes/outer_join.rb @@ -52,6 +53,7 @@ lib/arel/visitors.rb lib/arel/visitors/depth_first.rb lib/arel/visitors/dot.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 @@ -67,6 +69,7 @@ test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_equality.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 @@ -88,6 +91,7 @@ test/test_update_manager.rb test/visitors/test_depth_first.rb test/visitors/test_dot.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 diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index c43134bb506e6..64f2cc13fd794 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -28,6 +28,7 @@ require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/values' +require 'arel/nodes/named_function' # joins require 'arel/nodes/inner_join' diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index c6e19afb34820..5c8ade1cf98fb 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -1,9 +1,6 @@ module Arel module Nodes class Count < Arel::Nodes::Function - - attr_accessor :distinct - def initialize expr, distinct = false, aliaz = nil super(expr, aliaz) @distinct = distinct diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index e4e45bff31604..b58eba7f380a3 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -2,11 +2,12 @@ module Arel module Nodes class Function < Arel::Nodes::Node include Arel::Expression - attr_accessor :expressions, :alias + attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil @expressions = expr @alias = aliaz + @distinct = false end def as aliaz diff --git a/lib/arel/nodes/named_function.rb b/lib/arel/nodes/named_function.rb new file mode 100644 index 0000000000000..56669bf85853a --- /dev/null +++ b/lib/arel/nodes/named_function.rb @@ -0,0 +1,12 @@ +module Arel + module Nodes + class NamedFunction < Arel::Nodes::Function + attr_accessor :name + + def initialize name, expr, aliaz = nil + super(expr, aliaz) + @name = name + end + end + end +end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index ed95cad472b10..914b2d1999e82 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -28,6 +28,7 @@ def unary o 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 @@ -35,6 +36,13 @@ def function o 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 diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 3c4fe12d1f470..92d05c7b675d1 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -38,13 +38,6 @@ def visit_Arel_Nodes_TableAlias o visit_edge o, "relation" end - def visit_Arel_Nodes_Sum o - visit_edge o, "expressions" - visit_edge o, "alias" - end - alias :visit_Arel_Nodes_Max :visit_Arel_Nodes_Sum - alias :visit_Arel_Nodes_Avg :visit_Arel_Nodes_Sum - def visit_Arel_Nodes_Count o visit_edge o, "expressions" visit_edge o, "distinct" @@ -82,6 +75,24 @@ def unary o alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary + 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 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" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4eae5a9ae56da..d5534384f8f7d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -183,6 +183,12 @@ 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_Count o "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x diff --git a/test/nodes/test_named_function.rb b/test/nodes/test_named_function.rb new file mode 100644 index 0000000000000..18ecdd2851f34 --- /dev/null +++ b/test/nodes/test_named_function.rb @@ -0,0 +1,13 @@ +require '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 + end + end +end diff --git a/test/nodes/test_node.rb b/test/nodes/test_node.rb index ffa3f273ea45a..b8d06b9cccafa 100644 --- a/test/nodes/test_node.rb +++ b/test/nodes/test_node.rb @@ -11,6 +11,7 @@ def test_all_nodes_are_nodes Nodes.const_get(k) }.grep(Class).each do |klass| next if Nodes::SqlLiteral == klass + next if klass.name =~ /^Arel::Nodes::Test/ assert klass.ancestors.include?(Nodes::Node), klass.name end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 306605b7c6887..6d7492674337c 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -52,10 +52,16 @@ def test_raises_with_object define_method("test_#{klass.name.gsub('::', '_')}") do func = klass.new(:a, :b) @visitor.accept func - assert_equal [:a, :b, func], @collector.calls + 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 @visitor.accept lock diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 3c7da8958a668..2909d87799dbd 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -7,6 +7,25 @@ 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, diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 34ebb2b27841e..0c7baab9236e9 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -15,6 +15,16 @@ module Visitors 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 '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) From dae7a245f8ec9f8eb5d9866938ea46ed7c88dcf1 Mon Sep 17 00:00:00 2001 From: Ken Chau Date: Thu, 6 Jan 2011 06:34:40 +0800 Subject: [PATCH 0960/1492] Regenerating arel.gemspec so the gemspec file is valid for gem build --- arel.gemspec | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index c7ec979042d9c..f6e89a4f167e0 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,42 +2,42 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20101201093009" + s.version = "2.0.7.beta.20110105143137" 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 = %q{2010-12-01} + s.date = %q{2011-01-05} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/as.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/does_not_match.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/matches.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/not_in.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.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/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.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_update_statement.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_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_join_sql.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} s.rubygems_version = %q{1.3.7} s.summary = %q{Arel is a Relational Algebra for Ruby} - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.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_update_statement.rb", "test/test_activerecord_compat.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_join_sql.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.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, [">= 2.0.0"]) + s.add_development_dependency(%q, [">= 1.6.0"]) s.add_development_dependency(%q, [">= 2.1.0"]) s.add_development_dependency(%q, [">= 1.6.0"]) - s.add_development_dependency(%q, [">= 2.6.2"]) + s.add_development_dependency(%q, [">= 2.8.0"]) else - s.add_dependency(%q, [">= 2.0.0"]) + s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) - s.add_dependency(%q, [">= 2.6.2"]) + s.add_dependency(%q, [">= 2.8.0"]) end else - s.add_dependency(%q, [">= 2.0.0"]) + s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) - s.add_dependency(%q, [">= 2.6.2"]) + s.add_dependency(%q, [">= 2.8.0"]) end end From af5c81339a19c731924c58b820ec549b0062562b Mon Sep 17 00:00:00 2001 From: Daniel Azuma Date: Wed, 19 Jan 2011 12:40:15 -0800 Subject: [PATCH 0961/1492] Chain predications off of named functions --- lib/arel/nodes/named_function.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/arel/nodes/named_function.rb b/lib/arel/nodes/named_function.rb index 56669bf85853a..5fca33e3231aa 100644 --- a/lib/arel/nodes/named_function.rb +++ b/lib/arel/nodes/named_function.rb @@ -3,6 +3,8 @@ module Nodes class NamedFunction < Arel::Nodes::Function attr_accessor :name + include Arel::Predications + def initialize name, expr, aliaz = nil super(expr, aliaz) @name = name From e86d4e035bc28e107f7d2234046b80db4825d447 Mon Sep 17 00:00:00 2001 From: Daniel Azuma Date: Wed, 19 Jan 2011 13:07:38 -0800 Subject: [PATCH 0962/1492] Test for NamedFunction predication chaining --- test/visitors/test_to_sql.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 0c7baab9236e9..c8ad40e242ea0 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -20,6 +20,12 @@ module Visitors 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 'works with lists' do function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star]) assert_equal 'omg(*, *)', @visitor.accept(function) From 6c65b0176223c90e08903ebc1a9a1075659f2c43 Mon Sep 17 00:00:00 2001 From: Jesse Storimer Date: Thu, 20 Jan 2011 00:37:05 -0500 Subject: [PATCH 0963/1492] Allow database specific locking clauses to be used --- lib/arel/nodes/lock.rb | 4 ++++ lib/arel/select_manager.rb | 2 +- lib/arel/visitors/mysql.rb | 6 +++++- lib/arel/visitors/postgresql.rb | 6 +++++- test/visitors/test_mysql.rb | 15 ++++++++++----- test/visitors/test_postgres.rb | 17 +++++++++++++---- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/arel/nodes/lock.rb b/lib/arel/nodes/lock.rb index e5fb258e26572..f4eaf125e037d 100644 --- a/lib/arel/nodes/lock.rb +++ b/lib/arel/nodes/lock.rb @@ -1,6 +1,10 @@ module Arel module Nodes class Lock < Arel::Nodes::Node + attr_reader :locking + def initialize locking = true + @locking = locking + end end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index b4103144fec92..fce6ca17d8359 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -40,7 +40,7 @@ def where_clauses def lock locking = true # FIXME: do we even need to store this? If locking is +false+ shouldn't # we just remove the node from the AST? - @ast.lock = Nodes::Lock.new + @ast.lock = Nodes::Lock.new(locking) self end diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index e90161eee49aa..8f9c3cc809372 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -3,7 +3,11 @@ module Visitors class MySQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Lock o - "FOR UPDATE" + if o.locking.is_a?(String) + o.locking + else + "FOR UPDATE" + end end ### diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 0e82a703ca09d..45e7349fd3d03 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -3,7 +3,11 @@ module Visitors class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Lock o - "FOR UPDATE" + if o.locking.is_a?(String) + o.locking + else + "FOR UPDATE" + end end def visit_Arel_Nodes_SelectStatement o diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index c3b79ca667b43..c22cbaff19a16 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -29,11 +29,16 @@ module Visitors sql.must_be_like "SELECT FROM DUAL" end - it 'uses FOR UPDATE when locking' do - stmt = Nodes::SelectStatement.new - stmt.lock = Nodes::Lock.new - sql = @visitor.accept(stmt) - sql.must_be_like "SELECT FROM DUAL FOR UPDATE" + describe 'locking' do + it 'defaults to FOR UPDATE when locking' do + node = Nodes::Lock.new + @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('LOCK IN SHARE MODE') + @visitor.accept(node).must_be_like "LOCK IN SHARE MODE" + end end end end diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 6e8f399b6b295..ec55e555a6b8c 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -7,10 +7,19 @@ module Visitors @visitor = PostgreSQL.new Table.engine end - it 'should produce a lock value' do - @visitor.accept(Nodes::Lock.new).must_be_like %{ - FOR UPDATE - } + describe 'locking' do + it 'defaults to FOR UPDATE' do + @visitor.accept(Nodes::Lock.new).must_be_like %{ + FOR UPDATE + } + end + + it 'allows a custom string to be used as a lock' do + node = Nodes::Lock.new('FOR SHARE') + @visitor.accept(node).must_be_like %{ + FOR SHARE + } + end end it "should escape LIMIT" do From d532b7ee430c5d0c412ab9f1a5e0dd3ebc47f86b Mon Sep 17 00:00:00 2001 From: Paul Sadauskas Date: Thu, 20 Jan 2011 12:56:08 -0700 Subject: [PATCH 0964/1492] Add support for WITH and UNION PostgreSQL WITH RECURSIVE support Make WITH be a unary node --- lib/arel/nodes.rb | 1 + lib/arel/nodes/binary.rb | 2 + lib/arel/nodes/select_statement.rb | 14 +++--- lib/arel/nodes/with.rb | 17 +++++++ lib/arel/select_manager.rb | 29 ++++++++++++ lib/arel/visitors/to_sql.rb | 18 ++++++++ test/test_select_manager.rb | 73 ++++++++++++++++++++++++++++++ test/visitors/test_postgres.rb | 1 + 8 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 lib/arel/nodes/with.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 64f2cc13fd794..cbd10c31e055c 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -9,6 +9,7 @@ # unary require 'arel/nodes/unary' require 'arel/nodes/unqualified_column' +require 'arel/nodes/with' # binary require 'arel/nodes/binary' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 0d025541991eb..e72228f11c37e 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -29,6 +29,8 @@ def initialize_copy other NotEqual NotIn Or + Union + UnionAll }.each do |name| const_set name, Class.new(Binary) end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index c9a0cde4e00f9..cd74dd8e28c0a 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -2,15 +2,17 @@ module Arel module Nodes class SelectStatement < Arel::Nodes::Node attr_reader :cores - attr_accessor :limit, :orders, :lock, :offset + attr_accessor :limit, :orders, :lock, :offset, :with, :with_recursive def initialize cores = [SelectCore.new] #puts caller - @cores = cores - @orders = [] - @limit = nil - @lock = nil - @offset = nil + @cores = cores + @orders = [] + @limit = nil + @lock = nil + @offset = nil + @with = nil + @with_recursive = nil end def initialize_copy other diff --git a/lib/arel/nodes/with.rb b/lib/arel/nodes/with.rb new file mode 100644 index 0000000000000..ce1644b60eb96 --- /dev/null +++ b/lib/arel/nodes/with.rb @@ -0,0 +1,17 @@ +module Arel + module Nodes + class With < Arel::Nodes::Unary + attr_reader :children + alias value children + alias expr children + + def initialize *children + @children = children + end + + end + + class WithRecursive < With; end + end +end + diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index b4103144fec92..4f510d096b07d 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -134,6 +134,35 @@ def where_sql Nodes::SqlLiteral.new viz.accept @ctx end + def union operation, other = nil + if operation.is_a? Symbol + if operation === :all + node_class = Nodes::UnionAll + else + raise "Only supported UNION operation is :all" + end + else + other = operation + node_class = Nodes::Union + end + + node_class.new self.ast, other.ast + end + + def with *subqueries + if subqueries.first.is_a? Symbol + if subqueries.shift == :recursive + node_class = Nodes::WithRecursive + else + raise "Only supported WITH modifier is :recursive" + end + else + node_class = Nodes::With + end + @ast.with = node_class.new(*subqueries) + end + + def take limit @ast.limit = Nodes::Limit.new(limit) @ctx.top = Nodes::Top.new(limit) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d5534384f8f7d..f3c871006879a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -129,6 +129,8 @@ def visit_Arel_Nodes_Values o def visit_Arel_Nodes_SelectStatement o [ + (visit(o.with) if o.with), + (visit(o.with_recursive) if o.with_recursive), 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.limit) if o.limit), @@ -149,6 +151,22 @@ def visit_Arel_Nodes_SelectCore o ].compact.join ' ' end + def visit_Arel_Nodes_With o + "WITH #{visit o.children}" + end + + def visit_Arel_Nodes_WithRecursive o + "WITH RECURSIVE #{visit o.children}" + 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_Having o "HAVING #{visit o.expr}" end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 271a8ae0b0c6b..f2873b2a65c5e 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -178,6 +178,79 @@ def test_join_sources 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 '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.from replies + manager.with :recursive, as_statement + manager.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 diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 6e8f399b6b295..8d3f19aa6ebea 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -22,6 +22,7 @@ module Visitors assert_match(/LIMIT 'omg'/, sql) assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit' end + end end end From 6abed021b19d073f159f9b7e6d9f466e053f8e6b Mon Sep 17 00:00:00 2001 From: Paul Sadauskas Date: Fri, 21 Jan 2011 17:30:10 -0700 Subject: [PATCH 0965/1492] Don't need with_recursive --- lib/arel/nodes/select_statement.rb | 3 +-- lib/arel/visitors/to_sql.rb | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index cd74dd8e28c0a..c99842f22f794 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -2,7 +2,7 @@ module Arel module Nodes class SelectStatement < Arel::Nodes::Node attr_reader :cores - attr_accessor :limit, :orders, :lock, :offset, :with, :with_recursive + attr_accessor :limit, :orders, :lock, :offset, :with def initialize cores = [SelectCore.new] #puts caller @@ -12,7 +12,6 @@ def initialize cores = [SelectCore.new] @lock = nil @offset = nil @with = nil - @with_recursive = nil end def initialize_copy other diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f3c871006879a..37c6a533ed4cc 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -130,7 +130,6 @@ def visit_Arel_Nodes_Values o def visit_Arel_Nodes_SelectStatement o [ (visit(o.with) if o.with), - (visit(o.with_recursive) if o.with_recursive), 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.limit) if o.limit), From 75bfee8cc15ca8bd07629c6e7b6f0950dcb2d864 Mon Sep 17 00:00:00 2001 From: Paul Sadauskas Date: Fri, 21 Jan 2011 17:40:44 -0700 Subject: [PATCH 0966/1492] With node takes an array, less code to determine alternative nodes --- lib/arel/nodes/with.rb | 9 +-------- lib/arel/select_manager.rb | 12 ++---------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/arel/nodes/with.rb b/lib/arel/nodes/with.rb index ce1644b60eb96..0745080cc3383 100644 --- a/lib/arel/nodes/with.rb +++ b/lib/arel/nodes/with.rb @@ -1,14 +1,7 @@ module Arel module Nodes class With < Arel::Nodes::Unary - attr_reader :children - alias value children - alias expr children - - def initialize *children - @children = children - end - + alias children expr end class WithRecursive < With; end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 4f510d096b07d..22e3dd07e0555 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -136,11 +136,7 @@ def where_sql def union operation, other = nil if operation.is_a? Symbol - if operation === :all - node_class = Nodes::UnionAll - else - raise "Only supported UNION operation is :all" - end + node_class = Nodes.const_get("Union#{operation.to_s.capitalize}") else other = operation node_class = Nodes::Union @@ -151,11 +147,7 @@ def union operation, other = nil def with *subqueries if subqueries.first.is_a? Symbol - if subqueries.shift == :recursive - node_class = Nodes::WithRecursive - else - raise "Only supported WITH modifier is :recursive" - end + node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") else node_class = Nodes::With end From 430d88b37632a3c91dd6c02eb2b19863207d1cae Mon Sep 17 00:00:00 2001 From: Paul Sadauskas Date: Fri, 21 Jan 2011 17:43:01 -0700 Subject: [PATCH 0967/1492] WITH expr as array in visitor --- lib/arel/select_manager.rb | 3 +-- lib/arel/visitors/to_sql.rb | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 22e3dd07e0555..8f5995e32c896 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -151,10 +151,9 @@ def with *subqueries else node_class = Nodes::With end - @ast.with = node_class.new(*subqueries) + @ast.with = node_class.new(subqueries.flatten) end - def take limit @ast.limit = Nodes::Limit.new(limit) @ctx.top = Nodes::Top.new(limit) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 37c6a533ed4cc..e021b5a707733 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -151,11 +151,11 @@ def visit_Arel_Nodes_SelectCore o end def visit_Arel_Nodes_With o - "WITH #{visit o.children}" + "WITH #{o.children.map { |x| visit x }.join(', ')}" end def visit_Arel_Nodes_WithRecursive o - "WITH RECURSIVE #{visit o.children}" + "WITH RECURSIVE #{o.children.map { |x| visit x }.join(', ')}" end def visit_Arel_Nodes_Union o From f0fe5e30dab40c500186d5901f3502796dca0d2c Mon Sep 17 00:00:00 2001 From: Paul Sadauskas Date: Fri, 21 Jan 2011 17:54:58 -0700 Subject: [PATCH 0968/1492] WTF, tabs? --- lib/arel/nodes/with.rb | 12 ++++---- lib/arel/select_manager.rb | 32 ++++++++++---------- lib/arel/visitors/to_sql.rb | 34 ++++++++++----------- test/test_select_manager.rb | 60 ++++++++++++++++++------------------- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/lib/arel/nodes/with.rb b/lib/arel/nodes/with.rb index 0745080cc3383..7f08abe47daab 100644 --- a/lib/arel/nodes/with.rb +++ b/lib/arel/nodes/with.rb @@ -1,10 +1,10 @@ module Arel - module Nodes - class With < Arel::Nodes::Unary - alias children expr - end + module Nodes + class With < Arel::Nodes::Unary + alias children expr + end - class WithRecursive < With; end - end + class WithRecursive < With; end + end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 8f5995e32c896..4e1382224d66b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -31,7 +31,7 @@ def exists def where_clauses if $VERBOSE - warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" + warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" end to_sql = Visitors::ToSql.new @engine @ctx.wheres.map { |c| to_sql.accept c } @@ -135,24 +135,24 @@ def where_sql end def union operation, other = nil - if operation.is_a? Symbol - node_class = Nodes.const_get("Union#{operation.to_s.capitalize}") - else - other = operation - node_class = Nodes::Union - end + if operation.is_a? Symbol + 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 + node_class.new self.ast, other.ast + end 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) - end + 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) + end def take limit @ast.limit = Nodes::Limit.new(limit) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index e021b5a707733..7cb4213fbb74d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -48,7 +48,7 @@ def visit_Arel_Nodes_UpdateStatement o (#{caller.first}) Using UpdateManager without setting UpdateManager#key is deprecated and support will be removed in ARel 3.0.0. Please set the primary key on UpdateManager using UpdateManager#key= -eowarn + eowarn key = o.relation.primary_key end @@ -75,8 +75,8 @@ 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?), + quote_column_name x.name + }.join ', '})" unless o.columns.empty?), (visit o.values if o.values), ].compact.join ' ' @@ -129,7 +129,7 @@ def visit_Arel_Nodes_Values o def visit_Arel_Nodes_SelectStatement o [ - (visit(o.with) if o.with), + (visit(o.with) if o.with), 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.limit) if o.limit), @@ -151,20 +151,20 @@ def visit_Arel_Nodes_SelectCore o end def visit_Arel_Nodes_With o - "WITH #{o.children.map { |x| visit x }.join(', ')}" - end + "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_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_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_UnionAll o + "( #{visit o.left} UNION ALL #{visit o.right} )" + end def visit_Arel_Nodes_Having o "HAVING #{visit o.expr}" @@ -303,11 +303,11 @@ def visit_Arel_Table o end def visit_Arel_Nodes_In o - "#{visit o.left} IN (#{visit o.right})" + "#{visit o.left} IN (#{visit o.right})" end def visit_Arel_Nodes_NotIn o - "#{visit o.left} NOT IN (#{visit o.right})" + "#{visit o.left} NOT IN (#{visit o.right})" end def visit_Arel_Nodes_And o diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index f2873b2a65c5e..bd96345b0188a 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -48,9 +48,9 @@ def execute sql, name = nil, *args 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 + 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 @@ -179,41 +179,41 @@ def test_join_sources 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)) + 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)) + @m2 = Arel::SelectManager.new Table.engine, table + @m2.project Arel.star + @m2.where(table[:age].gt(99)) - end + 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 + 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 + # 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 + 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 + node.to_sql.must_be_like %{ + ( SELECT * FROM "users" WHERE "users"."age" < 18 UNION ALL SELECT * FROM "users" WHERE "users"."age" > 99 ) + } + end - end + end - describe 'with' do + describe 'with' do it "should support WITH RECURSIVE" do comments = Table.new(:comments) @@ -249,7 +249,7 @@ def test_join_sources } end - end + end describe 'ast' do it 'should return the ast' do From e411e26f0798e64c634c3dc2da8ad05fc8e936de Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 21 Jan 2011 16:57:04 -0800 Subject: [PATCH 0969/1492] udpating manifest and gemspec --- Manifest.txt | 1 + arel.gemspec | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 8ecf21693e017..5545ddf0cfb67 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -41,6 +41,7 @@ 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/with.rb lib/arel/predications.rb lib/arel/relation.rb lib/arel/select_manager.rb diff --git a/arel.gemspec b/arel.gemspec index f6e89a4f167e0..5df1dd918abdf 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,15 +2,15 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110105143137" + s.version = "2.0.7.beta.20110121165657" 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 = %q{2011-01-05} + s.date = %q{2011-01-21} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] @@ -24,18 +24,18 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, [">= 1.6.0"]) + s.add_development_dependency(%q, [">= 2.0.0"]) s.add_development_dependency(%q, [">= 2.1.0"]) s.add_development_dependency(%q, [">= 1.6.0"]) s.add_development_dependency(%q, [">= 2.8.0"]) else - s.add_dependency(%q, [">= 1.6.0"]) + s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.8.0"]) end else - s.add_dependency(%q, [">= 1.6.0"]) + s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) s.add_dependency(%q, [">= 2.8.0"]) From 74caeaad157e79853b9c6804f561d3c70eea2346 Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Sat, 22 Jan 2011 09:16:53 -0500 Subject: [PATCH 0970/1492] Added support for INTERSECT and EXCEPT --- lib/arel/nodes/binary.rb | 2 ++ lib/arel/select_manager.rb | 10 +++++++ lib/arel/visitors/to_sql.rb | 8 ++++++ test/test_select_manager.rb | 54 +++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index e72228f11c37e..bcd46db39890d 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -31,6 +31,8 @@ def initialize_copy other Or Union UnionAll + Intersect + Except }.each do |name| const_set name, Class.new(Binary) end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 4e1382224d66b..afc46a626e791 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -145,6 +145,16 @@ def union operation, other = nil node_class.new self.ast, other.ast end + def intersect other = nil + node_class = Nodes::Intersect + node_class.new self.ast, other.ast + end + + def except other = nil + node_class = Nodes::Except + node_class.new self.ast, other.ast + end + def with *subqueries if subqueries.first.is_a? Symbol node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7cb4213fbb74d..a395b7f7658ad 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -166,6 +166,14 @@ 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_Having o "HAVING #{visit o.expr}" end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index bd96345b0188a..f457c55f40e8b 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -213,6 +213,60 @@ def test_join_sources 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 From f574327f19f717a66b327ebffd8ef0fdb3967fdc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 22 Jan 2011 14:08:27 -0800 Subject: [PATCH 0971/1492] other should not be optional --- lib/arel/select_manager.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index afc46a626e791..e330e49e71f46 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -145,14 +145,12 @@ def union operation, other = nil node_class.new self.ast, other.ast end - def intersect other = nil - node_class = Nodes::Intersect - node_class.new self.ast, other.ast + def intersect other + Nodes::Intersect.new ast, other.ast end - def except other = nil - node_class = Nodes::Except - node_class.new self.ast, other.ast + def except other + Nodes::Except.new ast, other.ast end def with *subqueries From 5bc709be9eed03022927cbe8ab0708fcfa971f2b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 22 Jan 2011 14:11:01 -0800 Subject: [PATCH 0972/1492] no need for is_a? check --- lib/arel/select_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index e330e49e71f46..77853ea854d25 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -135,7 +135,7 @@ def where_sql end def union operation, other = nil - if operation.is_a? Symbol + if other node_class = Nodes.const_get("Union#{operation.to_s.capitalize}") else other = operation From 7b445c6dd578277f7313746fc497429a56e4b43c Mon Sep 17 00:00:00 2001 From: Brian Cardarella Date: Sun, 23 Jan 2011 11:54:00 -0500 Subject: [PATCH 0973/1492] Added MINUS for Oracle Aliased :minus to :except for the SelectManager --- lib/arel/select_manager.rb | 1 + lib/arel/visitors/oracle.rb | 4 ++++ test/visitors/test_oracle.rb | 9 +++++++++ 3 files changed, 14 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 77853ea854d25..0fa344945e356 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -152,6 +152,7 @@ def intersect other def except other Nodes::Except.new ast, other.ast end + alias :minus :except def with *subqueries if subqueries.first.is_a? Symbol diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index aaf0324fd72f2..3beea287a6455 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -61,6 +61,10 @@ 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 + ### # Hacks for the order clauses specific to Oracle def order_hacks o diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index c6fcb7134c8fd..87b94409e3aba 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -134,6 +134,15 @@ module Visitors 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 end end end From 2158d592c074813471baa8fa20044b683bb156e6 Mon Sep 17 00:00:00 2001 From: Vladimir Meremyanin Date: Sat, 29 Jan 2011 14:40:39 +0800 Subject: [PATCH 0974/1492] implemented support for math operations in numeric attributes --- README.markdown | 17 +++++++++++++++++ lib/arel.rb | 1 + lib/arel/attributes/attribute.rb | 10 +++++++--- lib/arel/math.rb | 21 +++++++++++++++++++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/math_operation.rb | 15 +++++++++++++++ lib/arel/visitors/to_sql.rb | 16 ++++++++++++++++ test/support/fake_record.rb | 8 ++++++-- test/visitors/test_to_sql.rb | 22 ++++++++++++++++++++++ 9 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 lib/arel/math.rb create mode 100644 lib/arel/nodes/math_operation.rb diff --git a/README.markdown b/README.markdown index b71879e4e3878..4952ec6191bf5 100644 --- a/README.markdown +++ b/README.markdown @@ -74,6 +74,23 @@ The `AND` operator behaves similarly. 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: diff --git a/lib/arel.rb b/lib/arel.rb index 32fc8d9bc08ff..de429f532e1dd 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -3,6 +3,7 @@ require 'arel/expressions' require 'arel/predications' +require 'arel/math' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 9a42e5a4da40a..bd3f4b58f1a96 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -5,12 +5,16 @@ class Attribute < Struct.new :relation, :name include Arel::Predications end + class NumericAttribute < Attribute + include Arel::Math + 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 Decimal < NumericAttribute; end + class Float < NumericAttribute; end + class Integer < NumericAttribute; end class Undefined < Attribute; end end diff --git a/lib/arel/math.rb b/lib/arel/math.rb new file mode 100644 index 0000000000000..551b1f1010bea --- /dev/null +++ b/lib/arel/math.rb @@ -0,0 +1,21 @@ +module Arel + module Math + + def *(other) + Arel::Nodes::Multiplication.new(self, other) + end + + def +(other) + Arel::Nodes::Addition.new(self, other) + end + + def -(other) + Arel::Nodes::Subtraction.new(self, other) + end + + def /(other) + Arel::Nodes::Division.new(self, other) + end + + end +end \ No newline at end of file diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index cbd10c31e055c..129c43b7136f7 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -19,6 +19,7 @@ require 'arel/nodes/ordering' require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' +require 'arel/nodes/math_operation' # nary require 'arel/nodes/and' diff --git a/lib/arel/nodes/math_operation.rb b/lib/arel/nodes/math_operation.rb new file mode 100644 index 0000000000000..d9820f1ecee1c --- /dev/null +++ b/lib/arel/nodes/math_operation.rb @@ -0,0 +1,15 @@ +module Arel + module Nodes + class MathOperation < Binary + include Arel::Expressions + include Arel::Predications + include Arel::Math + end + + class Multiplication < MathOperation; end + class Division < MathOperation; end + class Addition < MathOperation; end + class Subtraction < MathOperation; end + + end +end \ No newline at end of file diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a395b7f7658ad..376d1460db9bc 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -395,6 +395,22 @@ def quoted o; quote(o, @last_column) end alias :visit_Time :quoted alias :visit_TrueClass :quoted + def visit_Arel_Nodes_Multiplication o + "#{visit o.left} * #{visit o.right}" + end + + def visit_Arel_Nodes_Division o + "#{visit o.left} / #{visit o.right}" + end + + def visit_Arel_Nodes_Addition o + "(#{visit o.left} + #{visit o.right})" + end + + def visit_Arel_Nodes_Subtraction o + "(#{visit o.left} - #{visit o.right})" + end + def visit_Array o o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') end diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 376ed40f2d7ef..cdea690a7b71f 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -6,13 +6,17 @@ class Connection attr_reader :tables def initialize - @tables = %w{ users photos developers } + @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), + Column.new('created_at', :date) + ], + 'products' => [ + Column.new('id', :integer), + Column.new('price', :decimal) ] } @primary_keys = { diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 0c7baab9236e9..82ad17a82cdc3 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -188,6 +188,28 @@ def quote value, column = nil end end + describe "Nodes::MathOperation" 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 + end + describe "Nodes::NotIn" do it "should know how to visit" do node = @attr.not_in [1, 2, 3] From b4ca49dd9f2ea15fe34dd5f01215afad834f2f40 Mon Sep 17 00:00:00 2001 From: Paul Sadauskas Date: Tue, 25 Jan 2011 11:27:42 -0700 Subject: [PATCH 0975/1492] Make #with chainable --- lib/arel/select_manager.rb | 2 ++ test/test_select_manager.rb | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 0fa344945e356..2747bdfda821b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -161,6 +161,8 @@ def with *subqueries node_class = Nodes::With end @ast.with = node_class.new(subqueries.flatten) + + self end def take limit diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index f457c55f40e8b..3ffdbe2e23b5b 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -288,9 +288,7 @@ def test_join_sources as_statement = Arel::Nodes::As.new replies, union manager = Arel::SelectManager.new Table.engine - manager.from replies - manager.with :recursive, as_statement - manager.project Arel.star + manager.with(:recursive, as_statement).from(replies).project(Arel.star) sql = manager.to_sql sql.must_be_like %{ @@ -302,7 +300,6 @@ def test_join_sources SELECT * FROM "replies" } end - end describe 'ast' do From 41ed0708955c0dacccf882ac1cb57ab396dde6ab Mon Sep 17 00:00:00 2001 From: Brian Dunn Date: Tue, 11 Jan 2011 14:53:14 -0600 Subject: [PATCH 0976/1492] Added test, thanks josephholsten --- test/visitors/test_mssql.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index b658e46828e7e..3d002dc563c2f 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -13,6 +13,15 @@ module Visitors sql = @visitor.accept(stmt) sql.must_be_like "SELECT TOP 1" end + + it 'uses TOP 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 TOP 1 'id' )" + end + end end end From 345646619f034fbce952b0339ea86e1607548570 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 2 Feb 2011 15:00:54 -0800 Subject: [PATCH 0977/1492] fixing whitespace errors --- test/visitors/test_mssql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index 3d002dc563c2f..ccaea395fe127 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -13,7 +13,7 @@ module Visitors sql = @visitor.accept(stmt) sql.must_be_like "SELECT TOP 1" end - + it 'uses TOP in updates with a limit' do stmt = Nodes::UpdateStatement.new stmt.limit = Nodes::Limit.new(1) From 066d9a3f5d24feb628187117769aee81f8538159 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 2 Feb 2011 15:09:54 -0800 Subject: [PATCH 0978/1492] adding TOP to sub selects for mssql --- History.txt | 4 ++++ lib/arel/visitors/mssql.rb | 7 +++++++ lib/arel/visitors/to_sql.rb | 21 ++++++++++++--------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/History.txt b/History.txt index 51e950512f850..aa5bbd77e2537 100644 --- a/History.txt +++ b/History.txt @@ -7,6 +7,10 @@ * SQL Literals may be used as Attribute names * Added Arel::Nodes::NamedFunction for representing generic SQL functions +* Bug fixes + + * MSSQL adds TOP to sub selects + * Deprecations * Calls to `insert` are deprecated. Please use `compile_insert` then call diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 9b0e77c19bc84..ea7ab6394c3f2 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -3,6 +3,13 @@ module Visitors class MSSQL < Arel::Visitors::ToSql private + def build_subselect key, o + stmt = super + core = stmt.cores.first + core.top = Nodes::Top.new(o.limit.expr) if o.limit + stmt + end + def visit_Arel_Nodes_Limit o "" end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a395b7f7658ad..61f68a8c09a4c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -38,6 +38,17 @@ def visit_Arel_Nodes_DeleteStatement o ].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.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 @@ -52,15 +63,7 @@ def visit_Arel_Nodes_UpdateStatement o key = o.relation.primary_key end - wheres = o.wheres - stmt = Nodes::SelectStatement.new - core = stmt.cores.first - core.froms = o.relation - core.projections = [key] - stmt.limit = o.limit - stmt.orders = o.orders - - wheres = [Nodes::In.new(key, [stmt])] + wheres = [Nodes::In.new(key, [build_subselect(key, o)])] end [ From 3cd905ee7b6ec8765cf9690b88ada5ae27fc3fd0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 7 Feb 2011 09:26:18 -0800 Subject: [PATCH 0979/1492] use the cache mechanism in the connection pool rather than our own cache --- lib/arel/visitors/to_sql.rb | 31 +++---------------------------- test/support/fake_record.rb | 13 ++++++++++++- test/test_select_manager.rb | 4 ++++ 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 61f68a8c09a4c..70e10a5e0f9c5 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -11,14 +11,6 @@ def initialize engine @last_column = nil @quoted_tables = {} @quoted_columns = {} - @column_cache = Hash.new { |h,pool| - h[pool] = Hash.new { |conn_h,column| - conn_h[column] = {} - } - } - @table_exists = Hash.new { |h,pool| - h[pool] = {} - } end def accept object @@ -91,37 +83,20 @@ def visit_Arel_Nodes_Exists o end def table_exists? name - return true if table_exists.key? name - - @connection.tables.each do |table| - table_exists[table] = true - end - - table_exists.key? name - end - - def table_exists - @table_exists[@pool] + @pool.table_exists? name end def column_for attr - name = attr.name.to_sym + name = attr.name.to_s table = attr.relation.name return nil unless table_exists? table - # If we don't have this column cached, get a list of columns and - # cache them for this table - unless column_cache.key? table - columns = @connection.columns(table, "#{table}(#{name}) Columns") - column_cache[table] = Hash[columns.map { |c| [c.name.to_sym, c] }] - end - column_cache[table][name] end def column_cache - @column_cache[@pool] + @pool.columns_hash end def visit_Arel_Nodes_Values o diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 376ed40f2d7ef..54f73489c9012 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -3,7 +3,7 @@ class Column < Struct.new(:name, :type) end class Connection - attr_reader :tables + attr_reader :tables, :columns_hash def initialize @tables = %w{ users photos developers } @@ -15,6 +15,9 @@ def initialize Column.new('created_at', :date), ] } + @columns_hash = { + 'users' => Hash[@columns['users'].map { |x| [x.name, x] }] + } @primary_keys = { 'users' => 'id' } @@ -75,6 +78,14 @@ def initialize def with_connection yield connection end + + def table_exists? name + connection.tables.include? name.to_s + end + + def columns_hash + connection.columns_hash + end end class Base diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 3ffdbe2e23b5b..3b5ded8389a09 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -30,6 +30,10 @@ 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 From 3d21dabaa6c214ab2f2941c063bd7de04fd95202 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Mon, 7 Feb 2011 21:39:19 -0500 Subject: [PATCH 0980/1492] Fix modification of input on *_any/*_all predications --- lib/arel/predications.rb | 2 ++ test/attributes/test_attribute.rb | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 58f02a2b53bb8..920a9ee374a19 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -163,6 +163,7 @@ def desc private def grouping_any method_id, others + others = others.dup first = send method_id, others.shift Nodes::Grouping.new others.inject(first) { |memo,expr| @@ -171,6 +172,7 @@ def grouping_any method_id, others end def grouping_all method_id, others + others = others.dup first = send method_id, others.shift Nodes::Grouping.new others.inject(first) { |memo,expr| diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index df7dc6962106d..352774071a424 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -366,6 +366,14 @@ module Attributes 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 @@ -382,6 +390,14 @@ module Attributes 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 From dbc86c0f2c2fc3c8bacf35c67fb8e0967b0a8980 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 11 Feb 2011 12:08:32 -0500 Subject: [PATCH 0981/1492] Fix #not to stop wrapping in a grouping node --- lib/arel/nodes/node.rb | 2 +- test/nodes/test_not.rb | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 711fa34b6d4a4..1a5bc278567e7 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -10,7 +10,7 @@ class Node # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. def not - Nodes::Not.new Nodes::Grouping.new self + Nodes::Not.new self end ### diff --git a/test/nodes/test_not.rb b/test/nodes/test_not.rb index d02a9bad74e38..c5bb0088c8ac8 100644 --- a/test/nodes/test_not.rb +++ b/test/nodes/test_not.rb @@ -6,13 +6,10 @@ module Nodes describe '#not' do it 'makes a NOT 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 - - node.or(right).not + expr = attr.eq(10) + node = expr.not + node.must_be_kind_of Not + node.expr.must_equal expr end end end From a4c10530e70fc42358cf7ea32440376f2c3c4c58 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 Feb 2011 15:01:49 -0800 Subject: [PATCH 0982/1492] adding failing tests for rails #6384 --- test/test_select_manager.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 3b5ded8389a09..4b4733db97f46 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -126,6 +126,24 @@ def test_join_sources 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 From 8ed3ab00f1ba8cdf48dea4ca28d2d3a7e73396ab Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 Feb 2011 15:14:29 -0800 Subject: [PATCH 0983/1492] Lock should be a unary node --- lib/arel/nodes.rb | 1 - lib/arel/nodes/lock.rb | 10 ---------- lib/arel/nodes/unary.rb | 1 + lib/arel/visitors/mysql.rb | 4 ++-- lib/arel/visitors/postgresql.rb | 4 ++-- test/visitors/test_depth_first.rb | 2 +- test/visitors/test_mysql.rb | 2 +- test/visitors/test_postgres.rb | 2 +- 8 files changed, 8 insertions(+), 18 deletions(-) delete mode 100644 lib/arel/nodes/lock.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index cbd10c31e055c..442b313593caa 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,6 +1,5 @@ # node require 'arel/nodes/node' -require 'arel/nodes/lock' require 'arel/nodes/select_statement' require 'arel/nodes/select_core' require 'arel/nodes/insert_statement' diff --git a/lib/arel/nodes/lock.rb b/lib/arel/nodes/lock.rb deleted file mode 100644 index f4eaf125e037d..0000000000000 --- a/lib/arel/nodes/lock.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - module Nodes - class Lock < Arel::Nodes::Node - attr_reader :locking - def initialize locking = true - @locking = locking - end - end - end -end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index e1576b9c99a19..1b1dcb1053363 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -18,6 +18,7 @@ def initialize expr Offset On Top + Lock }.each do |name| const_set(name, Class.new(Unary)) end diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 8f9c3cc809372..dad4d5e3b20d6 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -3,8 +3,8 @@ module Visitors class MySQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Lock o - if o.locking.is_a?(String) - o.locking + if o.expr.is_a?(String) + o.expr else "FOR UPDATE" end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 45e7349fd3d03..68b483910ee77 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -3,8 +3,8 @@ module Visitors class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Lock o - if o.locking.is_a?(String) - o.locking + if o.expr.is_a?(String) + o.expr else "FOR UPDATE" end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 6d7492674337c..06e7bba9fb0fe 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -63,7 +63,7 @@ def test_named_function end def test_lock - lock = Nodes::Lock.new + lock = Nodes::Lock.new true @visitor.accept lock assert_equal [lock], @collector.calls end diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index c22cbaff19a16..ee70d4c1742d7 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -31,7 +31,7 @@ module Visitors describe 'locking' do it 'defaults to FOR UPDATE when locking' do - node = Nodes::Lock.new + node = Nodes::Lock.new true @visitor.accept(node).must_be_like "FOR UPDATE" end diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 9ed42b18066c8..169510185e99e 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -9,7 +9,7 @@ module Visitors describe 'locking' do it 'defaults to FOR UPDATE' do - @visitor.accept(Nodes::Lock.new).must_be_like %{ + @visitor.accept(Nodes::Lock.new(true)).must_be_like %{ FOR UPDATE } end From c7eef391dbcf3364f3792c0e0bbffd4bc3e139d0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 Feb 2011 15:40:38 -0800 Subject: [PATCH 0984/1492] refactoring custom lock logic to use sql literals --- lib/arel/select_manager.rb | 12 +++++++++--- lib/arel/visitors/mysql.rb | 6 +----- lib/arel/visitors/postgresql.rb | 6 +----- test/visitors/test_mysql.rb | 4 ++-- test/visitors/test_postgres.rb | 4 ++-- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 249ad680a72cf..adffcca764861 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -37,9 +37,15 @@ def where_clauses @ctx.wheres.map { |c| to_sql.accept c } end - def lock locking = true - # FIXME: do we even need to store this? If locking is +false+ shouldn't - # we just remove the node from the AST? + 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 diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index dad4d5e3b20d6..4f029245ac970 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -3,11 +3,7 @@ module Visitors class MySQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Lock o - if o.expr.is_a?(String) - o.expr - else - "FOR UPDATE" - end + visit o.expr end ### diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 68b483910ee77..c423dc6fc6726 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -3,11 +3,7 @@ module Visitors class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Lock o - if o.expr.is_a?(String) - o.expr - else - "FOR UPDATE" - end + visit o.expr end def visit_Arel_Nodes_SelectStatement o diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index ee70d4c1742d7..3c15c218b21cf 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -31,12 +31,12 @@ module Visitors describe 'locking' do it 'defaults to FOR UPDATE when locking' do - node = Nodes::Lock.new true + 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('LOCK IN SHARE MODE') + node = Nodes::Lock.new(Arel.sql('LOCK IN SHARE MODE')) @visitor.accept(node).must_be_like "LOCK IN SHARE MODE" end end diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 169510185e99e..74446c23ba7c7 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -9,13 +9,13 @@ module Visitors describe 'locking' do it 'defaults to FOR UPDATE' do - @visitor.accept(Nodes::Lock.new(true)).must_be_like %{ + @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('FOR SHARE') + node = Nodes::Lock.new(Arel.sql('FOR SHARE')) @visitor.accept(node).must_be_like %{ FOR SHARE } From a64d47781ed6020868545db2cdfbdd07c93e12bb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 24 Feb 2011 09:46:10 -0800 Subject: [PATCH 0985/1492] updating gemspec and manifest --- Manifest.txt | 1 - arel.gemspec | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 5545ddf0cfb67..f5fd7d7a803b2 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -27,7 +27,6 @@ lib/arel/nodes/in.rb lib/arel/nodes/inner_join.rb lib/arel/nodes/insert_statement.rb lib/arel/nodes/join_source.rb -lib/arel/nodes/lock.rb lib/arel/nodes/named_function.rb lib/arel/nodes/node.rb lib/arel/nodes/ordering.rb diff --git a/arel.gemspec b/arel.gemspec index 5df1dd918abdf..2e1796dd17164 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,42 +2,41 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110121165657" + s.version = "2.0.7.beta.20110224094525" 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 = %q{2011-01-21} + s.date = %q{2011-02-24} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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", ".gemtest"] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.3.7} + s.rubygems_version = %q{1.5.2} s.summary = %q{Arel is a Relational Algebra for Ruby} s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, [">= 2.0.0"]) s.add_development_dependency(%q, [">= 2.1.0"]) s.add_development_dependency(%q, [">= 1.6.0"]) - s.add_development_dependency(%q, [">= 2.8.0"]) + s.add_development_dependency(%q, [">= 2.9.1"]) else s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) - s.add_dependency(%q, [">= 2.8.0"]) + s.add_dependency(%q, [">= 2.9.1"]) end else s.add_dependency(%q, [">= 2.0.0"]) s.add_dependency(%q, [">= 2.1.0"]) s.add_dependency(%q, [">= 1.6.0"]) - s.add_dependency(%q, [">= 2.8.0"]) + s.add_dependency(%q, [">= 2.9.1"]) end end From 6b021764ff16bbab92f8c27ea8f93f1c8df6bd50 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 24 Feb 2011 09:51:08 -0800 Subject: [PATCH 0986/1492] one more spec update --- arel.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 2e1796dd17164..16ceb11c053d1 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110224094525" + s.version = "2.0.7.beta.20110224095102" 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"] @@ -10,7 +10,7 @@ Gem::Specification.new do |s| s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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", ".gemtest"] + s.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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", ".gemtest"] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] From abffef945a64a32ac959ee11d41593d575bcccab Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 25 Feb 2011 15:19:11 -0800 Subject: [PATCH 0987/1492] Adding SelectManager#limit= and removing limit nodes when nil is assigned to limit --- History.txt | 2 ++ lib/arel/select_manager.rb | 10 ++++++++-- test/test_select_manager.rb | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index aa5bbd77e2537..a931afd0ef2ea 100644 --- a/History.txt +++ b/History.txt @@ -6,10 +6,12 @@ * 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= * Bug fixes * MSSQL adds TOP to sub selects + * Assigning nil to take() removes LIMIT from statement. * Deprecations diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index adffcca764861..37405b45965b3 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -172,10 +172,16 @@ def with *subqueries end def take limit - @ast.limit = Nodes::Limit.new(limit) - @ctx.top = Nodes::Top.new(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? diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 4b4733db97f46..efea44d56f5ee 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -743,6 +743,15 @@ def test_join_sources 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 From 2644bcec7dbe3a65277b3a6a141853484171535a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 25 Feb 2011 15:23:21 -0800 Subject: [PATCH 0988/1492] assinging nil to an offset will remove the offset from the AST --- History.txt | 3 +++ lib/arel/select_manager.rb | 11 ++++++++++- test/test_select_manager.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index a931afd0ef2ea..fac98381a6302 100644 --- a/History.txt +++ b/History.txt @@ -7,11 +7,14 @@ * 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= * Bug fixes * MSSQL adds TOP to sub selects * Assigning nil to take() removes LIMIT from statement. + * Assigning nil to offset() removes OFFSET from statement. * Deprecations diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 37405b45965b3..7f533fa91b225 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -18,10 +18,19 @@ def constraints @ctx.wheres end + def offset + @ast.offset && @ast.offset.expr + end + def skip amount - @ast.offset = Nodes::Offset.new(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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index efea44d56f5ee..2fe43aa982279 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -180,6 +180,32 @@ def test_join_sources 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) From a85530820426f8baa4dbb1fa863313c6a6c69484 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 4 Mar 2011 06:13:22 +0800 Subject: [PATCH 0989/1492] Add an #table_name method to Table and TableAlias, which always returns the actual table name, not the alias. Then fix ToSql#column_for to use this table name when checking whether the table exists (rather than before, where it was checking whether a table with the alias name exists, which was incorrect). --- lib/arel/nodes/table_alias.rb | 4 ++++ lib/arel/table.rb | 3 +++ lib/arel/visitors/to_sql.rb | 2 +- test/test_table.rb | 4 ++++ test/visitors/test_to_sql.rb | 9 +++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 4f4d5e29e9f40..1d3d36be0c504 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -8,6 +8,10 @@ class TableAlias < Arel::Nodes::Binary def [] name Attribute.new(self, name) end + + def table_name + relation.name + end end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index d1d1e40e11692..2aff71b220874 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -8,6 +8,9 @@ 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 70e10a5e0f9c5..f76c1491ee10b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -88,7 +88,7 @@ def table_exists? name def column_for attr name = attr.name.to_s - table = attr.relation.name + table = attr.relation.table_name return nil unless table_exists? table diff --git a/test/test_table.rb b/test/test_table.rb index 129d7ba736ebc..10355405135b5 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -164,6 +164,10 @@ module Arel @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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index c8ad40e242ea0..2d5549ca43442 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -259,6 +259,15 @@ def quote value, column = nil } 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 end end end From e7cdaedb6bc7d452142b9b8c42942d659efcd11a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 7 Mar 2011 08:35:48 -0800 Subject: [PATCH 0990/1492] cleaning up math operations on attributes --- History.txt | 2 ++ arel.gemspec | 6 +++--- lib/arel/attributes/attribute.rb | 9 +++------ lib/arel/math.rb | 4 +--- test/support/fake_record.rb | 6 ++++-- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/History.txt b/History.txt index fac98381a6302..a5f630b0216c4 100644 --- a/History.txt +++ b/History.txt @@ -9,6 +9,8 @@ * Add Arel::SelectManager#limit= * Add Arel::SelectManager#offset * Add Arel::SelectManager#offset= + * Math operations have been added to attributes, thanks to + Vladimir Meremyanin. * Bug fixes diff --git a/arel.gemspec b/arel.gemspec index 16ceb11c053d1..58cb8f61fb985 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,15 +2,15 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110224095102" + s.version = "2.0.7.beta.20110228092631" 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 = %q{2011-02-24} + s.date = %q{2011-02-28} s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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", ".gemtest"] + s.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index bd3f4b58f1a96..5aea87ac43e6c 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -3,18 +3,15 @@ module Attributes class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications - end - - class NumericAttribute < Attribute include Arel::Math end class String < Attribute; end class Time < Attribute; end class Boolean < Attribute; end - class Decimal < NumericAttribute; end - class Float < NumericAttribute; end - class Integer < NumericAttribute; end + class Decimal < Attribute; end + class Float < Attribute; end + class Integer < Attribute; end class Undefined < Attribute; end end diff --git a/lib/arel/math.rb b/lib/arel/math.rb index 551b1f1010bea..b7c2419233c6b 100644 --- a/lib/arel/math.rb +++ b/lib/arel/math.rb @@ -1,6 +1,5 @@ module Arel module Math - def *(other) Arel::Nodes::Multiplication.new(self, other) end @@ -16,6 +15,5 @@ def -(other) def /(other) Arel::Nodes::Division.new(self, other) end - end -end \ No newline at end of file +end diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index a0fa79d519733..babf5fa25b6dd 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -20,10 +20,12 @@ def initialize ] } @columns_hash = { - 'users' => Hash[@columns['users'].map { |x| [x.name, x] }] + 'users' => Hash[@columns['users'].map { |x| [x.name, x] }], + 'products' => Hash[@columns['products'].map { |x| [x.name, x] }] } @primary_keys = { - 'users' => 'id' + 'users' => 'id', + 'products' => 'id' } end From 21e052796d3007488d5dd9f00299a3a22fdb6249 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 9 Mar 2011 02:27:43 +0800 Subject: [PATCH 0991/1492] Replace MathOperation with InfixOperation to support more operators --- lib/arel/math.rb | 4 +-- lib/arel/nodes.rb | 2 +- lib/arel/nodes/infix_operation.rb | 42 +++++++++++++++++++++++++++++++ lib/arel/nodes/math_operation.rb | 15 ----------- lib/arel/visitors/to_sql.rb | 19 +++++--------- test/visitors/test_to_sql.rb | 11 +++++++- 6 files changed, 61 insertions(+), 32 deletions(-) create mode 100644 lib/arel/nodes/infix_operation.rb delete mode 100644 lib/arel/nodes/math_operation.rb diff --git a/lib/arel/math.rb b/lib/arel/math.rb index b7c2419233c6b..f3dbc7bc49438 100644 --- a/lib/arel/math.rb +++ b/lib/arel/math.rb @@ -5,11 +5,11 @@ def *(other) end def +(other) - Arel::Nodes::Addition.new(self, other) + Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new(self, other)) end def -(other) - Arel::Nodes::Subtraction.new(self, other) + Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other)) end def /(other) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 4b97e28668ef8..cf2aeb2ddc8fe 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -18,7 +18,7 @@ require 'arel/nodes/ordering' require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' -require 'arel/nodes/math_operation' +require 'arel/nodes/infix_operation' # nary require 'arel/nodes/and' diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb new file mode 100644 index 0000000000000..6847650fe40f1 --- /dev/null +++ b/lib/arel/nodes/infix_operation.rb @@ -0,0 +1,42 @@ +module Arel + module Nodes + + class InfixOperation < Binary + include Arel::Expressions + include Arel::Predications + 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 +end \ No newline at end of file diff --git a/lib/arel/nodes/math_operation.rb b/lib/arel/nodes/math_operation.rb deleted file mode 100644 index d9820f1ecee1c..0000000000000 --- a/lib/arel/nodes/math_operation.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Arel - module Nodes - class MathOperation < Binary - include Arel::Expressions - include Arel::Predications - include Arel::Math - end - - class Multiplication < MathOperation; end - class Division < MathOperation; end - class Addition < MathOperation; end - class Subtraction < MathOperation; end - - end -end \ No newline at end of file diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f30557e509f0e..1550757cf4711 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -373,21 +373,14 @@ def quoted o; quote(o, @last_column) end alias :visit_Time :quoted alias :visit_TrueClass :quoted - def visit_Arel_Nodes_Multiplication o - "#{visit o.left} * #{visit o.right}" + def visit_Arel_Nodes_InfixOperation o + "#{visit o.left} #{o.operator} #{visit o.right}" end - def visit_Arel_Nodes_Division o - "#{visit o.left} / #{visit o.right}" - end - - def visit_Arel_Nodes_Addition o - "(#{visit o.left} + #{visit o.right})" - end - - def visit_Arel_Nodes_Subtraction o - "(#{visit o.left} - #{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.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index c47fd57a284ef..25ff7be3e2f26 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -194,7 +194,7 @@ def quote value, column = nil end end - describe "Nodes::MathOperation" do + 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") @@ -214,6 +214,15 @@ def quote value, column = nil 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 From d13ae3d51b32bfda31ebfee5230122f8fdb3a343 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 11 Mar 2011 18:12:09 -0800 Subject: [PATCH 0992/1492] zenspider says we do not need these lines --- Rakefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Rakefile b/Rakefile index 7e3e4b31c8a0a..fe82460ae37c3 100644 --- a/Rakefile +++ b/Rakefile @@ -15,6 +15,4 @@ Hoe.spec 'arel' do self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] - self.extra_dev_deps << [ 'hoe', '>= 2.1.0' ] - self.extra_dev_deps << [ 'minitest', '>= 1.6.0' ] end From 05887fc406820f2e8fecc5cedcc42b87cf9f0ab1 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 12 Mar 2011 10:53:47 +0800 Subject: [PATCH 0993/1492] Make as factory method convert alias name to SqlLiteral --- lib/arel/predications.rb | 2 +- test/nodes/test_as.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 920a9ee374a19..75c4c75855743 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,7 +1,7 @@ module Arel module Predications def as other - Nodes::As.new self, other + Nodes::As.new self, Nodes::SqlLiteral.new(other) end def not_eq other diff --git a/test/nodes/test_as.rb b/test/nodes/test_as.rb index 8585fbc963dbb..02cbe5f7b0112 100644 --- a/test/nodes/test_as.rb +++ b/test/nodes/test_as.rb @@ -10,6 +10,12 @@ module Nodes 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 end end From 856fd75c9b6defb7711f93e6ecda2932e98c4113 Mon Sep 17 00:00:00 2001 From: Hugo Peixoto Date: Sun, 6 Mar 2011 10:28:46 +0000 Subject: [PATCH 0994/1492] Fixes rails bug #6058. Propagates 'where' clauses when subquerying is triggered on the UpdateManager. --- lib/arel/visitors/to_sql.rb | 1 + test/test_select_manager.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f30557e509f0e..6bf5a3bb6b264 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -35,6 +35,7 @@ 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 2fe43aa982279..410fe38e2a3a7 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -713,6 +713,20 @@ def test_join_sources } 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 From aca58b2360f7459623499018e0a19febac926267 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 Mar 2011 21:23:48 -0700 Subject: [PATCH 0995/1492] adding create_insert method --- History.txt | 1 + lib/arel/crud.rb | 6 +++++- test/test_select_manager.rb | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index a5f630b0216c4..9c0d3198a18ef 100644 --- a/History.txt +++ b/History.txt @@ -9,6 +9,7 @@ * Add Arel::SelectManager#limit= * Add Arel::SelectManager#offset * Add Arel::SelectManager#offset= + * Added Arel::SelectManager#create_insert for building an insert manager. * Math operations have been added to attributes, thanks to Vladimir Meremyanin. diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index bedfb8c30cafa..43805dd46416f 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -32,11 +32,15 @@ def update values end def compile_insert values - im = InsertManager.new @engine + 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 410fe38e2a3a7..3eec73a1f0f84 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -483,6 +483,12 @@ def test_join_sources 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' From 4dade480a1d19b1343de8c68b94f74a1237c396a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 Mar 2011 21:31:45 -0700 Subject: [PATCH 0996/1492] added a factory method for creating values nodes --- lib/arel/insert_manager.rb | 6 +++++- test/test_insert_manager.rb | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index f62f36369b8ed..d6a11b7be01c7 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -27,8 +27,12 @@ def insert fields @ast.columns << column values << value end - @ast.values = Nodes::Values.new values, @ast.columns + @ast.values = create_values values, @ast.columns end end + + def create_values values, columns + Nodes::Values.new values, columns + end end end diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 0a1b1fcf5a1f4..f3900da4e0c82 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -9,6 +9,16 @@ module Arel end describe 'insert' do + it 'can create a Values node' do + table = Table.new(:users) + 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 "inserts false" do table = Table.new(:users) manager = Arel::InsertManager.new Table.engine From b707dddd89a61b86570cbe3a5e923bb8e436c38d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 Mar 2011 21:35:23 -0700 Subject: [PATCH 0997/1492] allowing sql literals for values in insert statements --- History.txt | 1 + lib/arel/visitors/to_sql.rb | 6 +++++- test/test_insert_manager.rb | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index 9c0d3198a18ef..3937f6b5b7f4b 100644 --- a/History.txt +++ b/History.txt @@ -10,6 +10,7 @@ * 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. diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 1c91d7f5e69bf..bbb2c54655f87 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -102,7 +102,11 @@ def column_cache def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| - quote(value, attr && column_for(attr)) + if Nodes::SqlLiteral === value + visit_Arel_Nodes_SqlLiteral value + else + quote(value, attr && column_for(attr)) + end }.join ', '})" end diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index f3900da4e0c82..4878a33c90a74 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -19,6 +19,15 @@ module Arel assert_equal %w{ c d }, values.right end + it 'allows sql literals' do + table = Table.new(:users) + 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 From 2b27e653f7be7649f56b834543bcaf27e2b44c74 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 23 Mar 2011 17:55:03 -0700 Subject: [PATCH 0998/1492] supporting any node in SelectManager#from --- lib/arel/select_manager.rb | 8 ++++++-- test/test_select_manager.rb | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 7f533fa91b225..34a86da68d690 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -38,6 +38,10 @@ def exists Arel::Nodes::Exists.new @ast end + def as node, expr + Arel::Nodes::As.new node, expr + end + def where_clauses if $VERBOSE warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" @@ -86,10 +90,10 @@ def from table # from the AR tests. case table - when Nodes::SqlLiteral, Arel::Table - @ctx.source.left = table when Nodes::Join @ctx.source.right << table + else + @ctx.source.left = table end self diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 3eec73a1f0f84..799c9fe453e61 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -101,6 +101,23 @@ def test_join_sources 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 manager2.grouping(manager2.ast), Arel.sql('omg') + manager1.from as + + manager1.to_sql.must_be_like %{ + SELECT lol FROM (SELECT * FROM "users" ) AS omg + } + end end describe 'having' do From fe5719fea54468f0ebcc97060df6958db17303de Mon Sep 17 00:00:00 2001 From: gmile Date: Thu, 24 Mar 2011 22:12:48 +0200 Subject: [PATCH 0999/1492] Generate more sqlish queue. Now, instead of the following SQL code: some_field IN (1, 2, NULL) Arel will generate the proper one: some_field IN (1, 2) OR IS NULL --- lib/arel/predications.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 75c4c75855743..44059a54feb27 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -41,7 +41,17 @@ def in other Nodes::Between.new(self, Nodes::And.new([other.begin, other.end])) end else - Nodes::In.new self, other + if other.include?(nil) + if other.size > 1 + set = Nodes::In.new self, other.compact + null = Nodes::Equality.new self, nil + Nodes::Or.new set, null + else + Nodes::Equality.new self, nil + end + else + Nodes::In.new self, other + end end end From f771b71d1d7cb75e4d19b85e33a85f659088f17f Mon Sep 17 00:00:00 2001 From: John Mileham Date: Fri, 25 Mar 2011 02:13:21 +0800 Subject: [PATCH 1000/1492] Make SelectManager#as act like node predications --- lib/arel/select_manager.rb | 4 ++-- test/test_select_manager.rb | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 34a86da68d690..de68b25b64193 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -38,8 +38,8 @@ def exists Arel::Nodes::Exists.new @ast end - def as node, expr - Arel::Nodes::As.new node, expr + def as other + Nodes::As.new grouping(@ast), Nodes::SqlLiteral.new(other) end def where_clauses diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 799c9fe453e61..7f276d071fdf0 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -91,6 +91,22 @@ def test_join_sources 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 + end + describe 'from' do it 'ignores strings when table of same name exists' do table = Table.new :users @@ -111,8 +127,8 @@ def test_join_sources manager2.from table manager1.project Arel.sql('lol') - as = manager2.as manager2.grouping(manager2.ast), Arel.sql('omg') - manager1.from as + as = manager2.as Arel.sql('omg') + manager1.from(as) manager1.to_sql.must_be_like %{ SELECT lol FROM (SELECT * FROM "users" ) AS omg From ff1718142c29d6373d07c108a9ea85a96d4ec62f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 30 Mar 2011 09:21:45 -0700 Subject: [PATCH 1001/1492] fixing the leg order of TableAlias nodes --- History.txt | 1 + lib/arel/nodes/table_alias.rb | 4 ++-- lib/arel/table.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/History.txt b/History.txt index 3937f6b5b7f4b..7b72342ea54c3 100644 --- a/History.txt +++ b/History.txt @@ -19,6 +19,7 @@ * 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 diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 1d3d36be0c504..6ec17885fb9fa 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -1,8 +1,8 @@ module Arel module Nodes class TableAlias < Arel::Nodes::Binary - alias :name :left - alias :relation :right + alias :name :right + alias :relation :left alias :table_alias :name def [] name diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 2aff71b220874..82d160b87eb38 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -43,7 +43,7 @@ def primary_key end def alias name = "#{self.name}_2" - Nodes::TableAlias.new(name, self).tap do |node| + Nodes::TableAlias.new(self, name).tap do |node| @aliases << node end end From e8563a6234b4f60f8d756d89b3b35026a467694e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 30 Mar 2011 09:54:23 -0700 Subject: [PATCH 1002/1492] use TableAlias nodes for aliasing subselects --- lib/arel/factory_methods.rb | 4 ++++ lib/arel/select_manager.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- test/test_select_manager.rb | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 09b82c05555e1..2ced1f8971c21 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -2,6 +2,10 @@ module Arel ### # Methods for creating various nodes module FactoryMethods + 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 diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index de68b25b64193..904a24bbb387e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -39,7 +39,7 @@ def exists end def as other - Nodes::As.new grouping(@ast), Nodes::SqlLiteral.new(other) + create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other) end def where_clauses diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index bbb2c54655f87..d1175df2a0c7a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -396,7 +396,7 @@ def quote value, column = nil end def quote_table_name name - @quoted_tables[name] ||= @connection.quote_table_name(name) + @quoted_tables[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.quote_table_name(name) end def quote_column_name name diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7f276d071fdf0..81a32e449026d 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -131,7 +131,7 @@ def test_join_sources manager1.from(as) manager1.to_sql.must_be_like %{ - SELECT lol FROM (SELECT * FROM "users" ) AS omg + SELECT lol FROM (SELECT * FROM "users" ) omg } end end From 0505df1dbfaab15acac25fad0c0d1b8510e4065a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 11 Apr 2011 09:47:47 -0700 Subject: [PATCH 1003/1492] updating the readme a little --- README.markdown | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 4952ec6191bf5..eaefe2d69456f 100644 --- a/README.markdown +++ b/README.markdown @@ -4,7 +4,14 @@ ## DESCRIPTION -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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. +Arel is a SQL AST manager for Ruby. It + +1. Simplifies the generation complex of 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 From d7ed2338b13821aba6cabf204bbd7f6b3e851644 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 11 Apr 2011 10:02:28 -0700 Subject: [PATCH 1004/1492] adding a Bin node to emit mysql BINARY keywords --- lib/arel/nodes/unary.rb | 1 + lib/arel/visitors/mysql.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 4 ++++ test/nodes/test_bin.rb | 23 +++++++++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 test/nodes/test_bin.rb diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 1b1dcb1053363..1c834913fae71 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -10,6 +10,7 @@ def initialize expr end %w{ + Bin Group Grouping Having diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 4f029245ac970..763cf11aadf76 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,6 +2,10 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql private + def visit_Arel_Nodes_Bin o + "BINARY #{visit o.expr}" + end + def visit_Arel_Nodes_Lock o visit o.expr end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d1175df2a0c7a..061e46a43632e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -133,6 +133,10 @@ def visit_Arel_Nodes_SelectCore o ].compact.join ' ' end + def visit_Arel_Nodes_Bin o + visit o.expr + end + def visit_Arel_Nodes_With o "WITH #{o.children.map { |x| visit x }.join(', ')}" end diff --git a/test/nodes/test_bin.rb b/test/nodes/test_bin.rb new file mode 100644 index 0000000000000..b06aeb0b0d9f2 --- /dev/null +++ b/test/nodes/test_bin.rb @@ -0,0 +1,23 @@ +require '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 + 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 + node = Arel::Nodes::Bin.new(Arel.sql('zomg')) + assert_equal 'BINARY zomg', viz.accept(node) + end + end + end +end From fc353baa803ba5ab2c11d71adcec358ea5c75f44 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 11 Apr 2011 15:49:27 -0700 Subject: [PATCH 1005/1492] deprecating SelectManager#wheres method --- History.txt | 3 +++ lib/arel/select_manager.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/History.txt b/History.txt index 7b72342ea54c3..6eec0b1d0db5a 100644 --- a/History.txt +++ b/History.txt @@ -49,6 +49,9 @@ * 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.7 (unreleased) * Bug Fixes diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 904a24bbb387e..048cc5133d176 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -143,6 +143,7 @@ def orders end def wheres + warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in ARel 3.0.0 with no replacement" Compatibility::Wheres.new @engine, @ctx.wheres end From 660f706491ac012cb133554cffeaa6b9ae6046e9 Mon Sep 17 00:00:00 2001 From: Arthur Taylor Date: Fri, 15 Apr 2011 16:34:18 +0200 Subject: [PATCH 1006/1492] Fixed deep copy bug in SelectManager clone --- lib/arel/select_manager.rb | 5 +++++ test/test_select_manager.rb | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 048cc5133d176..d95a259177d8c 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -9,6 +9,11 @@ def initialize engine, table = nil from table end + def initialize_copy other + super + @ctx = @ast.cores.last + end + def limit @ast.limit && @ast.limit.expr end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 81a32e449026d..955d8e8d3a667 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -187,6 +187,16 @@ def test_join_sources 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 From 3e3d4d197943d6fc30976021a0f125ba8eab1dd1 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Tue, 19 Apr 2011 00:05:19 +0800 Subject: [PATCH 1007/1492] Improve performance of grouping_any/grouping_all --- lib/arel/predications.rb | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 75c4c75855743..7e2425e45fead 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -163,21 +163,14 @@ def desc private def grouping_any method_id, others - others = others.dup - first = send method_id, others.shift - - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::Or.new(memo, send(method_id, expr)) + 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 - others = others.dup - first = send method_id, others.shift - - Nodes::Grouping.new others.inject(first) { |memo,expr| - Nodes::And.new([memo, send(method_id, expr)]) - } + Nodes::Grouping.new Nodes::And.new(others.map {|expr| send(method_id, expr)}) end end end From a318d6f5a7695bae85e7da67f423e86e164344b3 Mon Sep 17 00:00:00 2001 From: Arthur Taylor Date: Fri, 15 Apr 2011 22:34:18 +0800 Subject: [PATCH 1008/1492] Fixed deep copy bug in SelectManager clone --- lib/arel/select_manager.rb | 5 +++++ test/test_select_manager.rb | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 048cc5133d176..d95a259177d8c 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -9,6 +9,11 @@ def initialize engine, table = nil from table end + def initialize_copy other + super + @ctx = @ast.cores.last + end + def limit @ast.limit && @ast.limit.expr end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 81a32e449026d..955d8e8d3a667 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -187,6 +187,16 @@ def test_join_sources 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 From 28f8b651721148504711368b4cf12a4b526bd062 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 18 Apr 2011 09:40:38 -0700 Subject: [PATCH 1009/1492] fixing Table tests --- test/test_select_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 955d8e8d3a667..2e6844965b0a4 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -204,7 +204,7 @@ def test_join_sources 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 } + mgr.to_sql.must_be_like %{ SELECT FROM "users" foo OFFSET 10 } end end From 885a3acb1ce183189b8628f14fa834b3e1ba39ec Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 18 Apr 2011 09:40:47 -0700 Subject: [PATCH 1010/1492] adding a spec to demonstrate subqueries --- test/test_select_manager.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 2e6844965b0a4..351d8d321b85c 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -105,6 +105,18 @@ def test_join_sources 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 From cae83ce964b9919b890bb7fa6f920a536e6b5425 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 21 Apr 2011 15:28:21 -0500 Subject: [PATCH 1011/1492] adding a DISTINCT node --- lib/arel/nodes/select_core.rb | 17 +++++++++------- lib/arel/nodes/unary.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 5 +++++ test/nodes/test_select_core.rb | 37 +++++++++++++++++++++------------- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 7f577e0a0511c..bee0a5930c634 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -2,15 +2,18 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node attr_accessor :top, :projections, :wheres, :groups - attr_accessor :having, :source + attr_accessor :having, :source, :set_quantifier def initialize - @source = JoinSource.new nil - @top = nil - @projections = [] - @wheres = [] - @groups = [] - @having = nil + @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 end def from diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 1c834913fae71..e6e40e6b13400 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -23,5 +23,11 @@ def initialize expr }.each do |name| const_set(name, Class.new(Unary)) end + + class Distinct < Unary + def initialize expr = nil + super + end + end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 061e46a43632e..6aba31d94dd75 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -125,6 +125,7 @@ def visit_Arel_Nodes_SelectCore o [ "SELECT", (visit(o.top) if o.top), + (visit(o.set_quantifier) if o.set_quantifier), "#{o.projections.map { |x| visit x }.join ', '}", visit(o.source), ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?), @@ -137,6 +138,10 @@ def visit_Arel_Nodes_Bin o visit o.expr end + def visit_Arel_Nodes_Distinct o + 'DISTINCT' + end + def visit_Arel_Nodes_With o "WITH #{o.children.map { |x| visit x }.join(', ')}" end diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index 884d86e21fd15..47f85aee8ab07 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -1,22 +1,31 @@ require 'helper' -describe Arel::Nodes::SelectCore do - describe "#clone" do - it "clones froms, projections and wheres" do - core = Arel::Nodes::SelectCore.new - core.froms = %w[a b c] - core.projections = %w[d e f] - core.wheres = %w[g h i] +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 = core.clone - dolly.froms.must_equal core.froms - dolly.projections.must_equal core.projections - dolly.wheres.must_equal core.wheres + 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 + 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 + assert_match 'DISTINCT', viz.accept(core) + end end end end From 0b9af9762a5f3431f83a9bba6919fef9346e310a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 21 Apr 2011 15:46:24 -0500 Subject: [PATCH 1012/1492] adding Distinct ON node --- lib/arel/nodes.rb | 4 ++++ lib/arel/nodes/terminal.rb | 6 ++++++ lib/arel/nodes/unary.rb | 7 +------ lib/arel/visitors/postgresql.rb | 27 ++------------------------- lib/arel/visitors/to_sql.rb | 4 ++-- test/test_select_manager.rb | 2 +- test/visitors/test_oracle.rb | 4 ++-- test/visitors/test_postgres.rb | 11 +++++++++++ 8 files changed, 29 insertions(+), 36 deletions(-) create mode 100644 lib/arel/nodes/terminal.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index cf2aeb2ddc8fe..9576930a5421d 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -5,6 +5,10 @@ require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' +# terminal + +require 'arel/nodes/terminal' + # unary require 'arel/nodes/unary' require 'arel/nodes/unqualified_column' diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb new file mode 100644 index 0000000000000..c6b4f4e1e2230 --- /dev/null +++ b/lib/arel/nodes/terminal.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class Distinct < Arel::Nodes::Node + end + end +end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index e6e40e6b13400..5c4add4792b4c 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -20,14 +20,9 @@ def initialize expr On Top Lock + DistinctOn }.each do |name| const_set(name, Class.new(Unary)) end - - class Distinct < Unary - def initialize expr = nil - super - end - end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index c423dc6fc6726..377a65a21694a 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -6,25 +6,6 @@ def visit_Arel_Nodes_Lock o visit o.expr end - def visit_Arel_Nodes_SelectStatement o - if !o.orders.empty? && using_distinct_on?(o) - subquery = o.dup - subquery.orders = [] - subquery.limit = nil - subquery.offset = nil - - sql = super(subquery) - [ - "SELECT * FROM (#{sql}) AS id_list", - "ORDER BY #{aliased_orders(o.orders).join(', ')}", - (visit(o.limit) if o.limit), - (visit(o.offset) if o.offset), - ].compact.join ' ' - else - super - end - end - def visit_Arel_Nodes_Matches o "#{visit o.left} ILIKE #{visit o.right}" end @@ -33,12 +14,8 @@ def visit_Arel_Nodes_DoesNotMatch o "#{visit o.left} NOT ILIKE #{visit o.right}" end - def using_distinct_on?(o) - o.cores.any? do |core| - core.projections.any? do |projection| - /DISTINCT ON/ === projection - end - end + def visit_Arel_Nodes_DistinctOn o + "DISTINCT ON ( #{visit o.expr} )" end def aliased_orders orders diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 6aba31d94dd75..5319aeb4186d9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -126,8 +126,8 @@ def visit_Arel_Nodes_SelectCore o "SELECT", (visit(o.top) if o.top), (visit(o.set_quantifier) if o.set_quantifier), - "#{o.projections.map { |x| visit x }.join ', '}", - visit(o.source), + ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?), + (visit(o.source) if o.source), ("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), diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 351d8d321b85c..8de1520b6f721 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -54,7 +54,7 @@ def execute sql, name = nil, *args 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 + assert_equal "SELECT FROM 'foo'", manager.to_sql end describe 'backwards compatibility' do diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 87b94409e3aba..eaf68013a735a 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -101,7 +101,7 @@ module Visitors sql.must_be_like %{ SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ - FROM (SELECT ) raw_sql_ + FROM (SELECT) raw_sql_ WHERE rownum <= 20 ) WHERE raw_rnum_ > 10 @@ -126,7 +126,7 @@ module Visitors sql.must_be_like %{ SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ - FROM (SELECT ) raw_sql_ + FROM (SELECT) raw_sql_ ) WHERE raw_rnum_ > 10 } diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 74446c23ba7c7..446eae0c4adab 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -32,6 +32,17 @@ module Visitors 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 From f72989de5b3b3cfb6e6e639b57c3a3bebb2de8f2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 21 Apr 2011 15:50:19 -0500 Subject: [PATCH 1013/1492] raising not implemented exceptions for distinct on where it is not supported --- lib/arel/visitors/to_sql.rb | 4 ++++ test/visitors/test_to_sql.rb | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5319aeb4186d9..73319364d5a5b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -142,6 +142,10 @@ 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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 25ff7be3e2f26..1d5f89280b537 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -299,6 +299,17 @@ def quote value, column = nil } 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 From 30c7f0e4b365c85b7a910a0553ed936be56b9c4b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 25 Apr 2011 12:01:22 -0700 Subject: [PATCH 1014/1492] add a factory method for production LOWER functions --- lib/arel/factory_methods.rb | 6 ++++++ test/test_factory_methods.rb | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 2ced1f8971c21..9fd0878ada068 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -25,5 +25,11 @@ def create_on expr def grouping expr Nodes::Grouping.new expr end + + ### + # Create a LOWER() function + def lower column + Nodes::NamedFunction.new 'LOWER', [column] + end end end diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index 6506d3c47298a..50f77c3175609 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -22,6 +22,13 @@ def test_create_on assert_instance_of Nodes::On, on assert_equal :one, on.expr 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 From 113240e0b75e53b41e3d0837ec53ec594bcd9a28 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 25 Apr 2011 12:12:05 -0700 Subject: [PATCH 1015/1492] adding attribute#lower for lowercasing an attribute --- lib/arel/attributes/attribute.rb | 6 ++++++ test/test_attributes.rb | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 5aea87ac43e6c..240f224d8c250 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -4,6 +4,12 @@ class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications include Arel::Math + + ### + # Create a node for lowering this attribute + def lower + relation.lower self + end end class String < Attribute; end diff --git a/test/test_attributes.rb b/test/test_attributes.rb index 3654e78314400..010d708859753 100644 --- a/test/test_attributes.rb +++ b/test/test_attributes.rb @@ -2,6 +2,14 @@ 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 'for' do it 'deals with unknown column types' do column = Struct.new(:type).new :crazy From 4e8edb4aff9c271a67755d7335d45b4b8b2ad3dc Mon Sep 17 00:00:00 2001 From: Chris Berkhout Date: Wed, 27 Apr 2011 18:49:06 +0800 Subject: [PATCH 1016/1492] Fixed first example in README (it was attempting to call #to_sql on an Arel::Table). --- README.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index eaefe2d69456f..eb6426b1ecb3d 100644 --- a/README.markdown +++ b/README.markdown @@ -26,8 +26,8 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: users = Arel::Table.new(:users) - users.project(Arel.sql('*')) - users.to_sql + query = users.project(Arel.sql('*')) + query.to_sql ### More Sophisticated Queries From 85882d1b26b033afb2643865afe6410673949d32 Mon Sep 17 00:00:00 2001 From: Arthur Taylor Date: Thu, 28 Apr 2011 10:11:50 +0200 Subject: [PATCH 1017/1492] Add support for ordering on expressions Conflicts: lib/arel.rb lib/arel/attributes/attribute.rb lib/arel/nodes/infix_operation.rb lib/arel/nodes/named_function.rb Conflicts: lib/arel.rb lib/arel/attributes/attribute.rb --- lib/arel.rb | 1 + lib/arel/attributes/attribute.rb | 1 + lib/arel/expression.rb | 1 + lib/arel/nodes/sql_literal.rb | 1 + lib/arel/order_predications.rb | 13 +++++++++++++ lib/arel/predications.rb | 9 +-------- test/test_select_manager.rb | 23 +++++++++++++++++++++++ 7 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 lib/arel/order_predications.rb diff --git a/lib/arel.rb b/lib/arel.rb index de429f532e1dd..bc599514e2246 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -4,6 +4,7 @@ require 'arel/expressions' require 'arel/predications' require 'arel/math' +require 'arel/order_predications' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 240f224d8c250..b9fd8da67ebca 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -3,6 +3,7 @@ module Attributes class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications + include Arel::OrderPredications include Arel::Math ### diff --git a/lib/arel/expression.rb b/lib/arel/expression.rb index eb2c21bfd32b0..3884d6ede6ed6 100644 --- a/lib/arel/expression.rb +++ b/lib/arel/expression.rb @@ -1,4 +1,5 @@ module Arel module Expression + include Arel::OrderPredications end end diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index c76a16daf18f8..ad0bb00484b47 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -3,6 +3,7 @@ module Nodes class SqlLiteral < String include Arel::Expressions include Arel::Predications + include Arel::OrderPredications end end end diff --git a/lib/arel/order_predications.rb b/lib/arel/order_predications.rb new file mode 100644 index 0000000000000..af163c94541d3 --- /dev/null +++ b/lib/arel/order_predications.rb @@ -0,0 +1,13 @@ +module Arel + module OrderPredications + + def asc + Nodes::Ordering.new self, :asc + end + + def desc + Nodes::Ordering.new self, :desc + end + + end +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 7e2425e45fead..08cbf16d9d4ad 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,5 +1,6 @@ module Arel module Predications + def as other Nodes::As.new self, Nodes::SqlLiteral.new(other) end @@ -152,14 +153,6 @@ def lteq_all others grouping_all :lteq, others end - def asc - Nodes::Ordering.new self, :asc - end - - def desc - Nodes::Ordering.new self, :desc - end - private def grouping_any method_id, others diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 8de1520b6f721..29d317e16ab9b 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -484,6 +484,29 @@ def test_join_sources 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 From 484e2e6cfe5412252ca28ef22a58a76f4b350104 Mon Sep 17 00:00:00 2001 From: Arthur Taylor Date: Thu, 28 Apr 2011 10:13:54 +0200 Subject: [PATCH 1018/1492] Updated manifest, gemspec Conflicts: arel.gemspec --- Manifest.txt | 1 + arel.gemspec | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Manifest.txt b/Manifest.txt index f5fd7d7a803b2..1a448d7e8e2ab 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -42,6 +42,7 @@ lib/arel/nodes/update_statement.rb lib/arel/nodes/values.rb lib/arel/nodes/with.rb lib/arel/predications.rb +lib/arel/order_predications.rb lib/arel/relation.rb lib/arel/select_manager.rb lib/arel/sql/engine.rb diff --git a/arel.gemspec b/arel.gemspec index 58cb8f61fb985..8539f0ab4a277 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |s| s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] From 909538048e17cea47f5c57f36ca103865ea17353 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 28 Apr 2011 11:01:04 -0700 Subject: [PATCH 1019/1492] updating manifest and gemspec --- .gemtest | 0 Manifest.txt | 6 +++++- arel.gemspec | 33 +++++++++++++++++---------------- 3 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 .gemtest diff --git a/.gemtest b/.gemtest new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/Manifest.txt b/Manifest.txt index 1a448d7e8e2ab..0cbd39634892f 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -16,6 +16,7 @@ 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/binary.rb @@ -24,6 +25,7 @@ lib/arel/nodes/delete_statement.rb lib/arel/nodes/equality.rb lib/arel/nodes/function.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 @@ -36,13 +38,14 @@ 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/unary.rb lib/arel/nodes/unqualified_column.rb lib/arel/nodes/update_statement.rb lib/arel/nodes/values.rb lib/arel/nodes/with.rb -lib/arel/predications.rb lib/arel/order_predications.rb +lib/arel/predications.rb lib/arel/relation.rb lib/arel/select_manager.rb lib/arel/sql/engine.rb @@ -66,6 +69,7 @@ lib/arel/visitors/where_sql.rb test/attributes/test_attribute.rb test/helper.rb test/nodes/test_as.rb +test/nodes/test_bin.rb test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_equality.rb diff --git a/arel.gemspec b/arel.gemspec index 8539f0ab4a277..b2fe598b42007 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,41 +2,42 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110228092631" + s.version = "2.0.7.beta.20110428110043" 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 = %q{2011-02-28} - s.description = %q{Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 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.} + s.date = %q{2011-04-28} + s.description = %q{Arel is a SQL AST manager for Ruby. It + +1. Simplifies the generation complex of 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.} 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/in.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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.files = [".autotest", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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", ".gemtest"] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.5.2} - s.summary = %q{Arel is a Relational Algebra for Ruby} - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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.rubygems_version = %q{1.6.1} + s.summary = %q{Arel is a SQL AST manager for Ruby} + s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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 = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, [">= 2.0.0"]) - s.add_development_dependency(%q, [">= 2.1.0"]) - s.add_development_dependency(%q, [">= 1.6.0"]) + s.add_development_dependency(%q, [">= 2.0.2"]) s.add_development_dependency(%q, [">= 2.9.1"]) else - s.add_dependency(%q, [">= 2.0.0"]) - s.add_dependency(%q, [">= 2.1.0"]) - s.add_dependency(%q, [">= 1.6.0"]) + s.add_dependency(%q, [">= 2.0.2"]) s.add_dependency(%q, [">= 2.9.1"]) end else - s.add_dependency(%q, [">= 2.0.0"]) - s.add_dependency(%q, [">= 2.1.0"]) - s.add_dependency(%q, [">= 1.6.0"]) + s.add_dependency(%q, [">= 2.0.2"]) s.add_dependency(%q, [">= 2.9.1"]) end end From b4d6e5debc4f8293eb15cffed56d8a4dbf74378c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 28 Apr 2011 11:03:31 -0700 Subject: [PATCH 1020/1492] removing the aliased orders method from the pg visitor --- lib/arel/visitors/postgresql.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 377a65a21694a..bbcefe8a8de9d 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -17,19 +17,6 @@ def visit_Arel_Nodes_DoesNotMatch o def visit_Arel_Nodes_DistinctOn o "DISTINCT ON ( #{visit o.expr} )" end - - def aliased_orders orders - #orders = o.orders.map { |x| visit x }.join(', ').split(',') - list = [] - orders.each_with_index do |o,i| - list << - [ - "id_list.alias_#{i}", - (o.index(/desc/i) && 'DESC') - ].compact.join(' ') - end - list - end end end end From c2e7f36f87184f23e9d83269ff20f99a29ec75ad Mon Sep 17 00:00:00 2001 From: Shane Emmons Date: Fri, 29 Apr 2011 10:10:06 -0400 Subject: [PATCH 1021/1492] replace 'LIMIT n' with 'FETCH FIRST n ROWS ONLY' when using ibm_db --- lib/arel/visitors.rb | 2 ++ lib/arel/visitors/ibm_db.rb | 12 ++++++++++++ test/visitors/test_ibm_db.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 lib/arel/visitors/ibm_db.rb create mode 100644 test/visitors/test_ibm_db.rb diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 8410b2b912eaa..f2644d7205491 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -10,6 +10,7 @@ require 'arel/visitors/where_sql' require 'arel/visitors/order_clauses' require 'arel/visitors/dot' +require 'arel/visitors/ibm_db' module Arel module Visitors @@ -22,6 +23,7 @@ module Visitors 'oracle_enhanced' => Arel::Visitors::Oracle, 'sqlite' => Arel::Visitors::SQLite, 'sqlite3' => Arel::Visitors::SQLite, + 'ibm_db' => Arel::Visitors::IBM_DB, } ENGINE_VISITORS = Hash.new do |hash, engine| diff --git a/lib/arel/visitors/ibm_db.rb b/lib/arel/visitors/ibm_db.rb new file mode 100644 index 0000000000000..0c26a3ae9ef95 --- /dev/null +++ b/lib/arel/visitors/ibm_db.rb @@ -0,0 +1,12 @@ +module 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 diff --git a/test/visitors/test_ibm_db.rb b/test/visitors/test_ibm_db.rb new file mode 100644 index 0000000000000..cc35bb768d161 --- /dev/null +++ b/test/visitors/test_ibm_db.rb @@ -0,0 +1,27 @@ +require 'helper' + +module Arel + module Visitors + describe 'the ibm_db visitor' do + before do + @visitor = IBM_DB.new Table.engine + 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 From d09a882329e8eeebac89e907289c537077f81d44 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 29 Apr 2011 10:26:53 -0700 Subject: [PATCH 1022/1492] Revert "Merged pull request #40 from gmile/master." This reverts commit 490d6f98f8974c717ddca29df162f5f1ad48e094, reversing changes made to dd07005dceb6641214f7d1166f75acbd379fb570. --- lib/arel/predications.rb | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 36eae074a8c62..08cbf16d9d4ad 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -42,17 +42,7 @@ def in other Nodes::Between.new(self, Nodes::And.new([other.begin, other.end])) end else - if other.include?(nil) - if other.size > 1 - set = Nodes::In.new self, other.compact - null = Nodes::Equality.new self, nil - Nodes::Or.new set, null - else - Nodes::Equality.new self, nil - end - else - Nodes::In.new self, other - end + Nodes::In.new self, other end end From 7361b6cbd5e4c6f03198ed42eed4e3dd4feb149e Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 29 Apr 2011 13:36:22 -0400 Subject: [PATCH 1023/1492] Move #as to AliasPredication, stop overriding Function's #as. --- lib/arel.rb | 1 + lib/arel/alias_predication.rb | 7 +++++++ lib/arel/attributes/attribute.rb | 1 + lib/arel/nodes/function.rb | 4 ++-- lib/arel/nodes/infix_operation.rb | 1 + lib/arel/nodes/sql_literal.rb | 1 + lib/arel/predications.rb | 4 ---- test/nodes/test_named_function.rb | 17 +++++++++++++++++ test/visitors/test_depth_first.rb | 6 +++--- 9 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 lib/arel/alias_predication.rb diff --git a/lib/arel.rb b/lib/arel.rb index bc599514e2246..ff43de2067ecd 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -4,6 +4,7 @@ require 'arel/expressions' require 'arel/predications' require 'arel/math' +require 'arel/alias_predication' require 'arel/order_predications' require 'arel/table' require 'arel/attributes' diff --git a/lib/arel/alias_predication.rb b/lib/arel/alias_predication.rb new file mode 100644 index 0000000000000..3f3db7671e7c9 --- /dev/null +++ b/lib/arel/alias_predication.rb @@ -0,0 +1,7 @@ +module Arel + module AliasPredication + def as other + Nodes::As.new self, Nodes::SqlLiteral.new(other.to_s) + end + end +end \ No newline at end of file diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index b9fd8da67ebca..0906fa4f1dcd5 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -3,6 +3,7 @@ module Attributes class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications + include Arel::AliasPredication include Arel::OrderPredications include Arel::Math diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index b58eba7f380a3..3263ff9cd487f 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -6,12 +6,12 @@ class Function < Arel::Nodes::Node def initialize expr, aliaz = nil @expressions = expr - @alias = aliaz + @alias = aliaz && SqlLiteral.new(aliaz.to_s) @distinct = false end def as aliaz - self.alias = SqlLiteral.new(aliaz) + self.alias = SqlLiteral.new(aliaz.to_s) self end end diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb index 6847650fe40f1..75879ce43ff5e 100644 --- a/lib/arel/nodes/infix_operation.rb +++ b/lib/arel/nodes/infix_operation.rb @@ -4,6 +4,7 @@ module Nodes class InfixOperation < Binary include Arel::Expressions include Arel::Predications + include Arel::AliasPredication include Arel::Math attr_reader :operator diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index ad0bb00484b47..2e934b2a1bad0 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -3,6 +3,7 @@ module Nodes class SqlLiteral < String include Arel::Expressions include Arel::Predications + include Arel::AliasPredication include Arel::OrderPredications end end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 08cbf16d9d4ad..4b124ce05cde3 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,10 +1,6 @@ module Arel module Predications - def as other - Nodes::As.new self, Nodes::SqlLiteral.new(other) - end - def not_eq other Nodes::NotEqual.new self, other end diff --git a/test/nodes/test_named_function.rb b/test/nodes/test_named_function.rb index 18ecdd2851f34..3e0b2c3972edb 100644 --- a/test/nodes/test_named_function.rb +++ b/test/nodes/test_named_function.rb @@ -8,6 +8,23 @@ def test_construct 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 end end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 06e7bba9fb0fe..e078d4add58c1 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -52,14 +52,14 @@ def test_raises_with_object define_method("test_#{klass.name.gsub('::', '_')}") do func = klass.new(:a, :b) @visitor.accept func - assert_equal [:a, :b, false, func], @collector.calls + 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 + assert_equal [:a, :b, false, "c", func], @collector.calls end def test_lock @@ -71,7 +71,7 @@ def test_lock def test_count count = Nodes::Count.new :a, :b, :c @visitor.accept count - assert_equal [:a, :c, :b, count], @collector.calls + assert_equal [:a, "c", :b, count], @collector.calls end def test_inner_join From 27b09e04982abf37c98e6f7b64995c17e59ea7bb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 29 Apr 2011 11:14:56 -0700 Subject: [PATCH 1024/1492] updating manifest and spec --- Manifest.txt | 4 ++++ arel.gemspec | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 0cbd39634892f..d7a57e099529c 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,4 +1,5 @@ .autotest +.gemtest History.txt MIT-LICENSE.txt Manifest.txt @@ -6,6 +7,7 @@ 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 @@ -56,6 +58,7 @@ lib/arel/update_manager.rb lib/arel/visitors.rb lib/arel/visitors/depth_first.rb lib/arel/visitors/dot.rb +lib/arel/visitors/ibm_db.rb lib/arel/visitors/join_sql.rb lib/arel/visitors/mssql.rb lib/arel/visitors/mysql.rb @@ -95,6 +98,7 @@ test/test_table.rb test/test_update_manager.rb test/visitors/test_depth_first.rb test/visitors/test_dot.rb +test/visitors/test_ibm_db.rb test/visitors/test_join_sql.rb test/visitors/test_mssql.rb test/visitors/test_mysql.rb diff --git a/arel.gemspec b/arel.gemspec index b2fe598b42007..7a07b0a64d134 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110428110043" + s.version = "2.0.7.beta.20110429111451" 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 = %q{2011-04-28} + s.date = %q{2011-04-29} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -17,14 +17,14 @@ with it, focusing on innovative object and collection modeling as opposed to database 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", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.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/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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", ".gemtest"] + s.files = [".autotest", ".gemtest", "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/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = %q{arel} s.rubygems_version = %q{1.6.1} s.summary = %q{Arel is a SQL AST manager for Ruby} - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.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.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.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 = 3 From 1f5ed8eb20231644525bdad9a94a91e810191186 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 29 Apr 2011 14:27:45 -0400 Subject: [PATCH 1025/1492] Stop calling to_s on aliases, require them to be strings already. --- lib/arel/alias_predication.rb | 2 +- lib/arel/nodes/function.rb | 4 ++-- test/visitors/test_depth_first.rb | 6 +++--- test/visitors/test_dot.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/arel/alias_predication.rb b/lib/arel/alias_predication.rb index 3f3db7671e7c9..f42e9ee1a6afb 100644 --- a/lib/arel/alias_predication.rb +++ b/lib/arel/alias_predication.rb @@ -1,7 +1,7 @@ module Arel module AliasPredication def as other - Nodes::As.new self, Nodes::SqlLiteral.new(other.to_s) + Nodes::As.new self, Nodes::SqlLiteral.new(other) end end end \ No newline at end of file diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 3263ff9cd487f..85347fc02839f 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -6,12 +6,12 @@ class Function < Arel::Nodes::Node def initialize expr, aliaz = nil @expressions = expr - @alias = aliaz && SqlLiteral.new(aliaz.to_s) + @alias = aliaz && SqlLiteral.new(aliaz) @distinct = false end def as aliaz - self.alias = SqlLiteral.new(aliaz.to_s) + self.alias = SqlLiteral.new(aliaz) self end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index e078d4add58c1..5bbdf57697e76 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -50,14 +50,14 @@ def test_raises_with_object Arel::Nodes::Sum, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do - func = klass.new(:a, :b) + 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) + func = Arel::Nodes::NamedFunction.new(:a, :b, "c") @visitor.accept func assert_equal [:a, :b, false, "c", func], @collector.calls end @@ -69,7 +69,7 @@ def test_lock end def test_count - count = Nodes::Count.new :a, :b, :c + count = Nodes::Count.new :a, :b, "c" @visitor.accept count assert_equal [:a, "c", :b, count], @collector.calls end diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 2909d87799dbd..b311246436174 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -16,7 +16,7 @@ def setup Nodes::Avg, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do - op = klass.new(:a, :z) + op = klass.new(:a, "z") @visitor.accept op end end From a9a4a5d41b263bc19346309a48d6610037ad7438 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 30 Apr 2011 17:24:06 -0700 Subject: [PATCH 1026/1492] merging old history, adding release date --- History.txt | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 6eec0b1d0db5a..22fa15eb7ab75 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 2.1.0 (unreleased) +== 2.1.0 / 2011/04/30 * Enhancements @@ -52,7 +52,25 @@ * Arel::SelectManager#wheres is deprecated and will be removed in 3.0.0 with no replacement. -== 2.0.7 (unreleased) +== 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 From 2abc58018d2f06ae7dcf2e173d92f563bafc8359 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 30 Apr 2011 17:24:15 -0700 Subject: [PATCH 1027/1492] increasing version to 2.1.0 --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index ff43de2067ecd..7ec9068df3312 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.0.7.beta' + VERSION = '2.1.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From a6f56d8b2860a0edd846b94cfe08cdfe61e97e48 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 30 Apr 2011 17:24:37 -0700 Subject: [PATCH 1028/1492] fixing spec --- arel.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 7a07b0a64d134..7cccd00b7ac5d 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.0.7.beta.20110429111451" + s.version = "2.1.0.20110430172428" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2011-04-29} + s.date = %q{2011-04-30} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries From 13a20317ff820cc37502bdb7296e66c85b74e465 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Fri, 29 Apr 2011 15:08:27 -0400 Subject: [PATCH 1029/1492] InfixOperations are valid value expressions per SQL99 BNF, and should support ordering --- lib/arel/nodes/infix_operation.rb | 1 + test/nodes/test_infix_operation.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 test/nodes/test_infix_operation.rb diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb index 75879ce43ff5e..3911a1e05e8e1 100644 --- a/lib/arel/nodes/infix_operation.rb +++ b/lib/arel/nodes/infix_operation.rb @@ -4,6 +4,7 @@ module Nodes class InfixOperation < Binary include Arel::Expressions include Arel::Predications + include Arel::OrderPredications include Arel::AliasPredication include Arel::Math diff --git a/test/nodes/test_infix_operation.rb b/test/nodes/test_infix_operation.rb new file mode 100644 index 0000000000000..db3216eeee6ad --- /dev/null +++ b/test/nodes/test_infix_operation.rb @@ -0,0 +1,30 @@ +require '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 Ordering, ordering + assert_equal operation, ordering.expr + assert_equal :desc, ordering.direction + end + end + end +end From 73ca3932d3669f7a6f9bb722a6abaedb75f66929 Mon Sep 17 00:00:00 2001 From: Damon McCormick + Cameron Walters Date: Tue, 10 May 2011 16:41:05 -0700 Subject: [PATCH 1030/1492] Make ToSql more thread safe. Because the ToSql visitor instance is shared across all threads, there is a race condition around column types for binary nodes. It's possible, for instance, to end up with ActiveRecord converting a string value in the final SQL to an integer during heavy concurrent operations. --- lib/arel/visitors/to_sql.rb | 9 ++++----- test/visitors/test_to_sql.rb | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 73319364d5a5b..4de497a17c3d8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -8,14 +8,13 @@ def initialize engine @engine = engine @connection = nil @pool = nil - @last_column = nil @quoted_tables = {} @quoted_columns = {} end def accept object - @last_column = nil - @pool = @engine.connection_pool + Thread.current[:arel_visitors_to_sql_last_column] = nil + @pool = @engine.connection_pool @pool.with_connection do |conn| @connection = conn super @@ -356,7 +355,7 @@ def visit_Arel_Nodes_UnqualifiedColumn o end def visit_Arel_Attributes_Attribute o - @last_column = column_for o + Thread.current[:arel_visitors_to_sql_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 @@ -374,7 +373,7 @@ def literal o; o end alias :visit_Bignum :literal alias :visit_Fixnum :literal - def quoted o; quote(o, @last_column) end + def quoted o; quote(o, Thread.current[:arel_visitors_to_sql_last_column]) end alias :visit_ActiveSupport_Multibyte_Chars :quoted alias :visit_ActiveSupport_StringInquirer :quoted diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 1d5f89280b537..8084e6441cee7 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,5 +1,9 @@ require 'helper' +class Arel::Visitors::ToSql + def last_column; Thread.current[:arel_visitors_to_sql_last_column] || @last_column; end +end + module Arel module Visitors describe 'the to_sql visitor' do @@ -9,6 +13,19 @@ module Visitors @attr = @table[:id] end + it "should be thread safe around usage of last_column" do + visit_integer_column = Thread.new do + Thread.stop + @visitor.send(:visit_Arel_Attributes_Attribute, @attr) + end + + @visitor.accept(@table[:name]) + assert_equal(:string, @visitor.last_column.type) + visit_integer_column.run + visit_integer_column.join + assert_equal(:string, @visitor.last_column.type) + end + it 'should not quote sql literals' do node = @table[Arel.star] sql = @visitor.accept node From 64f2df112410705a8c9e100b5369bbdd1e248efe Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 10 May 2011 17:09:28 -0700 Subject: [PATCH 1031/1492] updating History --- History.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/History.txt b/History.txt index 22fa15eb7ab75..0c2366c366ae8 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,10 @@ +== 2.1.1 (unreleased) + +* Bug fixes + + * Fixed thread safety bug in ToSql visitor. Thanks Damon McCormick and + Cameron Walters! + == 2.1.0 / 2011/04/30 * Enhancements From 8ec1b8490a383fd0b7189ba05f550853fc37fa72 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 10 May 2011 17:12:54 -0700 Subject: [PATCH 1032/1492] refactoring to a method --- lib/arel/visitors/to_sql.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4de497a17c3d8..312f92ea2f059 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -13,7 +13,7 @@ def initialize engine end def accept object - Thread.current[:arel_visitors_to_sql_last_column] = nil + self.last_column = nil @pool = @engine.connection_pool @pool.with_connection do |conn| @connection = conn @@ -22,6 +22,14 @@ def accept object end private + def last_column= col + Thread.current[:arel_visitors_to_sql_last_column] = col + end + + def last_column + Thread.current[:arel_visitors_to_sql_last_column] + end + def visit_Arel_Nodes_DeleteStatement o [ "DELETE FROM #{visit o.relation}", @@ -355,7 +363,7 @@ def visit_Arel_Nodes_UnqualifiedColumn o end def visit_Arel_Attributes_Attribute o - Thread.current[:arel_visitors_to_sql_last_column] = column_for 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 @@ -373,7 +381,7 @@ def literal o; o end alias :visit_Bignum :literal alias :visit_Fixnum :literal - def quoted o; quote(o, Thread.current[:arel_visitors_to_sql_last_column]) end + def quoted o; quote(o, last_column) end alias :visit_ActiveSupport_Multibyte_Chars :quoted alias :visit_ActiveSupport_StringInquirer :quoted From 85da41912e35eb4c00e10315ecae5edda2c58d4b Mon Sep 17 00:00:00 2001 From: Martin Little Date: Mon, 16 May 2011 08:56:54 -0400 Subject: [PATCH 1033/1492] Added initial informix visitor support --- lib/arel/visitors/informix.rb | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 lib/arel/visitors/informix.rb diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb new file mode 100644 index 0000000000000..cd2ec5d265312 --- /dev/null +++ b/lib/arel/visitors/informix.rb @@ -0,0 +1,40 @@ +module Arel + module Visitors + class Informix < Arel::Visitors::ToSql + @skip = nil + @first = nil + private + def visit_Arel_Nodes_SelectStatement o +# @skip = o.offset if o.offset +# @first = o.limit if o.limit + [ + "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 + # s,f = @skip,@first + # @skip, @first = nil,nil + [ + "#{o.projections.map { |x| visit x }.join ', '}", + ("FROM #{visit o.froms}" if o.froms), + ("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 + #(visit(o.offset) if o.offset) + 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 + From ca6e7f71da7ed23aa723adb6611bf1fbb06e2137 Mon Sep 17 00:00:00 2001 From: Martin Little Date: Mon, 16 May 2011 09:24:04 -0400 Subject: [PATCH 1034/1492] Added a basic test for the informix visitor --- lib/arel/visitors.rb | 2 ++ test/visitors/test_informix.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 test/visitors/test_informix.rb diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index f2644d7205491..8276eace2bb35 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -11,6 +11,7 @@ require 'arel/visitors/order_clauses' require 'arel/visitors/dot' require 'arel/visitors/ibm_db' +require 'arel/visitors/informix' module Arel module Visitors @@ -24,6 +25,7 @@ module Visitors '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| diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb new file mode 100644 index 0000000000000..db5e52b8a4e45 --- /dev/null +++ b/test/visitors/test_informix.rb @@ -0,0 +1,34 @@ +require 'helper' + +module Arel + module Visitors + describe 'the informix visitor' do + before do + @visitor = Informix.new Table.engine + 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 + + end + end +end From 157969a565606277575bd436f64434a2a5b1d4a2 Mon Sep 17 00:00:00 2001 From: Martin Little Date: Mon, 16 May 2011 09:30:40 -0400 Subject: [PATCH 1035/1492] Removed some old dev code --- lib/arel/visitors/informix.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index cd2ec5d265312..25eef1e6de4d7 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -1,12 +1,8 @@ module Arel module Visitors class Informix < Arel::Visitors::ToSql - @skip = nil - @first = nil private def visit_Arel_Nodes_SelectStatement o -# @skip = o.offset if o.offset -# @first = o.limit if o.limit [ "SELECT", (visit(o.offset) if o.offset), @@ -17,8 +13,6 @@ def visit_Arel_Nodes_SelectStatement o ].compact.join ' ' end def visit_Arel_Nodes_SelectCore o - # s,f = @skip,@first - # @skip, @first = nil,nil [ "#{o.projections.map { |x| visit x }.join ', '}", ("FROM #{visit o.froms}" if o.froms), @@ -27,7 +21,6 @@ def visit_Arel_Nodes_SelectCore o (visit(o.having) if o.having), ].compact.join ' ' end - #(visit(o.offset) if o.offset) def visit_Arel_Nodes_Offset o "SKIP #{visit o.expr}" end From 0d39cbe523206c90f4a3eaf9279f882510f375c5 Mon Sep 17 00:00:00 2001 From: Martin Little Date: Mon, 16 May 2011 09:49:37 -0400 Subject: [PATCH 1036/1492] Added an additional test since skip/limit can not be used in reverse order --- test/visitors/test_informix.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index db5e52b8a4e45..a8a52a0160428 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -29,6 +29,14 @@ module Visitors 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 + end end end From 0eeb2da5c4174ce023d248ef426840d76d5ce765 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 17 May 2011 17:48:49 -0400 Subject: [PATCH 1037/1492] no longer use this instance variable --- test/visitors/test_to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 8084e6441cee7..ba3c5c994ab38 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,7 +1,7 @@ require 'helper' class Arel::Visitors::ToSql - def last_column; Thread.current[:arel_visitors_to_sql_last_column] || @last_column; end + def last_column; Thread.current[:arel_visitors_to_sql_last_column]; end end module Arel From bc0510c0027c28a2b45c8c51f75edaf40d6f4536 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 17 May 2011 18:01:35 -0400 Subject: [PATCH 1038/1492] do not cache sql literal values --- lib/arel/visitors/to_sql.rb | 3 ++- test/test_select_manager.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 312f92ea2f059..29e965bef80d5 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -416,7 +416,8 @@ def quote value, column = nil end def quote_table_name name - @quoted_tables[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 29d317e16ab9b..e948aec1311d3 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -216,7 +216,7 @@ def test_join_sources 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 } + mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 } end end From 12e330fc566489d0a40b360e179037370d10403b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 17 May 2011 18:02:11 -0400 Subject: [PATCH 1039/1492] make sure thread runs --- test/visitors/test_to_sql.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index ba3c5c994ab38..d046e543e1ae5 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -19,6 +19,7 @@ module Visitors @visitor.send(:visit_Arel_Attributes_Attribute, @attr) end + sleep 0.2 @visitor.accept(@table[:name]) assert_equal(:string, @visitor.last_column.type) visit_integer_column.run From 2f2b3853f2f42c044ee4a3a8dec42ecbf2aeae4f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 17 May 2011 18:03:48 -0400 Subject: [PATCH 1040/1492] zomg prep release --- History.txt | 2 +- lib/arel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 0c2366c366ae8..b5c37193eda82 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 2.1.1 (unreleased) +== 2.1.1 / 2011/05/14 * Bug fixes diff --git a/lib/arel.rb b/lib/arel.rb index 7ec9068df3312..6ef2f52a2112f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.1.0' + VERSION = '2.1.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 58c3d1d56cf38aebf09e64803441b606680b680a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 18 May 2011 14:38:12 -0400 Subject: [PATCH 1041/1492] updating spec --- arel.gemspec | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 7cccd00b7ac5d..85dc329eda37b 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.0.20110430172428" + s.version = "2.1.1.20110518143805" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2011-04-30} + s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] + s.date = %q{2011-05-18} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -15,16 +15,16 @@ Gem::Specification.new do |s| 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.} - 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", "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/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.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", "test/attributes/test_attribute.rb", "test/helper.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.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.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] + s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] + s.files = [%q{.autotest}, %q{.gemtest}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}, %q{test/nodes/test_infix_operation.rb}] s.homepage = %q{http://github.com/rails/arel} - s.rdoc_options = ["--main", "README.markdown"] - s.require_paths = ["lib"] + s.rdoc_options = [%q{--main}, %q{README.markdown}] + s.require_paths = [%q{lib}] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.6.1} + s.rubygems_version = %q{1.8.2} s.summary = %q{Arel is a SQL AST manager for Ruby} - s.test_files = ["test/attributes/test_attribute.rb", "test/nodes/test_as.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_depth_first.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.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.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] if s.respond_to? :specification_version then s.specification_version = 3 From 00d1482fefa1cf9c3753b58f4fe9b580c52ae935 Mon Sep 17 00:00:00 2001 From: Samuel Kadolph Date: Fri, 27 May 2011 17:21:40 -0400 Subject: [PATCH 1042/1492] Include Arel::Predicates to Arel::Nodes::Function so you can do table[:id].count.eq(2) --- lib/arel/nodes/function.rb | 1 + lib/arel/nodes/named_function.rb | 2 -- test/nodes/test_count.rb | 9 +++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 85347fc02839f..b6f6644678562 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -2,6 +2,7 @@ module Arel module Nodes class Function < Arel::Nodes::Node include Arel::Expression + include Arel::Predications attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil diff --git a/lib/arel/nodes/named_function.rb b/lib/arel/nodes/named_function.rb index 5fca33e3231aa..56669bf85853a 100644 --- a/lib/arel/nodes/named_function.rb +++ b/lib/arel/nodes/named_function.rb @@ -3,8 +3,6 @@ module Nodes class NamedFunction < Arel::Nodes::Function attr_accessor :name - include Arel::Predications - def initialize name, expr, aliaz = nil super(expr, aliaz) @name = name diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index afa423e8f5357..be53b8685586a 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -15,4 +15,13 @@ } 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 end From be48ed3071fd6524d0145c4ad3faeb4aafe3eda3 Mon Sep 17 00:00:00 2001 From: arkadiy kraportov Date: Thu, 9 Jun 2011 18:24:54 +0900 Subject: [PATCH 1043/1492] LIMIT and OFFSET support for MS SQL --- lib/arel/visitors/mssql.rb | 78 ++++++++++++++++++++++++++++++++----- test/visitors/test_mssql.rb | 63 ++++++++++++++++++++++++++---- 2 files changed, 124 insertions(+), 17 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index ea7ab6394c3f2..713ad0f0f8357 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -3,19 +3,79 @@ module Visitors class MSSQL < Arel::Visitors::ToSql private - def build_subselect key, o - stmt = super - core = stmt.cores.first - core.top = Nodes::Top.new(o.limit.expr) if o.limit - stmt + # `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_Limit o - "" + 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 + guard_against_select_constant! x + 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 visit_Arel_Nodes_Top o - "TOP #{visit o.expr}" + 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 + + def guard_against_select_constant! x + # guard against .select(1) (i.e. validate_uniqueness uses it to minimize qry result set) + # todo it won't work for .select('a'), which is probably ok. 'coz of workaround: .select("'a' as a") + x.projections.map! do |p| + p.kind_of?(Fixnum) ? Nodes::SqlLiteral.new("#{p} as _fld_#{p}") : p + end + 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 diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index ccaea395fe127..4e8d5c4bceb58 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -5,21 +5,68 @@ module Visitors describe 'the mssql visitor' do before do @visitor = MSSQL.new Table.engine + @table = Arel::Table.new "users" end - it 'uses TOP to limit results' do + it 'should not modify query if no offset or limit' do stmt = Nodes::SelectStatement.new - stmt.cores.last.top = Nodes::Top.new(1) sql = @visitor.accept(stmt) - sql.must_be_like "SELECT TOP 1" + sql.must_be_like "SELECT" end - it 'uses TOP in updates with a limit' do - stmt = Nodes::UpdateStatement.new - stmt.limit = Nodes::Limit.new(1) - stmt.key = 'id' + 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 guard FixNums' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(10) + stmt.cores.first.projections << 1 + sql = @visitor.accept(stmt) + sql.must_be_like "SELECT _t.* FROM (SELECT 1 as _fld_1, ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10" + 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 "UPDATE NULL WHERE 'id' IN (SELECT TOP 1 'id' )" + 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 From 3da816a77318d28617d0e12739d29d76e372a4f9 Mon Sep 17 00:00:00 2001 From: arkadiy kraportov Date: Fri, 10 Jun 2011 12:47:55 +0900 Subject: [PATCH 1044/1492] remove unnecessary guarding agains literal --- lib/arel/visitors/mssql.rb | 10 ---------- test/visitors/test_mssql.rb | 8 -------- 2 files changed, 18 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 713ad0f0f8357..23dc06a936998 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -24,7 +24,6 @@ def visit_Arel_Nodes_SelectStatement o x.projections = [row_num_literal(core_order_by)] is_select_count = true else - guard_against_select_constant! x x.projections << row_num_literal(core_order_by) end @@ -63,21 +62,12 @@ def select_count? x x.projections.length == 1 && Arel::Nodes::Count === x.projections.first end - def guard_against_select_constant! x - # guard against .select(1) (i.e. validate_uniqueness uses it to minimize qry result set) - # todo it won't work for .select('a'), which is probably ok. 'coz of workaround: .select("'a' as a") - x.projections.map! do |p| - p.kind_of?(Fixnum) ? Nodes::SqlLiteral.new("#{p} as _fld_#{p}") : p - end - 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 diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index 4e8d5c4bceb58..8b2b756900685 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -53,14 +53,6 @@ module Visitors 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 guard FixNums' do - stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(10) - stmt.cores.first.projections << 1 - sql = @visitor.accept(stmt) - sql.must_be_like "SELECT _t.* FROM (SELECT 1 as _fld_1, ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10" - end - it 'should generate subquery for .count' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) From ba3578a22f824da3478b6dceb100deb9f41a56e9 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Tue, 14 Jun 2011 17:43:22 -0400 Subject: [PATCH 1045/1492] Break Ordering into Ascending/Descending nodes, allow reversal --- lib/arel/nodes.rb | 3 ++- lib/arel/nodes/ascending.rb | 23 ++++++++++++++++++++ lib/arel/nodes/descending.rb | 23 ++++++++++++++++++++ lib/arel/nodes/ordering.rb | 16 +------------- lib/arel/nodes/unary.rb | 1 + lib/arel/order_predications.rb | 4 ++-- lib/arel/visitors/depth_first.rb | 2 +- lib/arel/visitors/dot.rb | 1 - lib/arel/visitors/to_sql.rb | 8 +++++-- test/attributes/test_attribute.rb | 8 +++---- test/nodes/test_ascending.rb | 34 ++++++++++++++++++++++++++++++ test/nodes/test_descending.rb | 34 ++++++++++++++++++++++++++++++ test/nodes/test_infix_operation.rb | 4 ++-- test/visitors/test_depth_first.rb | 2 +- test/visitors/test_dot.rb | 2 +- 15 files changed, 135 insertions(+), 30 deletions(-) create mode 100644 lib/arel/nodes/ascending.rb create mode 100644 lib/arel/nodes/descending.rb create mode 100644 test/nodes/test_ascending.rb create mode 100644 test/nodes/test_descending.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 9576930a5421d..9edf3a9a95084 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -11,6 +11,8 @@ # unary require 'arel/nodes/unary' +require 'arel/nodes/ascending' +require 'arel/nodes/descending' require 'arel/nodes/unqualified_column' require 'arel/nodes/with' @@ -19,7 +21,6 @@ require 'arel/nodes/equality' require 'arel/nodes/in' # Why is this subclassed from equality? require 'arel/nodes/join_source' -require 'arel/nodes/ordering' require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' require 'arel/nodes/infix_operation' diff --git a/lib/arel/nodes/ascending.rb b/lib/arel/nodes/ascending.rb new file mode 100644 index 0000000000000..bca00a833911f --- /dev/null +++ b/lib/arel/nodes/ascending.rb @@ -0,0 +1,23 @@ +module 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 diff --git a/lib/arel/nodes/descending.rb b/lib/arel/nodes/descending.rb new file mode 100644 index 0000000000000..d886bdcb5f759 --- /dev/null +++ b/lib/arel/nodes/descending.rb @@ -0,0 +1,23 @@ +module 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 diff --git a/lib/arel/nodes/ordering.rb b/lib/arel/nodes/ordering.rb index 0a3621cf5434c..efb4d18ae445e 100644 --- a/lib/arel/nodes/ordering.rb +++ b/lib/arel/nodes/ordering.rb @@ -1,20 +1,6 @@ module Arel module Nodes - class Ordering < Arel::Nodes::Binary - alias :expr :left - alias :direction :right - - def initialize expr, direction = :asc - super - end - - def ascending? - direction == :asc - end - - def descending? - direction == :desc - end + class Ordering < Unary end end end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 5c4add4792b4c..4688fff62311c 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -18,6 +18,7 @@ def initialize expr Not Offset On + Ordering Top Lock DistinctOn diff --git a/lib/arel/order_predications.rb b/lib/arel/order_predications.rb index af163c94541d3..153fcffb41d20 100644 --- a/lib/arel/order_predications.rb +++ b/lib/arel/order_predications.rb @@ -2,11 +2,11 @@ module Arel module OrderPredications def asc - Nodes::Ordering.new self, :asc + Nodes::Ascending.new self end def desc - Nodes::Ordering.new self, :desc + Nodes::Descending.new self end end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 914b2d1999e82..6f9385de1bc7b 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -22,6 +22,7 @@ def unary o 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_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary @@ -75,7 +76,6 @@ def binary o alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary - alias :visit_Arel_Nodes_Ordering :binary alias :visit_Arel_Nodes_OuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 92d05c7b675d1..8303279211399 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -30,7 +30,6 @@ def accept object private def visit_Arel_Nodes_Ordering o visit_edge o, "expr" - visit_edge o, "direction" end def visit_Arel_Nodes_TableAlias o diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 29e965bef80d5..933edc15f26ba 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -203,8 +203,12 @@ def visit_Arel_Nodes_Grouping o "(#{visit o.expr})" end - def visit_Arel_Nodes_Ordering o - "#{visit o.expr} #{o.descending? ? 'DESC' : 'ASC'}" + 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 diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 352774071a424..901850ff4bd61 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -619,9 +619,9 @@ module Attributes end describe '#asc' do - it 'should create an Ordering node' do + it 'should create an Ascending node' do relation = Table.new(:users) - relation[:id].asc.must_be_kind_of Nodes::Ordering + relation[:id].asc.must_be_kind_of Nodes::Ascending end it 'should generate ASC in sql' do @@ -635,9 +635,9 @@ module Attributes end describe '#desc' do - it 'should create an Ordering node' do + it 'should create a Descending node' do relation = Table.new(:users) - relation[:id].desc.must_be_kind_of Nodes::Ordering + relation[:id].desc.must_be_kind_of Nodes::Descending end it 'should generate DESC in sql' do diff --git a/test/nodes/test_ascending.rb b/test/nodes/test_ascending.rb new file mode 100644 index 0000000000000..0e2c4810c643b --- /dev/null +++ b/test/nodes/test_ascending.rb @@ -0,0 +1,34 @@ +require '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 + end + end +end diff --git a/test/nodes/test_descending.rb b/test/nodes/test_descending.rb new file mode 100644 index 0000000000000..424f8298cd494 --- /dev/null +++ b/test/nodes/test_descending.rb @@ -0,0 +1,34 @@ +require '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 + end + end +end diff --git a/test/nodes/test_infix_operation.rb b/test/nodes/test_infix_operation.rb index db3216eeee6ad..3d2eb0d9c6321 100644 --- a/test/nodes/test_infix_operation.rb +++ b/test/nodes/test_infix_operation.rb @@ -21,9 +21,9 @@ def test_operation_alias def test_opertaion_ordering operation = InfixOperation.new :+, 1, 2 ordering = operation.desc - assert_kind_of Ordering, ordering + assert_kind_of Descending, ordering assert_equal operation, ordering.expr - assert_equal :desc, ordering.direction + assert ordering.descending? end end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 5bbdf57697e76..e62ce5266fb5b 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -28,6 +28,7 @@ def test_raises_with_object Arel::Nodes::On, Arel::Nodes::Grouping, Arel::Nodes::Offset, + Arel::Nodes::Ordering, Arel::Nodes::Having, Arel::Nodes::StringJoin, Arel::Nodes::UnqualifiedColumn, @@ -104,7 +105,6 @@ def test_outer_join Arel::Nodes::Values, Arel::Nodes::As, Arel::Nodes::DeleteStatement, - Arel::Nodes::Ordering, Arel::Nodes::JoinSource, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index b311246436174..362e39339c2b1 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -33,6 +33,7 @@ def test_named_function Arel::Nodes::On, Arel::Nodes::Grouping, Arel::Nodes::Offset, + Arel::Nodes::Ordering, Arel::Nodes::Having, Arel::Nodes::UnqualifiedColumn, Arel::Nodes::Top, @@ -63,7 +64,6 @@ def test_named_function Arel::Nodes::Values, Arel::Nodes::As, Arel::Nodes::DeleteStatement, - Arel::Nodes::Ordering, Arel::Nodes::JoinSource, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do From 0c8723af70b8518c1a9ae43e650afb433e078470 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 09:11:47 -0700 Subject: [PATCH 1046/1492] visitors can define their own cache strategy for dispatch. fixes #57 --- History.txt | 7 +++++++ lib/arel/visitors/visitor.rb | 12 ++++++++---- test/visitors/test_to_sql.rb | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/History.txt b/History.txt index b5c37193eda82..4158f5e968863 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,10 @@ +== 2.1.2 / Unreleased + +* Bug Fixes + + * Visitors can define their own cache strategey so caches are not shared. + Fixes #57 + == 2.1.1 / 2011/05/14 * Bug fixes diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index c9cdf34adb615..8f9dd929e1b28 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -11,15 +11,19 @@ def accept object hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" end + def dispatch + DISPATCH + end + def visit object - send DISPATCH[object.class], object + send dispatch[object.class], object rescue NoMethodError => e - raise e if respond_to?(DISPATCH[object.class], true) + raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| - respond_to?(DISPATCH[klass], true) + respond_to?(dispatch[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass - DISPATCH[object.class] = DISPATCH[superklass] + dispatch[object.class] = dispatch[superklass] retry end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index d046e543e1ae5..b52722ddd63c6 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -13,6 +13,22 @@ module Visitors @attr = @table[:id] 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 be thread safe around usage of last_column" do visit_integer_column = Thread.new do Thread.stop From 8b5d227d3cf4d3829cc21ba07be1c748222e0fd0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 09:31:01 -0700 Subject: [PATCH 1047/1492] updating history file --- History.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/History.txt b/History.txt index 4158f5e968863..70d301a2e4703 100644 --- a/History.txt +++ b/History.txt @@ -4,6 +4,9 @@ * 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 From 86361f64220518ec1e2782617c3d9fa3d94bc0a3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 09:43:10 -0700 Subject: [PATCH 1048/1492] version bump --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 6ef2f52a2112f..4479d0aa0762a 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.1.1' + VERSION = '2.1.2' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 4168cb9ee68a2fa1390be4d0da00fcc49b56b18f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 09:44:09 -0700 Subject: [PATCH 1049/1492] bumping spec --- arel.gemspec | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 85dc329eda37b..cb754b46c9dfa 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.1.20110518143805" + s.version = "2.1.2.20110627094400" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] - s.date = %q{2011-05-18} + s.date = %q{2011-06-27} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -17,27 +17,27 @@ with it, focusing on innovative object and collection modeling as opposed to database compatibility and query generation.} s.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] - s.files = [%q{.autotest}, %q{.gemtest}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}, %q{test/nodes/test_infix_operation.rb}] + s.files = [%q{.autotest}, %q{.gemtest}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/visitors/test_informix.rb}] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = [%q{--main}, %q{README.markdown}] s.require_paths = [%q{lib}] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.8.2} + s.rubygems_version = %q{1.8.5} s.summary = %q{Arel is a SQL AST manager for Ruby} - s.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] + s.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] if s.respond_to? :specification_version then s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, [">= 2.0.2"]) - s.add_development_dependency(%q, [">= 2.9.1"]) + s.add_development_dependency(%q, [">= 2.2.2"]) + s.add_development_dependency(%q, [">= 2.9.4"]) else - s.add_dependency(%q, [">= 2.0.2"]) - s.add_dependency(%q, [">= 2.9.1"]) + s.add_dependency(%q, [">= 2.2.2"]) + s.add_dependency(%q, [">= 2.9.4"]) end else - s.add_dependency(%q, [">= 2.0.2"]) - s.add_dependency(%q, [">= 2.9.1"]) + s.add_dependency(%q, [">= 2.2.2"]) + s.add_dependency(%q, [">= 2.9.4"]) end end From 5750fa8a3b4b21d246f42400573b37d6de849a6a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 09:58:30 -0700 Subject: [PATCH 1050/1492] fixing manifest --- Manifest.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Manifest.txt b/Manifest.txt index d7a57e099529c..16333b7cf2fa8 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -21,9 +21,11 @@ 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/function.rb lib/arel/nodes/in.rb @@ -59,6 +61,7 @@ lib/arel/visitors.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 @@ -72,10 +75,13 @@ lib/arel/visitors/where_sql.rb test/attributes/test_attribute.rb test/helper.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_equality.rb +test/nodes/test_infix_operation.rb test/nodes/test_insert_statement.rb test/nodes/test_named_function.rb test/nodes/test_node.rb @@ -99,6 +105,7 @@ test/test_update_manager.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 From 2dd4486575b95b26fbc825cf602b38b1fe538ea6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 09:59:46 -0700 Subject: [PATCH 1051/1492] fixing broken gem build --- History.txt | 8 +++++++- lib/arel.rb | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 70d301a2e4703..e9eed4e50ade1 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,10 @@ -== 2.1.2 / Unreleased +== 2.1.3 / 2011-06-27 + +* Bug Fixues + + * Fixed broken gem build. + +== 2.1.2 / 2011-06-27 * Bug Fixes diff --git a/lib/arel.rb b/lib/arel.rb index 4479d0aa0762a..58fa2ea77f7d4 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.1.2' + VERSION = '2.1.3' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From da99e806703ff1e6b004dd0371b323df21d598e7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 27 Jun 2011 10:00:01 -0700 Subject: [PATCH 1052/1492] generating a spec --- arel.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index cb754b46c9dfa..174992ee0e7f2 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.2.20110627094400" + s.version = "2.1.3.20110627095956" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] @@ -17,7 +17,7 @@ with it, focusing on innovative object and collection modeling as opposed to database compatibility and query generation.} s.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] - s.files = [%q{.autotest}, %q{.gemtest}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/visitors/test_informix.rb}] + s.files = [%q{.autotest}, %q{.gemtest}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/ascending.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/descending.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/informix.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = [%q{--main}, %q{README.markdown}] s.require_paths = [%q{lib}] From 7832cd3bb3c6cfd76fdb63ca75995f2e6c87757c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 29 Jun 2011 13:45:26 -0700 Subject: [PATCH 1053/1492] fix depth first visitor to support ascending and descending nodes --- History.txt | 6 ++++++ lib/arel/visitors/depth_first.rb | 2 ++ test/test_select_manager.rb | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/History.txt b/History.txt index e9eed4e50ade1..ea27ae6d6d149 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +== 2.1.4 / unreleased + +* Bug Fixes + + * Fix depth-first traversal to understand ascending / descending nodes. + == 2.1.3 / 2011-06-27 * Bug Fixues diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 6f9385de1bc7b..43d186cc1a833 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -23,6 +23,8 @@ def unary o 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index e948aec1311d3..119ad3ec4f623 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -412,6 +412,15 @@ def test_join_sources 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 From 2567b72f9582c14a591156653e2b656d48200b11 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 20 Jul 2011 14:00:06 -0700 Subject: [PATCH 1054/1492] supressing nested parenthesis in multiple unions on mysql. thanks jhtwong. fixes #58 --- History.txt | 1 + lib/arel/visitors/mysql.rb | 22 ++++++++++++++++++++++ test/visitors/test_mysql.rb | 10 ++++++++++ 3 files changed, 33 insertions(+) diff --git a/History.txt b/History.txt index ea27ae6d6d149..8b6941314006d 100644 --- a/History.txt +++ b/History.txt @@ -3,6 +3,7 @@ * 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 diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 763cf11aadf76..70166a15c5978 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,6 +2,28 @@ module 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 diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 3c15c218b21cf..8d220ac04b471 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -7,6 +7,16 @@ module Visitors @visitor = MySQL.new Table.engine 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 From ecd670100e21015746852a3781a75dd57b60eae4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 20 Jul 2011 14:13:46 -0700 Subject: [PATCH 1055/1492] adding Gemfile --- Gemfile | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Gemfile diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000000..4f87fc9ecbc9b --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +gem 'hoe', '>= 2.1.0' +gem 'minitest' From c750aef10c528db308ab8edcfaaca8c868231f7d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 20 Jul 2011 14:14:38 -0700 Subject: [PATCH 1056/1492] oops, forgot source --- Gemfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gemfile b/Gemfile index 4f87fc9ecbc9b..517921797ae6e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,2 +1,4 @@ +source "http://rubygems.org" + gem 'hoe', '>= 2.1.0' gem 'minitest' From 7d5ef0b0c6a37dd068f68ee1c5aca5aefe395ce7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 25 Jul 2011 15:59:05 -0700 Subject: [PATCH 1057/1492] prepping for 2.1.4 release --- History.txt | 2 +- arel.gemspec | 35 ++++++++++++++++++----------------- lib/arel.rb | 2 +- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/History.txt b/History.txt index 8b6941314006d..a6a1784a03488 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 2.1.4 / unreleased +== 2.1.4 / 2011-07-25 * Bug Fixes diff --git a/arel.gemspec b/arel.gemspec index 174992ee0e7f2..84addb34045fd 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.3.20110627095956" + s.version = "2.1.4.20110725155854" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] - s.date = %q{2011-06-27} + s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] + s.date = %q{2011-07-25} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -15,29 +15,30 @@ Gem::Specification.new do |s| 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.} - s.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] - s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] - s.files = [%q{.autotest}, %q{.gemtest}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/ascending.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/descending.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/informix.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] + 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", "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/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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 = %q{http://github.com/rails/arel} - s.rdoc_options = [%q{--main}, %q{README.markdown}] - s.require_paths = [%q{lib}] + s.rdoc_options = ["--main", "README.markdown"] + s.require_paths = ["lib"] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.8.5} + s.rubygems_version = %q{1.3.6} s.summary = %q{Arel is a SQL AST manager for Ruby} - s.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] + s.test_files = ["test/attributes/test_attribute.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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 + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 3 - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, [">= 2.2.2"]) - s.add_development_dependency(%q, [">= 2.9.4"]) + if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["~> 2.3"]) + s.add_development_dependency(%q, ["~> 2.9"]) else - s.add_dependency(%q, [">= 2.2.2"]) - s.add_dependency(%q, [">= 2.9.4"]) + s.add_dependency(%q, ["~> 2.3"]) + s.add_dependency(%q, ["~> 2.9"]) end else - s.add_dependency(%q, [">= 2.2.2"]) - s.add_dependency(%q, [">= 2.9.4"]) + s.add_dependency(%q, ["~> 2.3"]) + s.add_dependency(%q, ["~> 2.9"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index 58fa2ea77f7d4..a76227577cc33 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.1.3' + VERSION = '2.1.4' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 75a78b3496d4d7dbba3675b2d66250408b4efcf5 Mon Sep 17 00:00:00 2001 From: thedarkone Date: Tue, 26 Jul 2011 12:35:41 +0200 Subject: [PATCH 1058/1492] Oracle does not allow ORDER BY/LIMIT in UPDATE queries. --- lib/arel/visitors/oracle.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 3beea287a6455..375f7dbfe9570 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -65,6 +65,18 @@ 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 From 11f929b5c485adab60ea2d8b515ef2abcf5400f4 Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Tue, 31 May 2011 00:40:11 -0300 Subject: [PATCH 1059/1492] Add nodes for boolean constants This is useful for dynamically created predicates e.g: expr1 = table.create_false expr2 = table.create_false expr1 = create_a_predicate() if some_condition expr2 = create_another_predicate() if some_other_condition table.where(expr1.and(expr2)) --- lib/arel/factory_methods.rb | 8 ++++++++ lib/arel/nodes.rb | 2 ++ lib/arel/nodes/false.rb | 17 +++++++++++++++++ lib/arel/nodes/true.rb | 17 +++++++++++++++++ lib/arel/predications.rb | 1 - lib/arel/visitors/to_sql.rb | 8 ++++++++ test/test_factory_methods.rb | 10 ++++++++++ test/visitors/test_to_sql.rb | 16 ++++++++++++++++ 8 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/false.rb create mode 100644 lib/arel/nodes/true.rb diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 9fd0878ada068..3b16feae1074e 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -2,6 +2,14 @@ module 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 diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 9edf3a9a95084..e37b09a8acd1d 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -8,6 +8,8 @@ # terminal require 'arel/nodes/terminal' +require 'arel/nodes/true' +require 'arel/nodes/false' # unary require 'arel/nodes/unary' diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb new file mode 100644 index 0000000000000..419607094639c --- /dev/null +++ b/lib/arel/nodes/false.rb @@ -0,0 +1,17 @@ +module Arel + module Nodes + class False < Arel::Nodes::Node + def not + True.new + end + + def or right + right + end + + def and right + self + end + end + end +end diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb new file mode 100644 index 0000000000000..82f20837f8557 --- /dev/null +++ b/lib/arel/nodes/true.rb @@ -0,0 +1,17 @@ +module Arel + module Nodes + class True < Arel::Nodes::Node + def not + False.new + end + + def or right + self + end + + def and right + right + end + end + end +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 4b124ce05cde3..e3f72d46a27fe 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,6 +1,5 @@ module Arel module Predications - def not_eq other Nodes::NotEqual.new self, other end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 933edc15f26ba..8aec4cb1475da 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -90,6 +90,14 @@ def visit_Arel_Nodes_Exists o 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 @pool.table_exists? name end diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index 50f77c3175609..21671cd239524 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -23,6 +23,16 @@ def test_create_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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b52722ddd63c6..3b58c71cd8074 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -325,6 +325,22 @@ def quote value, column = nil 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' From 3712071148485a8a6f2e28944f1d4932ce72b4bd Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Wed, 3 Aug 2011 20:58:29 -0300 Subject: [PATCH 1060/1492] Remove short circuit evaluation and leave AST as it is --- lib/arel/nodes/false.rb | 11 ----------- lib/arel/nodes/true.rb | 11 ----------- 2 files changed, 22 deletions(-) diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb index 419607094639c..611e19633bb5d 100644 --- a/lib/arel/nodes/false.rb +++ b/lib/arel/nodes/false.rb @@ -1,17 +1,6 @@ module Arel module Nodes class False < Arel::Nodes::Node - def not - True.new - end - - def or right - right - end - - def and right - self - end end end end diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb index 82f20837f8557..63dd5562e1a15 100644 --- a/lib/arel/nodes/true.rb +++ b/lib/arel/nodes/true.rb @@ -1,17 +1,6 @@ module Arel module Nodes class True < Arel::Nodes::Node - def not - False.new - end - - def or right - self - end - - def and right - right - end end end end From 8fe010a5370f5249de962e1ad345d29a00aec70d Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 16:41:32 +0100 Subject: [PATCH 1061/1492] Support update statements containing joins --- lib/arel/nodes/join_source.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 5 +---- test/test_update_manager.rb | 13 +++++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/arel/nodes/join_source.rb b/lib/arel/nodes/join_source.rb index c57ad0e930d96..da828cf9eeee9 100644 --- a/lib/arel/nodes/join_source.rb +++ b/lib/arel/nodes/join_source.rb @@ -9,6 +9,10 @@ class JoinSource < Arel::Nodes::Binary def initialize single_source, joinop = [] super end + + def empty? + !left && right.empty? + end end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8aec4cb1475da..ec62f4fb89cc4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -142,7 +142,7 @@ def visit_Arel_Nodes_SelectCore o (visit(o.top) if o.top), (visit(o.set_quantifier) if o.set_quantifier), ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?), - (visit(o.source) if o.source), + ("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), @@ -288,10 +288,7 @@ def visit_Arel_Nodes_DoesNotMatch o end def visit_Arel_Nodes_JoinSource o - return unless o.left || !o.right.empty? - [ - "FROM", (visit(o.left) if o.left), o.right.map { |j| visit j }.join(' ') ].compact.join ' ' diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 62a2eccaf594a..3099fb367e898 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -62,6 +62,19 @@ module Arel 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 From 03b6ca269ac8dfec8f70f2b98439d45b873f9e97 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 17:58:39 +0100 Subject: [PATCH 1062/1492] Ignore Gemfile.lock --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 93a12f1c3d634..cc2151e0e8a42 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ debug.log pkg .bundle *.swp +Gemfile.lock From 79411322ae225289e1c051f4f68ed84c6349e4a0 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 8 Aug 2011 23:23:51 +0100 Subject: [PATCH 1063/1492] Make it the responsibility of the connection to hold on to a visitor for generating SQL, rather than the TreeManager. (There is a related commit coming in Active Record.) --- lib/arel/nodes/node.rb | 3 +-- lib/arel/select_manager.rb | 9 +++++---- lib/arel/tree_manager.rb | 12 +++++++----- lib/arel/visitors/to_sql.rb | 6 ++---- test/nodes/test_bin.rb | 4 ++-- test/nodes/test_select_core.rb | 2 +- test/nodes/test_sql_literal.rb | 19 +++++++++---------- test/support/fake_record.rb | 7 ++++--- test/test_select_manager.rb | 4 ++++ test/visitors/test_ibm_db.rb | 2 +- test/visitors/test_informix.rb | 2 +- test/visitors/test_join_sql.rb | 2 +- test/visitors/test_mssql.rb | 2 +- test/visitors/test_mysql.rb | 2 +- test/visitors/test_oracle.rb | 2 +- test/visitors/test_postgres.rb | 2 +- test/visitors/test_sqlite.rb | 2 +- test/visitors/test_to_sql.rb | 6 +++--- 18 files changed, 46 insertions(+), 42 deletions(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 1a5bc278567e7..4faace378287c 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -32,8 +32,7 @@ def and right # # Maybe we should just use `Table.engine`? :'( def to_sql engine = Table.engine - viz = Visitors.for engine - viz.accept self + engine.connection.visitor.accept self end # Iterate through AST, nodes will be yielded depth-first diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index d95a259177d8c..dc8015095725f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -149,13 +149,13 @@ def orders def wheres warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in ARel 3.0.0 with no replacement" - Compatibility::Wheres.new @engine, @ctx.wheres + Compatibility::Wheres.new @engine.connection_pool, @ctx.wheres end def where_sql return if @ctx.wheres.empty? - viz = Visitors::WhereSql.new @engine + viz = Visitors::WhereSql.new @engine.connection_pool Nodes::SqlLiteral.new viz.accept @ctx end @@ -205,12 +205,13 @@ def take limit def join_sql return nil if @ctx.source.right.empty? - sql = @visitor.dup.extend(Visitors::JoinSql).accept @ctx + sql = visitor.dup.extend(Visitors::JoinSql).accept @ctx Nodes::SqlLiteral.new sql end def order_clauses - Visitors::OrderClauses.new(@engine).accept(@ast).map { |x| + visitor = Visitors::OrderClauses.new(@engine.connection_pool) + visitor.accept(@ast).map { |x| Nodes::SqlLiteral.new x } end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 5722baca77969..99a7164e2e6bd 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -4,21 +4,23 @@ class TreeManager include Arel::Relation include Arel::FactoryMethods - attr_accessor :visitor attr_reader :ast, :engine def initialize engine - @engine = engine - @visitor = Visitors.visitor_for @engine - @ctx = nil + @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 + visitor.accept @ast end def initialize_copy other diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ec62f4fb89cc4..d424f8602e5e6 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -4,17 +4,15 @@ module Arel module Visitors class ToSql < Arel::Visitors::Visitor - def initialize engine - @engine = engine + def initialize pool + @pool = pool @connection = nil - @pool = nil @quoted_tables = {} @quoted_columns = {} end def accept object self.last_column = nil - @pool = @engine.connection_pool @pool.with_connection do |conn| @connection = conn super diff --git a/test/nodes/test_bin.rb b/test/nodes/test_bin.rb index b06aeb0b0d9f2..7f123eab13559 100644 --- a/test/nodes/test_bin.rb +++ b/test/nodes/test_bin.rb @@ -8,13 +8,13 @@ def test_new end def test_default_to_sql - viz = Arel::Visitors::ToSql.new Table.engine + 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 + 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 diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index 47f85aee8ab07..4382c79865e05 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -23,7 +23,7 @@ def test_clone def test_set_quantifier core = Arel::Nodes::SelectCore.new core.set_quantifier = Arel::Nodes::Distinct.new - viz = Arel::Visitors::ToSql.new Table.engine + viz = Arel::Visitors::ToSql.new Table.engine.connection_pool assert_match 'DISTINCT', viz.accept(core) end end diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index d280d6d92845f..54d1d4417f80d 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -3,6 +3,10 @@ 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' @@ -13,38 +17,33 @@ module Nodes describe 'count' do it 'makes a count node' do node = SqlLiteral.new('*').count - viz = Visitors::ToSql.new Table.engine - viz.accept(node).must_be_like %{ COUNT(*) } + @visitor.accept(node).must_be_like %{ COUNT(*) } end it 'makes a distinct node' do node = SqlLiteral.new('*').count true - viz = Visitors::ToSql.new Table.engine - viz.accept(node).must_be_like %{ COUNT(DISTINCT *) } + @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) - viz = Visitors::ToSql.new Table.engine - viz.accept(node).must_be_like %{ foo = 1 } + @visitor.accept(node).must_be_like %{ foo = 1 } 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]) - viz = Visitors::ToSql.new Table.engine - viz.accept(node).must_be_like %{ (foo = 1 OR foo = 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]) - viz = Visitors::ToSql.new Table.engine - viz.accept(node).must_be_like %{ (foo = 1 AND foo = 2) } + @visitor.accept(node).must_be_like %{ (foo = 1 AND foo = 2) } end end end diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index babf5fa25b6dd..ddef7b66c5e4c 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -3,9 +3,9 @@ class Column < Struct.new(:name, :type) end class Connection - attr_reader :tables, :columns_hash + attr_reader :tables, :columns_hash, :visitor - def initialize + def initialize(visitor) @tables = %w{ users photos developers products} @columns = { 'users' => [ @@ -27,6 +27,7 @@ def initialize 'users' => 'id', 'products' => 'id' } + @visitor = visitor end def primary_key name @@ -78,7 +79,7 @@ class Spec < Struct.new(:config) def initialize @spec = Spec.new(:adapter => 'america') - @connection = Connection.new + @connection = Connection.new(Arel::Visitors::ToSql.new(self)) end def with_connection diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 119ad3ec4f623..3d43ecfc11e2d 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -42,6 +42,10 @@ def tables @engine.connection.tables end + def visitor + @engine.connection.visitor + end + def execute sql, name = nil, *args @executed << sql end diff --git a/test/visitors/test_ibm_db.rb b/test/visitors/test_ibm_db.rb index cc35bb768d161..90008ba05e319 100644 --- a/test/visitors/test_ibm_db.rb +++ b/test/visitors/test_ibm_db.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the ibm_db visitor' do before do - @visitor = IBM_DB.new Table.engine + @visitor = IBM_DB.new Table.engine.connection_pool end it 'uses FETCH FIRST n ROWS to limit results' do diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index a8a52a0160428..422da846fe6bc 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the informix visitor' do before do - @visitor = Informix.new Table.engine + @visitor = Informix.new Table.engine.connection_pool end it 'uses LIMIT n to limit results' do diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index b672f88ecf61c..6f7440cc47546 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the join_sql visitor' do before do - @visitor = ToSql.new Table.engine + @visitor = ToSql.new Table.engine.connection_pool @visitor.extend(JoinSql) end diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index 8b2b756900685..21588f53cf000 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the mssql visitor' do before do - @visitor = MSSQL.new Table.engine + @visitor = MSSQL.new Table.engine.connection_pool @table = Arel::Table.new "users" end diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 8d220ac04b471..487db325e8138 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the mysql visitor' do before do - @visitor = MySQL.new Table.engine + @visitor = MySQL.new Table.engine.connection_pool end it 'squashes parenthesis on multiple unions' do diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index eaf68013a735a..b53690a1a8478 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the oracle visitor' do before do - @visitor = Oracle.new Table.engine + @visitor = Oracle.new Table.engine.connection_pool end it 'modifies order when there is distinct and first value' do diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 446eae0c4adab..e8df6812693f1 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the postgres visitor' do before do - @visitor = PostgreSQL.new Table.engine + @visitor = PostgreSQL.new Table.engine.connection_pool end describe 'locking' do diff --git a/test/visitors/test_sqlite.rb b/test/visitors/test_sqlite.rb index fb8392c504718..5b81ea90c58de 100644 --- a/test/visitors/test_sqlite.rb +++ b/test/visitors/test_sqlite.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the sqlite visitor' do before do - @visitor = SQLite.new Table.engine + @visitor = SQLite.new Table.engine.connection_pool end it 'defaults limit to -1' do diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 3b58c71cd8074..12af197596996 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -8,7 +8,7 @@ module Arel module Visitors describe 'the to_sql visitor' do before do - @visitor = ToSql.new Table.engine + @visitor = ToSql.new Table.engine.connection_pool @table = Table.new(:users) @attr = @table[:id] end @@ -220,7 +220,7 @@ def quote value, column = nil end end in_node = Nodes::In.new @attr, %w{ a b c } - visitor = visitor.new(Table.engine) + visitor = visitor.new(Table.engine.connection_pool) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } @@ -308,7 +308,7 @@ def quote value, column = nil end end in_node = Nodes::NotIn.new @attr, %w{ a b c } - visitor = visitor.new(Table.engine) + visitor = visitor.new(Table.engine.connection_pool) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } From 4ce8aeb327873fef1adb7e352948ddfb22aa8cb2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 15:46:23 -0700 Subject: [PATCH 1064/1492] updating changelog --- History.txt | 8 ++++++++ Manifest.txt | 3 +++ 2 files changed, 11 insertions(+) diff --git a/History.txt b/History.txt index a6a1784a03488..8028347abcb60 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,11 @@ +== 2.1.5 / 2011-08-08 + +* 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 diff --git a/Manifest.txt b/Manifest.txt index 16333b7cf2fa8..2159c90a9b8a9 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,5 +1,6 @@ .autotest .gemtest +Gemfile History.txt MIT-LICENSE.txt Manifest.txt @@ -27,6 +28,7 @@ lib/arel/nodes/count.rb lib/arel/nodes/delete_statement.rb lib/arel/nodes/descending.rb lib/arel/nodes/equality.rb +lib/arel/nodes/false.rb lib/arel/nodes/function.rb lib/arel/nodes/in.rb lib/arel/nodes/infix_operation.rb @@ -43,6 +45,7 @@ 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 From c3c8424e1c0d9c604ce2020c8c1d84ba305a49e3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 8 Aug 2011 15:46:54 -0700 Subject: [PATCH 1065/1492] updating version --- arel.gemspec | 6 +++--- lib/arel.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 84addb34045fd..a4f7653461829 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.4.20110725155854" + s.version = "2.1.5.20110808154647" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2011-07-25} + s.date = %q{2011-08-08} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -17,7 +17,7 @@ with it, focusing on innovative object and collection modeling as opposed to database 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", "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/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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.files = [".autotest", ".gemtest", "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/false.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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 = %q{http://github.com/rails/arel} s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] diff --git a/lib/arel.rb b/lib/arel.rb index a76227577cc33..c96d2417767bb 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.1.4' + VERSION = '2.1.5' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From e4863ceb0668567e0dcba476a286333f3f39eb2b Mon Sep 17 00:00:00 2001 From: "Michael S. Klishin" Date: Tue, 9 Aug 2011 02:59:34 +0400 Subject: [PATCH 1066/1492] Test against multiple rubies, add IRC notifications --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000..419ced76d387d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +script: "rake test" +rvm: + - 1.8.7 + - rbx + - rbx-2.0 + - jruby + - 1.9.2 + - 1.9.3 +notifications: + email: false + irc: + - "irc.freenode.org#rails-contrib" From 89b726316ed7022ae0310f9fe63c7c0057f6f721 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Tue, 9 Aug 2011 09:55:10 -0500 Subject: [PATCH 1067/1492] Add Ruby trunk (1.9.4dev) to TravisCI matrix --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 419ced76d387d..eb28ccb96e9f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ rvm: - jruby - 1.9.2 - 1.9.3 + - ruby-head notifications: email: false irc: From 22006cf03f70a1838703f3756a74ae775304860e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 9 Aug 2011 14:01:44 -0700 Subject: [PATCH 1068/1492] bumping to 2.2.0 --- History.txt | 2 +- arel.gemspec | 32 ++++++++++++++------------------ lib/arel.rb | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/History.txt b/History.txt index 8028347abcb60..675fefb0f6a73 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 2.1.5 / 2011-08-08 +== 2.2.0 / 2011-08-09 * Bug Fixes diff --git a/arel.gemspec b/arel.gemspec index a4f7653461829..7d48448ef69c5 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.1.5.20110808154647" + s.version = "2.2.0.20110809140134" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = %q{2011-08-08} + s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] + s.date = %q{2011-08-09} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -15,30 +15,26 @@ Gem::Specification.new do |s| 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.} - 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", "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/false.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] + s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] + s.files = [%q{.autotest}, %q{.gemtest}, %q{Gemfile}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/ascending.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/descending.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/false.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/true.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/informix.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] s.homepage = %q{http://github.com/rails/arel} - s.rdoc_options = ["--main", "README.markdown"] - s.require_paths = ["lib"] + s.rdoc_options = [%q{--main}, %q{README.markdown}] + s.require_paths = [%q{lib}] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.3.6} + s.rubygems_version = %q{1.8.6.1} s.summary = %q{Arel is a SQL AST manager for Ruby} - s.test_files = ["test/attributes/test_attribute.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION s.specification_version = 3 - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.3"]) - s.add_development_dependency(%q, ["~> 2.9"]) + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, ["~> 2.10"]) else - s.add_dependency(%q, ["~> 2.3"]) - s.add_dependency(%q, ["~> 2.9"]) + s.add_dependency(%q, ["~> 2.10"]) end else - s.add_dependency(%q, ["~> 2.3"]) - s.add_dependency(%q, ["~> 2.9"]) + s.add_dependency(%q, ["~> 2.10"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index c96d2417767bb..39bca8d52d753 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.1.5' + VERSION = '2.2.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 160917526a8d038d4fbb4d90635e26a9df8d8871 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 11 Aug 2011 08:14:51 +0100 Subject: [PATCH 1069/1492] add UpdateManager#key method to access the key --- lib/arel/update_manager.rb | 4 ++++ test/test_update_manager.rb | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index f13aeb0a8c63b..56e219040c17f 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -15,6 +15,10 @@ def key= key @ast.key = key end + def key + @ast.key + end + def order *expr @ast.orders = expr self diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 3099fb367e898..f9704af425add 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -95,5 +95,21 @@ module Arel 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 From 88c91f7cdbe904c0a215a05be76ae120eacb24fb Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 11 Aug 2011 08:43:21 +0100 Subject: [PATCH 1070/1492] Add SelectManager#projections= method to overwrite projections --- lib/arel/select_manager.rb | 4 ++++ test/test_select_manager.rb | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index dc8015095725f..cff3236a3312b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -135,6 +135,10 @@ def project *projections self end + def projections= projections + @ctx.projections = projections + end + def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 3d43ecfc11e2d..ada0f1423d480 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -860,6 +860,15 @@ def test_join_sources 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 From 34bd53ba015b8f9bca77172784e62994487eef9b Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Thu, 11 Aug 2011 08:51:13 +0100 Subject: [PATCH 1071/1492] Add SelectManager#source method to get the source of the ctx --- lib/arel/select_manager.rb | 4 ++++ test/test_select_manager.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index cff3236a3312b..88f26e4894adf 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -224,6 +224,10 @@ 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 3.0.0" diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index ada0f1423d480..6603102a3a179 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -956,5 +956,13 @@ def test_join_sources 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 + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.source.must_equal manager.ast.cores.last.source + end + end end end From 1fbea9eb4ba8cd64d4be65b5a51b41a028b27996 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 13 Aug 2011 17:10:24 +0100 Subject: [PATCH 1072/1492] Update History.txt --- History.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index 675fefb0f6a73..7ff44a9e4d8a8 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,11 @@ +== 2.2.1 / (unreleased) + +* 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 @@ -166,7 +174,7 @@ == 2.0.0 / 2010-08-01 * Enhancements - + * Recreate library using the Visitor pattern. http://en.wikipedia.org/wiki/Visitor_pattern From 43a811263062338a89737843d16f6db97081560c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 15 Aug 2011 09:55:09 -0700 Subject: [PATCH 1073/1492] updating gem manifest --- Manifest.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Manifest.txt b/Manifest.txt index 2159c90a9b8a9..3fbbf4c803730 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -1,5 +1,6 @@ .autotest .gemtest +.travis.yml Gemfile History.txt MIT-LICENSE.txt From 716687bfde04ec532e88bd5f1a7ec3e6f44fed3a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 15 Aug 2011 10:02:17 -0700 Subject: [PATCH 1074/1492] version bump --- History.txt | 2 +- lib/arel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 7ff44a9e4d8a8..66e2c73be76a2 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -== 2.2.1 / (unreleased) +== 2.2.1 / 2011-09-15 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index 39bca8d52d753..3d38535aa1126 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.2.0' + VERSION = '2.2.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 73b8ffadbc00db7f81405671a962e8b5c37b2e52 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 15 Aug 2011 10:03:18 -0700 Subject: [PATCH 1075/1492] updating the gemspec --- arel.gemspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 7d48448ef69c5..335a0e82a4aea 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = %q{arel} - s.version = "2.2.0.20110809140134" + s.version = "2.2.1.20110815100311" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] - s.date = %q{2011-08-09} + s.date = %q{2011-08-15} s.description = %q{Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation complex of SQL queries @@ -17,12 +17,12 @@ with it, focusing on innovative object and collection modeling as opposed to database compatibility and query generation.} s.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] - s.files = [%q{.autotest}, %q{.gemtest}, %q{Gemfile}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/ascending.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/descending.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/false.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/true.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/informix.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] + s.files = [%q{.autotest}, %q{.gemtest}, %q{.travis.yml}, %q{Gemfile}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/ascending.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/descending.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/false.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/true.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/informix.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] s.homepage = %q{http://github.com/rails/arel} s.rdoc_options = [%q{--main}, %q{README.markdown}] s.require_paths = [%q{lib}] s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.8.6.1} + s.rubygems_version = %q{1.8.8} s.summary = %q{Arel is a SQL AST manager for Ruby} s.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] From 83a5d4d4e37a2c72824315597cb8b737f37b7960 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 16 Aug 2011 13:23:00 -0700 Subject: [PATCH 1076/1492] generating a Gemfile, using the hoe-bundler plugin --- Gemfile | 13 ++++++++++--- Rakefile | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 517921797ae6e..3c2680734cdfe 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,11 @@ -source "http://rubygems.org" +# -*- ruby -*- -gem 'hoe', '>= 2.1.0' -gem 'minitest' +# DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`. + +source :gemcutter + + +gem "minitest", "~>2.2", :group => [:development, :test] +gem "hoe", "~>2.10", :group => [:development, :test] + +# vim: syntax=ruby diff --git a/Rakefile b/Rakefile index fe82460ae37c3..bbf67415dab2c 100644 --- a/Rakefile +++ b/Rakefile @@ -6,6 +6,7 @@ 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') From bca49f4e5beaa135a9b96270426968793550b708 Mon Sep 17 00:00:00 2001 From: Edgars Beigarts Date: Fri, 26 Aug 2011 15:19:36 +0300 Subject: [PATCH 1077/1492] Support locking in Oracle --- lib/arel/visitors/oracle.rb | 4 ++++ test/visitors/test_oracle.rb | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 375f7dbfe9570..43a382886c616 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -3,6 +3,10 @@ module Visitors class Oracle < Arel::Visitors::ToSql private + def visit_Arel_Nodes_Lock o + visit o.expr + end + def visit_Arel_Nodes_SelectStatement o o = order_hacks(o) diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index b53690a1a8478..9a5fa304ab3fb 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -143,6 +143,13 @@ module Visitors ( 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 From 481ccefedd407c1f8941596b03e72cfe35c42d41 Mon Sep 17 00:00:00 2001 From: Edgars Beigarts Date: Fri, 26 Aug 2011 20:01:00 +0300 Subject: [PATCH 1078/1492] Support locking by default and disable it only for SQLite. --- lib/arel/visitors/mysql.rb | 4 ---- lib/arel/visitors/oracle.rb | 4 ---- lib/arel/visitors/postgresql.rb | 3 --- lib/arel/visitors/sqlite.rb | 5 +++++ lib/arel/visitors/to_sql.rb | 3 +-- test/test_select_manager.rb | 2 +- test/visitors/test_sqlite.rb | 5 +++++ 7 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 70166a15c5978..ee8483372acfe 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -28,10 +28,6 @@ def visit_Arel_Nodes_Bin o "BINARY #{visit o.expr}" end - def visit_Arel_Nodes_Lock o - visit o.expr - end - ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 43a382886c616..375f7dbfe9570 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -3,10 +3,6 @@ module Visitors class Oracle < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Lock o - visit o.expr - end - def visit_Arel_Nodes_SelectStatement o o = order_hacks(o) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index bbcefe8a8de9d..812710181c55e 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -2,9 +2,6 @@ module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Lock o - visit o.expr - end def visit_Arel_Nodes_Matches o "#{visit o.left} ILIKE #{visit o.right}" diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index 237ae913bbb49..2a509e95b59ed 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -2,6 +2,11 @@ module 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d424f8602e5e6..b41423476683e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -200,9 +200,8 @@ def visit_Arel_Nodes_Top o "" end - # FIXME: this does nothing on SQLLite3, but should do things on other - # databases. def visit_Arel_Nodes_Lock o + visit o.expr end def visit_Arel_Nodes_Grouping o diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 6603102a3a179..7e9099d0d05b1 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -454,7 +454,7 @@ def test_join_sources it 'adds a lock node' do table = Table.new :users mgr = table.from table - mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" } + mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" FOR UPDATE } end end diff --git a/test/visitors/test_sqlite.rb b/test/visitors/test_sqlite.rb index 5b81ea90c58de..c06f554ea48c9 100644 --- a/test/visitors/test_sqlite.rb +++ b/test/visitors/test_sqlite.rb @@ -13,6 +13,11 @@ module Visitors 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 From 90ff5f1a74a8731fde4c6d915e79001addb9ef34 Mon Sep 17 00:00:00 2001 From: jsanders Date: Mon, 29 Aug 2011 16:10:45 -0600 Subject: [PATCH 1079/1492] Proposed fix for issue 79 - https://github.com/rails/arel/issues/79 - Pass the connection_pool to the ToSql initializer, rather than the engine itself. --- lib/arel/select_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 88f26e4894adf..7a1fbbe4389bb 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -51,7 +51,7 @@ def where_clauses if $VERBOSE warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" end - to_sql = Visitors::ToSql.new @engine + to_sql = Visitors::ToSql.new @engine.connection_pool @ctx.wheres.map { |c| to_sql.accept c } end From 4653755ca28d49ef8215254c4de9da4bb6b888e6 Mon Sep 17 00:00:00 2001 From: Philip Arndt Date: Wed, 14 Sep 2011 15:52:41 +1200 Subject: [PATCH 1080/1492] Removed lib/arel/sql/engine.rb because it's not required anymore. --- lib/arel/sql/engine.rb | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 lib/arel/sql/engine.rb diff --git a/lib/arel/sql/engine.rb b/lib/arel/sql/engine.rb deleted file mode 100644 index 8917f5f29423c..0000000000000 --- a/lib/arel/sql/engine.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - module Sql - class Engine - def self.new thing - #warn "#{caller.first} -- Engine will be removed" - thing - end - end - end -end From 45f87174d11dc549a059b7a041172db25bcc32ce Mon Sep 17 00:00:00 2001 From: JoelJuliano Date: Sun, 30 Oct 2011 19:06:15 -0500 Subject: [PATCH 1081/1492] Allow using non-table alias as a rhs relation name, fix for #84 and #59 --- lib/arel/nodes/table_alias.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index 6ec17885fb9fa..b32f057117ca9 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -10,7 +10,7 @@ def [] name end def table_name - relation.name + relation.respond_to?(:name) ? relation.name : name end end end From d75a0ef0d5139348b7b4d046374502824254a076 Mon Sep 17 00:00:00 2001 From: Joel Bryan Juliano Date: Mon, 31 Oct 2011 00:42:22 -0500 Subject: [PATCH 1082/1492] Added a failing test for a non-table alias as rhs relation name --- test/test_select_manager.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7e9099d0d05b1..ca47b873a2ef5 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -654,6 +654,24 @@ def test_join_sources } 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 table = Table.new :users manager = Arel::SelectManager.new Table.engine From 2680d6485ae79f7232f032e3209a371e17c76191 Mon Sep 17 00:00:00 2001 From: Joel Bryan Juliano Date: Mon, 31 Oct 2011 00:47:18 -0500 Subject: [PATCH 1083/1492] Removed trailing space on the test sql string statement. --- test/test_select_manager.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index ca47b873a2ef5..a00d1843ba6b9 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -668,7 +668,6 @@ def test_join_sources 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 From c0396833cd826483f1b6c957d2b1a8f0b80056ec Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 4 Nov 2011 16:55:40 +0000 Subject: [PATCH 1084/1492] Add SelectManager#distinct to set/unset the Arel::Nodes::Distinct.new quantifier --- lib/arel/select_manager.rb | 8 ++++++++ test/test_select_manager.rb | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 7a1fbbe4389bb..ce8a9caf23e62 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -139,6 +139,14 @@ 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| diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index a00d1843ba6b9..bd5a4be68bd85 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -981,5 +981,18 @@ def test_join_sources manager.source.must_equal manager.ast.cores.last.source end end + + describe 'distinct' do + it 'sets the quantifier' do + table = Table.new :users + 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 From b796e96ce459d5c253083700ebd2f84e877f7cef Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2011 12:02:40 -0800 Subject: [PATCH 1085/1492] Fix grammatical error in README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index eb6426b1ecb3d..0cb53f33e9408 100644 --- a/README.markdown +++ b/README.markdown @@ -6,7 +6,7 @@ Arel is a SQL AST manager for Ruby. It -1. Simplifies the generation complex of SQL queries +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 From 9a0b1c4001869a05200effed883a8ef8bd3ddac9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 19 Nov 2011 18:57:14 -0800 Subject: [PATCH 1086/1492] bumping version --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 3d38535aa1126..41fca9a7901d9 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '2.2.1' + VERSION = '3.0.0.pre' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From c5f9fbf0d66ddeaf1fb2992e696ffe88244bda82 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 19 Nov 2011 18:57:36 -0800 Subject: [PATCH 1087/1492] calling cache methods against the connection --- lib/arel/select_manager.rb | 8 ++++---- lib/arel/visitors/to_sql.rb | 30 ++++++++++++------------------ test/support/fake_record.rb | 16 +++++++++++++--- test/visitors/test_ibm_db.rb | 2 +- test/visitors/test_informix.rb | 2 +- test/visitors/test_join_sql.rb | 2 +- test/visitors/test_mssql.rb | 2 +- test/visitors/test_mysql.rb | 2 +- test/visitors/test_postgres.rb | 2 +- test/visitors/test_to_sql.rb | 24 +++--------------------- 10 files changed, 38 insertions(+), 52 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index ce8a9caf23e62..82b73cf3aa389 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -51,7 +51,7 @@ def where_clauses if $VERBOSE warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" end - to_sql = Visitors::ToSql.new @engine.connection_pool + to_sql = Visitors::ToSql.new @engine.connection @ctx.wheres.map { |c| to_sql.accept c } end @@ -161,13 +161,13 @@ def orders def wheres warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in ARel 3.0.0 with no replacement" - Compatibility::Wheres.new @engine.connection_pool, @ctx.wheres + Compatibility::Wheres.new @engine.connection, @ctx.wheres end def where_sql return if @ctx.wheres.empty? - viz = Visitors::WhereSql.new @engine.connection_pool + viz = Visitors::WhereSql.new @engine.connection Nodes::SqlLiteral.new viz.accept @ctx end @@ -222,7 +222,7 @@ def join_sql end def order_clauses - visitor = Visitors::OrderClauses.new(@engine.connection_pool) + visitor = Visitors::OrderClauses.new(@engine.connection) visitor.accept(@ast).map { |x| Nodes::SqlLiteral.new x } diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b41423476683e..ab48ce8724891 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -4,30 +4,22 @@ module Arel module Visitors class ToSql < Arel::Visitors::Visitor - def initialize pool - @pool = pool - @connection = nil + 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 - @pool.with_connection do |conn| - @connection = conn - super - end + super end private - def last_column= col - Thread.current[:arel_visitors_to_sql_last_column] = col - end - - def last_column - Thread.current[:arel_visitors_to_sql_last_column] - end - def visit_Arel_Nodes_DeleteStatement o [ "DELETE FROM #{visit o.relation}", @@ -97,7 +89,7 @@ def visit_Arel_Nodes_False o end def table_exists? name - @pool.table_exists? name + @schema_cache.table_exists? name end def column_for attr @@ -110,7 +102,7 @@ def column_for attr end def column_cache - @pool.columns_hash + @schema_cache.columns_hash end def visit_Arel_Nodes_Values o @@ -387,7 +379,9 @@ def literal o; o end alias :visit_Bignum :literal alias :visit_Fixnum :literal - def quoted o; quote(o, last_column) end + def quoted o + quote(o, last_column) + end alias :visit_ActiveSupport_Multibyte_Chars :quoted alias :visit_ActiveSupport_StringInquirer :quoted diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index ddef7b66c5e4c..79182f86bdebd 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -3,9 +3,10 @@ class Column < Struct.new(:name, :type) end class Connection - attr_reader :tables, :columns_hash, :visitor + attr_reader :tables, :columns_hash + attr_accessor :visitor - def initialize(visitor) + def initialize(visitor = nil) @tables = %w{ users photos developers products} @columns = { 'users' => [ @@ -50,6 +51,10 @@ 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? @@ -79,7 +84,8 @@ class Spec < Struct.new(:config) def initialize @spec = Spec.new(:adapter => 'america') - @connection = Connection.new(Arel::Visitors::ToSql.new(self)) + @connection = Connection.new + @connection.visitor = Arel::Visitors::ToSql.new(connection) end def with_connection @@ -93,6 +99,10 @@ def table_exists? name def columns_hash connection.columns_hash end + + def schema_cache + connection + end end class Base diff --git a/test/visitors/test_ibm_db.rb b/test/visitors/test_ibm_db.rb index 90008ba05e319..b055e883d6bfc 100644 --- a/test/visitors/test_ibm_db.rb +++ b/test/visitors/test_ibm_db.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the ibm_db visitor' do before do - @visitor = IBM_DB.new Table.engine.connection_pool + @visitor = IBM_DB.new Table.engine.connection end it 'uses FETCH FIRST n ROWS to limit results' do diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index 422da846fe6bc..67b02e0a648cc 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the informix visitor' do before do - @visitor = Informix.new Table.engine.connection_pool + @visitor = Informix.new Table.engine.connection end it 'uses LIMIT n to limit results' do diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index 6f7440cc47546..b3fc7661aa46a 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the join_sql visitor' do before do - @visitor = ToSql.new Table.engine.connection_pool + @visitor = ToSql.new Table.engine.connection @visitor.extend(JoinSql) end diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index 21588f53cf000..d62d4b8d1f6d7 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the mssql visitor' do before do - @visitor = MSSQL.new Table.engine.connection_pool + @visitor = MSSQL.new Table.engine.connection @table = Arel::Table.new "users" end diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 487db325e8138..6330112229d93 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the mysql visitor' do before do - @visitor = MySQL.new Table.engine.connection_pool + @visitor = MySQL.new Table.engine.connection end it 'squashes parenthesis on multiple unions' do diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index e8df6812693f1..921bd96c1a877 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -4,7 +4,7 @@ module Arel module Visitors describe 'the postgres visitor' do before do - @visitor = PostgreSQL.new Table.engine.connection_pool + @visitor = PostgreSQL.new Table.engine.connection end describe 'locking' do diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 12af197596996..9b86a89300a01 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,14 +1,10 @@ require 'helper' -class Arel::Visitors::ToSql - def last_column; Thread.current[:arel_visitors_to_sql_last_column]; end -end - module Arel module Visitors describe 'the to_sql visitor' do before do - @visitor = ToSql.new Table.engine.connection_pool + @visitor = ToSql.new Table.engine.connection @table = Table.new(:users) @attr = @table[:id] end @@ -29,20 +25,6 @@ def dispatch assert visited, 'hello method was called' end - it "should be thread safe around usage of last_column" do - visit_integer_column = Thread.new do - Thread.stop - @visitor.send(:visit_Arel_Attributes_Attribute, @attr) - end - - sleep 0.2 - @visitor.accept(@table[:name]) - assert_equal(:string, @visitor.last_column.type) - visit_integer_column.run - visit_integer_column.join - assert_equal(:string, @visitor.last_column.type) - end - it 'should not quote sql literals' do node = @table[Arel.star] sql = @visitor.accept node @@ -220,7 +202,7 @@ def quote value, column = nil end end in_node = Nodes::In.new @attr, %w{ a b c } - visitor = visitor.new(Table.engine.connection_pool) + visitor = visitor.new(Table.engine.connection) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } @@ -308,7 +290,7 @@ def quote value, column = nil end end in_node = Nodes::NotIn.new @attr, %w{ a b c } - visitor = visitor.new(Table.engine.connection_pool) + visitor = visitor.new(Table.engine.connection) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } From 6525b409c2a753488681f4cd955cfda29a06b1ac Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 19 Nov 2011 20:41:45 -0800 Subject: [PATCH 1088/1492] regenerating the spec --- arel.gemspec | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 335a0e82a4aea..995bc421a7150 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,40 +1,36 @@ # -*- encoding: utf-8 -*- Gem::Specification.new do |s| - s.name = %q{arel} - s.version = "2.2.1.20110815100311" + s.name = "arel" + s.version = "3.0.0.pre.20111119204131" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = [%q{Aaron Patterson}, %q{Bryan Halmkamp}, %q{Emilio Tagua}, %q{Nick Kallen}] - s.date = %q{2011-08-15} - s.description = %q{Arel is a SQL AST manager for Ruby. It - -1. Simplifies the generation complex of 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.} - s.email = [%q{aaron@tenderlovemaking.com}, %q{bryan@brynary.com}, %q{miloops@gmail.com}, %q{nick@example.org}] - s.extra_rdoc_files = [%q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}] - s.files = [%q{.autotest}, %q{.gemtest}, %q{.travis.yml}, %q{Gemfile}, %q{History.txt}, %q{MIT-LICENSE.txt}, %q{Manifest.txt}, %q{README.markdown}, %q{Rakefile}, %q{arel.gemspec}, %q{lib/arel.rb}, %q{lib/arel/alias_predication.rb}, %q{lib/arel/attributes.rb}, %q{lib/arel/attributes/attribute.rb}, %q{lib/arel/compatibility/wheres.rb}, %q{lib/arel/crud.rb}, %q{lib/arel/delete_manager.rb}, %q{lib/arel/deprecated.rb}, %q{lib/arel/expression.rb}, %q{lib/arel/expressions.rb}, %q{lib/arel/factory_methods.rb}, %q{lib/arel/insert_manager.rb}, %q{lib/arel/math.rb}, %q{lib/arel/nodes.rb}, %q{lib/arel/nodes/and.rb}, %q{lib/arel/nodes/ascending.rb}, %q{lib/arel/nodes/binary.rb}, %q{lib/arel/nodes/count.rb}, %q{lib/arel/nodes/delete_statement.rb}, %q{lib/arel/nodes/descending.rb}, %q{lib/arel/nodes/equality.rb}, %q{lib/arel/nodes/false.rb}, %q{lib/arel/nodes/function.rb}, %q{lib/arel/nodes/in.rb}, %q{lib/arel/nodes/infix_operation.rb}, %q{lib/arel/nodes/inner_join.rb}, %q{lib/arel/nodes/insert_statement.rb}, %q{lib/arel/nodes/join_source.rb}, %q{lib/arel/nodes/named_function.rb}, %q{lib/arel/nodes/node.rb}, %q{lib/arel/nodes/ordering.rb}, %q{lib/arel/nodes/outer_join.rb}, %q{lib/arel/nodes/select_core.rb}, %q{lib/arel/nodes/select_statement.rb}, %q{lib/arel/nodes/sql_literal.rb}, %q{lib/arel/nodes/string_join.rb}, %q{lib/arel/nodes/table_alias.rb}, %q{lib/arel/nodes/terminal.rb}, %q{lib/arel/nodes/true.rb}, %q{lib/arel/nodes/unary.rb}, %q{lib/arel/nodes/unqualified_column.rb}, %q{lib/arel/nodes/update_statement.rb}, %q{lib/arel/nodes/values.rb}, %q{lib/arel/nodes/with.rb}, %q{lib/arel/order_predications.rb}, %q{lib/arel/predications.rb}, %q{lib/arel/relation.rb}, %q{lib/arel/select_manager.rb}, %q{lib/arel/sql/engine.rb}, %q{lib/arel/sql_literal.rb}, %q{lib/arel/table.rb}, %q{lib/arel/tree_manager.rb}, %q{lib/arel/update_manager.rb}, %q{lib/arel/visitors.rb}, %q{lib/arel/visitors/depth_first.rb}, %q{lib/arel/visitors/dot.rb}, %q{lib/arel/visitors/ibm_db.rb}, %q{lib/arel/visitors/informix.rb}, %q{lib/arel/visitors/join_sql.rb}, %q{lib/arel/visitors/mssql.rb}, %q{lib/arel/visitors/mysql.rb}, %q{lib/arel/visitors/oracle.rb}, %q{lib/arel/visitors/order_clauses.rb}, %q{lib/arel/visitors/postgresql.rb}, %q{lib/arel/visitors/sqlite.rb}, %q{lib/arel/visitors/to_sql.rb}, %q{lib/arel/visitors/visitor.rb}, %q{lib/arel/visitors/where_sql.rb}, %q{test/attributes/test_attribute.rb}, %q{test/helper.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/support/fake_record.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] - s.homepage = %q{http://github.com/rails/arel} - s.rdoc_options = [%q{--main}, %q{README.markdown}] - s.require_paths = [%q{lib}] - s.rubyforge_project = %q{arel} - s.rubygems_version = %q{1.8.8} - s.summary = %q{Arel is a SQL AST manager for Ruby} - s.test_files = [%q{test/attributes/test_attribute.rb}, %q{test/nodes/test_as.rb}, %q{test/nodes/test_ascending.rb}, %q{test/nodes/test_bin.rb}, %q{test/nodes/test_count.rb}, %q{test/nodes/test_delete_statement.rb}, %q{test/nodes/test_descending.rb}, %q{test/nodes/test_equality.rb}, %q{test/nodes/test_infix_operation.rb}, %q{test/nodes/test_insert_statement.rb}, %q{test/nodes/test_named_function.rb}, %q{test/nodes/test_node.rb}, %q{test/nodes/test_not.rb}, %q{test/nodes/test_or.rb}, %q{test/nodes/test_select_core.rb}, %q{test/nodes/test_select_statement.rb}, %q{test/nodes/test_sql_literal.rb}, %q{test/nodes/test_sum.rb}, %q{test/nodes/test_update_statement.rb}, %q{test/test_activerecord_compat.rb}, %q{test/test_attributes.rb}, %q{test/test_crud.rb}, %q{test/test_delete_manager.rb}, %q{test/test_factory_methods.rb}, %q{test/test_insert_manager.rb}, %q{test/test_select_manager.rb}, %q{test/test_table.rb}, %q{test/test_update_manager.rb}, %q{test/visitors/test_depth_first.rb}, %q{test/visitors/test_dot.rb}, %q{test/visitors/test_ibm_db.rb}, %q{test/visitors/test_informix.rb}, %q{test/visitors/test_join_sql.rb}, %q{test/visitors/test_mssql.rb}, %q{test/visitors/test_mysql.rb}, %q{test/visitors/test_oracle.rb}, %q{test/visitors/test_postgres.rb}, %q{test/visitors/test_sqlite.rb}, %q{test/visitors/test_to_sql.rb}] + 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 = "2011-11-20" + 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/false.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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 = "1.8.11" + s.summary = "Arel is a SQL AST manager for Ruby" + s.test_files = ["test/attributes/test_attribute.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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 = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.10"]) + s.add_development_dependency(%q, ["~> 2.8"]) + s.add_development_dependency(%q, ["~> 2.12"]) else - s.add_dependency(%q, ["~> 2.10"]) + s.add_dependency(%q, ["~> 2.8"]) + s.add_dependency(%q, ["~> 2.12"]) end else - s.add_dependency(%q, ["~> 2.10"]) + s.add_dependency(%q, ["~> 2.8"]) + s.add_dependency(%q, ["~> 2.12"]) end end From 733002f5e725489d5dfc5f3c2c4dd58ca394f546 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 14 Dec 2011 12:44:36 -0800 Subject: [PATCH 1089/1492] updating to rc1 --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 41fca9a7901d9..8d5895dbeac3e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '3.0.0.pre' + VERSION = '3.0.0.rc1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 18c87d2913409bf692512ade96e59297f3574000 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 14 Dec 2011 13:25:19 -0800 Subject: [PATCH 1090/1492] updating the gemspec --- arel.gemspec | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 995bc421a7150..eb0fbefc8dcf1 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.0.pre.20111119204131" + s.version = "3.0.0.rc1.20111214132513" 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 = "2011-11-20" + s.date = "2011-12-14" 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"] @@ -23,14 +23,17 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.8"]) + s.add_development_dependency(%q, ["~> 2.9"]) s.add_development_dependency(%q, ["~> 2.12"]) + s.add_development_dependency(%q, ["~> 3.10"]) else - s.add_dependency(%q, ["~> 2.8"]) + s.add_dependency(%q, ["~> 2.9"]) s.add_dependency(%q, ["~> 2.12"]) + s.add_dependency(%q, ["~> 3.10"]) end else - s.add_dependency(%q, ["~> 2.8"]) + s.add_dependency(%q, ["~> 2.9"]) s.add_dependency(%q, ["~> 2.12"]) + s.add_dependency(%q, ["~> 3.10"]) end end From c9bf52be8ba7acbc6fba542790683920b5c611e0 Mon Sep 17 00:00:00 2001 From: Norman Clarke Date: Sat, 7 Jan 2012 14:25:59 -0300 Subject: [PATCH 1091/1492] Ensure @last_column is cleared after visiting object --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ab48ce8724891..ccaa328a78782 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -133,7 +133,7 @@ def visit_Arel_Nodes_SelectCore o (visit(o.set_quantifier) if o.set_quantifier), ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?), ("FROM #{visit(o.source)}" if o.source && !o.source.empty?), - ("WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" unless o.wheres.empty?), + ("WHERE #{o.wheres.map { |x| accept 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 ' ' From 10fc7d668492c2130c6a794c00e22e4cd0733564 Mon Sep 17 00:00:00 2001 From: Steve Richert Date: Sun, 8 Jan 2012 12:06:15 -0500 Subject: [PATCH 1092/1492] Add build and dependency status images to README --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 0cb53f33e9408..29d00c87ba906 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -# ARel +# 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 From 34f7d3442e7b0fa8f6dd2d270ee26545232ca816 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 12 Jan 2012 11:36:24 -0800 Subject: [PATCH 1093/1492] bumping to 3.0.0 --- arel.gemspec | 9 +++------ lib/arel.rb | 2 +- lib/arel/crud.rb | 6 +++--- lib/arel/select_manager.rb | 8 ++++---- lib/arel/table.rb | 8 ++++---- lib/arel/visitors/to_sql.rb | 2 +- 6 files changed, 16 insertions(+), 19 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index eb0fbefc8dcf1..f2ee5f8d1b227 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.0.rc1.20111214132513" + s.version = "3.0.0.20120112113618" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2011-12-14" + s.date = "2012-01-12" 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"] @@ -23,16 +23,13 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.9"]) s.add_development_dependency(%q, ["~> 2.12"]) s.add_development_dependency(%q, ["~> 3.10"]) else - s.add_dependency(%q, ["~> 2.9"]) s.add_dependency(%q, ["~> 2.12"]) s.add_dependency(%q, ["~> 3.10"]) end else - s.add_dependency(%q, ["~> 2.9"]) s.add_dependency(%q, ["~> 2.12"]) s.add_dependency(%q, ["~> 3.10"]) end diff --git a/lib/arel.rb b/lib/arel.rb index 8d5895dbeac3e..e092fd7998e6e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '3.0.0.rc1' + VERSION = '3.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 43805dd46416f..6c29d5fee4a72 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -22,7 +22,7 @@ def compile_update values def update values if $VERBOSE warn <<-eowarn -update (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please +update (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please switch to `compile_update` eowarn end @@ -45,7 +45,7 @@ def create_insert def insert values if $VERBOSE warn <<-eowarn -insert (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please +insert (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please switch to `compile_insert` eowarn end @@ -62,7 +62,7 @@ def compile_delete def delete if $VERBOSE warn <<-eowarn -delete (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please +delete (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please switch to `compile_delete` eowarn end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 82b73cf3aa389..32f833f686bdd 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -49,7 +49,7 @@ def as other def where_clauses if $VERBOSE - warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement" + 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 } @@ -160,7 +160,7 @@ def orders end def wheres - warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in ARel 3.0.0 with no replacement" + 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 @@ -238,7 +238,7 @@ def source def joins manager if $VERBOSE - warn "joins is deprecated and will be removed in 3.0.0" + 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 @@ -266,7 +266,7 @@ def to_a # :nodoc: def insert values if $VERBOSE warn <<-eowarn -insert (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please +insert (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please switch to `compile_insert` eowarn end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 82d160b87eb38..7a1983b3d2f24 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -32,7 +32,7 @@ def initialize name, engine = Table.engine def primary_key if $VERBOSE warn <<-eowarn -primary_key (#{caller.first}) is deprecated and will be removed in ARel 3.0.0 +primary_key (#{caller.first}) is deprecated and will be removed in ARel 4.0.0 eowarn end @primary_key ||= begin @@ -54,7 +54,7 @@ def from table def joins manager if $VERBOSE - warn "joins is deprecated and will be removed in 3.0.0" + warn "joins is deprecated and will be removed in 4.0.0" warn "please remove your call to joins from #{caller.first}" end nil @@ -104,7 +104,7 @@ def columns if $VERBOSE warn <<-eowarn (#{caller.first}) Arel::Table#columns is deprecated and will be removed in -Arel 3.0.0 with no replacement. PEW PEW PEW!!! +Arel 4.0.0 with no replacement. PEW PEW PEW!!! eowarn end @columns ||= @@ -138,7 +138,7 @@ def self.table_cache engine # :nodoc: if $VERBOSE warn <<-eowarn (#{caller.first}) Arel::Table.table_cache is deprecated and will be removed in -Arel 3.0.0 with no replacement. PEW PEW PEW!!! +Arel 4.0.0 with no replacement. PEW PEW PEW!!! eowarn end @@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }] diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ccaa328a78782..260cb6959f067 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -47,7 +47,7 @@ def visit_Arel_Nodes_UpdateStatement o unless key warn(<<-eowarn) if $VERBOSE (#{caller.first}) Using UpdateManager without setting UpdateManager#key is -deprecated and support will be removed in ARel 3.0.0. Please set the primary +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 From daa7e829e0222b8cd977610f13f049b1f0175fd1 Mon Sep 17 00:00:00 2001 From: Adam H Date: Fri, 20 Jan 2012 10:10:09 -0500 Subject: [PATCH 1094/1492] while using activerecord-sqlserver-adapter 3.1.5 with Rails 3.1 with Arel 2.2.1 we encountered the error uninitialized constant Arel::Nodes::Visitors::DepthFirst apparently Arel was trying to call a relative namespace with Visitors::DepthFirst.new(block).accept self we fixed this by making it call an absolute namespace with ::Arel::Visitors::DepthFirst.new(block).accept self --- lib/arel/nodes/node.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 4faace378287c..84dcb1cdf5218 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -39,7 +39,7 @@ def to_sql engine = Table.engine def each &block return enum_for(:each) unless block_given? - Visitors::DepthFirst.new(block).accept self + ::Arel::Visitors::DepthFirst.new(block).accept self end end end From eebf5d77aad712fad27a3adf70cd0ab2e8246668 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 9 Feb 2012 15:37:48 -0800 Subject: [PATCH 1095/1492] Borked the tests, so I'm reverting for now. Revert "Merge pull request #81 from parndt/master" This reverts commit f3214d9ff0b7a3efb14f7e9cb93c51d3468c16d8, reversing changes made to fc787a42c0febcee41e13d16e06b72492ab00468. --- lib/arel/sql/engine.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 lib/arel/sql/engine.rb diff --git a/lib/arel/sql/engine.rb b/lib/arel/sql/engine.rb new file mode 100644 index 0000000000000..8917f5f29423c --- /dev/null +++ b/lib/arel/sql/engine.rb @@ -0,0 +1,10 @@ +module Arel + module Sql + class Engine + def self.new thing + #warn "#{caller.first} -- Engine will be removed" + thing + end + end + end +end From d1c9c46c96c016b6561018d8017261feea3912a7 Mon Sep 17 00:00:00 2001 From: babinho Date: Fri, 17 Feb 2012 09:47:31 +0100 Subject: [PATCH 1096/1492] Oracle limit and offset issue when query is ordered, issue #99 solved. --- lib/arel/visitors/oracle.rb | 3 +-- test/visitors/test_oracle.rb | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 375f7dbfe9570..1441a20dbc2d4 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -25,9 +25,8 @@ def visit_Arel_Nodes_SelectStatement o SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ - WHERE rownum <= #{offset.expr.to_i + limit} ) - WHERE #{visit offset} + WHERE raw_rnum_ between #{offset.expr.to_i + 1 } and #{offset.expr.to_i + limit} eosql end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 9a5fa304ab3fb..af81f2058b489 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -102,9 +102,8 @@ module Visitors SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (SELECT) raw_sql_ - WHERE rownum <= 20 ) - WHERE raw_rnum_ > 10 + WHERE raw_rnum_ between 11 and 20 } end From 33f03c5557526d54c2b0053c79ea0e837016aef5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Feb 2012 17:57:37 -0800 Subject: [PATCH 1097/1492] bind parameters can be differentiated from sql literals --- lib/arel/nodes/sql_literal.rb | 3 +++ lib/arel/visitors/depth_first.rb | 1 + lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/to_sql.rb | 1 + test/nodes/test_node.rb | 1 + test/visitors/test_to_sql.rb | 6 ++++++ 6 files changed, 13 insertions(+) diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 2e934b2a1bad0..1bae8c9366638 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -6,5 +6,8 @@ class SqlLiteral < String include Arel::AliasPredication include Arel::OrderPredications end + + class BindParam < SqlLiteral + end end end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 43d186cc1a833..d1ae524db4323 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -109,6 +109,7 @@ def terminal o 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_SqlLiteral :terminal alias :visit_BigDecimal :terminal alias :visit_Bignum :terminal diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 8303279211399..001843d8babab 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -65,6 +65,7 @@ def unary o visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_BindParam :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 260cb6959f067..29df72ff9777c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -374,6 +374,7 @@ def visit_Arel_Attributes_Attribute o 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 diff --git a/test/nodes/test_node.rb b/test/nodes/test_node.rb index b8d06b9cccafa..335cba8aab587 100644 --- a/test/nodes/test_node.rb +++ b/test/nodes/test_node.rb @@ -11,6 +11,7 @@ def test_all_nodes_are_nodes 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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 9b86a89300a01..f832bdf9259e1 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -9,6 +9,12 @@ module Visitors @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) { From aa43fe1eb7db56f333698033e02b5e879b85145b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 Feb 2012 18:04:54 -0800 Subject: [PATCH 1098/1492] bumping to 3.0.1 --- arel.gemspec | 13 ++++++++----- lib/arel.rb | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index f2ee5f8d1b227..2b8cacda8e60a 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.0.20120112113618" + s.version = "3.0.1.20120220180444" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2012-01-12" + s.date = "2012-02-21" 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"] @@ -23,14 +23,17 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.12"]) + s.add_development_dependency(%q, ["~> 2.11"]) s.add_development_dependency(%q, ["~> 3.10"]) + s.add_development_dependency(%q, ["~> 2.13"]) else - s.add_dependency(%q, ["~> 2.12"]) + s.add_dependency(%q, ["~> 2.11"]) s.add_dependency(%q, ["~> 3.10"]) + s.add_dependency(%q, ["~> 2.13"]) end else - s.add_dependency(%q, ["~> 2.12"]) + s.add_dependency(%q, ["~> 2.11"]) s.add_dependency(%q, ["~> 3.10"]) + s.add_dependency(%q, ["~> 2.13"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index e092fd7998e6e..4118451aa45ac 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '3.0.0' + VERSION = '3.0.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From bb22e84abe262b6e6e0975b3f6c4262929ab8bca Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Feb 2012 15:01:27 -0800 Subject: [PATCH 1099/1492] added a module for visiting and transforming bind values --- lib/arel/visitors/bind_visitor.rb | 24 ++++++++++++++++++ lib/arel/visitors/to_sql.rb | 4 +-- test/visitors/test_bind_visitor.rb | 39 ++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 lib/arel/visitors/bind_visitor.rb create mode 100644 test/visitors/test_bind_visitor.rb diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb new file mode 100644 index 0000000000000..0f1e38315bec7 --- /dev/null +++ b/lib/arel/visitors/bind_visitor.rb @@ -0,0 +1,24 @@ +module 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_BindParam o + if @block + @block.call + else + super + end + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 29df72ff9777c..64f96b44dd40f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -108,7 +108,7 @@ def column_cache def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| if Nodes::SqlLiteral === value - visit_Arel_Nodes_SqlLiteral value + visit value else quote(value, attr && column_for(attr)) end @@ -133,7 +133,7 @@ def visit_Arel_Nodes_SelectCore o (visit(o.set_quantifier) if o.set_quantifier), ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?), ("FROM #{visit(o.source)}" if o.source && !o.source.empty?), - ("WHERE #{o.wheres.map { |x| accept x }.join ' AND ' }" unless o.wheres.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 ' ' diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb new file mode 100644 index 0000000000000..92e5d1612cb68 --- /dev/null +++ b/test/visitors/test_bind_visitor.rb @@ -0,0 +1,39 @@ +require 'helper' +require 'arel/visitors/bind_visitor' + +module Arel + module Visitors + class TestBindVisitor < MiniTest::Unit::TestCase + 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 From 6e427e589820278908e7a746749eb9b79b0f85e3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 21 Feb 2012 15:05:41 -0800 Subject: [PATCH 1100/1492] bumping version and spec --- Manifest.txt | 2 ++ arel.gemspec | 6 +++--- lib/arel.rb | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 3fbbf4c803730..286dbf6b27ea7 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -62,6 +62,7 @@ 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 @@ -106,6 +107,7 @@ 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 diff --git a/arel.gemspec b/arel.gemspec index 2b8cacda8e60a..878c42ec0fda4 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.1.20120220180444" + s.version = "3.0.2.20120221150532" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] @@ -10,14 +10,14 @@ Gem::Specification.new do |s| 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/false.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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/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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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.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/false.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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 = "1.8.11" s.summary = "Arel is a SQL AST manager for Ruby" - s.test_files = ["test/attributes/test_attribute.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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_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.test_files = ["test/attributes/test_attribute.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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 = 3 diff --git a/lib/arel.rb b/lib/arel.rb index 4118451aa45ac..9d08caebeb2f8 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -33,7 +33,7 @@ #### module Arel - VERSION = '3.0.1' + VERSION = '3.0.2' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From a1a6fbc189d0cb8c44606eafcb8bda7a010554c0 Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Wed, 22 Feb 2012 15:25:10 +0100 Subject: [PATCH 1101/1492] Support ANSI SQL2003 window functions. --- lib/arel.rb | 1 + lib/arel/nodes.rb | 4 + lib/arel/nodes/function.rb | 1 + lib/arel/nodes/over.rb | 13 +++ lib/arel/nodes/select_core.rb | 4 +- lib/arel/nodes/window.rb | 78 +++++++++++++++ lib/arel/select_manager.rb | 6 ++ lib/arel/visitors/depth_first.rb | 2 + lib/arel/visitors/dot.rb | 19 ++++ lib/arel/visitors/to_sql.rb | 54 +++++++++++ lib/arel/window_predications.rb | 9 ++ test/nodes/test_over.rb | 40 ++++++++ test/test_select_manager.rb | 156 ++++++++++++++++++++++++++++++ test/visitors/test_depth_first.rb | 6 +- 14 files changed, 390 insertions(+), 3 deletions(-) create mode 100644 lib/arel/nodes/over.rb create mode 100644 lib/arel/nodes/window.rb create mode 100644 lib/arel/window_predications.rb create mode 100644 test/nodes/test_over.rb diff --git a/lib/arel.rb b/lib/arel.rb index 9d08caebeb2f8..b27da2fb056fd 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -3,6 +3,7 @@ require 'arel/expressions' require 'arel/predications' +require 'arel/window_predications' require 'arel/math' require 'arel/alias_predication' require 'arel/order_predications' diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index e37b09a8acd1d..b9b5353df7f03 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -26,6 +26,7 @@ require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' require 'arel/nodes/infix_operation' +require 'arel/nodes/over' # nary require 'arel/nodes/and' @@ -38,6 +39,9 @@ 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' diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index b6f6644678562..5f6056a6b6034 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -3,6 +3,7 @@ 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 diff --git a/lib/arel/nodes/over.rb b/lib/arel/nodes/over.rb new file mode 100644 index 0000000000000..727ccd2dc70d8 --- /dev/null +++ b/lib/arel/nodes/over.rb @@ -0,0 +1,13 @@ +module Arel + module Nodes + + class Over < Binary + def initialize(left, right = nil) + super(left, right) + end + + def operator; 'OVER' end + end + + end +end \ No newline at end of file diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index bee0a5930c634..9b8c4a2a1f915 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,7 +1,7 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node - attr_accessor :top, :projections, :wheres, :groups + attr_accessor :top, :projections, :wheres, :groups, :windows attr_accessor :having, :source, :set_quantifier def initialize @@ -14,6 +14,7 @@ def initialize @wheres = [] @groups = [] @having = nil + @windows = [] end def from @@ -34,6 +35,7 @@ def initialize_copy other @wheres = @wheres.clone @groups = @groups.clone @having = @having.clone if @having + @windows = @windows.clone end end end diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb new file mode 100644 index 0000000000000..b54eb7fe64bed --- /dev/null +++ b/lib/arel/nodes/window.rb @@ -0,0 +1,78 @@ +module 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) + raise ArgumentError, "Window frame cannot be set more than once" if @frame + @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 + end + + class NamedWindow < Window + attr_accessor :name + + def initialize name + super() + @name = name + end + + def initialize_copy other + super + @name = other.name.clone + end + 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 < Arel::Nodes::Node; 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 \ No newline at end of file diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 32f833f686bdd..d20faa6eb3a4c 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -126,6 +126,12 @@ def having *exprs 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. diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index d1ae524db4323..10bc24f36b74f 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -110,6 +110,7 @@ def terminal o 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 @@ -136,6 +137,7 @@ def visit_Arel_Nodes_SelectCore o visit o.source visit o.wheres visit o.groups + visit o.windows visit o.having end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 001843d8babab..800b44b602dd0 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -74,6 +74,23 @@ def unary o 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" @@ -103,6 +120,7 @@ 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 @@ -159,6 +177,7 @@ def binary o 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 64f96b44dd40f..c22df6289dfc8 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -136,6 +136,7 @@ def visit_Arel_Nodes_SelectCore o ("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), + ("WINDOW #{o.windows.map { |x| visit x }.join ', ' }" unless o.windows.empty?) ].compact.join ' ' end @@ -175,6 +176,59 @@ 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 diff --git a/lib/arel/window_predications.rb b/lib/arel/window_predications.rb new file mode 100644 index 0000000000000..71844eab53131 --- /dev/null +++ b/lib/arel/window_predications.rb @@ -0,0 +1,9 @@ +module Arel + module WindowPredications + + def over(expr = nil) + Nodes::Over.new(self, expr) + end + + end +end \ No newline at end of file diff --git a/test/nodes/test_over.rb b/test/nodes/test_over.rb new file mode 100644 index 0000000000000..fcc5078e7b970 --- /dev/null +++ b/test/nodes/test_over.rb @@ -0,0 +1,40 @@ +require 'helper' + +describe Arel::Nodes::Over do + 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 +end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index bd5a4be68bd85..d68deb3061c32 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -731,6 +731,162 @@ def test_join_sources 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 diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index e62ce5266fb5b..9c01fb8fcc162 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -179,7 +179,8 @@ def test_select_core core.froms = :b core.wheres << :c core.groups << :d - core.having = :e + core.windows << :e + core.having = :f @visitor.accept core assert_equal [ @@ -188,7 +189,8 @@ def test_select_core core.source, :c, core.wheres, :d, core.groups, - :e, + :e, core.windows, + :f, core], @collector.calls end From 2db4ec6a28a59a3f74a4979ae5bc117e5c7573c4 Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Thu, 23 Feb 2012 14:06:05 +0100 Subject: [PATCH 1102/1492] Add #extract, which produces ANSI SQL function EXTRACT( from ). --- lib/arel/expressions.rb | 4 ++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/extract.rb | 23 +++++++++++++++++++++++ lib/arel/visitors/dot.rb | 6 ++++++ lib/arel/visitors/to_sql.rb | 4 ++++ test/nodes/test_extract.rb | 19 +++++++++++++++++++ 6 files changed, 57 insertions(+) create mode 100644 lib/arel/nodes/extract.rb create mode 100644 test/nodes/test_extract.rb diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index d1fbfd83d90d9..fa18f15b6770b 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -19,5 +19,9 @@ def minimum def average Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') end + + def extract field + Nodes::Extract.new [self], field + end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index b9b5353df7f03..0477591caedd4 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -36,6 +36,7 @@ # 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' diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb new file mode 100644 index 0000000000000..1c9ee78816303 --- /dev/null +++ b/lib/arel/nodes/extract.rb @@ -0,0 +1,23 @@ +module 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 + end + end +end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 800b44b602dd0..8a83ebf48effe 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -103,6 +103,12 @@ def function o 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" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index c22df6289dfc8..a6be451e6febe 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -272,6 +272,10 @@ def visit_Arel_Nodes_NamedFunction o }.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 diff --git a/test/nodes/test_extract.rb b/test/nodes/test_extract.rb new file mode 100644 index 0000000000000..bd1dfa4750dad --- /dev/null +++ b/test/nodes/test_extract.rb @@ -0,0 +1,19 @@ +require 'helper' + +describe Arel::Nodes::Extract do + it "should extract field" do + table = Arel::Table.new :users + table[:timestamp].extract('date').to_sql.must_be_like %{ + EXTRACT(DATE FROM "users"."timestamp") + } + end + + describe "as" do + it 'should alias the extract' do + table = Arel::Table.new :users + table[:timestamp].extract('date').as('foo').to_sql.must_be_like %{ + EXTRACT(DATE FROM "users"."timestamp") AS foo + } + end + end +end From 74aadecc4f58e73704ac6a6fdaf25e48832374cf Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Thu, 23 Feb 2012 14:16:44 +0100 Subject: [PATCH 1103/1492] Must support aliases for OVER operator. --- lib/arel/nodes/over.rb | 2 ++ test/nodes/test_over.rb | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/arel/nodes/over.rb b/lib/arel/nodes/over.rb index 727ccd2dc70d8..21d1b5029e096 100644 --- a/lib/arel/nodes/over.rb +++ b/lib/arel/nodes/over.rb @@ -2,6 +2,8 @@ module Arel module Nodes class Over < Binary + include Arel::AliasPredication + def initialize(left, right = nil) super(left, right) end diff --git a/test/nodes/test_over.rb b/test/nodes/test_over.rb index fcc5078e7b970..0bdd665e564e6 100644 --- a/test/nodes/test_over.rb +++ b/test/nodes/test_over.rb @@ -1,6 +1,15 @@ require 'helper' describe Arel::Nodes::Over do + describe 'as' do + it 'should alias the expression' do + table = Arel::Table.new :users + table[:id].count.over.as('foo').to_sql.must_be_like %{ + COUNT("users"."id") OVER () AS foo + } + end + end + describe 'with literal' do it 'should reference the window definition by name' do table = Arel::Table.new :users From 7cb1044343d474d9174459e9176f144d2b776eec Mon Sep 17 00:00:00 2001 From: Jordan Date: Wed, 29 Feb 2012 15:14:47 -0500 Subject: [PATCH 1104/1492] Patch Informix Visitor so that it includes joins --- lib/arel/visitors/informix.rb | 2 +- test/visitors/test_informix.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index 25eef1e6de4d7..984098cdf3962 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -15,7 +15,7 @@ def visit_Arel_Nodes_SelectStatement o def visit_Arel_Nodes_SelectCore o [ "#{o.projections.map { |x| visit x }.join ', '}", - ("FROM #{visit o.froms}" if o.froms), + ("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), diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index 67b02e0a648cc..90bbf5c10493a 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -37,6 +37,16 @@ module Visitors 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 From 762d1ee0b9cf08c7d9a7f4314387f0088cfbc834 Mon Sep 17 00:00:00 2001 From: Jeremy McAnally Date: Mon, 12 Mar 2012 14:05:12 -0400 Subject: [PATCH 1105/1492] Fix egregious lack of code formatting there. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 29d00c87ba906..afef04212a33e 100644 --- a/README.markdown +++ b/README.markdown @@ -83,7 +83,7 @@ The examples above are fairly simple and other libraries match or come close to #### 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: +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]] From c50b40674664e0e5b971931536482ffbac47a1cf Mon Sep 17 00:00:00 2001 From: Benedikt Deicke Date: Thu, 22 Mar 2012 17:09:32 +0100 Subject: [PATCH 1106/1492] Adds visit_Arel_Nodes_InfixOperation to Arel::Visitors::DepthFirst --- lib/arel/visitors/depth_first.rb | 1 + test/visitors/test_depth_first.rb | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 10bc24f36b74f..24c435ad1daca 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -70,6 +70,7 @@ def binary o 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 diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 9c01fb8fcc162..05360ff6e8d2c 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -114,6 +114,12 @@ def test_outer_join 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, From 00c5435311c621453ce231b74e99c1e9539e47a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Tue, 27 Mar 2012 12:52:43 +0200 Subject: [PATCH 1107/1492] Remove deprecated Relation module --- lib/arel.rb | 2 -- lib/arel/relation.rb | 6 ------ lib/arel/tree_manager.rb | 2 -- 3 files changed, 10 deletions(-) delete mode 100644 lib/arel/relation.rb diff --git a/lib/arel.rb b/lib/arel.rb index b27da2fb056fd..6d7aec64b1d8e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -12,8 +12,6 @@ require 'arel/compatibility/wheres' #### these are deprecated -# The Arel::Relation constant is referenced in Rails -require 'arel/relation' require 'arel/expression' #### diff --git a/lib/arel/relation.rb b/lib/arel/relation.rb deleted file mode 100644 index 87786d7701761..0000000000000 --- a/lib/arel/relation.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - ### - # This is deprecated. Fix rails, then remove this. - module Relation - end -end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 99a7164e2e6bd..21a52d8a60061 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,7 +1,5 @@ module Arel class TreeManager - # FIXME: Remove this. - include Arel::Relation include Arel::FactoryMethods attr_reader :ast, :engine From 6e8d1587091e00a84ea24ab92d9e836c3c38bcb8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Mar 2012 13:54:21 -0700 Subject: [PATCH 1108/1492] Revert "Merge pull request #113 from xuanxu/remove_relation" This reverts commit 9978fc40a8a5a262670279129a335845ad647f48, reversing changes made to b45466757424b98e1fe9699042d23550fd5b8751. --- lib/arel.rb | 2 ++ lib/arel/relation.rb | 6 ++++++ lib/arel/tree_manager.rb | 2 ++ 3 files changed, 10 insertions(+) create mode 100644 lib/arel/relation.rb diff --git a/lib/arel.rb b/lib/arel.rb index 6d7aec64b1d8e..b27da2fb056fd 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -12,6 +12,8 @@ require 'arel/compatibility/wheres' #### these are deprecated +# The Arel::Relation constant is referenced in Rails +require 'arel/relation' require 'arel/expression' #### diff --git a/lib/arel/relation.rb b/lib/arel/relation.rb new file mode 100644 index 0000000000000..87786d7701761 --- /dev/null +++ b/lib/arel/relation.rb @@ -0,0 +1,6 @@ +module Arel + ### + # This is deprecated. Fix rails, then remove this. + module Relation + end +end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 21a52d8a60061..99a7164e2e6bd 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,5 +1,7 @@ module Arel class TreeManager + # FIXME: Remove this. + include Arel::Relation include Arel::FactoryMethods attr_reader :ast, :engine From d43ae586aab7092c6bf742609ff1dc3ebf6aff6a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Mar 2012 14:12:22 -0700 Subject: [PATCH 1109/1492] Revert "Revert "Merge pull request #113 from xuanxu/remove_relation"" This reverts commit 6e8d1587091e00a84ea24ab92d9e836c3c38bcb8. --- lib/arel.rb | 2 -- lib/arel/relation.rb | 6 ------ lib/arel/tree_manager.rb | 2 -- 3 files changed, 10 deletions(-) delete mode 100644 lib/arel/relation.rb diff --git a/lib/arel.rb b/lib/arel.rb index b27da2fb056fd..6d7aec64b1d8e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -12,8 +12,6 @@ require 'arel/compatibility/wheres' #### these are deprecated -# The Arel::Relation constant is referenced in Rails -require 'arel/relation' require 'arel/expression' #### diff --git a/lib/arel/relation.rb b/lib/arel/relation.rb deleted file mode 100644 index 87786d7701761..0000000000000 --- a/lib/arel/relation.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - ### - # This is deprecated. Fix rails, then remove this. - module Relation - end -end diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 99a7164e2e6bd..21a52d8a60061 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,7 +1,5 @@ module Arel class TreeManager - # FIXME: Remove this. - include Arel::Relation include Arel::FactoryMethods attr_reader :ast, :engine From 083a7ffc9137f2bbb2709a01115fc407a96c355a Mon Sep 17 00:00:00 2001 From: Ben Moss Date: Sat, 31 Mar 2012 17:35:34 -0400 Subject: [PATCH 1110/1492] Update travis.yml to use the proper rbx build names --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index eb28ccb96e9f2..e76e753520449 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ script: "rake test" rvm: - 1.8.7 - - rbx - - rbx-2.0 + - rbx-18mode + - rbx-19mode - jruby - 1.9.2 - 1.9.3 From a56b772282f604f48e341f07cb04a9355387df89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sat, 12 May 2012 17:33:30 -0300 Subject: [PATCH 1111/1492] Update manifest --- Manifest.txt | 7 ++++++- arel.gemspec | 16 ++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 286dbf6b27ea7..e0ce1627b10f6 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -29,6 +29,7 @@ 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/in.rb @@ -40,6 +41,7 @@ lib/arel/nodes/named_function.rb lib/arel/nodes/node.rb lib/arel/nodes/ordering.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 @@ -51,10 +53,10 @@ 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/relation.rb lib/arel/select_manager.rb lib/arel/sql/engine.rb lib/arel/sql_literal.rb @@ -77,6 +79,7 @@ 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_as.rb @@ -86,12 +89,14 @@ test/nodes/test_count.rb test/nodes/test_delete_statement.rb test/nodes/test_descending.rb test/nodes/test_equality.rb +test/nodes/test_extract.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 diff --git a/arel.gemspec b/arel.gemspec index 878c42ec0fda4..0acfec46d2b22 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,22 +2,22 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.2.20120221150532" + s.version = "3.0.2.20120512172828" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2012-02-21" + s.date = "2012-05-12" 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/false.rb", "lib/arel/nodes/function.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/ordering.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/relation.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", "test/attributes/test_attribute.rb", "test/helper.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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.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/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/ordering.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_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_equality.rb", "test/nodes/test_extract.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_update_statement.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 = "1.8.11" + s.rubygems_version = "1.8.23" s.summary = "Arel is a SQL AST manager for Ruby" - s.test_files = ["test/attributes/test_attribute.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_equality.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_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_update_statement.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.test_files = ["test/attributes/test_attribute.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_equality.rb", "test/nodes/test_extract.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_update_statement.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 = 3 @@ -25,15 +25,15 @@ Gem::Specification.new do |s| if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q, ["~> 2.11"]) s.add_development_dependency(%q, ["~> 3.10"]) - s.add_development_dependency(%q, ["~> 2.13"]) + s.add_development_dependency(%q, ["~> 3.0"]) else s.add_dependency(%q, ["~> 2.11"]) s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 2.13"]) + s.add_dependency(%q, ["~> 3.0"]) end else s.add_dependency(%q, ["~> 2.11"]) s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 2.13"]) + s.add_dependency(%q, ["~> 3.0"]) end end From c78227d9b219933f54cecefb99c72bb231fbb8f2 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 19 May 2012 11:10:47 -0400 Subject: [PATCH 1112/1492] Include Predications in Grouping Also, removed unused ordering.rb file, since it is identical to the one being created in unary.rb already, and isn't required anywhere. --- lib/arel/nodes.rb | 1 + lib/arel/nodes/grouping.rb | 7 +++++++ lib/arel/nodes/ordering.rb | 6 ------ lib/arel/nodes/unary.rb | 1 - test/nodes/test_grouping.rb | 13 +++++++++++++ 5 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 lib/arel/nodes/grouping.rb delete mode 100644 lib/arel/nodes/ordering.rb create mode 100644 test/nodes/test_grouping.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 0477591caedd4..54caea69a192b 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -13,6 +13,7 @@ # unary require 'arel/nodes/unary' +require 'arel/nodes/grouping' require 'arel/nodes/ascending' require 'arel/nodes/descending' require 'arel/nodes/unqualified_column' diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb new file mode 100644 index 0000000000000..e7f4bd9cd5c4f --- /dev/null +++ b/lib/arel/nodes/grouping.rb @@ -0,0 +1,7 @@ +module Arel + module Nodes + class Grouping < Unary + include Arel::Predications + end + end +end diff --git a/lib/arel/nodes/ordering.rb b/lib/arel/nodes/ordering.rb deleted file mode 100644 index efb4d18ae445e..0000000000000 --- a/lib/arel/nodes/ordering.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Arel - module Nodes - class Ordering < Unary - end - end -end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 4688fff62311c..7828cceae54e0 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -12,7 +12,6 @@ def initialize expr %w{ Bin Group - Grouping Having Limit Not diff --git a/test/nodes/test_grouping.rb b/test/nodes/test_grouping.rb new file mode 100644 index 0000000000000..3f84ac301e36a --- /dev/null +++ b/test/nodes/test_grouping.rb @@ -0,0 +1,13 @@ +require '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 + end + end +end + From af07bd12fd182de04a2829a5db3ae1abac299174 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Wed, 30 May 2012 17:12:01 -0400 Subject: [PATCH 1113/1492] Update manifest. --- Manifest.txt | 3 ++- arel.gemspec | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index e0ce1627b10f6..3f51c53c3749c 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -32,6 +32,7 @@ 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 @@ -39,7 +40,6 @@ 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/ordering.rb lib/arel/nodes/outer_join.rb lib/arel/nodes/over.rb lib/arel/nodes/select_core.rb @@ -90,6 +90,7 @@ test/nodes/test_delete_statement.rb test/nodes/test_descending.rb test/nodes/test_equality.rb test/nodes/test_extract.rb +test/nodes/test_grouping.rb test/nodes/test_infix_operation.rb test/nodes/test_insert_statement.rb test/nodes/test_named_function.rb diff --git a/arel.gemspec b/arel.gemspec index 0acfec46d2b22..aa5c66adfaa75 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,38 +2,38 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.2.20120512172828" + s.version = "3.0.2.20120530170952" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2012-05-12" + s.date = "2012-05-30" 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/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/ordering.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_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_equality.rb", "test/nodes/test_extract.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_update_statement.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.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_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_equality.rb", "test/nodes/test_extract.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_update_statement.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 = "1.8.23" + s.rubygems_version = "1.8.24" s.summary = "Arel is a SQL AST manager for Ruby" - s.test_files = ["test/attributes/test_attribute.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_equality.rb", "test/nodes/test_extract.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_update_statement.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.test_files = ["test/attributes/test_attribute.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_equality.rb", "test/nodes/test_extract.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_update_statement.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 = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.11"]) + s.add_development_dependency(%q, ["~> 2.12"]) s.add_development_dependency(%q, ["~> 3.10"]) - s.add_development_dependency(%q, ["~> 3.0"]) + s.add_development_dependency(%q, ["~> 2.16"]) else - s.add_dependency(%q, ["~> 2.11"]) + s.add_dependency(%q, ["~> 2.12"]) s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 3.0"]) + s.add_dependency(%q, ["~> 2.16"]) end else - s.add_dependency(%q, ["~> 2.11"]) + s.add_dependency(%q, ["~> 2.12"]) s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 3.0"]) + s.add_dependency(%q, ["~> 2.16"]) end end From 62207faee92c820da9fbc9cc6fe785461c2d826b Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 13 Jun 2012 20:09:40 -0300 Subject: [PATCH 1114/1492] Do not generate NOT IN (NULL) when empty right --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a6be451e6febe..cb8df8329a079 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -467,7 +467,7 @@ def visit_Arel_Nodes_InfixOperation o alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation def visit_Array o - o.empty? ? 'NULL' : o.map { |x| visit x }.join(', ') + o.map { |x| visit x }.join(', ') end def quote value, column = nil diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index f832bdf9259e1..58eec1f63bbe8 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -167,10 +167,10 @@ def dispatch } end - it "should turn empty right to NULL" do + it "should return IN () when empty right which is invalid SQL" do node = @attr.in [] @visitor.accept(node).must_be_like %{ - "users"."id" IN (NULL) + "users"."id" IN () } end @@ -255,10 +255,10 @@ def quote value, column = nil } end - it "should turn empty right to NULL" do + it "should return NOT IN () when empty right which is invalid SQL" do node = @attr.not_in [] @visitor.accept(node).must_be_like %{ - "users"."id" NOT IN (NULL) + "users"."id" NOT IN () } end From cbff1bcf385aba876933b2b4569826e9bc46183c Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Thu, 14 Jun 2012 11:45:51 -0400 Subject: [PATCH 1115/1492] Fix in [] to be false, in [] to be true This is in response to discussion on 62207fa --- lib/arel/visitors/to_sql.rb | 12 ++++++++++-- test/visitors/test_to_sql.rb | 12 ++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index cb8df8329a079..a350daa3da4ea 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -370,11 +370,19 @@ def visit_Arel_Table o end def visit_Arel_Nodes_In o - "#{visit o.left} IN (#{visit o.right})" + 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 - "#{visit o.left} NOT IN (#{visit o.right})" + 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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 58eec1f63bbe8..1caedacd45381 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -167,11 +167,9 @@ def dispatch } end - it "should return IN () when empty right which is invalid SQL" do + it "should return 1=0 when empty right which is always false" do node = @attr.in [] - @visitor.accept(node).must_be_like %{ - "users"."id" IN () - } + @visitor.accept(node).must_equal '1=0' end it 'can handle two dot ranges' do @@ -255,11 +253,9 @@ def quote value, column = nil } end - it "should return NOT IN () when empty right which is invalid SQL" do + it "should return 1=1 when empty right which is always true" do node = @attr.not_in [] - @visitor.accept(node).must_be_like %{ - "users"."id" NOT IN () - } + @visitor.accept(node).must_equal '1=1' end it 'can handle two dot ranges' do From b5432046134e8c8aa8cafa5960b387b4befff889 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 13 Jul 2012 11:09:47 +0100 Subject: [PATCH 1116/1492] Remove ArgumentError. It is untested. There is no `@frame` variable. Presumably it is supposed to be `@framing`, but changing that shows that some of the tests *are* setting frame twice. I don't see why this level of strictness is necessary. If someone disagrees, they should add a test for this behaviour and make the other tests pass. --- lib/arel/nodes/window.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index b54eb7fe64bed..383d6b877814c 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -17,7 +17,6 @@ def order *expr end def frame(expr) - raise ArgumentError, "Window frame cannot be set more than once" if @frame @framing = expr end @@ -75,4 +74,4 @@ def initialize(expr = nil) end end end -end \ No newline at end of file +end From 1de1041c00abff9cfc57837a80e12157901ff194 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 13 Jul 2012 11:19:17 +0100 Subject: [PATCH 1117/1492] Add Nodes::TableAlias#engine Eventually #engine should go away, but until that time, this means that Table and Nodes::TableAlias can be used more interchangeably. --- lib/arel/nodes/table_alias.rb | 4 ++++ test/nodes/test_table_alias.rb | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/nodes/test_table_alias.rb diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index b32f057117ca9..ebfcb58e640de 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -12,6 +12,10 @@ def [] name def table_name relation.respond_to?(:name) ? relation.name : name end + + def engine + relation.engine + end end end end diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb new file mode 100644 index 0000000000000..fef24bb19e592 --- /dev/null +++ b/test/nodes/test_table_alias.rb @@ -0,0 +1,16 @@ +require 'helper' +require 'ostruct' + +module Arel + module Nodes + describe 'table alias' do + it 'has an #engine which delegates to the relation' do + engine = Object.new + relation = OpenStruct.new(:engine => engine) + + node = TableAlias.new relation, :foo + node.engine.must_equal engine + end + end + end +end From 6e638bba594b6164190d2a6fb96ffa07a20b11f3 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 18 Aug 2012 22:33:25 -0400 Subject: [PATCH 1118/1492] Add equality to ALL THE THINGS (that matter) People are often trying to use ARel nodes inside ActiveRecord, and when they do so, lots of things can break, because ActiveRecord relies on Array#uniq and sometimes hash key equality to handle values that end up in wheres, havings, etc. By implementing equality for all the nodes, we should hopefully be able to prevent any nodes (even nodes containing other nodes) from failing an equality check they should otherwise pass, and alleviate many of these errors. Fixes #130 --- lib/arel/nodes/and.rb | 10 ++++ lib/arel/nodes/binary.rb | 11 +++++ lib/arel/nodes/extract.rb | 11 +++++ lib/arel/nodes/false.rb | 7 +++ lib/arel/nodes/function.rb | 11 +++++ lib/arel/nodes/insert_statement.rb | 12 +++++ lib/arel/nodes/named_function.rb | 9 ++++ lib/arel/nodes/select_core.rb | 20 ++++++++ lib/arel/nodes/select_statement.rb | 16 ++++++- lib/arel/nodes/terminal.rb | 7 +++ lib/arel/nodes/true.rb | 7 +++ lib/arel/nodes/unary.rb | 10 ++++ lib/arel/nodes/update_statement.rb | 15 ++++++ lib/arel/nodes/window.rb | 30 +++++++++++- lib/arel/table.rb | 13 +++++ test/nodes/test_and.rb | 20 ++++++++ test/nodes/test_as.rb | 12 +++++ test/nodes/test_ascending.rb | 10 ++++ test/nodes/test_bin.rb | 10 ++++ test/nodes/test_count.rb | 12 +++++ test/nodes/test_delete_statement.rb | 20 ++++++++ test/nodes/test_descending.rb | 10 ++++ test/nodes/test_distinct.rb | 20 ++++++++ test/nodes/test_equality.rb | 10 ++++ test/nodes/test_extract.rb | 14 ++++++ test/nodes/test_false.rb | 20 ++++++++ test/nodes/test_grouping.rb | 12 +++++ test/nodes/test_infix_operation.rb | 10 ++++ test/nodes/test_insert_statement.rb | 24 ++++++++++ test/nodes/test_named_function.rb | 16 +++++++ test/nodes/test_not.rb | 12 +++++ test/nodes/test_or.rb | 12 +++++ test/nodes/test_over.rb | 18 +++++++ test/nodes/test_select_core.rb | 38 +++++++++++++++ test/nodes/test_select_statement.rb | 36 ++++++++++++++ test/nodes/test_sql_literal.rb | 10 ++++ test/nodes/test_sum.rb | 12 +++++ test/nodes/test_table_alias.rb | 24 +++++++++- test/nodes/test_true.rb | 21 +++++++++ test/nodes/test_update_statement.rb | 40 ++++++++++++++++ test/nodes/test_window.rb | 73 +++++++++++++++++++++++++++++ test/test_attributes.rb | 12 +++++ test/test_table.rb | 24 ++++++++++ 43 files changed, 737 insertions(+), 4 deletions(-) create mode 100644 test/nodes/test_and.rb create mode 100644 test/nodes/test_distinct.rb create mode 100644 test/nodes/test_false.rb create mode 100644 test/nodes/test_true.rb create mode 100644 test/nodes/test_window.rb diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb index b4443c3d2760e..0d0fb3ee824c1 100644 --- a/lib/arel/nodes/and.rb +++ b/lib/arel/nodes/and.rb @@ -18,6 +18,16 @@ def left 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 diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index bcd46db39890d..d55c7a54784b9 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -13,6 +13,17 @@ def initialize_copy other @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{ diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb index 1c9ee78816303..92fbde62e122a 100644 --- a/lib/arel/nodes/extract.rb +++ b/lib/arel/nodes/extract.rb @@ -18,6 +18,17 @@ 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 diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb index 611e19633bb5d..6df70e43cef07 100644 --- a/lib/arel/nodes/false.rb +++ b/lib/arel/nodes/false.rb @@ -1,6 +1,13 @@ module 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 diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 5f6056a6b6034..90bbf4a77b46a 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -16,6 +16,17 @@ 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{ diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index 37c12f011a98f..518160cce4f95 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -14,6 +14,18 @@ def initialize_copy other @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 diff --git a/lib/arel/nodes/named_function.rb b/lib/arel/nodes/named_function.rb index 56669bf85853a..c792f0af985d1 100644 --- a/lib/arel/nodes/named_function.rb +++ b/lib/arel/nodes/named_function.rb @@ -7,6 +7,15 @@ 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 diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 9b8c4a2a1f915..3b400c768d200 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -37,6 +37,26 @@ def initialize_copy other @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 diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index c99842f22f794..32bdd7080c8ed 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -5,7 +5,6 @@ class SelectStatement < Arel::Nodes::Node attr_accessor :limit, :orders, :lock, :offset, :with def initialize cores = [SelectCore.new] - #puts caller @cores = cores @orders = [] @limit = nil @@ -19,6 +18,21 @@ def initialize_copy other @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 diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb index c6b4f4e1e2230..f4cdfdfe17273 100644 --- a/lib/arel/nodes/terminal.rb +++ b/lib/arel/nodes/terminal.rb @@ -1,6 +1,13 @@ module 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 diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb index 63dd5562e1a15..082963e5e6b99 100644 --- a/lib/arel/nodes/true.rb +++ b/lib/arel/nodes/true.rb @@ -1,6 +1,13 @@ module 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 diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 7828cceae54e0..42c31267dd543 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -7,6 +7,16 @@ class Unary < Arel::Nodes::Node 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{ diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index c08f1b2c5e450..d6831dc2424f5 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -18,6 +18,21 @@ def initialize_copy other @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 diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index 383d6b877814c..3c05f47f14878 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -32,6 +32,17 @@ 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 @@ -46,6 +57,15 @@ 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 @@ -60,7 +80,15 @@ def initialize(expr = nil) end end - class CurrentRow < Arel::Nodes::Node; 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) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 7a1983b3d2f24..6f1ab7e90fcdf 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -123,6 +123,19 @@ 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 diff --git a/test/nodes/test_and.rb b/test/nodes/test_and.rb new file mode 100644 index 0000000000000..88d6d61531d70 --- /dev/null +++ b/test/nodes/test_and.rb @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'And' do + describe 'equality' do + it 'is equal with equal ivars' do + array = [And.new(['foo', 'bar']), And.new(['foo', 'bar'])] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [And.new(['foo', 'bar']), And.new(['foo', 'baz'])] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff --git a/test/nodes/test_as.rb b/test/nodes/test_as.rb index 02cbe5f7b0112..b1dcccf7c7b3a 100644 --- a/test/nodes/test_as.rb +++ b/test/nodes/test_as.rb @@ -17,6 +17,18 @@ module Nodes assert_kind_of Arel::Nodes::SqlLiteral, as.right end end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [As.new('foo', 'bar'), As.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [As.new('foo', 'bar'), As.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end + end end end end diff --git a/test/nodes/test_ascending.rb b/test/nodes/test_ascending.rb index 0e2c4810c643b..63d758a8a82da 100644 --- a/test/nodes/test_ascending.rb +++ b/test/nodes/test_ascending.rb @@ -29,6 +29,16 @@ def test_descending? ascending = Ascending.new 'zomg' assert !ascending.descending? end + + def test_equality_with_same_ivars + array = [Ascending.new('zomg'), Ascending.new('zomg')] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [Ascending.new('zomg'), Ascending.new('zomg!')] + assert_equal 2, array.uniq.size + end end end end diff --git a/test/nodes/test_bin.rb b/test/nodes/test_bin.rb index 7f123eab13559..c370c5755f98c 100644 --- a/test/nodes/test_bin.rb +++ b/test/nodes/test_bin.rb @@ -18,6 +18,16 @@ def test_mysql_to_sql 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 diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index be53b8685586a..88d2a694c8f21 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -24,4 +24,16 @@ } end end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Arel::Nodes::Count.new('foo'), Arel::Nodes::Count.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Arel::Nodes::Count.new('foo'), Arel::Nodes::Count.new('foo!')] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_delete_statement.rb b/test/nodes/test_delete_statement.rb index 299bdd38eefe8..4bd5446ba2dc9 100644 --- a/test/nodes/test_delete_statement.rb +++ b/test/nodes/test_delete_statement.rb @@ -11,4 +11,24 @@ dolly.wheres.wont_be_same_as statement.wheres end end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::DeleteStatement.new + statement1.wheres = %w[a b c] + statement2 = Arel::Nodes::DeleteStatement.new + statement2.wheres = %w[a b c] + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::DeleteStatement.new + statement1.wheres = %w[a b c] + statement2 = Arel::Nodes::DeleteStatement.new + statement2.wheres = %w[1 2 3] + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_descending.rb b/test/nodes/test_descending.rb index 424f8298cd494..22b456fd8db4b 100644 --- a/test/nodes/test_descending.rb +++ b/test/nodes/test_descending.rb @@ -29,6 +29,16 @@ def test_descending? descending = Descending.new 'zomg' assert descending.descending? end + + def test_equality_with_same_ivars + array = [Descending.new('zomg'), Descending.new('zomg')] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [Descending.new('zomg'), Descending.new('zomg!')] + assert_equal 2, array.uniq.size + end end end end diff --git a/test/nodes/test_distinct.rb b/test/nodes/test_distinct.rb new file mode 100644 index 0000000000000..ffa8a68e6c77c --- /dev/null +++ b/test/nodes/test_distinct.rb @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'Distinct' do + describe 'equality' do + it 'is equal to other distinct nodes' do + array = [Distinct.new, Distinct.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [Distinct.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb index fb022f615f16e..79764cc7d361d 100644 --- a/test/nodes/test_equality.rb +++ b/test/nodes/test_equality.rb @@ -69,6 +69,16 @@ def quote_table_name(*args) @quote_count += 1; super; end node.right.must_equal right end end + + it 'is equal with equal ivars' do + array = [Equality.new('foo', 'bar'), Equality.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Equality.new('foo', 'bar'), Equality.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end end end end diff --git a/test/nodes/test_extract.rb b/test/nodes/test_extract.rb index bd1dfa4750dad..80bb465f24db8 100644 --- a/test/nodes/test_extract.rb +++ b/test/nodes/test_extract.rb @@ -16,4 +16,18 @@ } end end + + describe 'equality' do + it 'is equal with equal ivars' do + table = Arel::Table.new :users + array = [table[:attr].extract('foo'), table[:attr].extract('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + table = Arel::Table.new :users + array = [table[:attr].extract('foo'), table[:attr].extract('bar')] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_false.rb b/test/nodes/test_false.rb new file mode 100644 index 0000000000000..a2a88666803f0 --- /dev/null +++ b/test/nodes/test_false.rb @@ -0,0 +1,20 @@ +require 'helper' + +module Arel + module Nodes + describe 'False' do + describe 'equality' do + it 'is equal to other false nodes' do + array = [False.new, False.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [False.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end + diff --git a/test/nodes/test_grouping.rb b/test/nodes/test_grouping.rb index 3f84ac301e36a..b7aa51d37f5e7 100644 --- a/test/nodes/test_grouping.rb +++ b/test/nodes/test_grouping.rb @@ -7,6 +7,18 @@ module Nodes 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 diff --git a/test/nodes/test_infix_operation.rb b/test/nodes/test_infix_operation.rb index 3d2eb0d9c6321..b7b6b02d0faca 100644 --- a/test/nodes/test_infix_operation.rb +++ b/test/nodes/test_infix_operation.rb @@ -25,6 +25,16 @@ def test_opertaion_ordering assert_equal operation, ordering.expr assert ordering.descending? end + + def test_equality_with_same_ivars + array = [InfixOperation.new(:+, 1, 2), InfixOperation.new(:+, 1, 2)] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [InfixOperation.new(:+, 1, 2), InfixOperation.new(:+, 1, 3)] + assert_equal 2, array.uniq.size + end end end end diff --git a/test/nodes/test_insert_statement.rb b/test/nodes/test_insert_statement.rb index ef37e5c871a84..e0a5696ea45ac 100644 --- a/test/nodes/test_insert_statement.rb +++ b/test/nodes/test_insert_statement.rb @@ -15,4 +15,28 @@ dolly.values.wont_be_same_as statement.values end end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::InsertStatement.new + statement1.columns = %w[a b c] + statement1.values = %w[x y z] + statement2 = Arel::Nodes::InsertStatement.new + statement2.columns = %w[a b c] + statement2.values = %w[x y z] + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::InsertStatement.new + statement1.columns = %w[a b c] + statement1.values = %w[x y z] + statement2 = Arel::Nodes::InsertStatement.new + statement2.columns = %w[a b c] + statement2.values = %w[1 2 3] + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_named_function.rb b/test/nodes/test_named_function.rb index 3e0b2c3972edb..9d16f9cbee1bd 100644 --- a/test/nodes/test_named_function.rb +++ b/test/nodes/test_named_function.rb @@ -25,6 +25,22 @@ def test_construct_with_alias assert_kind_of SqlLiteral, function.alias assert_equal 'wth', function.alias end + + def test_equality_with_same_ivars + array = [ + NamedFunction.new('omg', 'zomg', 'wth'), + NamedFunction.new('omg', 'zomg', 'wth') + ] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [ + NamedFunction.new('omg', 'zomg', 'wth'), + NamedFunction.new('zomg', 'zomg', 'wth') + ] + assert_equal 2, array.uniq.size + end end end end diff --git a/test/nodes/test_not.rb b/test/nodes/test_not.rb index c5bb0088c8ac8..a08d0374456ff 100644 --- a/test/nodes/test_not.rb +++ b/test/nodes/test_not.rb @@ -12,6 +12,18 @@ module Nodes node.expr.must_equal expr end end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Not.new('foo'), Not.new('foo')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Not.new('foo'), Not.new('baz')] + assert_equal 2, array.uniq.size + end + end end end end diff --git a/test/nodes/test_or.rb b/test/nodes/test_or.rb index 88115669d1d24..3e7bcc9379066 100644 --- a/test/nodes/test_or.rb +++ b/test/nodes/test_or.rb @@ -17,6 +17,18 @@ module Nodes oror.expr.right.must_equal right end end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [Or.new('foo', 'bar'), Or.new('foo', 'bar')] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [Or.new('foo', 'bar'), Or.new('foo', 'baz')] + assert_equal 2, array.uniq.size + end + end end end end diff --git a/test/nodes/test_over.rb b/test/nodes/test_over.rb index 0bdd665e564e6..0aac00b23034e 100644 --- a/test/nodes/test_over.rb +++ b/test/nodes/test_over.rb @@ -46,4 +46,22 @@ } end end + + describe 'equality' do + it 'is equal with equal ivars' do + array = [ + Arel::Nodes::Over.new('foo', 'bar'), + Arel::Nodes::Over.new('foo', 'bar') + ] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + array = [ + Arel::Nodes::Over.new('foo', 'bar'), + Arel::Nodes::Over.new('foo', 'baz') + ] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index 4382c79865e05..e4ed06b8531cf 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -26,6 +26,44 @@ def test_set_quantifier 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 diff --git a/test/nodes/test_select_statement.rb b/test/nodes/test_select_statement.rb index 8bbf7d174c725..3e4fcc0c079e6 100644 --- a/test/nodes/test_select_statement.rb +++ b/test/nodes/test_select_statement.rb @@ -10,4 +10,40 @@ dolly.cores.wont_be_same_as statement.cores end end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::SelectStatement.new %w[a b c] + statement1.offset = 1 + statement1.limit = 2 + statement1.lock = false + statement1.orders = %w[x y z] + statement1.with = 'zomg' + statement2 = Arel::Nodes::SelectStatement.new %w[a b c] + statement2.offset = 1 + statement2.limit = 2 + statement2.lock = false + statement2.orders = %w[x y z] + statement2.with = 'zomg' + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::SelectStatement.new %w[a b c] + statement1.offset = 1 + statement1.limit = 2 + statement1.lock = false + statement1.orders = %w[x y z] + statement1.with = 'zomg' + statement2 = Arel::Nodes::SelectStatement.new %w[a b c] + statement2.offset = 1 + statement2.limit = 2 + statement2.lock = false + statement2.orders = %w[x y z] + statement2.with = 'wth' + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index 54d1d4417f80d..9deb8e5d8d67d 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -31,6 +31,16 @@ module Nodes 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 diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb index 50f5c0f4b567e..d65cd31d4becf 100644 --- a/test/nodes/test_sum.rb +++ b/test/nodes/test_sum.rb @@ -9,4 +9,16 @@ } 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 diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb index fef24bb19e592..4aafd12b79dce 100644 --- a/test/nodes/test_table_alias.rb +++ b/test/nodes/test_table_alias.rb @@ -5,12 +5,32 @@ module Arel module Nodes describe 'table alias' do it 'has an #engine which delegates to the relation' do - engine = Object.new - relation = OpenStruct.new(:engine => engine) + engine = 'vroom' + relation = Table.new(:users, engine) node = TableAlias.new relation, :foo node.engine.must_equal engine end + + describe 'equality' do + it 'is equal with equal ivars' do + relation1 = Table.new(:users, 'vroom') + node1 = TableAlias.new relation1, :foo + relation2 = Table.new(:users, 'vroom') + node2 = TableAlias.new relation2, :foo + array = [node1, node2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + relation1 = Table.new(:users, 'vroom') + node1 = TableAlias.new relation1, :foo + relation2 = Table.new(:users, 'vroom') + node2 = TableAlias.new relation2, :bar + array = [node1, node2] + assert_equal 2, array.uniq.size + end + end end end end diff --git a/test/nodes/test_true.rb b/test/nodes/test_true.rb new file mode 100644 index 0000000000000..ed4743a63b382 --- /dev/null +++ b/test/nodes/test_true.rb @@ -0,0 +1,21 @@ +require 'helper' + +module Arel + module Nodes + describe 'True' do + describe 'equality' do + it 'is equal to other true nodes' do + array = [True.new, True.new] + assert_equal 1, array.uniq.size + end + + it 'is not equal with other nodes' do + array = [True.new, Node.new] + assert_equal 2, array.uniq.size + end + end + end + end +end + + diff --git a/test/nodes/test_update_statement.rb b/test/nodes/test_update_statement.rb index 8920e977b539e..920dc6e3efee8 100644 --- a/test/nodes/test_update_statement.rb +++ b/test/nodes/test_update_statement.rb @@ -15,4 +15,44 @@ dolly.values.wont_be_same_as statement.values end end + + describe 'equality' do + it 'is equal with equal ivars' do + statement1 = Arel::Nodes::UpdateStatement.new + statement1.relation = 'zomg' + statement1.wheres = 2 + statement1.values = false + statement1.orders = %w[x y z] + statement1.limit = 42 + statement1.key = 'zomg' + statement2 = Arel::Nodes::UpdateStatement.new + statement2.relation = 'zomg' + statement2.wheres = 2 + statement2.values = false + statement2.orders = %w[x y z] + statement2.limit = 42 + statement2.key = 'zomg' + array = [statement1, statement2] + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + statement1 = Arel::Nodes::UpdateStatement.new + statement1.relation = 'zomg' + statement1.wheres = 2 + statement1.values = false + statement1.orders = %w[x y z] + statement1.limit = 42 + statement1.key = 'zomg' + statement2 = Arel::Nodes::UpdateStatement.new + statement2.relation = 'zomg' + statement2.wheres = 2 + statement2.values = false + statement2.orders = %w[x y z] + statement2.limit = 42 + statement2.key = 'wth' + array = [statement1, statement2] + assert_equal 2, array.uniq.size + end + end end diff --git a/test/nodes/test_window.rb b/test/nodes/test_window.rb new file mode 100644 index 0000000000000..f09d16e4412d6 --- /dev/null +++ b/test/nodes/test_window.rb @@ -0,0 +1,73 @@ +require 'helper' + +module Arel + module Nodes + describe 'Window' do + describe 'equality' do + it 'is equal with equal ivars' do + window1 = Window.new + window1.orders = [1, 2] + window1.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 + + diff --git a/test/test_attributes.rb b/test/test_attributes.rb index 010d708859753..d0b00d4333010 100644 --- a/test/test_attributes.rb +++ b/test/test_attributes.rb @@ -10,6 +10,18 @@ module Arel 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 diff --git a/test/test_table.rb b/test/test_table.rb index 10355405135b5..5db8cdd6c067e 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -180,5 +180,29 @@ module Arel 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 From e032dabdb2adb34e3db8cd35e9f58bc0536475c1 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sun, 19 Aug 2012 07:58:32 -0400 Subject: [PATCH 1119/1492] Update manifest --- Manifest.txt | 6 ++++++ arel.gemspec | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 3f51c53c3749c..b70d706ba9e50 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -82,14 +82,17 @@ 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 @@ -102,7 +105,10 @@ 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 diff --git a/arel.gemspec b/arel.gemspec index aa5c66adfaa75..711f01e598b18 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,22 +2,22 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.2.20120530170952" + s.version = "3.0.2.20120819075748" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2012-05-30" + s.date = "2012-08-19" 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_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_equality.rb", "test/nodes/test_extract.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_update_statement.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.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 = "1.8.24" s.summary = "Arel is a SQL AST manager for Ruby" - s.test_files = ["test/attributes/test_attribute.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_equality.rb", "test/nodes/test_extract.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_update_statement.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.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 = 3 From 112617766915b0068027b4ac809dad8129c88e81 Mon Sep 17 00:00:00 2001 From: Dimko Date: Tue, 18 Sep 2012 12:27:33 +0400 Subject: [PATCH 1120/1492] added a visitor for Set objects --- lib/arel/visitors/depth_first.rb | 1 + lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/to_sql.rb | 1 + test/visitors/test_depth_first.rb | 8 ++++++++ test/visitors/test_to_sql.rb | 5 +++++ 5 files changed, 16 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 24c435ad1daca..2894bea19c7d6 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -161,6 +161,7 @@ def visit_Arel_Nodes_UpdateStatement o def visit_Array o o.each { |i| visit i } end + alias :visit_Set :visit_Array def visit_Hash o o.each { |k,v| visit(k); visit(v) } diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 8a83ebf48effe..9bf9f88d18418 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -212,6 +212,7 @@ def visit_Array o edge(i) { visit x } end end + alias :visit_Set :visit_Array def visit_edge o, method edge(method) { visit o.send(method) } diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a350daa3da4ea..6dd652a709421 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -477,6 +477,7 @@ def visit_Arel_Nodes_InfixOperation o def visit_Array o o.map { |x| visit x }.join(', ') end + alias :visit_Set :visit_Array def quote value, column = nil @connection.quote value, column diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 05360ff6e8d2c..38d12b487c31d 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -1,4 +1,5 @@ require 'helper' +require 'set' module Arel module Visitors @@ -159,6 +160,13 @@ def test_array assert_equal [:a, :b, node, list], @collector.calls end + def test_set + node = Nodes::Or.new(:a, :b) + set = Set.new([node]) + @visitor.accept set + assert_equal [:a, :b, node, set], @collector.calls + end + def test_hash node = Nodes::Or.new(:a, :b) hash = { node => node } diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 1caedacd45381..2164e68cb759f 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,4 +1,5 @@ require 'helper' +require 'set' module Arel module Visitors @@ -114,6 +115,10 @@ def dispatch @visitor.accept({:a => 1}) end + it "should visit_Set" do + @visitor.accept Set.new([1, 2]) + end + it "should visit_BigDecimal" do @visitor.accept BigDecimal.new('2.14') end From efdda5030a460e8af58ef0f7f4cd5ce8d7f1b541 Mon Sep 17 00:00:00 2001 From: "Suraj N. Kurapati" Date: Fri, 21 Sep 2012 02:48:20 -0700 Subject: [PATCH 1121/1492] GH-139: some aggregations lacked DISTINCT emission --- lib/arel/visitors/to_sql.rb | 8 ++++---- test/visitors/test_to_sql.rb | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a350daa3da4ea..9c76772ef83e0 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -283,22 +283,22 @@ def visit_Arel_Nodes_Count o end def visit_Arel_Nodes_Sum o - "SUM(#{o.expressions.map { |x| + "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.expressions.map { |x| + "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.expressions.map { |x| + "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.expressions.map { |x| + "AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 1caedacd45381..dfe1d49a4e4c0 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -48,6 +48,45 @@ def dispatch 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) From 24ff439eeeef2b9b4ddf1b0ee360e78610fe30c8 Mon Sep 17 00:00:00 2001 From: "Suraj N. Kurapati" Date: Fri, 21 Sep 2012 03:12:49 -0700 Subject: [PATCH 1122/1492] GH-138: add Arel::SelectManager#projections method --- lib/arel/select_manager.rb | 4 ++++ test/test_select_manager.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index d20faa6eb3a4c..b5c5834a51b21 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -141,6 +141,10 @@ def project *projections self end + def projections + @ctx.projections + end + def projections= projections @ctx.projections = projections end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index d68deb3061c32..46a2cbbe9722f 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1033,6 +1033,14 @@ def test_join_sources 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 From c001fadd2f2f420267db809439581e388684e9de Mon Sep 17 00:00:00 2001 From: "Suraj N. Kurapati" Date: Sat, 22 Sep 2012 15:27:10 -0700 Subject: [PATCH 1123/1492] to_sql: add support for emitting SQL subqueries --- lib/arel/visitors/to_sql.rb | 4 ++++ test/visitors/test_to_sql.rb | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a350daa3da4ea..f5be934ba50ab 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -254,6 +254,10 @@ 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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 1caedacd45381..064f14739ce7d 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -126,6 +126,11 @@ def dispatch @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 %{ From e2322265cc84ddd204fddbc1398db42179f6a31b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 12 Oct 2012 16:19:39 -0700 Subject: [PATCH 1124/1492] adding some roflscale to the sql visitor --- lib/arel/visitors/to_sql.rb | 109 +++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 13 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b194319002fbd..ee6ca6fb92336 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -4,6 +4,54 @@ 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: + WINDOW = ' WINDOW ' # :nodoc: + AND = ' AND ' # :nodoc: + + DISTINCT = 'DISTINCT' # :nodoc: + attr_accessor :last_column def initialize connection @@ -23,7 +71,7 @@ def accept object def visit_Arel_Nodes_DeleteStatement o [ "DELETE FROM #{visit o.relation}", - ("WHERE #{o.wheres.map { |x| visit x }.join ' AND '}" unless o.wheres.empty?) + ("WHERE #{o.wheres.map { |x| visit x }.join AND}" unless o.wheres.empty?) ].compact.join ' ' end @@ -127,17 +175,52 @@ def visit_Arel_Nodes_SelectStatement o end def visit_Arel_Nodes_SelectCore o - [ - "SELECT", - (visit(o.top) if o.top), - (visit(o.set_quantifier) if o.set_quantifier), - ("#{o.projections.map { |x| visit x }.join ', '}" unless o.projections.empty?), - ("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), - ("WINDOW #{o.windows.map { |x| visit x }.join ', ' }" unless o.windows.empty?) - ].compact.join ' ' + 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 @@ -145,7 +228,7 @@ def visit_Arel_Nodes_Bin o end def visit_Arel_Nodes_Distinct o - 'DISTINCT' + DISTINCT end def visit_Arel_Nodes_DistinctOn o From 9367992b4cc274766d3dd099330bbe610c8038f4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 12 Oct 2012 16:36:30 -0700 Subject: [PATCH 1125/1492] more roflscaling strings in the visitor --- lib/arel/visitors/to_sql.rb | 34 ++++++++++++++++++++++++++-------- test/test_select_manager.rb | 4 ++-- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ee6ca6fb92336..76355a00dfc7b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -47,6 +47,7 @@ class ToSql < Arel::Visitors::Visitor SPACE = ' ' # :nodoc: COMMA = ', ' # :nodoc: GROUP_BY = ' GROUP BY ' # :nodoc: + ORDER_BY = ' ORDER BY ' # :nodoc: WINDOW = ' WINDOW ' # :nodoc: AND = ' AND ' # :nodoc: @@ -164,14 +165,31 @@ def visit_Arel_Nodes_Values o end def visit_Arel_Nodes_SelectStatement o - [ - (visit(o.with) if o.with), - 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.limit) if o.limit), - (visit(o.offset) if o.offset), - (visit(o.lock) if o.lock), - ].compact.join ' ' + 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 46a2cbbe9722f..407860718ca7e 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -119,7 +119,7 @@ def test_join_sources 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" + manager.to_sql.must_be_like "SELECT name FROM (SELECT * FROM zomg) foo" end end @@ -147,7 +147,7 @@ def test_join_sources manager1.from(as) manager1.to_sql.must_be_like %{ - SELECT lol FROM (SELECT * FROM "users" ) omg + SELECT lol FROM (SELECT * FROM "users") omg } end end From 890eaf4784fb6b4ee9e1a8f167f6a9b28525722e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 15 Oct 2012 11:28:44 -0700 Subject: [PATCH 1126/1492] avoid extra string objects in the inner join case --- lib/arel/visitors/to_sql.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 76355a00dfc7b..c4c2e6fe0f6e9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -455,7 +455,12 @@ def visit_Arel_Nodes_OuterJoin o end def visit_Arel_Nodes_InnerJoin o - "INNER JOIN #{visit o.left} #{visit o.right if o.right}" + s = "INNER JOIN #{visit o.left}" + if o.right + s << SPACE + s << visit(o.right) + end + s end def visit_Arel_Nodes_On o From ff86da4f930c290942bfcf1896eaee24fec0377b Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 2 Apr 2012 09:11:45 -0300 Subject: [PATCH 1127/1492] Remove some test warnings --- test/test_insert_manager.rb | 2 -- test/test_select_manager.rb | 3 --- 2 files changed, 5 deletions(-) diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 4878a33c90a74..2c5000fb8b7cd 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -10,7 +10,6 @@ module Arel describe 'insert' do it 'can create a Values node' do - table = Table.new(:users) manager = Arel::InsertManager.new Table.engine values = manager.create_values %w{ a b }, %w{ c d } @@ -20,7 +19,6 @@ module Arel end it 'allows sql literals' do - table = Table.new(:users) manager = Arel::InsertManager.new Table.engine manager.values = manager.create_values [Arel.sql('*')], %w{ a } manager.to_sql.must_be_like %{ diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 407860718ca7e..a449f78bd8bb1 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -672,7 +672,6 @@ def test_join_sources end it 'returns string join sql' do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new('hello') manager.join_sql.must_be_like %{ 'hello' } @@ -1140,7 +1139,6 @@ def test_join_sources describe 'source' do it 'returns the join source of the select core' do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.source.must_equal manager.ast.cores.last.source end @@ -1148,7 +1146,6 @@ def test_join_sources describe 'distinct' do it 'sets the quantifier' do - table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.distinct From d136d2d1fe1ff85530713a6fc802654bb2b7666f Mon Sep 17 00:00:00 2001 From: Robert Evans Date: Sat, 8 Dec 2012 09:03:52 -0800 Subject: [PATCH 1128/1492] Updated 3 gems: * MiniTest from 2.2 to 4.3.3 * Hoe from 2.10 to 3.3.1 * Rdoc from 3.10 to 3.12 --- Gemfile | 4 ++-- Rakefile | 2 +- arel.gemspec | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index 3c2680734cdfe..2befa94ae8a04 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ source :gemcutter -gem "minitest", "~>2.2", :group => [:development, :test] -gem "hoe", "~>2.10", :group => [:development, :test] +gem "minitest", "~>4.3.3", :group => [:development, :test] +gem "hoe", "~>3.3.1", :group => [:development, :test] # vim: syntax=ruby diff --git a/Rakefile b/Rakefile index bbf67415dab2c..74476cf85b640 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,5 @@ require "rubygems" -gem 'hoe', '>= 2.1.0' +gem 'hoe', '>= 3.3.1' require 'hoe' Hoe.plugins.delete :rubyforge diff --git a/arel.gemspec b/arel.gemspec index 711f01e598b18..a272ddd075556 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -23,17 +23,17 @@ Gem::Specification.new do |s| s.specification_version = 3 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 2.12"]) - s.add_development_dependency(%q, ["~> 3.10"]) - s.add_development_dependency(%q, ["~> 2.16"]) + s.add_development_dependency(%q, ["~> 4.3.3"]) + s.add_development_dependency(%q, ["~> 3.12"]) + s.add_development_dependency(%q, ["~> 3.3.1"]) else - s.add_dependency(%q, ["~> 2.12"]) - s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 2.16"]) + s.add_dependency(%q, ["~> 4.3.3"]) + s.add_dependency(%q, ["~> 3.12"]) + s.add_dependency(%q, ["~> 3.3.1"]) end else - s.add_dependency(%q, ["~> 2.12"]) - s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 2.16"]) + s.add_dependency(%q, ["~> 4.3.3"]) + s.add_dependency(%q, ["~> 3.12"]) + s.add_dependency(%q, ["~> 3.3.1"]) end end From 22b0dbe82cdc3c29c2e0036d1fa8f8d8f5530a5d Mon Sep 17 00:00:00 2001 From: Lew Parker Date: Thu, 13 Dec 2012 17:16:36 -0700 Subject: [PATCH 1129/1492] Make GROUP BY example more accurate and complete. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index afef04212a33e..70b378ff33c7a 100644 --- a/README.markdown +++ b/README.markdown @@ -54,7 +54,7 @@ What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel `GROUP BY` is called `group`: - users.group(users[:name]) # => SELECT * FROM users GROUP BY name + 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: From 78977c9c5fa6edd7eaa46cf8ff380b4e25825d5d Mon Sep 17 00:00:00 2001 From: tom Date: Tue, 8 Jan 2013 09:30:35 -0500 Subject: [PATCH 1130/1492] Add oracle paging optimization discussed in issue 99 --- lib/arel/visitors/oracle.rb | 2 +- test/visitors/test_oracle.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 1441a20dbc2d4..6a58a3cff2662 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -26,7 +26,7 @@ def visit_Arel_Nodes_SelectStatement o SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ ) - WHERE raw_rnum_ between #{offset.expr.to_i + 1 } and #{offset.expr.to_i + limit} + WHERE raw_rnum_ >= #{offset.expr.to_i + 1 } and rownum <= #{limit} eosql end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index af81f2058b489..42bfaadf8abf9 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -103,7 +103,7 @@ module Visitors SELECT raw_sql_.*, rownum raw_rnum_ FROM (SELECT) raw_sql_ ) - WHERE raw_rnum_ between 11 and 20 + WHERE raw_rnum_ >= 11 and rownum <= 10 } end From 9c514f39bd040c45ffa7df43bab24c2a0c88c6e3 Mon Sep 17 00:00:00 2001 From: Noemj Date: Tue, 29 Jan 2013 21:39:36 +0200 Subject: [PATCH 1131/1492] Denied the quoting of SqlLiterals --- lib/arel/visitors/to_sql.rb | 1 + test/test_update_manager.rb | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index c4c2e6fe0f6e9..050a9b2e634d2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -589,6 +589,7 @@ def visit_Array o end def quote value, column = nil + return value if Arel::Nodes::SqlLiteral === value @connection.quote value, column end diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index f9704af425add..1dd881b259a30 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -8,6 +8,14 @@ module Arel 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 From e6ec4ab87eb324c138da250941a28ec7ebf0f6b8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 30 Jan 2013 10:54:52 -0800 Subject: [PATCH 1132/1492] fixing bind param visiting in the dot visitor --- lib/arel/visitors/dot.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 8a83ebf48effe..e309bd6f12fc1 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -65,7 +65,6 @@ def unary o visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary - alias :visit_Arel_Nodes_BindParam :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary @@ -195,6 +194,7 @@ def visit_String o 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 From b4fd431b973e7fc50d3cbf0432b3d8272ac65f0e Mon Sep 17 00:00:00 2001 From: Noemj Date: Mon, 4 Feb 2013 10:29:41 +0200 Subject: [PATCH 1133/1492] Fixed the bind param visiting for mysql2 prepared statements case --- lib/arel/visitors/bind_visitor.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb index 0f1e38315bec7..77f91d9451f59 100644 --- a/lib/arel/visitors/bind_visitor.rb +++ b/lib/arel/visitors/bind_visitor.rb @@ -12,6 +12,15 @@ def accept node, &block 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 @@ -19,6 +28,7 @@ def visit_Arel_Nodes_BindParam o super end end + end end end From 30a74c09e794a46eac6bd0719f1b0333704317b2 Mon Sep 17 00:00:00 2001 From: Noemj Date: Tue, 5 Feb 2013 15:06:04 +0200 Subject: [PATCH 1134/1492] Added unit test for the mysql2 bind substitution --- test/visitors/test_bind_visitor.rb | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index 92e5d1612cb68..dbcfb67df53e5 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -1,9 +1,28 @@ require 'helper' require 'arel/visitors/bind_visitor' +require 'support/fake_record' module Arel module Visitors - class TestBindVisitor < MiniTest::Unit::TestCase + 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 From 0df9ab8442fc4a33b1962a49cebd66a3d1b0faf5 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Tue, 19 Feb 2013 11:44:31 -0500 Subject: [PATCH 1135/1492] Support Float::INFINITY in ranges --- lib/arel/predications.rb | 20 ++++++++++++++++++-- test/visitors/test_to_sql.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index e3f72d46a27fe..c485de07e3cca 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -29,7 +29,15 @@ def in other when Arel::SelectManager Arel::Nodes::In.new(self, other.ast) when Range - if other.exclude_end? + 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] @@ -54,7 +62,15 @@ def not_in other when Arel::SelectManager Arel::Nodes::NotIn.new(self, other.ast) when Range - if other.exclude_end? + 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 diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 08cf4566d117b..d3e4dae963ec5 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -230,6 +230,23 @@ def dispatch } 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')) @@ -316,6 +333,23 @@ def quote value, column = nil } 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')) From 7402f90366f18d1794217e808c9a324e0d738870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 25 Feb 2013 18:20:47 -0300 Subject: [PATCH 1136/1492] No need to test against 1.8 --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e76e753520449..d21ff3a18cd10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,10 @@ script: "rake test" rvm: - - 1.8.7 - - rbx-18mode - rbx-19mode - jruby - 1.9.2 - 1.9.3 - - ruby-head + - 2.0.0 notifications: email: false irc: From 9798938927f3c43e02f79bdd825a42e28d105394 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 25 Feb 2013 13:24:43 -0800 Subject: [PATCH 1137/1492] bumping to beta1 --- arel.gemspec | 28 ++++++++++++++-------------- lib/arel.rb | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index a272ddd075556..8088e1e411efc 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "3.0.2.20120819075748" + s.version = "4.0.0.beta1.20130225132415" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + 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 = "2012-08-19" + s.date = "2013-02-25" 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"] @@ -15,25 +15,25 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" - s.rubygems_version = "1.8.24" + s.rubygems_version = "2.0.0" 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 = 3 + s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 4.3.3"]) - s.add_development_dependency(%q, ["~> 3.12"]) - s.add_development_dependency(%q, ["~> 3.3.1"]) + 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.3.3"]) - s.add_dependency(%q, ["~> 3.12"]) - s.add_dependency(%q, ["~> 3.3.1"]) + 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.3.3"]) - s.add_dependency(%q, ["~> 3.12"]) - s.add_dependency(%q, ["~> 3.3.1"]) + s.add_dependency(%q, ["~> 4.6"]) + s.add_dependency(%q, ["~> 3.10"]) + s.add_dependency(%q, ["~> 3.5"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index 6d7aec64b1d8e..1777e10390a7d 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -32,7 +32,7 @@ #### module Arel - VERSION = '3.0.2' + VERSION = '4.0.0.beta1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From df838b9f94aa971278617f9cf5d0ad3e3e42c53d Mon Sep 17 00:00:00 2001 From: Vladislav Bogomolov Date: Tue, 5 Mar 2013 17:10:42 +0400 Subject: [PATCH 1138/1492] Updated minitest to 4.6.2 and RDoc to 4.0.0 --- Gemfile | 2 +- arel.gemspec | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 2befa94ae8a04..4add8869d3a9b 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ source :gemcutter -gem "minitest", "~>4.3.3", :group => [:development, :test] +gem "minitest", "~>4.6.2", :group => [:development, :test] gem "hoe", "~>3.3.1", :group => [:development, :test] # vim: syntax=ruby diff --git a/arel.gemspec b/arel.gemspec index 8088e1e411efc..1d2544254d146 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -24,16 +24,16 @@ Gem::Specification.new do |s| 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, ["~> 4.0"]) s.add_development_dependency(%q, ["~> 3.5"]) else s.add_dependency(%q, ["~> 4.6"]) - s.add_dependency(%q, ["~> 3.10"]) + s.add_dependency(%q, ["~> 4.0"]) s.add_dependency(%q, ["~> 3.5"]) end else s.add_dependency(%q, ["~> 4.6"]) - s.add_dependency(%q, ["~> 3.10"]) + s.add_dependency(%q, ["~> 4.0"]) s.add_dependency(%q, ["~> 3.5"]) end end From 0ec3a9271f967c9ee063bf8184f06dbbd57a57d1 Mon Sep 17 00:00:00 2001 From: Gasparyan A Date: Tue, 5 Mar 2013 22:11:51 +0400 Subject: [PATCH 1139/1492] Added License block to README.md --- README.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.markdown b/README.markdown index 70b378ff33c7a..89a422d15f2d4 100644 --- a/README.markdown +++ b/README.markdown @@ -116,3 +116,7 @@ The `parent_id` column is a foreign key from the `comments` table to itself. Now # => 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). From 425925b1c6433309fcbaa7242df39394b70280a6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 14 Mar 2013 22:22:34 -0700 Subject: [PATCH 1140/1492] call the columns hash method --- lib/arel/visitors/to_sql.rb | 6 +++--- test/support/fake_record.rb | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 050a9b2e634d2..d0a05fac7e08e 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -147,11 +147,11 @@ def column_for attr return nil unless table_exists? table - column_cache[table][name] + column_cache(table)[name] end - def column_cache - @schema_cache.columns_hash + def column_cache(table) + @schema_cache.columns_hash(table) end def visit_Arel_Nodes_Values o diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 79182f86bdebd..58883e43cd59e 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -3,7 +3,7 @@ class Column < Struct.new(:name, :type) end class Connection - attr_reader :tables, :columns_hash + attr_reader :tables attr_accessor :visitor def initialize(visitor = nil) @@ -31,6 +31,10 @@ def initialize(visitor = nil) @visitor = visitor end + def columns_hash table_name + @columns_hash[table_name] + end + def primary_key name @primary_keys[name.to_s] end From 026695ae4068d2714ba5ff77d712b99769bf72e9 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 14 Mar 2013 23:07:17 -0700 Subject: [PATCH 1141/1492] bumping to beta2 --- arel.gemspec | 12 ++++++------ lib/arel.rb | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 1d2544254d146..7cd92e1561a62 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "4.0.0.beta1.20130225132415" + s.version = "4.0.0.beta2.20130314230643" 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-02-25" + s.date = "2013-03-15" 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"] @@ -15,7 +15,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" - s.rubygems_version = "2.0.0" + 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"] @@ -24,16 +24,16 @@ Gem::Specification.new do |s| 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, ["~> 4.0"]) + 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, ["~> 4.0"]) + s.add_dependency(%q, ["~> 3.10"]) s.add_dependency(%q, ["~> 3.5"]) end else s.add_dependency(%q, ["~> 4.6"]) - s.add_dependency(%q, ["~> 4.0"]) + s.add_dependency(%q, ["~> 3.10"]) s.add_dependency(%q, ["~> 3.5"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index 1777e10390a7d..df7daf5d57501 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -32,7 +32,7 @@ #### module Arel - VERSION = '4.0.0.beta1' + VERSION = '4.0.0.beta2' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 53990486fa488d26ee95b6d452b0a76b08a446fa Mon Sep 17 00:00:00 2001 From: Eduardo Mourao Date: Fri, 15 Mar 2013 16:39:50 -0300 Subject: [PATCH 1142/1492] Revert issue #99 fixes There are two commits involving issue #99 which should be reverted. First of all, #99 is not an issue in Arel at all. Second, the fix provides pretty much destroys the purpose of pagination by cause full table scans. The original code (it seems I can't simply revert the commits) is 900 times slower than this one. ``` SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (SELECT "LANCAMENTOS".* FROM "LANCAMENTOS" ) raw_sql_ ) WHERE raw_rnum_ between 1 and 30 ---------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 4636K| 2701M| 23442 (2)| 00:04:42 | |* 1 | VIEW | | 4636K| 2701M| 23442 (2)| 00:04:42 | | 2 | COUNT | | | | | | | 3 | TABLE ACCESS FULL| LANCAMENTOS | 4636K| 738M| 23442 (2)| 00:04:42 | ----------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("RAW_RNUM_"<=30 AND "RAW_RNUM_">=1) Statistics ----------------------------------------------------------- 4 user calls 13 physical read total multi block requests 202588160 physical read total bytes 202588160 cell physical IO interconnect bytes 0 commit cleanout failures: block lost 0 IMU commits 0 IMU Flushes 0 IMU contention 0 IMU bind flushes 0 IMU mbu flush SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (SELECT "LANCAMENTOS".* FROM "LANCAMENTOS" ) raw_sql_ WHERE rownum <= 30 ) WHERE raw_rnum_ >= 0 ----------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 30 | 18330 | 2 (0)| 00:00:01 | |* 1 | VIEW | | 30 | 18330 | 2 (0)| 00:00:01 | |* 2 | COUNT STOPKEY | | | | | | | 3 | TABLE ACCESS FULL| LANCAMENTOS | 30 | 5010 | 2 (0)| 00:00:01 | ----------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("RAW_RNUM_">=0) 2 - filter(ROWNUM<=30) Statistics ----------------------------------------------------------- 4 user calls 0 physical read total multi block requests 0 physical read total bytes 0 cell physical IO interconnect bytes 0 commit cleanout failures: block lost 0 IMU commits 0 IMU Flushes 0 IMU contention 0 IMU bind flushes 0 IMU mbu flush ``` --- lib/arel/visitors/oracle.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 6a58a3cff2662..375f7dbfe9570 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -25,8 +25,9 @@ def visit_Arel_Nodes_SelectStatement o SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ + WHERE rownum <= #{offset.expr.to_i + limit} ) - WHERE raw_rnum_ >= #{offset.expr.to_i + 1 } and rownum <= #{limit} + WHERE #{visit offset} eosql end From 47d530218968ca7bfaeab08c561cecf99e880260 Mon Sep 17 00:00:00 2001 From: Eduardo Mourao Date: Fri, 15 Mar 2013 18:19:33 -0300 Subject: [PATCH 1143/1492] Update test_oracle.rb --- test/visitors/test_oracle.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 42bfaadf8abf9..421e9951e6544 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -102,8 +102,9 @@ module Visitors SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (SELECT) raw_sql_ + WHERE rownum <= 20 ) - WHERE raw_rnum_ >= 11 and rownum <= 10 + WHERE raw_rnum_ > 10 } end From 6b3bc33e1cb85cb55d1d15c6aa9cf241bd8c2ee2 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 14 Apr 2013 20:39:07 +0200 Subject: [PATCH 1144/1492] ActiveRecord -> Active Record As per the Rails documentation guidelines. --- History.txt | 4 ++-- README.markdown | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.txt b/History.txt index 66e2c73be76a2..88cfecd5eacd3 100644 --- a/History.txt +++ b/History.txt @@ -184,7 +184,7 @@ * Introduced "SQL compilers" for query generation. * Added support for Oracle (Raimonds Simanovskis) and IBM/DB (Praveen Devarao). - * Improvements to give better support to ActiveRecord. + * Improvements to give better support to Active Record. == 0.2.1 / 2010-02-05 @@ -195,7 +195,7 @@ == 0.2.0 / 2010-01-31 * Ruby 1.9 compatibility - * Many improvements to support the Arel integration into ActiveRecord (see `git log v0.1.0..v0.2.0`) + * 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 diff --git a/README.markdown b/README.markdown index 70b378ff33c7a..d7ed9004fd1b5 100644 --- a/README.markdown +++ b/README.markdown @@ -15,7 +15,7 @@ database compatibility and query generation. ## Status -For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. +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 From 8c21663f655b9a67069c03094e5da2dc8a674eb3 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Sun, 14 Apr 2013 20:45:31 +0200 Subject: [PATCH 1145/1492] ARel -> Arel The project uses "Arel" most of the time, but there were a few "ARel" here and there. I checked with @brynary back in 2010 to pick one for the Rails documentation guidelines and "Arel" was chosen and documented. This patch chooses "Arel" vs "ARel" based on that. --- History.txt | 2 +- README.markdown | 4 ++-- lib/arel/crud.rb | 6 +++--- lib/arel/select_manager.rb | 4 ++-- lib/arel/table.rb | 2 +- lib/arel/visitors/dot.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/History.txt b/History.txt index 88cfecd5eacd3..b24faf3267988 100644 --- a/History.txt +++ b/History.txt @@ -144,7 +144,7 @@ * Deprecations - * Support for Subclasses of core classes will be removed in ARel version + * Support for Subclasses of core classes will be removed in Arel version 2.2.0 == 2.0.4 diff --git a/README.markdown b/README.markdown index d7ed9004fd1b5..384cc74451c24 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -# 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) +# 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 @@ -19,7 +19,7 @@ For the moment, Arel uses Active Record's connection adapters to connect to the ## A Gentle Introduction -Generating a query with ARel is simple. For example, in order to produce +Generating a query with Arel is simple. For example, in order to produce SELECT * FROM users diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 6c29d5fee4a72..e8e78a381c7e8 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -22,7 +22,7 @@ def compile_update values def update values if $VERBOSE warn <<-eowarn -update (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please +update (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_update` eowarn end @@ -45,7 +45,7 @@ def create_insert def insert values if $VERBOSE warn <<-eowarn -insert (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please +insert (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_insert` eowarn end @@ -62,7 +62,7 @@ def compile_delete def delete if $VERBOSE warn <<-eowarn -delete (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please +delete (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_delete` eowarn end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index b5c5834a51b21..ee9d34a514736 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -170,7 +170,7 @@ def orders end def wheres - warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in ARel 4.0.0 with no replacement" + 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 @@ -276,7 +276,7 @@ def to_a # :nodoc: def insert values if $VERBOSE warn <<-eowarn -insert (#{caller.first}) is deprecated and will be removed in ARel 4.0.0. Please +insert (#{caller.first}) is deprecated and will be removed in Arel 4.0.0. Please switch to `compile_insert` eowarn end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 6f1ab7e90fcdf..5fb1254d17125 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -32,7 +32,7 @@ def initialize name, engine = Table.engine def primary_key if $VERBOSE warn <<-eowarn -primary_key (#{caller.first}) is deprecated and will be removed in ARel 4.0.0 +primary_key (#{caller.first}) is deprecated and will be removed in Arel 4.0.0 eowarn end @primary_key ||= begin diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index e309bd6f12fc1..843266f85a828 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -254,7 +254,7 @@ def quote string end def to_dot - "digraph \"ARel\" {\nnode [width=0.375,height=0.25,shape=record];\n" + + "digraph \"Arel\" {\nnode [width=0.375,height=0.25,shape=record];\n" + @nodes.map { |node| label = "#{node.name}" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d0a05fac7e08e..1a4826bcd2ced 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -96,7 +96,7 @@ def visit_Arel_Nodes_UpdateStatement o 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 +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 From 85b0b19c11e971aac0c8f40ee50be4fe127386c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 18 Apr 2013 13:38:39 -0300 Subject: [PATCH 1146/1492] Updage Gemfile to use https URL --- Gemfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 4add8869d3a9b..bfada66749bfa 100644 --- a/Gemfile +++ b/Gemfile @@ -2,10 +2,11 @@ # DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`. -source :gemcutter +source "https://rubygems.org/" -gem "minitest", "~>4.6.2", :group => [:development, :test] -gem "hoe", "~>3.3.1", :group => [:development, :test] +gem "minitest", "~>4.4", :group => [:development, :test] +gem "rdoc", "~>4.0", :group => [:development, :test] +gem "hoe", "~>3.5", :group => [:development, :test] # vim: syntax=ruby From 3ef63ac5366000b232ca5fe0848de9db9a3c1f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 18 Apr 2013 13:40:43 -0300 Subject: [PATCH 1147/1492] Release 4.0.0 --- arel.gemspec | 4 ++-- lib/arel.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 7cd92e1561a62..1a9799e4009cb 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,11 +2,11 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "4.0.0.beta2.20130314230643" + 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-03-15" + 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"] diff --git a/lib/arel.rb b/lib/arel.rb index df7daf5d57501..f2f046f672673 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -32,7 +32,7 @@ #### module Arel - VERSION = '4.0.0.beta2' + VERSION = '4.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 68a95542e1a7a79d9777223fbffd2b982fed0268 Mon Sep 17 00:00:00 2001 From: Ernie Miller Date: Sat, 16 Mar 2013 19:20:11 -0400 Subject: [PATCH 1148/1492] Make visitors threadsafe by removing @last_column The last_column feature of the ToSql visitor and its descendants is what enabled quoting based on the column last visited -- in other words, if you have a standard condition like an equality with a string attribute on the left side and an integer on the right side, then when ARel visits the node, it'll first visit the left side attribute, setting the column of the string attribute as the last column, and resulting in the right side of the condition getting the appropriate quoting. The downside is that this means that visitors can't be shared between threads, because of the state mutation. It also makes for some really weird behavior in the event that the visitor visits a node that happens to contain an attribute you weren't expecting to be there, since it'll potentially quote something based on that attribute. So, it prevents reversing an equality condition. column = value will work, but not value = column, since the last column wouldn't be the column you're hoping for. This is a first pass at fixing this by changing the signature of the visit methods to accept the currently-relevant attribute, if any. --- lib/arel/visitors/bind_visitor.rb | 8 +- lib/arel/visitors/depth_first.rb | 112 +++++----- lib/arel/visitors/dot.rb | 150 ++++++------- lib/arel/visitors/ibm_db.rb | 4 +- lib/arel/visitors/informix.rb | 34 +-- lib/arel/visitors/join_sql.rb | 4 +- lib/arel/visitors/mssql.rb | 24 +- lib/arel/visitors/mysql.rb | 30 +-- lib/arel/visitors/oracle.rb | 34 +-- lib/arel/visitors/order_clauses.rb | 4 +- lib/arel/visitors/postgresql.rb | 12 +- lib/arel/visitors/sqlite.rb | 4 +- lib/arel/visitors/to_sql.rb | 338 +++++++++++++++-------------- lib/arel/visitors/visitor.rb | 4 +- lib/arel/visitors/where_sql.rb | 4 +- test/visitors/test_to_sql.rb | 2 +- 16 files changed, 386 insertions(+), 382 deletions(-) diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb index 77f91d9451f59..77b3f8237bfbf 100644 --- a/lib/arel/visitors/bind_visitor.rb +++ b/lib/arel/visitors/bind_visitor.rb @@ -13,22 +13,22 @@ def accept node, &block private - def visit_Arel_Nodes_Assignment o + def visit_Arel_Nodes_Assignment o, a if o.right.is_a? Arel::Nodes::BindParam - "#{visit o.left} = #{visit o.right}" + "#{visit o.left, a} = #{visit o.right, a}" else super end end - def visit_Arel_Nodes_BindParam o + def visit_Arel_Nodes_BindParam o, a if @block @block.call else super end end - + end end end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 24c435ad1daca..67cdecfa369a8 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -7,13 +7,13 @@ def initialize block = nil private - def visit o + def visit o, a = nil super @block.call o end - def unary o - visit o.expr + def unary o, a + visit o.expr, a end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary @@ -28,10 +28,10 @@ def unary o alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary - def function o - visit o.expressions - visit o.alias - visit o.distinct + def function o, a + visit o.expressions, a + visit o.alias, a + visit o.distinct, a end alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Exists :function @@ -39,27 +39,27 @@ def function o 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 + def visit_Arel_Nodes_NamedFunction o, a + visit o.name, a + visit o.expressions, a + visit o.distinct, a + visit o.alias, a end - def visit_Arel_Nodes_Count o - visit o.expressions - visit o.alias - visit o.distinct + def visit_Arel_Nodes_Count o, a + visit o.expressions, a + visit o.alias, a + visit o.distinct, a end - def nary o - o.children.each { |child| visit child } + def nary o, a + o.children.each { |child| visit child, a } end alias :visit_Arel_Nodes_And :nary - def binary o - visit o.left - visit o.right + def binary o, a + visit o.left, a + visit o.right, a end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary @@ -83,13 +83,13 @@ def binary o alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary - def visit_Arel_Nodes_StringJoin o - visit o.left + def visit_Arel_Nodes_StringJoin o, a + visit o.left, a end - def visit_Arel_Attribute o - visit o.relation - visit o.name + def visit_Arel_Attribute o, a + visit o.relation, a + visit o.name, a end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute @@ -99,11 +99,11 @@ def visit_Arel_Attribute o alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute alias :visit_Arel_Attributes_Decimal :visit_Arel_Attribute - def visit_Arel_Table o - visit o.name + def visit_Arel_Table o, a + visit o.name, a end - def terminal o + def terminal o, a end alias :visit_ActiveSupport_Multibyte_Chars :terminal alias :visit_ActiveSupport_StringInquirer :terminal @@ -127,43 +127,43 @@ def terminal o alias :visit_Time :terminal alias :visit_TrueClass :terminal - def visit_Arel_Nodes_InsertStatement o - visit o.relation - visit o.columns - visit o.values + def visit_Arel_Nodes_InsertStatement o, a + visit o.relation, a + visit o.columns, a + visit o.values, a 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 + def visit_Arel_Nodes_SelectCore o, a + visit o.projections, a + visit o.source, a + visit o.wheres, a + visit o.groups, a + visit o.windows, a + visit o.having, a end - def visit_Arel_Nodes_SelectStatement o - visit o.cores - visit o.orders - visit o.limit - visit o.lock - visit o.offset + def visit_Arel_Nodes_SelectStatement o, a + visit o.cores, a + visit o.orders, a + visit o.limit, a + visit o.lock, a + visit o.offset, a end - def visit_Arel_Nodes_UpdateStatement o - visit o.relation - visit o.values - visit o.wheres - visit o.orders - visit o.limit + def visit_Arel_Nodes_UpdateStatement o, a + visit o.relation, a + visit o.values, a + visit o.wheres, a + visit o.orders, a + visit o.limit, a end - def visit_Array o - o.each { |i| visit i } + def visit_Array o, a + o.each { |i| visit i, a } end - def visit_Hash o - o.each { |k,v| visit(k); visit(v) } + def visit_Hash o, a + o.each { |k,v| visit(k, a); visit(v, a) } end end end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 843266f85a828..82b8c771e4a76 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,41 +28,41 @@ def accept object end private - def visit_Arel_Nodes_Ordering o - visit_edge o, "expr" + def visit_Arel_Nodes_Ordering o, a + visit_edge o, a, "expr" end - def visit_Arel_Nodes_TableAlias o - visit_edge o, "name" - visit_edge o, "relation" + def visit_Arel_Nodes_TableAlias o, a + visit_edge o, a, "name" + visit_edge o, a, "relation" end - def visit_Arel_Nodes_Count o - visit_edge o, "expressions" - visit_edge o, "distinct" + def visit_Arel_Nodes_Count o, a + visit_edge o, a, "expressions" + visit_edge o, a, "distinct" end - def visit_Arel_Nodes_Values o - visit_edge o, "expressions" + def visit_Arel_Nodes_Values o, a + visit_edge o, a, "expressions" end - def visit_Arel_Nodes_StringJoin o - visit_edge o, "left" + def visit_Arel_Nodes_StringJoin o, a + visit_edge o, a, "left" end - def visit_Arel_Nodes_InnerJoin o - visit_edge o, "left" - visit_edge o, "right" + def visit_Arel_Nodes_InnerJoin o, a + visit_edge o, a, "left" + visit_edge o, a, "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" + def visit_Arel_Nodes_DeleteStatement o, a + visit_edge o, a, "relation" + visit_edge o, a, "wheres" end - def unary o - visit_edge o, "expr" + def unary o, a + visit_edge o, a, "expr" end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary @@ -78,23 +78,23 @@ def unary o alias :visit_Arel_Nodes_Rows :unary alias :visit_Arel_Nodes_Range :unary - def window o - visit_edge o, "orders" - visit_edge o, "framing" + def window o, a + visit_edge o, a, "orders" + visit_edge o, a, "framing" end alias :visit_Arel_Nodes_Window :window - def named_window o - visit_edge o, "orders" - visit_edge o, "framing" - visit_edge o, "name" + def named_window o, a + visit_edge o, a, "orders" + visit_edge o, a, "framing" + visit_edge o, a, "name" end alias :visit_Arel_Nodes_NamedWindow :named_window - def function o - visit_edge o, "expressions" - visit_edge o, "distinct" - visit_edge o, "alias" + def function o, a + visit_edge o, a, "expressions" + visit_edge o, a, "distinct" + visit_edge o, a, "alias" end alias :visit_Arel_Nodes_Exists :function alias :visit_Arel_Nodes_Min :function @@ -102,52 +102,52 @@ def function o alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Sum :function - def extract o - visit_edge o, "expressions" - visit_edge o, "alias" + def extract o, a + visit_edge o, a, "expressions" + visit_edge o, a, "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" + def visit_Arel_Nodes_NamedFunction o, a + visit_edge o, a, "name" + visit_edge o, a, "expressions" + visit_edge o, a, "distinct" + visit_edge o, a, "alias" end - def visit_Arel_Nodes_InsertStatement o - visit_edge o, "relation" - visit_edge o, "columns" - visit_edge o, "values" + def visit_Arel_Nodes_InsertStatement o, a + visit_edge o, a, "relation" + visit_edge o, a, "columns" + visit_edge o, a, "values" end - def visit_Arel_Nodes_SelectCore o - visit_edge o, "source" - visit_edge o, "projections" - visit_edge o, "wheres" - visit_edge o, "windows" + def visit_Arel_Nodes_SelectCore o, a + visit_edge o, a, "source" + visit_edge o, a, "projections" + visit_edge o, a, "wheres" + visit_edge o, a, "windows" end - def visit_Arel_Nodes_SelectStatement o - visit_edge o, "cores" - visit_edge o, "limit" - visit_edge o, "orders" - visit_edge o, "offset" + def visit_Arel_Nodes_SelectStatement o, a + visit_edge o, a, "cores" + visit_edge o, a, "limit" + visit_edge o, a, "orders" + visit_edge o, a, "offset" end - def visit_Arel_Nodes_UpdateStatement o - visit_edge o, "relation" - visit_edge o, "wheres" - visit_edge o, "values" + def visit_Arel_Nodes_UpdateStatement o, a + visit_edge o, a, "relation" + visit_edge o, a, "wheres" + visit_edge o, a, "values" end - def visit_Arel_Table o - visit_edge o, "name" + def visit_Arel_Table o, a + visit_edge o, a, "name" end - def visit_Arel_Attribute o - visit_edge o, "relation" - visit_edge o, "name" + def visit_Arel_Attribute o, a + visit_edge o, a, "relation" + visit_edge o, a, "name" end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute @@ -156,16 +156,16 @@ def visit_Arel_Attribute o alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute - def nary o + def nary o, a o.children.each_with_index do |x,i| - edge(i) { visit x } + edge(i) { visit x, a } end end alias :visit_Arel_Nodes_And :nary - def binary o - visit_edge o, "left" - visit_edge o, "right" + def binary o, a + visit_edge o, a, "left" + visit_edge o, a, "right" end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary @@ -184,7 +184,7 @@ def binary o alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_Over :binary - def visit_String o + def visit_String o, a @node_stack.last.fields << o end alias :visit_Time :visit_String @@ -201,23 +201,23 @@ def visit_String o alias :visit_Symbol :visit_String alias :visit_Arel_Nodes_SqlLiteral :visit_String - def visit_Hash o + def visit_Hash o, a o.each_with_index do |pair, i| - edge("pair_#{i}") { visit pair } + edge("pair_#{i}") { visit pair, a } end end - def visit_Array o + def visit_Array o, a o.each_with_index do |x,i| - edge(i) { visit x } + edge(i) { visit x, a } end end - def visit_edge o, method - edge(method) { visit o.send(method) } + def visit_edge o, a, method + edge(method) { visit o.send(method), a } end - def visit o + def visit o, a = nil if node = @seen[o.object_id] @edge_stack.last.to = node return diff --git a/lib/arel/visitors/ibm_db.rb b/lib/arel/visitors/ibm_db.rb index 0c26a3ae9ef95..13af27df716e3 100644 --- a/lib/arel/visitors/ibm_db.rb +++ b/lib/arel/visitors/ibm_db.rb @@ -3,8 +3,8 @@ module Visitors class IBM_DB < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Limit o - "FETCH FIRST #{visit o.expr} ROWS ONLY" + def visit_Arel_Nodes_Limit o, a + "FETCH FIRST #{visit o.expr, a} ROWS ONLY" end end diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index 984098cdf3962..a578119d9be3a 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -2,32 +2,32 @@ module Arel module Visitors class Informix < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, a [ "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), + (visit(o.offset, a) if o.offset), + (visit(o.limit, a) if o.limit), + o.cores.map { |x| visit_Arel_Nodes_SelectCore x, a }.join, + ("ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?), + (visit(o.lock, a) if o.lock), ].compact.join ' ' end - def visit_Arel_Nodes_SelectCore o + def visit_Arel_Nodes_SelectCore o, a [ - "#{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), + "#{o.projections.map { |x| visit x, a }.join ', '}", + ("FROM #{visit(o.source, a)}" if o.source && !o.source.empty?), + ("WHERE #{o.wheres.map { |x| visit x, a }.join ' AND ' }" unless o.wheres.empty?), + ("GROUP BY #{o.groups.map { |x| visit x, a }.join ', ' }" unless o.groups.empty?), + (visit(o.having, a) if o.having), ].compact.join ' ' end - def visit_Arel_Nodes_Offset o - "SKIP #{visit o.expr}" + def visit_Arel_Nodes_Offset o, a + "SKIP #{visit o.expr, a}" end - def visit_Arel_Nodes_Limit o - "LIMIT #{visit o.expr}" + def visit_Arel_Nodes_Limit o, a + "LIMIT #{visit o.expr, a}" end end end -end +end diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 1cdd7eb5ca0d6..9708887075761 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -11,8 +11,8 @@ module Visitors module JoinSql private - def visit_Arel_Nodes_SelectCore o - o.source.right.map { |j| visit j }.join ' ' + def visit_Arel_Nodes_SelectCore o, a + o.source.right.map { |j| visit j, a }.join ' ' end end end diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 23dc06a936998..9a88ee5b0fef3 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -6,20 +6,20 @@ class MSSQL < Arel::Visitors::ToSql # `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 + def visit_Arel_Nodes_Top o, a "" end - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, a if !o.limit && !o.offset - return super o + return super o, a end - select_order_by = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty? + select_order_by = "ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty? is_select_count = false sql = o.cores.map { |x| - core_order_by = select_order_by || determine_order_by(x) + core_order_by = select_order_by || determine_order_by(x, a) if select_count? x x.projections = [row_num_literal(core_order_by)] is_select_count = true @@ -27,7 +27,7 @@ def visit_Arel_Nodes_SelectStatement o x.projections << row_num_literal(core_order_by) end - visit_Arel_Nodes_SelectCore x + visit_Arel_Nodes_SelectCore x, a }.join sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}" @@ -46,11 +46,11 @@ def get_offset_limit_clause o end end - def determine_order_by x + def determine_order_by x, a unless x.groups.empty? - "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" + "ORDER BY #{x.groups.map { |g| visit g, a }.join ', ' }" else - "ORDER BY #{find_left_table_pk(x.froms)}" + "ORDER BY #{find_left_table_pk(x.froms, a)}" end end @@ -64,9 +64,9 @@ def select_count? x # 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 + def find_left_table_pk o, a + return visit o.primary_key, a if o.instance_of? Arel::Table + find_left_table_pk o.left, a if o.kind_of? Arel::Nodes::Join end end end diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index ee8483372acfe..4db5a94019f03 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,19 +2,19 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Union o, suppress_parens = false + def visit_Arel_Nodes_Union o, a, suppress_parens = false left_result = case o.left when Arel::Nodes::Union - visit_Arel_Nodes_Union o.left, true + visit_Arel_Nodes_Union o.left, a, true else - visit o.left + visit o.left, a end right_result = case o.right when Arel::Nodes::Union - visit_Arel_Nodes_Union o.right, true + visit_Arel_Nodes_Union o.right, a, true else - visit o.right + visit o.right, a end if suppress_parens @@ -24,30 +24,30 @@ def visit_Arel_Nodes_Union o, suppress_parens = false end end - def visit_Arel_Nodes_Bin o - "BINARY #{visit o.expr}" + def visit_Arel_Nodes_Bin o, a + "BINARY #{visit o.expr, a}" end ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, a o.limit = Arel::Nodes::Limit.new(18446744073709551615) if o.offset && !o.limit super end - def visit_Arel_Nodes_SelectCore o + def visit_Arel_Nodes_SelectCore o, a o.froms ||= Arel.sql('DUAL') super end - def visit_Arel_Nodes_UpdateStatement o + def visit_Arel_Nodes_UpdateStatement o, a [ - "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), + "UPDATE #{visit o.relation, a}", + ("SET #{o.values.map { |value| visit value, a }.join ', '}" unless o.values.empty?), + ("WHERE #{o.wheres.map { |x| visit x, a }.join ' AND '}" unless o.wheres.empty?), + ("ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?), + (visit(o.limit, a) if o.limit), ].compact.join ' ' end diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 375f7dbfe9570..b58d7338efa85 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -3,8 +3,8 @@ module Visitors class Oracle < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o - o = order_hacks(o) + def visit_Arel_Nodes_SelectStatement o, a + o = order_hacks(o, a) # if need to select first records without ORDER BY and GROUP BY and without DISTINCT # then can use simple ROWNUM in WHERE clause @@ -20,53 +20,53 @@ def visit_Arel_Nodes_SelectStatement o limit = o.limit.expr.to_i offset = o.offset o.offset = nil - sql = super(o) + sql = super(o, a) return <<-eosql SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ WHERE rownum <= #{offset.expr.to_i + limit} ) - WHERE #{visit offset} + WHERE #{visit offset, a} eosql end if o.limit o = o.dup limit = o.limit.expr - return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}" + return "SELECT * FROM (#{super(o, a)}) WHERE ROWNUM <= #{visit limit, a}" end if o.offset o = o.dup offset = o.offset o.offset = nil - sql = super(o) + sql = super(o, a) return <<-eosql SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ ) - WHERE #{visit offset} + WHERE #{visit offset, a} eosql end super end - def visit_Arel_Nodes_Limit o + def visit_Arel_Nodes_Limit o, a end - def visit_Arel_Nodes_Offset o - "raw_rnum_ > #{visit o.expr}" + def visit_Arel_Nodes_Offset o, a + "raw_rnum_ > #{visit o.expr, a}" end - def visit_Arel_Nodes_Except o - "( #{visit o.left} MINUS #{visit o.right} )" + def visit_Arel_Nodes_Except o, a + "( #{visit o.left, a} MINUS #{visit o.right, a} )" end - def visit_Arel_Nodes_UpdateStatement o - # Oracle does not allow ORDER BY/LIMIT in UPDATEs. + def visit_Arel_Nodes_UpdateStatement o, a + # 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 @@ -79,7 +79,7 @@ def visit_Arel_Nodes_UpdateStatement o ### # Hacks for the order clauses specific to Oracle - def order_hacks o + def order_hacks o, a return o if o.orders.empty? return o unless o.cores.any? do |core| core.projections.any? do |projection| @@ -89,9 +89,9 @@ def order_hacks o # 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 { |x| visit x, a }.join(', ').split(',') orders = o.orders.map do |x| - string = visit x + string = visit x, a if string.include?(',') split_order_string(string) else diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb index 11dbfdad2ae14..b470d3f084dcb 100644 --- a/lib/arel/visitors/order_clauses.rb +++ b/lib/arel/visitors/order_clauses.rb @@ -3,8 +3,8 @@ module Visitors class OrderClauses < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o - o.orders.map { |x| visit x } + def visit_Arel_Nodes_SelectStatement o, a + o.orders.map { |x| visit x, a } end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 812710181c55e..080e402e3b625 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -3,16 +3,16 @@ module Visitors class PostgreSQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Matches o - "#{visit o.left} ILIKE #{visit o.right}" + def visit_Arel_Nodes_Matches o, a + "#{visit o.left, a} ILIKE #{visit o.right, a}" end - def visit_Arel_Nodes_DoesNotMatch o - "#{visit o.left} NOT ILIKE #{visit o.right}" + def visit_Arel_Nodes_DoesNotMatch o, a + "#{visit o.left, a} NOT ILIKE #{visit o.right, a}" end - def visit_Arel_Nodes_DistinctOn o - "DISTINCT ON ( #{visit o.expr} )" + def visit_Arel_Nodes_DistinctOn o, a + "DISTINCT ON ( #{visit o.expr, a} )" end end end diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index 2a509e95b59ed..07a18fc2f58b8 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -4,10 +4,10 @@ class SQLite < Arel::Visitors::ToSql private # Locks are not supported in SQLite - def visit_Arel_Nodes_Lock o + def visit_Arel_Nodes_Lock o, a end - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, a o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 1a4826bcd2ced..4e1f7ab46636b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -53,23 +53,16 @@ class ToSql < Arel::Visitors::Visitor 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 + + def visit_Arel_Nodes_DeleteStatement o, a [ "DELETE FROM #{visit o.relation}", ("WHERE #{o.wheres.map { |x| visit x }.join AND}" unless o.wheres.empty?) @@ -88,7 +81,7 @@ def build_subselect key, o stmt end - def visit_Arel_Nodes_UpdateStatement o + def visit_Arel_Nodes_UpdateStatement o, a if o.orders.empty? && o.limit.nil? wheres = o.wheres else @@ -106,34 +99,34 @@ def visit_Arel_Nodes_UpdateStatement 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?), + "UPDATE #{visit o.relation, a}", + ("SET #{o.values.map { |value| visit value, a }.join ', '}" unless o.values.empty?), + ("WHERE #{wheres.map { |x| visit x, a }.join ' AND '}" unless wheres.empty?), ].compact.join ' ' end - def visit_Arel_Nodes_InsertStatement o + def visit_Arel_Nodes_InsertStatement o, a [ - "INSERT INTO #{visit o.relation}", + "INSERT INTO #{visit o.relation, a}", ("(#{o.columns.map { |x| quote_column_name x.name }.join ', '})" unless o.columns.empty?), - (visit o.values if o.values), + (visit o.values, a if o.values), ].compact.join ' ' end - def visit_Arel_Nodes_Exists o - "EXISTS (#{visit o.expressions})#{ - o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Exists o, a + "EXISTS (#{visit o.expressions, a})#{ + o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_True o + def visit_Arel_Nodes_True o, a "TRUE" end - def visit_Arel_Nodes_False o + def visit_Arel_Nodes_False o, a "FALSE" end @@ -142,6 +135,7 @@ def table_exists? name end def column_for attr + return unless attr name = attr.name.to_s table = attr.relation.table_name @@ -154,66 +148,66 @@ def column_cache(table) @schema_cache.columns_hash(table) end - def visit_Arel_Nodes_Values o + def visit_Arel_Nodes_Values o, a "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| if Nodes::SqlLiteral === value - visit value + visit value, a else quote(value, attr && column_for(attr)) end }.join ', '})" end - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, a str = '' if o.with - str << visit(o.with) + str << visit(o.with, a) str << SPACE end - o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x) } + o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x, a) } 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 << visit(x, a) 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 << " #{visit(o.limit, a)}" if o.limit + str << " #{visit(o.offset, a)}" if o.offset + str << " #{visit(o.lock, a)}" if o.lock str.strip! str end - def visit_Arel_Nodes_SelectCore o + def visit_Arel_Nodes_SelectCore o, a str = "SELECT" - str << " #{visit(o.top)}" if o.top - str << " #{visit(o.set_quantifier)}" if o.set_quantifier + str << " #{visit(o.top, a)}" if o.top + str << " #{visit(o.set_quantifier, a)}" 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 << visit(x, a) str << COMMA unless len == i end end - str << " FROM #{visit(o.source)}" if o.source && !o.source.empty? + str << " FROM #{visit(o.source, a)}" 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 << visit(x, a) str << AND unless len == i end end @@ -222,18 +216,18 @@ def visit_Arel_Nodes_SelectCore o str << GROUP_BY len = o.groups.length - 1 o.groups.each_with_index do |x, i| - str << visit(x) + str << visit(x, a) str << COMMA unless len == i end end - str << " #{visit(o.having)}" if o.having + str << " #{visit(o.having, a)}" 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 << visit(x, a) str << COMMA unless len == i end end @@ -241,237 +235,244 @@ def visit_Arel_Nodes_SelectCore o str end - def visit_Arel_Nodes_Bin o - visit o.expr + def visit_Arel_Nodes_Bin o, a + visit o.expr, a end - def visit_Arel_Nodes_Distinct o + def visit_Arel_Nodes_Distinct o, a DISTINCT end - def visit_Arel_Nodes_DistinctOn o + def visit_Arel_Nodes_DistinctOn o, a raise NotImplementedError, 'DISTINCT ON not implemented for this db' end - def visit_Arel_Nodes_With o - "WITH #{o.children.map { |x| visit x }.join(', ')}" + def visit_Arel_Nodes_With o, a + "WITH #{o.children.map { |x| visit x, a }.join(', ')}" end - def visit_Arel_Nodes_WithRecursive o - "WITH RECURSIVE #{o.children.map { |x| visit x }.join(', ')}" + def visit_Arel_Nodes_WithRecursive o, a + "WITH RECURSIVE #{o.children.map { |x| visit x, a }.join(', ')}" end - def visit_Arel_Nodes_Union o - "( #{visit o.left} UNION #{visit o.right} )" + def visit_Arel_Nodes_Union o, a + "( #{visit o.left, a} UNION #{visit o.right, a} )" end - def visit_Arel_Nodes_UnionAll o - "( #{visit o.left} UNION ALL #{visit o.right} )" + def visit_Arel_Nodes_UnionAll o, a + "( #{visit o.left, a} UNION ALL #{visit o.right, a} )" end - def visit_Arel_Nodes_Intersect o - "( #{visit o.left} INTERSECT #{visit o.right} )" + def visit_Arel_Nodes_Intersect o, a + "( #{visit o.left, a} INTERSECT #{visit o.right, a} )" end - def visit_Arel_Nodes_Except o - "( #{visit o.left} EXCEPT #{visit o.right} )" + def visit_Arel_Nodes_Except o, a + "( #{visit o.left, a} EXCEPT #{visit o.right, a} )" end - def visit_Arel_Nodes_NamedWindow o - "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o}" + def visit_Arel_Nodes_NamedWindow o, a + "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o, a}" end - def visit_Arel_Nodes_Window o + def visit_Arel_Nodes_Window o, a s = [ - ("ORDER BY #{o.orders.map { |x| visit(x) }.join(', ')}" unless o.orders.empty?), - (visit o.framing if o.framing) + ("ORDER BY #{o.orders.map { |x| visit(x, a) }.join(', ')}" unless o.orders.empty?), + (visit o.framing, a if o.framing) ].compact.join ' ' "(#{s})" end - def visit_Arel_Nodes_Rows o + def visit_Arel_Nodes_Rows o, a if o.expr - "ROWS #{visit o.expr}" + "ROWS #{visit o.expr, a}" else "ROWS" end end - def visit_Arel_Nodes_Range o + def visit_Arel_Nodes_Range o, a if o.expr - "RANGE #{visit o.expr}" + "RANGE #{visit o.expr, a}" else "RANGE" end end - def visit_Arel_Nodes_Preceding o - "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} PRECEDING" + def visit_Arel_Nodes_Preceding o, a + "#{o.expr ? visit(o.expr, a) : 'UNBOUNDED'} PRECEDING" end - def visit_Arel_Nodes_Following o - "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} FOLLOWING" + def visit_Arel_Nodes_Following o, a + "#{o.expr ? visit(o.expr, a) : 'UNBOUNDED'} FOLLOWING" end - def visit_Arel_Nodes_CurrentRow o + def visit_Arel_Nodes_CurrentRow o, a "CURRENT ROW" end - def visit_Arel_Nodes_Over o + def visit_Arel_Nodes_Over o, a case o.right when nil - "#{visit o.left} OVER ()" + "#{visit o.left, a} OVER ()" when Arel::Nodes::SqlLiteral - "#{visit o.left} OVER #{visit o.right}" + "#{visit o.left, a} OVER #{visit o.right, a}" when String, Symbol - "#{visit o.left} OVER #{quote_column_name o.right.to_s}" + "#{visit o.left, a} OVER #{quote_column_name o.right.to_s}" else - "#{visit o.left} OVER #{visit o.right}" + "#{visit o.left, a} OVER #{visit o.right, a}" end end - def visit_Arel_Nodes_Having o - "HAVING #{visit o.expr}" + def visit_Arel_Nodes_Having o, a + "HAVING #{visit o.expr, a}" end - def visit_Arel_Nodes_Offset o - "OFFSET #{visit o.expr}" + def visit_Arel_Nodes_Offset o, a + "OFFSET #{visit o.expr, a}" end - def visit_Arel_Nodes_Limit o - "LIMIT #{visit o.expr}" + def visit_Arel_Nodes_Limit o, a + "LIMIT #{visit o.expr, a}" end # FIXME: this does nothing on most databases, but does on MSSQL - def visit_Arel_Nodes_Top o + def visit_Arel_Nodes_Top o, a "" end - def visit_Arel_Nodes_Lock o - visit o.expr + def visit_Arel_Nodes_Lock o, a + visit o.expr, a end - def visit_Arel_Nodes_Grouping o - "(#{visit o.expr})" + def visit_Arel_Nodes_Grouping o, a + "(#{visit o.expr, a})" end - def visit_Arel_SelectManager o + def visit_Arel_SelectManager o, a "(#{o.to_sql.rstrip})" end - def visit_Arel_Nodes_Ascending o - "#{visit o.expr} ASC" + def visit_Arel_Nodes_Ascending o, a + "#{visit o.expr, a} ASC" end - def visit_Arel_Nodes_Descending o - "#{visit o.expr} DESC" + def visit_Arel_Nodes_Descending o, a + "#{visit o.expr, a} DESC" end - def visit_Arel_Nodes_Group o - visit o.expr + def visit_Arel_Nodes_Group o, a + visit o.expr, a end - def visit_Arel_Nodes_NamedFunction o + def visit_Arel_Nodes_NamedFunction o, a "#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x - }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + visit x, a + }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_Extract o - "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr})#{o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Extract o, a + "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr, a})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_Count o + def visit_Arel_Nodes_Count o, a "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x - }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + visit x, a + }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_Sum o + def visit_Arel_Nodes_Sum o, a "SUM(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_Max o + def visit_Arel_Nodes_Max o, a "MAX(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_Min o + def visit_Arel_Nodes_Min o, a "MIN(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_Avg o + def visit_Arel_Nodes_Avg o, a "AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" end - def visit_Arel_Nodes_TableAlias o - "#{visit o.relation} #{quote_table_name o.name}" + def visit_Arel_Nodes_TableAlias o, a + "#{visit o.relation, a} #{quote_table_name o.name}" end - def visit_Arel_Nodes_Between o - "#{visit o.left} BETWEEN #{visit o.right}" + def visit_Arel_Nodes_Between o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} BETWEEN #{visit o.right, a}" end - def visit_Arel_Nodes_GreaterThanOrEqual o - "#{visit o.left} >= #{visit o.right}" + def visit_Arel_Nodes_GreaterThanOrEqual o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} >= #{visit o.right, a}" end - def visit_Arel_Nodes_GreaterThan o - "#{visit o.left} > #{visit o.right}" + def visit_Arel_Nodes_GreaterThan o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} > #{visit o.right, a}" end - def visit_Arel_Nodes_LessThanOrEqual o - "#{visit o.left} <= #{visit o.right}" + def visit_Arel_Nodes_LessThanOrEqual o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} <= #{visit o.right, a}" end - def visit_Arel_Nodes_LessThan o - "#{visit o.left} < #{visit o.right}" + def visit_Arel_Nodes_LessThan o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} < #{visit o.right, a}" end - def visit_Arel_Nodes_Matches o - "#{visit o.left} LIKE #{visit o.right}" + def visit_Arel_Nodes_Matches o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} LIKE #{visit o.right, a}" end - def visit_Arel_Nodes_DoesNotMatch o - "#{visit o.left} NOT LIKE #{visit o.right}" + def visit_Arel_Nodes_DoesNotMatch o, a + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} NOT LIKE #{visit o.right, a}" end - def visit_Arel_Nodes_JoinSource o + def visit_Arel_Nodes_JoinSource o, a [ - (visit(o.left) if o.left), - o.right.map { |j| visit j }.join(' ') + (visit(o.left, a) if o.left), + o.right.map { |j| visit j, a }.join(' ') ].compact.join ' ' end - def visit_Arel_Nodes_StringJoin o - visit o.left + def visit_Arel_Nodes_StringJoin o, a + visit o.left, a end - def visit_Arel_Nodes_OuterJoin o - "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" + def visit_Arel_Nodes_OuterJoin o, a + "LEFT OUTER JOIN #{visit o.left, a} #{visit o.right, a}" end - def visit_Arel_Nodes_InnerJoin o - s = "INNER JOIN #{visit o.left}" + def visit_Arel_Nodes_InnerJoin o, a + s = "INNER JOIN #{visit o.left, a}" if o.right s << SPACE - s << visit(o.right) + s << visit(o.right, a) end s end - def visit_Arel_Nodes_On o - "ON #{visit o.expr}" + def visit_Arel_Nodes_On o, a + "ON #{visit o.expr, a}" end - def visit_Arel_Nodes_Not o - "NOT (#{visit o.expr})" + def visit_Arel_Nodes_Not o, a + "NOT (#{visit o.expr, a})" end - def visit_Arel_Table o + def visit_Arel_Table o, a if o.table_alias "#{quote_table_name o.name} #{quote_table_name o.table_alias}" else @@ -479,65 +480,68 @@ def visit_Arel_Table o end end - def visit_Arel_Nodes_In o + def visit_Arel_Nodes_In o, a if Array === o.right && o.right.empty? '1=0' else - "#{visit o.left} IN (#{visit o.right})" + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} IN (#{visit o.right, a})" end end - def visit_Arel_Nodes_NotIn o + def visit_Arel_Nodes_NotIn o, a if Array === o.right && o.right.empty? '1=1' else - "#{visit o.left} NOT IN (#{visit o.right})" + a = o.left if Arel::Attributes::Attribute === o.left + "#{visit o.left, a} NOT IN (#{visit o.right, a})" end end - def visit_Arel_Nodes_And o - o.children.map { |x| visit x }.join ' AND ' + def visit_Arel_Nodes_And o, a + o.children.map { |x| visit x, a }.join ' AND ' end - def visit_Arel_Nodes_Or o - "#{visit o.left} OR #{visit o.right}" + def visit_Arel_Nodes_Or o, a + "#{visit o.left, a} OR #{visit o.right, a}" end - def visit_Arel_Nodes_Assignment o + def visit_Arel_Nodes_Assignment o, a right = quote(o.right, column_for(o.left)) - "#{visit o.left} = #{right}" + "#{visit o.left, a} = #{right}" end - def visit_Arel_Nodes_Equality o + def visit_Arel_Nodes_Equality o, a right = o.right + a = o.left if Arel::Attributes::Attribute === o.left if right.nil? - "#{visit o.left} IS NULL" + "#{visit o.left, a} IS NULL" else - "#{visit o.left} = #{visit right}" + "#{visit o.left, a} = #{visit right, a}" end end - def visit_Arel_Nodes_NotEqual o + def visit_Arel_Nodes_NotEqual o, a right = o.right + a = o.left if Arel::Attributes::Attribute === o.left if right.nil? - "#{visit o.left} IS NOT NULL" + "#{visit o.left, a} IS NOT NULL" else - "#{visit o.left} != #{visit right}" + "#{visit o.left, a} != #{visit right, a}" end end - def visit_Arel_Nodes_As o - "#{visit o.left} AS #{visit o.right}" + def visit_Arel_Nodes_As o, a + "#{visit o.left, a} AS #{visit o.right, a}" end - def visit_Arel_Nodes_UnqualifiedColumn o + def visit_Arel_Nodes_UnqualifiedColumn o, a "#{quote_column_name o.name}" end - def visit_Arel_Attributes_Attribute o - self.last_column = column_for o + def visit_Arel_Attributes_Attribute o, a join_name = o.relation.table_alias || o.relation.name "#{quote_table_name join_name}.#{quote_column_name o.name}" end @@ -548,7 +552,7 @@ def visit_Arel_Attributes_Attribute o alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute - def literal o; o end + def literal o, a; o end alias :visit_Arel_Nodes_BindParam :literal alias :visit_Arel_Nodes_SqlLiteral :literal @@ -556,8 +560,8 @@ def literal o; o end alias :visit_Bignum :literal alias :visit_Fixnum :literal - def quoted o - quote(o, last_column) + def quoted o, a + quote(o, column_for(a)) end alias :visit_ActiveSupport_Multibyte_Chars :quoted @@ -575,8 +579,8 @@ def quoted o alias :visit_Time :quoted alias :visit_TrueClass :quoted - def visit_Arel_Nodes_InfixOperation o - "#{visit o.left} #{o.operator} #{visit o.right}" + def visit_Arel_Nodes_InfixOperation o, a + "#{visit o.left, a} #{o.operator} #{visit o.right, a}" end alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation @@ -584,8 +588,8 @@ def visit_Arel_Nodes_InfixOperation o 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(', ') + def visit_Array o, a + o.map { |x| visit x, a }.join(', ') end def quote value, column = nil diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 8f9dd929e1b28..204657883ffd6 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -15,8 +15,8 @@ def dispatch DISPATCH end - def visit object - send dispatch[object.class], object + def visit object, attribute = nil + send dispatch[object.class], object, attribute rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index 9816fa7a70c25..d59bc26cb4c3b 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -1,8 +1,8 @@ module Arel module Visitors class WhereSql < Arel::Visitors::ToSql - def visit_Arel_Nodes_SelectCore o - "WHERE #{o.wheres.map { |x| visit x }.join ' AND ' }" + def visit_Arel_Nodes_SelectCore o, a + "WHERE #{o.wheres.map { |x| visit x, a }.join ' AND ' }" end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index d3e4dae963ec5..eb35d1703a2fe 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -18,7 +18,7 @@ module Visitors it 'can define a dispatch method' do visited = false viz = Class.new(Arel::Visitors::Visitor) { - define_method(:hello) do |node| + define_method(:hello) do |node, attribute| visited = true end From 9f431ea6ca886b5f0415a212283fa6f1cdd41ac4 Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Fri, 17 May 2013 23:57:29 +0530 Subject: [PATCH 1149/1492] Fixed typos --- History.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/History.txt b/History.txt index b24faf3267988..9f8e9c99f79f2 100644 --- a/History.txt +++ b/History.txt @@ -19,11 +19,11 @@ * Bug Fixes * Fix depth-first traversal to understand ascending / descending nodes. - * Parentheis are suppressed with nested unions in MySQL. Thanks jhtwong! + * Parenthesis are suppressed with nested unions in MySQL. Thanks jhtwong! == 2.1.3 / 2011-06-27 -* Bug Fixues +* Bug Fixes * Fixed broken gem build. @@ -31,7 +31,7 @@ * Bug Fixes - * Visitors can define their own cache strategey so caches are not shared. + * Visitors can define their own cache strategy so caches are not shared. Fixes #57 * Informix support fixed. Thanks Khronos. * Ordering nodes broken to subclasses. Thanks Ernie Miller! From 5b1d2d80d376bd0281febca853588b078b181af1 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 17 May 2013 15:43:54 -0700 Subject: [PATCH 1150/1492] call super from initialize --- lib/arel/nodes/and.rb | 1 + lib/arel/nodes/binary.rb | 1 + lib/arel/nodes/function.rb | 1 + lib/arel/nodes/insert_statement.rb | 1 + lib/arel/nodes/node.rb | 3 +++ lib/arel/nodes/select_core.rb | 1 + lib/arel/nodes/select_statement.rb | 1 + lib/arel/nodes/unary.rb | 1 + 8 files changed, 10 insertions(+) diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb index 0d0fb3ee824c1..62e8ef6f11aad 100644 --- a/lib/arel/nodes/and.rb +++ b/lib/arel/nodes/and.rb @@ -4,6 +4,7 @@ class And < Arel::Nodes::Node attr_reader :children def initialize children, right = nil + super() unless Array === children warn "(#{caller.first}) AND nodes should be created with a list" children = [children, right] diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index d55c7a54784b9..0e7e281b4b1e5 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -4,6 +4,7 @@ class Binary < Arel::Nodes::Node attr_accessor :left, :right def initialize left, right + super() @left = left @right = right end diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 90bbf4a77b46a..dcafbbf1f4cf2 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -7,6 +7,7 @@ class Function < Arel::Nodes::Node attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil + super() @expressions = expr @alias = aliaz && SqlLiteral.new(aliaz) @distinct = false diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index 518160cce4f95..ec8870a1c2b79 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -4,6 +4,7 @@ class InsertStatement < Arel::Nodes::Node attr_accessor :relation, :columns, :values def initialize + super() @relation = nil @columns = [] @values = nil diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 84dcb1cdf5218..f10487ff6baf6 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -6,6 +6,9 @@ class Node include Arel::FactoryMethods include Enumerable + def initialize + end + ### # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 3b400c768d200..09ae420aa187f 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -5,6 +5,7 @@ class SelectCore < Arel::Nodes::Node attr_accessor :having, :source, :set_quantifier def initialize + super() @source = JoinSource.new nil @top = nil diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 32bdd7080c8ed..830ac27046ac4 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -5,6 +5,7 @@ class SelectStatement < Arel::Nodes::Node attr_accessor :limit, :orders, :lock, :offset, :with def initialize cores = [SelectCore.new] + super() @cores = cores @orders = [] @limit = nil diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 42c31267dd543..3d4a4b014a900 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -5,6 +5,7 @@ class Unary < Arel::Nodes::Node alias :value :expr def initialize expr + super() @expr = expr end From a1b72178714fbf0033fe076b7e51f57eff152bdd Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 20 May 2013 15:29:10 -0700 Subject: [PATCH 1151/1492] record who created the node when $DEBUG is true --- lib/arel/nodes/node.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index f10487ff6baf6..36e762861255c 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -6,7 +6,14 @@ class Node include Arel::FactoryMethods include Enumerable - def initialize + if $DEBUG + def _caller + @caller + end + + def initialize + @caller = caller.dup + end end ### From 8263b9954bb8acc259ee929fbefd4dc7be9b201a Mon Sep 17 00:00:00 2001 From: Denis Savitsky Date: Tue, 25 Jun 2013 17:29:19 +0400 Subject: [PATCH 1152/1492] "Relational Database Managements systems", not "Relational Database Managements System systems" --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 76fe7302940cd..dc9605634b936 100644 --- a/README.markdown +++ b/README.markdown @@ -7,7 +7,7 @@ Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation of complex SQL queries -2. Adapts to various RDBMS systems +2. Adapts to various RDBM 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 From 6d39b29361522abeef8347033df9da0622f91e9c Mon Sep 17 00:00:00 2001 From: Philip Arndt Date: Fri, 28 Jun 2013 04:11:25 +1200 Subject: [PATCH 1153/1492] Prettied up the README with syntax highlighting. [ci skip] --- README.markdown | 105 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/README.markdown b/README.markdown index 76fe7302940cd..7f6bac1c75ee2 100644 --- a/README.markdown +++ b/README.markdown @@ -21,13 +21,17 @@ For the moment, Arel uses Active Record's connection adapters to connect to the Generating a query with Arel is simple. For example, in order to produce - SELECT * FROM users +```sql +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 +```ruby +users = Arel::Table.new(:users) +query = users.project(Arel.sql('*')) +query.to_sql +``` ### More Sophisticated Queries @@ -35,45 +39,65 @@ Here is a whirlwind tour through the most common relational operators. These wil First is the 'restriction' operator, `where`: - users.where(users[:name].eq('amy')) - # => SELECT * FROM users WHERE users.name = 'amy' +```ruby +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 +```ruby +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 +```ruby +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 +```ruby +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 +```ruby +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' +```ruby +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)) +```ruby +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)) +```ruby +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))) +```ruby +users.where(users[:name].eq('bob').or(users[:age].lt(25))) +``` The `AND` operator behaves similarly. @@ -85,38 +109,51 @@ The examples above are fairly simple and other libraries match or come close to 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]] +```ruby +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]] +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]) +```ruby +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) +```ruby +comments = Arel::Table.new(:comments) +``` And this table has the following attributes: - comments.columns # => [comments[:id], comments[:body], comments[:parent_id]] +```ruby +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 +```ruby +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). From 402b8ffdca81075fdee86f213c3a14bbb43dee13 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Thu, 4 Jul 2013 08:34:52 +0530 Subject: [PATCH 1154/1492] Remove deprecated `Arel::Table.table_cache` with no replacement --- lib/arel/table.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 5fb1254d17125..aa61c36a314db 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -146,15 +146,5 @@ def attributes_for columns 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 From e2f0dd62f237c6048edc50744cd67499b2d693ff Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Thu, 4 Jul 2013 08:36:19 +0530 Subject: [PATCH 1155/1492] Remove deprecated `Arel::Table#columns` with no replacement --- lib/arel/table.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index aa61c36a314db..189fb8eb9458c 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -100,17 +100,6 @@ 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 From 4524c7f8a8225677893e0731f40993de17d4babc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 18 Jul 2013 10:28:20 -0300 Subject: [PATCH 1156/1492] Add licences to gemspec Closes #197 --- Rakefile | 1 + arel.gemspec | 1 + 2 files changed, 2 insertions(+) diff --git a/Rakefile b/Rakefile index 74476cf85b640..9bcddaf80ce28 100644 --- a/Rakefile +++ b/Rakefile @@ -14,6 +14,7 @@ Hoe.spec 'arel' do developer('Emilio Tagua', 'miloops@gmail.com') developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email + self.licenses = ['MIT'] self.readme_file = 'README.markdown' self.extra_rdoc_files = FileList['README.markdown'] end diff --git a/arel.gemspec b/arel.gemspec index 1a9799e4009cb..491c6952914c2 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| 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.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" From d93a05eec1adc5ca9d752a1e0b33313fc092c3e7 Mon Sep 17 00:00:00 2001 From: Colin Jones Date: Wed, 14 Aug 2013 17:02:17 -0500 Subject: [PATCH 1157/1492] Cache visitor dispatch on a per-visitor basis --- lib/arel/visitors/visitor.rb | 9 +++++--- test/visitors/test_dispatch_contamination.rb | 22 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 test/visitors/test_dispatch_contamination.rb diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 204657883ffd6..33ec5eafb476f 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -7,12 +7,15 @@ def accept object private - DISPATCH = Hash.new do |hash, klass| - hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" + DISPATCH = Hash.new do |hash, visitor_class| + hash[visitor_class] = + Hash.new do |hash, node_class| + hash[node_class] = "visit_#{(node_class.name || '').gsub('::', '_')}" + end end def dispatch - DISPATCH + DISPATCH[self.class] end def visit object, attribute = nil diff --git a/test/visitors/test_dispatch_contamination.rb b/test/visitors/test_dispatch_contamination.rb new file mode 100644 index 0000000000000..d3c9e8af2edb3 --- /dev/null +++ b/test/visitors/test_dispatch_contamination.rb @@ -0,0 +1,22 @@ +require 'helper' + +module Arel + module Visitors + describe 'avoiding contamination between visitor dispatch tables' do + before do + @connection = Table.engine.connection + @table = Table.new(:users) + end + + it 'dispatches properly after failing upwards' do + node = Nodes::Union.new(Nodes::True.new, Nodes::False.new) + assert_equal "( TRUE UNION FALSE )", node.to_sql + + node.first # from Nodes::Node's Enumerable mixin + + assert_equal "( TRUE UNION FALSE )", node.to_sql + end + end + end +end + From 707554e6a8b125cf6bdbc9214be4407ba4b624b3 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 30 Aug 2013 15:44:10 +1000 Subject: [PATCH 1158/1492] Improve performance of #uniq across a large number of nodes --- lib/arel/table.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 5fb1254d17125..ef109afe95459 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -124,7 +124,10 @@ def insert_manager end def hash - [@name, @engine, @aliases, @table_alias].hash + # Perf note: aliases, table alias and engine is excluded from the hash + # aliases can have a loop back to this table breaking hashes in parent + # relations, for the vast majority of cases @name is unique to a query + @name.hash end def eql? other From 51f5bece0867316d035d5d8eeb3a2eb44cf89ad1 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Thu, 6 Jun 2013 21:33:20 +0900 Subject: [PATCH 1159/1492] Support `columns_for_distinct` --- lib/arel/visitors/oracle.rb | 4 ++-- test/visitors/test_oracle.rb | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index b58d7338efa85..b6f7b4cc3c701 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -8,7 +8,7 @@ def visit_Arel_Nodes_SelectStatement o, a # 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 / + if o.limit && o.orders.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /Distinct/ o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) @@ -83,7 +83,7 @@ def order_hacks o, a return o if o.orders.empty? return o unless o.cores.any? do |core| core.projections.any? do |projection| - /DISTINCT.*FIRST_VALUE/ === projection + /FIRST_VALUE/ === projection end end # Previous version with join and split broke ORDER BY clause diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 421e9951e6544..bd22822bcaebe 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -85,7 +85,8 @@ module Visitors it 'creates a subquery when there is DISTINCT' do stmt = Nodes::SelectStatement.new - stmt.cores.first.projections << Nodes::SqlLiteral.new('DISTINCT id') + stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new + stmt.cores.first.projections << Nodes::SqlLiteral.new('id') stmt.limit = Arel::Nodes::Limit.new(10) sql = @visitor.accept stmt sql.must_be_like %{ From b64c886483e3ad2dc92bf54510cd481f9124fb69 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 14 Oct 2013 19:05:59 -0700 Subject: [PATCH 1160/1492] fix one deprecation warning --- lib/arel/visitors/to_sql.rb | 2 +- test/test_update_manager.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4e1f7ab46636b..b61d5f7acd82f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -90,7 +90,7 @@ def visit_Arel_Nodes_UpdateStatement o, a 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= +key on UpdateManager using UpdateManager#key= '#{key.inspect}' eowarn key = o.relation.primary_key end diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 1dd881b259a30..f1a019970d263 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -19,6 +19,7 @@ module Arel it 'handles limit properly' do table = Table.new(:users) um = Arel::UpdateManager.new Table.engine + um.key = 'id' um.take 10 um.table table um.set [[table[:name], nil]] From 0c605cdee894f4c1eddde31ea38ae6bec74fd858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 22 Oct 2013 20:11:38 -0200 Subject: [PATCH 1161/1492] Release 4.0.1 --- History.txt | 12 ++++++++++++ Manifest.txt | 1 + arel.gemspec | 30 +++++++++++++++--------------- lib/arel.rb | 2 +- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/History.txt b/History.txt index 9f8e9c99f79f2..71c8a815141f3 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,15 @@ +== 4.0.1 / 2013-10-22 + +* Enhancements + + * Cache visitor dispatch on a per-visitor basis + * Improve performance of #uniq across a large number of nodes + +* Bug Fixes + + * Make visitors threadsafe by removing @last_column + * Support `columns_for_distinct` with Oracle adapter + == 2.2.1 / 2011-09-15 * Enhancements diff --git a/Manifest.txt b/Manifest.txt index b70d706ba9e50..cd4af8c588c4a 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -121,6 +121,7 @@ test/test_table.rb test/test_update_manager.rb test/visitors/test_bind_visitor.rb test/visitors/test_depth_first.rb +test/visitors/test_dispatch_contamination.rb test/visitors/test_dot.rb test/visitors/test_ibm_db.rb test/visitors/test_informix.rb diff --git a/arel.gemspec b/arel.gemspec index 491c6952914c2..1e3f73acbab69 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -2,39 +2,39 @@ Gem::Specification.new do |s| s.name = "arel" - s.version = "4.0.0.20130418133826" + s.version = "4.0.1.20131022201058" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2013-04-18" + s.date = "2013-10-22" 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.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_dispatch_contamination.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.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" - s.rubygems_version = "2.0.2" + s.rubygems_version = "2.0.6" 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"] + 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_dispatch_contamination.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"]) + s.add_development_dependency(%q, ["~> 5.0"]) + s.add_development_dependency(%q, ["~> 4.0"]) + s.add_development_dependency(%q, ["~> 3.7"]) else - s.add_dependency(%q, ["~> 4.6"]) - s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 3.5"]) + s.add_dependency(%q, ["~> 5.0"]) + s.add_dependency(%q, ["~> 4.0"]) + s.add_dependency(%q, ["~> 3.7"]) end else - s.add_dependency(%q, ["~> 4.6"]) - s.add_dependency(%q, ["~> 3.10"]) - s.add_dependency(%q, ["~> 3.5"]) + s.add_dependency(%q, ["~> 5.0"]) + s.add_dependency(%q, ["~> 4.0"]) + s.add_dependency(%q, ["~> 3.7"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index f2f046f672673..5d4982502c6e7 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -32,7 +32,7 @@ #### module Arel - VERSION = '4.0.0' + VERSION = '4.0.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 9e53488b1d8d535182a989bd38fbb171aebbeef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 24 Oct 2013 14:15:50 -0200 Subject: [PATCH 1162/1492] Fix warning of shadowing variable --- lib/arel/visitors/visitor.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 33ec5eafb476f..420549b2aa596 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -9,8 +9,8 @@ def accept object DISPATCH = Hash.new do |hash, visitor_class| hash[visitor_class] = - Hash.new do |hash, node_class| - hash[node_class] = "visit_#{(node_class.name || '').gsub('::', '_')}" + Hash.new do |method_hash, node_class| + method_hash[node_class] = "visit_#{(node_class.name || '').gsub('::', '_')}" end end From fcb00d388c8afe25cdc8bd0fa5c762840921a8c9 Mon Sep 17 00:00:00 2001 From: Ivan Antropov Date: Sat, 9 Nov 2013 10:16:19 +0700 Subject: [PATCH 1163/1492] Add :encode_with for proper YAML serialization --- lib/arel/nodes/sql_literal.rb | 4 ++++ test/nodes/test_sql_literal.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 1bae8c9366638..b43288b29cf5f 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -5,6 +5,10 @@ class SqlLiteral < String include Arel::Predications include Arel::AliasPredication include Arel::OrderPredications + + def encode_with(coder) + coder.scalar = self.to_s + end end class BindParam < SqlLiteral diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index 9deb8e5d8d67d..085c5dad6be29 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -1,4 +1,5 @@ require 'helper' +require 'yaml' module Arel module Nodes @@ -56,6 +57,13 @@ module Nodes @visitor.accept(node).must_be_like %{ (foo = 1 AND foo = 2) } end end + + describe 'serialization' do + it 'serializes into YAML' do + yaml_literal = SqlLiteral.new('foo').to_yaml + assert_equal('foo', YAML.load(yaml_literal)) + end + end end end end From 6aa055f5ab8ad4aee2791d9ba505d8328707ca83 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 20:31:25 +0530 Subject: [PATCH 1164/1492] Remove deprecated calls to `delete` with preference to using `compile_delete` and then calling `to_sql` on the resulting object to execute the SQL --- lib/arel/crud.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index e8e78a381c7e8..cc50a820e40d7 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -59,14 +59,5 @@ def compile_delete 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 From 4cbc19075bd2bdf77b591a362db2bd4f72722754 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 20:32:34 +0530 Subject: [PATCH 1165/1492] Remove deprecated calls to `insert` with preference to using `compile_insert` and then calling `to_sql` on the resulting object to execute the SQL --- lib/arel/crud.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index cc50a820e40d7..98e109d6f992a 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -41,17 +41,6 @@ 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 From 5f5a1447bef24ec216c8f21e8a0b6dd6623168b8 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 20:33:41 +0530 Subject: [PATCH 1166/1492] Remove deprecated calls to `update` with preference to using `compile_update` and then calling `to_sql` on the resulting object to execute the SQL --- lib/arel/crud.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 98e109d6f992a..6b3a776c6f2ef 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -18,19 +18,6 @@ def compile_update values 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 From 87fd8b390328557661500208b64cc15f61efddd1 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 21:10:20 +0530 Subject: [PATCH 1167/1492] Remove deprecated calls to using `UpdateManager` without setting `UpdateManager#key` --- lib/arel/crud.rb | 1 + lib/arel/visitors/to_sql.rb | 12 +----------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 6b3a776c6f2ef..ef14439a1fc21 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -10,6 +10,7 @@ def compile_update values else relation = values.first.first.relation end + um.key= relation.primary_key um.table relation um.set values um.take @ast.limit.expr if @ast.limit diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b61d5f7acd82f..1d8cd35806fae 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -85,17 +85,7 @@ def visit_Arel_Nodes_UpdateStatement o, a 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= '#{key.inspect}' - eowarn - key = o.relation.primary_key - end - - wheres = [Nodes::In.new(key, [build_subselect(key, o)])] + wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])] end [ From 27330ebae9537dd5503b10d3c0e6f422a38bd9c8 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 21:11:35 +0530 Subject: [PATCH 1168/1492] Remove deprecated calls to using `where_clauses` --- lib/arel/select_manager.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index ee9d34a514736..399cddb51393b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -47,14 +47,6 @@ 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 From a8f6662defe086258814f82dc8acb8d2eeee9842 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 21:15:09 +0530 Subject: [PATCH 1169/1492] Remove deprecated calls to `SelectManage#insert` with preference to using `compile_insert` --- lib/arel/select_manager.rb | 25 ------------------------- test/test_select_manager.rb | 14 -------------- 2 files changed, 39 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 399cddb51393b..b4899177d59e2 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -264,31 +264,6 @@ def to_a # :nodoc: @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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index a449f78bd8bb1..9779aca21d642 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -435,20 +435,6 @@ def test_join_sources 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 From 9cbfc8a370bf6537a02a2f21e7246dc21ba4cf1f Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 14 Jul 2013 21:17:57 +0530 Subject: [PATCH 1170/1492] Remove deprecated calls to `SelectManager#wheres` with no replacement --- lib/arel/select_manager.rb | 5 ----- test/test_activerecord_compat.rb | 18 ------------------ 2 files changed, 23 deletions(-) delete mode 100644 test/test_activerecord_compat.rb diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index b4899177d59e2..60df12c700633 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -161,11 +161,6 @@ 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? diff --git a/test/test_activerecord_compat.rb b/test/test_activerecord_compat.rb deleted file mode 100644 index d8812096100f3..0000000000000 --- a/test/test_activerecord_compat.rb +++ /dev/null @@ -1,18 +0,0 @@ -require '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 From 1e2e6ff8a9a7b10beb06a7963a94c7f321b3bc79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sun, 10 Nov 2013 23:11:54 -0200 Subject: [PATCH 1171/1492] Don't test against Ruby 1.9.2 Rails is not testing against this version so even if arel works we can't guarantee people application will --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d21ff3a18cd10..496c32f394b92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ script: "rake test" rvm: - rbx-19mode - jruby - - 1.9.2 - 1.9.3 - 2.0.0 notifications: From 8f5084eab4d47e6e4e95a5d91f0e625398d1a536 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 11 Nov 2013 01:08:06 -0500 Subject: [PATCH 1172/1492] Remove deleted file by 9cbfc8 from gemspec --- Manifest.txt | 1 - arel.gemspec | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index cd4af8c588c4a..ead313ce3f539 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -110,7 +110,6 @@ 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 diff --git a/arel.gemspec b/arel.gemspec index 1e3f73acbab69..71bc1ad135c86 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |s| 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_dispatch_contamination.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.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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.rubyforge_project = "arel" s.rubygems_version = "2.0.6" 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_dispatch_contamination.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.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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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 From e5269fef96316815e9f5964aa001494c4e9f9629 Mon Sep 17 00:00:00 2001 From: Andrew Vit Date: Tue, 12 Nov 2013 10:07:48 -0800 Subject: [PATCH 1173/1492] Update History for previous releases Conflicts: History.txt --- History.txt | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/History.txt b/History.txt index 71c8a815141f3..10d5d09399009 100644 --- a/History.txt +++ b/History.txt @@ -10,6 +10,47 @@ * Make visitors threadsafe by removing @last_column * Support `columns_for_distinct` with Oracle adapter +== 3.0.2 / 2012-02-21 + +* Enhancements + + * Added a module for visiting and transforming bind values + * Fix in [] to be false, not in [] to be true + +* Bug Fixes + + * Revert fix for LIMIT / OFFSET when query is ordered in Oracle + +== 3.0.1 / 2012-02-17 + +* Bug Fixes + + * Fixed LIMIT / OFFSET when query is ordered in Oracle + +== 3.0.0 / 2012-01-12 + +* Enhancements + + * Support connection pool and schema cache + +* Bug Fixes + + * Conditions with no column can be followed by other conditions in Postgres + +== 2.2.3 / 2012-02-21 + +* Enhancements + + * Added a module for visiting and transforming bind values + +== 2.2.2 / 2012-02-20 + +* Enhancements + + * Support LOCK + * Allow using non-table alias as a right-hand relation name + * Added SelectManager#distinct + == 2.2.1 / 2011-09-15 * Enhancements From ff8b3bcf7044288bb13e98208650f141e0460908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 15 Nov 2013 12:25:07 -0200 Subject: [PATCH 1174/1492] Add 3.0.3 to CHANGELOG entry [ci skip] --- History.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/History.txt b/History.txt index 10d5d09399009..7123d49bbf9c7 100644 --- a/History.txt +++ b/History.txt @@ -10,6 +10,16 @@ * Make visitors threadsafe by removing @last_column * Support `columns_for_distinct` with Oracle adapter +== 3.0.3 / 2013-11-12 + +* Enhancements + + * Support ANSI 2003 window functions + +* Bug Fixes + + * Fix joins in Informix + == 3.0.2 / 2012-02-21 * Enhancements From aa14068100a968c6c616a525c287fbfaacc7d487 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 16 Nov 2013 14:20:07 -0800 Subject: [PATCH 1175/1492] explicitly pass the pk to compile_update --- lib/arel/crud.rb | 4 ++-- test/test_crud.rb | 2 +- test/test_select_manager.rb | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index ef14439a1fc21..6f4962cbfec12 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -2,7 +2,7 @@ module Arel ### # FIXME hopefully we can remove this module Crud - def compile_update values + def compile_update values, pk um = UpdateManager.new @engine if Nodes::SqlLiteral === values @@ -10,7 +10,7 @@ def compile_update values else relation = values.first.first.relation end - um.key= relation.primary_key + um.key = pk um.table relation um.set values um.take @ast.limit.expr if @ast.limit diff --git a/test/test_crud.rb b/test/test_crud.rb index fe3e4f2e02342..ded1b632b7bf7 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -45,7 +45,7 @@ def initialize engine = FakeEngine.new table = Table.new :users fc = FakeCrudder.new fc.from table - stmt = fc.compile_update [[table[:id], 'foo']] + stmt = fc.compile_update [[table[:id], 'foo']], table.primary_key assert_instance_of Arel::UpdateManager, stmt end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 9779aca21d642..960e2b1a021ea 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -921,7 +921,7 @@ def test_join_sources manager = Arel::SelectManager.new engine manager.from table manager.take 1 - stmt = manager.compile_update(SqlLiteral.new('foo = bar')) + stmt = manager.compile_update(SqlLiteral.new('foo = bar'), table.primary_key) stmt.key = table['id'] stmt.to_sql.must_be_like %{ @@ -936,7 +936,7 @@ def test_join_sources manager = Arel::SelectManager.new engine manager.from table manager.order :foo - stmt = manager.compile_update(SqlLiteral.new('foo = bar')) + stmt = manager.compile_update(SqlLiteral.new('foo = bar'), table.primary_key) stmt.key = table['id'] stmt.to_sql.must_be_like %{ @@ -950,7 +950,7 @@ def test_join_sources table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - stmt = manager.compile_update(SqlLiteral.new('foo = bar')) + stmt = manager.compile_update(SqlLiteral.new('foo = bar'), table.primary_key) stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end @@ -961,7 +961,7 @@ def test_join_sources manager = Arel::SelectManager.new engine manager.where table[:id].eq 10 manager.from table - stmt = manager.compile_update(table[:id] => 1) + stmt = manager.compile_update({table[:id] => 1}, table.primary_key) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 @@ -975,7 +975,7 @@ def test_join_sources manager.where table[:foo].eq 10 manager.take 42 manager.from table - stmt = manager.compile_update(table[:id] => 1) + stmt = manager.compile_update({table[:id] => 1}, table.primary_key) 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) @@ -987,7 +987,7 @@ def test_join_sources table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - stmt = manager.compile_update(table[:id] => 1) + stmt = manager.compile_update({table[:id] => 1}, table.primary_key) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 From cd0509d9920ef39a86a5c9781b3f1fe38e3c8068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 18 Nov 2013 17:42:00 -0200 Subject: [PATCH 1176/1492] Arel master is 5.0.0 --- arel.gemspec | 7 ++++--- lib/arel.rb | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 71bc1ad135c86..fbd7c967f83f9 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,12 +1,13 @@ # -*- encoding: utf-8 -*- +# stub: arel 5.0.0.20131118174145 ruby lib Gem::Specification.new do |s| s.name = "arel" - s.version = "4.0.1.20131022201058" + s.version = "5.0.0.20131118174145" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2013-10-22" + s.date = "2013-11-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"] @@ -16,7 +17,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.require_paths = ["lib"] s.rubyforge_project = "arel" - s.rubygems_version = "2.0.6" + s.rubygems_version = "2.1.11" 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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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"] diff --git a/lib/arel.rb b/lib/arel.rb index 5d4982502c6e7..fd0a81a5a05f9 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -32,7 +32,7 @@ #### module Arel - VERSION = '4.0.1' + VERSION = '5.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 986773ecc6fb6d34b56c45393bcc320b8bd2a66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 4 Dec 2013 23:25:42 -0200 Subject: [PATCH 1177/1492] Copy edit --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 7f582ab24e31b..bcdbaba0b247e 100644 --- a/README.markdown +++ b/README.markdown @@ -7,7 +7,7 @@ Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation of complex SQL queries -2. Adapts to various RDBM systems +2. Adapts to various RDBMSes It is intended to be a framework framework; that is, you can build your own ORM with it, focusing on innovative object and collection modeling as opposed to From a4ddbe4e80dba6840019862dec54748fc8799163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 4 Dec 2013 23:33:25 -0200 Subject: [PATCH 1178/1492] Remove columns usage from the README Closes #189 --- README.markdown | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index bcdbaba0b247e..c7346d9efdd37 100644 --- a/README.markdown +++ b/README.markdown @@ -111,12 +111,10 @@ Suppose we have a table `products` with prices in different currencies. And we h ```ruby products = Arel::Table.new(:products) -products.columns -# => [products[:id], products[:name], products[:price], products[:currency_id]] +# Attributes: [:id, :name, :price, :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]] +# Attributes: [:from_id, :to_id, :date, :rate] ``` Now, to order products by price in user preferred currency simply call: @@ -139,8 +137,7 @@ comments = Arel::Table.new(:comments) And this table has the following attributes: ```ruby -comments.columns -# => [comments[:id], comments[:body], comments[:parent_id]] +# [:id, :body, :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: From f1192f74282850ba2884d55934732ceb4ae5f891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 4 Dec 2013 23:58:55 -0200 Subject: [PATCH 1179/1492] Release 5.0.0 --- History.txt | 10 ++++++++++ arel.gemspec | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/History.txt b/History.txt index 7123d49bbf9c7..60aae4a59b28c 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,13 @@ +== 5.0.0 / 2013-12-04 + +* Enhancements + + * Remove deprecated code + +* Bug Fixes + + * Fix serializing a relation when calling `to_yaml` + == 4.0.1 / 2013-10-22 * Enhancements diff --git a/arel.gemspec b/arel.gemspec index fbd7c967f83f9..3c58ef26e31c1 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,14 +1,14 @@ # -*- encoding: utf-8 -*- -# stub: arel 5.0.0.20131118174145 ruby lib +# stub: arel 5.0.0.20131204235845 ruby lib Gem::Specification.new do |s| s.name = "arel" - s.version = "5.0.0.20131118174145" + s.version = "5.0.0.20131204235845" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2013-11-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.date = "2013-12-05" + s.description = "Arel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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"] From 0507bc3f58b7d6a36d93dcd5c21d7f40e9322c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 5 Dec 2013 00:18:22 -0200 Subject: [PATCH 1180/1492] Remove deprecated calls from the tests --- lib/arel/visitors/mssql.rb | 4 ++-- test/test_crud.rb | 2 +- test/test_select_manager.rb | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 9a88ee5b0fef3..2f5edce19a872 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -62,8 +62,8 @@ 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?? + # FIXME raise exception of there is no pk? + # FIXME!! Table.primary_key will be deprecated. What is the replacement?? def find_left_table_pk o, a return visit o.primary_key, a if o.instance_of? Arel::Table find_left_table_pk o.left, a if o.kind_of? Arel::Nodes::Join diff --git a/test/test_crud.rb b/test/test_crud.rb index ded1b632b7bf7..5c470155acfb3 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -45,7 +45,7 @@ def initialize engine = FakeEngine.new table = Table.new :users fc = FakeCrudder.new fc.from table - stmt = fc.compile_update [[table[:id], 'foo']], table.primary_key + stmt = fc.compile_update [[table[:id], 'foo']], Arel::Attributes::Attribute.new(table, 'id') assert_instance_of Arel::UpdateManager, stmt end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 960e2b1a021ea..b2db28753bd70 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -921,7 +921,7 @@ def test_join_sources manager = Arel::SelectManager.new engine manager.from table manager.take 1 - stmt = manager.compile_update(SqlLiteral.new('foo = bar'), table.primary_key) + stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) stmt.key = table['id'] stmt.to_sql.must_be_like %{ @@ -936,7 +936,7 @@ def test_join_sources manager = Arel::SelectManager.new engine manager.from table manager.order :foo - stmt = manager.compile_update(SqlLiteral.new('foo = bar'), table.primary_key) + stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) stmt.key = table['id'] stmt.to_sql.must_be_like %{ @@ -950,7 +950,7 @@ def test_join_sources table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - stmt = manager.compile_update(SqlLiteral.new('foo = bar'), table.primary_key) + stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end @@ -961,7 +961,7 @@ def test_join_sources manager = Arel::SelectManager.new engine manager.where table[:id].eq 10 manager.from table - stmt = manager.compile_update({table[:id] => 1}, table.primary_key) + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 @@ -975,7 +975,7 @@ def test_join_sources manager.where table[:foo].eq 10 manager.take 42 manager.from table - stmt = manager.compile_update({table[:id] => 1}, table.primary_key) + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42) @@ -987,7 +987,7 @@ def test_join_sources table = Table.new :users manager = Arel::SelectManager.new engine manager.from table - stmt = manager.compile_update({table[:id] => 1}, table.primary_key) + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 From fa6cc5c5b20dc4858292e4c659c25b08c4ee4744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 5 Dec 2013 00:25:09 -0200 Subject: [PATCH 1181/1492] Remove joins method --- lib/arel/table.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 32e3d84099c46..16ae83c284903 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -52,14 +52,6 @@ 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 From f2e8ef94ff74575389e5aba58cc08a10781aa91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 5 Dec 2013 00:27:32 -0200 Subject: [PATCH 1182/1492] Test on 2.1.0 preview --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 496c32f394b92..36ec6aadfe9ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ rvm: - jruby - 1.9.3 - 2.0.0 + - 2.1.0-preview2 notifications: email: false irc: From 6f8a16ae333fca8ae9e3f497a32264d23ca21137 Mon Sep 17 00:00:00 2001 From: Robb Shecter Date: Thu, 5 Dec 2013 16:54:34 -0800 Subject: [PATCH 1183/1492] Documented the case-insensitive nature of the match feature. Documenting the library's behavior. People and other libraries (cf. Squeel) have come to depend on this behavior, and so am submitting this pull request to specify it authoritatively. --- lib/arel/visitors/to_sql.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 1d8cd35806fae..554f98da1462c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -42,6 +42,10 @@ class ToSql < Arel::Visitors::Visitor # `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. + # + # `matches` and `doesNotMatch` operate case-insensitively via Visitor subclasses + # specialized for specific databases when necessary. + # WHERE = ' WHERE ' # :nodoc: SPACE = ' ' # :nodoc: From 08d85a9ec47338d1e34e6b17129c3fdbea9e2750 Mon Sep 17 00:00:00 2001 From: Aaron Ackerman Date: Thu, 2 Jan 2014 20:36:36 -0600 Subject: [PATCH 1184/1492] Remove README inaccuracy, where does not allow multiple arguments --- README.markdown | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.markdown b/README.markdown index c7346d9efdd37..e2c60bd90edd5 100644 --- a/README.markdown +++ b/README.markdown @@ -87,12 +87,6 @@ All operators are chainable in this way, and they are chainable any number of ti 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: - -```ruby -users.where(users[:name].eq('bob'), users[:age].lt(25)) -``` - The `OR` operator works like this: ```ruby From 6776911e174a9c26e5ab4620f155e8be114630cf Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sat, 4 Jan 2014 15:27:50 +0530 Subject: [PATCH 1185/1492] Test against ruby 2.1 on travis. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 36ec6aadfe9ee..5544b66d05097 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ rvm: - jruby - 1.9.3 - 2.0.0 - - 2.1.0-preview2 + - 2.1.0 notifications: email: false irc: From 481ff10916a245bd65d188f3821143f648ef9bc1 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sat, 4 Jan 2014 15:38:46 +0530 Subject: [PATCH 1186/1492] Bump minitest to 5.1. --- Gemfile | 2 +- test/nodes/test_ascending.rb | 2 +- test/nodes/test_bin.rb | 2 +- test/nodes/test_descending.rb | 2 +- test/nodes/test_infix_operation.rb | 2 +- test/nodes/test_named_function.rb | 2 +- test/nodes/test_node.rb | 2 +- test/nodes/test_select_core.rb | 2 +- test/test_factory_methods.rb | 2 +- test/visitors/test_bind_visitor.rb | 2 +- test/visitors/test_depth_first.rb | 2 +- test/visitors/test_dot.rb | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile b/Gemfile index bfada66749bfa..12c57d37370fa 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,7 @@ source "https://rubygems.org/" -gem "minitest", "~>4.4", :group => [:development, :test] +gem "minitest", "~>5.1", :group => [:development, :test] gem "rdoc", "~>4.0", :group => [:development, :test] gem "hoe", "~>3.5", :group => [:development, :test] diff --git a/test/nodes/test_ascending.rb b/test/nodes/test_ascending.rb index 63d758a8a82da..2991d46583caa 100644 --- a/test/nodes/test_ascending.rb +++ b/test/nodes/test_ascending.rb @@ -2,7 +2,7 @@ module Arel module Nodes - class TestAscending < MiniTest::Unit::TestCase + class TestAscending < Minitest::Test def test_construct ascending = Ascending.new 'zomg' assert_equal 'zomg', ascending.expr diff --git a/test/nodes/test_bin.rb b/test/nodes/test_bin.rb index c370c5755f98c..1d955b218b182 100644 --- a/test/nodes/test_bin.rb +++ b/test/nodes/test_bin.rb @@ -2,7 +2,7 @@ module Arel module Nodes - class TestBin < MiniTest::Unit::TestCase + class TestBin < Minitest::Test def test_new assert Arel::Nodes::Bin.new('zomg') end diff --git a/test/nodes/test_descending.rb b/test/nodes/test_descending.rb index 22b456fd8db4b..fce71d69e90db 100644 --- a/test/nodes/test_descending.rb +++ b/test/nodes/test_descending.rb @@ -2,7 +2,7 @@ module Arel module Nodes - class TestDescending < MiniTest::Unit::TestCase + class TestDescending < Minitest::Test def test_construct descending = Descending.new 'zomg' assert_equal 'zomg', descending.expr diff --git a/test/nodes/test_infix_operation.rb b/test/nodes/test_infix_operation.rb index b7b6b02d0faca..bec226e395b35 100644 --- a/test/nodes/test_infix_operation.rb +++ b/test/nodes/test_infix_operation.rb @@ -2,7 +2,7 @@ module Arel module Nodes - class TestInfixOperation < MiniTest::Unit::TestCase + class TestInfixOperation < Minitest::Test def test_construct operation = InfixOperation.new :+, 1, 2 assert_equal :+, operation.operator diff --git a/test/nodes/test_named_function.rb b/test/nodes/test_named_function.rb index 9d16f9cbee1bd..33830d9d4369e 100644 --- a/test/nodes/test_named_function.rb +++ b/test/nodes/test_named_function.rb @@ -2,7 +2,7 @@ module Arel module Nodes - class TestNamedFunction < MiniTest::Unit::TestCase + class TestNamedFunction < Minitest::Test def test_construct function = NamedFunction.new 'omg', 'zomg' assert_equal 'omg', function.name diff --git a/test/nodes/test_node.rb b/test/nodes/test_node.rb index 335cba8aab587..056df7a584352 100644 --- a/test/nodes/test_node.rb +++ b/test/nodes/test_node.rb @@ -1,7 +1,7 @@ require 'helper' module Arel - class TestNode < MiniTest::Unit::TestCase + class TestNode < Minitest::Test def test_includes_factory_methods assert Node.new.respond_to?(:create_join) end diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index e4ed06b8531cf..9aca0cff16cd9 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -2,7 +2,7 @@ module Arel module Nodes - class TestSelectCore < MiniTest::Unit::TestCase + class TestSelectCore < Minitest::Test def test_clone core = Arel::Nodes::SelectCore.new core.froms = %w[a b c] diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index 21671cd239524..64d747610bf26 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -2,7 +2,7 @@ module Arel module FactoryMethods - class TestFactoryMethods < MiniTest::Unit::TestCase + class TestFactoryMethods < Minitest::Test class Factory include Arel::FactoryMethods end diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index dbcfb67df53e5..2bfd03c861549 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -4,7 +4,7 @@ module Arel module Visitors - class TestBindVisitor < MiniTest::Unit::TestCase + class TestBindVisitor < Minitest::Test ## # Tests visit_Arel_Nodes_Assignment correctly diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 05360ff6e8d2c..cbaa780dae8d5 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -2,7 +2,7 @@ module Arel module Visitors - class TestDepthFirst < MiniTest::Unit::TestCase + class TestDepthFirst < Minitest::Test Collector = Struct.new(:calls) do def call object calls << object diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 362e39339c2b1..ee7fc7886c1d5 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -2,7 +2,7 @@ module Arel module Visitors - class TestDot < MiniTest::Unit::TestCase + class TestDot < Minitest::Test def setup @visitor = Visitors::Dot.new end From bc37fd4370ce63afc4e85eea43dcce49b61e7838 Mon Sep 17 00:00:00 2001 From: Aaron Ackerman Date: Sat, 4 Jan 2014 14:56:45 -0600 Subject: [PATCH 1187/1492] Assert that SelectManager#project accepts a raw String --- test/test_select_manager.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index b2db28753bd70..2edd69a149888 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1005,16 +1005,14 @@ def test_join_sources it 'takes strings' do manager = Arel::SelectManager.new Table.engine - manager.project Nodes::SqlLiteral.new('*') + manager.project '*' 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 * - } + manager.to_sql.must_be_like %{ SELECT * } end end From 8fdd2eae55980a5709ba7f7d4795d91af8be46cb Mon Sep 17 00:00:00 2001 From: Aaron Ackerman Date: Sat, 4 Jan 2014 15:14:01 -0600 Subject: [PATCH 1188/1492] Removed EngineProxy in SelectManager tests --- test/test_select_manager.rb | 76 ++++--------------------------------- 1 file changed, 8 insertions(+), 68 deletions(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index b2db28753bd70..2d213597ccff5 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1,58 +1,6 @@ require '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 @@ -874,9 +822,8 @@ def test_join_sources describe 'delete' do it "copies from" do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.from table stmt = manager.compile_delete @@ -884,9 +831,8 @@ def test_join_sources end it "copies where" do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.from table manager.where table[:id].eq 10 stmt = manager.compile_delete @@ -916,9 +862,8 @@ def test_join_sources describe 'update' do it 'copies limits' do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.from table manager.take 1 stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) @@ -931,9 +876,8 @@ def test_join_sources end it 'copies order' do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.from table manager.order :foo stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) @@ -946,9 +890,8 @@ def test_join_sources end it 'takes a string' do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.from table stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) @@ -956,9 +899,8 @@ def test_join_sources end it 'copies where clauses' do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.where table[:id].eq 10 manager.from table stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) @@ -969,9 +911,8 @@ def test_join_sources 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 = Arel::SelectManager.new Table.engine manager.where table[:foo].eq 10 manager.take 42 manager.from table @@ -983,9 +924,8 @@ def test_join_sources end it 'executes an update statement' do - engine = EngineProxy.new Table.engine table = Table.new :users - manager = Arel::SelectManager.new engine + manager = Arel::SelectManager.new Table.engine manager.from table stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) From b72e076dde06c7e9d357d4b2baf87c44f8cace79 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 7 Jan 2014 19:00:55 +0530 Subject: [PATCH 1189/1492] Extract comparison array to a constant for the time being until removing the check completely. --- lib/arel/select_manager.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 60df12c700633..5fbe642df0ba7 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -2,6 +2,8 @@ module Arel class SelectManager < Arel::TreeManager include Arel::Crud + STRING_OR_SYMBOL_CLASS = [Symbol, String] + def initialize engine, table = nil super(engine) @ast = Nodes::SelectStatement.new @@ -128,7 +130,7 @@ 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 + STRING_OR_SYMBOL_CLASS.include?(x.class) ? SqlLiteral.new(x.to_s) : x } self end @@ -152,7 +154,7 @@ def distinct(value = true) 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 + STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x } self end From f0ba9e4e56cf4dfa266147fad7e8f58ca577d614 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 14 Jan 2014 14:32:32 -0800 Subject: [PATCH 1190/1492] add bind values to the manager class --- lib/arel/tree_manager.rb | 3 +++ test/test_select_manager.rb | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 21a52d8a60061..1adb230991034 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -4,9 +4,12 @@ class TreeManager attr_reader :ast, :engine + attr_accessor :bind_values + def initialize engine @engine = engine @ctx = nil + @bind_values = [] end def to_dot diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 35b1ba40bfc74..6d0407c65c77a 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -9,6 +9,13 @@ def test_join_sources assert_equal "SELECT FROM 'foo'", manager.to_sql end + def test_manager_stores_bind_values + manager = Arel::SelectManager.new Table.engine + assert_equal [], manager.bind_values + manager.bind_values = [1] + assert_equal [1], manager.bind_values + end + describe 'backwards compatibility' do describe 'project' do it 'accepts symbols as sql literals' do From f3938cd77a2e2602a919c3ce4189f29f056dc68c Mon Sep 17 00:00:00 2001 From: vanderhoorn Date: Wed, 5 Feb 2014 13:21:19 +0100 Subject: [PATCH 1191/1492] PostgreSQL bugfix for invalid SQL in subqueries In commit 68a95542e1a7a79d9777223fbffd2b982fed0268 the last_column feature of ToSql was removed. The visit_Arel_Nodes_Matches and visit_Arel_Nodes_DoesNotMatch methods are overwritten in the PostgreSQL class, but were not updated appropriately. This commit fixes the issue accordingly. This bug affects at least all update_all statements in Rails 4.0.2 that have subqueries with ILIKE statements on PostgreSQL. The bug is present in Arel 4.0.1 and later, so it probably affects most Rails 4.0.2 projects. It would be highly appreciated if Arel 4 could get a point release as well. Thanks for your continued work. --- lib/arel/visitors/postgresql.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 080e402e3b625..7520a1ccc79bc 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -4,10 +4,12 @@ class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Matches o, a + a = o.left if Arel::Attributes::Attribute === o.left "#{visit o.left, a} ILIKE #{visit o.right, a}" end def visit_Arel_Nodes_DoesNotMatch o, a + a = o.left if Arel::Attributes::Attribute === o.left "#{visit o.left, a} NOT ILIKE #{visit o.right, a}" end From 557a8769ae5b1e82af0efb1cf07cbc7bc24e3452 Mon Sep 17 00:00:00 2001 From: Roel van der Hoorn Date: Wed, 5 Feb 2014 19:18:56 +0100 Subject: [PATCH 1192/1492] Add tests for PostgreSLQ bugfix regarding invalid SQL in subqueries when using matches() or does_not_match(). --- test/visitors/test_postgres.rb | 36 ++++++++++++++++++++++++++++++++++ test/visitors/test_to_sql.rb | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 921bd96c1a877..dc68279b8dc9e 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -5,6 +5,8 @@ module Visitors describe 'the postgres visitor' do before do @visitor = PostgreSQL.new Table.engine.connection + @table = Table.new(:users) + @attr = @table[:id] end describe 'locking' do @@ -43,6 +45,40 @@ module Visitors core.set_quantifier = Arel::Nodes::Distinct.new assert_equal 'SELECT DISTINCT', @visitor.accept(core) end + + describe "Nodes::Matches" do + it "should know how to visit" do + node = @table[:name].matches('foo%') + @visitor.accept(node).must_be_like %{ + "users"."name" ILIKE 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') + } + end + end + + describe "Nodes::DoesNotMatch" do + it "should know how to visit" do + node = @table[:name].does_not_match('foo%') + @visitor.accept(node).must_be_like %{ + "users"."name" NOT ILIKE 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT ILIKE 'foo%') + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index eb35d1703a2fe..34d3459a27ecd 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -194,6 +194,40 @@ def dispatch @visitor.accept(test).must_be_like %{ "users"."bool" = 't' } end + describe "Nodes::Matches" do + it "should know how to visit" do + node = @table[:name].matches('foo%') + @visitor.accept(node).must_be_like %{ + "users"."name" LIKE 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" LIKE 'foo%') + } + end + end + + describe "Nodes::DoesNotMatch" do + it "should know how to visit" do + node = @table[:name].does_not_match('foo%') + @visitor.accept(node).must_be_like %{ + "users"."name" NOT LIKE 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT LIKE 'foo%') + } + end + end + describe "Nodes::Ordering" do it "should know how to visit" do node = @attr.desc From 493def415de78fd01a234a70b94e2bb5fde19ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 5 Feb 2014 18:09:53 -0200 Subject: [PATCH 1193/1492] Sync CHANGELOG --- History.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/History.txt b/History.txt index 60aae4a59b28c..e5234e0f9ad76 100644 --- a/History.txt +++ b/History.txt @@ -8,6 +8,13 @@ * Fix serializing a relation when calling `to_yaml` +=== 4.0.2 / 2014-02-05 + + * Bug Fixes + + * Fix `SqlLiteral` YAML serialization + * PostgreSQL bugfix for invalid SQL in subqueries + == 4.0.1 / 2013-10-22 * Enhancements From b1965567c34a6349c365875bfd2988823819cc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 5 Feb 2014 18:43:07 -0200 Subject: [PATCH 1194/1492] Use rbx on travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5544b66d05097..4725665611f43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ script: "rake test" rvm: - - rbx-19mode + - rbx - jruby - 1.9.3 - 2.0.0 From ff6fe8529cd0be9a52e779f295e0c660493b95b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 5 Feb 2014 18:52:12 -0200 Subject: [PATCH 1195/1492] Allow failures on rubinius --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4725665611f43..0eb36dcda2859 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,9 @@ rvm: - 1.9.3 - 2.0.0 - 2.1.0 +matrix: + allow_failures: + - rvm: rbx notifications: email: false irc: From 73f8d385971cf8244aec73d526bf9e7d17955a47 Mon Sep 17 00:00:00 2001 From: Roel van der Hoorn Date: Fri, 7 Feb 2014 19:41:11 +0100 Subject: [PATCH 1196/1492] Add tests for Nodes::Equality and Nodes::NotEqual to the ToSql class. --- test/visitors/test_to_sql.rb | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 34d3459a27ecd..35effd4105ea3 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -92,7 +92,14 @@ def dispatch assert_equal 'omg(*, *)', @visitor.accept(function) end - describe 'equality' do + describe 'Nodes::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 + it 'should handle false' do sql = @visitor.accept Nodes::Equality.new(false, false) sql.must_be_like %{ 'f' = 'f' } @@ -103,6 +110,23 @@ def dispatch sql = @visitor.accept Nodes::Equality.new(table[:id], '1-fooo') sql.must_be_like %{ "users"."id" = 1 } end + + it 'should handle nil' do + sql = @visitor.accept Nodes::Equality.new(@table[:name], nil) + sql.must_be_like %{ "users"."name" IS NULL } + end + end + + describe 'Nodes::NotEqual' do + it 'should handle false' do + sql = @visitor.accept Nodes::NotEqual.new(@table[:active], false) + sql.must_be_like %{ "users"."active" != 'f' } + end + + it 'should handle nil' do + sql = @visitor.accept Nodes::NotEqual.new(@table[:name], nil) + sql.must_be_like %{ "users"."name" IS NOT NULL } + end end it "should visit string subclass" do @@ -412,15 +436,6 @@ def quote value, column = nil 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 From a09c9f061734436bb59ff3571284800319ae009f Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sat, 4 Jan 2014 15:20:23 +0530 Subject: [PATCH 1197/1492] Removed deprecated `Arel::Sql::Engine` and make use of `FakeRecord::Base` inplace directly for test helper. --- lib/arel.rb | 1 - lib/arel/sql/engine.rb | 10 ---------- test/helper.rb | 2 +- 3 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 lib/arel/sql/engine.rb diff --git a/lib/arel.rb b/lib/arel.rb index fd0a81a5a05f9..b1faf8ef71cb1 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -27,7 +27,6 @@ #### these are deprecated require 'arel/deprecated' -require 'arel/sql/engine' require 'arel/sql_literal' #### diff --git a/lib/arel/sql/engine.rb b/lib/arel/sql/engine.rb deleted file mode 100644 index 8917f5f29423c..0000000000000 --- a/lib/arel/sql/engine.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - module Sql - class Engine - def self.new thing - #warn "#{caller.first} -- Engine will be removed" - thing - end - end - end -end diff --git a/test/helper.rb b/test/helper.rb index f13596f9ec84b..1292c09a08b6c 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -4,7 +4,7 @@ require 'arel' require 'support/fake_record' -Arel::Table.engine = Arel::Sql::Engine.new(FakeRecord::Base.new) +Arel::Table.engine = FakeRecord::Base.new class Object def must_be_like other From d956772b3c61d97940ebcccd7c83e2397ca0c36c Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 7 Jan 2014 17:57:39 +0530 Subject: [PATCH 1198/1492] Remove deprecated `SelectManager#to_a` --- lib/arel/select_manager.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 5fbe642df0ba7..010845cf5628b 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -255,12 +255,6 @@ def method_missing(name, *args) 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 - private def collapse exprs, existing = nil exprs = exprs.unshift(existing.expr) if existing From 36d3452f0471b9e2c151abf43e0392cb54f1f422 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 7 Jan 2014 18:53:34 +0530 Subject: [PATCH 1199/1492] Remove deprecated `SelectManager#joins` --- lib/arel/select_manager.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 010845cf5628b..f251d0d09e4b7 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -235,14 +235,6 @@ 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'] From f4ab6a39be5c4743ed1dc5605c65688a67dfa42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 5 Feb 2014 18:26:22 -0200 Subject: [PATCH 1200/1492] Remove deprecated constant aliases --- lib/arel.rb | 1 - lib/arel/deprecated.rb | 4 ---- 2 files changed, 5 deletions(-) delete mode 100644 lib/arel/deprecated.rb diff --git a/lib/arel.rb b/lib/arel.rb index b1faf8ef71cb1..38cb47de5aa41 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -26,7 +26,6 @@ #### these are deprecated -require 'arel/deprecated' require 'arel/sql_literal' #### diff --git a/lib/arel/deprecated.rb b/lib/arel/deprecated.rb deleted file mode 100644 index 31db11bd2ccc5..0000000000000 --- a/lib/arel/deprecated.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Arel - InnerJoin = Nodes::InnerJoin - OuterJoin = Nodes::OuterJoin -end From a7d06943dd54b2d16d63b2b9a67bb97820c7c8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 5 Feb 2014 18:40:52 -0200 Subject: [PATCH 1201/1492] Remove deprecated Arel::SqlLiteral --- lib/arel.rb | 5 ----- lib/arel/insert_manager.rb | 2 +- lib/arel/select_manager.rb | 2 +- lib/arel/sql_literal.rb | 4 ---- lib/arel/visitors/depth_first.rb | 1 - lib/arel/visitors/dot.rb | 1 - lib/arel/visitors/to_sql.rb | 1 - test/test_select_manager.rb | 20 ++++++++++---------- test/test_table.rb | 6 +++--- 9 files changed, 15 insertions(+), 27 deletions(-) delete mode 100644 lib/arel/sql_literal.rb diff --git a/lib/arel.rb b/lib/arel.rb index 38cb47de5aa41..a2a358892fbf6 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -24,11 +24,6 @@ require 'arel/delete_manager' require 'arel/nodes' - -#### these are deprecated -require 'arel/sql_literal' -#### - module Arel VERSION = '5.0.0' diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index d6a11b7be01c7..b5d2aeb3a489b 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -17,7 +17,7 @@ def insert fields return if fields.empty? if String === fields - @ast.values = SqlLiteral.new(fields) + @ast.values = Nodes::SqlLiteral.new(fields) else @ast.relation ||= fields.first.first.relation diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f251d0d09e4b7..e3d8792acaab5 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -130,7 +130,7 @@ def project *projections # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. @ctx.projections.concat projections.map { |x| - STRING_OR_SYMBOL_CLASS.include?(x.class) ? SqlLiteral.new(x.to_s) : x + STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x } self end diff --git a/lib/arel/sql_literal.rb b/lib/arel/sql_literal.rb deleted file mode 100644 index 5cb4973117647..0000000000000 --- a/lib/arel/sql_literal.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Arel - class SqlLiteral < Nodes::SqlLiteral - end -end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 67cdecfa369a8..18bd81fb9c797 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -112,7 +112,6 @@ def terminal o, a 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 diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 82b8c771e4a76..cb4c2d494c851 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -193,7 +193,6 @@ def visit_String o, a 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 554f98da1462c..bd0cd8f03c6e3 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -550,7 +550,6 @@ def literal o, a; 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 6d0407c65c77a..c1575a79292e1 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -33,7 +33,7 @@ def test_manager_stores_bind_values it 'accepts symbols' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order :foo manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo } @@ -224,7 +224,7 @@ def test_manager_stores_bind_values it 'should create an exists clause' do table = Table.new(:users) manager = Arel::SelectManager.new Table.engine, table - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' m2 = Arel::SelectManager.new(manager.engine) m2.project manager.exists m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) } @@ -233,7 +233,7 @@ def test_manager_stores_bind_values it 'can be aliased' do table = Table.new(:users) manager = Arel::SelectManager.new Table.engine, table - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' m2 = Arel::SelectManager.new(manager.engine) m2.project manager.exists.as('foo') m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo } @@ -413,7 +413,7 @@ def test_manager_stores_bind_values it 'generates order clauses' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id] manager.to_sql.must_be_like %{ @@ -425,7 +425,7 @@ def test_manager_stores_bind_values it 'takes *args' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id], table[:name] manager.to_sql.must_be_like %{ @@ -442,7 +442,7 @@ def test_manager_stores_bind_values it 'has order attributes' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id].desc manager.to_sql.must_be_like %{ @@ -453,7 +453,7 @@ def test_manager_stores_bind_values it 'has order attributes for expressions' do table = Table.new :users manager = Arel::SelectManager.new Table.engine - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id].count.desc manager.to_sql.must_be_like %{ @@ -873,7 +873,7 @@ def test_manager_stores_bind_values manager = Arel::SelectManager.new Table.engine manager.from table manager.take 1 - stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) stmt.key = table['id'] stmt.to_sql.must_be_like %{ @@ -887,7 +887,7 @@ def test_manager_stores_bind_values manager = Arel::SelectManager.new Table.engine manager.from table manager.order :foo - stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) stmt.key = table['id'] stmt.to_sql.must_be_like %{ @@ -900,7 +900,7 @@ def test_manager_stores_bind_values table = Table.new :users manager = Arel::SelectManager.new Table.engine manager.from table - stmt = manager.compile_update(SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end diff --git a/test/test_table.rb b/test/test_table.rb index 5db8cdd6c067e..2c1683b4ce38e 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -130,19 +130,19 @@ module Arel describe 'take' do it "should add a limit" do manager = @relation.take 1 - manager.project SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new '*' manager.to_sql.must_be_like %{ SELECT * FROM "users" LIMIT 1 } end end describe 'project' do it 'can project' do - manager = @relation.project SqlLiteral.new '*' + manager = @relation.project Nodes::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 = @relation.project Nodes::SqlLiteral.new('*'), Nodes::SqlLiteral.new('*') manager.to_sql.must_be_like %{ SELECT *, * FROM "users" } end end From 7bf868e320efb0b53b0ce51afb925174e5db2377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 10 Feb 2014 18:58:54 -0200 Subject: [PATCH 1202/1492] Remove deprecated Arel::Expression --- lib/arel.rb | 4 ---- lib/arel/expression.rb | 5 ----- lib/arel/nodes/extract.rb | 2 -- lib/arel/nodes/function.rb | 1 - lib/arel/nodes/window.rb | 1 - test/nodes/test_count.rb | 6 ------ test/test_select_manager.rb | 12 ------------ 7 files changed, 31 deletions(-) delete mode 100644 lib/arel/expression.rb diff --git a/lib/arel.rb b/lib/arel.rb index a2a358892fbf6..70b46fc48669f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -11,10 +11,6 @@ require 'arel/attributes' require 'arel/compatibility/wheres' -#### these are deprecated -require 'arel/expression' -#### - require 'arel/visitors' require 'arel/tree_manager' diff --git a/lib/arel/expression.rb b/lib/arel/expression.rb deleted file mode 100644 index 3884d6ede6ed6..0000000000000 --- a/lib/arel/expression.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Arel - module Expression - include Arel::OrderPredications - end -end diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb index 92fbde62e122a..64f5c3ff0f83e 100644 --- a/lib/arel/nodes/extract.rb +++ b/lib/arel/nodes/extract.rb @@ -1,8 +1,6 @@ module Arel module Nodes - class Extract < Arel::Nodes::Unary - include Arel::Expression include Arel::Predications attr_accessor :field diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index dcafbbf1f4cf2..733a00df46f10 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -1,7 +1,6 @@ module Arel module Nodes class Function < Arel::Nodes::Node - include Arel::Expression include Arel::Predications include Arel::WindowPredications attr_accessor :expressions, :alias, :distinct diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index 3c05f47f14878..60259e8c05a6d 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -1,7 +1,6 @@ module Arel module Nodes class Window < Arel::Nodes::Node - include Arel::Expression attr_accessor :orders, :framing def initialize diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index 88d2a694c8f21..a9a329420ebd1 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -1,12 +1,6 @@ require '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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index c1575a79292e1..cf8903a05b8b8 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -449,18 +449,6 @@ def test_manager_stores_bind_values 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 Nodes::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 From 1ebacd299c5152d367692373faffa93c0a7fe1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 10 Feb 2014 19:40:37 -0200 Subject: [PATCH 1203/1492] Update history --- History.txt | 12 ++++++++++++ Manifest.txt | 4 ---- arel.gemspec | 24 ++++++++++++------------ 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/History.txt b/History.txt index e5234e0f9ad76..4fc06816a39fd 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,15 @@ +=== NEXT / 2014-02-10 + +* Enhancements + + * Remove deprecated `Arel::Expression` + * Remove deprecated `Arel::SqlLiteral` + * Remove deprecated `SelectManager#joins` + * Remove deprecated `SelectManager#to_a` + * Remove deprecated `Arel::Sql::Engine` + * Remove deprecated `Arel::InnerJoin` constant + * Remove deprecated `Arel::OuterJoin` constant + == 5.0.0 / 2013-12-04 * Enhancements diff --git a/Manifest.txt b/Manifest.txt index ead313ce3f539..a5c2c2bab5771 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -15,8 +15,6 @@ 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 @@ -58,8 +56,6 @@ 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 diff --git a/arel.gemspec b/arel.gemspec index 3c58ef26e31c1..84caf0df0810a 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,23 +1,23 @@ # -*- encoding: utf-8 -*- -# stub: arel 5.0.0.20131204235845 ruby lib +# stub: arel 5.0.0.20140210193626 ruby lib Gem::Specification.new do |s| s.name = "arel" - s.version = "5.0.0.20131204235845" + s.version = "5.0.0.20140210193626" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib"] s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2013-12-05" + s.date = "2014-02-10" s.description = "Arel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] - s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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.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/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/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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] - s.require_paths = ["lib"] s.rubyforge_project = "arel" - s.rubygems_version = "2.1.11" + s.rubygems_version = "2.2.0" 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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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"] @@ -25,17 +25,17 @@ Gem::Specification.new do |s| s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 5.0"]) + s.add_development_dependency(%q, ["~> 5.2"]) s.add_development_dependency(%q, ["~> 4.0"]) - s.add_development_dependency(%q, ["~> 3.7"]) + s.add_development_dependency(%q, ["~> 3.8"]) else - s.add_dependency(%q, ["~> 5.0"]) + s.add_dependency(%q, ["~> 5.2"]) s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.7"]) + s.add_dependency(%q, ["~> 3.8"]) end else - s.add_dependency(%q, ["~> 5.0"]) + s.add_dependency(%q, ["~> 5.2"]) s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.7"]) + s.add_dependency(%q, ["~> 3.8"]) end end From d1ec33d69d85a3608aef9b064bc2c4799a214000 Mon Sep 17 00:00:00 2001 From: Loic Nageleisen Date: Tue, 4 Feb 2014 11:38:00 +0100 Subject: [PATCH 1204/1492] Allow assignment right member to reference columns Such queries become possible for mortals: ```ruby table.where(table[:qux].eq 'zomg').compile_update(table[:foo] => table[:bar]) ``` Arguably much more sane than using `engine.connection.quote_column_name` or `engine.connection.visitor.accept` on the right hand (bar), which is totally leaking the abstraction. --- lib/arel/visitors/to_sql.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 554f98da1462c..ede43095ab9ef 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -501,8 +501,13 @@ def visit_Arel_Nodes_Or o, a end def visit_Arel_Nodes_Assignment o, a - right = quote(o.right, column_for(o.left)) - "#{visit o.left, a} = #{right}" + case o.right + when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute + "#{visit o.left, a} = #{visit o.right, a}" + else + right = quote(o.right, column_for(o.left)) + "#{visit o.left, a} = #{right}" + end end def visit_Arel_Nodes_Equality o, a From 164645423935738ca7a56ef233b3c4fd9d43eea3 Mon Sep 17 00:00:00 2001 From: cmohanprasath Date: Tue, 18 Feb 2014 15:11:08 +0200 Subject: [PATCH 1205/1492] Test case for Issue No 242. The evaluates the assignment of two unqualified columns. --- test/visitors/test_to_sql.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 35effd4105ea3..b4fdd51abde17 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -208,6 +208,17 @@ def dispatch } end + it "should visit_Arel_Nodes_Assignment" do + column = @table["id"] + node = Nodes::Assignment.new( + Nodes::UnqualifiedColumn.new(column), + Nodes::UnqualifiedColumn.new(column) + ) + @visitor.accept(node).must_be_like %{ + "id" = "id" + } + end + it "should visit visit_Arel_Attributes_Time" do attr = Attributes::Time.new(@attr.relation, @attr.name) @visitor.accept attr From 5c415ec6c10ad71684ab6422a43d10d3d07ad07c Mon Sep 17 00:00:00 2001 From: Ryan Davis Date: Tue, 18 Feb 2014 14:45:40 -0800 Subject: [PATCH 1206/1492] fixed the readme per discussion w/ tenderlove --- README.markdown | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.markdown b/README.markdown index e2c60bd90edd5..99263dc2d22ad 100644 --- a/README.markdown +++ b/README.markdown @@ -4,6 +4,8 @@ ## DESCRIPTION +Arel Really Exasperates Logicians + Arel is a SQL AST manager for Ruby. It 1. Simplifies the generation of complex SQL queries @@ -35,7 +37,7 @@ 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. +Here is a whirlwind tour through the most common SQL operators. These will probably cover 80% of all interaction with the database. First is the 'restriction' operator, `where`: @@ -72,7 +74,7 @@ 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: +The best property of arel is its "composability", or closure under all operations. For example, to restrict AND project, just "chain" the method invocations: ```ruby users \ From 93d72131bcc24ccb5536bec672d2dac94f8de651 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 24 Mar 2014 16:26:09 -0700 Subject: [PATCH 1207/1492] add the casting node to the AST at build time If we add the casting node to the ast at build time, then we can avoid doing the lookup at visit time. --- lib/arel/nodes.rb | 32 +++++++++++++ lib/arel/nodes/node.rb | 2 + lib/arel/predications.rb | 8 ++-- lib/arel/update_manager.rb | 4 +- lib/arel/visitors/mysql.rb | 4 +- lib/arel/visitors/to_sql.rb | 40 ++++++++++------ test/attributes/test_attribute.rb | 2 +- test/nodes/test_equality.rb | 2 +- test/nodes/test_grouping.rb | 2 +- test/nodes/test_sql_literal.rb | 2 +- test/support/fake_record.rb | 6 ++- test/test_insert_manager.rb | 3 +- test/test_select_manager.rb | 4 +- test/test_table.rb | 3 +- test/visitors/test_ibm_db.rb | 8 ++-- test/visitors/test_informix.rb | 8 ++-- test/visitors/test_join_sql.rb | 2 +- test/visitors/test_mysql.rb | 13 +++--- test/visitors/test_postgres.rb | 6 +-- test/visitors/test_to_sql.rb | 78 ++++++++++++++++++++++++------- 20 files changed, 166 insertions(+), 63 deletions(-) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 54caea69a192b..3642958cf8ba9 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -50,3 +50,35 @@ require 'arel/nodes/string_join' require 'arel/nodes/sql_literal' + +module Arel + module Nodes + class Casted < Arel::Nodes::Node # :nodoc: + attr_reader :val, :attribute + def initialize val, attribute + @val = val + @attribute = attribute + super() + end + + def nil?; @val.nil?; end + end + + class Quoted < Arel::Nodes::Unary # :nodoc: + end + + def self.build_quoted other, attribute = nil + case other + when Arel::Nodes::Node, Arel::Attributes::Attribute + other + else + case attribute + when Arel::Attributes::Attribute + Casted.new other, attribute + else + Quoted.new other + end + end + end + end +end diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 36e762861255c..a3eadf7170135 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -51,6 +51,8 @@ def each &block ::Arel::Visitors::DepthFirst.new(block).accept self end + + def cast_reference?; false; end # :nodoc: end end end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index c485de07e3cca..fb98f0a383ebb 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -13,7 +13,7 @@ def not_eq_all others end def eq other - Nodes::Equality.new self, other + Nodes::Equality.new self, Nodes.build_quoted(other, self) end def eq_any others @@ -21,7 +21,7 @@ def eq_any others end def eq_all others - grouping_all :eq, others + grouping_all :eq, others.map { |x| Nodes.build_quoted(x, self) } end def in other @@ -93,7 +93,7 @@ def not_in_all others end def matches other - Nodes::Matches.new self, other + Nodes::Matches.new self, Nodes.build_quoted(other, self) end def matches_any others @@ -105,7 +105,7 @@ def matches_all others end def does_not_match other - Nodes::DoesNotMatch.new self, other + Nodes::DoesNotMatch.new self, Nodes.build_quoted(other, self) end def does_not_match_any others diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 56e219040c17f..db8cf05f7667d 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -7,12 +7,12 @@ def initialize engine end def take limit - @ast.limit = Nodes::Limit.new(limit) if limit + @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit self end def key= key - @ast.key = key + @ast.key = Nodes.build_quoted(key) end def key diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 4db5a94019f03..ec9d91f8ce926 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -32,7 +32,9 @@ def visit_Arel_Nodes_Bin o, a # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 def visit_Arel_Nodes_SelectStatement o, a - o.limit = Arel::Nodes::Limit.new(18446744073709551615) if o.offset && !o.limit + if o.offset && !o.limit + o.limit = Arel::Nodes::Limit.new(Nodes.build_quoted(18446744073709551615)) + end super end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 236f0354b14fc..69c82e792a51d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -116,6 +116,14 @@ def visit_Arel_Nodes_Exists o, a o.alias ? " AS #{visit o.alias, a}" : ''}" end + def visit_Arel_Nodes_Casted o, a + quoted o.val, o.attribute + end + + def visit_Arel_Nodes_Quoted o, a + quoted o.expr, nil + end + def visit_Arel_Nodes_True o, a "TRUE" end @@ -562,20 +570,24 @@ def quoted o, a quote(o, column_for(a)) 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 unsupported o, a + raise "unsupported: #{o.class.name}" + end + + alias :visit_ActiveSupport_Multibyte_Chars :unsupported + alias :visit_ActiveSupport_StringInquirer :unsupported + alias :visit_BigDecimal :unsupported + alias :visit_Class :unsupported + alias :visit_Date :unsupported + alias :visit_DateTime :unsupported + alias :visit_FalseClass :unsupported + alias :visit_Float :unsupported + alias :visit_Hash :unsupported + alias :visit_NilClass :unsupported + alias :visit_String :unsupported + alias :visit_Symbol :unsupported + alias :visit_Time :unsupported + alias :visit_TrueClass :unsupported def visit_Arel_Nodes_InfixOperation o, a "#{visit o.left, a} #{o.operator} #{visit o.right, a}" diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 901850ff4bd61..e53b32d0ac399 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -329,7 +329,7 @@ module Attributes attribute = Attribute.new nil, nil equality = attribute.eq 1 equality.left.must_equal attribute - equality.right.must_equal 1 + equality.right.val.must_equal 1 equality.must_be_kind_of Nodes::Equality end diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb index 79764cc7d361d..42a156b051a29 100644 --- a/test/nodes/test_equality.rb +++ b/test/nodes/test_equality.rb @@ -43,7 +43,7 @@ def quote_table_name(*args) @quote_count += 1; super; end attr = Table.new(:users)[:id] test = attr.eq(10) test.to_sql engine - engine.connection.quote_count.must_equal 2 + engine.connection.quote_count.must_equal 3 end end end diff --git a/test/nodes/test_grouping.rb b/test/nodes/test_grouping.rb index b7aa51d37f5e7..febf0bee40623 100644 --- a/test/nodes/test_grouping.rb +++ b/test/nodes/test_grouping.rb @@ -4,7 +4,7 @@ module Arel module Nodes describe 'Grouping' do it 'should create Equality nodes' do - grouping = Grouping.new('foo') + grouping = Grouping.new(Nodes.build_quoted('foo')) grouping.eq('foo').to_sql.must_be_like %q{('foo') = 'foo'} end diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index 085c5dad6be29..2f17cfd72a4a8 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -5,7 +5,7 @@ module Arel module Nodes describe 'sql literal' do before do - @visitor = Visitors::ToSql.new Table.engine.connection_pool + @visitor = Visitors::ToSql.new Table.engine.connection end describe 'sql' do diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 58883e43cd59e..ed4420a2cdd1c 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -66,6 +66,10 @@ def quote thing, column = nil end case thing + when DateTime + "'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'" + when Date + "'#{thing.strftime("%Y-%m-%d")}'" when true "'t'" when false @@ -75,7 +79,7 @@ def quote thing, column = nil when Numeric thing else - "'#{thing}'" + "'#{thing.to_s.gsub("'", "\\\\'")}'" end end end diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 2c5000fb8b7cd..9e4cc9d05e2f7 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -20,9 +20,10 @@ module Arel it 'allows sql literals' do manager = Arel::InsertManager.new Table.engine + manager.into Table.new(:users) manager.values = manager.create_values [Arel.sql('*')], %w{ a } manager.to_sql.must_be_like %{ - INSERT INTO NULL VALUES (*) + INSERT INTO \"users\" VALUES (*) } end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index cf8903a05b8b8..7f025f7a029b8 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -5,7 +5,7 @@ module Arel describe 'select manager' do def test_join_sources manager = Arel::SelectManager.new Table.engine - manager.join_sources << Arel::Nodes::StringJoin.new('foo') + manager.join_sources << Arel::Nodes::StringJoin.new(Nodes.build_quoted('foo')) assert_equal "SELECT FROM 'foo'", manager.to_sql end @@ -602,7 +602,7 @@ def test_manager_stores_bind_values it 'returns string join sql' do manager = Arel::SelectManager.new Table.engine - manager.from Nodes::StringJoin.new('hello') + manager.from Nodes::StringJoin.new(Nodes.build_quoted('hello')) manager.join_sql.must_be_like %{ 'hello' } end diff --git a/test/test_table.rb b/test/test_table.rb index 2c1683b4ce38e..431a919de1a20 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -29,7 +29,8 @@ module Arel 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 + im.into Table.new(:users) + assert_equal "INSERT INTO \"users\" VALUES(NULL)", im.to_sql end it 'should return IM from insert_manager' do diff --git a/test/visitors/test_ibm_db.rb b/test/visitors/test_ibm_db.rb index b055e883d6bfc..75f1daff6a577 100644 --- a/test/visitors/test_ibm_db.rb +++ b/test/visitors/test_ibm_db.rb @@ -15,11 +15,13 @@ module Visitors end it 'uses FETCH FIRST n ROWS in updates with a limit' do + table = Table.new(:users) stmt = Nodes::UpdateStatement.new - stmt.limit = Nodes::Limit.new(1) - stmt.key = 'id' + stmt.relation = table + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) + stmt.key = table[:id] sql = @visitor.accept(stmt) - sql.must_be_like "UPDATE NULL WHERE 'id' IN (SELECT 'id' FETCH FIRST 1 ROWS ONLY)" + sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT \"users\".\"id\" FROM \"users\" FETCH FIRST 1 ROWS ONLY)" end end diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index 90bbf5c10493a..e4c2e81296d7c 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -15,11 +15,13 @@ module Visitors end it 'uses LIMIT n in updates with a limit' do + table = Table.new(:users) stmt = Nodes::UpdateStatement.new - stmt.limit = Nodes::Limit.new(1) - stmt.key = 'id' + stmt.relation = table + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) + stmt.key = table[:id] sql = @visitor.accept(stmt) - sql.must_be_like "UPDATE NULL WHERE 'id' IN (SELECT LIMIT 1 'id')" + sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT LIMIT 1 \"users\".\"id\" FROM \"users\" )" end it 'uses SKIP n to jump results' do diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index b3fc7661aa46a..ea71c05d79ca8 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -9,7 +9,7 @@ module Visitors end it 'should visit string join' do - sql = @visitor.accept Nodes::StringJoin.new('omg') + sql = @visitor.accept Nodes::StringJoin.new(Nodes.build_quoted('omg')) sql.must_be_like "'omg'" end diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 6330112229d93..6b62ec133ae0a 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -8,12 +8,12 @@ module Visitors end it 'squashes parenthesis on multiple unions' do - subnode = Nodes::Union.new 'left', 'right' - node = Nodes::Union.new subnode, 'topright' + subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') + node = Nodes::Union.new subnode, Arel.sql('topright') assert_equal 1, @visitor.accept(node).scan('(').length - subnode = Nodes::Union.new 'left', 'right' - node = Nodes::Union.new 'topleft', subnode + subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') + node = Nodes::Union.new Arel.sql('topleft'), subnode assert_equal 1, @visitor.accept(node).scan('(').length end @@ -29,8 +29,9 @@ module Visitors 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)) + sc.relation = Table.new(:users) + sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) + assert_equal("UPDATE \"users\" LIMIT 'omg'", @visitor.accept(sc)) end it 'uses DUAL for empty from' do diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index dc68279b8dc9e..4287baaf14d14 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -26,9 +26,9 @@ module Visitors 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" + sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) + sc.cores.first.projections << Arel.sql('DISTINCT ON') + sc.orders << Arel.sql("xyz") sql = @visitor.accept(sc) assert_match(/LIMIT 'omg'/, sql) assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit' diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b4fdd51abde17..161a4e1b9e53c 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -4,7 +4,8 @@ module Arel module Visitors describe 'the to_sql visitor' do before do - @visitor = ToSql.new Table.engine.connection + @conn = FakeRecord::Base.new + @visitor = ToSql.new @conn.connection @table = Table.new(:users) @attr = @table[:id] end @@ -101,13 +102,16 @@ def dispatch end it 'should handle false' do - sql = @visitor.accept Nodes::Equality.new(false, false) + table = Table.new(:users) + val = Nodes.build_quoted(false, table[:active]) + sql = @visitor.accept Nodes::Equality.new(val, val) 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') + val = Nodes.build_quoted('1-fooo', table[:id]) + sql = @visitor.accept Nodes::Equality.new(table[:id], val) sql.must_be_like %{ "users"."id" = 1 } end @@ -119,37 +123,61 @@ def dispatch describe 'Nodes::NotEqual' do it 'should handle false' do - sql = @visitor.accept Nodes::NotEqual.new(@table[:active], false) + val = Nodes.build_quoted(false, @table[:active]) + sql = @visitor.accept Nodes::NotEqual.new(@table[:active], val) sql.must_be_like %{ "users"."active" != 'f' } end it 'should handle nil' do - sql = @visitor.accept Nodes::NotEqual.new(@table[:name], nil) + val = Nodes.build_quoted(nil, @table[:active]) + sql = @visitor.accept Nodes::NotEqual.new(@table[:name], val) sql.must_be_like %{ "users"."name" IS NOT NULL } end end it "should visit string subclass" do - @visitor.accept(Class.new(String).new(":'(")) - @visitor.accept(Class.new(Class.new(String)).new(":'(")) + [ + Class.new(String).new(":'("), + Class.new(Class.new(String)).new(":'("), + ].each do |obj| + val = Nodes.build_quoted(obj, @table[:active]) + sql = @visitor.accept Nodes::NotEqual.new(@table[:name], val) + sql.must_be_like %{ "users"."name" != ':\\'(' } + end end it "should visit_Class" do - @visitor.accept(DateTime).must_equal "'DateTime'" + @visitor.accept(Nodes.build_quoted(DateTime)).must_equal "'DateTime'" end it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new - sc.limit = Arel::Nodes::Limit.new("omg") + sc.limit = Arel::Nodes::Limit.new(Nodes.build_quoted("omg")) assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) end it "should visit_DateTime" do - @visitor.accept DateTime.now + called_with = nil + @conn.connection.extend(Module.new { + define_method(:quote) do |thing, column| + called_with = column + super(thing, column) + end + }) + + dt = DateTime.now + table = Table.new(:users) + test = table[:created_at].eq dt + sql = @visitor.accept test + + assert_equal "created_at", called_with.name + sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d %H:%M:%S")}'} end it "should visit_Float" do - @visitor.accept 2.14 + test = Table.new(:users)[:name].eq 2.14 + sql = @visitor.accept test + sql.must_be_like %{"users"."name" = 2.14} end it "should visit_Not" do @@ -174,19 +202,33 @@ def dispatch end it "should visit_Hash" do - @visitor.accept({:a => 1}) + @visitor.accept(Nodes.build_quoted({:a => 1})) end it "should visit_BigDecimal" do - @visitor.accept BigDecimal.new('2.14') + @visitor.accept Nodes.build_quoted(BigDecimal.new('2.14')) end it "should visit_Date" do - @visitor.accept Date.today + called_with = nil + @conn.connection.extend(Module.new { + define_method(:quote) do |thing, column| + called_with = column + super(thing, column) + end + }) + + dt = Date.today + table = Table.new(:users) + test = table[:created_at].eq dt + sql = @visitor.accept test + + assert_equal "created_at", called_with.name + sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d")}'} end it "should visit_NilClass" do - @visitor.accept(nil).must_be_like "NULL" + @visitor.accept(Nodes.build_quoted(nil)).must_be_like "NULL" end it "should visit_Arel_SelectManager, which is a subquery" do @@ -335,7 +377,8 @@ def quote value, column = nil super end end - in_node = Nodes::In.new @attr, %w{ a b c } + vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) } + in_node = Nodes::In.new @attr, vals visitor = visitor.new(Table.engine.connection) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' @@ -438,7 +481,8 @@ def quote value, column = nil super end end - in_node = Nodes::NotIn.new @attr, %w{ a b c } + vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) } + in_node = Nodes::NotIn.new @attr, vals visitor = visitor.new(Table.engine.connection) visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' From d38352ef9e63ec6e1ffee3e4fe78101df36bd6d8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 24 Mar 2014 16:50:34 -0700 Subject: [PATCH 1208/1492] build quoted strings --- lib/arel/factory_methods.rb | 2 +- lib/arel/predications.rb | 14 +++++++------- lib/arel/select_manager.rb | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index 3b16feae1074e..cb66f6f888419 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -37,7 +37,7 @@ def grouping expr ### # Create a LOWER() function def lower column - Nodes::NamedFunction.new 'LOWER', [column] + Nodes::NamedFunction.new 'LOWER', [Nodes.build_quoted(column)] end end end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index fb98f0a383ebb..74411a0522da9 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -32,20 +32,20 @@ def in other if other.begin == -Float::INFINITY && other.end == Float::INFINITY Nodes::NotIn.new self, [] elsif other.end == Float::INFINITY - Nodes::GreaterThanOrEqual.new(self, other.begin) + Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self)) elsif other.begin == -Float::INFINITY && other.exclude_end? - Nodes::LessThan.new(self, other.end) + Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) elsif other.begin == -Float::INFINITY - Nodes::LessThanOrEqual.new(self, other.end) + Nodes::LessThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) elsif other.exclude_end? - left = Nodes::GreaterThanOrEqual.new(self, other.begin) - right = Nodes::LessThan.new(self, other.end) + left = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self)) + right = Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) Nodes::And.new [left, right] else - Nodes::Between.new(self, Nodes::And.new([other.begin, other.end])) + Nodes::Between.new(self, Nodes::And.new([Nodes.build_quoted(other.begin, self), Nodes.build_quoted(other.end, self)])) end else - Nodes::In.new self, other + Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) } end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index e3d8792acaab5..cd84e263ad237 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -203,8 +203,8 @@ def with *subqueries def take limit if limit - @ast.limit = Nodes::Limit.new(limit) - @ctx.top = Nodes::Top.new(limit) + @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) + @ctx.top = Nodes::Top.new(Nodes.build_quoted(limit)) else @ast.limit = nil @ctx.top = nil From 6d47c4cae51fe5fd04ef999de96f54138cae7f88 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 24 Mar 2014 17:18:56 -0700 Subject: [PATCH 1209/1492] build quoted nodes in factory methods --- lib/arel/nodes.rb | 9 ++++++++- lib/arel/nodes/node.rb | 2 -- lib/arel/predications.rb | 28 ++++++++++++++++------------ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 3642958cf8ba9..6ce1ed7dba03f 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -62,6 +62,13 @@ def initialize val, attribute end def nil?; @val.nil?; end + + def eql? other + self.class == other.class && + self.val == other.val && + self.attribute == other.attribute + end + alias :== :eql? end class Quoted < Arel::Nodes::Unary # :nodoc: @@ -69,7 +76,7 @@ class Quoted < Arel::Nodes::Unary # :nodoc: def self.build_quoted other, attribute = nil case other - when Arel::Nodes::Node, Arel::Attributes::Attribute + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Nodes::SelectStatement, Arel::Table, Arel::Nodes::BindParam other else case attribute diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index a3eadf7170135..36e762861255c 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -51,8 +51,6 @@ def each &block ::Arel::Visitors::DepthFirst.new(block).accept self end - - def cast_reference?; false; end # :nodoc: end end end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 74411a0522da9..2ef48375482f4 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,7 +1,7 @@ module Arel module Predications def not_eq other - Nodes::NotEqual.new self, other + Nodes::NotEqual.new self, Nodes.build_quoted(other, self) end def not_eq_any others @@ -44,8 +44,10 @@ def in other else Nodes::Between.new(self, Nodes::And.new([Nodes.build_quoted(other.begin, self), Nodes.build_quoted(other.end, self)])) end - else + when Array Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) } + else + Nodes::In.new self, Nodes.build_quoted(other, self) end end @@ -65,22 +67,24 @@ def not_in other if other.begin == -Float::INFINITY && other.end == Float::INFINITY Nodes::In.new self, [] elsif other.end == Float::INFINITY - Nodes::LessThan.new(self, other.begin) + Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) elsif other.begin == -Float::INFINITY && other.exclude_end? - Nodes::GreaterThanOrEqual.new(self, other.end) + Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) elsif other.begin == -Float::INFINITY - Nodes::GreaterThan.new(self, other.end) + Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) elsif other.exclude_end? - left = Nodes::LessThan.new(self, other.begin) - right = Nodes::GreaterThanOrEqual.new(self, other.end) + left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) + right = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) Nodes::Or.new left, right else - left = Nodes::LessThan.new(self, other.begin) - right = Nodes::GreaterThan.new(self, other.end) + left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) + right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) Nodes::Or.new left, right end + when Array + Nodes::NotIn.new self, other.map { |x| Nodes.build_quoted(x, self) } else - Nodes::NotIn.new self, other + Nodes::NotIn.new self, Nodes.build_quoted(other, self) end end @@ -117,7 +121,7 @@ def does_not_match_all others end def gteq right - Nodes::GreaterThanOrEqual.new self, right + Nodes::GreaterThanOrEqual.new self, Nodes.build_quoted(right, self) end def gteq_any others @@ -129,7 +133,7 @@ def gteq_all others end def gt right - Nodes::GreaterThan.new self, right + Nodes::GreaterThan.new self, Nodes.build_quoted(right, self) end def gt_any others From c52df44784308e5d3cd608566fd9a3514ce28959 Mon Sep 17 00:00:00 2001 From: Alex Lin Date: Mon, 24 Mar 2014 23:42:27 -0400 Subject: [PATCH 1210/1492] Removed all the fiels in lib/arel/visitors/ which needs dependency on 'a' also fixed the test case for : test/visitors/test_to_sql.rb:22 which pass in the parameter attribute e.g the parameter a. --- lib/arel/visitors/bind_visitor.rb | 6 +- lib/arel/visitors/depth_first.rb | 112 +++++----- lib/arel/visitors/dot.rb | 148 ++++++------- lib/arel/visitors/ibm_db.rb | 4 +- lib/arel/visitors/informix.rb | 32 +-- lib/arel/visitors/join_sql.rb | 4 +- lib/arel/visitors/mssql.rb | 24 +-- lib/arel/visitors/mysql.rb | 30 +-- lib/arel/visitors/oracle.rb | 30 +-- lib/arel/visitors/order_clauses.rb | 4 +- lib/arel/visitors/postgresql.rb | 14 +- lib/arel/visitors/sqlite.rb | 4 +- lib/arel/visitors/to_sql.rb | 329 ++++++++++++++--------------- lib/arel/visitors/visitor.rb | 2 +- lib/arel/visitors/where_sql.rb | 4 +- test/visitors/test_to_sql.rb | 2 +- 16 files changed, 368 insertions(+), 381 deletions(-) diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb index 77b3f8237bfbf..5cb251ffdece0 100644 --- a/lib/arel/visitors/bind_visitor.rb +++ b/lib/arel/visitors/bind_visitor.rb @@ -13,15 +13,15 @@ def accept node, &block private - def visit_Arel_Nodes_Assignment o, a + def visit_Arel_Nodes_Assignment o if o.right.is_a? Arel::Nodes::BindParam - "#{visit o.left, a} = #{visit o.right, a}" + "#{visit o.left} = #{visit o.right}" else super end end - def visit_Arel_Nodes_BindParam o, a + def visit_Arel_Nodes_BindParam o if @block @block.call else diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 18bd81fb9c797..1770ab21d531e 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -7,13 +7,13 @@ def initialize block = nil private - def visit o, a = nil + def visit o super @block.call o end - def unary o, a - visit o.expr, a + def unary o + visit o.expr end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary @@ -28,10 +28,10 @@ def unary o, a alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary - def function o, a - visit o.expressions, a - visit o.alias, a - visit o.distinct, a + 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 @@ -39,27 +39,27 @@ def function o, a alias :visit_Arel_Nodes_Min :function alias :visit_Arel_Nodes_Sum :function - def visit_Arel_Nodes_NamedFunction o, a - visit o.name, a - visit o.expressions, a - visit o.distinct, a - visit o.alias, a + 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, a - visit o.expressions, a - visit o.alias, a - visit o.distinct, a + def visit_Arel_Nodes_Count o + visit o.expressions + visit o.alias + visit o.distinct end - def nary o, a - o.children.each { |child| visit child, a } + def nary o + o.children.each { |child| visit child} end alias :visit_Arel_Nodes_And :nary - def binary o, a - visit o.left, a - visit o.right, a + def binary o + visit o.left + visit o.right end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary @@ -83,13 +83,13 @@ def binary o, a alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary - def visit_Arel_Nodes_StringJoin o, a - visit o.left, a + def visit_Arel_Nodes_StringJoin o + visit o.left end - def visit_Arel_Attribute o, a - visit o.relation, a - visit o.name, a + 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 @@ -99,11 +99,11 @@ def visit_Arel_Attribute o, a alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute alias :visit_Arel_Attributes_Decimal :visit_Arel_Attribute - def visit_Arel_Table o, a - visit o.name, a + def visit_Arel_Table o + visit o.name end - def terminal o, a + def terminal o end alias :visit_ActiveSupport_Multibyte_Chars :terminal alias :visit_ActiveSupport_StringInquirer :terminal @@ -126,43 +126,43 @@ def terminal o, a alias :visit_Time :terminal alias :visit_TrueClass :terminal - def visit_Arel_Nodes_InsertStatement o, a - visit o.relation, a - visit o.columns, a - visit o.values, a + def visit_Arel_Nodes_InsertStatement o + visit o.relation + visit o.columns + visit o.values end - def visit_Arel_Nodes_SelectCore o, a - visit o.projections, a - visit o.source, a - visit o.wheres, a - visit o.groups, a - visit o.windows, a - visit o.having, a + 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, a - visit o.cores, a - visit o.orders, a - visit o.limit, a - visit o.lock, a - visit o.offset, a + 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, a - visit o.relation, a - visit o.values, a - visit o.wheres, a - visit o.orders, a - visit o.limit, a + 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, a - o.each { |i| visit i, a } + def visit_Array o + o.each { |i| visit i } end - def visit_Hash o, a - o.each { |k,v| visit(k, a); visit(v, a) } + def visit_Hash o + o.each { |k,v| visit(k); visit(v) } end end end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index cb4c2d494c851..d5033d166d65e 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -28,41 +28,41 @@ def accept object end private - def visit_Arel_Nodes_Ordering o, a - visit_edge o, a, "expr" + def visit_Arel_Nodes_Ordering o + visit_edge o, "expr" end - def visit_Arel_Nodes_TableAlias o, a - visit_edge o, a, "name" - visit_edge o, a, "relation" + def visit_Arel_Nodes_TableAlias o + visit_edge o, "name" + visit_edge o, "relation" end - def visit_Arel_Nodes_Count o, a - visit_edge o, a, "expressions" - visit_edge o, a, "distinct" + def visit_Arel_Nodes_Count o + visit_edge o, "expressions" + visit_edge o, "distinct" end - def visit_Arel_Nodes_Values o, a - visit_edge o, a, "expressions" + def visit_Arel_Nodes_Values o + visit_edge o, "expressions" end - def visit_Arel_Nodes_StringJoin o, a - visit_edge o, a, "left" + def visit_Arel_Nodes_StringJoin o + visit_edge o, "left" end - def visit_Arel_Nodes_InnerJoin o, a - visit_edge o, a, "left" - visit_edge o, a, "right" + 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, a - visit_edge o, a, "relation" - visit_edge o, a, "wheres" + def visit_Arel_Nodes_DeleteStatement o + visit_edge o, "relation" + visit_edge o, "wheres" end - def unary o, a - visit_edge o, a, "expr" + def unary o + visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary @@ -78,23 +78,23 @@ def unary o, a alias :visit_Arel_Nodes_Rows :unary alias :visit_Arel_Nodes_Range :unary - def window o, a - visit_edge o, a, "orders" - visit_edge o, a, "framing" + def window o + visit_edge o, "orders" + visit_edge o, "framing" end alias :visit_Arel_Nodes_Window :window - def named_window o, a - visit_edge o, a, "orders" - visit_edge o, a, "framing" - visit_edge o, a, "name" + 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, a - visit_edge o, a, "expressions" - visit_edge o, a, "distinct" - visit_edge o, a, "alias" + 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 @@ -102,52 +102,52 @@ def function o, a alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Sum :function - def extract o, a - visit_edge o, a, "expressions" - visit_edge o, a, "alias" + def extract o + visit_edge o, "expressions" + visit_edge o, "alias" end alias :visit_Arel_Nodes_Extract :extract - def visit_Arel_Nodes_NamedFunction o, a - visit_edge o, a, "name" - visit_edge o, a, "expressions" - visit_edge o, a, "distinct" - visit_edge o, a, "alias" + 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, a - visit_edge o, a, "relation" - visit_edge o, a, "columns" - visit_edge o, a, "values" + 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, a - visit_edge o, a, "source" - visit_edge o, a, "projections" - visit_edge o, a, "wheres" - visit_edge o, a, "windows" + 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, a - visit_edge o, a, "cores" - visit_edge o, a, "limit" - visit_edge o, a, "orders" - visit_edge o, a, "offset" + 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, a - visit_edge o, a, "relation" - visit_edge o, a, "wheres" - visit_edge o, a, "values" + def visit_Arel_Nodes_UpdateStatement o + visit_edge o, "relation" + visit_edge o, "wheres" + visit_edge o, "values" end - def visit_Arel_Table o, a - visit_edge o, a, "name" + def visit_Arel_Table o + visit_edge o, "name" end - def visit_Arel_Attribute o, a - visit_edge o, a, "relation" - visit_edge o, a, "name" + 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 @@ -156,16 +156,16 @@ def visit_Arel_Attribute o, a alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute - def nary o, a + def nary o o.children.each_with_index do |x,i| - edge(i) { visit x, a } + edge(i) { visit x } end end alias :visit_Arel_Nodes_And :nary - def binary o, a - visit_edge o, a, "left" - visit_edge o, a, "right" + def binary o + visit_edge o, "left" + visit_edge o, "right" end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary @@ -184,7 +184,7 @@ def binary o, a alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_Over :binary - def visit_String o, a + def visit_String o @node_stack.last.fields << o end alias :visit_Time :visit_String @@ -200,23 +200,23 @@ def visit_String o, a alias :visit_Symbol :visit_String alias :visit_Arel_Nodes_SqlLiteral :visit_String - def visit_Hash o, a + def visit_Hash o o.each_with_index do |pair, i| edge("pair_#{i}") { visit pair, a } end end - def visit_Array o, a + def visit_Array o o.each_with_index do |x,i| - edge(i) { visit x, a } + edge(i) { visit x } end end - def visit_edge o, a, method - edge(method) { visit o.send(method), a } + def visit_edge o, method + edge(method) { visit o.send(method) } end - def visit o, a = nil + def visit o = nil if node = @seen[o.object_id] @edge_stack.last.to = node return diff --git a/lib/arel/visitors/ibm_db.rb b/lib/arel/visitors/ibm_db.rb index 13af27df716e3..a41f8ff573669 100644 --- a/lib/arel/visitors/ibm_db.rb +++ b/lib/arel/visitors/ibm_db.rb @@ -3,8 +3,8 @@ module Visitors class IBM_DB < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Limit o, a - "FETCH FIRST #{visit o.expr, a} ROWS ONLY" + def visit_Arel_Nodes_Limit o + "FETCH FIRST #{visit o.expr } ROWS ONLY" end end diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index a578119d9be3a..244c68bed3708 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -2,30 +2,30 @@ module Arel module Visitors class Informix < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o, a + def visit_Arel_Nodes_SelectStatement o [ "SELECT", - (visit(o.offset, a) if o.offset), - (visit(o.limit, a) if o.limit), - o.cores.map { |x| visit_Arel_Nodes_SelectCore x, a }.join, - ("ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?), - (visit(o.lock, a) if o.lock), + (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, a + def visit_Arel_Nodes_SelectCore o [ - "#{o.projections.map { |x| visit x, a }.join ', '}", - ("FROM #{visit(o.source, a)}" if o.source && !o.source.empty?), - ("WHERE #{o.wheres.map { |x| visit x, a }.join ' AND ' }" unless o.wheres.empty?), - ("GROUP BY #{o.groups.map { |x| visit x, a }.join ', ' }" unless o.groups.empty?), - (visit(o.having, a) if o.having), + "#{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, a - "SKIP #{visit o.expr, a}" + def visit_Arel_Nodes_Offset o + "SKIP #{visit o.expr}" end - def visit_Arel_Nodes_Limit o, a - "LIMIT #{visit o.expr, a}" + def visit_Arel_Nodes_Limit o + "LIMIT #{visit o.expr}" end end end diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb index 9708887075761..1cdd7eb5ca0d6 100644 --- a/lib/arel/visitors/join_sql.rb +++ b/lib/arel/visitors/join_sql.rb @@ -11,8 +11,8 @@ module Visitors module JoinSql private - def visit_Arel_Nodes_SelectCore o, a - o.source.right.map { |j| visit j, a }.join ' ' + def visit_Arel_Nodes_SelectCore o + o.source.right.map { |j| visit j }.join ' ' end end end diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 2f5edce19a872..ef0b78058e43f 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -6,20 +6,20 @@ class MSSQL < Arel::Visitors::ToSql # `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, a + def visit_Arel_Nodes_Top o "" end - def visit_Arel_Nodes_SelectStatement o, a + def visit_Arel_Nodes_SelectStatement o if !o.limit && !o.offset - return super o, a + return super o end - select_order_by = "ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty? + 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, a) + 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 @@ -27,7 +27,7 @@ def visit_Arel_Nodes_SelectStatement o, a x.projections << row_num_literal(core_order_by) end - visit_Arel_Nodes_SelectCore x, a + visit_Arel_Nodes_SelectCore x }.join sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}" @@ -46,11 +46,11 @@ def get_offset_limit_clause o end end - def determine_order_by x, a + def determine_order_by x unless x.groups.empty? - "ORDER BY #{x.groups.map { |g| visit g, a }.join ', ' }" + "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" else - "ORDER BY #{find_left_table_pk(x.froms, a)}" + "ORDER BY #{find_left_table_pk(x.froms)}" end end @@ -64,9 +64,9 @@ def select_count? x # FIXME raise exception of there is no pk? # FIXME!! Table.primary_key will be deprecated. What is the replacement?? - def find_left_table_pk o, a - return visit o.primary_key, a if o.instance_of? Arel::Table - find_left_table_pk o.left, a if o.kind_of? Arel::Nodes::Join + 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 diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index ec9d91f8ce926..3b911e826fe97 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,19 +2,19 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Union o, a, suppress_parens = false + def visit_Arel_Nodes_Union o, suppress_parens = false left_result = case o.left when Arel::Nodes::Union - visit_Arel_Nodes_Union o.left, a, true + visit_Arel_Nodes_Union o.left, true else - visit o.left, a + visit o.left end right_result = case o.right when Arel::Nodes::Union - visit_Arel_Nodes_Union o.right, a, true + visit_Arel_Nodes_Union o.right, true else - visit o.right, a + visit o.right end if suppress_parens @@ -24,32 +24,32 @@ def visit_Arel_Nodes_Union o, a, suppress_parens = false end end - def visit_Arel_Nodes_Bin o, a - "BINARY #{visit o.expr, a}" + 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, a + def visit_Arel_Nodes_SelectStatement o if o.offset && !o.limit o.limit = Arel::Nodes::Limit.new(Nodes.build_quoted(18446744073709551615)) end super end - def visit_Arel_Nodes_SelectCore o, a + def visit_Arel_Nodes_SelectCore o o.froms ||= Arel.sql('DUAL') super end - def visit_Arel_Nodes_UpdateStatement o, a + def visit_Arel_Nodes_UpdateStatement o [ - "UPDATE #{visit o.relation, a}", - ("SET #{o.values.map { |value| visit value, a }.join ', '}" unless o.values.empty?), - ("WHERE #{o.wheres.map { |x| visit x, a }.join ' AND '}" unless o.wheres.empty?), - ("ORDER BY #{o.orders.map { |x| visit x, a }.join(', ')}" unless o.orders.empty?), - (visit(o.limit, a) if o.limit), + "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 diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index b6f7b4cc3c701..0b5f19baa1dac 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -3,8 +3,8 @@ module Visitors class Oracle < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o, a - o = order_hacks(o, a) + 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 @@ -20,52 +20,52 @@ def visit_Arel_Nodes_SelectStatement o, a limit = o.limit.expr.to_i offset = o.offset o.offset = nil - sql = super(o, a) + 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, a} + WHERE #{visit offset} eosql end if o.limit o = o.dup limit = o.limit.expr - return "SELECT * FROM (#{super(o, a)}) WHERE ROWNUM <= #{visit limit, a}" + 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, a) + sql = super(o) return <<-eosql SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (#{sql}) raw_sql_ ) - WHERE #{visit offset, a} + WHERE #{visit offset} eosql end super end - def visit_Arel_Nodes_Limit o, a + def visit_Arel_Nodes_Limit o end - def visit_Arel_Nodes_Offset o, a - "raw_rnum_ > #{visit o.expr, a}" + def visit_Arel_Nodes_Offset o + "raw_rnum_ > #{visit o.expr}" end - def visit_Arel_Nodes_Except o, a - "( #{visit o.left, a} MINUS #{visit o.right, a} )" + def visit_Arel_Nodes_Except o + "( #{visit o.left } MINUS #{visit o.right} )" end - def visit_Arel_Nodes_UpdateStatement o, a + 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, @@ -79,7 +79,7 @@ def visit_Arel_Nodes_UpdateStatement o, a ### # Hacks for the order clauses specific to Oracle - def order_hacks o, a + def order_hacks o return o if o.orders.empty? return o unless o.cores.any? do |core| core.projections.any? do |projection| @@ -91,7 +91,7 @@ def order_hacks o, a # # orders = o.orders.map { |x| visit x, a }.join(', ').split(',') orders = o.orders.map do |x| - string = visit x, a + string = visit x if string.include?(',') split_order_string(string) else diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb index b470d3f084dcb..11dbfdad2ae14 100644 --- a/lib/arel/visitors/order_clauses.rb +++ b/lib/arel/visitors/order_clauses.rb @@ -3,8 +3,8 @@ module Visitors class OrderClauses < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o, a - o.orders.map { |x| visit x, a } + def visit_Arel_Nodes_SelectStatement o + o.orders.map { |x| visit x } end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 7520a1ccc79bc..812710181c55e 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -3,18 +3,16 @@ module Visitors class PostgreSQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Matches o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} ILIKE #{visit o.right, a}" + def visit_Arel_Nodes_Matches o + "#{visit o.left} ILIKE #{visit o.right}" end - def visit_Arel_Nodes_DoesNotMatch o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} NOT ILIKE #{visit o.right, a}" + def visit_Arel_Nodes_DoesNotMatch o + "#{visit o.left} NOT ILIKE #{visit o.right}" end - def visit_Arel_Nodes_DistinctOn o, a - "DISTINCT ON ( #{visit o.expr, a} )" + def visit_Arel_Nodes_DistinctOn o + "DISTINCT ON ( #{visit o.expr} )" end end end diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index 07a18fc2f58b8..2a509e95b59ed 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -4,10 +4,10 @@ class SQLite < Arel::Visitors::ToSql private # Locks are not supported in SQLite - def visit_Arel_Nodes_Lock o, a + def visit_Arel_Nodes_Lock o end - def visit_Arel_Nodes_SelectStatement o, a + def visit_Arel_Nodes_SelectStatement o o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 69c82e792a51d..0c2e649995e82 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -66,7 +66,7 @@ def initialize connection private - def visit_Arel_Nodes_DeleteStatement o, a + def visit_Arel_Nodes_DeleteStatement o [ "DELETE FROM #{visit o.relation}", ("WHERE #{o.wheres.map { |x| visit x }.join AND}" unless o.wheres.empty?) @@ -85,7 +85,7 @@ def build_subselect key, o stmt end - def visit_Arel_Nodes_UpdateStatement o, a + def visit_Arel_Nodes_UpdateStatement o if o.orders.empty? && o.limit.nil? wheres = o.wheres else @@ -93,42 +93,42 @@ def visit_Arel_Nodes_UpdateStatement o, a end [ - "UPDATE #{visit o.relation, a}", - ("SET #{o.values.map { |value| visit value, a }.join ', '}" unless o.values.empty?), - ("WHERE #{wheres.map { |x| visit x, a }.join ' AND '}" unless wheres.empty?), + "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, a + def visit_Arel_Nodes_InsertStatement o [ - "INSERT INTO #{visit o.relation, a}", + "INSERT INTO #{visit o.relation}", ("(#{o.columns.map { |x| quote_column_name x.name }.join ', '})" unless o.columns.empty?), - (visit o.values, a if o.values), + (visit o.values if o.values), ].compact.join ' ' end - def visit_Arel_Nodes_Exists o, a - "EXISTS (#{visit o.expressions, a})#{ - o.alias ? " AS #{visit o.alias, a}" : ''}" + def visit_Arel_Nodes_Exists o + "EXISTS (#{visit o.expressions})#{ + o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Casted o, a + def visit_Arel_Nodes_Casted o quoted o.val, o.attribute end - def visit_Arel_Nodes_Quoted o, a + def visit_Arel_Nodes_Quoted o quoted o.expr, nil end - def visit_Arel_Nodes_True o, a + def visit_Arel_Nodes_True o "TRUE" end - def visit_Arel_Nodes_False o, a + def visit_Arel_Nodes_False o "FALSE" end @@ -150,66 +150,66 @@ def column_cache(table) @schema_cache.columns_hash(table) end - def visit_Arel_Nodes_Values o, a + def visit_Arel_Nodes_Values o "VALUES (#{o.expressions.zip(o.columns).map { |value, attr| if Nodes::SqlLiteral === value - visit value, a + visit value else quote(value, attr && column_for(attr)) end }.join ', '})" end - def visit_Arel_Nodes_SelectStatement o, a + def visit_Arel_Nodes_SelectStatement o str = '' if o.with - str << visit(o.with, a) + str << visit(o.with) str << SPACE end - o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x, a) } + 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, a) + str << visit(x) str << COMMA unless len == i } end - str << " #{visit(o.limit, a)}" if o.limit - str << " #{visit(o.offset, a)}" if o.offset - str << " #{visit(o.lock, a)}" if o.lock + 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, a + def visit_Arel_Nodes_SelectCore o str = "SELECT" - str << " #{visit(o.top, a)}" if o.top - str << " #{visit(o.set_quantifier, a)}" if o.set_quantifier + 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, a) + str << visit(x) str << COMMA unless len == i end end - str << " FROM #{visit(o.source, a)}" if o.source && !o.source.empty? + 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, a) + str << visit(x) str << AND unless len == i end end @@ -218,18 +218,18 @@ def visit_Arel_Nodes_SelectCore o, a str << GROUP_BY len = o.groups.length - 1 o.groups.each_with_index do |x, i| - str << visit(x, a) + str << visit(x) str << COMMA unless len == i end end - str << " #{visit(o.having, a)}" if o.having + 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, a) + str << visit(x) str << COMMA unless len == i end end @@ -237,244 +237,237 @@ def visit_Arel_Nodes_SelectCore o, a str end - def visit_Arel_Nodes_Bin o, a - visit o.expr, a + def visit_Arel_Nodes_Bin o + visit o.expr end - def visit_Arel_Nodes_Distinct o, a + def visit_Arel_Nodes_Distinct o DISTINCT end - def visit_Arel_Nodes_DistinctOn o, a + def visit_Arel_Nodes_DistinctOn o raise NotImplementedError, 'DISTINCT ON not implemented for this db' end - def visit_Arel_Nodes_With o, a - "WITH #{o.children.map { |x| visit x, a }.join(', ')}" + def visit_Arel_Nodes_With o + "WITH #{o.children.map { |x| visit x }.join(', ')}" end - def visit_Arel_Nodes_WithRecursive o, a - "WITH RECURSIVE #{o.children.map { |x| visit x, a }.join(', ')}" + def visit_Arel_Nodes_WithRecursive o + "WITH RECURSIVE #{o.children.map { |x| visit x }.join(', ')}" end - def visit_Arel_Nodes_Union o, a - "( #{visit o.left, a} UNION #{visit o.right, a} )" + def visit_Arel_Nodes_Union o + "( #{visit o.left} UNION #{visit o.right} )" end - def visit_Arel_Nodes_UnionAll o, a - "( #{visit o.left, a} UNION ALL #{visit o.right, a} )" + def visit_Arel_Nodes_UnionAll o + "( #{visit o.left} UNION ALL #{visit o.right} )" end - def visit_Arel_Nodes_Intersect o, a - "( #{visit o.left, a} INTERSECT #{visit o.right, a} )" + def visit_Arel_Nodes_Intersect o + "( #{visit o.left} INTERSECT #{visit o.right} )" end - def visit_Arel_Nodes_Except o, a - "( #{visit o.left, a} EXCEPT #{visit o.right, a} )" + def visit_Arel_Nodes_Except o + "( #{visit o.left} EXCEPT #{visit o.right} )" end - def visit_Arel_Nodes_NamedWindow o, a - "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o, a}" + def visit_Arel_Nodes_NamedWindow o + "#{quote_column_name o.name} AS #{visit_Arel_Nodes_Window o}" end - def visit_Arel_Nodes_Window o, a + def visit_Arel_Nodes_Window o s = [ - ("ORDER BY #{o.orders.map { |x| visit(x, a) }.join(', ')}" unless o.orders.empty?), - (visit o.framing, a if o.framing) + ("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, a + def visit_Arel_Nodes_Rows o if o.expr - "ROWS #{visit o.expr, a}" + "ROWS #{visit o.expr}" else "ROWS" end end - def visit_Arel_Nodes_Range o, a + def visit_Arel_Nodes_Range o if o.expr - "RANGE #{visit o.expr, a}" + "RANGE #{visit o.expr}" else "RANGE" end end - def visit_Arel_Nodes_Preceding o, a - "#{o.expr ? visit(o.expr, a) : 'UNBOUNDED'} PRECEDING" + def visit_Arel_Nodes_Preceding o + "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} PRECEDING" end - def visit_Arel_Nodes_Following o, a - "#{o.expr ? visit(o.expr, a) : 'UNBOUNDED'} FOLLOWING" + def visit_Arel_Nodes_Following o + "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} FOLLOWING" end - def visit_Arel_Nodes_CurrentRow o, a + def visit_Arel_Nodes_CurrentRow o "CURRENT ROW" end - def visit_Arel_Nodes_Over o, a + def visit_Arel_Nodes_Over o case o.right when nil - "#{visit o.left, a} OVER ()" + "#{visit o.left} OVER ()" when Arel::Nodes::SqlLiteral - "#{visit o.left, a} OVER #{visit o.right, a}" + "#{visit o.left} OVER #{visit o.right}" when String, Symbol - "#{visit o.left, a} OVER #{quote_column_name o.right.to_s}" + "#{visit o.left} OVER #{quote_column_name o.right.to_s}" else - "#{visit o.left, a} OVER #{visit o.right, a}" + "#{visit o.left} OVER #{visit o.right}" end end - def visit_Arel_Nodes_Having o, a - "HAVING #{visit o.expr, a}" + def visit_Arel_Nodes_Having o + "HAVING #{visit o.expr}" end - def visit_Arel_Nodes_Offset o, a - "OFFSET #{visit o.expr, a}" + def visit_Arel_Nodes_Offset o + "OFFSET #{visit o.expr}" end - def visit_Arel_Nodes_Limit o, a - "LIMIT #{visit o.expr, a}" + 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, a + def visit_Arel_Nodes_Top o "" end - def visit_Arel_Nodes_Lock o, a - visit o.expr, a + def visit_Arel_Nodes_Lock o + visit o.expr end - def visit_Arel_Nodes_Grouping o, a - "(#{visit o.expr, a})" + def visit_Arel_Nodes_Grouping o + "(#{visit o.expr})" end - def visit_Arel_SelectManager o, a + def visit_Arel_SelectManager o "(#{o.to_sql.rstrip})" end - def visit_Arel_Nodes_Ascending o, a - "#{visit o.expr, a} ASC" + def visit_Arel_Nodes_Ascending o + "#{visit o.expr} ASC" end - def visit_Arel_Nodes_Descending o, a - "#{visit o.expr, a} DESC" + def visit_Arel_Nodes_Descending o + "#{visit o.expr} DESC" end - def visit_Arel_Nodes_Group o, a - visit o.expr, a + def visit_Arel_Nodes_Group o + visit o.expr end - def visit_Arel_Nodes_NamedFunction o, a + def visit_Arel_Nodes_NamedFunction o "#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x, a - }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + visit x + }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Extract o, a - "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr, a})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + 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, a + def visit_Arel_Nodes_Count o "COUNT(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x, a - }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + visit x + }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Sum o, a + def visit_Arel_Nodes_Sum o "SUM(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + visit x}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Max o, a + def visit_Arel_Nodes_Max o "MAX(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + visit x}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Min o, a + def visit_Arel_Nodes_Min o "MIN(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Avg o, a + def visit_Arel_Nodes_Avg o "AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x, a }.join(', ')})#{o.alias ? " AS #{visit o.alias, a}" : ''}" + visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_TableAlias o, a - "#{visit o.relation, a} #{quote_table_name o.name}" + def visit_Arel_Nodes_TableAlias o + "#{visit o.relation} #{quote_table_name o.name}" end - def visit_Arel_Nodes_Between o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} BETWEEN #{visit o.right, a}" + def visit_Arel_Nodes_Between o + "#{visit o.left} BETWEEN #{visit o.right}" end - def visit_Arel_Nodes_GreaterThanOrEqual o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} >= #{visit o.right, a}" + def visit_Arel_Nodes_GreaterThanOrEqual o + "#{visit o.left} >= #{visit o.right}" end - def visit_Arel_Nodes_GreaterThan o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} > #{visit o.right, a}" + def visit_Arel_Nodes_GreaterThan o + "#{visit o.left} > #{visit o.right}" end - def visit_Arel_Nodes_LessThanOrEqual o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} <= #{visit o.right, a}" + def visit_Arel_Nodes_LessThanOrEqual o + "#{visit o.left} <= #{visit o.right}" end - def visit_Arel_Nodes_LessThan o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} < #{visit o.right, a}" + def visit_Arel_Nodes_LessThan o + "#{visit o.left} < #{visit o.right}" end - def visit_Arel_Nodes_Matches o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} LIKE #{visit o.right, a}" + def visit_Arel_Nodes_Matches o + "#{visit o.left} LIKE #{visit o.right}" end - def visit_Arel_Nodes_DoesNotMatch o, a - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} NOT LIKE #{visit o.right, a}" + def visit_Arel_Nodes_DoesNotMatch o + "#{visit o.left} NOT LIKE #{visit o.right}" end - def visit_Arel_Nodes_JoinSource o, a + def visit_Arel_Nodes_JoinSource o [ - (visit(o.left, a) if o.left), - o.right.map { |j| visit j, a }.join(' ') + (visit(o.left) if o.left), + o.right.map { |j| visit j }.join(' ') ].compact.join ' ' end - def visit_Arel_Nodes_StringJoin o, a - visit o.left, a + def visit_Arel_Nodes_StringJoin o + visit o.left end - def visit_Arel_Nodes_OuterJoin o, a - "LEFT OUTER JOIN #{visit o.left, a} #{visit o.right, a}" + def visit_Arel_Nodes_OuterJoin o + "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" end - def visit_Arel_Nodes_InnerJoin o, a - s = "INNER JOIN #{visit o.left, a}" + def visit_Arel_Nodes_InnerJoin o + s = "INNER JOIN #{visit o.left}" if o.right s << SPACE - s << visit(o.right, a) + s << visit(o.right) end s end - def visit_Arel_Nodes_On o, a - "ON #{visit o.expr, a}" + def visit_Arel_Nodes_On o + "ON #{visit o.expr}" end - def visit_Arel_Nodes_Not o, a - "NOT (#{visit o.expr, a})" + def visit_Arel_Nodes_Not o + "NOT (#{visit o.expr})" end - def visit_Arel_Table o, a + def visit_Arel_Table o if o.table_alias "#{quote_table_name o.name} #{quote_table_name o.table_alias}" else @@ -482,73 +475,69 @@ def visit_Arel_Table o, a end end - def visit_Arel_Nodes_In o, a + def visit_Arel_Nodes_In o if Array === o.right && o.right.empty? '1=0' else - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} IN (#{visit o.right, a})" + "#{visit o.left} IN (#{visit o.right})" end end - def visit_Arel_Nodes_NotIn o, a + def visit_Arel_Nodes_NotIn o if Array === o.right && o.right.empty? '1=1' else - a = o.left if Arel::Attributes::Attribute === o.left - "#{visit o.left, a} NOT IN (#{visit o.right, a})" + "#{visit o.left} NOT IN (#{visit o.right})" end end - def visit_Arel_Nodes_And o, a - o.children.map { |x| visit x, a }.join ' AND ' + def visit_Arel_Nodes_And o + o.children.map { |x| visit x}.join ' AND ' end - def visit_Arel_Nodes_Or o, a - "#{visit o.left, a} OR #{visit o.right, a}" + def visit_Arel_Nodes_Or o + "#{visit o.left} OR #{visit o.right}" end - def visit_Arel_Nodes_Assignment o, a + def visit_Arel_Nodes_Assignment o case o.right when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute - "#{visit o.left, a} = #{visit o.right, a}" + "#{visit o.left} = #{visit o.right}" else right = quote(o.right, column_for(o.left)) - "#{visit o.left, a} = #{right}" + "#{visit o.left} = #{right}" end end - def visit_Arel_Nodes_Equality o, a + def visit_Arel_Nodes_Equality o right = o.right - a = o.left if Arel::Attributes::Attribute === o.left if right.nil? - "#{visit o.left, a} IS NULL" + "#{visit o.left} IS NULL" else - "#{visit o.left, a} = #{visit right, a}" + "#{visit o.left} = #{visit right}" end end - def visit_Arel_Nodes_NotEqual o, a + def visit_Arel_Nodes_NotEqual o right = o.right - a = o.left if Arel::Attributes::Attribute === o.left if right.nil? - "#{visit o.left, a} IS NOT NULL" + "#{visit o.left} IS NOT NULL" else - "#{visit o.left, a} != #{visit right, a}" + "#{visit o.left} != #{visit right}" end end - def visit_Arel_Nodes_As o, a - "#{visit o.left, a} AS #{visit o.right, a}" + def visit_Arel_Nodes_As o + "#{visit o.left} AS #{visit o.right}" end - def visit_Arel_Nodes_UnqualifiedColumn o, a + def visit_Arel_Nodes_UnqualifiedColumn o "#{quote_column_name o.name}" end - def visit_Arel_Attributes_Attribute o, a + def visit_Arel_Attributes_Attribute o join_name = o.relation.table_alias || o.relation.name "#{quote_table_name join_name}.#{quote_column_name o.name}" end @@ -559,7 +548,7 @@ def visit_Arel_Attributes_Attribute o, a alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute - def literal o, a; o end + def literal o; o end alias :visit_Arel_Nodes_BindParam :literal alias :visit_Arel_Nodes_SqlLiteral :literal @@ -589,8 +578,8 @@ def unsupported o, a alias :visit_Time :unsupported alias :visit_TrueClass :unsupported - def visit_Arel_Nodes_InfixOperation o, a - "#{visit o.left, a} #{o.operator} #{visit o.right, a}" + def visit_Arel_Nodes_InfixOperation o + "#{visit o.left} #{o.operator} #{visit o.right}" end alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation @@ -598,8 +587,8 @@ def visit_Arel_Nodes_InfixOperation o, a alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation - def visit_Array o, a - o.map { |x| visit x, a }.join(', ') + def visit_Array o + o.map { |x| visit x }.join(', ') end def quote value, column = nil diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 420549b2aa596..437dc68e92868 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -19,7 +19,7 @@ def dispatch end def visit object, attribute = nil - send dispatch[object.class], object, attribute + send dispatch[object.class], object rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index d59bc26cb4c3b..acd84cd631d30 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -1,8 +1,8 @@ module Arel module Visitors class WhereSql < Arel::Visitors::ToSql - def visit_Arel_Nodes_SelectCore o, a - "WHERE #{o.wheres.map { |x| visit x, a }.join ' AND ' }" + def visit_Arel_Nodes_SelectCore o + "WHERE #{o.wheres.map { |x| visit x}.join ' AND ' }" end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 161a4e1b9e53c..b142ecd695d6b 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -19,7 +19,7 @@ module Visitors it 'can define a dispatch method' do visited = false viz = Class.new(Arel::Visitors::Visitor) { - define_method(:hello) do |node, attribute| + define_method(:hello) do |node| visited = true end From 78196509c3c6f2ee38225819efc5a88e8d95f8f7 Mon Sep 17 00:00:00 2001 From: Alex Lin Date: Tue, 25 Mar 2014 00:04:55 -0400 Subject: [PATCH 1211/1492] removed the attribute that was left in for testing --- lib/arel/visitors/visitor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 437dc68e92868..0540445088147 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -18,7 +18,7 @@ def dispatch DISPATCH[self.class] end - def visit object, attribute = nil + def visit object send dispatch[object.class], object rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) From 2fd000910915e665a0206ec21281a20dfb69bc51 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 25 Mar 2014 10:01:44 -0700 Subject: [PATCH 1212/1492] take in to account quoted and translated values --- lib/arel/select_manager.rb | 2 +- test/test_factory_methods.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index cd84e263ad237..5ab2778778639 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -17,7 +17,7 @@ def initialize_copy other end def limit - @ast.limit && @ast.limit.expr + @ast.limit && @ast.limit.expr.expr end alias :taken :limit diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index 64d747610bf26..3e23b090b4732 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -37,7 +37,7 @@ def test_lower lower = @factory.lower :one assert_instance_of Nodes::NamedFunction, lower assert_equal 'LOWER', lower.name - assert_equal [:one], lower.expressions + assert_equal [:one], lower.expressions.map(&:expr) end end end From a4a33fbb0a2375bfb13795148c17d460f3c5338d Mon Sep 17 00:00:00 2001 From: Alex Lin Date: Tue, 25 Mar 2014 13:28:09 -0400 Subject: [PATCH 1213/1492] remove the default parameter and updated comment --- lib/arel/visitors/dot.rb | 4 ++-- lib/arel/visitors/oracle.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index d5033d166d65e..b2fa6bfbd5bdd 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -202,7 +202,7 @@ def visit_String o def visit_Hash o o.each_with_index do |pair, i| - edge("pair_#{i}") { visit pair, a } + edge("pair_#{i}") { visit pair } end end @@ -216,7 +216,7 @@ def visit_edge o, method edge(method) { visit o.send(method) } end - def visit o = nil + def visit o if node = @seen[o.object_id] @edge_stack.last.to = node return diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 0b5f19baa1dac..0cd0179931bdc 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -89,7 +89,7 @@ def order_hacks o # 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, a }.join(', ').split(',') + # orders = o.orders.map { |x| visit x }.join(', ').split(',') orders = o.orders.map do |x| string = visit x if string.include?(',') From df52f7ca2ffe1dd4fb8e65db352c7bcaacfea1a5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 25 Mar 2014 11:29:41 -0700 Subject: [PATCH 1214/1492] initial commit for collector implementation --- lib/arel/collectors/sql_string.rb | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/arel/collectors/sql_string.rb diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb new file mode 100644 index 0000000000000..1b2ff21b18303 --- /dev/null +++ b/lib/arel/collectors/sql_string.rb @@ -0,0 +1,26 @@ +module Arel + module Collectors + class SQLString + def initialize + @str = '' + end + + def value + @str + end + + def << str + @str << str + self + end + + def start; self; end + def finish; self; end + + def add_bind bind + self << bind + self + end + end + end +end From 4cb02380116b102142f85d92b7923c11882f94c7 Mon Sep 17 00:00:00 2001 From: Stephen Prater & Fire-Dragon-DoL Date: Wed, 31 Jul 2013 01:08:22 +0200 Subject: [PATCH 1215/1492] Added right and full outer joins --- lib/arel/nodes.rb | 2 ++ lib/arel/nodes/full_outer_join.rb | 6 ++++++ lib/arel/nodes/right_outer_join.rb | 6 ++++++ lib/arel/visitors/depth_first.rb | 2 ++ lib/arel/visitors/dot.rb | 4 +++- lib/arel/visitors/to_sql.rb | 8 ++++++++ test/test_select_manager.rb | 16 ++++++++++++++++ test/test_table.rb | 14 ++++++++++++++ test/visitors/test_depth_first.rb | 12 ++++++++++++ test/visitors/test_join_sql.rb | 26 ++++++++++++++++++++++++++ 10 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/full_outer_join.rb create mode 100644 lib/arel/nodes/right_outer_join.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 6ce1ed7dba03f..a68e3279832b0 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -45,8 +45,10 @@ require 'arel/nodes/window' # joins +require 'arel/nodes/full_outer_join' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' +require 'arel/nodes/right_outer_join' require 'arel/nodes/string_join' require 'arel/nodes/sql_literal' diff --git a/lib/arel/nodes/full_outer_join.rb b/lib/arel/nodes/full_outer_join.rb new file mode 100644 index 0000000000000..708f161c9a7f3 --- /dev/null +++ b/lib/arel/nodes/full_outer_join.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class FullOuterJoin < Arel::Nodes::Join + end + end +end diff --git a/lib/arel/nodes/right_outer_join.rb b/lib/arel/nodes/right_outer_join.rb new file mode 100644 index 0000000000000..ea1ddb7d52080 --- /dev/null +++ b/lib/arel/nodes/right_outer_join.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class RightOuterJoin < Arel::Nodes::Join + end + end +end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 1770ab21d531e..7043e5d527e26 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -67,6 +67,7 @@ def binary o alias :visit_Arel_Nodes_DeleteStatement :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary + alias :visit_Arel_Nodes_FullOuterJoin :binary alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :binary @@ -80,6 +81,7 @@ def binary o alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_OuterJoin :binary + alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index b2fa6bfbd5bdd..99f4c467d2aa4 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -54,7 +54,9 @@ def visit_Arel_Nodes_InnerJoin o visit_edge o, "left" visit_edge o, "right" end - alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin def visit_Arel_Nodes_DeleteStatement o visit_edge o, "relation" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0c2e649995e82..84a88e1899b59 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -446,10 +446,18 @@ def visit_Arel_Nodes_StringJoin o visit o.left end + def visit_Arel_Nodes_FullOuterJoin o + "FULL OUTER JOIN #{visit o.left} #{visit o.right}" + end + def visit_Arel_Nodes_OuterJoin o "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" end + def visit_Arel_Nodes_RightOuterJoin o + "RIGHT OUTER JOIN #{visit o.left} #{visit o.right}" + end + def visit_Arel_Nodes_InnerJoin o s = "INNER JOIN #{visit o.left}" if o.right diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7f025f7a029b8..a0981476fe470 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -517,6 +517,14 @@ def test_manager_stores_bind_values 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::FullOuterJoin + assert_kind_of Arel::Nodes::FullOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should create join nodes with a klass' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin @@ -525,6 +533,14 @@ def test_manager_stores_bind_values 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::RightOuterJoin + assert_kind_of Arel::Nodes::RightOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + describe 'join' do it 'responds to join' do left = Table.new :users diff --git a/test/test_table.rb b/test/test_table.rb index 431a919de1a20..b4c2a65fcdac2 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -19,6 +19,13 @@ module Arel assert_equal 'bar', join.right end + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + assert_kind_of Arel::Nodes::FullOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should create join nodes with a klass' do join = @relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin assert_kind_of Arel::Nodes::OuterJoin, join @@ -26,6 +33,13 @@ module Arel assert_equal 'bar', join.right end + it 'should create join nodes with a klass' do + join = @relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + assert_kind_of Arel::Nodes::RightOuterJoin, join + assert_equal 'foo', join.left + assert_equal 'bar', join.right + end + it 'should return an insert manager' do im = @relation.compile_insert 'VALUES(NULL)' assert_kind_of Arel::InsertManager, im diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index cbaa780dae8d5..baa8f6418417e 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -81,12 +81,24 @@ def test_inner_join assert_equal [:a, :b, join], @collector.calls end + def test_full_outer_join + join = Nodes::FullOuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + def test_outer_join join = Nodes::OuterJoin.new :a, :b @visitor.accept join assert_equal [:a, :b, join], @collector.calls end + def test_right_outer_join + join = Nodes::RightOuterJoin.new :a, :b + @visitor.accept join + assert_equal [:a, :b, join], @collector.calls + end + [ Arel::Nodes::Assignment, Arel::Nodes::Between, diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb index ea71c05d79ca8..34378dafe7210 100644 --- a/test/visitors/test_join_sql.rb +++ b/test/visitors/test_join_sql.rb @@ -25,6 +25,19 @@ module Visitors end end + describe 'FULL 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::FullOuterJoin).on(t[:id]).join( + t, Nodes::FullOuterJoin).on(t[:id]) + sm.join_sql.must_be_like %{ + FULL OUTER JOIN "users" ON "users"."id" + FULL OUTER 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 @@ -37,6 +50,19 @@ module Visitors } end end + + describe 'right 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::RightOuterJoin).on(t[:id]).join( + t, Nodes::RightOuterJoin).on(t[:id]) + sm.join_sql.must_be_like %{ + RIGHT OUTER JOIN "users" ON "users"."id" + RIGHT OUTER JOIN "users" ON "users"."id" + } + end + end end end end From 8e3e04f47dd356ec6a0adba32a440ce388767faa Mon Sep 17 00:00:00 2001 From: Kazuki Hasegawa Date: Thu, 3 Apr 2014 12:38:26 +0900 Subject: [PATCH 1216/1492] flatten object.children in visit_Arel_Node_And --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 84a88e1899b59..2d81022a7ab7a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -500,7 +500,7 @@ def visit_Arel_Nodes_NotIn o end def visit_Arel_Nodes_And o - o.children.map { |x| visit x}.join ' AND ' + o.children.flatten.map { |x| visit x}.join ' AND ' end def visit_Arel_Nodes_Or o diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b142ecd695d6b..0a7af91397194 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -237,9 +237,9 @@ def dispatch end it "should visit_Arel_Nodes_And" do - node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] + node = Nodes::And.new [@attr.eq(10), [@attr.eq(11), @attr.eq(12)]] @visitor.accept(node).must_be_like %{ - "users"."id" = 10 AND "users"."id" = 11 + "users"."id" = 10 AND "users"."id" = 11 AND "users"."id" = 12 } end From 7515445966b265dd9e90ce4457bff972e1fc3746 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 7 Apr 2014 10:04:40 -0700 Subject: [PATCH 1217/1492] Revert "Merge pull request #253 from corrupt952/master" This reverts commit 6d3ed6d96c4a3ac85b97d81bad95b7254b2aa2d4, reversing changes made to a35fede61ac1a2fcff519ad052f2fcb8808922b9. --- lib/arel/visitors/to_sql.rb | 2 +- test/visitors/test_to_sql.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2d81022a7ab7a..84a88e1899b59 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -500,7 +500,7 @@ def visit_Arel_Nodes_NotIn o end def visit_Arel_Nodes_And o - o.children.flatten.map { |x| visit x}.join ' AND ' + o.children.map { |x| visit x}.join ' AND ' end def visit_Arel_Nodes_Or o diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 0a7af91397194..b142ecd695d6b 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -237,9 +237,9 @@ def dispatch end it "should visit_Arel_Nodes_And" do - node = Nodes::And.new [@attr.eq(10), [@attr.eq(11), @attr.eq(12)]] + node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] @visitor.accept(node).must_be_like %{ - "users"."id" = 10 AND "users"."id" = 11 AND "users"."id" = 12 + "users"."id" = 10 AND "users"."id" = 11 } end From 6296617c159d5cee0ba1c76f4ea983e3b5e26b6b Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 7 Mar 2014 13:15:33 +0000 Subject: [PATCH 1218/1492] Add Regexp and NotRegexp nodes for PostgreSQL --- lib/arel/nodes/binary.rb | 2 ++ lib/arel/visitors/depth_first.rb | 2 ++ lib/arel/visitors/postgresql.rb | 8 ++++++++ lib/arel/visitors/to_sql.rb | 8 ++++++++ test/visitors/test_postgres.rb | 34 ++++++++++++++++++++++++++++++++ test/visitors/test_to_sql.rb | 20 +++++++++++++++++++ 6 files changed, 74 insertions(+) diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 0e7e281b4b1e5..939684957f4dc 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -40,7 +40,9 @@ def eql? other Matches NotEqual NotIn + NotRegexp Or + Regexp Union UnionAll Intersect diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 7043e5d527e26..4d2ecfa5e1166 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -79,8 +79,10 @@ def binary o alias :visit_Arel_Nodes_Matches :binary alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary + alias :visit_Arel_Nodes_NotRegexp :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_OuterJoin :binary + alias :visit_Arel_Nodes_Regexp :binary alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 812710181c55e..49f7482e7d901 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -11,6 +11,14 @@ def visit_Arel_Nodes_DoesNotMatch o "#{visit o.left} NOT ILIKE #{visit o.right}" end + def visit_Arel_Nodes_Regexp o + "#{visit o.left} ~ #{visit o.right}" + end + + def visit_Arel_Nodes_NotRegexp o + "#{visit o.left} !~ #{visit o.right}" + end + def visit_Arel_Nodes_DistinctOn o "DISTINCT ON ( #{visit o.expr} )" end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 84a88e1899b59..c1c192fa1a526 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -435,6 +435,14 @@ def visit_Arel_Nodes_DoesNotMatch o "#{visit o.left} NOT LIKE #{visit o.right}" end + def visit_Arel_Nodes_Regexp o + raise NotImplementedError, '~ not implemented for this db' + end + + def visit_Arel_Nodes_NotRegexp o + raise NotImplementedError, '!~ not implemented for this db' + end + def visit_Arel_Nodes_JoinSource o [ (visit(o.left) if o.left), diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 4287baaf14d14..995e9bf515325 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -79,6 +79,40 @@ module Visitors } end end + + describe "Nodes::Regexp" do + it "should know how to visit" do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + @visitor.accept(node).must_be_like %{ + "users"."name" ~ 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo%') + } + end + end + + describe "Nodes::NotRegexp" do + it "should know how to visit" do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + @visitor.accept(node).must_be_like %{ + "users"."name" !~ 'foo%' + } + end + + it 'can handle subqueries' do + subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))) + node = @attr.in subquery + @visitor.accept(node).must_be_like %{ + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo%') + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b142ecd695d6b..644951d71c5c5 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -526,6 +526,26 @@ def quote value, column = nil end end end + + describe 'Nodes::Regexp' do + it 'raises not implemented error' do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + + assert_raises(NotImplementedError) do + @visitor.accept(node) + end + end + end + + describe 'Nodes::NotRegexp' do + it 'raises not implemented error' do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + + assert_raises(NotImplementedError) do + @visitor.accept(node) + end + end + end end end end From d4cc1e33b80a546a58bcd2eaa49ea4c5e9682cbc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 7 Apr 2014 17:10:27 -0700 Subject: [PATCH 1219/1492] fix whitespace and unsupported method args --- lib/arel/visitors/to_sql.rb | 2 +- lib/arel/visitors/visitor.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 84a88e1899b59..5b71291f0bd6d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -567,7 +567,7 @@ def quoted o, a quote(o, column_for(a)) end - def unsupported o, a + def unsupported o raise "unsupported: #{o.class.name}" end diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 0540445088147..0730c157949a6 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -19,7 +19,7 @@ def dispatch end def visit object - send dispatch[object.class], object + send dispatch[object.class], object rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| From 05b5bb12270b32e094c1c879273e0978dabe5b3b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 12:03:52 -0700 Subject: [PATCH 1220/1492] bind visitor working with collector object --- lib/arel/nodes/node.rb | 6 +++++- lib/arel/tree_manager.rb | 6 +++++- lib/arel/visitors/bind_visitor.rb | 12 +++++++----- lib/arel/visitors/to_sql.rb | 5 +++-- lib/arel/visitors/visitor.rb | 8 ++++---- test/helper.rb | 9 +++++++++ test/visitors/test_bind_visitor.rb | 22 ++++++++++++++++------ 7 files changed, 49 insertions(+), 19 deletions(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 36e762861255c..239c4fd766af2 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -1,3 +1,5 @@ +require 'arel/collectors/sql_string' + module Arel module Nodes ### @@ -42,7 +44,9 @@ def and right # # Maybe we should just use `Table.engine`? :'( def to_sql engine = Table.engine - engine.connection.visitor.accept self + collector = Arel::Collectors::SQLString.new + collector = engine.connection.visitor.accept self, collector + collector.value end # Iterate through AST, nodes will be yielded depth-first diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 1adb230991034..87887800d05fd 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,3 +1,5 @@ +require 'arel/collectors/sql_string' + module Arel class TreeManager include Arel::FactoryMethods @@ -21,7 +23,9 @@ def visitor end def to_sql - visitor.accept @ast + collector = Arel::Collectors::SQLString.new + collector = visitor.accept @ast, collector + collector.value end def initialize_copy other diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb index 5cb251ffdece0..c316c8d702898 100644 --- a/lib/arel/visitors/bind_visitor.rb +++ b/lib/arel/visitors/bind_visitor.rb @@ -6,24 +6,26 @@ def initialize target super end - def accept node, &block + def accept node, collector, &block @block = block if block_given? super end private - def visit_Arel_Nodes_Assignment o + def visit_Arel_Nodes_Assignment o, collector if o.right.is_a? Arel::Nodes::BindParam - "#{visit o.left} = #{visit o.right}" + collector = visit o.left, collector + collector << " = " + visit o.right, collector else super end end - def visit_Arel_Nodes_BindParam o + def visit_Arel_Nodes_BindParam o, collector if @block - @block.call + @block.call(collector) else super end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0c2e649995e82..8c90fd76afebd 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -533,8 +533,9 @@ 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}" + def visit_Arel_Nodes_UnqualifiedColumn o, collector + collector << "#{quote_column_name o.name}" + collector end def visit_Arel_Attributes_Attribute o diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 0540445088147..2d4b472ea30a4 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -1,8 +1,8 @@ module Arel module Visitors class Visitor - def accept object - visit object + def accept object, collector + visit object, collector end private @@ -18,8 +18,8 @@ def dispatch DISPATCH[self.class] end - def visit object - send dispatch[object.class], object + def visit object, collector + send dispatch[object.class], object, collector rescue NoMethodError => e raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| diff --git a/test/helper.rb b/test/helper.rb index 1292c09a08b6c..6e8ac836fcf63 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -11,3 +11,12 @@ def must_be_like other gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip end end + +module Arel + class Test < MiniTest::Test + def assert_like expected, actual + assert_equal expected.gsub(/\s+/, ' ').strip, + actual.gsub(/\s+/, ' ').strip + end + end +end diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index 2bfd03c861549..4563fddfd14cc 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -4,8 +4,14 @@ module Arel module Visitors - class TestBindVisitor < Minitest::Test - + class TestBindVisitor < Arel::Test + attr_reader :collector + + def setup + @collector = Collectors::SQLString.new + super + end + ## # Tests visit_Arel_Nodes_Assignment correctly # substitutes binds with values from block @@ -19,8 +25,12 @@ def test_assignment_binds_are_substituted }.new Table.engine.connection assignment = um.ast.values[0] - actual = visitor.accept(assignment) { "replace" } - actual.must_be_like "\"name\" = replace" + actual = visitor.accept(assignment, collector) { |collector| + collector << "replace" + } + assert actual + value = actual.value + assert_like "\"name\" = replace", value end def test_visitor_yields_on_binds @@ -33,7 +43,7 @@ def initialize omg bp = Nodes::BindParam.new 'omg' called = false - visitor.accept(bp) { called = true } + visitor.accept(bp, collector) { |collector| called = true } assert called end @@ -49,7 +59,7 @@ def initialize omg called = false assert_raises(TypeError) { - visitor.accept(bp) { called = true } + visitor.accept(bp, collector) { called = true } } refute called end From 1f9333e23b0e6c5634eaac9635f90a4235a16de8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 14:18:44 -0700 Subject: [PATCH 1221/1492] fixing some tests in to_sql --- lib/arel/collectors/sql_string.rb | 2 + lib/arel/visitors/to_sql.rb | 179 +++++++++++++++++++----------- test/visitors/test_to_sql.rb | 33 +++--- 3 files changed, 133 insertions(+), 81 deletions(-) diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index 1b2ff21b18303..824b0a1712777 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -1,3 +1,5 @@ +# encoding: utf-8 + module Arel module Collectors class SQLString diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8c90fd76afebd..4d5f81659fefc 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -116,20 +116,20 @@ def visit_Arel_Nodes_Exists o o.alias ? " AS #{visit o.alias}" : ''}" end - def visit_Arel_Nodes_Casted o - quoted o.val, o.attribute + def visit_Arel_Nodes_Casted o, collector + collector << quoted(o.val, o.attribute).to_s end def visit_Arel_Nodes_Quoted o quoted o.expr, nil end - def visit_Arel_Nodes_True o - "TRUE" + def visit_Arel_Nodes_True o, collector + collector << "TRUE" end - def visit_Arel_Nodes_False o - "FALSE" + def visit_Arel_Nodes_False o, collector + collector << "FALSE" end def table_exists? name @@ -160,81 +160,93 @@ def visit_Arel_Nodes_Values o }.join ', '})" end - def visit_Arel_Nodes_SelectStatement o - str = '' - + def visit_Arel_Nodes_SelectStatement o, collector if o.with - str << visit(o.with) - str << SPACE + collector = visit o.with, collector + collector << SPACE end - o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x) } + collector = o.cores.inject(collector) { |c,x| + visit_Arel_Nodes_SelectCore(x, c) + } unless o.orders.empty? - str << SPACE - str << ORDER_BY + collector << SPACE + collector << ORDER_BY len = o.orders.length - 1 o.orders.each_with_index { |x, i| - str << visit(x) - str << COMMA unless len == i + collector = visit(x, collector) + collector << 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 + collector = maybe_visit o.limit, collector + collector = maybe_visit o.offset, collector + collector = maybe_visit o.lock, collector - str.strip! - str + collector end - def visit_Arel_Nodes_SelectCore o - str = "SELECT" + def visit_Arel_Nodes_SelectCore o, collector + collector << "SELECT" - str << " #{visit(o.top)}" if o.top - str << " #{visit(o.set_quantifier)}" if o.set_quantifier + if o.top + collector << " " + collector = visit o.top, collector + end + + if o.set_quantifier + collector << " " + collector = visit o.set_quantifier, collector + end unless o.projections.empty? - str << SPACE + collector << SPACE len = o.projections.length - 1 o.projections.each_with_index do |x, i| - str << visit(x) - str << COMMA unless len == i + collector = visit(x, collector) + collector << COMMA unless len == i end end - str << " FROM #{visit(o.source)}" if o.source && !o.source.empty? + if o.source && !o.source.empty? + collector << " FROM " + collector = visit o.source, collector + end unless o.wheres.empty? - str << WHERE + collector << WHERE len = o.wheres.length - 1 o.wheres.each_with_index do |x, i| - str << visit(x) - str << AND unless len == i + collector = visit(x, collector) + collector << AND unless len == i end end unless o.groups.empty? - str << GROUP_BY + collector << GROUP_BY len = o.groups.length - 1 o.groups.each_with_index do |x, i| - str << visit(x) - str << COMMA unless len == i + collector = visit(x, collector) + collector << COMMA unless len == i end end - str << " #{visit(o.having)}" if o.having + if o.having + collector << " " + collector = visit(o.having, collector) + end unless o.windows.empty? - str << WINDOW + collector << WINDOW len = o.windows.length - 1 o.windows.each_with_index do |x, i| - str << visit(x) - str << COMMA unless len == i + collector = visit(x, collector) + collector << COMMA unless len == i end end - str + collector end def visit_Arel_Nodes_Bin o @@ -245,7 +257,7 @@ def visit_Arel_Nodes_Distinct o DISTINCT end - def visit_Arel_Nodes_DistinctOn o + def visit_Arel_Nodes_DistinctOn o, collector raise NotImplementedError, 'DISTINCT ON not implemented for this db' end @@ -411,8 +423,10 @@ 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}" + def visit_Arel_Nodes_GreaterThanOrEqual o, collector + collector = visit o.left, collector + collector << " >= " + visit o.right, collector end def visit_Arel_Nodes_GreaterThan o @@ -423,8 +437,10 @@ 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}" + def visit_Arel_Nodes_LessThan o, collector + collector = visit o.left, collector + collector << " < " + visit o.right, collector end def visit_Arel_Nodes_Matches o @@ -435,11 +451,15 @@ 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), + def visit_Arel_Nodes_JoinSource o, collector + if o.left + collector = visit o.left, collector + collector << " " + end + if o.right.any? o.right.map { |j| visit j }.join(' ') - ].compact.join ' ' + end + collector end def visit_Arel_Nodes_StringJoin o @@ -467,11 +487,11 @@ def visit_Arel_Nodes_Not o "NOT (#{visit o.expr})" end - def visit_Arel_Table o + def visit_Arel_Table o, collector if o.table_alias - "#{quote_table_name o.name} #{quote_table_name o.table_alias}" + collector << "#{quote_table_name o.name} #{quote_table_name o.table_alias}" else - quote_table_name o.name + collector << quote_table_name(o.name) end end @@ -483,20 +503,25 @@ def visit_Arel_Nodes_In o end end - def visit_Arel_Nodes_NotIn o + def visit_Arel_Nodes_NotIn o, collector if Array === o.right && o.right.empty? - '1=1' + collector << '1=1' else - "#{visit o.left} NOT IN (#{visit o.right})" + collector = visit o.left, collector + collector << " NOT IN (" + collector = visit o.right, collector + collector << ")" end end - def visit_Arel_Nodes_And o - o.children.map { |x| visit x}.join ' AND ' + def visit_Arel_Nodes_And o, collector + inject_join o.children, collector, " AND " end - def visit_Arel_Nodes_Or o - "#{visit o.left} OR #{visit o.right}" + def visit_Arel_Nodes_Or o, collector + collector = visit o.left, collector + collector << " OR " + visit o.right, collector end def visit_Arel_Nodes_Assignment o @@ -509,13 +534,16 @@ def visit_Arel_Nodes_Assignment o end end - def visit_Arel_Nodes_Equality o + def visit_Arel_Nodes_Equality o, collector right = o.right + collector = visit o.left, collector + if right.nil? - "#{visit o.left} IS NULL" + collector << " IS NULL" else - "#{visit o.left} = #{visit right}" + collector << " = " + visit right, collector end end @@ -538,9 +566,9 @@ def visit_Arel_Nodes_UnqualifiedColumn o, collector collector end - def visit_Arel_Attributes_Attribute o + def visit_Arel_Attributes_Attribute o, collector join_name = o.relation.table_alias || o.relation.name - "#{quote_table_name join_name}.#{quote_column_name o.name}" + collector << "#{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 @@ -549,7 +577,7 @@ def visit_Arel_Attributes_Attribute o alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute - def literal o; o end + def literal o, collector; collector << o; end alias :visit_Arel_Nodes_BindParam :literal alias :visit_Arel_Nodes_SqlLiteral :literal @@ -588,8 +616,8 @@ def visit_Arel_Nodes_InfixOperation o 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(', ') + def visit_Array o, collector + inject_join o, collector, ", " end def quote value, column = nil @@ -605,6 +633,23 @@ def quote_table_name name def quote_column_name name @quoted_columns[name] ||= Arel::Nodes::SqlLiteral === name ? name : @connection.quote_column_name(name) end + + def maybe_visit thing, collector + return collector unless thing + collector << " " + visit thing, collector + end + + def inject_join list, collector, join_str + len = list.length - 1 + list.each_with_index.inject(collector) { |c, (x,i)| + if i == len + visit x, c + else + visit(x, c) << join_str + end + } + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b142ecd695d6b..bcf2010d9772d 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -6,20 +6,25 @@ module Visitors before do @conn = FakeRecord::Base.new @visitor = ToSql.new @conn.connection + @collector = Collectors::SQLString.new @table = Table.new(:users) @attr = @table[:id] end + def compile node + @visitor.accept(node, @collector).value + end + it 'works with BindParams' do node = Nodes::BindParam.new 'omg' - sql = @visitor.accept node + sql = compile 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| + define_method(:hello) do |node, c| visited = true end @@ -28,13 +33,13 @@ def dispatch end }.new - viz.accept(@table) + viz.accept(@table, @collector) assert visited, 'hello method was called' end it 'should not quote sql literals' do node = @table[Arel.star] - sql = @visitor.accept node + sql = compile node sql.must_be_like '"users".*' end @@ -336,7 +341,7 @@ def dispatch it 'can handle three dot ranges' do node = @attr.in 1...3 - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" >= 1 AND "users"."id" < 3 } end @@ -421,14 +426,14 @@ def quote value, column = nil describe "Nodes::NotIn" do it "should know how to visit" do node = @attr.not_in [1, 2, 3] - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" NOT IN (1, 2, 3) } end it "should return 1=1 when empty right which is always true" do node = @attr.not_in [] - @visitor.accept(node).must_equal '1=1' + compile(node).must_equal '1=1' end it 'can handle two dot ranges' do @@ -440,14 +445,14 @@ def quote value, column = nil it 'can handle three dot ranges' do node = @attr.not_in 1...3 - @visitor.accept(node).must_be_like %{ + compile(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 %{ + compile(node).must_be_like %{ "users"."id" < 1 } node = @attr.not_in(-Float::INFINITY..3) @@ -466,7 +471,7 @@ def quote value, column = nil table = Table.new(:users) subquery = table.project(:id).where(table[:name].eq('Aaron')) node = @attr.not_in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" NOT IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') } end @@ -494,14 +499,14 @@ def quote value, column = nil describe 'Constants' do it "should handle true" do test = Table.new(:users).create_true - @visitor.accept(test).must_be_like %{ + compile(test).must_be_like %{ TRUE } end it "should handle false" do test = Table.new(:users).create_false - @visitor.accept(test).must_be_like %{ + compile(test).must_be_like %{ FALSE } end @@ -510,7 +515,7 @@ def quote value, column = nil 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 %{ + compile(test).must_be_like %{ "zomgusers"."id" = 3 } end @@ -522,7 +527,7 @@ def quote value, column = nil core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron')) assert_raises(NotImplementedError) do - @visitor.accept(core) + compile(core) end end end From 4e2e1cc63a81bf549712c4cacfe1f3dc32e632a2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 15:22:27 -0700 Subject: [PATCH 1222/1492] to_sql is passing --- lib/arel/visitors/to_sql.rb | 154 ++++++++++++++++++++++------------- test/visitors/test_to_sql.rb | 126 ++++++++++++++-------------- 2 files changed, 160 insertions(+), 120 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 4d5f81659fefc..545f95df2abc9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -120,8 +120,8 @@ def visit_Arel_Nodes_Casted o, collector collector << quoted(o.val, o.attribute).to_s end - def visit_Arel_Nodes_Quoted o - quoted o.expr, nil + def visit_Arel_Nodes_Quoted o, collector + collector << quoted(o.expr, nil).to_s end def visit_Arel_Nodes_True o, collector @@ -346,8 +346,9 @@ def visit_Arel_Nodes_Offset o "OFFSET #{visit o.expr}" end - def visit_Arel_Nodes_Limit o - "LIMIT #{visit o.expr}" + def visit_Arel_Nodes_Limit o, collector + collector << "LIMIT " + visit o.expr, collector end # FIXME: this does nothing on most databases, but does on MSSQL @@ -359,68 +360,72 @@ def visit_Arel_Nodes_Lock o visit o.expr end - def visit_Arel_Nodes_Grouping o - "(#{visit o.expr})" + def visit_Arel_Nodes_Grouping o, collector + collector << "(" + visit(o.expr, collector) << ")" end - def visit_Arel_SelectManager o - "(#{o.to_sql.rstrip})" + def visit_Arel_SelectManager o, collector + collector << "(#{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" + def visit_Arel_Nodes_Descending o, collector + visit(o.expr, collector) << " 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}" : ''}" + def visit_Arel_Nodes_NamedFunction o, collector + collector << o.name + collector << "(" + collector << "DISTINCT " if o.distinct + collector = inject_join(o.expressions, collector, ", ") << ")" + if o.alias + collector << " AS " + visit o.alias, collector + else + collector + end 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}" : ''}" + def visit_Arel_Nodes_Count o, collector + aggregate "COUNT", o, collector end - def visit_Arel_Nodes_Sum o - "SUM(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Sum o, collector + aggregate "SUM", o, collector end - def visit_Arel_Nodes_Max o - "MAX(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Max o, collector + aggregate "MAX", o, collector end - def visit_Arel_Nodes_Min o - "MIN(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Min o, collector + aggregate "MIN", o, collector end - def visit_Arel_Nodes_Avg o - "AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x| - visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Avg o, collector + aggregate "AVG", o, collector 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}" + def visit_Arel_Nodes_Between o, collector + collector = visit o.left, collector + collector << " BETWEEN " + visit o.right, collector end def visit_Arel_Nodes_GreaterThanOrEqual o, collector @@ -429,12 +434,16 @@ def visit_Arel_Nodes_GreaterThanOrEqual o, collector visit o.right, collector end - def visit_Arel_Nodes_GreaterThan o - "#{visit o.left} > #{visit o.right}" + def visit_Arel_Nodes_GreaterThan o, collector + collector = visit o.left, collector + collector << " > " + visit o.right, collector end - def visit_Arel_Nodes_LessThanOrEqual o - "#{visit o.left} <= #{visit o.right}" + def visit_Arel_Nodes_LessThanOrEqual o, collector + collector = visit o.left, collector + collector << " <= " + visit o.right, collector end def visit_Arel_Nodes_LessThan o, collector @@ -443,12 +452,16 @@ def visit_Arel_Nodes_LessThan o, collector visit o.right, collector end - def visit_Arel_Nodes_Matches o - "#{visit o.left} LIKE #{visit o.right}" + def visit_Arel_Nodes_Matches o, collector + collector = visit o.left, collector + collector << " LIKE " + visit o.right, collector end - def visit_Arel_Nodes_DoesNotMatch o - "#{visit o.left} NOT LIKE #{visit o.right}" + def visit_Arel_Nodes_DoesNotMatch o, collector + collector = visit o.left, collector + collector << " NOT LIKE " + visit o.right, collector end def visit_Arel_Nodes_JoinSource o, collector @@ -483,8 +496,9 @@ def visit_Arel_Nodes_On o "ON #{visit o.expr}" end - def visit_Arel_Nodes_Not o - "NOT (#{visit o.expr})" + def visit_Arel_Nodes_Not o, collector + collector << "NOT (" + visit(o.expr, collector) << ")" end def visit_Arel_Table o, collector @@ -495,11 +509,13 @@ def visit_Arel_Table o, collector end end - def visit_Arel_Nodes_In o + def visit_Arel_Nodes_In o, collector if Array === o.right && o.right.empty? - '1=0' + collector << '1=0' else - "#{visit o.left} IN (#{visit o.right})" + collector = visit o.left, collector + collector << " IN (" + visit(o.right, collector) << ")" end end @@ -524,13 +540,16 @@ def visit_Arel_Nodes_Or o, collector visit o.right, collector end - def visit_Arel_Nodes_Assignment o + def visit_Arel_Nodes_Assignment o, collector case o.right when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute - "#{visit o.left} = #{visit o.right}" + collector = visit o.left, collector + collector << " = " + visit o.right, collector else - right = quote(o.right, column_for(o.left)) - "#{visit o.left} = #{right}" + collector = visit o.left, collector + collector << " = " + collector << quote(o.right, column_for(o.left)).to_s end end @@ -547,18 +566,23 @@ def visit_Arel_Nodes_Equality o, collector end end - def visit_Arel_Nodes_NotEqual o + def visit_Arel_Nodes_NotEqual o, collector right = o.right + collector = visit o.left, collector + if right.nil? - "#{visit o.left} IS NOT NULL" + collector << " IS NOT NULL" else - "#{visit o.left} != #{visit right}" + collector << " != " + visit right, collector end end - def visit_Arel_Nodes_As o - "#{visit o.left} AS #{visit o.right}" + def visit_Arel_Nodes_As o, collector + collector = visit o.left, collector + collector << " AS " + visit o.right, collector end def visit_Arel_Nodes_UnqualifiedColumn o, collector @@ -577,7 +601,7 @@ def visit_Arel_Attributes_Attribute o, collector alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute - def literal o, collector; collector << o; end + def literal o, collector; collector << o.to_s; end alias :visit_Arel_Nodes_BindParam :literal alias :visit_Arel_Nodes_SqlLiteral :literal @@ -607,8 +631,10 @@ def unsupported o, a alias :visit_Time :unsupported alias :visit_TrueClass :unsupported - def visit_Arel_Nodes_InfixOperation o - "#{visit o.left} #{o.operator} #{visit o.right}" + def visit_Arel_Nodes_InfixOperation o, collector + collector = visit o.left, collector + collector << " #{o.operator} " + visit o.right, collector end alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation @@ -650,6 +676,20 @@ def inject_join list, collector, join_str end } end + + def aggregate name, o, collector + collector << "#{name}(" + if o.distinct + collector << "DISTINCT " + end + collector = inject_join(o.expressions, collector, ", ") << ")" + if o.alias + collector << " AS " + visit o.alias, collector + else + collector + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index bcf2010d9772d..33c7bb9e931f6 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -12,7 +12,7 @@ module Visitors end def compile node - @visitor.accept(node, @collector).value + @visitor.accept(node, Collectors::SQLString.new).value end it 'works with BindParams' do @@ -45,63 +45,63 @@ def dispatch it 'should visit named functions' do function = Nodes::NamedFunction.new('omg', [Arel.star]) - assert_equal 'omg(*)', @visitor.accept(function) + assert_equal 'omg(*)', compile(function) end it 'should chain predications on named functions' do function = Nodes::NamedFunction.new('omg', [Arel.star]) - sql = @visitor.accept(function.eq(2)) + sql = compile(function.eq(2)) sql.must_be_like %{ omg(*) = 2 } end it 'should visit built-in functions' do function = Nodes::Count.new([Arel.star]) - assert_equal 'COUNT(*)', @visitor.accept(function) + assert_equal 'COUNT(*)', compile(function) function = Nodes::Sum.new([Arel.star]) - assert_equal 'SUM(*)', @visitor.accept(function) + assert_equal 'SUM(*)', compile(function) function = Nodes::Max.new([Arel.star]) - assert_equal 'MAX(*)', @visitor.accept(function) + assert_equal 'MAX(*)', compile(function) function = Nodes::Min.new([Arel.star]) - assert_equal 'MIN(*)', @visitor.accept(function) + assert_equal 'MIN(*)', compile(function) function = Nodes::Avg.new([Arel.star]) - assert_equal 'AVG(*)', @visitor.accept(function) + assert_equal 'AVG(*)', compile(function) end it 'should visit built-in functions operating on distinct values' do function = Nodes::Count.new([Arel.star]) function.distinct = true - assert_equal 'COUNT(DISTINCT *)', @visitor.accept(function) + assert_equal 'COUNT(DISTINCT *)', compile(function) function = Nodes::Sum.new([Arel.star]) function.distinct = true - assert_equal 'SUM(DISTINCT *)', @visitor.accept(function) + assert_equal 'SUM(DISTINCT *)', compile(function) function = Nodes::Max.new([Arel.star]) function.distinct = true - assert_equal 'MAX(DISTINCT *)', @visitor.accept(function) + assert_equal 'MAX(DISTINCT *)', compile(function) function = Nodes::Min.new([Arel.star]) function.distinct = true - assert_equal 'MIN(DISTINCT *)', @visitor.accept(function) + assert_equal 'MIN(DISTINCT *)', compile(function) function = Nodes::Avg.new([Arel.star]) function.distinct = true - assert_equal 'AVG(DISTINCT *)', @visitor.accept(function) + assert_equal 'AVG(DISTINCT *)', compile(function) end it 'works with lists' do function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star]) - assert_equal 'omg(*, *)', @visitor.accept(function) + assert_equal 'omg(*, *)', compile(function) end describe 'Nodes::Equality' do it "should escape strings" do test = Table.new(:users)[:name].eq 'Aaron Patterson' - @visitor.accept(test).must_be_like %{ + compile(test).must_be_like %{ "users"."name" = 'Aaron Patterson' } end @@ -109,19 +109,19 @@ def dispatch it 'should handle false' do table = Table.new(:users) val = Nodes.build_quoted(false, table[:active]) - sql = @visitor.accept Nodes::Equality.new(val, val) + sql = compile Nodes::Equality.new(val, val) sql.must_be_like %{ 'f' = 'f' } end it 'should use the column to quote' do table = Table.new(:users) val = Nodes.build_quoted('1-fooo', table[:id]) - sql = @visitor.accept Nodes::Equality.new(table[:id], val) + sql = compile Nodes::Equality.new(table[:id], val) sql.must_be_like %{ "users"."id" = 1 } end it 'should handle nil' do - sql = @visitor.accept Nodes::Equality.new(@table[:name], nil) + sql = compile Nodes::Equality.new(@table[:name], nil) sql.must_be_like %{ "users"."name" IS NULL } end end @@ -129,13 +129,13 @@ def dispatch describe 'Nodes::NotEqual' do it 'should handle false' do val = Nodes.build_quoted(false, @table[:active]) - sql = @visitor.accept Nodes::NotEqual.new(@table[:active], val) + sql = compile Nodes::NotEqual.new(@table[:active], val) sql.must_be_like %{ "users"."active" != 'f' } end it 'should handle nil' do val = Nodes.build_quoted(nil, @table[:active]) - sql = @visitor.accept Nodes::NotEqual.new(@table[:name], val) + sql = compile Nodes::NotEqual.new(@table[:name], val) sql.must_be_like %{ "users"."name" IS NOT NULL } end end @@ -146,19 +146,19 @@ def dispatch Class.new(Class.new(String)).new(":'("), ].each do |obj| val = Nodes.build_quoted(obj, @table[:active]) - sql = @visitor.accept Nodes::NotEqual.new(@table[:name], val) + sql = compile Nodes::NotEqual.new(@table[:name], val) sql.must_be_like %{ "users"."name" != ':\\'(' } end end it "should visit_Class" do - @visitor.accept(Nodes.build_quoted(DateTime)).must_equal "'DateTime'" + compile(Nodes.build_quoted(DateTime)).must_equal "'DateTime'" end it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new sc.limit = Arel::Nodes::Limit.new(Nodes.build_quoted("omg")) - assert_match(/LIMIT 'omg'/, @visitor.accept(sc)) + assert_match(/LIMIT 'omg'/, compile(sc)) end it "should visit_DateTime" do @@ -173,7 +173,7 @@ def dispatch dt = DateTime.now table = Table.new(:users) test = table[:created_at].eq dt - sql = @visitor.accept test + sql = compile test assert_equal "created_at", called_with.name sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d %H:%M:%S")}'} @@ -181,37 +181,37 @@ def dispatch it "should visit_Float" do test = Table.new(:users)[:name].eq 2.14 - sql = @visitor.accept test + sql = compile test sql.must_be_like %{"users"."name" = 2.14} end it "should visit_Not" do - sql = @visitor.accept Nodes::Not.new(Arel.sql("foo")) + sql = compile Nodes::Not.new(Arel.sql("foo")) sql.must_be_like "NOT (foo)" end it "should apply Not to the whole expression" do node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] - sql = @visitor.accept Nodes::Not.new(node) + sql = compile Nodes::Not.new(node) sql.must_be_like %{NOT ("users"."id" = 10 AND "users"."id" = 11)} end it "should visit_As" do as = Nodes::As.new(Arel.sql("foo"), Arel.sql("bar")) - sql = @visitor.accept as + sql = compile as sql.must_be_like "foo AS bar" end it "should visit_Bignum" do - @visitor.accept 8787878092 + compile 8787878092 end it "should visit_Hash" do - @visitor.accept(Nodes.build_quoted({:a => 1})) + compile(Nodes.build_quoted({:a => 1})) end it "should visit_BigDecimal" do - @visitor.accept Nodes.build_quoted(BigDecimal.new('2.14')) + compile Nodes.build_quoted(BigDecimal.new('2.14')) end it "should visit_Date" do @@ -226,31 +226,31 @@ def dispatch dt = Date.today table = Table.new(:users) test = table[:created_at].eq dt - sql = @visitor.accept test + sql = compile test assert_equal "created_at", called_with.name sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d")}'} end it "should visit_NilClass" do - @visitor.accept(Nodes.build_quoted(nil)).must_be_like "NULL" + compile(Nodes.build_quoted(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")' + compile(mgr).must_be_like '(SELECT bar FROM "foo")' end it "should visit_Arel_Nodes_And" do node = Nodes::And.new [@attr.eq(10), @attr.eq(11)] - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" = 10 AND "users"."id" = 11 } end it "should visit_Arel_Nodes_Or" do node = Nodes::Or.new @attr.eq(10), @attr.eq(11) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" = 10 OR "users"."id" = 11 } end @@ -261,25 +261,25 @@ def dispatch Nodes::UnqualifiedColumn.new(column), Nodes::UnqualifiedColumn.new(column) ) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "id" = "id" } end it "should visit visit_Arel_Attributes_Time" do attr = Attributes::Time.new(@attr.relation, @attr.name) - @visitor.accept attr + compile attr end it "should visit_TrueClass" do test = Table.new(:users)[:bool].eq(true) - @visitor.accept(test).must_be_like %{ "users"."bool" = 't' } + compile(test).must_be_like %{ "users"."bool" = 't' } end describe "Nodes::Matches" do it "should know how to visit" do node = @table[:name].matches('foo%') - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."name" LIKE 'foo%' } end @@ -287,7 +287,7 @@ def dispatch it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].matches('foo%')) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" LIKE 'foo%') } end @@ -296,7 +296,7 @@ def dispatch describe "Nodes::DoesNotMatch" do it "should know how to visit" do node = @table[:name].does_not_match('foo%') - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."name" NOT LIKE 'foo%' } end @@ -304,7 +304,7 @@ def dispatch it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT LIKE 'foo%') } end @@ -313,7 +313,7 @@ def dispatch describe "Nodes::Ordering" do it "should know how to visit" do node = @attr.desc - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" DESC } end @@ -322,19 +322,19 @@ def dispatch describe "Nodes::In" do it "should know how to visit" do node = @attr.in [1, 2, 3] - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (1, 2, 3) } end it "should return 1=0 when empty right which is always false" do node = @attr.in [] - @visitor.accept(node).must_equal '1=0' + compile(node).must_equal '1=0' end it 'can handle two dot ranges' do node = @attr.in 1..3 - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" BETWEEN 1 AND 3 } end @@ -348,26 +348,26 @@ def dispatch it 'can handle ranges bounded by infinity' do node = @attr.in 1..Float::INFINITY - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" >= 1 } node = @attr.in(-Float::INFINITY..3) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" <= 3 } node = @attr.in(-Float::INFINITY...3) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" < 3 } node = @attr.in(-Float::INFINITY..Float::INFINITY) - @visitor.accept(node).must_be_like %{1=1} + compile(node).must_be_like %{1=1} end it 'can handle subqueries' do table = Table.new(:users) subquery = table.project(:id).where(table[:name].eq('Aaron')) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') } end @@ -388,29 +388,29 @@ def quote value, column = nil visitor.expected = Table.engine.connection.columns(:users).find { |x| x.name == 'name' } - visitor.accept(in_node).must_equal %("users"."name" IN ('a', 'b', 'c')) + visitor.accept(in_node, Collectors::SQLString.new).value.must_equal %("users"."name" IN ('a', 'b', 'c')) end end describe "Nodes::InfixOperation" do it "should handle Multiplication" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) * Arel::Attributes::Decimal.new(Table.new(:currency_rates), :rate) - @visitor.accept(node).must_equal %("products"."price" * "currency_rates"."rate") + compile(node).must_equal %("products"."price" * "currency_rates"."rate") end it "should handle Division" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) / 5 - @visitor.accept(node).must_equal %("products"."price" / 5) + compile(node).must_equal %("products"."price" / 5) end it "should handle Addition" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) + 6 - @visitor.accept(node).must_equal %(("products"."price" + 6)) + compile(node).must_equal %(("products"."price" + 6)) end it "should handle Subtraction" do node = Arel::Attributes::Decimal.new(Table.new(:products), :price) - 7 - @visitor.accept(node).must_equal %(("products"."price" - 7)) + compile(node).must_equal %(("products"."price" - 7)) end it "should handle arbitrary operators" do @@ -419,7 +419,7 @@ def quote value, column = nil 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") + compile(node).must_equal %("products"."name" || "products"."name") end end @@ -438,7 +438,7 @@ def quote value, column = nil it 'can handle two dot ranges' do node = @attr.not_in 1..3 - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" < 1 OR "users"."id" > 3 } end @@ -456,15 +456,15 @@ def quote value, column = nil "users"."id" < 1 } node = @attr.not_in(-Float::INFINITY..3) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" > 3 } node = @attr.not_in(-Float::INFINITY...3) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" >= 3 } node = @attr.not_in(-Float::INFINITY..Float::INFINITY) - @visitor.accept(node).must_be_like %{1=0} + compile(node).must_be_like %{1=0} end it 'can handle subqueries' do @@ -492,7 +492,7 @@ def quote value, column = nil 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')) + compile(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c')) end end From 55c0071ce3685a78b4f039be24b2ab40b8779467 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 16:16:32 -0700 Subject: [PATCH 1223/1492] remove order_clauses since we do not use it --- lib/arel/select_manager.rb | 7 ------- lib/arel/visitors.rb | 1 - lib/arel/visitors/order_clauses.rb | 11 ----------- test/test_select_manager.rb | 10 ---------- 4 files changed, 29 deletions(-) delete mode 100644 lib/arel/visitors/order_clauses.rb diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 5ab2778778639..f49f76d98f2b1 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -220,13 +220,6 @@ def join_sql 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 diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 8276eace2bb35..3986ad9ce53ab 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -8,7 +8,6 @@ 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' diff --git a/lib/arel/visitors/order_clauses.rb b/lib/arel/visitors/order_clauses.rb deleted file mode 100644 index 11dbfdad2ae14..0000000000000 --- a/lib/arel/visitors/order_clauses.rb +++ /dev/null @@ -1,11 +0,0 @@ -module 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index a0981476fe470..6258705e2f841 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -628,16 +628,6 @@ def test_manager_stores_bind_values 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 From b7a54435c73a5c4422ef2e53412516088d5e8fb4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 16:23:39 -0700 Subject: [PATCH 1224/1492] making some of the sql manager tests pass --- lib/arel/select_manager.rb | 4 +- lib/arel/visitors/to_sql.rb | 134 ++++++++++++++++++++++----------- lib/arel/visitors/where_sql.rb | 5 +- 3 files changed, 94 insertions(+), 49 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f49f76d98f2b1..db34ffb9467ca 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -1,3 +1,5 @@ +require 'arel/collectors/sql_string' + module Arel class SelectManager < Arel::TreeManager include Arel::Crud @@ -167,7 +169,7 @@ def where_sql return if @ctx.wheres.empty? viz = Visitors::WhereSql.new @engine.connection - Nodes::SqlLiteral.new viz.accept @ctx + Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value end def union operation, other = nil diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index d8883073d0ebd..a137e2a708d9b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -66,11 +66,15 @@ def initialize connection 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 ' ' + def visit_Arel_Nodes_DeleteStatement o, collector + collector << "DELETE FROM " + collector = visit o.relation, collector + if o.wheres.any? + collector << " WHERE " + inject_join o.wheres, collector, AND + else + collector + end end # FIXME: we should probably have a 2-pass visitor for this @@ -85,18 +89,29 @@ def build_subselect key, o stmt end - def visit_Arel_Nodes_UpdateStatement o + def visit_Arel_Nodes_UpdateStatement o, collector if o.orders.empty? && o.limit.nil? wheres = o.wheres else wheres = [Nodes::In.new(o.key, [build_subselect(o.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 ' ' + collector << "UPDATE " + collector = visit o.relation, collector + values = false + unless o.values.empty? + values = true + collector << " SET " + collector = inject_join o.values, collector, ", " + end + + unless wheres.empty? + collector << " " if values + collector << "WHERE " + collector = inject_join wheres, collector, " AND " + end + + collector end def visit_Arel_Nodes_InsertStatement o @@ -285,44 +300,66 @@ 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}" + def visit_Arel_Nodes_NamedWindow o, collector + collector << quote_column_name(o.name) + collector << " AS " + visit_Arel_Nodes_Window o, collector 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})" + def visit_Arel_Nodes_Window o, collector + collector << "(" + if o.orders.any? + collector << "ORDER BY " + collector = inject_join o.orders, collector, ", " + end + + if o.framing + collector = visit o.framing, collector + end + + collector << ")" end - def visit_Arel_Nodes_Rows o + def visit_Arel_Nodes_Rows o, collector if o.expr - "ROWS #{visit o.expr}" + collector << "ROWS " + visit o.expr, collector else - "ROWS" + collector << "ROWS" end end - def visit_Arel_Nodes_Range o + def visit_Arel_Nodes_Range o, collector if o.expr - "RANGE #{visit o.expr}" + collector << "RANGE " + visit o.expr, collector else - "RANGE" + collector << "RANGE" end end - def visit_Arel_Nodes_Preceding o - "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} PRECEDING" + def visit_Arel_Nodes_Preceding o, collector + collector = if o.expr + visit o.expr, collector + else + collector << "UNBOUNDED" + end + + collector << " PRECEDING" end - def visit_Arel_Nodes_Following o - "#{o.expr ? visit(o.expr) : 'UNBOUNDED'} FOLLOWING" + def visit_Arel_Nodes_Following o, collector + collector = if o.expr + visit o.expr, collector + else + collector << "UNBOUNDED" + end + + collector << " FOLLOWING" end - def visit_Arel_Nodes_CurrentRow o - "CURRENT ROW" + def visit_Arel_Nodes_CurrentRow o, collector + collector << "CURRENT ROW" end def visit_Arel_Nodes_Over o @@ -352,8 +389,8 @@ def visit_Arel_Nodes_Limit o, collector end # FIXME: this does nothing on most databases, but does on MSSQL - def visit_Arel_Nodes_Top o - "" + def visit_Arel_Nodes_Top o, collector + collector end def visit_Arel_Nodes_Lock o @@ -369,16 +406,16 @@ def visit_Arel_SelectManager o, collector collector << "(#{o.to_sql.rstrip})" end - def visit_Arel_Nodes_Ascending o - "#{visit o.expr} ASC" + def visit_Arel_Nodes_Ascending o, collector + visit(o.expr, collector) << " ASC" end def visit_Arel_Nodes_Descending o, collector visit(o.expr, collector) << " DESC" end - def visit_Arel_Nodes_Group o - visit o.expr + def visit_Arel_Nodes_Group o, collector + visit o.expr, collector end def visit_Arel_Nodes_NamedFunction o, collector @@ -418,8 +455,10 @@ def visit_Arel_Nodes_Avg o, collector aggregate "AVG", o, collector end - def visit_Arel_Nodes_TableAlias o - "#{visit o.relation} #{quote_table_name o.name}" + def visit_Arel_Nodes_TableAlias o, collector + collector = visit o.relation, collector + collector << " " + collector << quote_table_name(o.name) end def visit_Arel_Nodes_Between o, collector @@ -499,17 +538,20 @@ def visit_Arel_Nodes_RightOuterJoin o "RIGHT OUTER JOIN #{visit o.left} #{visit o.right}" end - def visit_Arel_Nodes_InnerJoin o - s = "INNER JOIN #{visit o.left}" + def visit_Arel_Nodes_InnerJoin o, collector + collector << "INNER JOIN " + collector = visit o.left, collector if o.right - s << SPACE - s << visit(o.right) + collector << SPACE + visit(o.right, collector) + else + collector end - s end - def visit_Arel_Nodes_On o - "ON #{visit o.expr}" + def visit_Arel_Nodes_On o, collector + collector << "ON " + visit o.expr, collector end def visit_Arel_Nodes_Not o, collector diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index acd84cd631d30..27dde73673737 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -1,8 +1,9 @@ module Arel module Visitors class WhereSql < Arel::Visitors::ToSql - def visit_Arel_Nodes_SelectCore o - "WHERE #{o.wheres.map { |x| visit x}.join ' AND ' }" + def visit_Arel_Nodes_SelectCore o, collector + collector << "WHERE " + inject_join o.wheres, collector, ' AND ' end end end From 8fc2241df61ce274b652fae09e4640a50a500af7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 16:27:33 -0700 Subject: [PATCH 1225/1492] removing unused join_sql method --- Manifest.txt | 5 +-- lib/arel/select_manager.rb | 7 ---- lib/arel/visitors.rb | 1 - lib/arel/visitors/join_sql.rb | 19 ---------- test/test_select_manager.rb | 17 +++------ test/visitors/test_join_sql.rb | 68 ---------------------------------- 6 files changed, 7 insertions(+), 110 deletions(-) delete mode 100644 lib/arel/visitors/join_sql.rb delete mode 100644 test/visitors/test_join_sql.rb diff --git a/Manifest.txt b/Manifest.txt index a5c2c2bab5771..b19411be8496c 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -29,6 +29,7 @@ lib/arel/nodes/descending.rb lib/arel/nodes/equality.rb lib/arel/nodes/extract.rb lib/arel/nodes/false.rb +lib/arel/nodes/full_outer_join.rb lib/arel/nodes/function.rb lib/arel/nodes/grouping.rb lib/arel/nodes/in.rb @@ -40,6 +41,7 @@ lib/arel/nodes/named_function.rb lib/arel/nodes/node.rb lib/arel/nodes/outer_join.rb lib/arel/nodes/over.rb +lib/arel/nodes/right_outer_join.rb lib/arel/nodes/select_core.rb lib/arel/nodes/select_statement.rb lib/arel/nodes/sql_literal.rb @@ -65,11 +67,9 @@ 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 @@ -120,7 +120,6 @@ test/visitors/test_dispatch_contamination.rb test/visitors/test_dot.rb test/visitors/test_ibm_db.rb test/visitors/test_informix.rb -test/visitors/test_join_sql.rb test/visitors/test_mssql.rb test/visitors/test_mysql.rb test/visitors/test_oracle.rb diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f49f76d98f2b1..a3bfa9a230d17 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -213,13 +213,6 @@ def take limit 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 join_sources @ctx.source.right end diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 3986ad9ce53ab..4a8d254ba77e2 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -6,7 +6,6 @@ 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/dot' require 'arel/visitors/ibm_db' diff --git a/lib/arel/visitors/join_sql.rb b/lib/arel/visitors/join_sql.rb deleted file mode 100644 index 1cdd7eb5ca0d6..0000000000000 --- a/lib/arel/visitors/join_sql.rb +++ /dev/null @@ -1,19 +0,0 @@ -module 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 diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 6258705e2f841..6c7098b3d98ba 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -584,9 +584,8 @@ def test_manager_stores_bind_values 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" - } + assert_match 'INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"', + manager.to_sql end it 'returns outer join sql' do @@ -594,9 +593,8 @@ def test_manager_stores_bind_values 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" - } + assert_match 'LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"', + manager.to_sql end it 'can have a non-table alias as relation name' do @@ -619,12 +617,7 @@ def test_manager_stores_bind_values it 'returns string join sql' do manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new(Nodes.build_quoted('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 + assert_match "'hello'", manager.to_sql end end diff --git a/test/visitors/test_join_sql.rb b/test/visitors/test_join_sql.rb deleted file mode 100644 index 34378dafe7210..0000000000000 --- a/test/visitors/test_join_sql.rb +++ /dev/null @@ -1,68 +0,0 @@ -require '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(Nodes.build_quoted('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 'FULL 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::FullOuterJoin).on(t[:id]).join( - t, Nodes::FullOuterJoin).on(t[:id]) - sm.join_sql.must_be_like %{ - FULL OUTER JOIN "users" ON "users"."id" - FULL OUTER 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 - - describe 'right 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::RightOuterJoin).on(t[:id]).join( - t, Nodes::RightOuterJoin).on(t[:id]) - sm.join_sql.must_be_like %{ - RIGHT OUTER JOIN "users" ON "users"."id" - RIGHT OUTER JOIN "users" ON "users"."id" - } - end - end - end - end -end From 208c00bbbf861297bd75bb45af47d999d1d3c46d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 16:39:08 -0700 Subject: [PATCH 1226/1492] more select manager tests passing --- lib/arel/visitors/depth_first.rb | 17 +++++++++++++--- lib/arel/visitors/to_sql.rb | 33 +++++++++++++++++++++----------- test/test_select_manager.rb | 3 ++- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 4d2ecfa5e1166..458934f8545a1 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -5,11 +5,22 @@ def initialize block = nil @block = block || Proc.new end + def accept object + visit object + end + private - def visit o - super - @block.call o + 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 def unary o diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a137e2a708d9b..b60edeb7200e1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -280,12 +280,14 @@ 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(', ')}" + def visit_Arel_Nodes_WithRecursive o, collector + collector << "WITH RECURSIVE " + inject_join o.children, collector, ', ' end - def visit_Arel_Nodes_Union o - "( #{visit o.left} UNION #{visit o.right} )" + def visit_Arel_Nodes_Union o, collector + collector << "( " + infix_value(o, collector, " UNION ") << " )" end def visit_Arel_Nodes_UnionAll o @@ -296,7 +298,7 @@ def visit_Arel_Nodes_Intersect o "( #{visit o.left} INTERSECT #{visit o.right} )" end - def visit_Arel_Nodes_Except o + def visit_Arel_Nodes_Except o, collector "( #{visit o.left} EXCEPT #{visit o.right} )" end @@ -393,8 +395,8 @@ def visit_Arel_Nodes_Top o, collector collector end - def visit_Arel_Nodes_Lock o - visit o.expr + def visit_Arel_Nodes_Lock o, collector + visit o.expr, collector end def visit_Arel_Nodes_Grouping o, collector @@ -522,16 +524,19 @@ def visit_Arel_Nodes_NotRegexp o, collector raise NotImplementedError, '!~ not implemented for this db' end - def visit_Arel_Nodes_StringJoin o - visit o.left + def visit_Arel_Nodes_StringJoin o, collector + visit o.left, collector end def visit_Arel_Nodes_FullOuterJoin o "FULL OUTER JOIN #{visit o.left} #{visit o.right}" end - def visit_Arel_Nodes_OuterJoin o - "LEFT OUTER JOIN #{visit o.left} #{visit o.right}" + def visit_Arel_Nodes_OuterJoin o, collector + collector << "LEFT OUTER JOIN " + collector = visit o.left, collector + collector << " " + visit o.right, collector end def visit_Arel_Nodes_RightOuterJoin o @@ -735,6 +740,12 @@ def inject_join list, collector, join_str } end + def infix_value o, collector, value + collector = visit o.left, collector + collector << " UNION " + visit o.right, collector + end + def aggregate name, o, collector collector << "#{name}(" if o.distinct diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 6c7098b3d98ba..837486fb4612c 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -369,8 +369,9 @@ def test_manager_stores_bind_values table = Table.new :users mgr = table.from table ast = mgr.ast - mgr.visitor.accept(ast).must_equal mgr.to_sql + assert ast end + it 'should allow orders to work when the ast is grepped' do table = Table.new :users mgr = table.from table From 6ae60fd2cbbf836dac01f6d2d56c38fb9deb225a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 16:51:17 -0700 Subject: [PATCH 1227/1492] select manager tests are passing --- lib/arel/visitors/to_sql.rb | 39 ++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index b60edeb7200e1..f8b8a9a07c195 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -126,9 +126,15 @@ def visit_Arel_Nodes_InsertStatement o ].compact.join ' ' end - def visit_Arel_Nodes_Exists o - "EXISTS (#{visit o.expressions})#{ - o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Exists o, collector + collector << "EXISTS (" + collector = visit(o.expressions, collector) << ")" + if o.alias + collector << " AS " + visit o.alias, collector + else + collector + end end def visit_Arel_Nodes_Casted o, collector @@ -290,16 +296,19 @@ def visit_Arel_Nodes_Union o, collector infix_value(o, collector, " UNION ") << " )" end - def visit_Arel_Nodes_UnionAll o - "( #{visit o.left} UNION ALL #{visit o.right} )" + def visit_Arel_Nodes_UnionAll o, collector + collector << "( " + infix_value(o, collector, " UNION ALL ") << " )" end - def visit_Arel_Nodes_Intersect o - "( #{visit o.left} INTERSECT #{visit o.right} )" + def visit_Arel_Nodes_Intersect o, collector + collector << "( " + infix_value(o, collector, " INTERSECT ") << " )" end def visit_Arel_Nodes_Except o, collector - "( #{visit o.left} EXCEPT #{visit o.right} )" + collector << "( " + infix_value(o, collector, " EXCEPT ") << " )" end def visit_Arel_Nodes_NamedWindow o, collector @@ -377,12 +386,14 @@ def visit_Arel_Nodes_Over o end end - def visit_Arel_Nodes_Having o - "HAVING #{visit o.expr}" + def visit_Arel_Nodes_Having o, collector + collector << "HAVING " + visit o.expr, collector end - def visit_Arel_Nodes_Offset o - "OFFSET #{visit o.expr}" + def visit_Arel_Nodes_Offset o, collector + collector << "OFFSET " + visit o.expr, collector end def visit_Arel_Nodes_Limit o, collector @@ -508,9 +519,9 @@ def visit_Arel_Nodes_DoesNotMatch o, collector def visit_Arel_Nodes_JoinSource o, collector if o.left collector = visit o.left, collector - collector << " " end if o.right.any? + collector << " " if o.left collector = inject_join o.right, collector, ' ' end collector @@ -742,7 +753,7 @@ def inject_join list, collector, join_str def infix_value o, collector, value collector = visit o.left, collector - collector << " UNION " + collector << value visit o.right, collector end From a6a7c75ff486657909e20e2f48764136caa5e87e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 17:01:53 -0700 Subject: [PATCH 1228/1492] push reduction visitors to a reduction base class this lets our old depth first and dot visitors to work normally --- lib/arel/visitors/depth_first.rb | 17 +++-------------- lib/arel/visitors/dot.rb | 3 ++- lib/arel/visitors/reduce.rb | 25 +++++++++++++++++++++++++ lib/arel/visitors/to_sql.rb | 3 ++- lib/arel/visitors/visitor.rb | 8 ++++---- test/visitors/test_to_sql.rb | 2 +- 6 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 lib/arel/visitors/reduce.rb diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 458934f8545a1..4d2ecfa5e1166 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -5,22 +5,11 @@ def initialize block = nil @block = block || Proc.new end - def accept object - visit object - end - private - 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 + def visit o + super + @block.call o end def unary o diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 99f4c467d2aa4..ba35223ac92b5 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -23,11 +23,12 @@ def initialize end def accept object - super + visit object to_dot end private + def visit_Arel_Nodes_Ordering o visit_edge o, "expr" end diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb new file mode 100644 index 0000000000000..9670cad27cb4a --- /dev/null +++ b/lib/arel/visitors/reduce.rb @@ -0,0 +1,25 @@ +require 'arel/visitors/visitor' + +module Arel + module Visitors + class Reduce < Arel::Visitors::Visitor + def accept object, collector + visit object, collector + end + + private + + def visit object, collector + send dispatch[object.class], object, collector + 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f8b8a9a07c195..0dbec61212019 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -1,9 +1,10 @@ require 'bigdecimal' require 'date' +require 'arel/visitors/reduce' module Arel module Visitors - class ToSql < Arel::Visitors::Visitor + class ToSql < Arel::Visitors::Reduce ## # This is some roflscale crazy stuff. I'm roflscaling this because # building SQL queries is a hotspot. I will explain the roflscale so that diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 2d4b472ea30a4..0730c157949a6 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -1,8 +1,8 @@ module Arel module Visitors class Visitor - def accept object, collector - visit object, collector + def accept object + visit object end private @@ -18,8 +18,8 @@ def dispatch DISPATCH[self.class] end - def visit object, collector - send dispatch[object.class], object, collector + 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| diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b6d91046b8378..4ed1f225ceb1b 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -23,7 +23,7 @@ def compile node it 'can define a dispatch method' do visited = false - viz = Class.new(Arel::Visitors::Visitor) { + viz = Class.new(Arel::Visitors::Reduce) { define_method(:hello) do |node, c| visited = true end From 93036b168b2877f2fe314b7fa0e8701878e32602 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 17:04:08 -0700 Subject: [PATCH 1229/1492] fix sqlite visitor --- lib/arel/visitors/sqlite.rb | 5 +++-- test/visitors/test_sqlite.rb | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index 2a509e95b59ed..ff6fc1fea4c5d 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -4,10 +4,11 @@ class SQLite < Arel::Visitors::ToSql private # Locks are not supported in SQLite - def visit_Arel_Nodes_Lock o + def visit_Arel_Nodes_Lock o, collector + collector end - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, collector o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end diff --git a/test/visitors/test_sqlite.rb b/test/visitors/test_sqlite.rb index c06f554ea48c9..8fb8e76095e03 100644 --- a/test/visitors/test_sqlite.rb +++ b/test/visitors/test_sqlite.rb @@ -10,13 +10,13 @@ module Visitors it 'defaults limit to -1' do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) - sql = @visitor.accept(stmt) + sql = @visitor.accept(stmt, Collectors::SQLString.new).value sql.must_be_like "SELECT LIMIT -1 OFFSET 1" end it 'does not support locking' do node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) - @visitor.accept(node).must_be_nil + assert_equal '', @visitor.accept(node, Collectors::SQLString.new).value end end end From b2fb1d3381027176505e8709acd22295fb57597a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 17:16:21 -0700 Subject: [PATCH 1230/1492] postgresql visitor is working --- lib/arel/visitors/postgresql.rb | 21 +++++++++++---------- lib/arel/visitors/to_sql.rb | 4 ++-- test/visitors/test_postgres.rb | 30 +++++++++++++++++------------- test/visitors/test_to_sql.rb | 3 +-- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 49f7482e7d901..60878ddd2006f 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -3,24 +3,25 @@ module Visitors class PostgreSQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Matches o - "#{visit o.left} ILIKE #{visit o.right}" + def visit_Arel_Nodes_Matches o, collector + infix_value o, collector, ' ILIKE ' end - def visit_Arel_Nodes_DoesNotMatch o - "#{visit o.left} NOT ILIKE #{visit o.right}" + def visit_Arel_Nodes_DoesNotMatch o, collector + infix_value o, collector, ' NOT ILIKE ' end - def visit_Arel_Nodes_Regexp o - "#{visit o.left} ~ #{visit o.right}" + def visit_Arel_Nodes_Regexp o, collector + infix_value o, collector, ' ~ ' end - def visit_Arel_Nodes_NotRegexp o - "#{visit o.left} !~ #{visit o.right}" + def visit_Arel_Nodes_NotRegexp o, collector + infix_value o, collector, ' !~ ' end - def visit_Arel_Nodes_DistinctOn o - "DISTINCT ON ( #{visit o.expr} )" + def visit_Arel_Nodes_DistinctOn o, collector + collector << "DISTINCT ON ( " + visit(o.expr, collector) << " )" end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 0dbec61212019..8e254d504b007 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -275,8 +275,8 @@ def visit_Arel_Nodes_Bin o visit o.expr end - def visit_Arel_Nodes_Distinct o - DISTINCT + def visit_Arel_Nodes_Distinct o, collector + collector << DISTINCT end def visit_Arel_Nodes_DistinctOn o, collector diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 995e9bf515325..3d646a7324e63 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -9,16 +9,20 @@ module Visitors @attr = @table[:id] end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + describe 'locking' do it 'defaults to FOR UPDATE' do - @visitor.accept(Nodes::Lock.new(Arel.sql('FOR UPDATE'))).must_be_like %{ + compile(Nodes::Lock.new(Arel.sql('FOR UPDATE'))).must_be_like %{ FOR UPDATE } end it 'allows a custom string to be used as a lock' do node = Nodes::Lock.new(Arel.sql('FOR SHARE')) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ FOR SHARE } end @@ -29,7 +33,7 @@ module Visitors sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) sc.cores.first.projections << Arel.sql('DISTINCT ON') sc.orders << Arel.sql("xyz") - sql = @visitor.accept(sc) + sql = compile(sc) assert_match(/LIMIT 'omg'/, sql) assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit' end @@ -37,19 +41,19 @@ module Visitors 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) + assert_match 'DISTINCT ON ( aaron )', compile(core) end it 'should support DISTINCT' do core = Arel::Nodes::SelectCore.new core.set_quantifier = Arel::Nodes::Distinct.new - assert_equal 'SELECT DISTINCT', @visitor.accept(core) + assert_equal 'SELECT DISTINCT', compile(core) end describe "Nodes::Matches" do it "should know how to visit" do node = @table[:name].matches('foo%') - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."name" ILIKE 'foo%' } end @@ -57,7 +61,7 @@ module Visitors it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].matches('foo%')) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') } end @@ -66,7 +70,7 @@ module Visitors describe "Nodes::DoesNotMatch" do it "should know how to visit" do node = @table[:name].does_not_match('foo%') - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."name" NOT ILIKE 'foo%' } end @@ -74,7 +78,7 @@ module Visitors it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT ILIKE 'foo%') } end @@ -83,7 +87,7 @@ module Visitors describe "Nodes::Regexp" do it "should know how to visit" do node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."name" ~ 'foo%' } end @@ -91,7 +95,7 @@ module Visitors it 'can handle subqueries' do subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo%') } end @@ -100,7 +104,7 @@ module Visitors describe "Nodes::NotRegexp" do it "should know how to visit" do node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."name" !~ 'foo%' } end @@ -108,7 +112,7 @@ module Visitors it 'can handle subqueries' do subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))) node = @attr.in subquery - @visitor.accept(node).must_be_like %{ + compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo%') } end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 4ed1f225ceb1b..eb102c19055a3 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -6,7 +6,6 @@ module Visitors before do @conn = FakeRecord::Base.new @visitor = ToSql.new @conn.connection - @collector = Collectors::SQLString.new @table = Table.new(:users) @attr = @table[:id] end @@ -33,7 +32,7 @@ def dispatch end }.new - viz.accept(@table, @collector) + viz.accept(@table, Collectors::SQLString.new) assert visited, 'hello method was called' end From 3ec26142a9f9f036bc3f763adac8fa38048d0a76 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 19:16:33 -0700 Subject: [PATCH 1231/1492] oracle tests passing --- lib/arel/visitors/oracle.rb | 47 +++++++++++++++++++++--------------- test/visitors/test_oracle.rb | 42 +++++++++++++++++--------------- 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 0cd0179931bdc..2cdbafadada24 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -3,7 +3,7 @@ module Visitors class Oracle < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, collector o = order_hacks(o) # if need to select first records without ORDER BY and GROUP BY and without DISTINCT @@ -20,49 +20,58 @@ def visit_Arel_Nodes_SelectStatement o limit = o.limit.expr.to_i offset = o.offset o.offset = nil - sql = super(o) - return <<-eosql + collector << " SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ - FROM (#{sql}) raw_sql_ + FROM (" + + collector = super(o, collector) + collector << ") raw_sql_ WHERE rownum <= #{offset.expr.to_i + limit} ) - WHERE #{visit offset} - eosql + WHERE " + return visit(offset, collector) end if o.limit o = o.dup limit = o.limit.expr - return "SELECT * FROM (#{super(o)}) WHERE ROWNUM <= #{visit limit}" + collector << "SELECT * FROM (" + collector = super(o, collector) + collector << ") WHERE ROWNUM <= " + return visit limit, collector end if o.offset o = o.dup offset = o.offset o.offset = nil - sql = super(o) - return <<-eosql - SELECT * FROM ( + collector << "SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ - FROM (#{sql}) raw_sql_ + FROM (" + collector = super(o, collector) + collector << ") raw_sql_ ) - WHERE #{visit offset} - eosql + WHERE " + return visit offset, collector end super end - def visit_Arel_Nodes_Limit o + def visit_Arel_Nodes_Limit o, collector + collector end - def visit_Arel_Nodes_Offset o - "raw_rnum_ > #{visit o.expr}" + def visit_Arel_Nodes_Offset o, collector + collector << "raw_rnum_ > " + visit o.expr, collector end - def visit_Arel_Nodes_Except o - "( #{visit o.left } MINUS #{visit o.right} )" + def visit_Arel_Nodes_Except o, collector + collector << "( " + collector = infix_value o, collector, " MINUS " + collector << " )" end def visit_Arel_Nodes_UpdateStatement o @@ -91,7 +100,7 @@ def order_hacks o # # orders = o.orders.map { |x| visit x }.join(', ').split(',') orders = o.orders.map do |x| - string = visit x + string = visit(x, Arel::Collectors::SQLString.new).value if string.include?(',') split_order_string(string) else diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index bd22822bcaebe..bb0fe404e8f97 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -7,13 +7,17 @@ module Visitors @visitor = Oracle.new Table.engine.connection_pool end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + it 'modifies order when there is distinct and first value' do # *sigh* select = "DISTINCT foo.id, FIRST_VALUE(projects.name) OVER (foo) AS alias_0__" stmt = Nodes::SelectStatement.new stmt.cores.first.projections << Nodes::SqlLiteral.new(select) stmt.orders << Nodes::SqlLiteral.new('foo') - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__ } @@ -26,8 +30,8 @@ module Visitors stmt.cores.first.projections << Nodes::SqlLiteral.new(select) stmt.orders << Nodes::SqlLiteral.new('foo') - sql = @visitor.accept(stmt) - sql2 = @visitor.accept(stmt) + sql = compile(stmt) + sql2 = compile(stmt) sql.must_equal sql2 end @@ -37,7 +41,7 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.cores.first.projections << Nodes::SqlLiteral.new(select) stmt.orders << Nodes::SqlLiteral.new('foo, bar') - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__, alias_1__ } @@ -49,7 +53,7 @@ module Visitors 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 = compile(stmt) sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__ DESC, alias_1__ } @@ -60,7 +64,7 @@ module Visitors it 'adds a rownum clause' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) - sql = @visitor.accept stmt + sql = compile stmt sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 } end @@ -68,8 +72,8 @@ module Visitors 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 = compile stmt + sql2 = compile stmt sql.must_equal sql2 end @@ -77,9 +81,9 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.orders << Nodes::SqlLiteral.new('foo') stmt.limit = Nodes::Limit.new(10) - sql = @visitor.accept stmt + sql = compile stmt sql.must_be_like %{ - SELECT * FROM (SELECT ORDER BY foo) WHERE ROWNUM <= 10 + SELECT * FROM (SELECT ORDER BY foo ) WHERE ROWNUM <= 10 } end @@ -88,9 +92,9 @@ module Visitors stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new stmt.cores.first.projections << Nodes::SqlLiteral.new('id') stmt.limit = Arel::Nodes::Limit.new(10) - sql = @visitor.accept stmt + sql = compile stmt sql.must_be_like %{ - SELECT * FROM (SELECT DISTINCT id) WHERE ROWNUM <= 10 + SELECT * FROM (SELECT DISTINCT id ) WHERE ROWNUM <= 10 } end @@ -98,11 +102,11 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(10) - sql = @visitor.accept stmt + sql = compile stmt sql.must_be_like %{ SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ - FROM (SELECT) raw_sql_ + FROM (SELECT ) raw_sql_ WHERE rownum <= 20 ) WHERE raw_rnum_ > 10 @@ -113,8 +117,8 @@ module Visitors 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 = compile stmt + sql2 = compile stmt sql.must_equal sql2 end end @@ -123,7 +127,7 @@ module Visitors 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 = compile stmt sql.must_be_like %{ SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ @@ -139,7 +143,7 @@ module Visitors 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 = compile Nodes::Except.new(left, right) sql.must_be_like %{ ( SELECT * FROM users WHERE age > 10 MINUS SELECT * FROM users WHERE age > 20 ) } @@ -148,7 +152,7 @@ module Visitors 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" + compile(node).must_be_like "FOR UPDATE" end end end From 5dceb0e9dc1e1e0abe595194ba1ef9f6112afd05 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 19:43:42 -0700 Subject: [PATCH 1232/1492] fixing mysql visitor --- lib/arel/visitors/mysql.rb | 61 +++++++++++++++++++++++++------------ test/visitors/test_mysql.rb | 18 ++++++----- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 3b911e826fe97..cf590598e1fb9 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -2,25 +2,31 @@ module Arel module Visitors class MySQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Union o, suppress_parens = false - left_result = case o.left + def visit_Arel_Nodes_Union o, collector, suppress_parens = false + unless suppress_parens + collector << "( " + end + + collector = case o.left when Arel::Nodes::Union - visit_Arel_Nodes_Union o.left, true + visit_Arel_Nodes_Union o.left, collector, true else - visit o.left + visit o.left, collector end - right_result = case o.right + collector << " UNION " + + collector = case o.right when Arel::Nodes::Union - visit_Arel_Nodes_Union o.right, true + visit_Arel_Nodes_Union o.right, collector, true else - visit o.right + visit o.right, collector end if suppress_parens - "#{left_result} UNION #{right_result}" + collector else - "( #{left_result} UNION #{right_result} )" + collector << " )" end end @@ -31,26 +37,43 @@ def visit_Arel_Nodes_Bin o ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, collector if o.offset && !o.limit o.limit = Arel::Nodes::Limit.new(Nodes.build_quoted(18446744073709551615)) end super end - def visit_Arel_Nodes_SelectCore o + def visit_Arel_Nodes_SelectCore o, collector 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 ' ' + def visit_Arel_Nodes_UpdateStatement o, collector + collector << "UPDATE " + collector = visit o.relation, collector + + unless o.values.empty? + collector << "SET " + collector = inject_join o.values, collector, ', ' + end + + unless o.wheres.empty? + collector << "SET " + collector = inject_join o.wheres, collector, ' AND ' + end + + unless o.orders.empty? + collector << "ORDER BY " + collector = inject_join o.wheres, collector, ', ' + end + + if o.limit + collector << " " + visit(o.limit, collector) + else + collector + end end end diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 6b62ec133ae0a..8e4b9e6861e92 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -7,14 +7,18 @@ module Visitors @visitor = MySQL.new Table.engine.connection end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + it 'squashes parenthesis on multiple unions' do subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') node = Nodes::Union.new subnode, Arel.sql('topright') - assert_equal 1, @visitor.accept(node).scan('(').length + assert_equal 1, compile(node).scan('(').length subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') node = Nodes::Union.new Arel.sql('topleft'), subnode - assert_equal 1, @visitor.accept(node).scan('(').length + assert_equal 1, compile(node).scan('(').length end ### @@ -23,7 +27,7 @@ module Visitors it 'defaults limit to 18446744073709551615' do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT FROM DUAL LIMIT 18446744073709551615 OFFSET 1" end @@ -31,24 +35,24 @@ module Visitors sc = Arel::Nodes::UpdateStatement.new sc.relation = Table.new(:users) sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) - assert_equal("UPDATE \"users\" LIMIT 'omg'", @visitor.accept(sc)) + assert_equal("UPDATE \"users\" LIMIT 'omg'", compile(sc)) end it 'uses DUAL for empty from' do stmt = Nodes::SelectStatement.new - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT FROM DUAL" end describe 'locking' do it 'defaults to FOR UPDATE when locking' do node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) - @visitor.accept(node).must_be_like "FOR UPDATE" + compile(node).must_be_like "FOR UPDATE" end it 'allows a custom string to be used as a lock' do node = Nodes::Lock.new(Arel.sql('LOCK IN SHARE MODE')) - @visitor.accept(node).must_be_like "LOCK IN SHARE MODE" + compile(node).must_be_like "LOCK IN SHARE MODE" end end end From 03e2006ad97cabb689e2a84bdbf9300baaf518b5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:30:40 -0700 Subject: [PATCH 1233/1492] refactor mssql nodes to move away from string interpolation --- lib/arel/visitors/mssql.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index ef0b78058e43f..cc077d863bd39 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -1,6 +1,14 @@ module Arel module Visitors class MSSQL < Arel::Visitors::ToSql + class RowNumber + attr_reader :expr + + def initialize node + @expr = node + end + end + private # `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate @@ -10,6 +18,10 @@ def visit_Arel_Nodes_Top o "" end + def visit_Arel_Visitors_MSSQL_RowNumber o + "ROW_NUMBER() OVER (#{o.expr}) as _row_num" + end + def visit_Arel_Nodes_SelectStatement o if !o.limit && !o.offset return super o @@ -55,7 +67,7 @@ def determine_order_by x end def row_num_literal order_by - Nodes::SqlLiteral.new("ROW_NUMBER() OVER (#{order_by}) as _row_num") + RowNumber.new order_by end def select_count? x From 9443c01b80f0942025634c9bd22cb741c891090c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:31:47 -0700 Subject: [PATCH 1234/1492] use if / else so my brain stops hurting --- lib/arel/visitors/mssql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index cc077d863bd39..49f79c527dd77 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -59,7 +59,7 @@ def get_offset_limit_clause o end def determine_order_by x - unless x.groups.empty? + if x.groups.any? "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" else "ORDER BY #{find_left_table_pk(x.froms)}" From 3cbafe833b5c388403cd78c3bcb278850733d032 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:35:28 -0700 Subject: [PATCH 1235/1492] move all the "ORDER BY" together --- lib/arel/visitors/mssql.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 49f79c527dd77..479a867e37a91 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -27,11 +27,9 @@ def visit_Arel_Nodes_SelectStatement o 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) + core_order_by = determine_order_by(o.orders, x) if select_count? x x.projections = [row_num_literal(core_order_by)] is_select_count = true @@ -58,11 +56,15 @@ def get_offset_limit_clause o end end - def determine_order_by x - if x.groups.any? - "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" + def determine_order_by orders, x + if orders.any? + "ORDER BY #{orders.map { |x| visit x }.join(', ')}" else - "ORDER BY #{find_left_table_pk(x.froms)}" + if x.groups.any? + "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" + else + "ORDER BY #{find_left_table_pk(x.froms)}" + end end end From 680bac202da2e9c717d4e47c9402f291a8971fad Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:38:00 -0700 Subject: [PATCH 1236/1492] move the ORDER BY to the RowNumber method --- lib/arel/visitors/mssql.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 479a867e37a91..c7ac56b43e0d5 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -19,7 +19,7 @@ def visit_Arel_Nodes_Top o end def visit_Arel_Visitors_MSSQL_RowNumber o - "ROW_NUMBER() OVER (#{o.expr}) as _row_num" + "ROW_NUMBER() OVER (ORDER BY #{o.expr}) as _row_num" end def visit_Arel_Nodes_SelectStatement o @@ -58,12 +58,12 @@ def get_offset_limit_clause o def determine_order_by orders, x if orders.any? - "ORDER BY #{orders.map { |x| visit x }.join(', ')}" + "#{orders.map { |x| visit x }.join(', ')}" else if x.groups.any? - "ORDER BY #{x.groups.map { |g| visit g }.join ', ' }" + "#{x.groups.map { |g| visit g }.join ', ' }" else - "ORDER BY #{find_left_table_pk(x.froms)}" + "#{find_left_table_pk(x.froms)}" end end end From 0d3e9161794e95995ee1f2dcfc063782758e64c0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:44:42 -0700 Subject: [PATCH 1237/1492] build the ast rather than passing around strings --- lib/arel/visitors/mssql.rb | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index c7ac56b43e0d5..cc5e74af1ffd7 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -2,10 +2,10 @@ module Arel module Visitors class MSSQL < Arel::Visitors::ToSql class RowNumber - attr_reader :expr + attr_reader :children def initialize node - @expr = node + @children = node end end @@ -19,7 +19,7 @@ def visit_Arel_Nodes_Top o end def visit_Arel_Visitors_MSSQL_RowNumber o - "ROW_NUMBER() OVER (ORDER BY #{o.expr}) as _row_num" + "ROW_NUMBER() OVER (ORDER BY #{o.children.map { |x| visit x }.join ', '}) as _row_num" end def visit_Arel_Nodes_SelectStatement o @@ -29,12 +29,12 @@ def visit_Arel_Nodes_SelectStatement o is_select_count = false sql = o.cores.map { |x| - core_order_by = determine_order_by(o.orders, x) + core_order_by = row_num_literal determine_order_by(o.orders, x) if select_count? x - x.projections = [row_num_literal(core_order_by)] + x.projections = [core_order_by] is_select_count = true else - x.projections << row_num_literal(core_order_by) + x.projections << core_order_by end visit_Arel_Nodes_SelectCore x @@ -58,13 +58,11 @@ def get_offset_limit_clause o def determine_order_by orders, x if orders.any? - "#{orders.map { |x| visit x }.join(', ')}" + orders + elsif x.groups.any? + x.groups else - if x.groups.any? - "#{x.groups.map { |g| visit g }.join ', ' }" - else - "#{find_left_table_pk(x.froms)}" - end + [Arel.sql(find_left_table_pk(x.froms).to_s)] end end From 2d80dc0cd29895230eaaae4595e249d582439298 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:49:22 -0700 Subject: [PATCH 1238/1492] loop over cores twice to make the collector implementation more convenient --- lib/arel/visitors/mssql.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index cc5e74af1ffd7..fdf37081dce46 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -28,7 +28,7 @@ def visit_Arel_Nodes_SelectStatement o end is_select_count = false - sql = o.cores.map { |x| + o.cores.each { |x| core_order_by = row_num_literal determine_order_by(o.orders, x) if select_count? x x.projections = [core_order_by] @@ -36,9 +36,9 @@ def visit_Arel_Nodes_SelectStatement o else x.projections << core_order_by end + } - visit_Arel_Nodes_SelectCore x - }.join + sql = o.cores.map { |x| 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 From b4f59097b0c9be3babcfb83734814cb74de6ff33 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:54:33 -0700 Subject: [PATCH 1239/1492] finally stop returning strings --- lib/arel/visitors/mssql.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index fdf37081dce46..4085af906963c 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -62,7 +62,8 @@ def determine_order_by orders, x elsif x.groups.any? x.groups else - [Arel.sql(find_left_table_pk(x.froms).to_s)] + pk = find_left_table_pk(x.froms) + pk ? [pk] : [] end end @@ -77,7 +78,7 @@ def select_count? x # FIXME raise exception of there is no pk? # FIXME!! Table.primary_key will be deprecated. What is the replacement?? def find_left_table_pk o - return visit o.primary_key if o.instance_of? Arel::Table + return o.primary_key if o.instance_of? Arel::Table find_left_table_pk o.left if o.kind_of? Arel::Nodes::Join end end From d3d7c218cb577919ce177f8155dc2f34d994f3cb Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 20:56:49 -0700 Subject: [PATCH 1240/1492] mssql visitor is working --- lib/arel/visitors/mssql.rb | 37 +++++++++++++++++++++---------------- test/visitors/test_mssql.rb | 20 ++++++++++++-------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 4085af906963c..0e5b75ec59f6f 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -1,13 +1,7 @@ module Arel module Visitors class MSSQL < Arel::Visitors::ToSql - class RowNumber - attr_reader :children - - def initialize node - @children = node - end - end + RowNumber = Struct.new :children private @@ -18,13 +12,14 @@ def visit_Arel_Nodes_Top o "" end - def visit_Arel_Visitors_MSSQL_RowNumber o - "ROW_NUMBER() OVER (ORDER BY #{o.children.map { |x| visit x }.join ', '}) as _row_num" + def visit_Arel_Visitors_MSSQL_RowNumber o, collector + collector << "ROW_NUMBER() OVER (ORDER BY " + inject_join(o.children, collector, ', ') << ") as _row_num" end - def visit_Arel_Nodes_SelectStatement o + def visit_Arel_Nodes_SelectStatement o, collector if !o.limit && !o.offset - return super o + return super end is_select_count = false @@ -38,12 +33,22 @@ def visit_Arel_Nodes_SelectStatement o end } - sql = o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join + if is_select_count + # fixme count distinct wouldn't work with limit or offset + collector << "SELECT COUNT(1) as count_id FROM (" + end + + collector << "SELECT _t.* FROM (" + collector = o.cores.inject(collector) { |c,x| + visit_Arel_Nodes_SelectCore x, c + } + collector << ") as _t WHERE #{get_offset_limit_clause(o)}" - 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 + if is_select_count + collector << ") AS subquery" + else + collector + end end def get_offset_limit_clause o diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index d62d4b8d1f6d7..a3efcb8b27729 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -8,9 +8,13 @@ module Visitors @table = Arel::Table.new "users" end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + it 'should not modify query if no offset or limit' do stmt = Nodes::SelectStatement.new - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT" end @@ -18,15 +22,15 @@ module Visitors 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" + sql = compile(stmt) + sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY \"users\".\"id\") as _row_num FROM \"users\") as _t WHERE _row_num BETWEEN 1 AND 10" end it 'should go over query ORDER BY if .order()' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.orders << Nodes::SqlLiteral.new('order_by') - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY order_by) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10" end @@ -34,7 +38,7 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.cores.first.groups << Nodes::SqlLiteral.new('group_by') stmt.limit = Nodes::Limit.new(10) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY group_by) as _row_num GROUP BY group_by) as _t WHERE _row_num BETWEEN 1 AND 10" end @@ -42,14 +46,14 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(20) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 21 AND 30" end it 'should use >= if only .offset' do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(20) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num >= 21" end @@ -57,7 +61,7 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.cores.first.projections << Nodes::Count.new('*') - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT COUNT(1) as count_id FROM (SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10) AS subquery" end From 136025996196a3c279d9d37a76ce69eb9cc7937b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:14:00 -0700 Subject: [PATCH 1241/1492] informix is working --- lib/arel/visitors/informix.rb | 60 ++++++++++++++++++++++------------ lib/arel/visitors/to_sql.rb | 3 +- test/visitors/test_informix.rb | 16 +++++---- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index 244c68bed3708..8de05f60f6209 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -2,30 +2,48 @@ module 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 ' ' + def visit_Arel_Nodes_SelectStatement o, collector + collector << "SELECT " + collector = maybe_visit o.offset, collector + collector = maybe_visit o.limit, collector + collector = o.cores.inject(collector) { |c,x| + visit_Arel_Nodes_SelectCore x, c + } + if o.orders.any? + collector << "ORDER BY " + collector = inject_join o.orders, collector, ", " + end + collector = maybe_visit o.lock, collector 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 ' ' + def visit_Arel_Nodes_SelectCore o, collector + collector = inject_join o.projections, collector, ", " + froms = false + if o.source && !o.source.empty? + froms = true + collector << " FROM " + collector = visit o.source, collector + end + + if o.wheres.any? + collector << " WHERE " + collector = inject_join o.wheres, collector, " AND " + end + + if o.groups.any? + collector << "GROUP BY " + collector = inject_join o.groups, collector, ", " + end + + maybe_visit o.having, collector end - def visit_Arel_Nodes_Offset o - "SKIP #{visit o.expr}" + def visit_Arel_Nodes_Offset o, collector + collector << "SKIP " + visit o.expr, collector end - def visit_Arel_Nodes_Limit o - "LIMIT #{visit o.expr}" + def visit_Arel_Nodes_Limit o, collector + collector << "LIMIT " + visit o.expr, collector + collector << " " end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8e254d504b007..ee72d864e1ba9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -107,8 +107,7 @@ def visit_Arel_Nodes_UpdateStatement o, collector end unless wheres.empty? - collector << " " if values - collector << "WHERE " + collector << " WHERE " collector = inject_join wheres, collector, " AND " end diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index e4c2e81296d7c..6d94282b7731c 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -7,10 +7,14 @@ module Visitors @visitor = Informix.new Table.engine.connection end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + it 'uses LIMIT n to limit results' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT LIMIT 1" end @@ -20,14 +24,14 @@ module Visitors stmt.relation = table stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) stmt.key = table[:id] - sql = @visitor.accept(stmt) - sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT LIMIT 1 \"users\".\"id\" FROM \"users\" )" + sql = compile(stmt) + sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT LIMIT 1 \"users\".\"id\" FROM \"users\")" end it 'uses SKIP n to jump results' do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(10) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT SKIP 10" end @@ -35,7 +39,7 @@ module Visitors stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) stmt.offset = Nodes::Offset.new(1) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT SKIP 1 LIMIT 1" end @@ -45,7 +49,7 @@ module Visitors core.source = Nodes::JoinSource.new(table, [table.create_join(Table.new(:comments))]) stmt = Nodes::SelectStatement.new([core]) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like 'SELECT FROM "posts" INNER JOIN "comments"' end From 4861bc62cf4832bcfbaecac9ad9ee73deb172c0c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:15:15 -0700 Subject: [PATCH 1242/1492] fixing ibm db --- lib/arel/visitors/ibm_db.rb | 6 ++++-- test/visitors/test_ibm_db.rb | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/ibm_db.rb b/lib/arel/visitors/ibm_db.rb index a41f8ff573669..f1d126790db53 100644 --- a/lib/arel/visitors/ibm_db.rb +++ b/lib/arel/visitors/ibm_db.rb @@ -3,8 +3,10 @@ module Visitors class IBM_DB < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Limit o - "FETCH FIRST #{visit o.expr } ROWS ONLY" + def visit_Arel_Nodes_Limit o, collector + collector << "FETCH FIRST " + collector = visit o.expr, collector + collector << " ROWS ONLY" end end diff --git a/test/visitors/test_ibm_db.rb b/test/visitors/test_ibm_db.rb index 75f1daff6a577..f1aa7612be09e 100644 --- a/test/visitors/test_ibm_db.rb +++ b/test/visitors/test_ibm_db.rb @@ -7,10 +7,14 @@ module Visitors @visitor = IBM_DB.new Table.engine.connection end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + it 'uses FETCH FIRST n ROWS to limit results' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY" end @@ -20,7 +24,7 @@ module Visitors stmt.relation = table stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) stmt.key = table[:id] - sql = @visitor.accept(stmt) + sql = compile(stmt) sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT \"users\".\"id\" FROM \"users\" FETCH FIRST 1 ROWS ONLY)" end From 02bf81f198a69b51a758aab96d450fafbcbc347c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:19:05 -0700 Subject: [PATCH 1243/1492] fixing bind value tests --- test/visitors/test_bind_visitor.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index 4563fddfd14cc..a04a04f4cb18b 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -34,7 +34,7 @@ def test_assignment_binds_are_substituted end def test_visitor_yields_on_binds - visitor = Class.new(Arel::Visitors::Visitor) { + visitor = Class.new(Arel::Visitors::ToSql) { def initialize omg end @@ -48,7 +48,7 @@ def initialize omg end def test_visitor_only_yields_on_binds - visitor = Class.new(Arel::Visitors::Visitor) { + visitor = Class.new(Arel::Visitors::ToSql) { def initialize omg end @@ -58,9 +58,7 @@ def initialize omg bp = Arel.sql 'omg' called = false - assert_raises(TypeError) { - visitor.accept(bp, collector) { called = true } - } + visitor.accept(bp, collector) { called = true } refute called end end From dc9b23624e5e2a6a5943f8eaef235df59d563805 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:21:36 -0700 Subject: [PATCH 1244/1492] fixing test_table.rb --- lib/arel/visitors/to_sql.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ee72d864e1ba9..921eeb9b91c30 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -114,16 +114,16 @@ def visit_Arel_Nodes_UpdateStatement o, collector collector 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?), + def visit_Arel_Nodes_InsertStatement o, collector + collector << "INSERT INTO " + collector = visit o.relation, collector + if o.columns.any? + collector << "(#{o.columns.map { |x| + quote_column_name x.name + }.join ', '})" + end - (visit o.values if o.values), - ].compact.join ' ' + maybe_visit o.values, collector end def visit_Arel_Nodes_Exists o, collector From 59b1d98a5f6268bee661a411f06b285fdb292a47 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:25:37 -0700 Subject: [PATCH 1245/1492] fixing insert manager --- lib/arel/visitors/to_sql.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 921eeb9b91c30..2c460ed4ba9f4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -118,7 +118,7 @@ def visit_Arel_Nodes_InsertStatement o, collector collector << "INSERT INTO " collector = visit o.relation, collector if o.columns.any? - collector << "(#{o.columns.map { |x| + collector << " (#{o.columns.map { |x| quote_column_name x.name }.join ', '})" end @@ -171,14 +171,18 @@ 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| + def visit_Arel_Nodes_Values o, collector + collector << "VALUES (" + + collector << o.expressions.zip(o.columns).map { |value, attr| if Nodes::SqlLiteral === value - visit value + value else quote(value, attr && column_for(attr)) end - }.join ', '})" + }.join(', ') + + collector << ")" end def visit_Arel_Nodes_SelectStatement o, collector From 307f89312353d1360ee547468ebaaf8791889d71 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:26:50 -0700 Subject: [PATCH 1246/1492] fixing sql_literal tests --- test/nodes/test_sql_literal.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index 2f17cfd72a4a8..ed602cc47df23 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -8,6 +8,10 @@ module Nodes @visitor = Visitors::ToSql.new Table.engine.connection end + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + describe 'sql' do it 'makes a sql literal node' do sql = Arel.sql 'foo' @@ -18,19 +22,19 @@ module Nodes describe 'count' do it 'makes a count node' do node = SqlLiteral.new('*').count - @visitor.accept(node).must_be_like %{ COUNT(*) } + compile(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 *) } + compile(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 } + compile(node).must_be_like %{ foo = 1 } end it 'is equal with equal contents' do @@ -47,14 +51,14 @@ module Nodes 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) } + compile(node).must_be_like %{ (foo = 1 OR foo = 2) } end end describe 'grouped "and" equality' do it 'makes a grouping node with an or node' do node = SqlLiteral.new('foo').eq_all([1,2]) - @visitor.accept(node).must_be_like %{ (foo = 1 AND foo = 2) } + compile(node).must_be_like %{ (foo = 1 AND foo = 2) } end end From ba577e539f585fd09dc96d70527b5f94e35b2971 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:33:04 -0700 Subject: [PATCH 1247/1492] fixing select core tests --- test/nodes/test_select_core.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index 9aca0cff16cd9..ca4f070444209 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -11,20 +11,20 @@ def test_clone dolly = core.clone - dolly.froms.must_equal core.froms - dolly.projections.must_equal core.projections - dolly.wheres.must_equal core.wheres + assert_equal core.froms, dolly.froms + assert_equal core.projections, dolly.projections + assert_equal core.wheres, dolly.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 + refute_same core.froms, dolly.froms + refute_same core.projections, dolly.projections + refute_same core.wheres, dolly.wheres end def test_set_quantifier core = Arel::Nodes::SelectCore.new core.set_quantifier = Arel::Nodes::Distinct.new viz = Arel::Visitors::ToSql.new Table.engine.connection_pool - assert_match 'DISTINCT', viz.accept(core) + assert_match 'DISTINCT', viz.accept(core, Collectors::SQLString.new).value end def test_equality_with_same_ivars From eba73dcbd505ce9b2ed28dc487e02046f1d9c257 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:35:23 -0700 Subject: [PATCH 1248/1492] fixing OVER --- lib/arel/visitors/to_sql.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 2c460ed4ba9f4..7b0d6e2de1689 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -377,16 +377,16 @@ def visit_Arel_Nodes_CurrentRow o, collector collector << "CURRENT ROW" end - def visit_Arel_Nodes_Over o + def visit_Arel_Nodes_Over o, collector 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}" + when nil + visit(o.left, collector) << " OVER ()" + when Arel::Nodes::SqlLiteral + infix_value o, collector, " OVER " + when String, Symbol + visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}" + else + infix_value o, collector, " OVER " end end From bf791073972a179e6d79c8e2f89536734e315f54 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:36:43 -0700 Subject: [PATCH 1249/1492] fixing EXTRACT --- lib/arel/visitors/to_sql.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7b0d6e2de1689..9ec926a66ec63 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -448,8 +448,16 @@ def visit_Arel_Nodes_NamedFunction o, collector end end - def visit_Arel_Nodes_Extract o - "EXTRACT(#{o.field.to_s.upcase} FROM #{visit o.expr})#{o.alias ? " AS #{visit o.alias}" : ''}" + def visit_Arel_Nodes_Extract o, collector + collector << "EXTRACT(#{o.field.to_s.upcase} FROM " + collector = visit o.expr, collector + collector << ")" + if o.alias + collector << " AS " + visit o.alias, collector + else + collector + end end def visit_Arel_Nodes_Count o, collector From 5d403e45858956e89d323e44ab7b413f80f5171f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 8 Apr 2014 21:38:19 -0700 Subject: [PATCH 1250/1492] fixing BINARY tests --- lib/arel/visitors/mysql.rb | 5 +++-- lib/arel/visitors/to_sql.rb | 4 ++-- test/nodes/test_bin.rb | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index cf590598e1fb9..92348ca7e3d18 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -30,8 +30,9 @@ def visit_Arel_Nodes_Union o, collector, suppress_parens = false end end - def visit_Arel_Nodes_Bin o - "BINARY #{visit o.expr}" + def visit_Arel_Nodes_Bin o, collector + collector << "BINARY " + visit o.expr, collector end ### diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9ec926a66ec63..cba289c35cf56 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -274,8 +274,8 @@ def visit_Arel_Nodes_SelectCore o, collector collector end - def visit_Arel_Nodes_Bin o - visit o.expr + def visit_Arel_Nodes_Bin o, collector + visit o.expr, collector end def visit_Arel_Nodes_Distinct o, collector diff --git a/test/nodes/test_bin.rb b/test/nodes/test_bin.rb index 1d955b218b182..0dcc5f7bb8d0f 100644 --- a/test/nodes/test_bin.rb +++ b/test/nodes/test_bin.rb @@ -10,13 +10,13 @@ def test_new 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) + assert_equal 'zomg', viz.accept(node, Collectors::SQLString.new).value end def test_mysql_to_sql viz = Arel::Visitors::MySQL.new Table.engine.connection_pool node = Arel::Nodes::Bin.new(Arel.sql('zomg')) - assert_equal 'BINARY zomg', viz.accept(node) + assert_equal 'BINARY zomg', viz.accept(node, Collectors::SQLString.new).value end def test_equality_with_same_ivars From 3b5b5d99ff9f68f00d9e121715e429ddbd8795cf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 10:24:41 -0700 Subject: [PATCH 1251/1492] make the bindvalue visitor backwards compatible --- lib/arel/visitors/bind_visitor.rb | 5 ++++- test/visitors/test_bind_visitor.rb | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb index c316c8d702898..c336e87395af3 100644 --- a/lib/arel/visitors/bind_visitor.rb +++ b/lib/arel/visitors/bind_visitor.rb @@ -25,7 +25,10 @@ def visit_Arel_Nodes_Assignment o, collector def visit_Arel_Nodes_BindParam o, collector if @block - @block.call(collector) + val = @block.call + if String === val + collector << val + end else super end diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index a04a04f4cb18b..5171bbe57caad 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -25,8 +25,8 @@ def test_assignment_binds_are_substituted }.new Table.engine.connection assignment = um.ast.values[0] - actual = visitor.accept(assignment, collector) { |collector| - collector << "replace" + actual = visitor.accept(assignment, collector) { + "replace" } assert actual value = actual.value @@ -43,7 +43,7 @@ def initialize omg bp = Nodes::BindParam.new 'omg' called = false - visitor.accept(bp, collector) { |collector| called = true } + visitor.accept(bp, collector) { called = true } assert called end From 05eda21c4164e394fbb21f705408011ddeb37d56 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 11:06:31 -0700 Subject: [PATCH 1252/1492] add a compile method for some backwards compatibility --- lib/arel/visitors/to_sql.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index cba289c35cf56..fd1332a4db50f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -65,6 +65,10 @@ def initialize connection @quoted_columns = {} end + def compile node, &block + accept(node, Arel::Collectors::SQLString.new, &block).value + end + private def visit_Arel_Nodes_DeleteStatement o, collector From 9c87737c9abefdf059a06f1213e8dee2d87f308a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 11:58:44 -0700 Subject: [PATCH 1253/1492] adding a bind value collector --- lib/arel/collectors/bind.rb | 32 +++++++++++++ lib/arel/collectors/sql_string.rb | 5 +-- lib/arel/visitors/to_sql.rb | 5 ++- test/collectors/test_bind_collector.rb | 62 ++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 lib/arel/collectors/bind.rb create mode 100644 test/collectors/test_bind_collector.rb diff --git a/lib/arel/collectors/bind.rb b/lib/arel/collectors/bind.rb new file mode 100644 index 0000000000000..4309de75c946e --- /dev/null +++ b/lib/arel/collectors/bind.rb @@ -0,0 +1,32 @@ +module Arel + module Collectors + class Bind + def initialize + @parts = [] + end + + def << str + @parts << str + self + end + + def add_bind bind + @parts << bind + self + end + + def value; @parts; end + + def substitute_binds bvs + bvs = bvs.dup + @parts.map do |val| + if Arel::Nodes::BindParam === val + bvs.shift + else + val + end + end + end + end + end +end diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index 824b0a1712777..526de66416ba0 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -16,11 +16,8 @@ def << str self end - def start; self; end - def finish; self; end - def add_bind bind - self << bind + self << bind.to_s self end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index fd1332a4db50f..9cda88454baf0 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -693,7 +693,10 @@ def visit_Arel_Attributes_Attribute o, collector def literal o, collector; collector << o.to_s; end - alias :visit_Arel_Nodes_BindParam :literal + def visit_Arel_Nodes_BindParam o, collector + collector.add_bind o + end + alias :visit_Arel_Nodes_SqlLiteral :literal alias :visit_Bignum :literal alias :visit_Fixnum :literal diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb new file mode 100644 index 0000000000000..c7748d7d1081a --- /dev/null +++ b/test/collectors/test_bind_collector.rb @@ -0,0 +1,62 @@ +require 'helper' +require 'arel/collectors/bind' + +module Arel + module Collectors + class TestBindCollector < Arel::Test + def setup + @conn = FakeRecord::Base.new + @visitor = Visitors::ToSql.new @conn.connection + super + end + + def collect node + @visitor.accept(node, Collectors::Bind.new) + end + + def compile node + collect(node).value + end + + def ast_with_binds bv + table = Table.new(:users) + manager = Arel::SelectManager.new Table.engine, table + manager.where(table[:age].eq(bv)) + manager.where(table[:name].eq(bv)) + manager.ast + end + + def test_leaves_binds + node = Nodes::BindParam.new 'omg' + list = compile node + assert_equal node, list.first + assert_equal node.class, list.first.class + end + + def test_adds_strings + bv = Nodes::BindParam.new('?') + list = compile ast_with_binds bv + assert_operator list.length, :>, 0 + assert_equal bv, list.grep(Nodes::BindParam).first + assert_equal bv.class, list.grep(Nodes::BindParam).first.class + end + + def test_substitute_binds + bv = Nodes::BindParam.new('?') + collector = collect ast_with_binds bv + + values = collector.value + + offsets = values.map.with_index { |v,i| + [v,i] + }.find_all { |(v,i)| Nodes::BindParam === v }.map(&:last) + + list = collector.substitute_binds ["hello", "world"] + assert_equal "hello", list[offsets[0]] + assert_equal "world", list[offsets[1]] + + assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', list.join + end + end + end +end From f81965509d74a4607ecbc3cc6f91c2ca22919f3a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 14:31:10 -0700 Subject: [PATCH 1254/1492] add a compile method to the collectors --- lib/arel/collectors/bind.rb | 4 ++++ lib/arel/collectors/sql_string.rb | 4 ++++ test/collectors/test_bind_collector.rb | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/lib/arel/collectors/bind.rb b/lib/arel/collectors/bind.rb index 4309de75c946e..05cd9665096ea 100644 --- a/lib/arel/collectors/bind.rb +++ b/lib/arel/collectors/bind.rb @@ -27,6 +27,10 @@ def substitute_binds bvs end end end + + def compile bvs + substitute_binds(bvs).join + end end end end diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index 526de66416ba0..45001bb50789a 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -20,6 +20,10 @@ def add_bind bind self << bind.to_s self end + + def compile bvs + value + end end end end diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb index c7748d7d1081a..036d8f05fe015 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_bind_collector.rb @@ -57,6 +57,14 @@ def test_substitute_binds assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', list.join end + + def test_compile + bv = Nodes::BindParam.new('?') + collector = collect ast_with_binds bv + + sql = collector.compile ["hello", "world"] + assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', sql + end end end end From e33c568f5e07e8caf7d36e8a8ca1a793b1781dc4 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 15:18:43 -0700 Subject: [PATCH 1255/1492] fix bind values in insert statements --- lib/arel/visitors/mysql.rb | 8 ++++---- lib/arel/visitors/to_sql.rb | 12 ++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 92348ca7e3d18..70a37582c2121 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -55,18 +55,18 @@ def visit_Arel_Nodes_UpdateStatement o, collector collector = visit o.relation, collector unless o.values.empty? - collector << "SET " + collector << " SET " collector = inject_join o.values, collector, ', ' end unless o.wheres.empty? - collector << "SET " + collector << " WHERE " collector = inject_join o.wheres, collector, ' AND ' end unless o.orders.empty? - collector << "ORDER BY " - collector = inject_join o.wheres, collector, ', ' + collector << " ORDER BY " + collector = inject_join o.orders, collector, ', ' end if o.limit diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 9cda88454baf0..5604b9de04fec 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -178,13 +178,17 @@ def column_cache(table) def visit_Arel_Nodes_Values o, collector collector << "VALUES (" - collector << o.expressions.zip(o.columns).map { |value, attr| + len = o.expressions.length - 1 + o.expressions.zip(o.columns).each_with_index { |(value, attr), i| if Nodes::SqlLiteral === value - value + collector = visit value, collector else - quote(value, attr && column_for(attr)) + collector << quote(value, attr && column_for(attr)).to_s end - }.join(', ') + unless i == len + collector << ', ' + end + } collector << ")" end From 03e560b0943f90155a13934c27abfe3827579d8b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 15:20:39 -0700 Subject: [PATCH 1256/1492] add test for sql string collector --- test/collectors/test_sql_string.rb | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/collectors/test_sql_string.rb diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb new file mode 100644 index 0000000000000..6d2e23151bcc7 --- /dev/null +++ b/test/collectors/test_sql_string.rb @@ -0,0 +1,38 @@ +require 'helper' +require 'arel/collectors/bind' + +module Arel + module Collectors + class TestSqlString < Arel::Test + def setup + @conn = FakeRecord::Base.new + @visitor = Visitors::ToSql.new @conn.connection + super + end + + def collect node + @visitor.accept(node, Collectors::SQLString.new) + end + + def compile node + collect(node).value + end + + def ast_with_binds bv + table = Table.new(:users) + manager = Arel::SelectManager.new Table.engine, table + manager.where(table[:age].eq(bv)) + manager.where(table[:name].eq(bv)) + manager.ast + end + + def test_compile + bv = Nodes::BindParam.new('?') + collector = collect ast_with_binds bv + + sql = collector.compile ["hello", "world"] + assert_equal 'SELECT FROM "users" WHERE "users"."age" = ? AND "users"."name" = ?', sql + end + end + end +end From 5703a965ad58c1f7515e389087ec2d1e73854028 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 15:42:26 -0700 Subject: [PATCH 1257/1492] rhs bind parameters should be visited --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5604b9de04fec..e1b46eb6e6658 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -636,7 +636,7 @@ def visit_Arel_Nodes_Or o, collector def visit_Arel_Nodes_Assignment o, collector case o.right - when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute + when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute, Arel::Nodes::BindParam collector = visit o.left, collector collector << " = " visit o.right, collector From 4b187a19b16ed4cb0b248e4e4d658a4ef6e8f26e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 9 Apr 2014 15:46:56 -0700 Subject: [PATCH 1258/1492] fix spacing so that Rails is happy --- lib/arel/visitors/mysql.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 70a37582c2121..c4800f0466672 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -54,18 +54,24 @@ def visit_Arel_Nodes_UpdateStatement o, collector collector << "UPDATE " collector = visit o.relation, collector + add_space = false + unless o.values.empty? - collector << " SET " + add_space = true + collector << "SET " collector = inject_join o.values, collector, ', ' end unless o.wheres.empty? - collector << " WHERE " + collector << ' ' if add_space + add_space = true + collector << "WHERE " collector = inject_join o.wheres, collector, ' AND ' end unless o.orders.empty? - collector << " ORDER BY " + collector << ' ' if add_space + collector << "ORDER BY " collector = inject_join o.orders, collector, ', ' end From 214af496460c3639e8963c85834ee064f203cc6b Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Thu, 10 Apr 2014 10:08:37 -0400 Subject: [PATCH 1259/1492] Allow INSERT INTO SELECT queries --- lib/arel/insert_manager.rb | 4 ++++ lib/arel/nodes/insert_statement.rb | 7 +++++-- lib/arel/visitors/to_sql.rb | 8 +++++++- test/test_insert_manager.rb | 23 +++++++++++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index b5d2aeb3a489b..8839dd8181504 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -13,6 +13,10 @@ def into table def columns; @ast.columns end def values= val; @ast.values = val; end + def select select + @ast.select = select + end + def insert fields return if fields.empty? diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index ec8870a1c2b79..ada4fcc5622d3 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -1,29 +1,32 @@ module Arel module Nodes class InsertStatement < Arel::Nodes::Node - attr_accessor :relation, :columns, :values + attr_accessor :relation, :columns, :values, :select def initialize super() @relation = nil @columns = [] @values = nil + @select = nil end def initialize_copy other super @columns = @columns.clone @values = @values.clone if @values + @select = @select.clone if @select end def hash - [@relation, @columns, @values].hash + [@relation, @columns, @values, @select].hash end def eql? other self.class == other.class && self.relation == other.relation && self.columns == other.columns && + self.select == other.select && self.values == other.values end alias :== :eql? diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index e1b46eb6e6658..22f7943ab918b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -127,7 +127,13 @@ def visit_Arel_Nodes_InsertStatement o, collector }.join ', '})" end - maybe_visit o.values, collector + if o.values + maybe_visit o.values, collector + elsif o.select + maybe_visit o.select, collector + else + collector + end end def visit_Arel_Nodes_Exists o, collector diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 9e4cc9d05e2f7..66598894388da 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -139,5 +139,28 @@ module Arel } end end + + describe "select" do + + it "accepts a select query in place of a VALUES clause" do + table = Table.new :users + + manager = Arel::InsertManager.new Table.engine + manager.into table + + select = Arel::SelectManager.new Table.engine + select.project Arel.sql('1') + select.project Arel.sql('"aaron"') + + manager.select select + manager.columns << table[:id] + manager.columns << table[:name] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id", "name") SELECT 1, "aaron" + } + end + + end + end end From 4a898b3c682f74890065e28ffe03899f23a4ab20 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Thu, 10 Apr 2014 13:30:22 -0400 Subject: [PATCH 1260/1492] Get rid of the visit select hack --- test/test_insert_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 66598894388da..4e82ca34c093e 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -156,7 +156,7 @@ module Arel manager.columns << table[:id] manager.columns << table[:name] manager.to_sql.must_be_like %{ - INSERT INTO "users" ("id", "name") SELECT 1, "aaron" + INSERT INTO "users" ("id", "name") (SELECT 1, "aaron") } end From d1192956e481474a77ea01da35c0546ff422a0e6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 11 Apr 2014 16:14:04 -0700 Subject: [PATCH 1261/1492] always add a space before keywords (it is easier) --- lib/arel/visitors/mysql.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index c4800f0466672..70a37582c2121 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -54,24 +54,18 @@ def visit_Arel_Nodes_UpdateStatement o, collector collector << "UPDATE " collector = visit o.relation, collector - add_space = false - unless o.values.empty? - add_space = true - collector << "SET " + collector << " SET " collector = inject_join o.values, collector, ', ' end unless o.wheres.empty? - collector << ' ' if add_space - add_space = true - collector << "WHERE " + collector << " WHERE " collector = inject_join o.wheres, collector, ' AND ' end unless o.orders.empty? - collector << ' ' if add_space - collector << "ORDER BY " + collector << " ORDER BY " collector = inject_join o.orders, collector, ', ' end From d31ab9f8a68235f1473784910090d0a82c58ac20 Mon Sep 17 00:00:00 2001 From: Andriy Tyurnikov Date: Sat, 12 Apr 2014 20:01:17 +0300 Subject: [PATCH 1262/1492] test gem build in ci process, inspired by issue #256 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0eb36dcda2859..5da682028ce51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ -script: "rake test" +script: + - "rake test" + - "gem build arel.gemspec" rvm: - rbx - jruby From 58a933069c2c2910c81174e8168047e3c08dbe04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sat, 12 Apr 2014 15:01:35 -0300 Subject: [PATCH 1263/1492] Fix manifest and gemspec Fixes #256 --- Manifest.txt | 6 ++++++ arel.gemspec | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index b19411be8496c..3892cd3b2aff9 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -12,6 +12,8 @@ lib/arel.rb lib/arel/alias_predication.rb lib/arel/attributes.rb lib/arel/attributes/attribute.rb +lib/arel/collectors/bind.rb +lib/arel/collectors/sql_string.rb lib/arel/compatibility/wheres.rb lib/arel/crud.rb lib/arel/delete_manager.rb @@ -62,6 +64,7 @@ lib/arel/table.rb lib/arel/tree_manager.rb lib/arel/update_manager.rb lib/arel/visitors.rb +lib/arel/visitors/bind_substitute.rb lib/arel/visitors/bind_visitor.rb lib/arel/visitors/depth_first.rb lib/arel/visitors/dot.rb @@ -71,12 +74,15 @@ lib/arel/visitors/mssql.rb lib/arel/visitors/mysql.rb lib/arel/visitors/oracle.rb lib/arel/visitors/postgresql.rb +lib/arel/visitors/reduce.rb lib/arel/visitors/sqlite.rb lib/arel/visitors/to_sql.rb lib/arel/visitors/visitor.rb lib/arel/visitors/where_sql.rb lib/arel/window_predications.rb test/attributes/test_attribute.rb +test/collectors/test_bind_collector.rb +test/collectors/test_sql_string.rb test/helper.rb test/nodes/test_and.rb test/nodes/test_as.rb diff --git a/arel.gemspec b/arel.gemspec index 84caf0df0810a..8861c222bf2a4 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,41 +1,41 @@ # -*- encoding: utf-8 -*- -# stub: arel 5.0.0.20140210193626 ruby lib +# stub: arel 5.0.0.20140412150050 ruby lib Gem::Specification.new do |s| s.name = "arel" - s.version = "5.0.0.20140210193626" + s.version = "5.0.0.20140412150050" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2014-02-10" - s.description = "Arel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." + s.date = "2014-04-12" + s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] - s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/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/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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/collectors/bind.rb", "lib/arel/collectors/sql_string.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/full_outer_join.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/right_outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_substitute.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/reduce.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] s.homepage = "http://github.com/rails/arel" s.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] s.rubyforge_project = "arel" - s.rubygems_version = "2.2.0" - 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_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_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.rubygems_version = "2.2.2" + s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" + s.test_files = ["test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] 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, ["~> 5.2"]) + s.add_development_dependency(%q, ["~> 5.3"]) s.add_development_dependency(%q, ["~> 4.0"]) - s.add_development_dependency(%q, ["~> 3.8"]) + s.add_development_dependency(%q, ["~> 3.6"]) else - s.add_dependency(%q, ["~> 5.2"]) + s.add_dependency(%q, ["~> 5.3"]) s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.8"]) + s.add_dependency(%q, ["~> 3.6"]) end else - s.add_dependency(%q, ["~> 5.2"]) + s.add_dependency(%q, ["~> 5.3"]) s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.8"]) + s.add_dependency(%q, ["~> 3.6"]) end end From a8f43c099d74d875e890dbdf64352c1bf8a1ca8f Mon Sep 17 00:00:00 2001 From: Erik Michaels-Ober Date: Mon, 14 Apr 2014 23:13:30 +0200 Subject: [PATCH 1264/1492] Fix typo in @brynary's name --- Rakefile | 2 +- arel.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 9bcddaf80ce28..f9257d696f225 100644 --- a/Rakefile +++ b/Rakefile @@ -10,7 +10,7 @@ Hoe.plugin :bundler # `gem install hoe-bundler` Hoe.spec 'arel' do developer('Aaron Patterson', 'aaron@tenderlovemaking.com') - developer('Bryan Halmkamp', 'bryan@brynary.com') + developer('Bryan Helmkamp', 'bryan@brynary.com') developer('Emilio Tagua', 'miloops@gmail.com') developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email diff --git a/arel.gemspec b/arel.gemspec index 8861c222bf2a4..b9b2cfbace180 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -7,7 +7,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] - s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"] + s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"] s.date = "2014-04-12" s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] From 1a2bf3df0e3350142d36a51d351ed38523b9f63c Mon Sep 17 00:00:00 2001 From: Dylan Smith Date: Wed, 13 Feb 2013 14:37:51 -0500 Subject: [PATCH 1265/1492] Test quoting integers when comparing a string column with integers. An equality with a string column and integer like SELECT * FROM `users` WHERE `login_token` = 0 LIMIT 1; will match match any string that doesn't start with a digit in certain databases, like mysql. Make sure we quote the integer to avoid this problem in a database independant way. --- test/support/fake_record.rb | 14 +++++++++++--- test/visitors/test_to_sql.rb | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index ed4420a2cdd1c..035a7a46cfd6c 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -60,9 +60,13 @@ def schema_cache end def quote thing, column = nil - if column && column.type == :integer - return 'NULL' if thing.nil? - return thing.to_i + if column && !thing.nil? + case column.type + when :integer + thing = thing.to_i + when :string + thing = thing.to_s + end end case thing @@ -111,6 +115,10 @@ def columns_hash def schema_cache connection end + + def quote thing, column = nil + connection.quote thing, column + end end class Base diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index eb102c19055a3..05e75b5e0d9bd 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -119,6 +119,12 @@ def dispatch sql.must_be_like %{ "users"."id" = 1 } end + it 'should use the column to quote integers' do + table = Table.new(:users) + sql = compile table[:name].eq(0) + sql.must_be_like %{ "users"."name" = '0' } + end + it 'should handle nil' do sql = compile Nodes::Equality.new(@table[:name], nil) sql.must_be_like %{ "users"."name" IS NULL } @@ -160,6 +166,12 @@ def dispatch assert_match(/LIMIT 'omg'/, compile(sc)) end + it "should quote LIMIT without column type coercion" do + table = Table.new(:users) + sc = table.where(table[:name].eq(0)).take(1).ast + assert_match(/WHERE "users"."name" = '0' LIMIT 1/, compile(sc)) + end + it "should visit_DateTime" do called_with = nil @conn.connection.extend(Module.new { @@ -179,9 +191,9 @@ def dispatch end it "should visit_Float" do - test = Table.new(:users)[:name].eq 2.14 + test = Table.new(:products)[:price].eq 2.14 sql = compile test - sql.must_be_like %{"users"."name" = 2.14} + sql.must_be_like %{"products"."price" = 2.14} end it "should visit_Not" do From ac3af505aa5df38c3826fccb42107aa88693ee17 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Fri, 2 May 2014 21:24:33 +0900 Subject: [PATCH 1266/1492] Add collector argument to address ArgumentError: wrong number of arguments (2 for 1) --- lib/arel/visitors/oracle.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 2cdbafadada24..699b52fe9ab6d 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -74,7 +74,7 @@ def visit_Arel_Nodes_Except o, collector collector << " )" end - def visit_Arel_Nodes_UpdateStatement o + def visit_Arel_Nodes_UpdateStatement o, collector # Oracle does not allow ORDER BY/LIMIT in UPDATEs. if o.orders.any? && o.limit.nil? # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, From 538ac7c2aadbe6142901f70b921f61f4398bd58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 2 May 2014 14:01:57 -0300 Subject: [PATCH 1267/1492] Test with Ruby 2.1.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5da682028ce51..9a11ead3ec4d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ rvm: - jruby - 1.9.3 - 2.0.0 - - 2.1.0 + - 2.1.1 matrix: allow_failures: - rvm: rbx From b5b13f254bb2a395bcde6b16e7d811339d634c01 Mon Sep 17 00:00:00 2001 From: bjhaid Date: Fri, 2 May 2014 13:56:24 -0500 Subject: [PATCH 1268/1492] Updated README --- README.markdown | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/README.markdown b/README.markdown index 99263dc2d22ad..8285bbfd12931 100644 --- a/README.markdown +++ b/README.markdown @@ -53,6 +53,18 @@ users.project(users[:id]) # => SELECT users.id FROM users ``` +Comparison operators `=`, `!=`, `<`, `>`, `<=`, `>=`, `IN`: + +```ruby +users.where(users[:age].eq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" = 10 +users.where(users[:age].not_eq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" != 10 +users.where(users[:age].lt(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" < 10 +users.where(users[:age].gt(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" > 10 +users.where(users[:age].lteq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" <= 10 +users.where(users[:age].gteq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" >= 10 +users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" IN (20, 16, 17) +``` + Joins resemble SQL strongly: ```ruby @@ -60,6 +72,13 @@ users.join(photos).on(users[:id].eq(photos[:user_id])) # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id ``` +Left Joins + +```ruby +users.join(photos, Arel::Nodes::OuterJoin).on(users[:id].eq(photos[:user_id])) +# => SELECT FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id +``` + What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel: ```ruby @@ -97,6 +116,23 @@ users.where(users[:name].eq('bob').or(users[:age].lt(25))) The `AND` operator behaves similarly. +Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: + +```ruby +photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 +users.project(users[:age].sum) # => SELECT SUM(users.age) AS sum_id FROM users +users.project(users[:age].average) # => SELECT AVG(users.age) AS avg_id FROM users +users.project(users[:age].maximum) # => SELECT MAX(users.age) AS max_id FROM users +users.project(users[:age].minimum) # => SELECT MIN(users.age) AS min_id FROM users +users.project(users[:age].count) # => SELECT COUNT(users.age) FROM users +``` + +Aliasing Aggregate Functions: + +```ruby +users.project(users[:age].average.as("mean_age")) # => SELECT AVG(users.age) AS mean_age FROM users +``` + ### 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). @@ -147,6 +183,44 @@ comments_with_replies = \ This will return the first comment's reply's body. +[Common Table Expresssions(CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: + +Create a `CTE` + +```ruby +cte_table = Arel::Table.new(:cte_table) +composed_cte = Arel::Nodes::As.new(cte_table, photos.where(photos[:created_at].gt(Date.current))) +``` + +Use the created `CTE`: + +```ruby +users. + join(cte_table).on(users[:id].eq(cte_table[:user_id])). + project(users[:id], cte_table[:click].sum). + with(composed_cte) + +# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) AS sum_id FROM users INNER JOIN cte_table ON users.id = cte_table.user_id +``` + +When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: + +```ruby +photo_clicks =Arel::Nodes::SqlLiteral.new(<<-SQL + CASE WHEN condition1 THEN calculation1 + WHEN condition2 THEN calculation2 + WHEN condition3 THEN calculation3 + ELSE default_calculation END +SQL +) +photos.project(photo_clicks.as("photo_clicks")) +# => SELECT CASE WHEN condition1 THEN calculation1 + WHEN condition2 THEN calculation2 + WHEN condition3 THEN calculation3 + ELSE default_calculation END + FROM "photos" +``` + ### License Arel is released under the [MIT License](http://opensource.org/licenses/MIT). From e7461065c5dc79191f98027efbf9a65dcd84f7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 5 May 2014 02:04:35 -0300 Subject: [PATCH 1269/1492] Arel master is 6.0 --- arel.gemspec | 6 +++--- lib/arel.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index b9b2cfbace180..e6fe10a4bff58 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,14 +1,14 @@ # -*- encoding: utf-8 -*- -# stub: arel 5.0.0.20140412150050 ruby lib +# stub: arel 6.0.0.20140505020427 ruby lib Gem::Specification.new do |s| s.name = "arel" - s.version = "5.0.0.20140412150050" + s.version = "6.0.0.20140505020427" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2014-04-12" + s.date = "2014-05-05" s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] diff --git a/lib/arel.rb b/lib/arel.rb index 70b46fc48669f..1e3c51a2548ab 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '5.0.0' + VERSION = '6.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 801a1516d0a219ce530a45f0a2e65a35b04c30eb Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Mon, 5 May 2014 23:10:38 +0900 Subject: [PATCH 1270/1492] Support to add the casting node to the AST at build time Ref https://github.com/rails/arel/commit/93d72131bcc24ccb5536bec672d2dac94f8de651 --- lib/arel/visitors/oracle.rb | 2 +- test/visitors/test_oracle.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 699b52fe9ab6d..8a80faaa970af 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -17,7 +17,7 @@ def visit_Arel_Nodes_SelectStatement o, collector if o.limit && o.offset o = o.dup - limit = o.limit.expr.to_i + limit = o.limit.expr.expr offset = o.offset o.offset = nil collector << " diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index bb0fe404e8f97..9111a266cf925 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -100,7 +100,7 @@ def compile node it 'creates a different subquery when there is an offset' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(10) + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) stmt.offset = Nodes::Offset.new(10) sql = compile stmt sql.must_be_like %{ @@ -115,7 +115,7 @@ def compile node it 'is idempotent with different subquery' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(10) + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) stmt.offset = Nodes::Offset.new(10) sql = compile stmt sql2 = compile stmt From 8274bd0aaeacd59a938cb007b16755d472e68d51 Mon Sep 17 00:00:00 2001 From: Arthur Neves Date: Wed, 7 May 2014 14:37:17 -0400 Subject: [PATCH 1271/1492] Make badges more consistent [skip ci] --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 8285bbfd12931..ca9dd5a29a865 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -# 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) +# Arel [![Build Status](https://secure.travis-ci.org/rails/arel.svg?branch=master)](http://travis-ci.org/rails/arel) [![Dependency Status](https://gemnasium.com/rails/arel.svg)](https://gemnasium.com/rails/arel) * http://github.com/rails/arel From e6b585e838e475b005b73a8b1a4b4cc3edb09474 Mon Sep 17 00:00:00 2001 From: Arthur Neves Date: Wed, 7 May 2014 15:02:00 -0400 Subject: [PATCH 1272/1492] Remove old FIXME comment The comment was introducted on https://github.com/rails/arel/commit/d8de55cee197d887b478b134ec692776613bf998 , and the code has changed --- lib/arel/select_manager.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index fe0d26a16edb2..804316209c21c 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -86,9 +86,6 @@ def group *columns 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 From 97bfc5b7328e1d2bc54b4592c931a2dcee9b7926 Mon Sep 17 00:00:00 2001 From: Jordan Sexton Date: Sat, 17 May 2014 16:15:31 -0500 Subject: [PATCH 1273/1492] Added #update_manager and #delete_manager convenience methods for consistency --- lib/arel/table.rb | 8 ++++++++ test/test_table.rb | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 16ae83c284903..b87c526de5c69 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -104,6 +104,14 @@ def insert_manager InsertManager.new(@engine) end + def update_manager + UpdateManager.new(@engine) + end + + def delete_manager + DeleteManager.new(@engine) + end + def hash # Perf note: aliases, table alias and engine is excluded from the hash # aliases can have a loop back to this table breaking hashes in parent diff --git a/test/test_table.rb b/test/test_table.rb index b4c2a65fcdac2..1591d1e49c9c6 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -67,6 +67,22 @@ module Arel end end + describe 'update_manager' do + it 'should return an update manager' do + um = @relation.update_manager + assert_kind_of Arel::UpdateManager, um + assert_equal um.engine, @relation.engine + end + end + + describe 'delete_manager' do + it 'should return a delete manager' do + dm = @relation.delete_manager + assert_kind_of Arel::DeleteManager, dm + assert_equal dm.engine, @relation.engine + end + end + describe 'having' do it 'adds a having clause' do mgr = @relation.having @relation[:id].eq(10) From acdd8e4f08e230926a7174903cf905e8a415a1d4 Mon Sep 17 00:00:00 2001 From: Jordan Sexton Date: Tue, 6 May 2014 15:38:26 -0500 Subject: [PATCH 1274/1492] Return self from #distinct so it's chainable --- lib/arel/select_manager.rb | 1 + test/test_select_manager.rb | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index fe0d26a16edb2..7ec9fdba79e12 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -151,6 +151,7 @@ def distinct(value = true) else @ctx.set_quantifier = nil end + self end def order *expr diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 837486fb4612c..611bba10c205d 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1073,6 +1073,12 @@ def test_manager_stores_bind_values manager.distinct(false) manager.ast.cores.last.set_quantifier.must_equal nil end + + it "chains" do + manager = Arel::SelectManager.new Table.engine + manager.distinct.must_equal manager + manager.distinct(false).must_equal manager + end end end end From dc2c2c3e95102124bb6157b8f66649e6546cbdda Mon Sep 17 00:00:00 2001 From: Brian Hahn Date: Sun, 12 May 2013 10:09:07 -0700 Subject: [PATCH 1275/1492] convenience method for outer_join --- lib/arel/select_manager.rb | 4 ++++ lib/arel/table.rb | 4 ++++ test/test_select_manager.rb | 22 ++++++++++++++++++++++ test/test_table.rb | 14 ++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 804316209c21c..0bcffba680c9f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -114,6 +114,10 @@ def join relation, klass = Nodes::InnerJoin self end + def outer_join relation + join(relation, Nodes::OuterJoin) + end + def having *exprs @ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having)) self diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 16ae83c284903..3866637bd2e02 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -64,6 +64,10 @@ def join relation, klass = Nodes::InnerJoin from(self).join(relation, klass) end + def outer_join relation + join(relation, Nodes::OuterJoin) + end + def group *columns from(self).group(*columns) end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 837486fb4612c..5662bc8990b43 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -579,6 +579,28 @@ def test_manager_stores_bind_values end end + describe 'outer join' do + it 'responds to join' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new Table.engine + + manager.from left + manager.outer_join(right).on(predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + LEFT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + + it 'noops on nil' do + manager = Arel::SelectManager.new Table.engine + manager.outer_join(nil).must_equal manager + end + end + describe 'joins' do it 'returns join sql' do table = Table.new :users diff --git a/test/test_table.rb b/test/test_table.rb index b4c2a65fcdac2..286ad1016788e 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -96,6 +96,20 @@ module Arel } end end + + describe 'join' do + it 'creates an outer join' do + right = @relation.alias + predicate = @relation[:id].eq(right[:id]) + mgr = @relation.outer_join(right).on(predicate) + + mgr.to_sql.must_be_like %{ + SELECT FROM "users" + LEFT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + end end describe 'group' do From 63642a913fd0754baf8afe1a472b6a36c4045f73 Mon Sep 17 00:00:00 2001 From: Adam Malcontenti-Wilson Date: Mon, 19 May 2014 12:13:51 +1000 Subject: [PATCH 1276/1492] Correct whitespace in README --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index ca9dd5a29a865..75b0b3ee0bee4 100644 --- a/README.markdown +++ b/README.markdown @@ -206,7 +206,7 @@ users. When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: ```ruby -photo_clicks =Arel::Nodes::SqlLiteral.new(<<-SQL +photo_clicks = Arel::Nodes::SqlLiteral.new(<<-SQL CASE WHEN condition1 THEN calculation1 WHEN condition2 THEN calculation2 WHEN condition3 THEN calculation3 From edf0c2914cbc980af67472bed69e072e624d0956 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 25 May 2014 21:46:47 +0530 Subject: [PATCH 1277/1492] Fix typo `delegte` => `delegate` --- lib/arel/visitors/bind_substitute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/bind_substitute.rb b/lib/arel/visitors/bind_substitute.rb index 0503a9c9868fa..ce0fb5c924602 100644 --- a/lib/arel/visitors/bind_substitute.rb +++ b/lib/arel/visitors/bind_substitute.rb @@ -1,7 +1,7 @@ module Arel module Visitors class BindSubstitute - def initialize delegte + def initialize delegate @delegate = delegate end end From 1e2c01db15ceecd97b53b32a954ad8bf164b397a Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 25 May 2014 21:57:57 +0530 Subject: [PATCH 1278/1492] Fix warning form bind collector test --- test/collectors/test_bind_collector.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb index 036d8f05fe015..60532f061c031 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_bind_collector.rb @@ -49,7 +49,7 @@ def test_substitute_binds offsets = values.map.with_index { |v,i| [v,i] - }.find_all { |(v,i)| Nodes::BindParam === v }.map(&:last) + }.find_all { |(v,_)| Nodes::BindParam === v }.map(&:last) list = collector.substitute_binds ["hello", "world"] assert_equal "hello", list[offsets[0]] From e7f0cbbeea28718c8ff2b588cba20ccc298347bf Mon Sep 17 00:00:00 2001 From: Brock Trappitt Date: Mon, 26 May 2014 20:22:33 +0800 Subject: [PATCH 1279/1492] Fixing method signature for unsupported visits in the ToSQL Visitor --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 22f7943ab918b..28c4bd8bfa1c6 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -715,7 +715,7 @@ def quoted o, a quote(o, column_for(a)) end - def unsupported o + def unsupported o, collector raise "unsupported: #{o.class.name}" end From 416ad003716bcc883c319ec30644bab8a3cf52c7 Mon Sep 17 00:00:00 2001 From: Sergey Alekseev Date: Mon, 26 May 2014 16:27:57 +0300 Subject: [PATCH 1280/1492] Wrap nested Nodes::Grouping in brackets only once --- lib/arel/visitors/to_sql.rb | 8 ++++++-- test/visitors/test_to_sql.rb | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 22f7943ab918b..264521f4c6c3c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -429,8 +429,12 @@ def visit_Arel_Nodes_Lock o, collector end def visit_Arel_Nodes_Grouping o, collector - collector << "(" - visit(o.expr, collector) << ")" + if o.expr.is_a? Nodes::Grouping + visit(o.expr, collector) + else + collector << "(" + visit(o.expr, collector) << ")" + end end def visit_Arel_SelectManager o, collector diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 05e75b5e0d9bd..738bbe96263cd 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -131,6 +131,13 @@ def dispatch end end + describe 'Nodes::Grouping' do + it 'wraps nested groupings in brackets only once' do + sql = compile Nodes::Grouping.new(Nodes::Grouping.new(Nodes.build_quoted('foo'))) + sql.must_equal "('foo')" + end + end + describe 'Nodes::NotEqual' do it 'should handle false' do val = Nodes.build_quoted(false, @table[:active]) From c28e9efde7e0c384b5f959e6eb48fa47d073227e Mon Sep 17 00:00:00 2001 From: Brock Trappitt Date: Tue, 27 May 2014 09:16:28 +0800 Subject: [PATCH 1281/1492] Test which checks the error being raised by #unsupported in ToSql Visitor --- test/visitors/test_to_sql.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 05e75b5e0d9bd..5d5a351737922 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -247,6 +247,12 @@ def dispatch compile(Nodes.build_quoted(nil)).must_be_like "NULL" end + it "unsupported input should not raise ArgumentError" do + assert_raises(RuntimeError) do + compile(nil) + end + end + it "should visit_Arel_SelectManager, which is a subquery" do mgr = Table.new(:foo).project(:bar) compile(mgr).must_be_like '(SELECT bar FROM "foo")' From b1bf89cb77b05e9c38fc922e796caa47daa3af86 Mon Sep 17 00:00:00 2001 From: Brock Trappitt Date: Wed, 28 May 2014 08:28:54 +0800 Subject: [PATCH 1282/1492] Asserting on error message --- test/visitors/test_to_sql.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 5d5a351737922..65d36bc0048b6 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -248,9 +248,8 @@ def dispatch end it "unsupported input should not raise ArgumentError" do - assert_raises(RuntimeError) do - compile(nil) - end + error = assert_raises(RuntimeError) { compile(nil) } + assert_match /\Aunsupported/, error.message end it "should visit_Arel_SelectManager, which is a subquery" do From 75de31a7f315512ade55b7d376fda8a7d5d393ff Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sat, 31 May 2014 23:22:51 +0530 Subject: [PATCH 1283/1492] - Fix ambiguous argument warning - Fix typo: `test_opertaion_ordering` => `test_operation_ordering` --- test/nodes/test_infix_operation.rb | 2 +- test/visitors/test_to_sql.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nodes/test_infix_operation.rb b/test/nodes/test_infix_operation.rb index bec226e395b35..40616024e5988 100644 --- a/test/nodes/test_infix_operation.rb +++ b/test/nodes/test_infix_operation.rb @@ -18,7 +18,7 @@ def test_operation_alias assert_equal 'zomg', aliaz.right end - def test_opertaion_ordering + def test_operation_ordering operation = InfixOperation.new :+, 1, 2 ordering = operation.desc assert_kind_of Descending, ordering diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 65d36bc0048b6..a88c8889080be 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -249,7 +249,7 @@ def dispatch it "unsupported input should not raise ArgumentError" do error = assert_raises(RuntimeError) { compile(nil) } - assert_match /\Aunsupported/, error.message + assert_match(/\Aunsupported/, error.message) end it "should visit_Arel_SelectManager, which is a subquery" do From 8574e97593a8b2b04dce35b9d7519c1c74ff58d9 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 1 Jun 2014 17:02:16 +0530 Subject: [PATCH 1284/1492] - Remove four year old deprecation --- lib/arel/nodes/and.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb index 62e8ef6f11aad..8e1afda709014 100644 --- a/lib/arel/nodes/and.rb +++ b/lib/arel/nodes/and.rb @@ -3,12 +3,8 @@ module Nodes class And < Arel::Nodes::Node attr_reader :children - def initialize children, right = nil + def initialize children super() - unless Array === children - warn "(#{caller.first}) AND nodes should be created with a list" - children = [children, right] - end @children = children end From a5cac2ab52570a2d17a28d725d94020d32f36417 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 1 Jun 2014 18:55:14 +0530 Subject: [PATCH 1285/1492] Arel doesn't depend on activesupport and doesn't have "String#blank?" Remove usage of `.blank?` to match empty strings with a regular expression instead. --- lib/arel/select_manager.rb | 2 +- lib/arel/table.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f1dde6403a27b..4a652f2c9c52f 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -106,7 +106,7 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral - raise if relation.blank? + raise if relation.empty? klass = Nodes::StringJoin end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 545e73e3ae698..01d4561ff1b9a 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -57,7 +57,7 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral - raise if relation.blank? + raise if relation.empty? klass = Nodes::StringJoin end From e5772a1f56568547ca72ad053cb812cd22dbd466 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 1 Jun 2014 22:19:11 +0530 Subject: [PATCH 1286/1492] Remove unused values variable --- lib/arel/visitors/to_sql.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 28c4bd8bfa1c6..a1dee43cab4d2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -103,9 +103,7 @@ def visit_Arel_Nodes_UpdateStatement o, collector collector << "UPDATE " collector = visit o.relation, collector - values = false unless o.values.empty? - values = true collector << " SET " collector = inject_join o.values, collector, ", " end From 493cc80fd5f59ba213d4ce54b707c16604e558b8 Mon Sep 17 00:00:00 2001 From: Noah Lindner Date: Sun, 1 Jun 2014 15:57:45 -0700 Subject: [PATCH 1287/1492] Cleaned up some edge cases with infinity, the logic seems more intuitive now --- lib/arel/predications.rb | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 2ef48375482f4..78cd87d4306c1 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -29,14 +29,16 @@ def in 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, [] + if other.begin == -Float::INFINITY + if other.end == Float::INFINITY + Nodes::NotIn.new self, [] + elsif other.exclude_end? + Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) + else + Nodes::LessThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) + end elsif other.end == Float::INFINITY Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self)) - elsif other.begin == -Float::INFINITY && other.exclude_end? - Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) - elsif other.begin == -Float::INFINITY - Nodes::LessThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) elsif other.exclude_end? left = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self)) right = Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) @@ -64,21 +66,23 @@ def not_in 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 + if other.begin == -Float::INFINITY # The range begins with negative infinity + if other.end == Float::INFINITY + Nodes::In.new self, [] # The range is infinite, so return an empty range + elsif other.exclude_end? + Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) + else + Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) + end + elsif other.end == Float::INFINITY Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) - elsif other.begin == -Float::INFINITY && other.exclude_end? - Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) - elsif other.begin == -Float::INFINITY - Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) - elsif other.exclude_end? - left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) - right = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) - Nodes::Or.new left, right else left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) - right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) + if other.exclude_end? + right = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) + else + right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) + end Nodes::Or.new left, right end when Array From ed7ef6baa42434aa4ca52679caf0636754cb27c5 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Fri, 6 Jun 2014 21:53:08 +0530 Subject: [PATCH 1288/1492] - Fixes to readme grammar - Fixed example and corresponding out interpretation [ci-skip] --- README.markdown | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.markdown b/README.markdown index 75b0b3ee0bee4..f12aa674983a0 100644 --- a/README.markdown +++ b/README.markdown @@ -160,7 +160,7 @@ products. #### 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: +Where Arel really shines is 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: ```ruby comments = Arel::Table.new(:comments) @@ -172,16 +172,17 @@ And this table has the following attributes: # [:id, :body, :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: +The `parent_id` column is a foreign key from the `comments` table to itself. +Joining a table to itself requires aliasing in SQL. This aliasing can be handled from Arel as below: ```ruby 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 + comments.join(replies).on(replies[:parent_id].eq(comments[:id])).where(comments[:id].eq(1)) +# => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id AND comments.id = 1 ``` -This will return the first comment's reply's body. +This will return the reply for the first comment. [Common Table Expresssions(CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: From 1171622c24109bb0552e354562a4741c27b08ed5 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sat, 7 Jun 2014 12:01:12 +0530 Subject: [PATCH 1289/1492] rm empty spec which is covered by other specs --- test/attributes/test_attribute.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index e53b32d0ac399..145da989680ce 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -550,8 +550,6 @@ module Attributes 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 From 19af353a8bbfb30898f1a32c3f5e39d557d34d65 Mon Sep 17 00:00:00 2001 From: Jiri Pospisil Date: Thu, 12 Jun 2014 17:57:54 +0200 Subject: [PATCH 1290/1492] Make sure visit_Arel_Nodes_With works with collectors --- lib/arel/visitors/to_sql.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a1dee43cab4d2..7f74ebb402c05 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -298,8 +298,9 @@ def visit_Arel_Nodes_DistinctOn o, collector raise NotImplementedError, 'DISTINCT ON not implemented for this db' end - def visit_Arel_Nodes_With o - "WITH #{o.children.map { |x| visit x }.join(', ')}" + def visit_Arel_Nodes_With o, collector + collector << "WITH " + inject_join o.children, collector, ', ' end def visit_Arel_Nodes_WithRecursive o, collector From b4bec045a8bb89c2a2cfc06a8071b34a97723de7 Mon Sep 17 00:00:00 2001 From: Jiri Pospisil Date: Thu, 12 Jun 2014 17:59:10 +0200 Subject: [PATCH 1291/1492] Add test for non-recursive WITH statement --- test/test_select_manager.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 09608ea71ed66..4678901bb4a58 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -330,6 +330,20 @@ def test_manager_stores_bind_values end describe 'with' do + it 'should support basic WITH' do + users = Table.new(:users) + users_top = Table.new(:users_top) + comments = Table.new(:comments) + + top = users.project(users[:id]).where(users[:karma].gt(100)) + users_as = Arel::Nodes::As.new(users_top, top) + select_manager = comments.project(Arel.star).with(users_as) + .where(comments[:author_id].in(users_top.project(users_top[:id]))) + + select_manager.to_sql.must_be_like %{ + WITH "users_top" AS (SELECT "users"."id" FROM "users" WHERE "users"."karma" > 100) SELECT * FROM "comments" WHERE "comments"."author_id" IN (SELECT "users_top"."id" FROM "users_top") + } + end it "should support WITH RECURSIVE" do comments = Table.new(:comments) From 0ee2c81e486e2b7155db75c6eb75fbd918e34386 Mon Sep 17 00:00:00 2001 From: Jiri Pospisil Date: Thu, 12 Jun 2014 18:32:26 +0200 Subject: [PATCH 1292/1492] Make sure Arel::SelectManager is not mistaken for an attribute --- lib/arel/nodes.rb | 2 +- test/attributes/test_attribute.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index a68e3279832b0..59cfc04dc2633 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -78,7 +78,7 @@ class Quoted < Arel::Nodes::Unary # :nodoc: def self.build_quoted other, attribute = nil case other - when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Nodes::SelectStatement, Arel::Table, Arel::Nodes::BindParam + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Nodes::SelectStatement, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager other else case attribute diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 145da989680ce..38ee189a46fbe 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -74,6 +74,17 @@ module Attributes SELECT "users"."id" FROM "users" WHERE "users"."id" > 10 } end + + it 'should handle comparing with a subquery' do + users = Table.new(:users) + + avg = users.project(users[:karma].average) + mgr = users.project(Arel.star).where(users[:karma].gt(avg)) + + mgr.to_sql.must_be_like %{ + SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") AS avg_id FROM "users") + } + end end describe '#gt_any' do From 99d6646e8ad9499ee54c703d21e6c9c5fb233965 Mon Sep 17 00:00:00 2001 From: Jiri Pospisil Date: Thu, 12 Jun 2014 18:34:14 +0200 Subject: [PATCH 1293/1492] No need to check for SelectStatement as it's a descendant of Node --- lib/arel/nodes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 59cfc04dc2633..c6bde8c3ccc19 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -78,7 +78,7 @@ class Quoted < Arel::Nodes::Unary # :nodoc: def self.build_quoted other, attribute = nil case other - when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Nodes::SelectStatement, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager other else case attribute From 0644f9f3a0878193ac9ba3720d406da97b789a9d Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 15 Jun 2014 01:08:38 +0530 Subject: [PATCH 1294/1492] Rename ambiguous test name to what it actually tests --- test/test_select_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 4678901bb4a58..59b000d654231 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -140,7 +140,7 @@ def test_manager_stores_bind_values mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg } end - it 'converts to sqlliterals' do + it 'converts to sqlliterals with multiple items' do table = Table.new :users right = table.alias mgr = table.from table From 0a7e0ef210e30e5f7a69ffe469faf62bdf57bd5c Mon Sep 17 00:00:00 2001 From: Jiri Pospisil Date: Sat, 14 Jun 2014 23:23:36 +0200 Subject: [PATCH 1295/1492] Collectors: Introduce PlainString and make use of it in SQLString --- lib/arel/collectors/plain_string.rb | 18 ++++++++++++++++++ lib/arel/collectors/sql_string.rb | 17 +++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 lib/arel/collectors/plain_string.rb diff --git a/lib/arel/collectors/plain_string.rb b/lib/arel/collectors/plain_string.rb new file mode 100644 index 0000000000000..2505bc376efa9 --- /dev/null +++ b/lib/arel/collectors/plain_string.rb @@ -0,0 +1,18 @@ +module Arel + module Collectors + class PlainString + def initialize + @str = '' + end + + def value + @str + end + + def << str + @str << str + self + end + end + end +end diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index 45001bb50789a..8ca89ca7bd429 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -1,21 +1,10 @@ # encoding: utf-8 +require 'arel/collectors/plain_string' + module Arel module Collectors - class SQLString - def initialize - @str = '' - end - - def value - @str - end - - def << str - @str << str - self - end - + class SQLString < PlainString def add_bind bind self << bind.to_s self From fcd11dcb99d69d40ff60b56bcd7330264128ecfd Mon Sep 17 00:00:00 2001 From: Jiri Pospisil Date: Sat, 14 Jun 2014 23:33:05 +0200 Subject: [PATCH 1296/1492] Modify Visitors::Dot's API to use collectors --- lib/arel/tree_manager.rb | 4 +++- lib/arel/visitors/dot.rb | 4 ++-- test/visitors/test_dot.rb | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 87887800d05fd..8bff97af78187 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -15,7 +15,9 @@ def initialize engine end def to_dot - Visitors::Dot.new.accept @ast + collector = Arel::Collectors::PlainString.new + collector = Visitors::Dot.new.accept @ast, collector + collector.value end def visitor diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index ba35223ac92b5..d96cf7a6a007c 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -22,9 +22,9 @@ def initialize @seen = {} end - def accept object + def accept object, collector visit object - to_dot + collector << to_dot end private diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index ee7fc7886c1d5..7763350f5ccbf 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -17,13 +17,13 @@ def setup ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do op = klass.new(:a, "z") - @visitor.accept op + @visitor.accept op, Collectors::PlainString.new end end def test_named_function func = Nodes::NamedFunction.new 'omg', 'omg' - @visitor.accept func + @visitor.accept func, Collectors::PlainString.new end # unary ops @@ -41,7 +41,7 @@ def test_named_function ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do op = klass.new(:a) - @visitor.accept op + @visitor.accept op, Collectors::PlainString.new end end @@ -68,7 +68,7 @@ def test_named_function ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do binary = klass.new(:a, :b) - @visitor.accept binary + @visitor.accept binary, Collectors::PlainString.new end end end From 43d1497cba60e2c788f0494933f92859f72eae3c Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 15 Jun 2014 13:47:53 +0530 Subject: [PATCH 1297/1492] - Stop passing redundant `:engine => Table.engine` to `Table#new` - Remove redundant `ast` variable creation - Rename similar join tests name to what they actually test - Move "joins itself" test to "joins" describe instead of defining describe block twice - Move update manager statement tests in logical order - Move `project` tests in logical order --- test/test_select_manager.rb | 103 ++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 59b000d654231..8880e325e42c3 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -152,7 +152,7 @@ def test_manager_stores_bind_values describe 'clone' do it 'creates new cores' do - table = Table.new :users, :engine => Table.engine, :as => 'foo' + table = Table.new :users, :as => 'foo' mgr = table.from table m2 = mgr.clone m2.project "foo" @@ -160,7 +160,7 @@ def test_manager_stores_bind_values end it 'makes updates to the correct copy' do - table = Table.new :users, :engine => Table.engine, :as => 'foo' + table = Table.new :users, :as => 'foo' mgr = table.from table m2 = mgr.clone m3 = m2.clone @@ -172,7 +172,7 @@ def test_manager_stores_bind_values describe 'initialize' do it 'uses alias in sql' do - table = Table.new :users, :engine => Table.engine, :as => 'foo' + table = Table.new :users, :as => 'foo' mgr = table.from table mgr.skip 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 } @@ -382,8 +382,7 @@ def test_manager_stores_bind_values it 'should return the ast' do table = Table.new :users mgr = table.from table - ast = mgr.ast - assert ast + assert mgr.ast end it 'should allow orders to work when the ast is grepped' do @@ -532,7 +531,7 @@ def test_manager_stores_bind_values assert_equal 'bar', join.right end - it 'should create join nodes with a klass' do + it 'should create join nodes with a full outer join klass' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin assert_kind_of Arel::Nodes::FullOuterJoin, join @@ -540,7 +539,7 @@ def test_manager_stores_bind_values assert_equal 'bar', join.right end - it 'should create join nodes with a klass' do + it 'should create join nodes with a outer join klass' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin assert_kind_of Arel::Nodes::OuterJoin, join @@ -548,7 +547,7 @@ def test_manager_stores_bind_values assert_equal 'bar', join.right end - it 'should create join nodes with a klass' do + it 'should create join nodes with a right outer join klass' do relation = Arel::SelectManager.new Table.engine join = relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin assert_kind_of Arel::Nodes::RightOuterJoin, join @@ -616,7 +615,8 @@ def test_manager_stores_bind_values end describe 'joins' do - it 'returns join sql' do + + it 'returns inner join sql' do table = Table.new :users aliaz = table.alias manager = Arel::SelectManager.new Table.engine @@ -651,6 +651,22 @@ def test_manager_stores_bind_values } end + it "joins itself" do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + + mgr = left.join(right) + mgr.project Nodes::SqlLiteral.new('*') + mgr.on(predicate).must_equal mgr + + mgr.to_sql.must_be_like %{ + SELECT * FROM "users" + INNER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + it 'returns string join sql' do manager = Arel::SelectManager.new Table.engine manager.from Nodes::StringJoin.new(Nodes.build_quoted('hello')) @@ -892,6 +908,27 @@ def test_manager_stores_bind_values end describe 'update' do + + it 'creates an update statement' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + + stmt.to_sql.must_be_like %{ + UPDATE "users" SET "id" = 1 + } + end + + it 'takes a string' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + + stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } + end + it 'copies limits' do table = Table.new :users manager = Arel::SelectManager.new Table.engine @@ -920,15 +957,6 @@ def test_manager_stores_bind_values } end - it 'takes a string' do - table = Table.new :users - manager = Arel::SelectManager.new Table.engine - manager.from table - stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) - - stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } - end - it 'copies where clauses' do table = Table.new :users manager = Arel::SelectManager.new Table.engine @@ -954,19 +982,15 @@ def test_manager_stores_bind_values } end - it 'executes an update statement' do - table = Table.new :users - manager = Arel::SelectManager.new Table.engine - manager.from table - stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) - - stmt.to_sql.must_be_like %{ - UPDATE "users" SET "id" = 1 - } - end end describe 'project' do + it "takes sql literals" do + manager = Arel::SelectManager.new Table.engine + manager.project Nodes::SqlLiteral.new '*' + manager.to_sql.must_be_like %{ SELECT * } + end + it 'takes multiple args' do manager = Arel::SelectManager.new Table.engine manager.project Nodes::SqlLiteral.new('foo'), @@ -980,11 +1004,6 @@ def test_manager_stores_bind_values 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 @@ -1056,24 +1075,6 @@ def test_manager_stores_bind_values 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 From 54f412ae8ce5bb291de4aedb9af69a354b54d7b1 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 15 Jun 2014 14:22:06 +0530 Subject: [PATCH 1298/1492] - Test noop when passing empty list to `insert` - Rename into test to indicate it accepts table and chains on it - Rename "combo" test to what it actually tests --- test/test_insert_manager.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 4e82ca34c093e..9cfd01262b3e3 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -78,14 +78,19 @@ module Arel } end - it 'takes an empty list' do + it 'noop for empty list' do + table = Table.new(:users) manager = Arel::InsertManager.new Table.engine + manager.insert [[table[:id], 1]] manager.insert [] + manager.to_sql.must_be_like %{ + INSERT INTO "users" ("id") VALUES (1) + } end end describe 'into' do - it 'takes an engine' do + it 'takes a Table and chains' do manager = Arel::InsertManager.new Table.engine manager.into(Table.new(:users)).must_equal manager end @@ -126,7 +131,7 @@ module Arel end describe "combo" do - it "puts shit together" do + it "combines columns and values list in order" do table = Table.new :users manager = Arel::InsertManager.new Table.engine manager.into table From 69e9be95ac233eb7b446920bb49399277ea594ce Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Tue, 19 Feb 2013 22:27:17 +0100 Subject: [PATCH 1299/1492] Windowing support for PARTITION BY clause. --- lib/arel/nodes/window.rb | 15 +++++++++++++-- lib/arel/visitors/dot.rb | 2 ++ lib/arel/visitors/to_sql.rb | 6 ++++++ test/nodes/test_window.rb | 12 +++++++++--- test/test_select_manager.rb | 30 ++++++++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index 60259e8c05a6d..6578a414d280f 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -1,10 +1,12 @@ module Arel module Nodes class Window < Arel::Nodes::Node - attr_accessor :orders, :framing + attr_accessor :orders, :framing, :partitions def initialize @orders = [] + @partitions = [] + @framing = nil end def order *expr @@ -15,6 +17,14 @@ def order *expr self end + def partition *expr + # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically + @partitions.concat expr.map { |x| + String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x + } + self + end + def frame(expr) @framing = expr end @@ -39,7 +49,8 @@ def hash def eql? other self.class == other.class && self.orders == other.orders && - self.framing == other.framing + self.framing == other.framing && + self.partitions == other.partitions end alias :== :eql? end diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index d96cf7a6a007c..f0cefeabd75c6 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -82,12 +82,14 @@ def unary o alias :visit_Arel_Nodes_Range :unary def window o + visit_edge o, "partitions" visit_edge o, "orders" visit_edge o, "framing" end alias :visit_Arel_Nodes_Window :window def named_window o + visit_edge o, "partitions" visit_edge o, "orders" visit_edge o, "framing" visit_edge o, "name" diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7f74ebb402c05..8a5e1dbf25e8d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -336,6 +336,12 @@ def visit_Arel_Nodes_NamedWindow o, collector def visit_Arel_Nodes_Window o, collector collector << "(" + + if o.partitions.any? + collector << "PARTITION BY " + collector = inject_join o.partitions, collector, ", " + end + if o.orders.any? collector << "ORDER BY " collector = inject_join o.orders, collector, ", " diff --git a/test/nodes/test_window.rb b/test/nodes/test_window.rb index f09d16e4412d6..9ec42be59fb9c 100644 --- a/test/nodes/test_window.rb +++ b/test/nodes/test_window.rb @@ -7,9 +7,11 @@ module Nodes it 'is equal with equal ivars' do window1 = Window.new window1.orders = [1, 2] + window1.partitions = [1] window1.frame 3 window2 = Window.new window2.orders = [1, 2] + window2.partitions = [1] window2.frame 3 array = [window1, window2] assert_equal 1, array.uniq.size @@ -18,9 +20,11 @@ module Nodes it 'is not equal with different ivars' do window1 = Window.new window1.orders = [1, 2] + window1.partitions = [1] window1.frame 3 window2 = Window.new window2.orders = [1, 2] + window1.partitions = [1] window2.frame 4 array = [window1, window2] assert_equal 2, array.uniq.size @@ -33,9 +37,11 @@ module Nodes it 'is equal with equal ivars' do window1 = NamedWindow.new 'foo' window1.orders = [1, 2] + window1.partitions = [1] window1.frame 3 window2 = NamedWindow.new 'foo' window2.orders = [1, 2] + window2.partitions = [1] window2.frame 3 array = [window1, window2] assert_equal 1, array.uniq.size @@ -44,9 +50,11 @@ module Nodes it 'is not equal with different ivars' do window1 = NamedWindow.new 'foo' window1.orders = [1, 2] + window1.partitions = [1] window1.frame 3 window2 = NamedWindow.new 'bar' window2.orders = [1, 2] + window2.partitions = [1] window2.frame 3 array = [window1, window2] assert_equal 2, array.uniq.size @@ -68,6 +76,4 @@ module Nodes end end end -end - - +end \ No newline at end of file diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 4678901bb4a58..8840d40d8f5d8 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -716,6 +716,36 @@ def test_manager_stores_bind_values } end + it 'takes an order with multiple columns' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').order(table['foo'].asc, table['bar'].desc) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (ORDER BY "users"."foo" ASC, "users"."bar" DESC) + } + end + + it 'takes a partition' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').partition(table['bar']) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."bar") + } + end + + it 'takes a partition with multiple columns' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').partition(table['bar'], table['baz']) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."bar", "users"."baz") + } + end + it 'takes a rows frame, unbounded preceding' do table = Table.new :users manager = Arel::SelectManager.new Table.engine From d9347943a22076911155d9a56d9a3ef6e022994b Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Tue, 19 Feb 2013 22:28:16 +0100 Subject: [PATCH 1300/1492] Windowing: Calling #rows or #range should assign framing only once. --- lib/arel/nodes/window.rb | 12 ++++++++++-- lib/arel/visitors/to_sql.rb | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index 6578a414d280f..fee8eeff7a9ae 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -30,11 +30,19 @@ def frame(expr) end def rows(expr = nil) - frame(Rows.new(expr)) + if @framing + Rows.new(expr) + else + frame(Rows.new(expr)) + end end def range(expr = nil) - frame(Range.new(expr)) + if @framing + Range.new(expr) + else + frame(Range.new(expr)) + end end def initialize_copy other diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 8a5e1dbf25e8d..8c63070084de9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -343,11 +343,13 @@ def visit_Arel_Nodes_Window o, collector end if o.orders.any? + collector << ' ' if o.partitions.any? collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end if o.framing + collector << ' ' if o.partitions.any? or o.orders.any? collector = visit o.framing, collector end From 4a72415555de19ca33c8ea16ee9ba26d1b73b078 Mon Sep 17 00:00:00 2001 From: Alexander Staubo Date: Sun, 22 Jun 2014 19:13:37 -0400 Subject: [PATCH 1301/1492] Add test for window + partition + order. --- test/test_select_manager.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 8840d40d8f5d8..0b9756709d0be 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -736,6 +736,17 @@ def test_manager_stores_bind_values } end + it 'takes a partition and an order' do + table = Table.new :users + manager = Arel::SelectManager.new Table.engine + manager.from table + manager.window('a_window').partition(table['foo']).order(table['foo'].asc) + manager.to_sql.must_be_like %{ + SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."foo" + ORDER BY "users"."foo" ASC) + } + end + it 'takes a partition with multiple columns' do table = Table.new :users manager = Arel::SelectManager.new Table.engine From bb8416d0943f3e797d572d127a2d74103761d947 Mon Sep 17 00:00:00 2001 From: Joshua Cody Date: Sat, 26 Jul 2014 22:27:31 -0500 Subject: [PATCH 1302/1492] Allow for alias omission in aggregate expressions --- lib/arel/expressions.rb | 23 +++++++++++++++-------- test/test_expressions.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 test/test_expressions.rb diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index fa18f15b6770b..717cf412ee071 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -4,24 +4,31 @@ def count distinct = false Nodes::Count.new [self], distinct end - def sum - Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id') + def sum(alias_as = "sum_id") + Nodes::Sum.new [self], node_alias(alias_as) end - def maximum - Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') + def maximum(alias_as = "max_id") + Nodes::Max.new [self], node_alias(alias_as) end - def minimum - Nodes::Min.new [self], Nodes::SqlLiteral.new('min_id') + def minimum(alias_as = "min_id") + Nodes::Min.new [self], node_alias(alias_as) end - def average - Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') + def average(alias_as = "avg_id") + Nodes::Avg.new [self], node_alias(alias_as) end def extract field Nodes::Extract.new [self], field end + + private + + def node_alias(alias_as) + alias_as.nil? ? nil : Nodes::SqlLiteral.new(alias_as) + end + end end diff --git a/test/test_expressions.rb b/test/test_expressions.rb new file mode 100644 index 0000000000000..d061bbc335aad --- /dev/null +++ b/test/test_expressions.rb @@ -0,0 +1,29 @@ +require 'helper' + +module Arel + describe "Expressions" do + before do + @table = Table.new(:users) + end + + describe "average" do + it "aliases the average as avg_id by default" do + @table[:score].average.to_sql.must_be_like %{ + AVG("users"."score") AS avg_id + } + end + + it "aliases the average as another string" do + @table[:score].average("my_alias").to_sql.must_be_like %{ + AVG("users"."score") AS my_alias + } + end + + it "omits the alias if nil" do + @table[:score].average(nil).to_sql.must_be_like %{ + AVG("users"."score") + } + end + end + end +end From 712c002af51700d128eb45996687600bb20c75a7 Mon Sep 17 00:00:00 2001 From: Joshua Cody Date: Thu, 31 Jul 2014 07:49:57 -0500 Subject: [PATCH 1303/1492] Remove default aliases from aggregate functions --- README.markdown | 10 +++++----- lib/arel/expressions.rb | 22 ++++++++-------------- test/attributes/test_attribute.rb | 17 +++++++---------- test/test_expressions.rb | 29 ----------------------------- 4 files changed, 20 insertions(+), 58 deletions(-) delete mode 100644 test/test_expressions.rb diff --git a/README.markdown b/README.markdown index f12aa674983a0..1776330da85c3 100644 --- a/README.markdown +++ b/README.markdown @@ -120,10 +120,10 @@ Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: ```ruby photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 -users.project(users[:age].sum) # => SELECT SUM(users.age) AS sum_id FROM users -users.project(users[:age].average) # => SELECT AVG(users.age) AS avg_id FROM users -users.project(users[:age].maximum) # => SELECT MAX(users.age) AS max_id FROM users -users.project(users[:age].minimum) # => SELECT MIN(users.age) AS min_id FROM users +users.project(users[:age].sum) # => SELECT SUM(users.age) FROM users +users.project(users[:age].average) # => SELECT AVG(users.age) FROM users +users.project(users[:age].maximum) # => SELECT MAX(users.age) FROM users +users.project(users[:age].minimum) # => SELECT MIN(users.age) FROM users users.project(users[:age].count) # => SELECT COUNT(users.age) FROM users ``` @@ -201,7 +201,7 @@ users. project(users[:id], cte_table[:click].sum). with(composed_cte) -# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) AS sum_id FROM users INNER JOIN cte_table ON users.id = cte_table.user_id +# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) FROM users INNER JOIN cte_table ON users.id = cte_table.user_id ``` When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index 717cf412ee071..d40268c2925ad 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -4,31 +4,25 @@ def count distinct = false Nodes::Count.new [self], distinct end - def sum(alias_as = "sum_id") - Nodes::Sum.new [self], node_alias(alias_as) + def sum + Nodes::Sum.new [self] end - def maximum(alias_as = "max_id") - Nodes::Max.new [self], node_alias(alias_as) + def maximum + Nodes::Max.new [self] end - def minimum(alias_as = "min_id") - Nodes::Min.new [self], node_alias(alias_as) + def minimum + Nodes::Min.new [self] end - def average(alias_as = "avg_id") - Nodes::Avg.new [self], node_alias(alias_as) + def average + Nodes::Avg.new [self] end def extract field Nodes::Extract.new [self], field end - private - - def node_alias(alias_as) - alias_as.nil? ? nil : Nodes::SqlLiteral.new(alias_as) - end - end end diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 38ee189a46fbe..f8886297a344e 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -82,7 +82,7 @@ module Attributes mgr = users.project(Arel.star).where(users[:karma].gt(avg)) mgr.to_sql.must_be_like %{ - SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") AS avg_id FROM "users") + SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") FROM "users") } end end @@ -269,12 +269,11 @@ module Attributes 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 + it 'should generate the proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].average mgr.to_sql.must_be_like %{ - SELECT AVG("users"."id") AS avg_id + SELECT AVG("users"."id") FROM "users" } end @@ -286,12 +285,11 @@ module Attributes 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 + it 'should generate the proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].maximum mgr.to_sql.must_be_like %{ - SELECT MAX("users"."id") AS max_id + SELECT MAX("users"."id") FROM "users" } end @@ -310,12 +308,11 @@ module Attributes 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 + it 'should generate the proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].sum mgr.to_sql.must_be_like %{ - SELECT SUM("users"."id") AS sum_id + SELECT SUM("users"."id") FROM "users" } end diff --git a/test/test_expressions.rb b/test/test_expressions.rb deleted file mode 100644 index d061bbc335aad..0000000000000 --- a/test/test_expressions.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'helper' - -module Arel - describe "Expressions" do - before do - @table = Table.new(:users) - end - - describe "average" do - it "aliases the average as avg_id by default" do - @table[:score].average.to_sql.must_be_like %{ - AVG("users"."score") AS avg_id - } - end - - it "aliases the average as another string" do - @table[:score].average("my_alias").to_sql.must_be_like %{ - AVG("users"."score") AS my_alias - } - end - - it "omits the alias if nil" do - @table[:score].average(nil).to_sql.must_be_like %{ - AVG("users"."score") - } - end - end - end -end From c93f6bd8abc800ba31950f719f7c1006062051ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sun, 17 Aug 2014 22:45:41 -0300 Subject: [PATCH 1304/1492] Prepare to 6.0.0.beta1 --- Manifest.txt | 1 + arel.gemspec | 23 +++++++++++------------ lib/arel.rb | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Manifest.txt b/Manifest.txt index 3892cd3b2aff9..32e1dd43a6e1d 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -13,6 +13,7 @@ lib/arel/alias_predication.rb lib/arel/attributes.rb lib/arel/attributes/attribute.rb lib/arel/collectors/bind.rb +lib/arel/collectors/plain_string.rb lib/arel/collectors/sql_string.rb lib/arel/compatibility/wheres.rb lib/arel/crud.rb diff --git a/arel.gemspec b/arel.gemspec index e6fe10a4bff58..832eb12f4902f 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,22 +1,21 @@ # -*- encoding: utf-8 -*- -# stub: arel 6.0.0.20140505020427 ruby lib +# stub: arel 6.0.0.beta1.20140817224534 ruby lib Gem::Specification.new do |s| s.name = "arel" - s.version = "6.0.0.20140505020427" + s.version = "6.0.0.beta1.20140817224534" - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= s.require_paths = ["lib"] s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2014-05-05" + s.date = "2014-08-18" s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] - s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/collectors/bind.rb", "lib/arel/collectors/sql_string.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/full_outer_join.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/right_outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_substitute.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/reduce.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] + s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/collectors/bind.rb", "lib/arel/collectors/plain_string.rb", "lib/arel/collectors/sql_string.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/full_outer_join.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/right_outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_substitute.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/reduce.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] s.homepage = "http://github.com/rails/arel" s.licenses = ["MIT"] s.rdoc_options = ["--main", "README.markdown"] - s.rubyforge_project = "arel" s.rubygems_version = "2.2.2" s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" s.test_files = ["test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] @@ -25,17 +24,17 @@ Gem::Specification.new do |s| s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 5.3"]) + s.add_development_dependency(%q, ["~> 5.4"]) s.add_development_dependency(%q, ["~> 4.0"]) - s.add_development_dependency(%q, ["~> 3.6"]) + s.add_development_dependency(%q, ["~> 3.12"]) else - s.add_dependency(%q, ["~> 5.3"]) + s.add_dependency(%q, ["~> 5.4"]) s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.6"]) + s.add_dependency(%q, ["~> 3.12"]) end else - s.add_dependency(%q, ["~> 5.3"]) + s.add_dependency(%q, ["~> 5.4"]) s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.6"]) + s.add_dependency(%q, ["~> 3.12"]) end end diff --git a/lib/arel.rb b/lib/arel.rb index 1e3c51a2548ab..80677953dfb62 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '6.0.0' + VERSION = '6.0.0.beta1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From ccaf67fcdb42f2294df597461baaf54a46a9e195 Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 21 Aug 2014 23:07:15 +0900 Subject: [PATCH 1305/1492] Fix typo `gt` means `>` --- test/attributes/test_attribute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 38ee189a46fbe..f55e39cfe93e0 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -66,7 +66,7 @@ module Attributes relation[:id].gt(10).must_be_kind_of Nodes::GreaterThan end - it 'should generate >= in sql' do + it 'should generate > in sql' do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].gt(10) From d27bfef96a86e7278dee297a8af3612ebefbe898 Mon Sep 17 00:00:00 2001 From: bigxiang Date: Sat, 23 Aug 2014 21:01:12 +0800 Subject: [PATCH 1306/1492] Fix lt & lteq don't accept most of values. --- lib/arel/predications.rb | 12 ++++++------ test/attributes/test_attribute.rb | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 78cd87d4306c1..1941383068a3d 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -31,7 +31,7 @@ def in other when Range if other.begin == -Float::INFINITY if other.end == Float::INFINITY - Nodes::NotIn.new self, [] + Nodes::NotIn.new self, [] elsif other.exclude_end? Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) else @@ -67,20 +67,20 @@ def not_in other Arel::Nodes::NotIn.new(self, other.ast) when Range if other.begin == -Float::INFINITY # The range begins with negative infinity - if other.end == Float::INFINITY + if other.end == Float::INFINITY Nodes::In.new self, [] # The range is infinite, so return an empty range elsif other.exclude_end? Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) else Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) end - elsif other.end == Float::INFINITY + elsif other.end == Float::INFINITY Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) else left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) if other.exclude_end? right = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) - else + else right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) end Nodes::Or.new left, right @@ -149,7 +149,7 @@ def gt_all others end def lt right - Nodes::LessThan.new self, right + Nodes::LessThan.new self, Nodes.build_quoted(right, self) end def lt_any others @@ -161,7 +161,7 @@ def lt_all others end def lteq right - Nodes::LessThanOrEqual.new self, right + Nodes::LessThanOrEqual.new self, Nodes.build_quoted(right, self) end def lteq_any others diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index f55e39cfe93e0..12dd25291e333 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -180,6 +180,9 @@ module Attributes mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" < 10 } + + mgr.where relation[:created_at].lt(::Time.now) + mgr.to_sql.must_match %{"users"."created_at" <} end end @@ -228,6 +231,9 @@ module Attributes mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" <= 10 } + + mgr.where relation[:created_at].lteq(::Time.now) + mgr.to_sql.must_match %{"users"."created_at" <=} end end From 112cb940aa17a0979b9f6282c07ace2f6a0896c1 Mon Sep 17 00:00:00 2001 From: Max Holder Date: Sat, 30 Aug 2014 13:58:18 -0400 Subject: [PATCH 1307/1492] Add SelectManager#distinct_on to set/unset Arel::Nodes::DistinctOn quantifier --- lib/arel/select_manager.rb | 9 +++++++++ test/test_select_manager.rb | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 4a652f2c9c52f..5a05e7e1818d9 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -155,6 +155,15 @@ def distinct(value = true) self end + def distinct_on(value) + if value + @ctx.set_quantifier = Arel::Nodes::DistinctOn.new(value) + else + @ctx.set_quantifier = nil + end + self + end + def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 3380bbec6f533..1ffb56fd9f391 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1158,5 +1158,26 @@ def test_manager_stores_bind_values manager.distinct(false).must_equal manager end end + + describe 'distinct_on' do + it 'sets the quantifier' do + manager = Arel::SelectManager.new Table.engine + table = Table.new :users + + manager.distinct_on(table['id']) + manager.ast.cores.last.set_quantifier.must_equal Arel::Nodes::DistinctOn.new(table['id']) + + manager.distinct_on(false) + manager.ast.cores.last.set_quantifier.must_equal nil + end + + it "chains" do + manager = Arel::SelectManager.new Table.engine + table = Table.new :users + + manager.distinct_on(table['id']).must_equal manager + manager.distinct_on(false).must_equal manager + end + end end end From 3f8ac523cbf2ebc544e5eec0db2b3247f396f9b3 Mon Sep 17 00:00:00 2001 From: bigxiang Date: Sun, 31 Aug 2014 22:11:25 +0800 Subject: [PATCH 1308/1492] Change specs to cover lt, lteq, gt and gteq. --- test/attributes/test_attribute.rb | 46 ++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 12dd25291e333..50da1cea5be67 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -85,6 +85,17 @@ module Attributes SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") AS avg_id FROM "users") } end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].gt('fake_name') + mgr.to_sql.must_match %{"users"."name" > 'fake_name'} + + current_time = ::Time.now + mgr.where relation[:created_at].gt(current_time) + mgr.to_sql.must_match %{"users"."created_at" > '#{current_time}'} + end end describe '#gt_any' do @@ -133,6 +144,17 @@ module Attributes SELECT "users"."id" FROM "users" WHERE "users"."id" >= 10 } end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].gteq('fake_name') + mgr.to_sql.must_match %{"users"."name" >= 'fake_name'} + + current_time = ::Time.now + mgr.where relation[:created_at].gteq(current_time) + mgr.to_sql.must_match %{"users"."created_at" >= '#{current_time}'} + end end describe '#gteq_any' do @@ -180,9 +202,17 @@ module Attributes mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" < 10 } + end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].lt('fake_name') + mgr.to_sql.must_match %{"users"."name" < 'fake_name'} - mgr.where relation[:created_at].lt(::Time.now) - mgr.to_sql.must_match %{"users"."created_at" <} + current_time = ::Time.now + mgr.where relation[:created_at].lt(current_time) + mgr.to_sql.must_match %{"users"."created_at" < '#{current_time}'} end end @@ -231,9 +261,17 @@ module Attributes mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE "users"."id" <= 10 } + end + + it 'should accept various data types.' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].lteq('fake_name') + mgr.to_sql.must_match %{"users"."name" <= 'fake_name'} - mgr.where relation[:created_at].lteq(::Time.now) - mgr.to_sql.must_match %{"users"."created_at" <=} + current_time = ::Time.now + mgr.where relation[:created_at].lteq(current_time) + mgr.to_sql.must_match %{"users"."created_at" <= '#{current_time}'} end end From 8c73dad0761980061ce45018172034cad34cd585 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Sat, 13 Sep 2014 19:35:34 -0700 Subject: [PATCH 1309/1492] `Extract#as` should not mutate the receiver Fixes https://github.com/rails/rails/issues/16913 --- lib/arel/nodes/extract.rb | 13 +++---------- lib/arel/visitors/to_sql.rb | 9 +-------- test/nodes/test_extract.rb | 8 ++++++++ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb index 64f5c3ff0f83e..7c69deadef6ed 100644 --- a/lib/arel/nodes/extract.rb +++ b/lib/arel/nodes/extract.rb @@ -1,20 +1,14 @@ module Arel module Nodes class Extract < Arel::Nodes::Unary + include Arel::AliasPredication include Arel::Predications attr_accessor :field - attr_accessor :alias - def initialize expr, field, aliaz = nil + def initialize expr, field super(expr) @field = field - @alias = aliaz && SqlLiteral.new(aliaz) - end - - def as aliaz - self.alias = SqlLiteral.new(aliaz) - self end def hash @@ -23,8 +17,7 @@ def hash def eql? other super && - self.field == other.field && - self.alias == other.alias + self.field == other.field end alias :== :eql? end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ae1b7930af4bb..ca09373b640ec 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -475,14 +475,7 @@ def visit_Arel_Nodes_NamedFunction o, collector def visit_Arel_Nodes_Extract o, collector collector << "EXTRACT(#{o.field.to_s.upcase} FROM " - collector = visit o.expr, collector - collector << ")" - if o.alias - collector << " AS " - visit o.alias, collector - else - collector - end + visit(o.expr, collector) << ")" end def visit_Arel_Nodes_Count o, collector diff --git a/test/nodes/test_extract.rb b/test/nodes/test_extract.rb index 80bb465f24db8..eb9855326845e 100644 --- a/test/nodes/test_extract.rb +++ b/test/nodes/test_extract.rb @@ -15,6 +15,14 @@ EXTRACT(DATE FROM "users"."timestamp") AS foo } end + + it 'should not mutate the extract' do + table = Arel::Table.new :users + extract = table[:timestamp].extract('date') + before = extract.dup + extract.as('foo') + assert_equal extract, before + end end describe 'equality' do From fb7532795b060fe409cbb731895ef8bd9a6449d8 Mon Sep 17 00:00:00 2001 From: Chris Dinger Date: Sat, 14 Jul 2012 00:24:09 -0500 Subject: [PATCH 1310/1492] Wrap group_by sql with a subquery for limiting rows in Oracle. Fixes #128 --- lib/arel/visitors/oracle.rb | 2 +- test/visitors/test_oracle.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 8a80faaa970af..91f6e0223eb07 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -8,7 +8,7 @@ def visit_Arel_Nodes_SelectStatement o, collector # 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.set_quantifier.class.to_s !~ /Distinct/ + if o.limit && o.orders.empty? && o.cores.first.groups.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /Distinct/ o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 9111a266cf925..29d70420845ce 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -87,6 +87,16 @@ def compile node } end + it 'creates a subquery when there is group by' do + stmt = Nodes::SelectStatement.new + stmt.cores.first.groups << Nodes::SqlLiteral.new('foo') + stmt.limit = Nodes::Limit.new(10) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM (SELECT GROUP BY foo ) WHERE ROWNUM <= 10 + } + end + it 'creates a subquery when there is DISTINCT' do stmt = Nodes::SelectStatement.new stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new From 3e6f0d963bcc8d3ff6f89b7505d7464d41ac5099 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Wed, 17 Sep 2014 00:13:28 +0930 Subject: [PATCH 1311/1492] Build on ruby-head --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9a11ead3ec4d6..8e5462c44051c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +language: ruby script: - "rake test" - "gem build arel.gemspec" @@ -6,7 +7,8 @@ rvm: - jruby - 1.9.3 - 2.0.0 - - 2.1.1 + - 2.1 + - ruby-head matrix: allow_failures: - rvm: rbx From f3aee123ec7fb77091b8df4e3bea4f4da11d7d52 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Tue, 16 Sep 2014 11:12:56 -0400 Subject: [PATCH 1312/1492] Remove unused @alias, being referenced in hashing. --- lib/arel/nodes/extract.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb index 7c69deadef6ed..7ed678ca08b9e 100644 --- a/lib/arel/nodes/extract.rb +++ b/lib/arel/nodes/extract.rb @@ -12,7 +12,7 @@ def initialize expr, field end def hash - super ^ [@field, @alias].hash + super ^ @field.hash end def eql? other From 7b75711ef85e80ad3ed03d51b555dd65697017ec Mon Sep 17 00:00:00 2001 From: Pierre Paridans Date: Sun, 3 Mar 2013 16:18:59 +0100 Subject: [PATCH 1313/1492] Informix versions < 10 use 'FIRST' keyword instead of 'LIMIT' Still supported in versions 10+ --- lib/arel/visitors/informix.rb | 2 +- test/visitors/test_informix.rb | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index 8de05f60f6209..7e8a3ea45871f 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -41,7 +41,7 @@ def visit_Arel_Nodes_Offset o, collector visit o.expr, collector end def visit_Arel_Nodes_Limit o, collector - collector << "LIMIT " + collector << "FIRST " visit o.expr, collector collector << " " end diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index 6d94282b7731c..04c42f8f609eb 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -11,21 +11,21 @@ def compile node @visitor.accept(node, Collectors::SQLString.new).value end - it 'uses LIMIT n to limit results' do + it 'uses FIRST n to limit results' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) sql = compile(stmt) - sql.must_be_like "SELECT LIMIT 1" + sql.must_be_like "SELECT FIRST 1" end - it 'uses LIMIT n in updates with a limit' do + it 'uses FIRST n in updates with a limit' do table = Table.new(:users) stmt = Nodes::UpdateStatement.new stmt.relation = table stmt.limit = Nodes::Limit.new(Nodes.build_quoted(1)) stmt.key = table[:id] sql = compile(stmt) - sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT LIMIT 1 \"users\".\"id\" FROM \"users\")" + sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT FIRST 1 \"users\".\"id\" FROM \"users\")" end it 'uses SKIP n to jump results' do @@ -35,12 +35,12 @@ def compile node sql.must_be_like "SELECT SKIP 10" end - it 'uses SKIP before LIMIT' do + it 'uses SKIP before FIRST' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) stmt.offset = Nodes::Offset.new(1) sql = compile(stmt) - sql.must_be_like "SELECT SKIP 1 LIMIT 1" + sql.must_be_like "SELECT SKIP 1 FIRST 1" end it 'uses INNER JOIN to perform joins' do From 33aab3adbd3f07887f1e6ce04a7b0983367fe1f0 Mon Sep 17 00:00:00 2001 From: Dimko Date: Wed, 17 Sep 2014 23:27:59 +0400 Subject: [PATCH 1314/1492] Fix set visiting spec --- test/visitors/test_to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index d84142e27a320..b495c4d994a99 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -230,7 +230,7 @@ def dispatch end it "should visit_Set" do - @visitor.accept Set.new([1, 2]) + compile Nodes.build_quoted(Set.new([1, 2])) end it "should visit_BigDecimal" do From c903c6b28933a041d42d943c6c83f98aaa81f42a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Sep 2014 10:23:10 -0700 Subject: [PATCH 1315/1492] connections should cache these values, so remove the cache in arel --- lib/arel/visitors/to_sql.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 095aa5279a680..dea6830e8f88f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -61,8 +61,6 @@ class ToSql < Arel::Visitors::Reduce def initialize connection @connection = connection @schema_cache = connection.schema_cache - @quoted_tables = {} - @quoted_columns = {} end def compile node, &block @@ -761,11 +759,12 @@ def quote value, column = nil def quote_table_name name return name if Arel::Nodes::SqlLiteral === name - @quoted_tables[name] ||= @connection.quote_table_name(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) + return name if Arel::Nodes::SqlLiteral === name + @connection.quote_column_name(name) end def maybe_visit thing, collector From b57a11cb8abfca345f63084ce841c6f412c1156e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 22 Sep 2014 11:01:03 -0700 Subject: [PATCH 1316/1492] move the dispatch table to be per-instance visitors are not shared among threads, so any mutations to the cache should be OK. The cache is also pre-populated on construction, but we should pull that out so we can share the cache among visitors in the future. --- lib/arel/visitors/depth_first.rb | 4 ++++ lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/reduce.rb | 8 ++++---- lib/arel/visitors/to_sql.rb | 10 +++++++--- lib/arel/visitors/visitor.rb | 31 ++++++++++++++++++------------ lib/arel/visitors/where_sql.rb | 2 ++ test/visitors/test_bind_visitor.rb | 6 ------ test/visitors/test_to_sql.rb | 2 +- 8 files changed, 38 insertions(+), 26 deletions(-) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index eab20ac83187e..a434f404c7e74 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -3,6 +3,7 @@ module Visitors class DepthFirst < Arel::Visitors::Visitor def initialize block = nil @block = block || Proc.new + super() end private @@ -86,6 +87,7 @@ def binary o alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary + alias :visit_Arel_Nodes_Union :binary def visit_Arel_Nodes_StringJoin o visit o.left @@ -116,6 +118,8 @@ def terminal o alias :visit_Arel_Nodes_SqlLiteral :terminal alias :visit_Arel_Nodes_BindParam :terminal alias :visit_Arel_Nodes_Window :terminal + alias :visit_Arel_Nodes_True :terminal + alias :visit_Arel_Nodes_False :terminal alias :visit_BigDecimal :terminal alias :visit_Bignum :terminal alias :visit_Class :terminal diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 12cce1e266c12..e0c02d717a372 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -15,6 +15,7 @@ class Edge < Struct.new :name, :from, :to # :nodoc: end def initialize + super() @nodes = [] @edges = [] @node_stack = [] diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb index 9670cad27cb4a..1d74934fe5dce 100644 --- a/lib/arel/visitors/reduce.rb +++ b/lib/arel/visitors/reduce.rb @@ -10,14 +10,14 @@ def accept object, collector private def visit object, collector - send dispatch[object.class], object, collector + send dispatch[object.class.name], object, collector rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class], true) + raise e if respond_to?(dispatch[object.class.name], true) superklass = object.class.ancestors.find { |klass| - respond_to?(dispatch[klass], true) + respond_to?(dispatch[klass.name], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass - dispatch[object.class] = dispatch[superklass] + dispatch[object.class.name] = dispatch[superklass.name] retry end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index dea6830e8f88f..7bef8feded49c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -59,8 +59,8 @@ class ToSql < Arel::Visitors::Reduce DISTINCT = 'DISTINCT' # :nodoc: def initialize connection + super() @connection = connection - @schema_cache = connection.schema_cache end def compile node, &block @@ -69,6 +69,10 @@ def compile node, &block private + def schema_cache + @connection.schema_cache + end + def visit_Arel_Nodes_DeleteStatement o, collector collector << "DELETE FROM " collector = visit o.relation, collector @@ -160,7 +164,7 @@ def visit_Arel_Nodes_False o, collector end def table_exists? name - @schema_cache.table_exists? name + schema_cache.table_exists? name end def column_for attr @@ -174,7 +178,7 @@ def column_for attr end def column_cache(table) - @schema_cache.columns_hash(table) + schema_cache.columns_hash(table) end def visit_Arel_Nodes_Values o, collector diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 0730c157949a6..2317d0c95f76c 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -1,32 +1,39 @@ module Arel module Visitors class Visitor + def initialize + @dispatch = Hash.new do |hash, class_name| + raise if class_name == 'Arel::Nodes::Union' + hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}" + end + + # pre-populate cache. FIXME: this should be passed in to each + # instance, but we can do that later. + self.class.private_instance_methods.sort.each do |name| + next unless name =~ /^visit_(.*)$/ + @dispatch[$1.gsub('_', '::')] = name + end + end + def accept object visit object end private - DISPATCH = Hash.new do |hash, visitor_class| - hash[visitor_class] = - Hash.new do |method_hash, node_class| - method_hash[node_class] = "visit_#{(node_class.name || '').gsub('::', '_')}" - end - end - def dispatch - DISPATCH[self.class] + @dispatch end def visit object - send dispatch[object.class], object + send dispatch[object.class.name], object rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class], true) + raise e if respond_to?(dispatch[object.class.name], true) superklass = object.class.ancestors.find { |klass| - respond_to?(dispatch[klass], true) + respond_to?(dispatch[klass.name], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass - dispatch[object.class] = dispatch[superklass] + dispatch[object.class.name] = dispatch[superklass.name] retry end end diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index 27dde73673737..afde15a6c5bb2 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -1,6 +1,8 @@ module Arel module Visitors class WhereSql < Arel::Visitors::ToSql + private + def visit_Arel_Nodes_SelectCore o, collector collector << "WHERE " inject_join o.wheres, collector, ' AND ' diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index 5171bbe57caad..333636ed514c7 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -35,9 +35,6 @@ def test_assignment_binds_are_substituted def test_visitor_yields_on_binds visitor = Class.new(Arel::Visitors::ToSql) { - def initialize omg - end - include Arel::Visitors::BindVisitor }.new nil @@ -49,9 +46,6 @@ def initialize omg def test_visitor_only_yields_on_binds visitor = Class.new(Arel::Visitors::ToSql) { - def initialize omg - end - include Arel::Visitors::BindVisitor }.new(nil) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index b495c4d994a99..195566902ba90 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -29,7 +29,7 @@ def compile node end def dispatch - { Arel::Table => 'hello' } + { Arel::Table.name => 'hello' } end }.new From fef9ce493ec3eab3cf120550abd0257f89eaddf7 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 24 Sep 2014 19:01:33 -0700 Subject: [PATCH 1317/1492] {Matches,DoesNotMatch} support the ESCAPE clause --- lib/arel/nodes.rb | 1 + lib/arel/nodes/binary.rb | 2 -- lib/arel/nodes/matches.rb | 14 ++++++++++++++ lib/arel/predications.rb | 33 +++++++++++++++++---------------- lib/arel/visitors/to_sql.rb | 16 ++++++++++++++-- test/visitors/test_to_sql.rb | 14 ++++++++++++++ 6 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 lib/arel/nodes/matches.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index c6bde8c3ccc19..ccccd471e2234 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -28,6 +28,7 @@ require 'arel/nodes/table_alias' require 'arel/nodes/infix_operation' require 'arel/nodes/over' +require 'arel/nodes/matches' # nary require 'arel/nodes/and' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 939684957f4dc..e35d2fd2e79de 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -31,13 +31,11 @@ def eql? other As Assignment Between - DoesNotMatch GreaterThan GreaterThanOrEqual Join LessThan LessThanOrEqual - Matches NotEqual NotIn NotRegexp diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb new file mode 100644 index 0000000000000..583fb97c9bfcf --- /dev/null +++ b/lib/arel/nodes/matches.rb @@ -0,0 +1,14 @@ +module Arel + module Nodes + class Matches < Binary + attr_reader :escape + + def initialize(left, right, escape = nil) + super(left, right) + @escape = escape && Nodes.build_quoted(escape) + end + end + + class DoesNotMatch < Matches; end + end +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 1941383068a3d..3050526a4374d 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -100,28 +100,28 @@ def not_in_all others grouping_all :not_in, others end - def matches other - Nodes::Matches.new self, Nodes.build_quoted(other, self) + def matches other, escape = nil + Nodes::Matches.new self, Nodes.build_quoted(other, self), escape end - def matches_any others - grouping_any :matches, others + def matches_any others, escape = nil + grouping_any :matches, others, escape end - def matches_all others - grouping_all :matches, others + def matches_all others, escape = nil + grouping_all :matches, others, escape end - def does_not_match other - Nodes::DoesNotMatch.new self, Nodes.build_quoted(other, self) + def does_not_match other, escape = nil + Nodes::DoesNotMatch.new self, Nodes.build_quoted(other, self), escape end - def does_not_match_any others - grouping_any :does_not_match, others + def does_not_match_any others, escape = nil + grouping_any :does_not_match, others, escape end - def does_not_match_all others - grouping_all :does_not_match, others + def does_not_match_all others, escape = nil + grouping_all :does_not_match, others, escape end def gteq right @@ -174,15 +174,16 @@ def lteq_all others private - def grouping_any method_id, others - nodes = others.map {|expr| send(method_id, expr)} + def grouping_any method_id, others, *extras + nodes = others.map {|expr| send(method_id, expr, *extras)} 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)}) + def grouping_all method_id, others, *extras + nodes = others.map {|expr| send(method_id, expr, *extras)} + Nodes::Grouping.new Nodes::And.new(nodes) end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7bef8feded49c..7fa3322148b5a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -539,13 +539,25 @@ def visit_Arel_Nodes_LessThan o, collector def visit_Arel_Nodes_Matches o, collector collector = visit o.left, collector collector << " LIKE " - visit o.right, collector + collector = visit o.right, collector + if o.escape + collector << ' ESCAPE ' + visit o.escape, collector + else + collector + end end def visit_Arel_Nodes_DoesNotMatch o, collector collector = visit o.left, collector collector << " NOT LIKE " - visit o.right, collector + collector = visit o.right, collector + if o.escape + collector << ' ESCAPE ' + visit o.escape, collector + else + collector + end end def visit_Arel_Nodes_JoinSource o, collector diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 195566902ba90..abd8cfe356a90 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -312,6 +312,13 @@ def dispatch } end + it "can handle ESCAPE" do + node = @table[:name].matches('foo!%', '!') + compile(node).must_be_like %{ + "users"."name" LIKE 'foo!%' ESCAPE '!' + } + end + it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].matches('foo%')) node = @attr.in subquery @@ -329,6 +336,13 @@ def dispatch } end + it "can handle ESCAPE" do + node = @table[:name].does_not_match('foo!%', '!') + compile(node).must_be_like %{ + "users"."name" NOT LIKE 'foo!%' ESCAPE '!' + } + end + it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) node = @attr.in subquery From e65d38cd8111ff8fde696c5501a05639a81ea941 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Fri, 24 Oct 2014 00:38:39 +0530 Subject: [PATCH 1318/1492] `Expresssions` => `Expressions` [ci skip] --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 1776330da85c3..76efb2b34a715 100644 --- a/README.markdown +++ b/README.markdown @@ -184,7 +184,7 @@ comments_with_replies = \ This will return the reply for the first comment. -[Common Table Expresssions(CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: +[Common Table Expressions(CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: Create a `CTE` From 08e64913d17f774420698c3dd917c285ebc42e55 Mon Sep 17 00:00:00 2001 From: claudiob Date: Thu, 23 Oct 2014 17:22:17 -0700 Subject: [PATCH 1319/1492] Reuse `maybe_visit` method This commit simply removes duplicated code by reusing the existing `maybe_visit` method. --- lib/arel/visitors/mysql.rb | 7 +------ lib/arel/visitors/to_sql.rb | 15 +++------------ 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 70a37582c2121..f989b8ddefcc9 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -69,12 +69,7 @@ def visit_Arel_Nodes_UpdateStatement o, collector collector = inject_join o.orders, collector, ', ' end - if o.limit - collector << " " - visit(o.limit, collector) - else - collector - end + maybe_visit o.limit, collector end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7fa3322148b5a..bccf1d4061586 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -229,15 +229,9 @@ def visit_Arel_Nodes_SelectStatement o, collector def visit_Arel_Nodes_SelectCore o, collector collector << "SELECT" - if o.top - collector << " " - collector = visit o.top, collector - end + maybe_visit o.top, collector - if o.set_quantifier - collector << " " - collector = visit o.set_quantifier, collector - end + maybe_visit o.set_quantifier, collector unless o.projections.empty? collector << SPACE @@ -271,10 +265,7 @@ def visit_Arel_Nodes_SelectCore o, collector end end - if o.having - collector << " " - collector = visit(o.having, collector) - end + maybe_visit o.having, collector unless o.windows.empty? collector << WINDOW From 621775361c2535b819ca1f3416170d4bb2deadd5 Mon Sep 17 00:00:00 2001 From: claudiob Date: Thu, 23 Oct 2014 17:35:43 -0700 Subject: [PATCH 1320/1492] Completes 08e6491 in reusing `maybe_visit` :sweat: I don't know why the tests did not fail, but to keep the same syntax as before, `collector =` is required. Maybe `visit` changes `collector` in-place, so the result is the same, but since I'm not sure about the side effects, I think this PR is needed to. Sorry! :sweat: --- lib/arel/visitors/to_sql.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index bccf1d4061586..a3f8cb565d0be 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -229,9 +229,9 @@ def visit_Arel_Nodes_SelectStatement o, collector def visit_Arel_Nodes_SelectCore o, collector collector << "SELECT" - maybe_visit o.top, collector + collector = maybe_visit o.top, collector - maybe_visit o.set_quantifier, collector + collector = maybe_visit o.set_quantifier, collector unless o.projections.empty? collector << SPACE @@ -265,7 +265,7 @@ def visit_Arel_Nodes_SelectCore o, collector end end - maybe_visit o.having, collector + collector = maybe_visit o.having, collector unless o.windows.empty? collector << WINDOW From 1120f8956729715027e47ddd76102c319d41a89b Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Fri, 24 Oct 2014 12:26:02 +0530 Subject: [PATCH 1321/1492] - Added test for verifying proper sql generated by minimum aggregate method. --- test/attributes/test_attribute.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index b50bb60b1e0cd..768df23d4dd61 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -329,7 +329,7 @@ module Attributes relation[:id].maximum.must_be_kind_of Nodes::Max end - it 'should generate the proper SQL' do + it 'should generate proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].maximum mgr.to_sql.must_be_like %{ @@ -344,6 +344,15 @@ module Attributes relation = Table.new(:users) relation[:id].minimum.must_be_kind_of Nodes::Min end + + it 'should generate proper SQL' do + relation = Table.new(:users) + mgr = relation.project relation[:id].minimum + mgr.to_sql.must_be_like %{ + SELECT MIN("users"."id") + FROM "users" + } + end end describe '#sum' do From 0c99711a1564bf1cb213b35142a3c05feddef0bd Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 23 Oct 2014 14:10:33 -0600 Subject: [PATCH 1322/1492] Binary nodes should not generate the same hash as nodes of other classes --- lib/arel/nodes/binary.rb | 2 +- test/nodes/test_binary.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 test/nodes/test_binary.rb diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index e35d2fd2e79de..dddbde14313ac 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -16,7 +16,7 @@ def initialize_copy other end def hash - [@left, @right].hash + [self.class, @left, @right].hash end def eql? other diff --git a/test/nodes/test_binary.rb b/test/nodes/test_binary.rb new file mode 100644 index 0000000000000..7e25a21151fcc --- /dev/null +++ b/test/nodes/test_binary.rb @@ -0,0 +1,26 @@ +require 'helper' +require 'set' + +module Arel + module Nodes + describe 'Binary' do + describe '#hash' do + it 'generates a hash based on its value' do + eq = Equality.new('foo', 'bar') + eq2 = Equality.new('foo', 'bar') + eq3 = Equality.new('bar', 'baz') + + assert_equal eq.hash, eq2.hash + refute_equal eq.hash, eq3.hash + end + + it 'generates a hash specific to its class' do + eq = Equality.new('foo', 'bar') + neq = NotEqual.new('foo', 'bar') + + refute_equal eq.hash, neq.hash + end + end + end + end +end From 51f48f0ed9ec84fd12584b750609a2f7e945b945 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 23 Oct 2014 14:53:20 -0600 Subject: [PATCH 1323/1492] `#not_in` with a range should respect proper precedence Currently, doing ```ruby relation[:id].not_eq(4).and(relation[:id].not_in(1..3)) ``` will generate ```sql "id" != 4 AND "id" < 1 OR "id" > 3 ``` Which would incorrectly include records with an id of 4, as the OR statement has higher precidence than the AND statement. The `or` method on `Node` properly groups the statement in parenthesis. --- lib/arel/predications.rb | 2 +- test/visitors/test_to_sql.rb | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 3050526a4374d..6f9a3c5f91835 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -83,7 +83,7 @@ def not_in other else right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) end - Nodes::Or.new left, right + left.or(right) end when Array Nodes::NotIn.new self, other.map { |x| Nodes.build_quoted(x, self) } diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index abd8cfe356a90..62e1c57c73e78 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -480,16 +480,16 @@ def quote value, column = nil it 'can handle two dot ranges' do node = @attr.not_in 1..3 - compile(node).must_be_like %{ - "users"."id" < 1 OR "users"."id" > 3 - } + compile(node).must_equal( + %{("users"."id" < 1 OR "users"."id" > 3)} + ) end it 'can handle three dot ranges' do node = @attr.not_in 1...3 - compile(node).must_be_like %{ - "users"."id" < 1 OR "users"."id" >= 3 - } + compile(node).must_equal( + %{("users"."id" < 1 OR "users"."id" >= 3)} + ) end it 'can handle ranges bounded by infinity' do From fefac0178c2d4815a2ceeebc2b7c4fea9ab6ed46 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 23 Oct 2014 14:35:13 -0600 Subject: [PATCH 1324/1492] Improve test coverage for `#in` and `#not_in` These methods are going to go through some heavy refactoring, and moving logic around. This adds missing tests for each of the branches on the predicate. --- test/attributes/test_attribute.rb | 209 ++++++++++++++++++++++++++++-- 1 file changed, 201 insertions(+), 8 deletions(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index b50bb60b1e0cd..264ba7e8786ca 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -549,14 +549,108 @@ module Attributes end describe '#in' do + it 'can be constructed with a subquery' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + attribute = Attribute.new nil, nil + + node = attribute.in(mgr) + + node.must_equal Nodes::In.new(attribute, mgr.ast) + end + + describe 'with a range' do + it 'can be constructed with a standard range' do + attribute = Attribute.new nil, nil + node = attribute.in(1..3) + + node.must_equal Nodes::Between.new( + attribute, + Nodes::And.new([ + Nodes::Casted.new(1, attribute), + Nodes::Casted.new(3, attribute) + ]) + ) + end + + it 'can be constructed with a range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.in(-::Float::INFINITY..3) + + node.must_equal Nodes::LessThanOrEqual.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end + + it 'can be constructed with an exclusive range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.in(-::Float::INFINITY...3) + + node.must_equal Nodes::LessThan.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end + + it 'can be constructed with an infinite range' do + attribute = Attribute.new nil, nil + node = attribute.in(-::Float::INFINITY..::Float::INFINITY) + + node.must_equal Nodes::NotIn.new(attribute, []) + end + + it 'can be constructed with a range ending at Infinity' do + attribute = Attribute.new nil, nil + node = attribute.in(0..::Float::INFINITY) + + node.must_equal Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(0, attribute) + ) + end + + it 'can be constructed with an exclusive range' do + attribute = Attribute.new nil, nil + node = attribute.in(0...3) + + node.must_equal Nodes::And.new([ + Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(0, attribute) + ), + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + ]) + end + end + it 'can be constructed with a list' do + attribute = Attribute.new nil, nil + node = attribute.in([1, 2, 3]) + + node.must_equal Nodes::In.new( + attribute, + [ + Nodes::Casted.new(1, attribute), + Nodes::Casted.new(2, attribute), + Nodes::Casted.new(3, attribute), + ] + ) end - it 'should return an in node' do + it 'can be constructed with a random object' do attribute = Attribute.new nil, nil - node = Nodes::In.new attribute, [1,2,3] - node.left.must_equal attribute - node.right.must_equal [1, 2, 3] + random_object = Object.new + node = attribute.in(random_object) + + node.must_equal Nodes::In.new( + attribute, + Nodes::Casted.new(random_object, attribute) + ) end it 'should generate IN in sql' do @@ -602,12 +696,111 @@ module Attributes end describe '#not_in' do + it 'can be constructed with a subquery' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + attribute = Attribute.new nil, nil - it 'should return a NotIn node' do + node = attribute.not_in(mgr) + + node.must_equal Nodes::NotIn.new(attribute, mgr.ast) + end + + describe 'with a range' do + it 'can be constructed with a standard range' do + attribute = Attribute.new nil, nil + node = attribute.not_in(1..3) + + node.must_equal Nodes::Or.new( + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(1, attribute) + ), + Nodes::GreaterThan.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + ) + end + + it 'can be constructed with a range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.not_in(-::Float::INFINITY..3) + + node.must_equal Nodes::GreaterThan.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end + + it 'can be constructed with an exclusive range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.not_in(-::Float::INFINITY...3) + + node.must_equal Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end + + it 'can be constructed with an infinite range' do + attribute = Attribute.new nil, nil + node = attribute.not_in(-::Float::INFINITY..::Float::INFINITY) + + node.must_equal Nodes::In.new(attribute, []) + end + + it 'can be constructed with a range ending at Infinity' do + attribute = Attribute.new nil, nil + node = attribute.not_in(0..::Float::INFINITY) + + node.must_equal Nodes::LessThan.new( + attribute, + Nodes::Casted.new(0, attribute) + ) + end + + it 'can be constructed with an exclusive range' do + attribute = Attribute.new nil, nil + node = attribute.not_in(0...3) + + node.must_equal Nodes::Or.new( + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(0, attribute) + ), + Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + ) + end + end + + it 'can be constructed with a list' 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] + node = attribute.not_in([1, 2, 3]) + + node.must_equal Nodes::NotIn.new( + attribute, + [ + Nodes::Casted.new(1, attribute), + Nodes::Casted.new(2, attribute), + Nodes::Casted.new(3, attribute), + ] + ) + end + + it 'can be constructed with a random object' do + attribute = Attribute.new nil, nil + random_object = Object.new + node = attribute.not_in(random_object) + + node.must_equal Nodes::NotIn.new( + attribute, + Nodes::Casted.new(random_object, attribute) + ) end it 'should generate NOT IN in sql' do From 438d553b76f59eed003c8e4bb569936e68e0e7c2 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 25 Oct 2014 07:18:28 -0500 Subject: [PATCH 1325/1492] =?UTF-8?q?=F0=9F=92=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/attributes/test_attribute.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 264ba7e8786ca..0851a0725833e 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -712,7 +712,7 @@ module Attributes attribute = Attribute.new nil, nil node = attribute.not_in(1..3) - node.must_equal Nodes::Or.new( + node.must_equal Nodes::Grouping.new(Nodes::Or.new( Nodes::LessThan.new( attribute, Nodes::Casted.new(1, attribute) @@ -721,7 +721,7 @@ module Attributes attribute, Nodes::Casted.new(3, attribute) ) - ) + )) end it 'can be constructed with a range starting from -Infinity' do @@ -765,7 +765,7 @@ module Attributes attribute = Attribute.new nil, nil node = attribute.not_in(0...3) - node.must_equal Nodes::Or.new( + node.must_equal Nodes::Grouping.new(Nodes::Or.new( Nodes::LessThan.new( attribute, Nodes::Casted.new(0, attribute) @@ -774,7 +774,7 @@ module Attributes attribute, Nodes::Casted.new(3, attribute) ) - ) + )) end end From df5723dfbe856abc8c91cc87c609156b432e97d3 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 25 Oct 2014 07:24:18 -0500 Subject: [PATCH 1326/1492] Refactor `#in` and `#not_in` These methods duplicate a lot of logic from the other predications. We can just use those methods directly, and only build nodes with the same name in our method directly. We've already had one bug that came from building nodes directly, rather than using the proper predicate. --- lib/arel/predications.rb | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 6f9a3c5f91835..4079b4830e904 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -24,6 +24,12 @@ def eq_all others grouping_all :eq, others.map { |x| Nodes.build_quoted(x, self) } end + def between other + left = Nodes.build_quoted(other.begin, self) + right = Nodes.build_quoted(other.end, self) + Nodes::Between.new(self, left.and(right)) + end + def in other case other when Arel::SelectManager @@ -31,20 +37,18 @@ def in other when Range if other.begin == -Float::INFINITY if other.end == Float::INFINITY - Nodes::NotIn.new self, [] + not_in([]) elsif other.exclude_end? - Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) + lt(other.end) else - Nodes::LessThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) + lteq(other.end) end elsif other.end == Float::INFINITY - Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self)) + gteq(other.begin) elsif other.exclude_end? - left = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.begin, self)) - right = Nodes::LessThan.new(self, Nodes.build_quoted(other.end, self)) - Nodes::And.new [left, right] + gteq(other.begin).and(lt(other.end)) else - Nodes::Between.new(self, Nodes::And.new([Nodes.build_quoted(other.begin, self), Nodes.build_quoted(other.end, self)])) + between(other) end when Array Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) } @@ -68,20 +72,20 @@ def not_in other when Range if other.begin == -Float::INFINITY # The range begins with negative infinity if other.end == Float::INFINITY - Nodes::In.new self, [] # The range is infinite, so return an empty range + self.in([]) elsif other.exclude_end? - Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) + gteq(other.end) else - Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) + gt(other.end) end elsif other.end == Float::INFINITY - Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) + lt(other.begin) else - left = Nodes::LessThan.new(self, Nodes.build_quoted(other.begin, self)) - if other.exclude_end? - right = Nodes::GreaterThanOrEqual.new(self, Nodes.build_quoted(other.end, self)) + left = lt(other.begin) + right = if other.exclude_end? + gteq(other.end) else - right = Nodes::GreaterThan.new(self, Nodes.build_quoted(other.end, self)) + gt(other.end) end left.or(right) end From f8d85cf24bca522a04edc5cc48f8716e65efb107 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 25 Oct 2014 07:38:56 -0500 Subject: [PATCH 1327/1492] Deprecate passing ranges to `#in` and `#not_in` The goal of these methods should be to generate in nodes, not handle every possible permutation of more than one value. The `#between` and `#not_between` methods have been extracted, which better represent the semantics of handling ranges in SQL. --- lib/arel/predications.rb | 84 ++++++---- test/attributes/test_attribute.rb | 258 +++++++++++++++--------------- test/test_select_manager.rb | 6 +- test/visitors/test_to_sql.rb | 24 +-- 4 files changed, 192 insertions(+), 180 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 4079b4830e904..a0b6728943b4a 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -25,9 +25,23 @@ def eq_all others end def between other - left = Nodes.build_quoted(other.begin, self) - right = Nodes.build_quoted(other.end, self) - Nodes::Between.new(self, left.and(right)) + if other.begin == -Float::INFINITY + if other.end == Float::INFINITY + not_in([]) + elsif other.exclude_end? + lt(other.end) + else + lteq(other.end) + end + elsif other.end == Float::INFINITY + gteq(other.begin) + elsif other.exclude_end? + gteq(other.begin).and(lt(other.end)) + else + left = Nodes.build_quoted(other.begin, self) + right = Nodes.build_quoted(other.end, self) + Nodes::Between.new(self, left.and(right)) + end end def in other @@ -35,21 +49,12 @@ def in other when Arel::SelectManager Arel::Nodes::In.new(self, other.ast) when Range - if other.begin == -Float::INFINITY - if other.end == Float::INFINITY - not_in([]) - elsif other.exclude_end? - lt(other.end) - else - lteq(other.end) - end - elsif other.end == Float::INFINITY - gteq(other.begin) - elsif other.exclude_end? - gteq(other.begin).and(lt(other.end)) - else - between(other) + if $VERBOSE + warn <<-eowarn +Passing a range to `#in` is deprecated. Call `#between`, instead. + eowarn end + between(other) when Array Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) } else @@ -65,30 +70,39 @@ def in_all others grouping_all :in, others end + def not_between other + if other.begin == -Float::INFINITY # The range begins with negative infinity + if other.end == Float::INFINITY + self.in([]) + elsif other.exclude_end? + gteq(other.end) + else + gt(other.end) + end + elsif other.end == Float::INFINITY + lt(other.begin) + else + left = lt(other.begin) + right = if other.exclude_end? + gteq(other.end) + else + gt(other.end) + end + left.or(right) + end + end + def not_in other case other when Arel::SelectManager Arel::Nodes::NotIn.new(self, other.ast) when Range - if other.begin == -Float::INFINITY # The range begins with negative infinity - if other.end == Float::INFINITY - self.in([]) - elsif other.exclude_end? - gteq(other.end) - else - gt(other.end) - end - elsif other.end == Float::INFINITY - lt(other.begin) - else - left = lt(other.begin) - right = if other.exclude_end? - gteq(other.end) - else - gt(other.end) - end - left.or(right) + if $VERBOSE + warn <<-eowarn +Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. + eowarn end + not_between(other) when Array Nodes::NotIn.new self, other.map { |x| Nodes.build_quoted(x, self) } else diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 0851a0725833e..500f9385f820b 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -548,84 +548,84 @@ module Attributes end end - describe '#in' do - it 'can be constructed with a subquery' do - relation = Table.new(:users) - mgr = relation.project relation[:id] - mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + describe 'with a range' do + it 'can be constructed with a standard range' do attribute = Attribute.new nil, nil + node = attribute.between(1..3) - node = attribute.in(mgr) - - node.must_equal Nodes::In.new(attribute, mgr.ast) + node.must_equal Nodes::Between.new( + attribute, + Nodes::And.new([ + Nodes::Casted.new(1, attribute), + Nodes::Casted.new(3, attribute) + ]) + ) end - describe 'with a range' do - it 'can be constructed with a standard range' do - attribute = Attribute.new nil, nil - node = attribute.in(1..3) + it 'can be constructed with a range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.between(-::Float::INFINITY..3) - node.must_equal Nodes::Between.new( - attribute, - Nodes::And.new([ - Nodes::Casted.new(1, attribute), - Nodes::Casted.new(3, attribute) - ]) - ) - end + node.must_equal Nodes::LessThanOrEqual.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end - it 'can be constructed with a range starting from -Infinity' do - attribute = Attribute.new nil, nil - node = attribute.in(-::Float::INFINITY..3) + it 'can be constructed with an exclusive range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.between(-::Float::INFINITY...3) - node.must_equal Nodes::LessThanOrEqual.new( - attribute, - Nodes::Casted.new(3, attribute) - ) - end + node.must_equal Nodes::LessThan.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end - it 'can be constructed with an exclusive range starting from -Infinity' do - attribute = Attribute.new nil, nil - node = attribute.in(-::Float::INFINITY...3) + it 'can be constructed with an infinite range' do + attribute = Attribute.new nil, nil + node = attribute.between(-::Float::INFINITY..::Float::INFINITY) - node.must_equal Nodes::LessThan.new( - attribute, - Nodes::Casted.new(3, attribute) - ) - end + node.must_equal Nodes::NotIn.new(attribute, []) + end - it 'can be constructed with an infinite range' do - attribute = Attribute.new nil, nil - node = attribute.in(-::Float::INFINITY..::Float::INFINITY) + it 'can be constructed with a range ending at Infinity' do + attribute = Attribute.new nil, nil + node = attribute.between(0..::Float::INFINITY) - node.must_equal Nodes::NotIn.new(attribute, []) - end + node.must_equal Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(0, attribute) + ) + end - it 'can be constructed with a range ending at Infinity' do - attribute = Attribute.new nil, nil - node = attribute.in(0..::Float::INFINITY) + it 'can be constructed with an exclusive range' do + attribute = Attribute.new nil, nil + node = attribute.between(0...3) - node.must_equal Nodes::GreaterThanOrEqual.new( + node.must_equal Nodes::And.new([ + Nodes::GreaterThanOrEqual.new( attribute, Nodes::Casted.new(0, attribute) + ), + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(3, attribute) ) - end - - it 'can be constructed with an exclusive range' do - attribute = Attribute.new nil, nil - node = attribute.in(0...3) - - node.must_equal Nodes::And.new([ - Nodes::GreaterThanOrEqual.new( - attribute, - Nodes::Casted.new(0, attribute) - ), - Nodes::LessThan.new( - attribute, - Nodes::Casted.new(3, attribute) - ) - ]) - end + ]) + end + end + + describe '#in' do + it 'can be constructed with a subquery' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + attribute = Attribute.new nil, nil + + node = attribute.in(mgr) + + node.must_equal Nodes::In.new(attribute, mgr.ast) end it 'can be constructed with a list' do @@ -695,87 +695,87 @@ module Attributes end end - describe '#not_in' do - it 'can be constructed with a subquery' do - relation = Table.new(:users) - mgr = relation.project relation[:id] - mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + describe 'with a range' do + it 'can be constructed with a standard range' do attribute = Attribute.new nil, nil + node = attribute.not_between(1..3) - node = attribute.not_in(mgr) - - node.must_equal Nodes::NotIn.new(attribute, mgr.ast) - end - - describe 'with a range' do - it 'can be constructed with a standard range' do - attribute = Attribute.new nil, nil - node = attribute.not_in(1..3) - - node.must_equal Nodes::Grouping.new(Nodes::Or.new( - Nodes::LessThan.new( - attribute, - Nodes::Casted.new(1, attribute) - ), - Nodes::GreaterThan.new( - attribute, - Nodes::Casted.new(3, attribute) - ) - )) - end - - it 'can be constructed with a range starting from -Infinity' do - attribute = Attribute.new nil, nil - node = attribute.not_in(-::Float::INFINITY..3) - - node.must_equal Nodes::GreaterThan.new( + node.must_equal Nodes::Grouping.new(Nodes::Or.new( + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(1, attribute) + ), + Nodes::GreaterThan.new( attribute, Nodes::Casted.new(3, attribute) ) - end + )) + end - it 'can be constructed with an exclusive range starting from -Infinity' do - attribute = Attribute.new nil, nil - node = attribute.not_in(-::Float::INFINITY...3) + it 'can be constructed with a range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.not_between(-::Float::INFINITY..3) - node.must_equal Nodes::GreaterThanOrEqual.new( - attribute, - Nodes::Casted.new(3, attribute) - ) - end + node.must_equal Nodes::GreaterThan.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end + + it 'can be constructed with an exclusive range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.not_between(-::Float::INFINITY...3) + + node.must_equal Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(3, attribute) + ) + end - it 'can be constructed with an infinite range' do - attribute = Attribute.new nil, nil - node = attribute.not_in(-::Float::INFINITY..::Float::INFINITY) + it 'can be constructed with an infinite range' do + attribute = Attribute.new nil, nil + node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY) - node.must_equal Nodes::In.new(attribute, []) - end + node.must_equal Nodes::In.new(attribute, []) + end - it 'can be constructed with a range ending at Infinity' do - attribute = Attribute.new nil, nil - node = attribute.not_in(0..::Float::INFINITY) + it 'can be constructed with a range ending at Infinity' do + attribute = Attribute.new nil, nil + node = attribute.not_between(0..::Float::INFINITY) - node.must_equal Nodes::LessThan.new( + node.must_equal Nodes::LessThan.new( + attribute, + Nodes::Casted.new(0, attribute) + ) + end + + it 'can be constructed with an exclusive range' do + attribute = Attribute.new nil, nil + node = attribute.not_between(0...3) + + node.must_equal Nodes::Grouping.new(Nodes::Or.new( + Nodes::LessThan.new( attribute, Nodes::Casted.new(0, attribute) + ), + Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Casted.new(3, attribute) ) - end - - it 'can be constructed with an exclusive range' do - attribute = Attribute.new nil, nil - node = attribute.not_in(0...3) - - node.must_equal Nodes::Grouping.new(Nodes::Or.new( - Nodes::LessThan.new( - attribute, - Nodes::Casted.new(0, attribute) - ), - Nodes::GreaterThanOrEqual.new( - attribute, - Nodes::Casted.new(3, attribute) - ) - )) - end + )) + end + end + + describe '#not_in' do + it 'can be constructed with a subquery' do + relation = Table.new(:users) + mgr = relation.project relation[:id] + mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + attribute = Attribute.new nil, nil + + node = attribute.not_in(mgr) + + node.must_equal Nodes::NotIn.new(attribute, mgr.ast) end it 'can be constructed with a list' do diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 1ffb56fd9f391..78b3a25928bd0 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -307,13 +307,11 @@ def test_manager_stores_bind_values table = Table.new :users @m1 = Arel::SelectManager.new Table.engine, table @m1.project Arel.star - @m1.where(table[:age].in(18..60)) + @m1.where(table[:age].between(18..60)) @m2 = Arel::SelectManager.new Table.engine, table @m2.project Arel.star - @m2.where(table[:age].in(40..99)) - - + @m2.where(table[:age].between(40..99)) end it 'should except two managers' do diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 62e1c57c73e78..9c18d74827305 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -375,33 +375,33 @@ def dispatch end it 'can handle two dot ranges' do - node = @attr.in 1..3 + node = @attr.between 1..3 compile(node).must_be_like %{ "users"."id" BETWEEN 1 AND 3 } end it 'can handle three dot ranges' do - node = @attr.in 1...3 + node = @attr.between 1...3 compile(node).must_be_like %{ "users"."id" >= 1 AND "users"."id" < 3 } end it 'can handle ranges bounded by infinity' do - node = @attr.in 1..Float::INFINITY + node = @attr.between 1..Float::INFINITY compile(node).must_be_like %{ "users"."id" >= 1 } - node = @attr.in(-Float::INFINITY..3) + node = @attr.between(-Float::INFINITY..3) compile(node).must_be_like %{ "users"."id" <= 3 } - node = @attr.in(-Float::INFINITY...3) + node = @attr.between(-Float::INFINITY...3) compile(node).must_be_like %{ "users"."id" < 3 } - node = @attr.in(-Float::INFINITY..Float::INFINITY) + node = @attr.between(-Float::INFINITY..Float::INFINITY) compile(node).must_be_like %{1=1} end @@ -479,33 +479,33 @@ def quote value, column = nil end it 'can handle two dot ranges' do - node = @attr.not_in 1..3 + node = @attr.not_between 1..3 compile(node).must_equal( %{("users"."id" < 1 OR "users"."id" > 3)} ) end it 'can handle three dot ranges' do - node = @attr.not_in 1...3 + node = @attr.not_between 1...3 compile(node).must_equal( %{("users"."id" < 1 OR "users"."id" >= 3)} ) end it 'can handle ranges bounded by infinity' do - node = @attr.not_in 1..Float::INFINITY + node = @attr.not_between 1..Float::INFINITY compile(node).must_be_like %{ "users"."id" < 1 } - node = @attr.not_in(-Float::INFINITY..3) + node = @attr.not_between(-Float::INFINITY..3) compile(node).must_be_like %{ "users"."id" > 3 } - node = @attr.not_in(-Float::INFINITY...3) + node = @attr.not_between(-Float::INFINITY...3) compile(node).must_be_like %{ "users"."id" >= 3 } - node = @attr.not_in(-Float::INFINITY..Float::INFINITY) + node = @attr.not_between(-Float::INFINITY..Float::INFINITY) compile(node).must_be_like %{1=0} end From 7db0e4accff919f0a7aea875fbc8d9f5696ecb69 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 27 Oct 2014 16:58:05 -0600 Subject: [PATCH 1328/1492] Dry up building quoted nodes in predication Given that we are going to remove casting from Arel in the near future, having a single place nodes in predications will help. --- lib/arel/predications.rb | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index a0b6728943b4a..f11f8dc86d393 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,7 +1,7 @@ module Arel module Predications def not_eq other - Nodes::NotEqual.new self, Nodes.build_quoted(other, self) + Nodes::NotEqual.new self, quoted_node(other) end def not_eq_any others @@ -13,7 +13,7 @@ def not_eq_all others end def eq other - Nodes::Equality.new self, Nodes.build_quoted(other, self) + Nodes::Equality.new self, quoted_node(other) end def eq_any others @@ -21,7 +21,7 @@ def eq_any others end def eq_all others - grouping_all :eq, others.map { |x| Nodes.build_quoted(x, self) } + grouping_all :eq, quoted_array(others) end def between other @@ -38,8 +38,8 @@ def between other elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) else - left = Nodes.build_quoted(other.begin, self) - right = Nodes.build_quoted(other.end, self) + left = quoted_node(other.begin) + right = quoted_node(other.end) Nodes::Between.new(self, left.and(right)) end end @@ -56,9 +56,9 @@ def in other end between(other) when Array - Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) } + Nodes::In.new self, quoted_array(other) else - Nodes::In.new self, Nodes.build_quoted(other, self) + Nodes::In.new self, quoted_node(other) end end @@ -104,9 +104,9 @@ def not_in other end not_between(other) when Array - Nodes::NotIn.new self, other.map { |x| Nodes.build_quoted(x, self) } + Nodes::NotIn.new self, quoted_array(other) else - Nodes::NotIn.new self, Nodes.build_quoted(other, self) + Nodes::NotIn.new self, quoted_node(other) end end @@ -119,7 +119,7 @@ def not_in_all others end def matches other, escape = nil - Nodes::Matches.new self, Nodes.build_quoted(other, self), escape + Nodes::Matches.new self, quoted_node(other), escape end def matches_any others, escape = nil @@ -131,7 +131,7 @@ def matches_all others, escape = nil end def does_not_match other, escape = nil - Nodes::DoesNotMatch.new self, Nodes.build_quoted(other, self), escape + Nodes::DoesNotMatch.new self, quoted_node(other), escape end def does_not_match_any others, escape = nil @@ -143,7 +143,7 @@ def does_not_match_all others, escape = nil end def gteq right - Nodes::GreaterThanOrEqual.new self, Nodes.build_quoted(right, self) + Nodes::GreaterThanOrEqual.new self, quoted_node(right) end def gteq_any others @@ -155,7 +155,7 @@ def gteq_all others end def gt right - Nodes::GreaterThan.new self, Nodes.build_quoted(right, self) + Nodes::GreaterThan.new self, quoted_node(right) end def gt_any others @@ -167,7 +167,7 @@ def gt_all others end def lt right - Nodes::LessThan.new self, Nodes.build_quoted(right, self) + Nodes::LessThan.new self, quoted_node(right) end def lt_any others @@ -179,7 +179,7 @@ def lt_all others end def lteq right - Nodes::LessThanOrEqual.new self, Nodes.build_quoted(right, self) + Nodes::LessThanOrEqual.new self, quoted_node(right) end def lteq_any others @@ -203,5 +203,13 @@ def grouping_all method_id, others, *extras nodes = others.map {|expr| send(method_id, expr, *extras)} Nodes::Grouping.new Nodes::And.new(nodes) end + + def quoted_node(other) + Nodes.build_quoted(other, self) + end + + def quoted_array(others) + others.map { |v| quoted_node(v) } + end end end From 9b92af7098b2728ced578ab9a7679176d20f120f Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 30 Oct 2014 12:40:41 -0600 Subject: [PATCH 1329/1492] Revert "Merge pull request #300 from jpcody/master" This reverts commit 36836fa5e7c084c0dce2818577e6fd0cf815f786, reversing changes made to 53bc8426648cc93695525e8f12102cd416b2d772. --- README.markdown | 10 +++++----- lib/arel/expressions.rb | 9 ++++----- test/attributes/test_attribute.rb | 17 ++++++++++------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/README.markdown b/README.markdown index 76efb2b34a715..ca4772ca7a9ab 100644 --- a/README.markdown +++ b/README.markdown @@ -120,10 +120,10 @@ Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: ```ruby photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 -users.project(users[:age].sum) # => SELECT SUM(users.age) FROM users -users.project(users[:age].average) # => SELECT AVG(users.age) FROM users -users.project(users[:age].maximum) # => SELECT MAX(users.age) FROM users -users.project(users[:age].minimum) # => SELECT MIN(users.age) FROM users +users.project(users[:age].sum) # => SELECT SUM(users.age) AS sum_id FROM users +users.project(users[:age].average) # => SELECT AVG(users.age) AS avg_id FROM users +users.project(users[:age].maximum) # => SELECT MAX(users.age) AS max_id FROM users +users.project(users[:age].minimum) # => SELECT MIN(users.age) AS min_id FROM users users.project(users[:age].count) # => SELECT COUNT(users.age) FROM users ``` @@ -201,7 +201,7 @@ users. project(users[:id], cte_table[:click].sum). with(composed_cte) -# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) FROM users INNER JOIN cte_table ON users.id = cte_table.user_id +# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) AS sum_id FROM users INNER JOIN cte_table ON users.id = cte_table.user_id ``` When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index d40268c2925ad..fa18f15b6770b 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -5,24 +5,23 @@ def count distinct = false end def sum - Nodes::Sum.new [self] + Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id') end def maximum - Nodes::Max.new [self] + Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') end def minimum - Nodes::Min.new [self] + Nodes::Min.new [self], Nodes::SqlLiteral.new('min_id') end def average - Nodes::Avg.new [self] + Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') end def extract field Nodes::Extract.new [self], field end - end end diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 500f9385f820b..6cfe9fbcbf5bd 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -82,7 +82,7 @@ module Attributes mgr = users.project(Arel.star).where(users[:karma].gt(avg)) mgr.to_sql.must_be_like %{ - SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") FROM "users") + SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") AS avg_id FROM "users") } end @@ -313,11 +313,12 @@ module Attributes relation[:id].average.must_be_kind_of Nodes::Avg end - it 'should generate the proper SQL' do + # 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") + SELECT AVG("users"."id") AS avg_id FROM "users" } end @@ -329,11 +330,12 @@ module Attributes relation[:id].maximum.must_be_kind_of Nodes::Max end - it 'should generate the proper SQL' do + # 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") + SELECT MAX("users"."id") AS max_id FROM "users" } end @@ -352,11 +354,12 @@ module Attributes relation[:id].sum.must_be_kind_of Nodes::Sum end - it 'should generate the proper SQL' do + # 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") + SELECT SUM("users"."id") AS sum_id FROM "users" } end From 88266ed4aeb3a5d9f54e857348d2d972e189755d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 30 Oct 2014 18:42:44 -0200 Subject: [PATCH 1330/1492] Stop using hoe to release the gem --- .autotest | 26 --------- .gemtest | 0 Manifest.txt | 135 ----------------------------------------------- Rakefile | 27 ++++------ arel.gemspec | 50 ++++++------------ arel.gemspec.erb | 24 +++++++++ 6 files changed, 52 insertions(+), 210 deletions(-) delete mode 100644 .autotest delete mode 100644 .gemtest delete mode 100644 Manifest.txt create mode 100644 arel.gemspec.erb diff --git a/.autotest b/.autotest deleted file mode 100644 index 19ea6ecbe689b..0000000000000 --- a/.autotest +++ /dev/null @@ -1,26 +0,0 @@ -# -*- ruby -*- - -# require 'autotest/restart' - -ENV['GEM_PATH'] = "tmp/isolate/ruby-1.8" - -module Autotest::Restart - Autotest.add_hook :updated do |at, *args| - if args.flatten.include? ".autotest" then - warn "Detected change to .autotest, restarting" - cmd = %w(autotest) - cmd << " -v" if $v - cmd += ARGV - - exec(*cmd) - end - end -end - -Autotest.add_hook :initialize do |at| - at.add_exception 'tmp' - at.testlib = "minitest/autorun" - - at.find_directories = ARGV unless ARGV.empty? -end - diff --git a/.gemtest b/.gemtest deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/Manifest.txt b/Manifest.txt deleted file mode 100644 index 32e1dd43a6e1d..0000000000000 --- a/Manifest.txt +++ /dev/null @@ -1,135 +0,0 @@ -.autotest -.gemtest -.travis.yml -Gemfile -History.txt -MIT-LICENSE.txt -Manifest.txt -README.markdown -Rakefile -arel.gemspec -lib/arel.rb -lib/arel/alias_predication.rb -lib/arel/attributes.rb -lib/arel/attributes/attribute.rb -lib/arel/collectors/bind.rb -lib/arel/collectors/plain_string.rb -lib/arel/collectors/sql_string.rb -lib/arel/compatibility/wheres.rb -lib/arel/crud.rb -lib/arel/delete_manager.rb -lib/arel/expressions.rb -lib/arel/factory_methods.rb -lib/arel/insert_manager.rb -lib/arel/math.rb -lib/arel/nodes.rb -lib/arel/nodes/and.rb -lib/arel/nodes/ascending.rb -lib/arel/nodes/binary.rb -lib/arel/nodes/count.rb -lib/arel/nodes/delete_statement.rb -lib/arel/nodes/descending.rb -lib/arel/nodes/equality.rb -lib/arel/nodes/extract.rb -lib/arel/nodes/false.rb -lib/arel/nodes/full_outer_join.rb -lib/arel/nodes/function.rb -lib/arel/nodes/grouping.rb -lib/arel/nodes/in.rb -lib/arel/nodes/infix_operation.rb -lib/arel/nodes/inner_join.rb -lib/arel/nodes/insert_statement.rb -lib/arel/nodes/join_source.rb -lib/arel/nodes/named_function.rb -lib/arel/nodes/node.rb -lib/arel/nodes/outer_join.rb -lib/arel/nodes/over.rb -lib/arel/nodes/right_outer_join.rb -lib/arel/nodes/select_core.rb -lib/arel/nodes/select_statement.rb -lib/arel/nodes/sql_literal.rb -lib/arel/nodes/string_join.rb -lib/arel/nodes/table_alias.rb -lib/arel/nodes/terminal.rb -lib/arel/nodes/true.rb -lib/arel/nodes/unary.rb -lib/arel/nodes/unqualified_column.rb -lib/arel/nodes/update_statement.rb -lib/arel/nodes/values.rb -lib/arel/nodes/window.rb -lib/arel/nodes/with.rb -lib/arel/order_predications.rb -lib/arel/predications.rb -lib/arel/select_manager.rb -lib/arel/table.rb -lib/arel/tree_manager.rb -lib/arel/update_manager.rb -lib/arel/visitors.rb -lib/arel/visitors/bind_substitute.rb -lib/arel/visitors/bind_visitor.rb -lib/arel/visitors/depth_first.rb -lib/arel/visitors/dot.rb -lib/arel/visitors/ibm_db.rb -lib/arel/visitors/informix.rb -lib/arel/visitors/mssql.rb -lib/arel/visitors/mysql.rb -lib/arel/visitors/oracle.rb -lib/arel/visitors/postgresql.rb -lib/arel/visitors/reduce.rb -lib/arel/visitors/sqlite.rb -lib/arel/visitors/to_sql.rb -lib/arel/visitors/visitor.rb -lib/arel/visitors/where_sql.rb -lib/arel/window_predications.rb -test/attributes/test_attribute.rb -test/collectors/test_bind_collector.rb -test/collectors/test_sql_string.rb -test/helper.rb -test/nodes/test_and.rb -test/nodes/test_as.rb -test/nodes/test_ascending.rb -test/nodes/test_bin.rb -test/nodes/test_count.rb -test/nodes/test_delete_statement.rb -test/nodes/test_descending.rb -test/nodes/test_distinct.rb -test/nodes/test_equality.rb -test/nodes/test_extract.rb -test/nodes/test_false.rb -test/nodes/test_grouping.rb -test/nodes/test_infix_operation.rb -test/nodes/test_insert_statement.rb -test/nodes/test_named_function.rb -test/nodes/test_node.rb -test/nodes/test_not.rb -test/nodes/test_or.rb -test/nodes/test_over.rb -test/nodes/test_select_core.rb -test/nodes/test_select_statement.rb -test/nodes/test_sql_literal.rb -test/nodes/test_sum.rb -test/nodes/test_table_alias.rb -test/nodes/test_true.rb -test/nodes/test_update_statement.rb -test/nodes/test_window.rb -test/support/fake_record.rb -test/test_attributes.rb -test/test_crud.rb -test/test_delete_manager.rb -test/test_factory_methods.rb -test/test_insert_manager.rb -test/test_select_manager.rb -test/test_table.rb -test/test_update_manager.rb -test/visitors/test_bind_visitor.rb -test/visitors/test_depth_first.rb -test/visitors/test_dispatch_contamination.rb -test/visitors/test_dot.rb -test/visitors/test_ibm_db.rb -test/visitors/test_informix.rb -test/visitors/test_mssql.rb -test/visitors/test_mysql.rb -test/visitors/test_oracle.rb -test/visitors/test_postgres.rb -test/visitors/test_sqlite.rb -test/visitors/test_to_sql.rb diff --git a/Rakefile b/Rakefile index f9257d696f225..351d66bd12d81 100644 --- a/Rakefile +++ b/Rakefile @@ -1,20 +1,15 @@ -require "rubygems" -gem 'hoe', '>= 3.3.1' -require 'hoe' +require 'bundler' +Bundler::GemHelper.install_tasks -Hoe.plugins.delete :rubyforge -Hoe.plugin :minitest -Hoe.plugin :gemspec # `gem install hoe-gemspec` -Hoe.plugin :git # `gem install hoe-git` -Hoe.plugin :bundler # `gem install hoe-bundler` +specname = "arel.gemspec" +deps = `git ls-files`.split("\n") - [specname] -Hoe.spec 'arel' do - developer('Aaron Patterson', 'aaron@tenderlovemaking.com') - developer('Bryan Helmkamp', 'bryan@brynary.com') - developer('Emilio Tagua', 'miloops@gmail.com') - developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email +file specname => deps do + files = `git ls-files`.split("\n") - ["#{specname}.erb"] - self.licenses = ['MIT'] - self.readme_file = 'README.markdown' - self.extra_rdoc_files = FileList['README.markdown'] + require 'erb' + + File.open specname, 'w:utf-8' do |f| + f.write ERB.new(File.read("#{specname}.erb")).result(binding) + end end diff --git a/arel.gemspec b/arel.gemspec index 832eb12f4902f..8b694aa33f9f4 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,40 +1,24 @@ -# -*- encoding: utf-8 -*- -# stub: arel 6.0.0.beta1.20140817224534 ruby lib +# # -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) +require "arel" Gem::Specification.new do |s| - s.name = "arel" - s.version = "6.0.0.beta1.20140817224534" - - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version= - s.require_paths = ["lib"] - s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"] - s.date = "2014-08-18" + s.name = "arel" + s.version = Arel::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"] + s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com"] + s.homepage = "https://github.com/rails/arel" s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." - s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"] - s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown"] - s.files = [".autotest", ".gemtest", ".travis.yml", "Gemfile", "History.txt", "MIT-LICENSE.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/alias_predication.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/collectors/bind.rb", "lib/arel/collectors/plain_string.rb", "lib/arel/collectors/sql_string.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/expressions.rb", "lib/arel/factory_methods.rb", "lib/arel/insert_manager.rb", "lib/arel/math.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/ascending.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/descending.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/extract.rb", "lib/arel/nodes/false.rb", "lib/arel/nodes/full_outer_join.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/infix_operation.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join_source.rb", "lib/arel/nodes/named_function.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/over.rb", "lib/arel/nodes/right_outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/terminal.rb", "lib/arel/nodes/true.rb", "lib/arel/nodes/unary.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/nodes/window.rb", "lib/arel/nodes/with.rb", "lib/arel/order_predications.rb", "lib/arel/predications.rb", "lib/arel/select_manager.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/visitors.rb", "lib/arel/visitors/bind_substitute.rb", "lib/arel/visitors/bind_visitor.rb", "lib/arel/visitors/depth_first.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/ibm_db.rb", "lib/arel/visitors/informix.rb", "lib/arel/visitors/mssql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/reduce.rb", "lib/arel/visitors/sqlite.rb", "lib/arel/visitors/to_sql.rb", "lib/arel/visitors/visitor.rb", "lib/arel/visitors/where_sql.rb", "lib/arel/window_predications.rb", "test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/helper.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/support/fake_record.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] - s.homepage = "http://github.com/rails/arel" - s.licenses = ["MIT"] + s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" + s.license = %q{MIT} + s.rdoc_options = ["--main", "README.markdown"] - s.rubygems_version = "2.2.2" - s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" - s.test_files = ["test/attributes/test_attribute.rb", "test/collectors/test_bind_collector.rb", "test/collectors/test_sql_string.rb", "test/nodes/test_and.rb", "test/nodes/test_as.rb", "test/nodes/test_ascending.rb", "test/nodes/test_bin.rb", "test/nodes/test_count.rb", "test/nodes/test_delete_statement.rb", "test/nodes/test_descending.rb", "test/nodes/test_distinct.rb", "test/nodes/test_equality.rb", "test/nodes/test_extract.rb", "test/nodes/test_false.rb", "test/nodes/test_grouping.rb", "test/nodes/test_infix_operation.rb", "test/nodes/test_insert_statement.rb", "test/nodes/test_named_function.rb", "test/nodes/test_node.rb", "test/nodes/test_not.rb", "test/nodes/test_or.rb", "test/nodes/test_over.rb", "test/nodes/test_select_core.rb", "test/nodes/test_select_statement.rb", "test/nodes/test_sql_literal.rb", "test/nodes/test_sum.rb", "test/nodes/test_table_alias.rb", "test/nodes/test_true.rb", "test/nodes/test_update_statement.rb", "test/nodes/test_window.rb", "test/test_attributes.rb", "test/test_crud.rb", "test/test_delete_manager.rb", "test/test_factory_methods.rb", "test/test_insert_manager.rb", "test/test_select_manager.rb", "test/test_table.rb", "test/test_update_manager.rb", "test/visitors/test_bind_visitor.rb", "test/visitors/test_depth_first.rb", "test/visitors/test_dispatch_contamination.rb", "test/visitors/test_dot.rb", "test/visitors/test_ibm_db.rb", "test/visitors/test_informix.rb", "test/visitors/test_mssql.rb", "test/visitors/test_mysql.rb", "test/visitors/test_oracle.rb", "test/visitors/test_postgres.rb", "test/visitors/test_sqlite.rb", "test/visitors/test_to_sql.rb"] + s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] - if s.respond_to? :specification_version then - s.specification_version = 4 + s.files = [".gitignore",".travis.yml","Gemfile","History.txt","MIT-LICENSE.txt","README.markdown","Rakefile","arel.gemspec","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb","test/attributes/test_attribute.rb","test/collectors/test_bind_collector.rb","test/collectors/test_sql_string.rb","test/helper.rb","test/nodes/test_and.rb","test/nodes/test_as.rb","test/nodes/test_ascending.rb","test/nodes/test_bin.rb","test/nodes/test_binary.rb","test/nodes/test_count.rb","test/nodes/test_delete_statement.rb","test/nodes/test_descending.rb","test/nodes/test_distinct.rb","test/nodes/test_equality.rb","test/nodes/test_extract.rb","test/nodes/test_false.rb","test/nodes/test_grouping.rb","test/nodes/test_infix_operation.rb","test/nodes/test_insert_statement.rb","test/nodes/test_named_function.rb","test/nodes/test_node.rb","test/nodes/test_not.rb","test/nodes/test_or.rb","test/nodes/test_over.rb","test/nodes/test_select_core.rb","test/nodes/test_select_statement.rb","test/nodes/test_sql_literal.rb","test/nodes/test_sum.rb","test/nodes/test_table_alias.rb","test/nodes/test_true.rb","test/nodes/test_update_statement.rb","test/nodes/test_window.rb","test/support/fake_record.rb","test/test_attributes.rb","test/test_crud.rb","test/test_delete_manager.rb","test/test_factory_methods.rb","test/test_insert_manager.rb","test/test_select_manager.rb","test/test_table.rb","test/test_update_manager.rb","test/visitors/test_bind_visitor.rb","test/visitors/test_depth_first.rb","test/visitors/test_dispatch_contamination.rb","test/visitors/test_dot.rb","test/visitors/test_ibm_db.rb","test/visitors/test_informix.rb","test/visitors/test_mssql.rb","test/visitors/test_mysql.rb","test/visitors/test_oracle.rb","test/visitors/test_postgres.rb","test/visitors/test_sqlite.rb","test/visitors/test_to_sql.rb"] + s.require_paths = ["lib"] - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q, ["~> 5.4"]) - s.add_development_dependency(%q, ["~> 4.0"]) - s.add_development_dependency(%q, ["~> 3.12"]) - else - s.add_dependency(%q, ["~> 5.4"]) - s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.12"]) - end - else - s.add_dependency(%q, ["~> 5.4"]) - s.add_dependency(%q, ["~> 4.0"]) - s.add_dependency(%q, ["~> 3.12"]) - end + s.add_development_dependency('minitest', '~> 5.4') + s.add_development_dependency('hoe', '~> 3.12') end diff --git a/arel.gemspec.erb b/arel.gemspec.erb new file mode 100644 index 0000000000000..203347c0e365e --- /dev/null +++ b/arel.gemspec.erb @@ -0,0 +1,24 @@ +# # -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) +require "arel" + +Gem::Specification.new do |s| + s.name = "arel" + s.version = Arel::VERSION + s.platform = Gem::Platform::RUBY + s.authors = ["Aaron Patterson", "Bryan Helmkamp", "Emilio Tagua", "Nick Kallen"] + s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com"] + s.homepage = "https://github.com/rails/arel" + s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." + s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" + s.license = %q{MIT} + + s.rdoc_options = ["--main", "README.markdown"] + s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] + + s.files = [<%= files.map(&:inspect).join ',' %>] + s.require_paths = ["lib"] + + s.add_development_dependency('minitest', '~> 5.4') + s.add_development_dependency('hoe', '~> 3.12') +end From ffffcded66c910ed9b57ac81832324cff4b91b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 30 Oct 2014 18:45:25 -0200 Subject: [PATCH 1331/1492] hoe is not the dependecy anymore --- arel.gemspec | 2 +- arel.gemspec.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 8b694aa33f9f4..d37c5cc64bbb3 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -20,5 +20,5 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') - s.add_development_dependency('hoe', '~> 3.12') + s.add_development_dependency('rdoc', '~> 4.0') end diff --git a/arel.gemspec.erb b/arel.gemspec.erb index 203347c0e365e..d27127b2e4c1d 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -20,5 +20,5 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') - s.add_development_dependency('hoe', '~> 3.12') + s.add_development_dependency('rdoc', '~> 4.0') end From 8c7aa53200fc82774747c0419b3bc23c60bf289e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 30 Oct 2014 18:46:20 -0200 Subject: [PATCH 1332/1492] Update the Gemfile --- Gemfile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Gemfile b/Gemfile index 12c57d37370fa..07483b27d32f3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,3 @@ -# -*- ruby -*- - -# DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake bundler:gemfile`. - source "https://rubygems.org/" - -gem "minitest", "~>5.1", :group => [:development, :test] -gem "rdoc", "~>4.0", :group => [:development, :test] -gem "hoe", "~>3.5", :group => [:development, :test] - -# vim: syntax=ruby +gemspec From 8ac47c4580e55a41c5a159fe7fe74c732214ccec Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Thu, 30 Oct 2014 13:58:44 -0700 Subject: [PATCH 1333/1492] Bump to 6.0.0.beta2 --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 80677953dfb62..018dc7593dbaa 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '6.0.0.beta1' + VERSION = '6.0.0.beta2' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 5437df4a79dd0e8a3ddfa493a0d88a234e268d84 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 31 Oct 2014 08:40:28 -0600 Subject: [PATCH 1334/1492] Revert "Revert "Merge pull request #300 from jpcody/master"" This reverts commit 9b92af7098b2728ced578ab9a7679176d20f120f. beta2 is out, and we've fixed the issue that this caused in Rails --- README.markdown | 10 +++++----- lib/arel/expressions.rb | 9 +++++---- test/attributes/test_attribute.rb | 17 +++++++---------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/README.markdown b/README.markdown index ca4772ca7a9ab..76efb2b34a715 100644 --- a/README.markdown +++ b/README.markdown @@ -120,10 +120,10 @@ Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: ```ruby photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 -users.project(users[:age].sum) # => SELECT SUM(users.age) AS sum_id FROM users -users.project(users[:age].average) # => SELECT AVG(users.age) AS avg_id FROM users -users.project(users[:age].maximum) # => SELECT MAX(users.age) AS max_id FROM users -users.project(users[:age].minimum) # => SELECT MIN(users.age) AS min_id FROM users +users.project(users[:age].sum) # => SELECT SUM(users.age) FROM users +users.project(users[:age].average) # => SELECT AVG(users.age) FROM users +users.project(users[:age].maximum) # => SELECT MAX(users.age) FROM users +users.project(users[:age].minimum) # => SELECT MIN(users.age) FROM users users.project(users[:age].count) # => SELECT COUNT(users.age) FROM users ``` @@ -201,7 +201,7 @@ users. project(users[:id], cte_table[:click].sum). with(composed_cte) -# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) AS sum_id FROM users INNER JOIN cte_table ON users.id = cte_table.user_id +# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) FROM users INNER JOIN cte_table ON users.id = cte_table.user_id ``` When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index fa18f15b6770b..d40268c2925ad 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -5,23 +5,24 @@ def count distinct = false end def sum - Nodes::Sum.new [self], Nodes::SqlLiteral.new('sum_id') + Nodes::Sum.new [self] end def maximum - Nodes::Max.new [self], Nodes::SqlLiteral.new('max_id') + Nodes::Max.new [self] end def minimum - Nodes::Min.new [self], Nodes::SqlLiteral.new('min_id') + Nodes::Min.new [self] end def average - Nodes::Avg.new [self], Nodes::SqlLiteral.new('avg_id') + Nodes::Avg.new [self] end def extract field Nodes::Extract.new [self], field end + end end diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 6cfe9fbcbf5bd..500f9385f820b 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -82,7 +82,7 @@ module Attributes mgr = users.project(Arel.star).where(users[:karma].gt(avg)) mgr.to_sql.must_be_like %{ - SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") AS avg_id FROM "users") + SELECT * FROM "users" WHERE "users"."karma" > (SELECT AVG("users"."karma") FROM "users") } end @@ -313,12 +313,11 @@ module Attributes 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 + it 'should generate the proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].average mgr.to_sql.must_be_like %{ - SELECT AVG("users"."id") AS avg_id + SELECT AVG("users"."id") FROM "users" } end @@ -330,12 +329,11 @@ module Attributes 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 + it 'should generate the proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].maximum mgr.to_sql.must_be_like %{ - SELECT MAX("users"."id") AS max_id + SELECT MAX("users"."id") FROM "users" } end @@ -354,12 +352,11 @@ module Attributes 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 + it 'should generate the proper SQL' do relation = Table.new(:users) mgr = relation.project relation[:id].sum mgr.to_sql.must_be_like %{ - SELECT SUM("users"."id") AS sum_id + SELECT SUM("users"."id") FROM "users" } end From 54798211ff9707917f59cbe0b044325065bff481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Fri, 31 Oct 2014 14:30:26 -0200 Subject: [PATCH 1335/1492] Fix rake test task --- Rakefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Rakefile b/Rakefile index 351d66bd12d81..0928e86ef3e52 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,15 @@ require 'bundler' Bundler::GemHelper.install_tasks +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/test_*.rb' + t.verbose = true +end + specname = "arel.gemspec" deps = `git ls-files`.split("\n") - [specname] From b364cb1083f4e9d7a9e313e5de1174046bcfcbd4 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sun, 2 Nov 2014 12:00:04 -0700 Subject: [PATCH 1336/1492] Look for `Enumerable` rather than `Array` in predicates It's not quite duck typed, but it will allow us to pass in our own objects with additional logic (like type casting). --- lib/arel/predications.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index f11f8dc86d393..ec779dd40fee4 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -55,7 +55,7 @@ def in other eowarn end between(other) - when Array + when Enumerable Nodes::In.new self, quoted_array(other) else Nodes::In.new self, quoted_node(other) @@ -103,7 +103,7 @@ def not_in other eowarn end not_between(other) - when Array + when Enumerable Nodes::NotIn.new self, quoted_array(other) else Nodes::NotIn.new self, quoted_node(other) From 9eb4a1c633894a367ad99e93e4e0000f7acf1e50 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 4 Nov 2014 16:17:01 -0800 Subject: [PATCH 1337/1492] oops! that should not have been checked in --- lib/arel/visitors/visitor.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 2317d0c95f76c..146ae216f6f4b 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -3,8 +3,7 @@ module Visitors class Visitor def initialize @dispatch = Hash.new do |hash, class_name| - raise if class_name == 'Arel::Nodes::Union' - hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}" + hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}" end # pre-populate cache. FIXME: this should be passed in to each From 5035526b534a5d7c9d95eb6b66ade349c3a947f0 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 10 Nov 2014 11:50:34 -0800 Subject: [PATCH 1338/1492] cache the dispatch table on the depth first visitor We know the API for the depth first visitor in advance, so it's OK to calcuate this cache in advance --- lib/arel/visitors/depth_first.rb | 6 ++++++ lib/arel/visitors/visitor.rb | 21 +++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index a434f404c7e74..d7d85cfcc6d8a 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -173,6 +173,12 @@ def visit_Array o def visit_Hash o o.each { |k,v| visit(k); visit(v) } end + + DISPATCH = dispatch_cache + + def get_dispatch_cache + DISPATCH + end end end end diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 146ae216f6f4b..2152da9f0538f 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -2,7 +2,17 @@ module Arel module Visitors class Visitor def initialize - @dispatch = Hash.new do |hash, class_name| + @dispatch = get_dispatch_cache + end + + def accept object + visit object + end + + private + + def self.dispatch_cache + dispatch = Hash.new do |hash, class_name| hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}" end @@ -10,16 +20,15 @@ def initialize # instance, but we can do that later. self.class.private_instance_methods.sort.each do |name| next unless name =~ /^visit_(.*)$/ - @dispatch[$1.gsub('_', '::')] = name + dispatch[$1.gsub('_', '::')] = name end + dispatch end - def accept object - visit object + def get_dispatch_cache + self.class.dispatch_cache end - private - def dispatch @dispatch end From 590c784a30b13153667f8db7915998d7731e24e5 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 17 Nov 2014 14:52:38 -0800 Subject: [PATCH 1339/1492] Add order to BindParams in the ToSql collector This removes the need for us to do the re-ordering by walking the AST in ActiveRecord. We're using a block to communicate with the collector, since the collector needs to be the thing which knows about the index, while the visitor is the thing that needs to know the syntax. The BindParam needs to know about neither of these things, so it's been changed to stop being a subclass of SqlLiteral I could also see an alternative implementation using format strings if for some reason blocks cause a problem. --- lib/arel/collectors/sql_string.rb | 8 +++++++- lib/arel/nodes.rb | 1 + lib/arel/nodes/bind_param.rb | 6 ++++++ lib/arel/nodes/sql_literal.rb | 3 --- lib/arel/visitors/postgresql.rb | 4 ++++ lib/arel/visitors/to_sql.rb | 5 +++-- test/collectors/test_bind_collector.rb | 8 ++++---- test/collectors/test_sql_string.rb | 2 +- test/test_update_manager.rb | 2 +- test/visitors/test_bind_visitor.rb | 4 ++-- test/visitors/test_postgres.rb | 10 ++++++++++ test/visitors/test_to_sql.rb | 11 +++++++++-- 12 files changed, 48 insertions(+), 16 deletions(-) create mode 100644 lib/arel/nodes/bind_param.rb diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index 8ca89ca7bd429..fd2faaef3ab4f 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -5,8 +5,14 @@ module Arel module Collectors class SQLString < PlainString + def initialize(*) + super + @bind_index = 1 + end + def add_bind bind - self << bind.to_s + self << yield(@bind_index) + @bind_index += 1 self end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index ccccd471e2234..2c3c48881bb89 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -4,6 +4,7 @@ require 'arel/nodes/select_core' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' +require 'arel/nodes/bind_param' # terminal diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb new file mode 100644 index 0000000000000..160bc21b91adb --- /dev/null +++ b/lib/arel/nodes/bind_param.rb @@ -0,0 +1,6 @@ +module Arel + module Nodes + class BindParam < Node + end + end +end diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index b43288b29cf5f..2c56644b99514 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -10,8 +10,5 @@ def encode_with(coder) coder.scalar = self.to_s end end - - class BindParam < SqlLiteral - end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 60878ddd2006f..f55aaf30fe0f6 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -23,6 +23,10 @@ def visit_Arel_Nodes_DistinctOn o, collector collector << "DISTINCT ON ( " visit(o.expr, collector) << " )" end + + def visit_Arel_Nodes_BindParam o, collector + collector.add_bind(o) { |i| "$#{i}" } + end end end end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index a3f8cb565d0be..884076d987533 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -186,7 +186,8 @@ def visit_Arel_Nodes_Values o, collector len = o.expressions.length - 1 o.expressions.zip(o.columns).each_with_index { |(value, attr), i| - if Nodes::SqlLiteral === value + case value + when Nodes::SqlLiteral, Nodes::BindParam collector = visit value, collector else collector << quote(value, attr && column_for(attr)).to_s @@ -713,7 +714,7 @@ def visit_Arel_Attributes_Attribute o, collector def literal o, collector; collector << o.to_s; end def visit_Arel_Nodes_BindParam o, collector - collector.add_bind o + collector.add_bind(o) { "?" } end alias :visit_Arel_Nodes_SqlLiteral :literal diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb index 60532f061c031..da55244a82c8e 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_bind_collector.rb @@ -27,14 +27,14 @@ def ast_with_binds bv end def test_leaves_binds - node = Nodes::BindParam.new 'omg' + node = Nodes::BindParam.new list = compile node assert_equal node, list.first assert_equal node.class, list.first.class end def test_adds_strings - bv = Nodes::BindParam.new('?') + bv = Nodes::BindParam.new list = compile ast_with_binds bv assert_operator list.length, :>, 0 assert_equal bv, list.grep(Nodes::BindParam).first @@ -42,7 +42,7 @@ def test_adds_strings end def test_substitute_binds - bv = Nodes::BindParam.new('?') + bv = Nodes::BindParam.new collector = collect ast_with_binds bv values = collector.value @@ -59,7 +59,7 @@ def test_substitute_binds end def test_compile - bv = Nodes::BindParam.new('?') + bv = Nodes::BindParam.new collector = collect ast_with_binds bv sql = collector.compile ["hello", "world"] diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index 6d2e23151bcc7..cd121a136455b 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -27,7 +27,7 @@ def ast_with_binds bv end def test_compile - bv = Nodes::BindParam.new('?') + bv = Nodes::BindParam.new collector = collect ast_with_binds bv sql = collector.compile ["hello", "world"] diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index f1a019970d263..d636ab548fc75 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -12,7 +12,7 @@ module Arel table = Table.new(:users) um = Arel::UpdateManager.new Table.engine um.table table - um.set [[table[:name], (Arel::Nodes::BindParam.new '?')]] + um.set [[table[:name], Arel::Nodes::BindParam.new]] um.to_sql.must_be_like %{ UPDATE "users" SET "name" = ? } end diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index 333636ed514c7..79d340e5cd175 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -18,7 +18,7 @@ def setup def test_assignment_binds_are_substituted table = Table.new(:users) um = Arel::UpdateManager.new Table.engine - bp = Nodes::BindParam.new '?' + bp = Nodes::BindParam.new um.set [[table[:name], bp]] visitor = Class.new(Arel::Visitors::ToSql) { include Arel::Visitors::BindVisitor @@ -38,7 +38,7 @@ def test_visitor_yields_on_binds include Arel::Visitors::BindVisitor }.new nil - bp = Nodes::BindParam.new 'omg' + bp = Nodes::BindParam.new called = false visitor.accept(bp, collector) { called = true } assert called diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 3d646a7324e63..368feb59773d9 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -117,6 +117,16 @@ def compile node } end end + + describe "Nodes::BindParam" do + it "increments each bind param" do + query = @table[:name].eq(Arel::Nodes::BindParam.new) + .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + compile(query).must_be_like %{ + "users"."name" = $1 AND "users"."id" = $2 + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 9c18d74827305..7895866809a09 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -16,9 +16,16 @@ def compile node end it 'works with BindParams' do - node = Nodes::BindParam.new 'omg' + node = Nodes::BindParam.new sql = compile node - sql.must_be_like 'omg' + sql.must_be_like '?' + end + + it 'does not quote BindParams used as part of a Values' do + bp = Nodes::BindParam.new + values = Nodes::Values.new([bp]) + sql = compile values + sql.must_be_like 'VALUES (?)' end it 'can define a dispatch method' do From a04851702b0e8e694a92139c3ee9f3b1622f3f5d Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 18 Nov 2014 15:27:42 -0800 Subject: [PATCH 1340/1492] Use class objects rather than strings for the dispatch cache The only reason we're using strings is to pre-populate the cache, but `Class#name` returns a new string instance on every call. This is a pretty major source of memory usage. We don't technically need to pre-populate the cache, and not doing so allows us to go back to using cache objects --- lib/arel/visitors/reduce.rb | 8 ++++---- lib/arel/visitors/visitor.rb | 20 ++++++-------------- test/visitors/test_to_sql.rb | 2 +- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb index 1d74934fe5dce..9670cad27cb4a 100644 --- a/lib/arel/visitors/reduce.rb +++ b/lib/arel/visitors/reduce.rb @@ -10,14 +10,14 @@ def accept object, collector private def visit object, collector - send dispatch[object.class.name], object, collector + send dispatch[object.class], object, collector rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class.name], true) + raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| - respond_to?(dispatch[klass.name], true) + respond_to?(dispatch[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass - dispatch[object.class.name] = dispatch[superklass.name] + dispatch[object.class] = dispatch[superklass] retry end end diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 2152da9f0538f..bfe7342f0414a 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -12,17 +12,9 @@ def accept object private def self.dispatch_cache - dispatch = Hash.new do |hash, class_name| - hash[class_name] = "visit_#{(class_name || '').gsub('::', '_')}" + Hash.new do |hash, klass| + hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" end - - # pre-populate cache. FIXME: this should be passed in to each - # instance, but we can do that later. - self.class.private_instance_methods.sort.each do |name| - next unless name =~ /^visit_(.*)$/ - dispatch[$1.gsub('_', '::')] = name - end - dispatch end def get_dispatch_cache @@ -34,14 +26,14 @@ def dispatch end def visit object - send dispatch[object.class.name], object + send dispatch[object.class], object rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class.name], true) + raise e if respond_to?(dispatch[object.class], true) superklass = object.class.ancestors.find { |klass| - respond_to?(dispatch[klass.name], true) + respond_to?(dispatch[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass - dispatch[object.class.name] = dispatch[superklass.name] + dispatch[object.class] = dispatch[superklass] retry end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 7895866809a09..2e3f7f862452e 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -36,7 +36,7 @@ def compile node end def dispatch - { Arel::Table.name => 'hello' } + { Arel::Table => 'hello' } end }.new From 2eb824e939a1a147854b5c4bb42cd9c9d320bea3 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Thu, 20 Nov 2014 21:58:08 +0900 Subject: [PATCH 1341/1492] Support Oracle bind parameter value --- lib/arel/visitors/oracle.rb | 4 ++++ test/visitors/test_oracle.rb | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 91f6e0223eb07..ff9e38d0500ac 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -132,6 +132,10 @@ def split_order_string(string) array end + def visit_Arel_Nodes_BindParam o, collector + collector.add_bind(o) { |i| ":a#{i}" } + end + end end end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 29d70420845ce..41e77d93c000a 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -4,7 +4,8 @@ module Arel module Visitors describe 'the oracle visitor' do before do - @visitor = Oracle.new Table.engine.connection_pool + @visitor = Oracle.new Table.engine.connection + @table = Table.new(:users) end def compile node @@ -165,6 +166,16 @@ def compile node compile(node).must_be_like "FOR UPDATE" end end + + describe "Nodes::BindParam" do + it "increments each bind param" do + query = @table[:name].eq(Arel::Nodes::BindParam.new) + .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + compile(query).must_be_like %{ + "users"."name" = :a1 AND "users"."id" = :a2 + } + end + end end end end From c1dede5d26ecd81652bbdb7981c916edb08c5236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Nov 2014 19:54:12 -0200 Subject: [PATCH 1342/1492] Only include the lib folder in the gem --- Rakefile | 2 +- arel.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 0928e86ef3e52..148c0c660248c 100644 --- a/Rakefile +++ b/Rakefile @@ -14,7 +14,7 @@ specname = "arel.gemspec" deps = `git ls-files`.split("\n") - [specname] file specname => deps do - files = `git ls-files`.split("\n") - ["#{specname}.erb"] + files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] + `git ls-files -- lib`.split("\n") require 'erb' diff --git a/arel.gemspec b/arel.gemspec index d37c5cc64bbb3..829823643aef9 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] - s.files = [".gitignore",".travis.yml","Gemfile","History.txt","MIT-LICENSE.txt","README.markdown","Rakefile","arel.gemspec","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb","test/attributes/test_attribute.rb","test/collectors/test_bind_collector.rb","test/collectors/test_sql_string.rb","test/helper.rb","test/nodes/test_and.rb","test/nodes/test_as.rb","test/nodes/test_ascending.rb","test/nodes/test_bin.rb","test/nodes/test_binary.rb","test/nodes/test_count.rb","test/nodes/test_delete_statement.rb","test/nodes/test_descending.rb","test/nodes/test_distinct.rb","test/nodes/test_equality.rb","test/nodes/test_extract.rb","test/nodes/test_false.rb","test/nodes/test_grouping.rb","test/nodes/test_infix_operation.rb","test/nodes/test_insert_statement.rb","test/nodes/test_named_function.rb","test/nodes/test_node.rb","test/nodes/test_not.rb","test/nodes/test_or.rb","test/nodes/test_over.rb","test/nodes/test_select_core.rb","test/nodes/test_select_statement.rb","test/nodes/test_sql_literal.rb","test/nodes/test_sum.rb","test/nodes/test_table_alias.rb","test/nodes/test_true.rb","test/nodes/test_update_statement.rb","test/nodes/test_window.rb","test/support/fake_record.rb","test/test_attributes.rb","test/test_crud.rb","test/test_delete_manager.rb","test/test_factory_methods.rb","test/test_insert_manager.rb","test/test_select_manager.rb","test/test_table.rb","test/test_update_manager.rb","test/visitors/test_bind_visitor.rb","test/visitors/test_depth_first.rb","test/visitors/test_dispatch_contamination.rb","test/visitors/test_dot.rb","test/visitors/test_ibm_db.rb","test/visitors/test_informix.rb","test/visitors/test_mssql.rb","test/visitors/test_mysql.rb","test/visitors/test_oracle.rb","test/visitors/test_postgres.rb","test/visitors/test_sqlite.rb","test/visitors/test_to_sql.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') From fdfe66a5aaba6366f6c12b9a2f9cfae55ace90b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Nov 2014 19:54:45 -0200 Subject: [PATCH 1343/1492] Prepare for 6.0.0 --- History.txt | 2 +- lib/arel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 4fc06816a39fd..b161f5ca194be 100644 --- a/History.txt +++ b/History.txt @@ -1,4 +1,4 @@ -=== NEXT / 2014-02-10 +=== 6.0.0 / 2014-11-25 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index 018dc7593dbaa..1e3c51a2548ab 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '6.0.0.beta2' + VERSION = '6.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 1fefe71b1872c0a83f09231164863cd8dbb57174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 25 Nov 2014 19:55:48 -0200 Subject: [PATCH 1344/1492] Rake is a development dependecy --- arel.gemspec | 1 + arel.gemspec.erb | 1 + 2 files changed, 2 insertions(+) diff --git a/arel.gemspec b/arel.gemspec index 829823643aef9..43fbc680e89a2 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -21,4 +21,5 @@ Gem::Specification.new do |s| s.add_development_dependency('minitest', '~> 5.4') s.add_development_dependency('rdoc', '~> 4.0') + s.add_development_dependency('rake') end diff --git a/arel.gemspec.erb b/arel.gemspec.erb index d27127b2e4c1d..7ed75226cabee 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -21,4 +21,5 @@ Gem::Specification.new do |s| s.add_development_dependency('minitest', '~> 5.4') s.add_development_dependency('rdoc', '~> 4.0') + s.add_development_dependency('rake') end From 8572455d4cf7a61462bde7cef2d3724685c1c44c Mon Sep 17 00:00:00 2001 From: Nihad Abbasov Date: Wed, 17 Apr 2013 18:13:29 +0500 Subject: [PATCH 1345/1492] remove extra space before 'ORDER BY' --- lib/arel/visitors/to_sql.rb | 1 - test/visitors/test_to_sql.rb | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 884076d987533..30c86341190ba 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -211,7 +211,6 @@ def visit_Arel_Nodes_SelectStatement o, collector } unless o.orders.empty? - collector << SPACE collector << ORDER_BY len = o.orders.length - 1 o.orders.each_with_index { |x, i| diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 2e3f7f862452e..04fca8024b689 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -181,6 +181,13 @@ def dispatch assert_match(/LIMIT 'omg'/, compile(sc)) end + it "should contain a single space before ORDER BY" do + table = Table.new(:users) + test = table.order(table[:name]) + sql = compile test + assert_match(/"users" ORDER BY/, sql) + end + it "should quote LIMIT without column type coercion" do table = Table.new(:users) sc = table.where(table[:name].eq(0)).take(1).ast @@ -291,7 +298,7 @@ def dispatch end it "should visit_Arel_Nodes_Assignment" do - column = @table["id"] + column = @table["id"] node = Nodes::Assignment.new( Nodes::UnqualifiedColumn.new(column), Nodes::UnqualifiedColumn.new(column) From ec083687a96af1f35f9fb9e75611cc4bf4f5bf81 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 26 Nov 2014 15:00:05 -0700 Subject: [PATCH 1346/1492] Remove deprecated method "Table#primary_key" The only place this method was still used is on the MSSQL visitor. The visitor has all of the objects required to inline this lookup there. Since the `primary_key` method on the connection adapter will perform a query when called, we can cache the result on the visitor. --- lib/arel/table.rb | 14 -------------- lib/arel/visitors/mssql.rb | 21 ++++++++++++++++++--- test/visitors/test_mssql.rb | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 01d4561ff1b9a..fb86c03404f79 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -17,7 +17,6 @@ def initialize name, engine = Table.engine @columns = nil @aliases = [] @table_alias = nil - @primary_key = nil if Hash === engine @engine = engine[:engine] || Table.engine @@ -29,19 +28,6 @@ def initialize name, engine = Table.engine 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 diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 0e5b75ec59f6f..7c65ad33f27b2 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -3,6 +3,11 @@ module Visitors class MSSQL < Arel::Visitors::ToSql RowNumber = Struct.new :children + def initialize(*) + @primary_keys = {} + super + end + private # `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate @@ -81,10 +86,20 @@ def select_count? x end # FIXME raise exception of there is no pk? - # FIXME!! Table.primary_key will be deprecated. What is the replacement?? def find_left_table_pk o - return o.primary_key if o.instance_of? Arel::Table - find_left_table_pk o.left if o.kind_of? Arel::Nodes::Join + if o.kind_of?(Arel::Nodes::Join) + find_left_table_pk(o.left) + elsif o.instance_of?(Arel::Table) + find_primary_key(o) + end + end + + def find_primary_key(o) + @primary_keys[o.name] ||= begin + primary_key_name = @connection.primary_key(o.name) + # some tables might be without primary key + primary_key_name && o[primary_key_name] + end end end end diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index a3efcb8b27729..7574aeb0a2613 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -26,6 +26,25 @@ def compile node sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY \"users\".\"id\") as _row_num FROM \"users\") as _t WHERE _row_num BETWEEN 1 AND 10" end + it 'caches the PK lookup for order' do + connection = MiniTest::Mock.new + connection.expect(:primary_key, ["id"], ["users"]) + + # We don't care how many times these methods are called + def connection.quote_table_name(*); ""; end + def connection.quote_column_name(*); ""; end + + @visitor = MSSQL.new(connection) + stmt = Nodes::SelectStatement.new + stmt.cores.first.from = @table + stmt.limit = Nodes::Limit.new(10) + + compile(stmt) + compile(stmt) + + connection.verify + end + it 'should go over query ORDER BY if .order()' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) From 7508284800f67b4611c767bff9eae7045674b66f Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 26 Nov 2014 13:45:31 -0700 Subject: [PATCH 1347/1492] Remove engine from the constructor arguments `Arel::Table` It is never used outside of convenience methods which are only used in tests. In practice, it just made constructing tables more complicated on the rails side. This is the minimum possible change to remove the constructor argument, but continue to have the tests passing. I'm not sure if we have a reason to keep `project` and friends, and the solution might actually just be to remove the engine from `SelectManager` and friends. As such I've held off on deleting those methods. We need to figure out what to do with `Table#from`. It's old invocation, which read `table.from(table)` was certainly nonsensical. --- lib/arel/table.rb | 61 ++++++++++++---------------------- test/nodes/test_table_alias.rb | 13 ++++---- test/test_select_manager.rb | 32 +++++++++--------- test/test_table.rb | 46 ++++--------------------- 4 files changed, 49 insertions(+), 103 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index fb86c03404f79..d534c44fa18d2 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -11,20 +11,18 @@ class << self; attr_accessor :engine; end # TableAlias and Table both have a #table_name which is the name of the underlying table alias :table_name :name - def initialize name, engine = Table.engine + def initialize name, options = {} @name = name.to_s - @engine = engine @columns = nil @aliases = [] - @table_alias = 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 + @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 = options[:as] + if @table_alias.to_s == @name + @table_alias = nil end end @@ -34,12 +32,12 @@ def alias name = "#{self.name}_2" end end - def from table - SelectManager.new(@engine, table) + def from engine = Table.engine + SelectManager.new(engine, self) end def join relation, klass = Nodes::InnerJoin - return from(self) unless relation + return from unless relation case relation when String, Nodes::SqlLiteral @@ -47,7 +45,7 @@ def join relation, klass = Nodes::InnerJoin klass = Nodes::StringJoin end - from(self).join(relation, klass) + from.join(relation, klass) end def outer_join relation @@ -55,55 +53,39 @@ def outer_join relation end def group *columns - from(self).group(*columns) + from.group(*columns) end def order *expr - from(self).order(*expr) + from.order(*expr) end def where condition - from(self).where condition + from.where condition end def project *things - from(self).project(*things) + from.project(*things) end def take amount - from(self).take amount + from.take amount end def skip amount - from(self).skip amount + from.skip amount end def having expr - from(self).having expr + from.having expr end def [] name ::Arel::Attribute.new self, name end - def select_manager - SelectManager.new(@engine) - end - - def insert_manager - InsertManager.new(@engine) - end - - def update_manager - UpdateManager.new(@engine) - end - - def delete_manager - DeleteManager.new(@engine) - end - def hash - # Perf note: aliases, table alias and engine is excluded from the hash + # Perf note: aliases and table alias is excluded from the hash # aliases can have a loop back to this table breaking hashes in parent # relations, for the vast majority of cases @name is unique to a query @name.hash @@ -112,7 +94,6 @@ def hash 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 diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb index 4aafd12b79dce..e30f97b748ad5 100644 --- a/test/nodes/test_table_alias.rb +++ b/test/nodes/test_table_alias.rb @@ -5,27 +5,26 @@ 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) + relation = OpenStruct.new(engine: 'vroom') node = TableAlias.new relation, :foo - node.engine.must_equal engine + node.engine.must_equal 'vroom' end describe 'equality' do it 'is equal with equal ivars' do - relation1 = Table.new(:users, 'vroom') + relation1 = Table.new(:users) node1 = TableAlias.new relation1, :foo - relation2 = Table.new(:users, 'vroom') + relation2 = Table.new(:users) node2 = TableAlias.new relation2, :foo array = [node1, node2] assert_equal 1, array.uniq.size end it 'is not equal with different ivars' do - relation1 = Table.new(:users, 'vroom') + relation1 = Table.new(:users) node1 = TableAlias.new relation1, :foo - relation2 = Table.new(:users, 'vroom') + relation2 = Table.new(:users) node2 = TableAlias.new relation2, :bar array = [node1, node2] assert_equal 2, array.uniq.size diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 78b3a25928bd0..f55b3877ebe21 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -110,14 +110,14 @@ def test_manager_stores_bind_values describe 'having' do it 'converts strings to SQLLiterals' do table = Table.new :users - mgr = table.from table + mgr = table.from 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 = table.from mgr.having 'foo' mgr.having 'bar' mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } @@ -125,7 +125,7 @@ def test_manager_stores_bind_values it 'can have multiple items specified together' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.having 'foo', 'bar' mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } end @@ -135,7 +135,7 @@ def test_manager_stores_bind_values it 'converts to sqlliterals' do table = Table.new :users right = table.alias - mgr = table.from table + mgr = table.from mgr.join(right).on("omg") mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg } end @@ -143,7 +143,7 @@ def test_manager_stores_bind_values it 'converts to sqlliterals with multiple items' do table = Table.new :users right = table.alias - mgr = table.from table + mgr = table.from mgr.join(right).on("omg", "123") mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg AND 123 } end @@ -153,7 +153,7 @@ def test_manager_stores_bind_values describe 'clone' do it 'creates new cores' do table = Table.new :users, :as => 'foo' - mgr = table.from table + mgr = table.from m2 = mgr.clone m2.project "foo" mgr.to_sql.wont_equal m2.to_sql @@ -161,7 +161,7 @@ def test_manager_stores_bind_values it 'makes updates to the correct copy' do table = Table.new :users, :as => 'foo' - mgr = table.from table + mgr = table.from m2 = mgr.clone m3 = m2.clone m2.project "foo" @@ -173,7 +173,7 @@ def test_manager_stores_bind_values describe 'initialize' do it 'uses alias in sql' do table = Table.new :users, :as => 'foo' - mgr = table.from table + mgr = table.from mgr.skip 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" "foo" OFFSET 10 } end @@ -182,14 +182,14 @@ def test_manager_stores_bind_values describe 'skip' do it 'should add an offset' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.skip 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } end it 'should chain' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.skip(10).to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } end end @@ -197,14 +197,14 @@ def test_manager_stores_bind_values describe 'offset' do it 'should add an offset' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.offset = 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } end it 'should remove an offset' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.offset = 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } @@ -214,7 +214,7 @@ def test_manager_stores_bind_values it 'should return the offset' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.offset = 10 assert_equal 10, mgr.offset end @@ -379,13 +379,13 @@ def test_manager_stores_bind_values describe 'ast' do it 'should return the ast' do table = Table.new :users - mgr = table.from table + mgr = table.from assert mgr.ast end it 'should allow orders to work when the ast is grepped' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.project Arel.sql '*' mgr.from table mgr.orders << Arel::Nodes::Ascending.new(Arel.sql('foo')) @@ -406,7 +406,7 @@ def test_manager_stores_bind_values # This should fail on other databases it 'adds a lock node' do table = Table.new :users - mgr = table.from table + mgr = table.from mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" FOR UPDATE } end end diff --git a/test/test_table.rb b/test/test_table.rb index 14256475ecc89..394a7557276fe 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -47,12 +47,6 @@ module Arel assert_equal "INSERT INTO \"users\" VALUES(NULL)", im.to_sql end - it 'should return IM from insert_manager' do - im = @relation.insert_manager - assert_kind_of Arel::InsertManager, im - assert_equal im.engine, @relation.engine - end - describe 'skip' do it 'should add an offset' do sm = @relation.skip 2 @@ -60,29 +54,6 @@ module Arel end end - describe 'select_manager' do - it 'should return an empty select manager' do - sm = @relation.select_manager - sm.to_sql.must_be_like 'SELECT' - end - end - - describe 'update_manager' do - it 'should return an update manager' do - um = @relation.update_manager - assert_kind_of Arel::UpdateManager, um - assert_equal um.engine, @relation.engine - end - end - - describe 'delete_manager' do - it 'should return a delete manager' do - dm = @relation.delete_manager - assert_kind_of Arel::DeleteManager, dm - assert_equal dm.engine, @relation.engine - end - end - describe 'having' do it 'adds a having clause' do mgr = @relation.having @relation[:id].eq(10) @@ -149,14 +120,9 @@ module Arel end describe 'new' do - it 'should accept an engine' do - rel = Table.new :users, 'foo' - rel.engine.must_equal 'foo' - end - it 'should accept a hash' do - rel = Table.new :users, :engine => 'foo' - rel.engine.must_equal 'foo' + rel = Table.new :users, :as => 'foo' + rel.table_alias.must_equal 'foo' end it 'ignores as if it equals name' do @@ -228,10 +194,10 @@ module Arel describe 'equality' do it 'is equal with equal ivars' do - relation1 = Table.new(:users, 'vroom') + relation1 = Table.new(:users) relation1.aliases = %w[a b c] relation1.table_alias = 'zomg' - relation2 = Table.new(:users, 'vroom') + relation2 = Table.new(:users) relation2.aliases = %w[a b c] relation2.table_alias = 'zomg' array = [relation1, relation2] @@ -239,10 +205,10 @@ module Arel end it 'is not equal with different ivars' do - relation1 = Table.new(:users, 'vroom') + relation1 = Table.new(:users) relation1.aliases = %w[a b c] relation1.table_alias = 'zomg' - relation2 = Table.new(:users, 'vroom') + relation2 = Table.new(:users) relation2.aliases = %w[x y z] relation2.table_alias = 'zomg' array = [relation1, relation2] From 98fc25991137ee09b6800578117f8c1c322680f2 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sat, 29 Nov 2014 17:22:17 -0700 Subject: [PATCH 1348/1492] Remove `engine` from `TreeManager` and subclasses This constructor parameter was unused for everything except the convenience methods `to_sql` and `where_sql`. We can pass the engine into those methods directly. --- lib/arel/crud.rb | 6 +- lib/arel/delete_manager.rb | 2 +- lib/arel/insert_manager.rb | 2 +- lib/arel/nodes/table_alias.rb | 4 - lib/arel/select_manager.rb | 8 +- lib/arel/table.rb | 7 +- lib/arel/tree_manager.rb | 11 +- lib/arel/update_manager.rb | 2 +- test/collectors/test_bind_collector.rb | 2 +- test/collectors/test_sql_string.rb | 2 +- test/nodes/test_table_alias.rb | 7 - test/test_delete_manager.rb | 10 +- test/test_insert_manager.rb | 32 ++--- test/test_select_manager.rb | 192 ++++++++++++------------- test/test_table.rb | 4 - test/test_update_manager.rb | 26 ++-- test/visitors/test_bind_visitor.rb | 2 +- 17 files changed, 149 insertions(+), 170 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 6f4962cbfec12..2dfe27445c14d 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -3,7 +3,7 @@ module Arel # FIXME hopefully we can remove this module Crud def compile_update values, pk - um = UpdateManager.new @engine + um = UpdateManager.new if Nodes::SqlLiteral === values relation = @ctx.from @@ -26,11 +26,11 @@ def compile_insert values end def create_insert - InsertManager.new @engine + InsertManager.new end def compile_delete - dm = DeleteManager.new @engine + dm = DeleteManager.new dm.wheres = @ctx.wheres dm.from @ctx.froms dm diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index b4c61f708f423..af33c60740b99 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -1,6 +1,6 @@ module Arel class DeleteManager < Arel::TreeManager - def initialize engine + def initialize super @ast = Nodes::DeleteStatement.new @ctx = @ast diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index 8839dd8181504..7829c3f4f9f15 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -1,6 +1,6 @@ module Arel class InsertManager < Arel::TreeManager - def initialize engine + def initialize super @ast = Nodes::InsertStatement.new end diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index ebfcb58e640de..b32f057117ca9 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -12,10 +12,6 @@ def [] name def table_name relation.respond_to?(:name) ? relation.name : name end - - def engine - relation.engine - end end end end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 5a05e7e1818d9..dd1ae37b653ff 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -6,8 +6,8 @@ class SelectManager < Arel::TreeManager STRING_OR_SYMBOL_CLASS = [Symbol, String] - def initialize engine, table = nil - super(engine) + def initialize table = nil + super() @ast = Nodes::SelectStatement.new @ctx = @ast.cores.last from table @@ -176,10 +176,10 @@ def orders @ast.orders end - def where_sql + def where_sql engine = Table.engine return if @ctx.wheres.empty? - viz = Visitors::WhereSql.new @engine.connection + viz = Visitors::WhereSql.new engine.connection Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index d534c44fa18d2..2c7a2b7f9344c 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -6,7 +6,7 @@ class Table @engine = nil class << self; attr_accessor :engine; end - attr_accessor :name, :engine, :aliases, :table_alias + attr_accessor :name, :aliases, :table_alias # TableAlias and Table both have a #table_name which is the name of the underlying table alias :table_name :name @@ -15,7 +15,6 @@ def initialize name, options = {} @name = name.to_s @columns = nil @aliases = [] - @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 @@ -32,8 +31,8 @@ def alias name = "#{self.name}_2" end end - def from engine = Table.engine - SelectManager.new(engine, self) + def from + SelectManager.new(self) end def join relation, klass = Nodes::InnerJoin diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 8bff97af78187..5278ab06a14e9 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -8,8 +8,7 @@ class TreeManager attr_accessor :bind_values - def initialize engine - @engine = engine + def initialize @ctx = nil @bind_values = [] end @@ -20,13 +19,9 @@ def to_dot collector.value end - def visitor - engine.connection.visitor - end - - def to_sql + def to_sql engine = Table.engine collector = Arel::Collectors::SQLString.new - collector = visitor.accept @ast, collector + collector = engine.connection.visitor.accept @ast, collector collector.value end diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index db8cf05f7667d..36fb74fe7c6d1 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -1,6 +1,6 @@ module Arel class UpdateManager < Arel::TreeManager - def initialize engine + def initialize super @ast = Nodes::UpdateStatement.new @ctx = @ast diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb index da55244a82c8e..fc7df2fc45521 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_bind_collector.rb @@ -20,7 +20,7 @@ def compile node def ast_with_binds bv table = Table.new(:users) - manager = Arel::SelectManager.new Table.engine, table + manager = Arel::SelectManager.new table manager.where(table[:age].eq(bv)) manager.where(table[:name].eq(bv)) manager.ast diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index cd121a136455b..37a9e41f71049 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -20,7 +20,7 @@ def compile node def ast_with_binds bv table = Table.new(:users) - manager = Arel::SelectManager.new Table.engine, table + manager = Arel::SelectManager.new table manager.where(table[:age].eq(bv)) manager.where(table[:name].eq(bv)) manager.ast diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb index e30f97b748ad5..57c9a42fc660f 100644 --- a/test/nodes/test_table_alias.rb +++ b/test/nodes/test_table_alias.rb @@ -4,13 +4,6 @@ module Arel module Nodes describe 'table alias' do - it 'has an #engine which delegates to the relation' do - relation = OpenStruct.new(engine: 'vroom') - - node = TableAlias.new relation, :foo - node.engine.must_equal 'vroom' - end - describe 'equality' do it 'is equal with equal ivars' do relation1 = Table.new(:users) diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index fd12c5acd2fec..b16b52cb9e77b 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -4,21 +4,21 @@ module Arel describe 'delete manager' do describe 'new' do it 'takes an engine' do - Arel::DeleteManager.new Table.engine + Arel::DeleteManager.new end end describe 'from' do it 'uses from' do table = Table.new(:users) - dm = Arel::DeleteManager.new Table.engine + dm = Arel::DeleteManager.new dm.from table dm.to_sql.must_be_like %{ DELETE FROM "users" } end it 'chains' do table = Table.new(:users) - dm = Arel::DeleteManager.new Table.engine + dm = Arel::DeleteManager.new dm.from(table).must_equal dm end end @@ -26,7 +26,7 @@ module Arel describe 'where' do it 'uses where values' do table = Table.new(:users) - dm = Arel::DeleteManager.new Table.engine + dm = Arel::DeleteManager.new dm.from table dm.where table[:id].eq(10) dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10} @@ -34,7 +34,7 @@ module Arel it 'chains' do table = Table.new(:users) - dm = Arel::DeleteManager.new Table.engine + dm = Arel::DeleteManager.new dm.where(table[:id].eq(10)).must_equal dm end end diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 9cfd01262b3e3..4289b0fa8cf73 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -4,13 +4,13 @@ module Arel describe 'insert manager' do describe 'new' do it 'takes an engine' do - Arel::InsertManager.new Table.engine + Arel::InsertManager.new end end describe 'insert' do it 'can create a Values node' do - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new values = manager.create_values %w{ a b }, %w{ c d } assert_kind_of Arel::Nodes::Values, values @@ -19,7 +19,7 @@ module Arel end it 'allows sql literals' do - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into Table.new(:users) manager.values = manager.create_values [Arel.sql('*')], %w{ a } manager.to_sql.must_be_like %{ @@ -29,7 +29,7 @@ module Arel it "inserts false" do table = Table.new(:users) - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.insert [[table[:bool], false]] manager.to_sql.must_be_like %{ @@ -39,7 +39,7 @@ module Arel it "inserts null" do table = Table.new(:users) - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.insert [[table[:id], nil]] manager.to_sql.must_be_like %{ INSERT INTO "users" ("id") VALUES (NULL) @@ -48,7 +48,7 @@ module Arel it "inserts time" do table = Table.new(:users) - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new time = Time.now attribute = table[:created_at] @@ -61,7 +61,7 @@ module Arel it 'takes a list of lists' do table = Table.new(:users) - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into table manager.insert [[table[:id], 1], [table[:name], 'aaron']] manager.to_sql.must_be_like %{ @@ -71,7 +71,7 @@ module Arel it 'defaults the table' do table = Table.new(:users) - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.insert [[table[:id], 1], [table[:name], 'aaron']] manager.to_sql.must_be_like %{ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') @@ -80,7 +80,7 @@ module Arel it 'noop for empty list' do table = Table.new(:users) - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.insert [[table[:id], 1]] manager.insert [] manager.to_sql.must_be_like %{ @@ -91,13 +91,13 @@ module Arel describe 'into' do it 'takes a Table and chains' do - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into(Table.new(:users)).must_equal manager end it 'converts to sql' do table = Table.new :users - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into table manager.to_sql.must_be_like %{ INSERT INTO "users" @@ -108,7 +108,7 @@ module Arel describe 'columns' do it "converts to sql" do table = Table.new :users - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into table manager.columns << table[:id] manager.to_sql.must_be_like %{ @@ -120,7 +120,7 @@ module Arel describe "values" do it "converts to sql" do table = Table.new :users - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into table manager.values = Nodes::Values.new [1] @@ -133,7 +133,7 @@ module Arel describe "combo" do it "combines columns and values list in order" do table = Table.new :users - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into table manager.values = Nodes::Values.new [1, 'aaron'] @@ -150,10 +150,10 @@ module Arel it "accepts a select query in place of a VALUES clause" do table = Table.new :users - manager = Arel::InsertManager.new Table.engine + manager = Arel::InsertManager.new manager.into table - select = Arel::SelectManager.new Table.engine + select = Arel::SelectManager.new select.project Arel.sql('1') select.project Arel.sql('"aaron"') diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index f55b3877ebe21..809f0de8df1f9 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -4,13 +4,13 @@ module Arel describe 'select manager' do def test_join_sources - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.join_sources << Arel::Nodes::StringJoin.new(Nodes.build_quoted('foo')) assert_equal "SELECT FROM 'foo'", manager.to_sql end def test_manager_stores_bind_values - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new assert_equal [], manager.bind_values manager.bind_values = [1] assert_equal [1], manager.bind_values @@ -20,7 +20,7 @@ def test_manager_stores_bind_values describe 'project' do it 'accepts symbols as sql literals' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project :id manager.from table manager.to_sql.must_be_like %{ @@ -32,7 +32,7 @@ def test_manager_stores_bind_values describe 'order' do it 'accepts symbols' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order :foo @@ -43,7 +43,7 @@ def test_manager_stores_bind_values describe 'group' do it 'takes a symbol' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.group :foo manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } @@ -52,7 +52,7 @@ def test_manager_stores_bind_values describe 'as' do it 'makes an AS node by grouping the AST' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new as = manager.as(Arel.sql('foo')) assert_kind_of Arel::Nodes::Grouping, as.left assert_equal manager.ast, as.left.expr @@ -60,18 +60,18 @@ def test_manager_stores_bind_values end it 'converts right to SqlLiteral if a string' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new as = manager.as('foo') assert_kind_of Arel::Nodes::SqlLiteral, as.right end it 'can make a subselect' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Arel.star manager.from Arel.sql('zomg') as = manager.as(Arel.sql('foo')) - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Arel.sql('name') manager.from as manager.to_sql.must_be_like "SELECT name FROM (SELECT * FROM zomg) foo" @@ -81,7 +81,7 @@ def test_manager_stores_bind_values describe 'from' do it 'ignores strings when table of same name exists' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.from 'users' @@ -91,9 +91,9 @@ def test_manager_stores_bind_values it 'should support any ast' do table = Table.new :users - manager1 = Arel::SelectManager.new Table.engine + manager1 = Arel::SelectManager.new - manager2 = Arel::SelectManager.new Table.engine + manager2 = Arel::SelectManager.new manager2.project(Arel.sql('*')) manager2.from table @@ -223,7 +223,7 @@ def test_manager_stores_bind_values describe 'exists' do it 'should create an exists clause' do table = Table.new(:users) - manager = Arel::SelectManager.new Table.engine, table + manager = Arel::SelectManager.new table manager.project Nodes::SqlLiteral.new '*' m2 = Arel::SelectManager.new(manager.engine) m2.project manager.exists @@ -232,7 +232,7 @@ def test_manager_stores_bind_values it 'can be aliased' do table = Table.new(:users) - manager = Arel::SelectManager.new Table.engine, table + manager = Arel::SelectManager.new table manager.project Nodes::SqlLiteral.new '*' m2 = Arel::SelectManager.new(manager.engine) m2.project manager.exists.as('foo') @@ -243,11 +243,11 @@ def test_manager_stores_bind_values describe 'union' do before do table = Table.new :users - @m1 = Arel::SelectManager.new Table.engine, table + @m1 = Arel::SelectManager.new table @m1.project Arel.star @m1.where(table[:age].lt(18)) - @m2 = Arel::SelectManager.new Table.engine, table + @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].gt(99)) @@ -278,11 +278,11 @@ def test_manager_stores_bind_values describe 'intersect' do before do table = Table.new :users - @m1 = Arel::SelectManager.new Table.engine, table + @m1 = Arel::SelectManager.new table @m1.project Arel.star @m1.where(table[:age].gt(18)) - @m2 = Arel::SelectManager.new Table.engine, table + @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].lt(99)) @@ -305,11 +305,11 @@ def test_manager_stores_bind_values describe 'except' do before do table = Table.new :users - @m1 = Arel::SelectManager.new Table.engine, table + @m1 = Arel::SelectManager.new table @m1.project Arel.star @m1.where(table[:age].between(18..60)) - @m2 = Arel::SelectManager.new Table.engine, table + @m2 = Arel::SelectManager.new table @m2.project Arel.star @m2.where(table[:age].between(40..99)) end @@ -351,17 +351,17 @@ def test_manager_stores_bind_values replies = Table.new(:replies) replies_id = replies[:id] - recursive_term = Arel::SelectManager.new Table.engine + recursive_term = Arel::SelectManager.new recursive_term.from(comments).project(comments_id, comments_parent_id).where(comments_id.eq 42) - non_recursive_term = Arel::SelectManager.new Table.engine + non_recursive_term = Arel::SelectManager.new non_recursive_term.from(comments).project(comments_id, comments_parent_id).join(replies).on(comments_parent_id.eq replies_id) union = recursive_term.union(non_recursive_term) as_statement = Arel::Nodes::As.new replies, union - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.with(:recursive, as_statement).from(replies).project(Arel.star) sql = manager.to_sql @@ -396,7 +396,7 @@ def test_manager_stores_bind_values describe 'taken' do it 'should return limit' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.take 10 manager.taken.must_equal 10 end @@ -414,7 +414,7 @@ def test_manager_stores_bind_values describe 'orders' do it 'returns order clauses' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new order = table[:id] manager.order table[:id] manager.orders.must_equal [order] @@ -424,7 +424,7 @@ def test_manager_stores_bind_values describe 'order' do it 'generates order clauses' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id] @@ -436,7 +436,7 @@ def test_manager_stores_bind_values # FIXME: I would like to deprecate this it 'takes *args' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id], table[:name] @@ -447,13 +447,13 @@ def test_manager_stores_bind_values it 'chains' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.order(table[:id]).must_equal manager end it 'has order attributes' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Nodes::SqlLiteral.new '*' manager.from table manager.order table[:id].desc @@ -468,7 +468,7 @@ def test_manager_stores_bind_values left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from left manager.join(right).on(predicate, predicate) @@ -484,7 +484,7 @@ def test_manager_stores_bind_values left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from left manager.join(right).on( @@ -503,12 +503,12 @@ def test_manager_stores_bind_values end it 'should hand back froms' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new assert_equal [], relation.froms end it 'should create and nodes' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new children = ['foo', 'bar', 'baz'] clause = relation.create_and children assert_kind_of Arel::Nodes::And, clause @@ -516,13 +516,13 @@ def test_manager_stores_bind_values end it 'should create insert managers' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new insert = relation.create_insert assert_kind_of Arel::InsertManager, insert end it 'should create join nodes' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new join = relation.create_join 'foo', 'bar' assert_kind_of Arel::Nodes::InnerJoin, join assert_equal 'foo', join.left @@ -530,7 +530,7 @@ def test_manager_stores_bind_values end it 'should create join nodes with a full outer join klass' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new join = relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin assert_kind_of Arel::Nodes::FullOuterJoin, join assert_equal 'foo', join.left @@ -538,7 +538,7 @@ def test_manager_stores_bind_values end it 'should create join nodes with a outer join klass' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin assert_kind_of Arel::Nodes::OuterJoin, join assert_equal 'foo', join.left @@ -546,7 +546,7 @@ def test_manager_stores_bind_values end it 'should create join nodes with a right outer join klass' do - relation = Arel::SelectManager.new Table.engine + relation = Arel::SelectManager.new join = relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin assert_kind_of Arel::Nodes::RightOuterJoin, join assert_equal 'foo', join.left @@ -558,7 +558,7 @@ def test_manager_stores_bind_values left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from left manager.join(right).on(predicate) @@ -573,7 +573,7 @@ def test_manager_stores_bind_values left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from left manager.join(right, Nodes::OuterJoin).on(predicate) @@ -585,7 +585,7 @@ def test_manager_stores_bind_values end it 'noops on nil' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.join(nil).must_equal manager end end @@ -595,7 +595,7 @@ def test_manager_stores_bind_values left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from left manager.outer_join(right).on(predicate) @@ -607,7 +607,7 @@ def test_manager_stores_bind_values end it 'noops on nil' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.outer_join(nil).must_equal manager end end @@ -617,7 +617,7 @@ def test_manager_stores_bind_values it 'returns inner join sql' do table = Table.new :users aliaz = table.alias - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from Nodes::InnerJoin.new(aliaz, table[:id].eq(aliaz[:id])) assert_match 'INNER JOIN "users" "users_2" "users"."id" = "users_2"."id"', manager.to_sql @@ -626,7 +626,7 @@ def test_manager_stores_bind_values it 'returns outer join sql' do table = Table.new :users aliaz = table.alias - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from Nodes::OuterJoin.new(aliaz, table[:id].eq(aliaz[:id])) assert_match 'LEFT OUTER JOIN "users" "users_2" "users"."id" = "users_2"."id"', manager.to_sql @@ -636,7 +636,7 @@ def test_manager_stores_bind_values users = Table.new :users comments = Table.new :comments - counts = comments.from(comments). + counts = comments.from. group(comments[:user_id]). project( comments[:user_id].as("user_id"), @@ -666,7 +666,7 @@ def test_manager_stores_bind_values end it 'returns string join sql' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from Nodes::StringJoin.new(Nodes.build_quoted('hello')) assert_match "'hello'", manager.to_sql end @@ -675,7 +675,7 @@ def test_manager_stores_bind_values describe 'group' do it 'takes an attribute' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.group table[:id] manager.to_sql.must_be_like %{ @@ -685,13 +685,13 @@ def test_manager_stores_bind_values it 'chains' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.group(table[:id]).must_equal manager end it 'takes multiple args' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.group table[:id], table[:name] manager.to_sql.must_be_like %{ @@ -702,7 +702,7 @@ def test_manager_stores_bind_values # FIXME: backwards compat it 'makes strings literals' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.group 'foo' manager.to_sql.must_be_like %{ SELECT FROM "users" GROUP BY foo } @@ -712,7 +712,7 @@ def test_manager_stores_bind_values describe 'window definition' do it 'can be empty' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window') manager.to_sql.must_be_like %{ @@ -722,7 +722,7 @@ def test_manager_stores_bind_values it 'takes an order' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').order(table['foo'].asc) manager.to_sql.must_be_like %{ @@ -732,7 +732,7 @@ def test_manager_stores_bind_values it 'takes an order with multiple columns' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').order(table['foo'].asc, table['bar'].desc) manager.to_sql.must_be_like %{ @@ -742,7 +742,7 @@ def test_manager_stores_bind_values it 'takes a partition' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').partition(table['bar']) manager.to_sql.must_be_like %{ @@ -752,7 +752,7 @@ def test_manager_stores_bind_values it 'takes a partition and an order' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').partition(table['foo']).order(table['foo'].asc) manager.to_sql.must_be_like %{ @@ -763,7 +763,7 @@ def test_manager_stores_bind_values it 'takes a partition with multiple columns' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').partition(table['bar'], table['baz']) manager.to_sql.must_be_like %{ @@ -773,7 +773,7 @@ def test_manager_stores_bind_values it 'takes a rows frame, unbounded preceding' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').rows(Arel::Nodes::Preceding.new) manager.to_sql.must_be_like %{ @@ -783,7 +783,7 @@ def test_manager_stores_bind_values it 'takes a rows frame, bounded preceding' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').rows(Arel::Nodes::Preceding.new(5)) manager.to_sql.must_be_like %{ @@ -793,7 +793,7 @@ def test_manager_stores_bind_values it 'takes a rows frame, unbounded following' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').rows(Arel::Nodes::Following.new) manager.to_sql.must_be_like %{ @@ -803,7 +803,7 @@ def test_manager_stores_bind_values it 'takes a rows frame, bounded following' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').rows(Arel::Nodes::Following.new(5)) manager.to_sql.must_be_like %{ @@ -813,7 +813,7 @@ def test_manager_stores_bind_values it 'takes a rows frame, current row' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').rows(Arel::Nodes::CurrentRow.new) manager.to_sql.must_be_like %{ @@ -823,7 +823,7 @@ def test_manager_stores_bind_values it 'takes a rows frame, between two delimiters' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table window = manager.window('a_window') window.frame( @@ -840,7 +840,7 @@ def test_manager_stores_bind_values it 'takes a range frame, unbounded preceding' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').range(Arel::Nodes::Preceding.new) manager.to_sql.must_be_like %{ @@ -850,7 +850,7 @@ def test_manager_stores_bind_values it 'takes a range frame, bounded preceding' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').range(Arel::Nodes::Preceding.new(5)) manager.to_sql.must_be_like %{ @@ -860,7 +860,7 @@ def test_manager_stores_bind_values it 'takes a range frame, unbounded following' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').range(Arel::Nodes::Following.new) manager.to_sql.must_be_like %{ @@ -870,7 +870,7 @@ def test_manager_stores_bind_values it 'takes a range frame, bounded following' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').range(Arel::Nodes::Following.new(5)) manager.to_sql.must_be_like %{ @@ -880,7 +880,7 @@ def test_manager_stores_bind_values it 'takes a range frame, current row' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.window('a_window').range(Arel::Nodes::CurrentRow.new) manager.to_sql.must_be_like %{ @@ -890,7 +890,7 @@ def test_manager_stores_bind_values it 'takes a range frame, between two delimiters' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table window = manager.window('a_window') window.frame( @@ -909,7 +909,7 @@ def test_manager_stores_bind_values describe 'delete' do it "copies from" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table stmt = manager.compile_delete @@ -918,7 +918,7 @@ def test_manager_stores_bind_values it "copies where" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.where table[:id].eq 10 stmt = manager.compile_delete @@ -932,7 +932,7 @@ def test_manager_stores_bind_values describe 'where_sql' do it 'gives me back the where sql' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.where table[:id].eq 10 manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 } @@ -940,7 +940,7 @@ def test_manager_stores_bind_values it 'returns nil when there are no wheres' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.where_sql.must_be_nil end @@ -950,7 +950,7 @@ def test_manager_stores_bind_values it 'creates an update statement' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) @@ -961,7 +961,7 @@ def test_manager_stores_bind_values it 'takes a string' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) @@ -970,7 +970,7 @@ def test_manager_stores_bind_values it 'copies limits' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.take 1 stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) @@ -984,7 +984,7 @@ def test_manager_stores_bind_values it 'copies order' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.order :foo stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) @@ -998,7 +998,7 @@ def test_manager_stores_bind_values it 'copies where clauses' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.where table[:id].eq 10 manager.from table stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) @@ -1010,7 +1010,7 @@ def test_manager_stores_bind_values it 'copies where clauses when nesting is triggered' do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.where table[:foo].eq 10 manager.take 42 manager.from table @@ -1025,20 +1025,20 @@ def test_manager_stores_bind_values describe 'project' do it "takes sql literals" do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Nodes::SqlLiteral.new '*' manager.to_sql.must_be_like %{ SELECT * } end it 'takes multiple args' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Nodes::SqlLiteral.new('foo'), Nodes::SqlLiteral.new('bar') manager.to_sql.must_be_like %{ SELECT foo, bar } end it 'takes strings' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project '*' manager.to_sql.must_be_like %{ SELECT * } end @@ -1047,7 +1047,7 @@ def test_manager_stores_bind_values describe 'projections' do it 'reads projections' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Arel.sql('foo'), Arel.sql('bar') manager.projections.must_equal [Arel.sql('foo'), Arel.sql('bar')] end @@ -1055,7 +1055,7 @@ def test_manager_stores_bind_values describe 'projections=' do it 'overwrites projections' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.project Arel.sql('foo') manager.projections = [Arel.sql('bar')] manager.to_sql.must_be_like %{ SELECT bar } @@ -1065,7 +1065,7 @@ def test_manager_stores_bind_values describe 'take' do it "knows take" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from(table).project(table['id']) manager.where(table['id'].eq(1)) manager.take 1 @@ -1079,12 +1079,12 @@ def test_manager_stores_bind_values end it "chains" do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.take(1).must_equal manager end it 'removes LIMIT when nil is passed' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.limit = 10 assert_match('LIMIT', manager.to_sql) @@ -1096,7 +1096,7 @@ def test_manager_stores_bind_values describe 'where' do it "knows where" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from(table).project(table['id']) manager.where(table['id'].eq(1)) manager.to_sql.must_be_like %{ @@ -1108,7 +1108,7 @@ def test_manager_stores_bind_values it "chains" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from(table) manager.project(table['id']).where(table['id'].eq 1).must_equal manager end @@ -1117,7 +1117,7 @@ def test_manager_stores_bind_values describe 'from' do it "makes sql" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from table manager.project table['id'] @@ -1126,7 +1126,7 @@ def test_manager_stores_bind_values it "chains" do table = Table.new :users - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.from(table).project(table['id']).must_equal manager manager.to_sql.must_be_like 'SELECT "users"."id" FROM "users"' end @@ -1134,14 +1134,14 @@ def test_manager_stores_bind_values describe 'source' do it 'returns the join source of the select core' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.source.must_equal manager.ast.cores.last.source end end describe 'distinct' do it 'sets the quantifier' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.distinct manager.ast.cores.last.set_quantifier.class.must_equal Arel::Nodes::Distinct @@ -1151,7 +1151,7 @@ def test_manager_stores_bind_values end it "chains" do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new manager.distinct.must_equal manager manager.distinct(false).must_equal manager end @@ -1159,7 +1159,7 @@ def test_manager_stores_bind_values describe 'distinct_on' do it 'sets the quantifier' do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new table = Table.new :users manager.distinct_on(table['id']) @@ -1170,7 +1170,7 @@ def test_manager_stores_bind_values end it "chains" do - manager = Arel::SelectManager.new Table.engine + manager = Arel::SelectManager.new table = Table.new :users manager.distinct_on(table['id']).must_equal manager diff --git a/test/test_table.rb b/test/test_table.rb index 394a7557276fe..e8eaf901cc981 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -179,10 +179,6 @@ module Arel @relation.table_name.must_equal 'users' end - it "should have an engine" do - @relation.engine.must_equal Table.engine - end - describe '[]' do describe 'when given a Symbol' do it "manufactures an attribute if the symbol names an attribute within the relation" do diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index d636ab548fc75..f41dc46e7dfd6 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -4,13 +4,13 @@ module Arel describe 'update manager' do describe 'new' do it 'takes an engine' do - Arel::UpdateManager.new Table.engine + Arel::UpdateManager.new end end it "should not quote sql literals" do table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table table um.set [[table[:name], Arel::Nodes::BindParam.new]] um.to_sql.must_be_like %{ UPDATE "users" SET "name" = ? } @@ -18,7 +18,7 @@ module Arel it 'handles limit properly' do table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.key = 'id' um.take 10 um.table table @@ -29,7 +29,7 @@ module Arel describe 'set' do it "updates with null" do table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table table um.set [[table[:name], nil]] um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL } @@ -37,7 +37,7 @@ module Arel it 'takes a string' do table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table table um.set Nodes::SqlLiteral.new "foo = bar" um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } @@ -45,7 +45,7 @@ module Arel it 'takes a list of lists' do table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table table um.set [[table[:id], 1], [table[:name], 'hello']] um.to_sql.must_be_like %{ @@ -55,25 +55,25 @@ module Arel it 'chains' do table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.set([[table[:id], 1], [table[:name], 'hello']]).must_equal um end end describe 'table' do it 'generates an update statement' do - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table Table.new(:users) um.to_sql.must_be_like %{ UPDATE "users" } end it 'chains' do - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table(Table.new(:users)).must_equal um end it 'generates an update statement with joins' do - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new table = Table.new(:users) join_source = Arel::Nodes::JoinSource.new( @@ -89,7 +89,7 @@ module Arel describe 'where' do it 'generates a where clause' do table = Table.new :users - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table table um.where table[:id].eq(1) um.to_sql.must_be_like %{ @@ -99,7 +99,7 @@ module Arel it 'chains' do table = Table.new :users - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new um.table table um.where(table[:id].eq(1)).must_equal um end @@ -108,7 +108,7 @@ module Arel describe 'key' do before do @table = Table.new :users - @um = Arel::UpdateManager.new Table.engine + @um = Arel::UpdateManager.new @um.key = @table[:foo] end diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index 79d340e5cd175..f0007cabbfd98 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -17,7 +17,7 @@ def setup # substitutes binds with values from block def test_assignment_binds_are_substituted table = Table.new(:users) - um = Arel::UpdateManager.new Table.engine + um = Arel::UpdateManager.new bp = Nodes::BindParam.new um.set [[table[:name], bp]] visitor = Class.new(Arel::Visitors::ToSql) { From e2f22adfaf4dacd40554db875c35a8a7e1980bd7 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 2 Dec 2014 15:46:58 -0700 Subject: [PATCH 1349/1492] Don't re-quote nodes which are already quoted We're going to start working on removing type casting from arel. To avoid doing one gigantic commit which moves everything over to eager casting, we need a way to tell Arel that we've already cast it. The easiest path to that is to give it a quoted node, and then we remove this case once we're never returning a Casted node --- lib/arel/nodes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 2c3c48881bb89..e62f9f909e6c9 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -80,7 +80,7 @@ class Quoted < Arel::Nodes::Unary # :nodoc: def self.build_quoted other, attribute = nil case other - when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted other else case attribute From 0b720f73ce58b9670f6e611252f475be6286c4de Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 4 Dec 2014 08:10:49 -0700 Subject: [PATCH 1350/1492] Quoted nodes respond to the same method as Casted nodes We need to be able to not care which we've gotten in ActiveRecord --- lib/arel/nodes.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index e62f9f909e6c9..49000af4ab64b 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -76,6 +76,7 @@ def eql? other end class Quoted < Arel::Nodes::Unary # :nodoc: + alias :val :value end def self.build_quoted other, attribute = nil From ba5effdc59f27bcd71f51a514a5496448bfad52c Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 4 Dec 2014 09:09:21 -0700 Subject: [PATCH 1351/1492] Quoted nodes respond to `nil?` in the same way as `Casted` nodes --- lib/arel/nodes.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 49000af4ab64b..e8de637323031 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -77,6 +77,7 @@ def eql? other class Quoted < Arel::Nodes::Unary # :nodoc: alias :val :value + def nil; val.nil?; end end def self.build_quoted other, attribute = nil From 0cd5fa9671592a16ee34f0718704b15f27911620 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 4 Dec 2014 09:16:23 -0700 Subject: [PATCH 1352/1492] =?UTF-8?q?=F0=9F=92=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `nil?` not `nil` --- lib/arel/nodes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index e8de637323031..7d900fe710c55 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -77,7 +77,7 @@ def eql? other class Quoted < Arel::Nodes::Unary # :nodoc: alias :val :value - def nil; val.nil?; end + def nil?; val.nil?; end end def self.build_quoted other, attribute = nil From 2c95c39e9345ef50a7e9c3ad573857b1d358e04a Mon Sep 17 00:00:00 2001 From: Kazuya NUMATA Date: Thu, 25 Dec 2014 12:58:42 +0900 Subject: [PATCH 1353/1492] {Matches,DoesNotMatch} support the ESCAPE clause with PostgreSQL to_SQL already has supported the ESCAPE clause in #318. PostgreSQL can use the ESCAPE clause too. --- lib/arel/visitors/postgresql.rb | 16 ++++++++++++++-- test/visitors/test_postgres.rb | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index f55aaf30fe0f6..bd23fc0a47985 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -4,11 +4,23 @@ class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Matches o, collector - infix_value o, collector, ' ILIKE ' + collector = infix_value o, collector, ' ILIKE ' + if o.escape + collector << ' ESCAPE ' + visit o.escape, collector + else + collector + end end def visit_Arel_Nodes_DoesNotMatch o, collector - infix_value o, collector, ' NOT ILIKE ' + collector = infix_value o, collector, ' NOT ILIKE ' + if o.escape + collector << ' ESCAPE ' + visit o.escape, collector + else + collector + end end def visit_Arel_Nodes_Regexp o, collector diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 368feb59773d9..d6de216d91d9b 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -58,6 +58,13 @@ def compile node } end + it "can handle ESCAPE" do + node = @table[:name].matches('foo!%', '!') + compile(node).must_be_like %{ + "users"."name" ILIKE 'foo!%' ESCAPE '!' + } + end + it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].matches('foo%')) node = @attr.in subquery @@ -75,6 +82,13 @@ def compile node } end + it "can handle ESCAPE" do + node = @table[:name].does_not_match('foo!%', '!') + compile(node).must_be_like %{ + "users"."name" NOT ILIKE 'foo!%' ESCAPE '!' + } + end + it 'can handle subqueries' do subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) node = @attr.in subquery From cf03bd45e39def057a2f63e42a3391b7d750dece Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 26 Dec 2014 15:45:34 -0700 Subject: [PATCH 1354/1492] Allow for handling quoted values in ranges Since Active Record needs to eagerly cast values, we need to check for quoted infinity in our range handling --- lib/arel/predications.rb | 20 +++++++++---- test/attributes/test_attribute.rb | 47 +++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index ec779dd40fee4..b05fc6f99a78b 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -25,15 +25,15 @@ def eq_all others end def between other - if other.begin == -Float::INFINITY - if other.end == Float::INFINITY + if equals_quoted?(other.begin, -Float::INFINITY) + if equals_quoted?(other.end, Float::INFINITY) not_in([]) elsif other.exclude_end? lt(other.end) else lteq(other.end) end - elsif other.end == Float::INFINITY + elsif equals_quoted?(other.end, Float::INFINITY) gteq(other.begin) elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) @@ -71,15 +71,15 @@ def in_all others end def not_between other - if other.begin == -Float::INFINITY # The range begins with negative infinity - if other.end == Float::INFINITY + if equals_quoted?(other.begin, -Float::INFINITY) + if equals_quoted?(other.end, Float::INFINITY) self.in([]) elsif other.exclude_end? gteq(other.end) else gt(other.end) end - elsif other.end == Float::INFINITY + elsif equals_quoted?(other.end, Float::INFINITY) lt(other.begin) else left = lt(other.begin) @@ -211,5 +211,13 @@ def quoted_node(other) def quoted_array(others) others.map { |v| quoted_node(v) } end + + def equals_quoted?(maybe_quoted, value) + if maybe_quoted.is_a?(Nodes::Quoted) + maybe_quoted.val == value + else + maybe_quoted == value + end + end end end diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 500f9385f820b..e4ddb27e725cd 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -1,4 +1,5 @@ require 'helper' +require 'ostruct' module Arel module Attributes @@ -572,6 +573,16 @@ module Attributes ) end + it 'can be constructed with a quoted range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.between(quoted_range(-::Float::INFINITY, 3, false)) + + node.must_equal Nodes::LessThanOrEqual.new( + attribute, + Nodes::Quoted.new(3) + ) + end + it 'can be constructed with an exclusive range starting from -Infinity' do attribute = Attribute.new nil, nil node = attribute.between(-::Float::INFINITY...3) @@ -582,6 +593,16 @@ module Attributes ) end + it 'can be constructed with a quoted exclusive range starting from -Infinity' do + attribute = Attribute.new nil, nil + node = attribute.between(quoted_range(-::Float::INFINITY, 3, true)) + + node.must_equal Nodes::LessThan.new( + attribute, + Nodes::Quoted.new(3) + ) + end + it 'can be constructed with an infinite range' do attribute = Attribute.new nil, nil node = attribute.between(-::Float::INFINITY..::Float::INFINITY) @@ -589,6 +610,14 @@ module Attributes node.must_equal Nodes::NotIn.new(attribute, []) end + it 'can be constructed with a quoted infinite range' do + attribute = Attribute.new nil, nil + node = attribute.between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false)) + + node.must_equal Nodes::NotIn.new(attribute, []) + end + + it 'can be constructed with a range ending at Infinity' do attribute = Attribute.new nil, nil node = attribute.between(0..::Float::INFINITY) @@ -599,6 +628,16 @@ module Attributes ) end + it 'can be constructed with a quoted range ending at Infinity' do + attribute = Attribute.new nil, nil + node = attribute.between(quoted_range(0, ::Float::INFINITY, false)) + + node.must_equal Nodes::GreaterThanOrEqual.new( + attribute, + Nodes::Quoted.new(0) + ) + end + it 'can be constructed with an exclusive range' do attribute = Attribute.new nil, nil node = attribute.between(0...3) @@ -614,6 +653,14 @@ module Attributes ) ]) end + + def quoted_range(begin_val, end_val, exclude) + OpenStruct.new( + begin: Nodes::Quoted.new(begin_val), + end: Nodes::Quoted.new(end_val), + exclude_end?: exclude, + ) + end end describe '#in' do From 008445d6fd5f825d9b445ac75a7be67f0f7ab52c Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 26 Dec 2014 18:02:56 -0700 Subject: [PATCH 1355/1492] Deprecate automatic type casting within Arel Rails now performs all casting eagerly, before passing the value into Arel. Once we remove this, the code on both sides will be simplified greatly. Ideally, we can provide the appropriate public APIs on the Rails side to ease this transition for library authors who depend on this behavior. --- lib/arel/nodes.rb | 11 +++++++++++ test/helper.rb | 2 ++ 2 files changed, 13 insertions(+) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 7d900fe710c55..8432106719602 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -87,6 +87,17 @@ def self.build_quoted other, attribute = nil else case attribute when Arel::Attributes::Attribute + unless $arel_silence_type_casting_deprecation + warn <<-eowarn +Arel performing automatic type casting is deprecated, and will be removed in Arel 8.0. If you are seeing this, it is because you are manually passing a value to an Arel predicate. + +If you're certain the value is already of the right type, change `attribute.eq(value)` to `attribute.eq(Arel::Nodes::Quoted.new(value))` (you will be able to remove that in Arel 8.0, it is only required to silence this deprecation warning). + +You can also silence this warning globally by setting `$arel_silence_type_casting_deprecation` to `true`. (Do NOT do this if you are a library author) + +If you are passing user input to a predicate, you are responsible for type casting appropriately before passing the value to Arel. + eowarn + end Casted.new other, attribute else Quoted.new other diff --git a/test/helper.rb b/test/helper.rb index 6e8ac836fcf63..87f5756d24fe5 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -6,6 +6,8 @@ require 'support/fake_record' Arel::Table.engine = FakeRecord::Base.new +$arel_silence_type_casting_deprecation = true + class Object def must_be_like other gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip From 6160bfbda1d1781c3b08a33ec4955f170e95be11 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Dec 2014 11:24:44 -0700 Subject: [PATCH 1356/1492] Allow a type caster to be given to the `Arel::Table` object This will allow most consuming code to avoid the deprecation introduced in 008445d6fd5f825d9b445ac75a7be67f0f7ab52c. The only code which will be affected is code that is building the `Arel::Table` object manually, rather than calling `arel_table` on an Active Record class. Hopefully this case will be rare enough that we don't need to introduce any additional APIs to work around it. --- lib/arel/attributes/attribute.rb | 8 ++++++++ lib/arel/nodes.rb | 11 ---------- lib/arel/nodes/table_alias.rb | 8 ++++++++ lib/arel/table.rb | 21 +++++++++++++++---- lib/arel/visitors/to_sql.rb | 23 ++++++++++++++++++++- test/attributes/test_attribute.rb | 34 +++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 16 deletions(-) diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index 0906fa4f1dcd5..cda5a5a3db636 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -12,6 +12,14 @@ class Attribute < Struct.new :relation, :name def lower relation.lower self end + + def type_cast_for_database(value) + relation.type_cast_for_database(name, value) + end + + def able_to_type_cast? + relation.able_to_type_cast? + end end class String < Attribute; end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 8432106719602..7d900fe710c55 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -87,17 +87,6 @@ def self.build_quoted other, attribute = nil else case attribute when Arel::Attributes::Attribute - unless $arel_silence_type_casting_deprecation - warn <<-eowarn -Arel performing automatic type casting is deprecated, and will be removed in Arel 8.0. If you are seeing this, it is because you are manually passing a value to an Arel predicate. - -If you're certain the value is already of the right type, change `attribute.eq(value)` to `attribute.eq(Arel::Nodes::Quoted.new(value))` (you will be able to remove that in Arel 8.0, it is only required to silence this deprecation warning). - -You can also silence this warning globally by setting `$arel_silence_type_casting_deprecation` to `true`. (Do NOT do this if you are a library author) - -If you are passing user input to a predicate, you are responsible for type casting appropriately before passing the value to Arel. - eowarn - end Casted.new other, attribute else Quoted.new other diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index b32f057117ca9..a5adc0766ab7e 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -12,6 +12,14 @@ def [] name def table_name relation.respond_to?(:name) ? relation.name : name end + + def type_cast_for_database(*args) + relation.type_cast_for_database(*args) + end + + def able_to_type_cast? + relation.respond_to?(:able_to_type_cast?) && relation.able_to_type_cast? + end end end end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 2c7a2b7f9344c..b4b4a861b83b4 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -11,18 +11,19 @@ class << self; attr_accessor :engine; end # TableAlias and Table both have a #table_name which is the name of the underlying table alias :table_name :name - def initialize name, options = {} + def initialize(name, as: nil, type_caster: nil) @name = name.to_s @columns = nil @aliases = [] + @type_caster = type_caster # 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 = options[:as] - if @table_alias.to_s == @name - @table_alias = nil + if as.to_s == @name + as = nil end + @table_alias = as end def alias name = "#{self.name}_2" @@ -98,6 +99,18 @@ def eql? other end alias :== :eql? + def type_cast_for_database(attribute_name, value) + type_caster.type_cast_for_database(attribute_name, value) + end + + def able_to_type_cast? + !type_caster.nil? + end + + protected + + attr_reader :type_caster + private def attributes_for columns diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 30c86341190ba..acf0a74d374b9 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -721,7 +721,11 @@ def visit_Arel_Nodes_BindParam o, collector alias :visit_Fixnum :literal def quoted o, a - quote(o, column_for(a)) + if a && a.able_to_type_cast? + quote(a.type_cast_for_database(o)) + else + quote(o, column_for(a)) + end end def unsupported o, collector @@ -761,6 +765,9 @@ def visit_Array o, collector def quote value, column = nil return value if Arel::Nodes::SqlLiteral === value + if column + print_type_cast_deprecation + end @connection.quote value, column end @@ -810,6 +817,20 @@ def aggregate name, o, collector collector end end + + def print_type_cast_deprecation + unless defined?($arel_silence_type_casting_deprecation) && $arel_silence_type_casting_deprecation + warn <<-eowarn +Arel performing automatic type casting is deprecated, and will be removed in Arel 8.0. If you are seeing this, it is because you are manually passing a value to an Arel predicate, and the `Arel::Table` object was constructed manually. The easiest way to remove this warning is to use an `Arel::Table` object returned from calling `arel_table` on an ActiveRecord::Base subclass. + +If you're certain the value is already of the right type, change `attribute.eq(value)` to `attribute.eq(Arel::Nodes::Quoted.new(value))` (you will be able to remove that in Arel 8.0, it is only required to silence this deprecation warning). + +You can also silence this warning globally by setting `$arel_silence_type_casting_deprecation` to `true`. (Do NOT do this if you are a library author) + +If you are passing user input to a predicate, you must either give an appropriate type caster object to the `Arel::Table`, or manually cast the value before passing it to Arel. + eowarn + end + end end end end diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index e4ddb27e725cd..0f6d6e447b187 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -950,5 +950,39 @@ def quoted_range(begin_val, end_val, exclude) end end end + + describe 'type casting' do + it 'does not type cast by default' do + table = Table.new(:foo) + condition = table["id"].eq("1") + + refute table.able_to_type_cast? + condition.to_sql.must_equal %("foo"."id" = '1') + end + + it 'type casts when given an explicit caster' do + fake_caster = Object.new + def fake_caster.type_cast_for_database(attr_name, value) + if attr_name == "id" + value.to_i + else + value + end + end + table = Table.new(:foo, type_caster: fake_caster) + condition = table["id"].eq("1").and(table["other_id"].eq("2")) + + assert table.able_to_type_cast? + condition.to_sql.must_equal %("foo"."id" = 1 AND "foo"."other_id" = '2') + end + + it 'falls back to using the connection adapter for type casting' do + table = Table.new(:users) + condition = table["id"].eq("1") + + refute table.able_to_type_cast? + condition.to_sql.must_equal %("users"."id" = 1) + end + end end end From f1a3421ce7083181ebd463c8147c2d4b95539ca8 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Dec 2014 11:36:30 -0700 Subject: [PATCH 1357/1492] Remove 1.9 from the Travis builds Arel 7.0 will not support Ruby 1.9 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e5462c44051c..d6eda2ce61932 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ script: rvm: - rbx - jruby - - 1.9.3 - 2.0.0 - 2.1 - ruby-head From 2345b80c0cfa0766875274a9e4e237a09e08b302 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 29 Dec 2014 11:39:25 -0700 Subject: [PATCH 1358/1492] Change the version to 7.0.0.alpha --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 1e3c51a2548ab..aab93913d5876 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '6.0.0' + VERSION = '7.0.0.alpha' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From c20cc2f458490f0cd2a2f64888c623722ca025b4 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Thu, 1 Jan 2015 18:18:38 +0530 Subject: [PATCH 1359/1492] Add default rake task as test. --- Rakefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Rakefile b/Rakefile index 148c0c660248c..956e95c939931 100644 --- a/Rakefile +++ b/Rakefile @@ -3,6 +3,9 @@ Bundler::GemHelper.install_tasks require 'rake/testtask' +desc "Default Task" +task default: [ :test ] + Rake::TestTask.new(:test) do |t| t.libs << 'lib' t.libs << 'test' From f94efffa9797cc9ec8650dd6df82bbf7819d316f Mon Sep 17 00:00:00 2001 From: Peter Suschlik Date: Wed, 21 Jan 2015 14:42:06 +0100 Subject: [PATCH 1360/1492] Remove jruby and add jruby-head on Travis Arel 7.0 dropped support for 1.9 (see f1a3421ce7083181ebd463c8147c2d4b95539ca8). We should remove jruby (1.7.18) which only supports 1.9 and test the latest jruby head (9.0.0.0.pre1). After jruby 9k has been released (and Travis has updated) we can safely switch back to jruby. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d6eda2ce61932..825c096c89ad7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ script: - "gem build arel.gemspec" rvm: - rbx - - jruby + - jruby-head - 2.0.0 - 2.1 - ruby-head From f984e8898f6ccc8e118430889dc4af32824b1729 Mon Sep 17 00:00:00 2001 From: Peter Suschlik Date: Wed, 21 Jan 2015 15:00:50 +0100 Subject: [PATCH 1361/1492] Speed up jruby tests Improve startup time and give Java more memory. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 825c096c89ad7..f7ac50ada5215 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: ruby script: - "rake test" - "gem build arel.gemspec" +env: + global: + - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - rbx - jruby-head From d36a769234911c8374e09069eb054d4c60eb1b99 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Sun, 25 Jan 2015 14:47:47 -0700 Subject: [PATCH 1362/1492] Implement equality for `BindParam` It is impossible to test equality of things constructing trees with bind params otherwise. --- lib/arel/nodes/bind_param.rb | 3 +++ test/nodes/test_bind_param.rb | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 test/nodes/test_bind_param.rb diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb index 160bc21b91adb..3a4aedc4baf33 100644 --- a/lib/arel/nodes/bind_param.rb +++ b/lib/arel/nodes/bind_param.rb @@ -1,6 +1,9 @@ module Arel module Nodes class BindParam < Node + def ==(other) + other.is_a?(BindParam) + end end end end diff --git a/test/nodes/test_bind_param.rb b/test/nodes/test_bind_param.rb new file mode 100644 index 0000000000000..ea008f4c996dc --- /dev/null +++ b/test/nodes/test_bind_param.rb @@ -0,0 +1,15 @@ +require 'helper' + +module Arel + module Nodes + describe 'BindParam' do + it 'is equal to other bind params' do + BindParam.new.must_equal(BindParam.new) + end + + it 'is not equal to other nodes' do + BindParam.new.wont_equal(Node.new) + end + end + end +end From aac9da257f291ad8d2d4f914528881c240848bb2 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 27 Jan 2015 09:52:54 -0700 Subject: [PATCH 1363/1492] Change the interface of `having` to match that of `where` These two clauses have nearly identical semantics with regards to how they would be constructed as an AST. It doesn't make sense for their interfaces to be separate. --- lib/arel/nodes/select_core.rb | 10 +++++----- lib/arel/nodes/unary.rb | 1 - lib/arel/select_manager.rb | 4 ++-- lib/arel/visitors/depth_first.rb | 2 +- lib/arel/visitors/informix.rb | 7 ++++++- lib/arel/visitors/to_sql.rb | 10 ++++------ test/nodes/test_select_core.rb | 8 ++++---- test/test_select_manager.rb | 10 +++++----- test/visitors/test_depth_first.rb | 5 ++--- test/visitors/test_dot.rb | 1 - 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 09ae420aa187f..3696dd20af004 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -2,7 +2,7 @@ module Arel module Nodes class SelectCore < Arel::Nodes::Node attr_accessor :top, :projections, :wheres, :groups, :windows - attr_accessor :having, :source, :set_quantifier + attr_accessor :havings, :source, :set_quantifier def initialize super() @@ -14,7 +14,7 @@ def initialize @projections = [] @wheres = [] @groups = [] - @having = nil + @havings = [] @windows = [] end @@ -35,14 +35,14 @@ def initialize_copy other @projections = @projections.clone @wheres = @wheres.clone @groups = @groups.clone - @having = @having.clone if @having + @havings = @havings.clone @windows = @windows.clone end def hash [ @source, @top, @set_quantifier, @projections, - @wheres, @groups, @having, @windows + @wheres, @groups, @havings, @windows ].hash end @@ -54,7 +54,7 @@ def eql? other self.projections == other.projections && self.wheres == other.wheres && self.groups == other.groups && - self.having == other.having && + self.havings == other.havings && self.windows == other.windows end alias :== :eql? diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 3d4a4b014a900..a0062ff5be8a0 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -23,7 +23,6 @@ def eql? other %w{ Bin Group - Having Limit Not Offset diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index dd1ae37b653ff..e5fdbc887c25c 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -118,8 +118,8 @@ def outer_join relation join(relation, Nodes::OuterJoin) end - def having *exprs - @ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having)) + def having expr + @ctx.havings << expr self end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index d7d85cfcc6d8a..22704dd038870 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -146,7 +146,7 @@ def visit_Arel_Nodes_SelectCore o visit o.wheres visit o.groups visit o.windows - visit o.having + visit o.havings end def visit_Arel_Nodes_SelectStatement o diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index 7e8a3ea45871f..c33ef5055454a 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -34,8 +34,13 @@ def visit_Arel_Nodes_SelectCore o, collector collector = inject_join o.groups, collector, ", " end - maybe_visit o.having, collector + if o.havings.any? + collector << " HAVING " + collector = inject_join o.havings, collector, " AND " + end + collector end + def visit_Arel_Nodes_Offset o, collector collector << "SKIP " visit o.expr, collector diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index acf0a74d374b9..7dfa86a5758fb 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -265,7 +265,10 @@ def visit_Arel_Nodes_SelectCore o, collector end end - collector = maybe_visit o.having, collector + unless o.havings.empty? + collector << " HAVING " + inject_join o.havings, collector, AND + end unless o.windows.empty? collector << WINDOW @@ -404,11 +407,6 @@ def visit_Arel_Nodes_Over o, collector end end - def visit_Arel_Nodes_Having o, collector - collector << "HAVING " - visit o.expr, collector - end - def visit_Arel_Nodes_Offset o, collector collector << "OFFSET " visit o.expr, collector diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index ca4f070444209..4114bcf4ffa42 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -34,14 +34,14 @@ def test_equality_with_same_ivars core1.wheres = %w[g h i] core1.groups = %w[j k l] core1.windows = %w[m n o] - core1.having = %w[p q r] + core1.havings = %w[p q r] core2 = SelectCore.new core2.froms = %w[a b c] core2.projections = %w[d e f] core2.wheres = %w[g h i] core2.groups = %w[j k l] core2.windows = %w[m n o] - core2.having = %w[p q r] + core2.havings = %w[p q r] array = [core1, core2] assert_equal 1, array.uniq.size end @@ -53,14 +53,14 @@ def test_inequality_with_different_ivars core1.wheres = %w[g h i] core1.groups = %w[j k l] core1.windows = %w[m n o] - core1.having = %w[p q r] + core1.havings = %w[p q r] core2 = SelectCore.new core2.froms = %w[a b c] core2.projections = %w[d e f] core2.wheres = %w[g h i] core2.groups = %w[j k l] core2.windows = %w[m n o] - core2.having = %w[l o l] + core2.havings = %w[l o l] array = [core1, core2] assert_equal 2, array.uniq.size end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 809f0de8df1f9..7192027df4525 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -111,22 +111,22 @@ def test_manager_stores_bind_values it 'converts strings to SQLLiterals' do table = Table.new :users mgr = table.from - mgr.having 'foo' + mgr.having Arel.sql('foo') mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo } end it 'can have multiple items specified separately' do table = Table.new :users mgr = table.from - mgr.having 'foo' - mgr.having 'bar' + mgr.having Arel.sql('foo') + mgr.having Arel.sql('bar') mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } end - it 'can have multiple items specified together' do + it 'can receive any node' do table = Table.new :users mgr = table.from - mgr.having 'foo', 'bar' + mgr.having Arel::Nodes::And.new([Arel.sql('foo'), Arel.sql('bar')]) mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index d50ea3e59aff5..3356759b7d79d 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -30,7 +30,6 @@ def test_raises_with_object Arel::Nodes::Grouping, Arel::Nodes::Offset, Arel::Nodes::Ordering, - Arel::Nodes::Having, Arel::Nodes::StringJoin, Arel::Nodes::UnqualifiedColumn, Arel::Nodes::Top, @@ -206,7 +205,7 @@ def test_select_core core.wheres << :c core.groups << :d core.windows << :e - core.having = :f + core.havings << :f @visitor.accept core assert_equal [ @@ -216,7 +215,7 @@ def test_select_core :c, core.wheres, :d, core.groups, :e, core.windows, - :f, + :f, core.havings, core], @collector.calls end diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 7763350f5ccbf..4dc3c9c6c5a76 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -34,7 +34,6 @@ def test_named_function Arel::Nodes::Grouping, Arel::Nodes::Offset, Arel::Nodes::Ordering, - Arel::Nodes::Having, Arel::Nodes::UnqualifiedColumn, Arel::Nodes::Top, Arel::Nodes::Limit, From dedfdb3aea474d3b9aa61f0fa1395850fa906055 Mon Sep 17 00:00:00 2001 From: Joe Eli McIlvain Date: Thu, 19 Feb 2015 09:11:08 -0800 Subject: [PATCH 1364/1492] Test with rbx-2 on Travis-CI Using `rbx-2` is the recommended way to test with the 2.0 branch of Rubinius. --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7ac50ada5215..f199590d1d9f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,14 +6,11 @@ env: global: - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - - rbx + - rbx-2 - jruby-head - 2.0.0 - 2.1 - ruby-head -matrix: - allow_failures: - - rvm: rbx notifications: email: false irc: From 8ae65d3533a86227e683d9f77b7e15ab809e0c34 Mon Sep 17 00:00:00 2001 From: Joe Eli McIlvain Date: Thu, 19 Feb 2015 10:25:59 -0800 Subject: [PATCH 1365/1492] Use bundle exec on Travis-CI This avoids problems with using the wrong version of gems that are also included in the Ruby standard library, like `minitest` --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f199590d1d9f1..18988f74eb401 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: ruby script: - - "rake test" + - "bundle exec rake test" - "gem build arel.gemspec" env: global: From 65135d00a854edfd1684f5163db8e68fdb956ae0 Mon Sep 17 00:00:00 2001 From: Bradford Folkens Date: Wed, 29 Feb 2012 09:47:28 -0600 Subject: [PATCH 1366/1492] Delete should respect 'limit' Conflicts: lib/arel/visitors/to_sql.rb --- lib/arel/crud.rb | 1 + lib/arel/delete_manager.rb | 5 +++++ lib/arel/nodes/delete_statement.rb | 2 ++ lib/arel/visitors/to_sql.rb | 6 +++--- test/test_delete_manager.rb | 8 ++++++++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index 2dfe27445c14d..d310c7381f0e9 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -31,6 +31,7 @@ def create_insert def compile_delete dm = DeleteManager.new + dm.take @ast.limit.expr if @ast.limit dm.wheres = @ctx.wheres dm.from @ctx.froms dm diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index af33c60740b99..20e988e01f26a 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -11,6 +11,11 @@ def from relation self end + def take limit + @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit + self + end + def wheres= list @ast.wheres = list end diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index 3bac8225ec905..8aaf8ca0b6704 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -1,6 +1,8 @@ module Arel module Nodes class DeleteStatement < Arel::Nodes::Binary + attr_accessor :limit + alias :relation :left alias :relation= :left= alias :wheres :right diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7dfa86a5758fb..6084f5746c71d 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -78,10 +78,10 @@ def visit_Arel_Nodes_DeleteStatement o, collector collector = visit o.relation, collector if o.wheres.any? collector << " WHERE " - inject_join o.wheres, collector, AND - else - collector + collector = inject_join o.wheres, collector, AND end + + maybe_visit o.limit, collector end # FIXME: we should probably have a 2-pass visitor for this diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index b16b52cb9e77b..ece2389d8844e 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -8,6 +8,14 @@ module Arel end end + it 'handles limit properly' do + table = Table.new(:users) + dm = Arel::DeleteManager.new + dm.take 10 + dm.from table + assert_match(/LIMIT 10/, dm.to_sql) + end + describe 'from' do it 'uses from' do table = Table.new(:users) From d86e20ccbea226bb6e42da508bc040fd03ab473f Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 23 Feb 2015 09:58:22 -0800 Subject: [PATCH 1367/1492] Special limited delete handling in MSSQL Refernce: https://technet.microsoft.com/en-us/library/ms175486%28v=sql.105%29.aspx --- lib/arel/visitors/mssql.rb | 17 +++++++++++++++++ lib/arel/visitors/to_sql.rb | 4 ++-- test/visitors/test_mssql.rb | 9 +++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 7c65ad33f27b2..92362a0c5fc7a 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -66,6 +66,23 @@ def get_offset_limit_clause o end end + def visit_Arel_Nodes_DeleteStatement o, collector + collector << 'DELETE ' + if o.limit + collector << 'TOP (' + visit o.limit.expr, collector + collector << ') ' + end + collector << 'FROM ' + collector = visit o.relation, collector + if o.wheres.any? + collector << ' WHERE ' + inject_join o.wheres, collector, AND + else + collector + end + end + def determine_order_by orders, x if orders.any? orders diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 6084f5746c71d..ba176a552cbc4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -74,10 +74,10 @@ def schema_cache end def visit_Arel_Nodes_DeleteStatement o, collector - collector << "DELETE FROM " + collector << 'DELETE FROM ' collector = visit o.relation, collector if o.wheres.any? - collector << " WHERE " + collector << ' WHERE ' collector = inject_join o.wheres, collector, AND end diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index 7574aeb0a2613..fe228bce4b2b0 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -45,6 +45,15 @@ def connection.quote_column_name(*); ""; end connection.verify end + it 'should use TOP for limited deletes' do + stmt = Nodes::DeleteStatement.new + stmt.relation = @table + stmt.limit = Nodes::Limit.new(10) + sql = compile(stmt) + + sql.must_be_like "DELETE TOP (10) FROM \"users\"" + end + it 'should go over query ORDER BY if .order()' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) From 956b40e93492b147e239d25b502148c9070ffa9d Mon Sep 17 00:00:00 2001 From: evgenim Date: Sun, 15 Mar 2015 21:52:54 +0300 Subject: [PATCH 1368/1492] Fix visit_Arel_Nodes_FullOuterJoin and visit_Arel_Nodes_RightOuterJoin to make them work with collectors. --- lib/arel/visitors/to_sql.rb | 14 ++++++++++---- test/test_select_manager.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ba176a552cbc4..6f72fdfb0eda4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -572,8 +572,11 @@ def visit_Arel_Nodes_StringJoin o, collector visit o.left, collector end - def visit_Arel_Nodes_FullOuterJoin o - "FULL OUTER JOIN #{visit o.left} #{visit o.right}" + def visit_Arel_Nodes_FullOuterJoin o, collector + collector << "FULL OUTER JOIN " + collector = visit o.left, collector + collector << SPACE + visit o.right, collector end def visit_Arel_Nodes_OuterJoin o, collector @@ -583,8 +586,11 @@ def visit_Arel_Nodes_OuterJoin o, collector visit o.right, collector end - def visit_Arel_Nodes_RightOuterJoin o - "RIGHT OUTER JOIN #{visit o.left} #{visit o.right}" + def visit_Arel_Nodes_RightOuterJoin o, collector + collector << "RIGHT OUTER JOIN " + collector = visit o.left, collector + collector << SPACE + visit o.right, collector end def visit_Arel_Nodes_InnerJoin o, collector diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 7192027df4525..8425cee031e3f 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -584,6 +584,36 @@ def test_manager_stores_bind_values } end + it 'takes the full outer join class' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new + + manager.from left + manager.join(right, Nodes::FullOuterJoin).on(predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + FULL OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + + it 'takes the right outer join class' do + left = Table.new :users + right = left.alias + predicate = left[:id].eq(right[:id]) + manager = Arel::SelectManager.new + + manager.from left + manager.join(right, Nodes::RightOuterJoin).on(predicate) + manager.to_sql.must_be_like %{ + SELECT FROM "users" + RIGHT OUTER JOIN "users" "users_2" + ON "users"."id" = "users_2"."id" + } + end + it 'noops on nil' do manager = Arel::SelectManager.new manager.join(nil).must_equal manager From 0e1dd3d490a50b94880e3b81a132732bc674d26a Mon Sep 17 00:00:00 2001 From: Courtland Caldwell Date: Mon, 23 Mar 2015 16:20:47 -0700 Subject: [PATCH 1369/1492] Fix a typo in the sql literal spec for grouped "and" equality --- test/nodes/test_sql_literal.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index ed602cc47df23..c09e5882d5ca4 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -56,7 +56,7 @@ def compile node end describe 'grouped "and" equality' do - it 'makes a grouping node with an or node' do + it 'makes a grouping node with an and node' do node = SqlLiteral.new('foo').eq_all([1,2]) compile(node).must_be_like %{ (foo = 1 AND foo = 2) } end From 0d69486b7c4ab347133847589da282945b8b85c6 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Sun, 31 May 2015 19:56:21 +0530 Subject: [PATCH 1370/1492] Move casted to its own file --- lib/arel/nodes.rb | 41 +--------------------------------------- lib/arel/nodes/casted.rb | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 40 deletions(-) create mode 100644 lib/arel/nodes/casted.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 7d900fe710c55..8d61bb320fdaa 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -55,43 +55,4 @@ require 'arel/nodes/sql_literal' -module Arel - module Nodes - class Casted < Arel::Nodes::Node # :nodoc: - attr_reader :val, :attribute - def initialize val, attribute - @val = val - @attribute = attribute - super() - end - - def nil?; @val.nil?; end - - def eql? other - self.class == other.class && - self.val == other.val && - self.attribute == other.attribute - end - alias :== :eql? - end - - class Quoted < Arel::Nodes::Unary # :nodoc: - alias :val :value - def nil?; val.nil?; end - end - - def self.build_quoted other, attribute = nil - case other - when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted - other - else - case attribute - when Arel::Attributes::Attribute - Casted.new other, attribute - else - Quoted.new other - end - end - end - end -end +require 'arel/nodes/casted' diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb new file mode 100644 index 0000000000000..9fa02955ef586 --- /dev/null +++ b/lib/arel/nodes/casted.rb @@ -0,0 +1,40 @@ +module Arel + module Nodes + class Casted < Arel::Nodes::Node # :nodoc: + attr_reader :val, :attribute + def initialize val, attribute + @val = val + @attribute = attribute + super() + end + + def nil?; @val.nil?; end + + def eql? other + self.class == other.class && + self.val == other.val && + self.attribute == other.attribute + end + alias :== :eql? + end + + class Quoted < Arel::Nodes::Unary # :nodoc: + alias :val :value + def nil?; val.nil?; end + end + + def self.build_quoted other, attribute = nil + case other + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted + other + else + case attribute + when Arel::Attributes::Attribute + Casted.new other, attribute + else + Quoted.new other + end + end + end + end +end From 96692228918fe5a6891ad16288a6c913c4a62496 Mon Sep 17 00:00:00 2001 From: Arthur Neves Date: Thu, 18 Jun 2015 22:08:04 +0200 Subject: [PATCH 1371/1492] Dont need to quote limit --- lib/arel/select_manager.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index e5fdbc887c25c..f7dec87ca3d7e 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -19,7 +19,7 @@ def initialize_copy other end def limit - @ast.limit && @ast.limit.expr.expr + @ast.limit && @ast.limit.expr end alias :taken :limit @@ -216,8 +216,8 @@ def with *subqueries def take limit if limit - @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) - @ctx.top = Nodes::Top.new(Nodes.build_quoted(limit)) + @ast.limit = Nodes::Limit.new(limit) + @ctx.top = Nodes::Top.new(limit) else @ast.limit = nil @ctx.top = nil From 8d04c28b619212f99e6ce534f75ebda59bb200a1 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Thu, 25 Sep 2014 19:38:35 +0900 Subject: [PATCH 1372/1492] Extract visit_Arel_Nodes_SelectOptions --- lib/arel/visitors/to_sql.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ba176a552cbc4..d7ed7abd5d178 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -219,11 +219,15 @@ def visit_Arel_Nodes_SelectStatement o, collector } end + visit_Arel_Nodes_SelectOptions(o, collector) + + collector + end + + def visit_Arel_Nodes_SelectOptions o, collector collector = maybe_visit o.limit, collector collector = maybe_visit o.offset, collector collector = maybe_visit o.lock, collector - - collector end def visit_Arel_Nodes_SelectCore o, collector From 0e1427e917a4e47dce9f02ad9309600073622c73 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Tue, 4 Nov 2014 04:44:01 +0900 Subject: [PATCH 1373/1492] Create Arel::Visitors::Oracle12 to provide better top-N query to support `FETCH FIRST n ROWS` and `OFFSET` for Oracle 12c database --- lib/arel/visitors.rb | 1 + lib/arel/visitors/oracle12.rb | 53 ++++++++++++++++++++++++++++++++++ test/visitors/test_oracle12.rb | 47 ++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 lib/arel/visitors/oracle12.rb create mode 100644 test/visitors/test_oracle12.rb diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 4a8d254ba77e2..f492ca2d9d5d2 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -6,6 +6,7 @@ require 'arel/visitors/mysql' require 'arel/visitors/mssql' require 'arel/visitors/oracle' +require 'arel/visitors/oracle12' require 'arel/visitors/where_sql' require 'arel/visitors/dot' require 'arel/visitors/ibm_db' diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb new file mode 100644 index 0000000000000..4a42343c9b426 --- /dev/null +++ b/lib/arel/visitors/oracle12.rb @@ -0,0 +1,53 @@ +module Arel + module Visitors + class Oracle12 < Arel::Visitors::ToSql + private + + def visit_Arel_Nodes_SelectStatement o, collector + # Oracle does not allow LIMIT clause with select for update + if o.limit && o.lock + o = o.dup + o.limit = [] + end + + super + end + + def visit_Arel_Nodes_SelectOptions o, collector + collector = maybe_visit o.offset, collector + collector = maybe_visit o.limit, collector + collector = maybe_visit o.lock, collector + end + + def visit_Arel_Nodes_Limit o, collector + collector << "FETCH FIRST " + collector = visit o.expr, collector + collector << " ROWS ONLY" + end + + def visit_Arel_Nodes_Offset o, collector + collector << "OFFSET " + visit o.expr, collector + collector << " ROWS" + end + + def visit_Arel_Nodes_Except o, collector + collector << "( " + collector = infix_value o, collector, " MINUS " + collector << " )" + end + + def visit_Arel_Nodes_UpdateStatement o, collector + # Oracle does not allow ORDER BY/LIMIT in UPDATEs. + if o.orders.any? && o.limit.nil? + # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, + # otherwise let the user deal with the error + o = o.dup + o.orders = [] + end + + super + end + end + end +end diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb new file mode 100644 index 0000000000000..cfa130fcab546 --- /dev/null +++ b/test/visitors/test_oracle12.rb @@ -0,0 +1,47 @@ +require 'helper' + +module Arel + module Visitors + describe 'the oracle visitor' do + before do + @visitor = Oracle12.new Table.engine.connection_pool + end + + def compile node + @visitor.accept(node, Collectors::SQLString.new).value + end + + it 'modified except to be minus' do + left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10") + right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20") + sql = compile Nodes::Except.new(left, right) + sql.must_be_like %{ + ( SELECT * FROM users WHERE age > 10 MINUS SELECT * FROM users WHERE age > 20 ) + } + end + + it 'generates select options offset then limit' do + stmt = Nodes::SelectStatement.new + stmt.offset = Nodes::Offset.new(1) + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) + sql = compile(stmt) + sql.must_be_like "SELECT OFFSET 1 ROWS FETCH FIRST 10 ROWS ONLY" + end + + describe 'locking' do + it 'removes limit when locking' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) + stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + sql = compile(stmt) + sql.must_be_like "SELECT FOR UPDATE" + end + + it 'defaults to FOR UPDATE when locking' do + node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + compile(node).must_be_like "FOR UPDATE" + end + end + end + end +end From d390046bd68bb7a65f1c846f4d58940981b7c6c6 Mon Sep 17 00:00:00 2001 From: Ilya Lavrov Date: Wed, 24 Jun 2015 17:16:04 +0300 Subject: [PATCH 1374/1492] Add nodes/casted.rb to gemspec file --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 43fbc680e89a2..015c74b446af8 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] - s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') From fd1df48c5c062affe9acc6decf554397e8be20a1 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Fri, 10 Jul 2015 13:49:57 -0400 Subject: [PATCH 1375/1492] No need to quote MySQL LIMIT --- lib/arel/visitors/mysql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index f989b8ddefcc9..724e0fc43e8aa 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -40,7 +40,7 @@ def visit_Arel_Nodes_Bin o, collector # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 def visit_Arel_Nodes_SelectStatement o, collector if o.offset && !o.limit - o.limit = Arel::Nodes::Limit.new(Nodes.build_quoted(18446744073709551615)) + o.limit = Arel::Nodes::Limit.new(18446744073709551615) end super end From 74563c63bdda08fdf1a026e908d51f536436c674 Mon Sep 17 00:00:00 2001 From: Eric Guo Date: Mon, 13 Jul 2015 13:09:59 +0800 Subject: [PATCH 1376/1492] Follow up #370 for Oracle, to fix undefined method `expr' for 10:Fixnum bug. --- lib/arel/visitors/oracle.rb | 2 +- test/visitors/test_oracle.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index ff9e38d0500ac..875b0e5b6a6c7 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -17,7 +17,7 @@ def visit_Arel_Nodes_SelectStatement o, collector if o.limit && o.offset o = o.dup - limit = o.limit.expr.expr + limit = o.limit.expr offset = o.offset o.offset = nil collector << " diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 41e77d93c000a..e9ed9d76b3a63 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -111,7 +111,7 @@ def compile node it 'creates a different subquery when there is an offset' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) + stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(10) sql = compile stmt sql.must_be_like %{ @@ -126,7 +126,7 @@ def compile node it 'is idempotent with different subquery' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) + stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(10) sql = compile stmt sql2 = compile stmt From ac5dfadb485ff1e06a73d69936de14464586af2c Mon Sep 17 00:00:00 2001 From: Sammy Larbi Date: Thu, 18 Jun 2015 06:30:54 -0500 Subject: [PATCH 1377/1492] Improve error message when passed unsupported type --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f2f9d20f21641..63097a23995a2 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -737,7 +737,7 @@ def quoted o, a end def unsupported o, collector - raise "unsupported: #{o.class.name}" + raise "unsupported argument type: #{o.class.name}. Construct an Arel node instead." end alias :visit_ActiveSupport_Multibyte_Chars :unsupported From 145f32ad8516f9654bdc469096c65549354829ab Mon Sep 17 00:00:00 2001 From: Sammy Larbi Date: Tue, 14 Jul 2015 17:17:15 -0500 Subject: [PATCH 1378/1492] Use a specific exception for unsupported visits --- lib/arel/visitors/to_sql.rb | 8 +++++++- test/visitors/test_to_sql.rb | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 63097a23995a2..ce1fdf80ce359 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -4,6 +4,12 @@ module Arel module Visitors + class UnsupportedVisitError < StandardError + def initialize(object) + super "Unsupported argument type: #{object.class.name}. Construct an Arel node instead." + end + end + class ToSql < Arel::Visitors::Reduce ## # This is some roflscale crazy stuff. I'm roflscaling this because @@ -737,7 +743,7 @@ def quoted o, a end def unsupported o, collector - raise "unsupported argument type: #{o.class.name}. Construct an Arel node instead." + raise UnsupportedVisitError.new(o) end alias :visit_ActiveSupport_Multibyte_Chars :unsupported diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 04fca8024b689..7ae5d5b3af45a 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -273,9 +273,9 @@ def dispatch compile(Nodes.build_quoted(nil)).must_be_like "NULL" end - it "unsupported input should not raise ArgumentError" do - error = assert_raises(RuntimeError) { compile(nil) } - assert_match(/\Aunsupported/, error.message) + it "unsupported input should raise UnsupportedVisitError" do + error = assert_raises(UnsupportedVisitError) { compile(nil) } + assert_match(/\AUnsupported/, error.message) end it "should visit_Arel_SelectManager, which is a subquery" do From 1aecf8b41ca3f238cb41c03902dacc8a5e3039f4 Mon Sep 17 00:00:00 2001 From: Carson Reinke Date: Thu, 23 Jul 2015 09:55:59 -0400 Subject: [PATCH 1379/1492] Add OrderPredications back into Nodes::Function (removed with deprecation of Expression) --- lib/arel/nodes/function.rb | 1 + test/nodes/test_sum.rb | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 733a00df46f10..182dfa73296bf 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -3,6 +3,7 @@ module Nodes class Function < Arel::Nodes::Node include Arel::Predications include Arel::WindowPredications + include Arel::OrderPredications attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb index d65cd31d4becf..d387e7f9efe82 100644 --- a/test/nodes/test_sum.rb +++ b/test/nodes/test_sum.rb @@ -21,4 +21,13 @@ assert_equal 2, array.uniq.size end end + + describe 'order' do + it 'should order the sum' do + table = Arel::Table.new :users + table[:id].sum.desc.to_sql.must_be_like %{ + SUM("users"."id") DESC + } + end + end end From 903de6f17c7923b25d750610c15325d28b398b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 4 Aug 2015 23:05:22 -0300 Subject: [PATCH 1380/1492] Improve travis configuration * Enable container builds * Notifications on Campfire * Bundle cache * Fast finish --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f7ac50ada5215..8168c24e330f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: ruby -script: +sudo: false +cache: bundler +script: - "rake test" - "gem build arel.gemspec" env: @@ -14,7 +16,14 @@ rvm: matrix: allow_failures: - rvm: rbx + fast_finish: true +bundler_args: --without test --jobs 3 --retry 3 notifications: email: false irc: - "irc.freenode.org#rails-contrib" + campfire: + on_success: change + on_failure: always + rooms: + - secure: "sD4VEjsiNHTb+9LYUy0ZiGu86nH1voUANpmiO62fvO1VPg80ReKv8vNiq285MZVjcPBx9lt1iNx1nNfVlBmDzRI1tWjoyEV5LTuCAt3yQMB5Qpjy3HH1FNgyY2TGjDhIDwgTD6d8+DOCQjj/vgqzWWu1jEJVdac1K5d+dc/uElI=" From c46242ee94aef0adb89216bec4768476dce0dd07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 4 Aug 2015 23:07:12 -0300 Subject: [PATCH 1381/1492] Run with Ruby 2.2 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8168c24e330f4..df4ccb3f57d70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,12 +12,13 @@ rvm: - jruby-head - 2.0.0 - 2.1 + - 2.2 - ruby-head matrix: allow_failures: - rvm: rbx fast_finish: true -bundler_args: --without test --jobs 3 --retry 3 +bundler_args: --jobs 3 --retry 3 notifications: email: false irc: From d5432b4616ff43fbb14540d351eed351e21bb20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 4 Aug 2015 23:17:24 -0300 Subject: [PATCH 1382/1492] Use bundled gems --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index df4ccb3f57d70..455e8b89318bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: ruby sudo: false cache: bundler script: - - "rake test" + - "bundle exec rake test" - "gem build arel.gemspec" env: global: From a7e9dd20114c812d4fba532f598791fbd94b2bac Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Tue, 1 Sep 2015 12:30:37 +0000 Subject: [PATCH 1383/1492] No need to quote limit for Oracle12 visitor --- test/visitors/test_oracle12.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index cfa130fcab546..df0f01b30b43d 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -23,7 +23,7 @@ def compile node it 'generates select options offset then limit' do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) - stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) + stmt.limit = Nodes::Limit.new(10) sql = compile(stmt) sql.must_be_like "SELECT OFFSET 1 ROWS FETCH FIRST 10 ROWS ONLY" end @@ -31,7 +31,7 @@ def compile node describe 'locking' do it 'removes limit when locking' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(Nodes.build_quoted(10)) + stmt.limit = Nodes::Limit.new(10) stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE')) sql = compile(stmt) sql.must_be_like "SELECT FOR UPDATE" From a8e8c2ff4df88210da4ba8f5de015632fb2d67e9 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Tue, 1 Sep 2015 12:41:14 +0000 Subject: [PATCH 1384/1492] Add "lib/arel/visitors/oracle12.rb" to its gemspec --- arel.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arel.gemspec b/arel.gemspec index 015c74b446af8..dd52c89e223af 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] - s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') From 17c5b6d3e330e122ecf418158bdb0d6558a93d1d Mon Sep 17 00:00:00 2001 From: maclover7 Date: Tue, 1 Sep 2015 11:20:19 -0400 Subject: [PATCH 1385/1492] Add CONTRIBUTING.md [ci skip] --- .travis.yml | 4 +- CONTRIBUTING.md | 100 +++++++++++++++++++++++++++++++++ MIT-LICENSE.txt => MIT-LICENSE | 3 +- README.markdown | 12 +++- 4 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 CONTRIBUTING.md rename MIT-LICENSE.txt => MIT-LICENSE (94%) diff --git a/.travis.yml b/.travis.yml index 455e8b89318bb..22287e11958fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,12 @@ env: global: - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - - rbx - - jruby-head - 2.0.0 - 2.1 - 2.2 - ruby-head + - rbx + - jruby-head matrix: allow_failures: - rvm: rbx diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000..104c05490f42a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,100 @@ +Contributing to Arel +===================== + +[![Build Status](https://secure.travis-ci.org/rails/arel.svg?branch=master)](http://travis-ci.org/rails/arel) +[![Dependency Status](https://gemnasium.com/rails/arel.svg)](https://gemnasium.com/rails/arel) + +Arel is work of [many contributors](https://github.com/rails/arel/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/rails/arel/pulls), [propose features and discuss issues](https://github.com/rails/arel/issues). + +#### Fork the Project + +Fork the [project on Github](https://github.com/rails/arel) and check out your copy. + +``` +git clone https://github.com/contributor/arel.git +cd arel +git remote add upstream https://github.com/rails/arel.git +``` + +#### Create a Topic Branch + +Make sure your fork is up-to-date and create a topic branch for your feature or bug fix. + +``` +git checkout master +git pull upstream master +git checkout -b my-feature-branch +``` + +#### Bundle Install and Test + +Ensure that you can build the project and run tests. + +``` +bundle install +bundle exec rake test +``` + +#### Write Tests + +Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [test](test). + +We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix. + +#### Write Code + +Implement your feature or bug fix. + +Make sure that `bundle exec rake test` completes without errors. + +#### Write Documentation + +Document any external behavior in the [README](README.md). + +#### Commit Changes + +Make sure git knows your name and email address: + +``` +git config --global user.name "Your Name" +git config --global user.email "contributor@example.com" +``` + +Writing good commit logs is important. A commit log should describe what changed and why. + +``` +git add ... +git commit +``` + +#### Push + +``` +git push origin my-feature-branch +``` + +#### Make a Pull Request + +Go to https://github.com/contributor/arel and select your feature branch. Click the 'Pull Request' button and fill out the form. Pull requests are usually reviewed within a few days. + +#### Rebase + +If you've been working on a change for a while, rebase with upstream/master. + +``` +git fetch upstream +git rebase upstream/master +git push origin my-feature-branch -f +``` + +#### Check on Your Pull Request + +Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above. + +#### Be Patient + +It's likely that your change will not be merged and that the nitpicky maintainers will ask you to do more, or fix seemingly benign problems. Hang on there! + +#### Thank You + +Please do know that we really appreciate and value your time and work. We love you, really. diff --git a/MIT-LICENSE.txt b/MIT-LICENSE similarity index 94% rename from MIT-LICENSE.txt rename to MIT-LICENSE index 52f1ff7a17f7a..001426b5b0047 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2007-2010 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson +Copyright (c) 2007-2015 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -18,3 +18,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/README.markdown b/README.markdown index 76efb2b34a715..d570f7855cf50 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -# Arel [![Build Status](https://secure.travis-ci.org/rails/arel.svg?branch=master)](http://travis-ci.org/rails/arel) [![Dependency Status](https://gemnasium.com/rails/arel.svg)](https://gemnasium.com/rails/arel) +# Arel * http://github.com/rails/arel @@ -222,6 +222,12 @@ photos.project(photo_clicks.as("photo_clicks")) FROM "photos" ``` -### License +## Contributing to Arel -Arel is released under the [MIT License](http://opensource.org/licenses/MIT). +Arel is work of many contributors. You're encouraged to submit pull requests, propose +features and discuss issues. + +See [CONTRIBUTING](CONTRIBUTING.md). + +## License +Arel is released under the [MIT License](http://www.opensource.org/licenses/MIT). From b275ffa3c4c325265217834c6e1a9d84b3ad808f Mon Sep 17 00:00:00 2001 From: Umang Raghuvanshi Date: Fri, 2 Oct 2015 19:02:55 +0530 Subject: [PATCH 1386/1492] Rename MIT-LICENSE to MIT-LICENSE.txt This renames MIT-LICENSE to MIT-LICENSE.txt. Closes #395, prevents builds from breaking. --- MIT-LICENSE => MIT-LICENSE.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename MIT-LICENSE => MIT-LICENSE.txt (100%) diff --git a/MIT-LICENSE b/MIT-LICENSE.txt similarity index 100% rename from MIT-LICENSE rename to MIT-LICENSE.txt From 508a6783c8f75742ac64e5073b3b211b0c15662a Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Sat, 5 Dec 2015 18:54:09 -0500 Subject: [PATCH 1387/1492] Add case sensitive match Explicitly declare if this is case sensitive or not most implementation assume case sensitive postgres assumes case insensitive --- lib/arel/nodes/matches.rb | 4 +++- lib/arel/predications.rb | 16 ++++++++-------- lib/arel/visitors/postgresql.rb | 6 ++++-- test/visitors/test_postgres.rb | 14 ++++++++++++++ 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb index 583fb97c9bfcf..0d9c1925dc9c7 100644 --- a/lib/arel/nodes/matches.rb +++ b/lib/arel/nodes/matches.rb @@ -2,10 +2,12 @@ module Arel module Nodes class Matches < Binary attr_reader :escape + attr_accessor :case_sensitive - def initialize(left, right, escape = nil) + def initialize(left, right, escape = nil, case_sensitive = false) super(left, right) @escape = escape && Nodes.build_quoted(escape) + @case_sensitive = case_sensitive end end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index b05fc6f99a78b..ed083f54025ce 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -118,20 +118,20 @@ def not_in_all others grouping_all :not_in, others end - def matches other, escape = nil - Nodes::Matches.new self, quoted_node(other), escape + def matches other, escape = nil, case_sensitive = false + Nodes::Matches.new self, quoted_node(other), escape, case_sensitive end - def matches_any others, escape = nil - grouping_any :matches, others, escape + def matches_any others, escape = nil, case_sensitive = false + grouping_any :matches, others, escape, case_sensitive end - def matches_all others, escape = nil - grouping_all :matches, others, escape + def matches_all others, escape = nil, case_sensitive = false + grouping_all :matches, others, escape, case_sensitive end - def does_not_match other, escape = nil - Nodes::DoesNotMatch.new self, quoted_node(other), escape + def does_not_match other, escape = nil, case_sensitive = false + Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive end def does_not_match_any others, escape = nil diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index bd23fc0a47985..75d2ad9c93326 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -4,7 +4,8 @@ class PostgreSQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Matches o, collector - collector = infix_value o, collector, ' ILIKE ' + op = o.case_sensitive ? ' LIKE ' : ' ILIKE ' + collector = infix_value o, collector, op if o.escape collector << ' ESCAPE ' visit o.escape, collector @@ -14,7 +15,8 @@ def visit_Arel_Nodes_Matches o, collector end def visit_Arel_Nodes_DoesNotMatch o, collector - collector = infix_value o, collector, ' NOT ILIKE ' + op = o.case_sensitive ? ' NOT LIKE ' : ' NOT ILIKE ' + collector = infix_value o, collector, op if o.escape collector << ' ESCAPE ' visit o.escape, collector diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index d6de216d91d9b..d00aa1c100817 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -58,6 +58,13 @@ def compile node } end + it "should know how to visit case sensitive" do + node = @table[:name].matches('foo%', nil, true) + compile(node).must_be_like %{ + "users"."name" LIKE 'foo%' + } + end + it "can handle ESCAPE" do node = @table[:name].matches('foo!%', '!') compile(node).must_be_like %{ @@ -82,6 +89,13 @@ def compile node } end + it "should know how to visit case sensitive" do + node = @table[:name].does_not_match('foo%', nil, true) + compile(node).must_be_like %{ + "users"."name" NOT LIKE 'foo%' + } + end + it "can handle ESCAPE" do node = @table[:name].does_not_match('foo!%', '!') compile(node).must_be_like %{ From 193d2ad2147a5cd1de44f2d57f4f3bd65e161293 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Sat, 5 Dec 2015 19:13:05 -0500 Subject: [PATCH 1388/1492] Add case sensitive regexp Explicitly declare if this is case sensitive or not currently postgres assumes case insensitive regexp no other databases support regexps --- lib/arel/nodes.rb | 1 + lib/arel/nodes/binary.rb | 2 -- lib/arel/nodes/regexp.rb | 14 ++++++++++++++ lib/arel/visitors/postgresql.rb | 6 ++++-- test/visitors/test_postgres.rb | 14 ++++++++++++++ 5 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 lib/arel/nodes/regexp.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 8d61bb320fdaa..0e66d2dd0cef7 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -30,6 +30,7 @@ require 'arel/nodes/infix_operation' require 'arel/nodes/over' require 'arel/nodes/matches' +require 'arel/nodes/regexp' # nary require 'arel/nodes/and' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index dddbde14313ac..763091c26708a 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -38,9 +38,7 @@ def eql? other LessThanOrEqual NotEqual NotIn - NotRegexp Or - Regexp Union UnionAll Intersect diff --git a/lib/arel/nodes/regexp.rb b/lib/arel/nodes/regexp.rb new file mode 100644 index 0000000000000..784368f5bfacb --- /dev/null +++ b/lib/arel/nodes/regexp.rb @@ -0,0 +1,14 @@ +module Arel + module Nodes + class Regexp < Binary + attr_accessor :case_sensitive + + def initialize(left, right, case_sensitive = true) + super(left, right) + @case_sensitive = case_sensitive + end + end + + class NotRegexp < Regexp; end + end +end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 75d2ad9c93326..1ef0261bdde2c 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -26,11 +26,13 @@ def visit_Arel_Nodes_DoesNotMatch o, collector end def visit_Arel_Nodes_Regexp o, collector - infix_value o, collector, ' ~ ' + op = o.case_sensitive ? ' ~ ' : ' ~* ' + infix_value o, collector, op end def visit_Arel_Nodes_NotRegexp o, collector - infix_value o, collector, ' !~ ' + op = o.case_sensitive ? ' !~ ' : ' !~* ' + infix_value o, collector, op end def visit_Arel_Nodes_DistinctOn o, collector diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index d00aa1c100817..e6fd4cd0dacfb 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -120,6 +120,13 @@ def compile node } end + it "can handle case insensitive" do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'), false) + compile(node).must_be_like %{ + "users"."name" ~* 'foo%' + } + end + it 'can handle subqueries' do subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))) node = @attr.in subquery @@ -137,6 +144,13 @@ def compile node } end + it "can handle case insensitive" do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'), false) + compile(node).must_be_like %{ + "users"."name" !~* 'foo%' + } + end + it 'can handle subqueries' do subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))) node = @attr.in subquery From 4e7b4693b89d920e43f5c2c94b44957a3f392a80 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Sat, 5 Dec 2015 19:49:44 -0500 Subject: [PATCH 1389/1492] use valid regular expression in regexp test --- test/visitors/test_postgres.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index e6fd4cd0dacfb..4209712e8e3ba 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -114,48 +114,48 @@ def compile node describe "Nodes::Regexp" do it "should know how to visit" do - node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo.*')) compile(node).must_be_like %{ - "users"."name" ~ 'foo%' + "users"."name" ~ 'foo.*' } end it "can handle case insensitive" do - node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'), false) + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo.*'), false) compile(node).must_be_like %{ - "users"."name" ~* 'foo%' + "users"."name" ~* 'foo.*' } end it 'can handle subqueries' do - subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%'))) + subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo.*'))) node = @attr.in subquery compile(node).must_be_like %{ - "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo%') + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo.*') } end end describe "Nodes::NotRegexp" do it "should know how to visit" do - node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo.*')) compile(node).must_be_like %{ - "users"."name" !~ 'foo%' + "users"."name" !~ 'foo.*' } end it "can handle case insensitive" do - node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'), false) + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo.*'), false) compile(node).must_be_like %{ - "users"."name" !~* 'foo%' + "users"."name" !~* 'foo.*' } end it 'can handle subqueries' do - subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%'))) + subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo.*'))) node = @attr.in subquery compile(node).must_be_like %{ - "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo%') + "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo.*') } end end From d2e6be1677b124b3eef5b3ebe0fd4a0d31d8a2bf Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Sat, 5 Dec 2015 20:23:12 -0500 Subject: [PATCH 1390/1492] introduce predicate {does_not_}matches_regexp --- lib/arel/predications.rb | 8 ++++++++ test/visitors/test_postgres.rb | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index ed083f54025ce..1d2b0de235dd4 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -122,6 +122,10 @@ def matches other, escape = nil, case_sensitive = false Nodes::Matches.new self, quoted_node(other), escape, case_sensitive end + def matches_regexp other, case_sensitive = true + Nodes::Regexp.new self, quoted_node(other), case_sensitive + end + def matches_any others, escape = nil, case_sensitive = false grouping_any :matches, others, escape, case_sensitive end @@ -134,6 +138,10 @@ def does_not_match other, escape = nil, case_sensitive = false Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive end + def does_not_match_regexp other, case_sensitive = true + Nodes::NotRegexp.new self, quoted_node(other), case_sensitive + end + def does_not_match_any others, escape = nil grouping_any :does_not_match, others, escape end diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 4209712e8e3ba..5901c569689e6 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -114,21 +114,25 @@ def compile node describe "Nodes::Regexp" do it "should know how to visit" do - node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo.*')) + node = @table[:name].matches_regexp('foo.*') + node.must_be_kind_of Nodes::Regexp + node.case_sensitive.must_equal(true) compile(node).must_be_like %{ "users"."name" ~ 'foo.*' } end it "can handle case insensitive" do - node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo.*'), false) + node = @table[:name].matches_regexp('foo.*', false) + node.must_be_kind_of Nodes::Regexp + node.case_sensitive.must_equal(false) compile(node).must_be_like %{ "users"."name" ~* 'foo.*' } end it 'can handle subqueries' do - subquery = @table.project(:id).where(Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo.*'))) + subquery = @table.project(:id).where(@table[:name].matches_regexp('foo.*')) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo.*') @@ -138,21 +142,24 @@ def compile node describe "Nodes::NotRegexp" do it "should know how to visit" do - node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo.*')) + node = @table[:name].does_not_match_regexp('foo.*') + node.must_be_kind_of Nodes::NotRegexp + node.case_sensitive.must_equal(true) compile(node).must_be_like %{ "users"."name" !~ 'foo.*' } end it "can handle case insensitive" do - node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo.*'), false) + node = @table[:name].does_not_match_regexp('foo.*', false) + node.case_sensitive.must_equal(false) compile(node).must_be_like %{ "users"."name" !~* 'foo.*' } end it 'can handle subqueries' do - subquery = @table.project(:id).where(Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo.*'))) + subquery = @table.project(:id).where(@table[:name].does_not_match_regexp('foo.*')) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo.*') From 725cf0502eb279c728bd93320cc5e22134228ff1 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Sat, 5 Dec 2015 20:23:48 -0500 Subject: [PATCH 1391/1492] test match predicate case sensitivity attribute --- test/visitors/test_postgres.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 5901c569689e6..4b7dbe367f45c 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -53,6 +53,8 @@ def compile node describe "Nodes::Matches" do it "should know how to visit" do node = @table[:name].matches('foo%') + node.must_be_kind_of Nodes::Matches + node.case_sensitive.must_equal(false) compile(node).must_be_like %{ "users"."name" ILIKE 'foo%' } @@ -60,6 +62,7 @@ def compile node it "should know how to visit case sensitive" do node = @table[:name].matches('foo%', nil, true) + node.case_sensitive.must_equal(true) compile(node).must_be_like %{ "users"."name" LIKE 'foo%' } @@ -84,6 +87,8 @@ def compile node describe "Nodes::DoesNotMatch" do it "should know how to visit" do node = @table[:name].does_not_match('foo%') + node.must_be_kind_of Nodes::DoesNotMatch + node.case_sensitive.must_equal(false) compile(node).must_be_like %{ "users"."name" NOT ILIKE 'foo%' } @@ -91,6 +96,7 @@ def compile node it "should know how to visit case sensitive" do node = @table[:name].does_not_match('foo%', nil, true) + node.case_sensitive.must_equal(true) compile(node).must_be_like %{ "users"."name" NOT LIKE 'foo%' } From f726dbe0802395aabf9cc99fe34bc69b375bf344 Mon Sep 17 00:00:00 2001 From: Edward Paget Date: Wed, 14 Jan 2015 12:23:37 -0600 Subject: [PATCH 1392/1492] Delegate to Connection Visitor in WhereSQL Visitor The WhereSQL visitor always uses the generic ToSQL visitor to create the where clause sql statement. This means that it'll miss database specific statements, such as 'ILIKE' in PostgreSQL. Since the `#where_sql` method is mainly used for ActiveRecord error reporting, this discrepancy could be confusing to users. This patch changes the WhereSQL visitor to use the its connection visitor to generate SQL for each statement in the SelectManager's wheres array. Then lets them be joined together with ' AND '. --- lib/arel/visitors/where_sql.rb | 6 +++++- test/test_select_manager.rb | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index afde15a6c5bb2..80797205c9663 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -5,7 +5,11 @@ class WhereSql < Arel::Visitors::ToSql def visit_Arel_Nodes_SelectCore o, collector collector << "WHERE " - inject_join o.wheres, collector, ' AND ' + wheres = o.wheres.map do |where| + Nodes::SqlLiteral.new(@connection.visitor.accept(where, collector.class.new).value) + end + + inject_join wheres, collector, ' AND ' end end end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 8425cee031e3f..e6b13e748dd3f 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -968,6 +968,27 @@ def test_manager_stores_bind_values manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 } end + it 'joins wheres with AND' do + table = Table.new :users + manager = Arel::SelectManager.new + manager.from table + manager.where table[:id].eq 10 + manager.where table[:id].eq 11 + manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 AND "users"."id" = 11} + end + + it 'handles database specific statements' do + old_visitor = Table.engine.connection.visitor + Table.engine.connection.visitor = Visitors::PostgreSQL.new Table.engine.connection + table = Table.new :users + manager = Arel::SelectManager.new + manager.from table + manager.where table[:id].eq 10 + manager.where table[:name].matches 'foo%' + manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 AND "users"."name" ILIKE 'foo%' } + Table.engine.connection.visitor = old_visitor + end + it 'returns nil when there are no wheres' do table = Table.new :users manager = Arel::SelectManager.new From cd395b9419ac3a860ee78cf9706af1bf7d86fe92 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Thu, 17 Dec 2015 12:54:27 -0700 Subject: [PATCH 1393/1492] Inject the visitor rather than relying on other objects internals This is ultimately messy no matter what, and increases the coupling to the database backend, but we can at least contain it somewhat into an object that's already coupled. --- lib/arel/select_manager.rb | 2 +- lib/arel/visitors/where_sql.rb | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index f7dec87ca3d7e..eae3bc8cbc0b9 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -179,7 +179,7 @@ def orders def where_sql engine = Table.engine return if @ctx.wheres.empty? - viz = Visitors::WhereSql.new engine.connection + viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection) Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value end diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index 80797205c9663..41972d5836136 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -1,12 +1,17 @@ module Arel module Visitors class WhereSql < Arel::Visitors::ToSql + def initialize(inner_visitor, *args, &block) + @inner_visitor = inner_visitor + super(*args, &block) + end + private def visit_Arel_Nodes_SelectCore o, collector collector << "WHERE " wheres = o.wheres.map do |where| - Nodes::SqlLiteral.new(@connection.visitor.accept(where, collector.class.new).value) + Nodes::SqlLiteral.new(@inner_visitor.accept(where, collector.class.new).value) end inject_join wheres, collector, ' AND ' From ea2d50706a5f8215ff2346fa562423700b2d2b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 17 Dec 2015 18:03:45 -0200 Subject: [PATCH 1394/1492] Release 7.0.0 --- History.txt | 8 ++++++++ arel.gemspec | 2 +- lib/arel.rb | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index b161f5ca194be..9d4cd32461dcc 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,11 @@ +=== 7.0.0 / 2015-12-17 + +* Enhancements + + * Remove deprecated method `Table#primary_key` + * Remove engine from the constructor arguments `Arel::Table` + * Deprecate automatic type casting within Arel + === 6.0.0 / 2014-11-25 * Enhancements diff --git a/arel.gemspec b/arel.gemspec index dd52c89e223af..df619df049dcf 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.markdown"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] - s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/lib/arel.rb b/lib/arel.rb index aab93913d5876..f32929e70f083 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '7.0.0.alpha' + VERSION = '7.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From c920e9d2c033ec8a7e13cb70a2cd5820b2d45167 Mon Sep 17 00:00:00 2001 From: Vinicius Tadeu Date: Sun, 27 Dec 2015 10:37:35 -0200 Subject: [PATCH 1395/1492] Rename README.markdown to README.md --- README.markdown => README.md | 0 Rakefile | 2 +- arel.gemspec | 6 +++--- arel.gemspec.erb | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename README.markdown => README.md (100%) diff --git a/README.markdown b/README.md similarity index 100% rename from README.markdown rename to README.md diff --git a/Rakefile b/Rakefile index 956e95c939931..02b92e0b44a85 100644 --- a/Rakefile +++ b/Rakefile @@ -17,7 +17,7 @@ specname = "arel.gemspec" deps = `git ls-files`.split("\n") - [specname] file specname => deps do - files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] + `git ls-files -- lib`.split("\n") + files = ["History.txt", "MIT-LICENSE.txt", "README.md"] + `git ls-files -- lib`.split("\n") require 'erb' diff --git a/arel.gemspec b/arel.gemspec index df619df049dcf..492d2d0bdb1e4 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -13,10 +13,10 @@ Gem::Specification.new do |s| s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" s.license = %q{MIT} - s.rdoc_options = ["--main", "README.markdown"] - s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] + s.rdoc_options = ["--main", "README.md"] + s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.markdown","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/arel.gemspec.erb b/arel.gemspec.erb index 7ed75226cabee..a64e585a28483 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -13,8 +13,8 @@ Gem::Specification.new do |s| s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" s.license = %q{MIT} - s.rdoc_options = ["--main", "README.markdown"] - s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.markdown"] + s.rdoc_options = ["--main", "README.md"] + s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] s.files = [<%= files.map(&:inspect).join ',' %>] s.require_paths = ["lib"] From 47894d4b14e6a3ffd88ff9a48fd0a2d4171eda0f Mon Sep 17 00:00:00 2001 From: Jeroen Visser Date: Fri, 1 Jan 2016 01:44:27 +0100 Subject: [PATCH 1396/1492] Update copyright year New year, new license! --- MIT-LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt index 001426b5b0047..f7a59c3c5fd8b 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2007-2015 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson +Copyright (c) 2007-2016 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 From 4c7e50f9328aca4e294b41fce0832bf6ac4a939a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Bu=CC=88nemann?= Date: Sat, 19 Dec 2015 19:40:46 +0100 Subject: [PATCH 1397/1492] Implement CASE Conditional Expression --- lib/arel/nodes.rb | 3 ++ lib/arel/nodes/case.rb | 57 +++++++++++++++++++++ lib/arel/predications.rb | 4 ++ lib/arel/visitors/depth_first.rb | 10 +++- lib/arel/visitors/to_sql.rb | 29 +++++++++++ test/nodes/test_case.rb | 82 +++++++++++++++++++++++++++++++ test/visitors/test_depth_first.rb | 12 +++++ test/visitors/test_to_sql.rb | 60 ++++++++++++++++++++++ 8 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/case.rb create mode 100644 test/nodes/test_case.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 0e66d2dd0cef7..89f0f563acb40 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -47,6 +47,9 @@ # windows require 'arel/nodes/window' +# conditional expressions +require 'arel/nodes/case' + # joins require 'arel/nodes/full_outer_join' require 'arel/nodes/inner_join' diff --git a/lib/arel/nodes/case.rb b/lib/arel/nodes/case.rb new file mode 100644 index 0000000000000..85f8851dbe900 --- /dev/null +++ b/lib/arel/nodes/case.rb @@ -0,0 +1,57 @@ +module Arel + module Nodes + class Case < Arel::Nodes::Node + include Arel::OrderPredications + include Arel::Predications + include Arel::AliasPredication + + attr_accessor :case, :conditions, :default + + def initialize expression = nil, default = nil + @case = expression + @conditions = [] + @default = default + end + + def when condition, expression = nil + @conditions << When.new(Nodes.build_quoted(condition), expression) + self + end + + def then expression + @conditions.last.right = Nodes.build_quoted(expression) + self + end + + def else expression + @default = Else.new Nodes.build_quoted(expression) + self + end + + def initialize_copy other + super + @case = @case.clone if @case + @conditions = @conditions.map { |x| x.clone } + @default = @default.clone if @default + end + + def hash + [@case, @conditions, @default].hash + end + + def eql? other + self.class == other.class && + self.case == other.case && + self.conditions == other.conditions && + self.default == other.default + end + alias :== :eql? + end + + class When < Binary # :nodoc: + end + + class Else < Unary # :nodoc: + end + end +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 1d2b0de235dd4..e9078e9c4bd9e 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -198,6 +198,10 @@ def lteq_all others grouping_all :lteq, others end + def when right + Nodes::Case.new(self).when quoted_node(right) + end + private def grouping_any method_id, others, *extras diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 22704dd038870..2f71455580316 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -16,6 +16,7 @@ def visit o def unary o visit o.expr end + alias :visit_Arel_Nodes_Else :unary alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary @@ -53,6 +54,12 @@ def visit_Arel_Nodes_Count o visit o.distinct end + def visit_Arel_Nodes_Case o + visit o.case + visit o.conditions + visit o.default + end + def nary o o.children.each { |child| visit child} end @@ -86,8 +93,9 @@ def binary o alias :visit_Arel_Nodes_Regexp :binary alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary - alias :visit_Arel_Nodes_Values :binary alias :visit_Arel_Nodes_Union :binary + alias :visit_Arel_Nodes_Values :binary + alias :visit_Arel_Nodes_When :binary def visit_Arel_Nodes_StringJoin o visit o.left diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ce1fdf80ce359..598bf2d98406c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -708,6 +708,35 @@ def visit_Arel_Nodes_As o, collector visit o.right, collector end + def visit_Arel_Nodes_Case o, collector + collector << "CASE " + if o.case + visit o.case, collector + collector << " " + end + o.conditions.each do |condition| + visit condition, collector + collector << " " + end + if o.default + visit o.default, collector + collector << " " + end + collector << "END" + end + + def visit_Arel_Nodes_When o, collector + collector << "WHEN " + visit o.left, collector + collector << " THEN " + visit o.right, collector + end + + def visit_Arel_Nodes_Else o, collector + collector << "ELSE " + visit o.expr, collector + end + def visit_Arel_Nodes_UnqualifiedColumn o, collector collector << "#{quote_column_name o.name}" collector diff --git a/test/nodes/test_case.rb b/test/nodes/test_case.rb new file mode 100644 index 0000000000000..a813ec7e695ea --- /dev/null +++ b/test/nodes/test_case.rb @@ -0,0 +1,82 @@ +require 'helper' + +module Arel + module Nodes + describe 'Case' do + describe '#initialize' do + it 'sets case expression from first argument' do + node = Case.new 'foo' + + assert_equal 'foo', node.case + end + + it 'sets default case from second argument' do + node = Case.new nil, 'bar' + + assert_equal 'bar', node.default + end + end + + describe '#clone' do + it 'clones case, conditions and default' do + foo = Nodes.build_quoted 'foo' + + node = Case.new + node.case = foo + node.conditions = [When.new(foo, foo)] + node.default = foo + + dolly = node.clone + + assert_equal dolly.case, node.case + refute_same dolly.case, node.case + + assert_equal dolly.conditions, node.conditions + refute_same dolly.conditions, node.conditions + + assert_equal dolly.default, node.default + refute_same dolly.default, node.default + end + end + + describe 'equality' do + it 'is equal with equal ivars' do + foo = Nodes.build_quoted 'foo' + one = Nodes.build_quoted 1 + zero = Nodes.build_quoted 0 + + case1 = Case.new foo + case1.conditions = [When.new(foo, one)] + case1.default = Else.new zero + + case2 = Case.new foo + case2.conditions = [When.new(foo, one)] + case2.default = Else.new zero + + array = [case1, case2] + + assert_equal 1, array.uniq.size + end + + it 'is not equal with different ivars' do + foo = Nodes.build_quoted 'foo' + bar = Nodes.build_quoted 'bar' + one = Nodes.build_quoted 1 + zero = Nodes.build_quoted 0 + + case1 = Case.new foo + case1.conditions = [When.new(foo, one)] + case1.default = Else.new zero + + case2 = Case.new foo + case2.conditions = [When.new(bar, one)] + case2.default = Else.new zero + + array = [case1, case2] + + assert_equal 2, array.uniq.size + end + end + end + end +end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 3356759b7d79d..1a72789f83515 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -34,6 +34,7 @@ def test_raises_with_object Arel::Nodes::UnqualifiedColumn, Arel::Nodes::Top, Arel::Nodes::Limit, + Arel::Nodes::Else, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do op = klass.new(:a) @@ -118,6 +119,7 @@ def test_right_outer_join Arel::Nodes::As, Arel::Nodes::DeleteStatement, Arel::Nodes::JoinSource, + Arel::Nodes::When, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do binary = klass.new(:a, :b) @@ -247,6 +249,16 @@ def test_insert_statement assert_equal [:a, :b, stmt.columns, :c, stmt], @collector.calls end + def test_case + node = Arel::Nodes::Case.new + node.case = :a + node.conditions << :b + node.default = :c + + @visitor.accept node + assert_equal [:a, :b, node.conditions, :c, node], @collector.calls + end + def test_node node = Nodes::Node.new @visitor.accept node diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 7ae5d5b3af45a..ea58039529e96 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -607,6 +607,66 @@ def quote value, column = nil end end end + + describe 'Nodes::Case' do + it 'supports simple case expressions' do + node = Arel::Nodes::Case.new(@table[:name]) + .when('foo').then(1) + .else(0) + + compile(node).must_be_like %{ + CASE "users"."name" WHEN 'foo' THEN 1 ELSE 0 END + } + end + + it 'supports extended case expressions' do + node = Arel::Nodes::Case.new + .when(@table[:name].in(%w(foo bar))).then(1) + .else(0) + + compile(node).must_be_like %{ + CASE WHEN "users"."name" IN ('foo', 'bar') THEN 1 ELSE 0 END + } + end + + it 'works without default branch' do + node = Arel::Nodes::Case.new(@table[:name]) + .when('foo').then(1) + + compile(node).must_be_like %{ + CASE "users"."name" WHEN 'foo' THEN 1 END + } + end + + it 'allows chaining multiple conditions' do + node = Arel::Nodes::Case.new(@table[:name]) + .when('foo').then(1) + .when('bar').then(2) + .else(0) + + compile(node).must_be_like %{ + CASE "users"."name" WHEN 'foo' THEN 1 WHEN 'bar' THEN 2 ELSE 0 END + } + end + + it 'supports #when with two arguments and no #then' do + node = Arel::Nodes::Case.new @table[:name] + + { foo: 1, bar: 0 }.reduce(node) { |node, pair| node.when *pair } + + compile(node).must_be_like %{ + CASE "users"."name" WHEN 'foo' THEN 1 WHEN 'bar' THEN 0 END + } + end + + it 'can be chained as a predicate' do + node = @table[:name].when('foo').then('bar').else('baz') + + compile(node).must_be_like %{ + CASE "users"."name" WHEN 'foo' THEN 'bar' ELSE 'baz' END + } + end + end end end end From 83c47c1962827698eb0ed58d191f121cedf89385 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Thu, 31 Dec 2015 20:22:07 -0500 Subject: [PATCH 1398/1492] Add database specific string concatenation --- lib/arel/nodes/infix_operation.rb | 7 ++++++- lib/arel/predications.rb | 4 ++++ lib/arel/visitors/depth_first.rb | 1 + lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/mysql.rb | 8 ++++++++ test/visitors/test_depth_first.rb | 1 + test/visitors/test_mysql.rb | 18 ++++++++++++++++++ test/visitors/test_to_sql.rb | 10 ++++++++-- 8 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb index 3911a1e05e8e1..a3f04da6fa504 100644 --- a/lib/arel/nodes/infix_operation.rb +++ b/lib/arel/nodes/infix_operation.rb @@ -40,5 +40,10 @@ def initialize left, right end end + class Concat < InfixOperation + def initialize left, right + super('||', left, right) + end + end end -end \ No newline at end of file +end diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index e9078e9c4bd9e..81bf3b4d954cf 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -202,6 +202,10 @@ def when right Nodes::Case.new(self).when quoted_node(right) end + def concat other + Nodes::Concat.new self, other + end + private def grouping_any method_id, others, *extras diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 2f71455580316..fb21fb1e700a7 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -72,6 +72,7 @@ def binary o alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary + alias :visit_Arel_Nodes_Concat :binary alias :visit_Arel_Nodes_DeleteStatement :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index e0c02d717a372..da75423523449 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -176,6 +176,7 @@ def binary o alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary + alias :visit_Arel_Nodes_Concat :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary alias :visit_Arel_Nodes_GreaterThan :binary diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index 724e0fc43e8aa..ac3ad7b470a14 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -72,6 +72,14 @@ def visit_Arel_Nodes_UpdateStatement o, collector maybe_visit o.limit, collector end + def visit_Arel_Nodes_Concat o, collector + collector << " CONCAT(" + visit o.left, collector + collector << ", " + visit o.right, collector + collector << ") " + collector + end end end end diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 1a72789f83515..81220b63a4d52 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -103,6 +103,7 @@ def test_right_outer_join [ Arel::Nodes::Assignment, Arel::Nodes::Between, + Arel::Nodes::Concat, Arel::Nodes::DoesNotMatch, Arel::Nodes::Equality, Arel::Nodes::GreaterThan, diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 8e4b9e6861e92..30dcea3d36b40 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -55,6 +55,24 @@ def compile node compile(node).must_be_like "LOCK IN SHARE MODE" end end + + describe "concat" do + it "concats columns" do + @table = Table.new(:users) + query = @table[:name].concat(@table[:name]) + compile(query).must_be_like %{ + CONCAT("users"."name", "users"."name") + } + end + + it "concats a string" do + @table = Table.new(:users) + query = @table[:name].concat(Nodes.build_quoted('abc')) + compile(query).must_be_like %{ + CONCAT("users"."name", 'abc') + } + end + end end end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index ea58039529e96..4162d970b5c2f 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -469,13 +469,19 @@ def quote value, column = nil compile(node).must_equal %(("products"."price" - 7)) end + it "should handle Concatination" do + table = Table.new(:users) + node = table[:name].concat(table[:name]) + compile(node).must_equal %("users"."name" || "users"."name") + end + it "should handle arbitrary operators" do node = Arel::Nodes::InfixOperation.new( - '||', + '&&', Arel::Attributes::String.new(Table.new(:products), :name), Arel::Attributes::String.new(Table.new(:products), :name) ) - compile(node).must_equal %("products"."name" || "products"."name") + compile(node).must_equal %("products"."name" && "products"."name") end end From c22abda79b7f0fbee5f0ef0e9648d52d7d483902 Mon Sep 17 00:00:00 2001 From: Shahbaz Javeed Date: Thu, 10 Dec 2015 16:50:28 -0500 Subject: [PATCH 1399/1492] * Support for bitwise operations as infix operators. Tests included. *** Individual commit messages included below *** * Preliminary support for bitwise operations as infix operators. Tests to follow. * Added bitwise xor, shift left and shift right operators * Fixed the BitwiseOr class so it uses the :| operator instead of :& * All the methods for the bitwise operators in the Arel::Math module now wrap them up in Arel::Nodes::Grouping so the operation becomes isolated like addition and subtraction * Preliminary set of tests for the new operators * Updated README with examples of bitwise operations * Added a new UnaryOperation class which is a riff on the InfixOperation class * Added tests for UnaryOperation (inspired by InfixOperation tests) * Added the bitwise not (~) operator as a UnaryOperation * Added tests for the bitwise not operator * Added documentation for the bitwise not operator * Updated gemspec using `rake arel.gemspec` --- README.md | 11 +++++++++ arel.gemspec | 2 +- lib/arel/math.rb | 24 ++++++++++++++++++ lib/arel/nodes.rb | 1 + lib/arel/nodes/infix_operation.rb | 30 +++++++++++++++++++++++ lib/arel/nodes/unary_operation.rb | 25 +++++++++++++++++++ lib/arel/visitors/to_sql.rb | 5 ++++ test/nodes/test_unary_operation.rb | 39 ++++++++++++++++++++++++++++++ test/visitors/test_to_sql.rb | 37 ++++++++++++++++++++++++++++ 9 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 lib/arel/nodes/unary_operation.rb create mode 100644 test/nodes/test_unary_operation.rb diff --git a/README.md b/README.md index d570f7855cf50..48df6700c4fba 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,17 @@ users.where(users[:age].gteq(10)).project(Arel.sql('*')) # => SELECT * FROM "use users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" IN (20, 16, 17) ``` +Bitwise operators `&`, `|`, `^`, `<<`, `>>`: + +```ruby +users.where((users[:bitmap] & 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" & 16) > 0 +users.where((users[:bitmap] | 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" | 16) > 0 +users.where((users[:bitmap] ^ 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" ^ 16) > 0 +users.where((users[:bitmap] << 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" << 1) > 0 +users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" >> 1) > 0 +users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*')) # => SELECT FROM "users" WHERE ~ "users"."bitmap" > 0 +``` + Joins resemble SQL strongly: ```ruby diff --git a/arel.gemspec b/arel.gemspec index 492d2d0bdb1e4..68b5a72101e8b 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -16,7 +16,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/lib/arel/math.rb b/lib/arel/math.rb index f3dbc7bc49438..04cae845984f3 100644 --- a/lib/arel/math.rb +++ b/lib/arel/math.rb @@ -15,5 +15,29 @@ def -(other) def /(other) Arel::Nodes::Division.new(self, other) end + + def &(other) + Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseAnd.new(self, other)) + end + + def |(other) + Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseOr.new(self, other)) + end + + def ^(other) + Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseXor.new(self, other)) + end + + def <<(other) + Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseShiftLeft.new(self, other)) + end + + def >>(other) + Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseShiftRight.new(self, other)) + end + + def ~@ + Arel::Nodes::BitwiseNot.new(self) + end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 89f0f563acb40..ff27bb9aa822f 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -28,6 +28,7 @@ require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' require 'arel/nodes/infix_operation' +require 'arel/nodes/unary_operation' require 'arel/nodes/over' require 'arel/nodes/matches' require 'arel/nodes/regexp' diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb index a3f04da6fa504..55ac715f73907 100644 --- a/lib/arel/nodes/infix_operation.rb +++ b/lib/arel/nodes/infix_operation.rb @@ -45,5 +45,35 @@ def initialize left, right super('||', left, right) end end + + class BitwiseAnd < InfixOperation + def initialize left, right + super(:&, left, right) + end + end + + class BitwiseOr < InfixOperation + def initialize left, right + super(:|, left, right) + end + end + + class BitwiseXor < InfixOperation + def initialize left, right + super(:^, left, right) + end + end + + class BitwiseShiftLeft < InfixOperation + def initialize left, right + super(:<<, left, right) + end + end + + class BitwiseShiftRight < InfixOperation + def initialize left, right + super(:>>, left, right) + end + end end end diff --git a/lib/arel/nodes/unary_operation.rb b/lib/arel/nodes/unary_operation.rb new file mode 100644 index 0000000000000..1636c012792fe --- /dev/null +++ b/lib/arel/nodes/unary_operation.rb @@ -0,0 +1,25 @@ +module Arel + module Nodes + + class UnaryOperation < Unary + include Arel::Expressions + include Arel::Predications + include Arel::OrderPredications + include Arel::AliasPredication + include Arel::Math + + attr_reader :operator + + def initialize operator, operand + super(operand) + @operator = operator + end + end + + class BitwiseNot < UnaryOperation + def initialize operand + super(:~, operand) + end + end + end +end \ No newline at end of file diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 598bf2d98406c..80bea56ce628f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -801,6 +801,11 @@ def visit_Arel_Nodes_InfixOperation o, collector alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation + def visit_Arel_Nodes_UnaryOperation o, collector + collector << " #{o.operator} " + visit o.expr, collector + end + def visit_Array o, collector inject_join o, collector, ", " end diff --git a/test/nodes/test_unary_operation.rb b/test/nodes/test_unary_operation.rb new file mode 100644 index 0000000000000..d89c10b43118b --- /dev/null +++ b/test/nodes/test_unary_operation.rb @@ -0,0 +1,39 @@ +require 'helper' + +module Arel + module Nodes + class TestUnaryOperation < Minitest::Test + def test_construct + operation = UnaryOperation.new :-, 1 + assert_equal :-, operation.operator + assert_equal 1, operation.expr + end + + def test_operation_alias + operation = UnaryOperation.new :-, 1 + aliaz = operation.as('zomg') + assert_kind_of As, aliaz + assert_equal operation, aliaz.left + assert_equal 'zomg', aliaz.right + end + + def test_operation_ordering + operation = UnaryOperation.new :-, 1 + ordering = operation.desc + assert_kind_of Descending, ordering + assert_equal operation, ordering.expr + assert ordering.descending? + end + + def test_equality_with_same_ivars + array = [UnaryOperation.new(:-, 1), UnaryOperation.new(:-, 1)] + assert_equal 1, array.uniq.size + end + + def test_inequality_with_different_ivars + array = [UnaryOperation.new(:-, 1), UnaryOperation.new(:-, 2)] + assert_equal 2, array.uniq.size + end + end + end +end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 4162d970b5c2f..6da86c2deecc4 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -475,6 +475,31 @@ def quote value, column = nil compile(node).must_equal %("users"."name" || "users"."name") end + it "should handle BitwiseAnd" do + node = Arel::Attributes::Integer.new(Table.new(:products), :bitmap) & 16 + compile(node).must_equal %(("products"."bitmap" & 16)) + end + + it "should handle BitwiseOr" do + node = Arel::Attributes::Integer.new(Table.new(:products), :bitmap) | 16 + compile(node).must_equal %(("products"."bitmap" | 16)) + end + + it "should handle BitwiseXor" do + node = Arel::Attributes::Integer.new(Table.new(:products), :bitmap) ^ 16 + compile(node).must_equal %(("products"."bitmap" ^ 16)) + end + + it "should handle BitwiseShiftLeft" do + node = Arel::Attributes::Integer.new(Table.new(:products), :bitmap) << 4 + compile(node).must_equal %(("products"."bitmap" << 4)) + end + + it "should handle BitwiseShiftRight" do + node = Arel::Attributes::Integer.new(Table.new(:products), :bitmap) >> 4 + compile(node).must_equal %(("products"."bitmap" >> 4)) + end + it "should handle arbitrary operators" do node = Arel::Nodes::InfixOperation.new( '&&', @@ -485,6 +510,18 @@ def quote value, column = nil end end + describe "Nodes::UnaryOperation" do + it "should handle BitwiseNot" do + node = ~ Arel::Attributes::Integer.new(Table.new(:products), :bitmap) + compile(node).must_equal %( ~ "products"."bitmap") + end + + it "should handle arbitrary operators" do + node = Arel::Nodes::UnaryOperation.new('!', Arel::Attributes::String.new(Table.new(:products), :active)) + compile(node).must_equal %( ! "products"."active") + end + end + describe "Nodes::NotIn" do it "should know how to visit" do node = @attr.not_in [1, 2, 3] From 63ea665c8083f8069a0d05d4f15cf19e08e470a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 6 Jan 2016 14:25:22 -0200 Subject: [PATCH 1400/1492] Test with Ruby 2.3 and allow failures with ruby-head --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b8a2f0019e4e9..31d4b9ed3abca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,13 @@ rvm: - jruby-head - 2.0.0 - 2.1 - - 2.2 + - 2.2.4 + - 2.3.0 - ruby-head matrix: fast_finish: true + allow_failures: + - rvm: ruby-head bundler_args: --jobs 3 --retry 3 notifications: email: false From 62e3596db89570b9d48b13c9966d754d5859d0dc Mon Sep 17 00:00:00 2001 From: yui-knk Date: Sat, 6 Feb 2016 16:42:33 +0900 Subject: [PATCH 1401/1492] Delete not used codes These codes were introduced by 03724fb1789198cc394f6e8b69cf9404e03eddd7, and to be not used by 79411322ae225289e1c051f4f68ed84c6349e4a0. --- lib/arel/visitors.rb | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index f492ca2d9d5d2..9bf5170463a65 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -14,28 +14,5 @@ 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 From df9dd77ee5cf2610599942555e49dedd678a8e8b Mon Sep 17 00:00:00 2001 From: Bert Bruynooghe Date: Wed, 17 Feb 2016 22:30:10 +0100 Subject: [PATCH 1402/1492] added Casted#hash --- lib/arel/nodes/casted.rb | 4 ++++ test/nodes/test_casted.rb | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/nodes/test_casted.rb diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb index 9fa02955ef586..543374d695071 100644 --- a/lib/arel/nodes/casted.rb +++ b/lib/arel/nodes/casted.rb @@ -10,6 +10,10 @@ def initialize val, attribute def nil?; @val.nil?; end + def hash + [@class, @val, @attribute].hash + end + def eql? other self.class == other.class && self.val == other.val && diff --git a/test/nodes/test_casted.rb b/test/nodes/test_casted.rb new file mode 100644 index 0000000000000..6d775e17ecc43 --- /dev/null +++ b/test/nodes/test_casted.rb @@ -0,0 +1,16 @@ +require 'helper' + +module Arel + module Nodes + describe Casted do + describe '#hash' do + it 'is equal when eql? returns true' do + one = Casted.new 1, 2 + also_one = Casted.new 1, 2 + + assert_equal one.hash, also_one.hash + end + end + end + end +end From f45b5f9dc8e7074506753e32ce8ad408b1b62bc8 Mon Sep 17 00:00:00 2001 From: Jeff Cole Date: Sun, 28 Feb 2016 10:05:00 -0700 Subject: [PATCH 1403/1492] Clean up README code * Fixes syntax highlighting of the output from `SqlLiteral` * Adds whitespace to improve readability --- README.md | 92 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 48df6700c4fba..757b062898ca0 100644 --- a/README.md +++ b/README.md @@ -56,24 +56,48 @@ users.project(users[:id]) Comparison operators `=`, `!=`, `<`, `>`, `<=`, `>=`, `IN`: ```ruby -users.where(users[:age].eq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" = 10 -users.where(users[:age].not_eq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" != 10 -users.where(users[:age].lt(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" < 10 -users.where(users[:age].gt(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" > 10 -users.where(users[:age].lteq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" <= 10 -users.where(users[:age].gteq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" >= 10 -users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" IN (20, 16, 17) +users.where(users[:age].eq(10)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" = 10 + +users.where(users[:age].not_eq(10)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" != 10 + +users.where(users[:age].lt(10)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" < 10 + +users.where(users[:age].gt(10)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" > 10 + +users.where(users[:age].lteq(10)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" <= 10 + +users.where(users[:age].gteq(10)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" >= 10 + +users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE "users"."age" IN (20, 16, 17) ``` Bitwise operators `&`, `|`, `^`, `<<`, `>>`: ```ruby -users.where((users[:bitmap] & 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" & 16) > 0 -users.where((users[:bitmap] | 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" | 16) > 0 -users.where((users[:bitmap] ^ 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" ^ 16) > 0 -users.where((users[:bitmap] << 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" << 1) > 0 -users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" >> 1) > 0 -users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*')) # => SELECT FROM "users" WHERE ~ "users"."bitmap" > 0 +users.where((users[:bitmap] & 16).gt(0)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE ("users"."bitmap" & 16) > 0 + +users.where((users[:bitmap] | 16).gt(0)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE ("users"."bitmap" | 16) > 0 + +users.where((users[:bitmap] ^ 16).gt(0)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE ("users"."bitmap" ^ 16) > 0 + +users.where((users[:bitmap] << 1).gt(0)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE ("users"."bitmap" << 1) > 0 + +users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*')) +# => SELECT * FROM "users" WHERE ("users"."bitmap" >> 1) > 0 + +users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*')) +# => SELECT FROM "users" WHERE ~ "users"."bitmap" > 0 ``` Joins resemble SQL strongly: @@ -130,18 +154,30 @@ The `AND` operator behaves similarly. Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: ```ruby -photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 -users.project(users[:age].sum) # => SELECT SUM(users.age) FROM users -users.project(users[:age].average) # => SELECT AVG(users.age) FROM users -users.project(users[:age].maximum) # => SELECT MAX(users.age) FROM users -users.project(users[:age].minimum) # => SELECT MIN(users.age) FROM users -users.project(users[:age].count) # => SELECT COUNT(users.age) FROM users +photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) +# => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 + +users.project(users[:age].sum) +# => SELECT SUM(users.age) FROM users + +users.project(users[:age].average) +# => SELECT AVG(users.age) FROM users + +users.project(users[:age].maximum) +# => SELECT MAX(users.age) FROM users + +users.project(users[:age].minimum) +# => SELECT MIN(users.age) FROM users + +users.project(users[:age].count) +# => SELECT COUNT(users.age) FROM users ``` Aliasing Aggregate Functions: ```ruby -users.project(users[:age].average.as("mean_age")) # => SELECT AVG(users.age) AS mean_age FROM users +users.project(users[:age].average.as("mean_age")) +# => SELECT AVG(users.age) AS mean_age FROM users ``` ### The Crazy Features @@ -190,7 +226,8 @@ Joining a table to itself requires aliasing in SQL. This aliasing can be handled replies = comments.alias comments_with_replies = \ comments.join(replies).on(replies[:parent_id].eq(comments[:id])).where(comments[:id].eq(1)) -# => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id AND comments.id = 1 +# => SELECT * FROM comments INNER JOIN comments AS comments_2 +# WHERE comments_2.parent_id = comments.id AND comments.id = 1 ``` This will return the reply for the first comment. @@ -212,7 +249,9 @@ users. project(users[:id], cte_table[:click].sum). with(composed_cte) -# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') SELECT users.id, SUM(cte_table.click) FROM users INNER JOIN cte_table ON users.id = cte_table.user_id +# => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') +# SELECT users.id, SUM(cte_table.click) +# FROM users INNER JOIN cte_table ON users.id = cte_table.user_id ``` When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: @@ -225,12 +264,13 @@ photo_clicks = Arel::Nodes::SqlLiteral.new(<<-SQL ELSE default_calculation END SQL ) + photos.project(photo_clicks.as("photo_clicks")) # => SELECT CASE WHEN condition1 THEN calculation1 - WHEN condition2 THEN calculation2 - WHEN condition3 THEN calculation3 - ELSE default_calculation END - FROM "photos" +# WHEN condition2 THEN calculation2 +# WHEN condition3 THEN calculation3 +# ELSE default_calculation END +# FROM "photos" ``` ## Contributing to Arel From 97dcd5133c9431eda6ecc00b57f8021bc766f71b Mon Sep 17 00:00:00 2001 From: Jeff Cole Date: Sun, 28 Feb 2016 10:13:42 -0700 Subject: [PATCH 1404/1492] Fix grammar in README * Fixes grammatical errors * Fixes capitalization * Fixes punctuation --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 757b062898ca0..ce2624404e663 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby. It -1. Simplifies the generation of complex SQL queries -2. Adapts to various RDBMSes +1. simplifies the generation of complex SQL queries, and +2. adapts to various RDBMSes. It is intended to be a framework framework; that is, you can build your own ORM with it, focusing on innovative object and collection modeling as opposed to @@ -17,7 +17,7 @@ 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. +For the moment, Arel uses Active Record's connection adapters to connect to the various engines and perform connection pooling, quoting, and type conversion. ## A Gentle Introduction @@ -27,7 +27,7 @@ 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: +you construct a table relation and convert it to SQL: ```ruby users = Arel::Table.new(:users) @@ -107,7 +107,7 @@ users.join(photos).on(users[:id].eq(photos[:user_id])) # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id ``` -Left Joins +Left joins: ```ruby users.join(photos, Arel::Nodes::OuterJoin).on(users[:id].eq(photos[:user_id])) @@ -128,7 +128,7 @@ users.project(users[:name]).group(users[:name]) # => SELECT users.name FROM users GROUP BY users.name ``` -The best property of arel is its "composability", or closure under all operations. For example, to restrict AND project, just "chain" the method invocations: +The best property of Arel is its "composability," or closure under all operations. For example, to restrict AND project, just "chain" the method invocations: ```ruby users \ @@ -182,7 +182,7 @@ users.project(users[:age].average.as("mean_age")) ### 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). +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 @@ -232,7 +232,7 @@ comments_with_replies = \ This will return the reply for the first comment. -[Common Table Expressions(CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: +[Common Table Expressions (CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: Create a `CTE` @@ -275,7 +275,7 @@ photos.project(photo_clicks.as("photo_clicks")) ## Contributing to Arel -Arel is work of many contributors. You're encouraged to submit pull requests, propose +Arel is the work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues. See [CONTRIBUTING](CONTRIBUTING.md). From c693cdae0860654e28f46c9af797212b68bef5bd Mon Sep 17 00:00:00 2001 From: Yong Guo Date: Tue, 1 Mar 2016 13:21:47 -0800 Subject: [PATCH 1405/1492] Fix issue #415 - Should Arel::Nodes::True.new() be 1 in sqlite3? --- lib/arel/visitors/sqlite.rb | 9 +++++++++ test/visitors/test_sqlite.rb | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index ff6fc1fea4c5d..165e9cb6db5c5 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -12,6 +12,15 @@ def visit_Arel_Nodes_SelectStatement o, collector o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end + + def visit_Arel_Nodes_True o, collector + collector << "1" + end + + def visit_Arel_Nodes_False o, collector + collector << "0" + end + end end end diff --git a/test/visitors/test_sqlite.rb b/test/visitors/test_sqlite.rb index 8fb8e76095e03..a9f3501f20198 100644 --- a/test/visitors/test_sqlite.rb +++ b/test/visitors/test_sqlite.rb @@ -18,6 +18,13 @@ module Visitors node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) assert_equal '', @visitor.accept(node, Collectors::SQLString.new).value end + + it 'does not support boolean' do + node = Nodes::True.new() + assert_equal '1', @visitor.accept(node, Collectors::SQLString.new).value + node = Nodes::False.new() + assert_equal '0', @visitor.accept(node, Collectors::SQLString.new).value + end end end end From 47d89b18aef0125179386274c4445b90f66fa3c9 Mon Sep 17 00:00:00 2001 From: zhufenggood Date: Thu, 31 Mar 2016 01:38:11 +0800 Subject: [PATCH 1406/1492] Update to_sql.rb. Slightly performance improment. Update to_sql.rb. Slightly performance improment. --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 80bea56ce628f..cab0ab7ecaabf 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -199,7 +199,7 @@ def visit_Arel_Nodes_Values o, collector collector << quote(value, attr && column_for(attr)).to_s end unless i == len - collector << ', ' + collector << COMMA end } From 549c06dc6d1432dcd5994a117716818f96f989af Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Fri, 24 Oct 2014 12:01:26 +0530 Subject: [PATCH 1407/1492] DRY up visit_Arel_Nodes_SelectCore and extract nodes collection to collect_nodes_for, for collecting wheres, projections, groups, windows --- lib/arel/visitors/to_sql.rb | 46 +++++++++++-------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index cab0ab7ecaabf..1435f3e21db0c 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -243,53 +243,33 @@ def visit_Arel_Nodes_SelectCore o, collector collector = maybe_visit o.set_quantifier, collector - unless o.projections.empty? - collector << SPACE - len = o.projections.length - 1 - o.projections.each_with_index do |x, i| - collector = visit(x, collector) - collector << COMMA unless len == i - end - end + collect_nodes_for o.projections, collector, SPACE if o.source && !o.source.empty? collector << " FROM " collector = visit o.source, collector end - unless o.wheres.empty? - collector << WHERE - len = o.wheres.length - 1 - o.wheres.each_with_index do |x, i| - collector = visit(x, collector) - collector << AND unless len == i - end - end - - unless o.groups.empty? - collector << GROUP_BY - len = o.groups.length - 1 - o.groups.each_with_index do |x, i| - collector = visit(x, collector) - collector << COMMA unless len == i - end - end - + collect_nodes_for o.wheres, collector, WHERE, AND + collect_nodes_for o.groups, collector, GROUP_BY unless o.havings.empty? collector << " HAVING " inject_join o.havings, collector, AND end + collect_nodes_for o.windows, collector, WINDOW + + collector + end - unless o.windows.empty? - collector << WINDOW - len = o.windows.length - 1 - o.windows.each_with_index do |x, i| + def collect_nodes_for nodes, collector, spacer, connector = COMMA + unless nodes.empty? + collector << spacer + len = nodes.length - 1 + nodes.each_with_index do |x, i| collector = visit(x, collector) - collector << COMMA unless len == i + collector << connector unless len == i end end - - collector end def visit_Arel_Nodes_Bin o, collector From 91b593dc19e8700540e78927e42a876730165f2b Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 11 Apr 2016 22:36:52 +0530 Subject: [PATCH 1408/1492] Fix warnings from test_to_sql test --- test/visitors/test_to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 6da86c2deecc4..6833d4e8f5669 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -695,7 +695,7 @@ def quote value, column = nil it 'supports #when with two arguments and no #then' do node = Arel::Nodes::Case.new @table[:name] - { foo: 1, bar: 0 }.reduce(node) { |node, pair| node.when *pair } + { foo: 1, bar: 0 }.reduce(node) { |_node, pair| _node.when(*pair) } compile(node).must_be_like %{ CASE "users"."name" WHEN 'foo' THEN 1 WHEN 'bar' THEN 0 END From 653966773238f82c78b4aa55379e624cd407e588 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Tue, 5 Apr 2016 20:48:48 +0000 Subject: [PATCH 1409/1492] Support Oracle bind parameter value for Oracle12 visitor --- lib/arel/visitors/oracle12.rb | 4 ++++ test/visitors/test_oracle12.rb | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb index 4a42343c9b426..0711e70df7c2a 100644 --- a/lib/arel/visitors/oracle12.rb +++ b/lib/arel/visitors/oracle12.rb @@ -48,6 +48,10 @@ def visit_Arel_Nodes_UpdateStatement o, collector super end + + def visit_Arel_Nodes_BindParam o, collector + collector.add_bind(o) { |i| ":a#{i}" } + end end end end diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index df0f01b30b43d..d6fbf8912b531 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -2,9 +2,10 @@ module Arel module Visitors - describe 'the oracle visitor' do + describe 'the oracle12 visitor' do before do - @visitor = Oracle12.new Table.engine.connection_pool + @visitor = Oracle12.new Table.engine.connection + @table = Table.new(:users) end def compile node @@ -42,6 +43,16 @@ def compile node compile(node).must_be_like "FOR UPDATE" end end + + describe "Nodes::BindParam" do + it "increments each bind param" do + query = @table[:name].eq(Arel::Nodes::BindParam.new) + .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + compile(query).must_be_like %{ + "users"."name" = :a1 AND "users"."id" = :a2 + } + end + end end end end From 9f669c7288b57cf51a31cb3b3773df57b4b02376 Mon Sep 17 00:00:00 2001 From: Vipul A M Date: Mon, 11 Apr 2016 23:32:27 +0530 Subject: [PATCH 1410/1492] - Disable jruby-head since bundle fetching is failing on travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 31d4b9ed3abca..4a1cf88bf307c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ matrix: fast_finish: true allow_failures: - rvm: ruby-head + - rvm: jruby-head bundler_args: --jobs 3 --retry 3 notifications: email: false From 45af55c0fc387bc07f3ae3bed987035a589ccb10 Mon Sep 17 00:00:00 2001 From: zhufenggood Date: Fri, 15 Apr 2016 06:17:50 +0800 Subject: [PATCH 1411/1492] Update to_sql.rb Update to_sql.rb. Slightly performance improvement. --- lib/arel/visitors/to_sql.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index cab0ab7ecaabf..f2a3d5aa0cae1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -349,13 +349,13 @@ def visit_Arel_Nodes_Window o, collector end if o.orders.any? - collector << ' ' if o.partitions.any? + collector << SPACE if o.partitions.any? collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end if o.framing - collector << ' ' if o.partitions.any? or o.orders.any? + collector << SPACE if o.partitions.any? or o.orders.any? collector = visit o.framing, collector end @@ -564,7 +564,7 @@ def visit_Arel_Nodes_JoinSource o, collector collector = visit o.left, collector end if o.right.any? - collector << " " if o.left + collector << SPACE if o.left collector = inject_join o.right, collector, ' ' end collector From f852b608d140addcbdc7ecb85d42eef0bbd512c5 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Mon, 2 May 2016 13:31:06 +0000 Subject: [PATCH 1412/1492] Raise ArgumentError if limit and lock are used for Oracle12 visitor it would generates `SELECT ... FETCH FIRST n ROWS ONLY FOR UPDATE` which causes Oracle 12c database returns this error : ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc. --- lib/arel/visitors/oracle12.rb | 8 +++++--- test/visitors/test_oracle12.rb | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb index 4a42343c9b426..d21a829848f30 100644 --- a/lib/arel/visitors/oracle12.rb +++ b/lib/arel/visitors/oracle12.rb @@ -6,10 +6,12 @@ class Oracle12 < Arel::Visitors::ToSql def visit_Arel_Nodes_SelectStatement o, collector # Oracle does not allow LIMIT clause with select for update if o.limit && o.lock - o = o.dup - o.limit = [] + raise ArgumentError, <<-MSG + 'Combination of limit and lock is not supported. + because generated SQL statements + `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.` + MSG end - super end diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index df0f01b30b43d..3263007ddbaf7 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -29,12 +29,13 @@ def compile node end describe 'locking' do - it 'removes limit when locking' do + it 'generates ArgumentError if limit and lock are used' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE')) - sql = compile(stmt) - sql.must_be_like "SELECT FOR UPDATE" + assert_raises ArgumentError do + sql = compile(stmt) + end end it 'defaults to FOR UPDATE when locking' do From 76fca40eb0d43a425dde3c3183912b3bc8e02c05 Mon Sep 17 00:00:00 2001 From: Mohammad Habbab Date: Wed, 4 May 2016 10:15:06 +0800 Subject: [PATCH 1413/1492] Add Support for GroupBy Cube, Rollup and Grouping Set Syntax for PostgreSQL Visitor --- lib/arel/nodes/unary.rb | 8 +++- lib/arel/visitors/depth_first.rb | 4 ++ lib/arel/visitors/dot.rb | 4 ++ lib/arel/visitors/postgresql.rb | 36 +++++++++++++++ test/visitors/test_postgres.rb | 78 ++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 2 deletions(-) diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index a0062ff5be8a0..50946980b4a67 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -22,15 +22,19 @@ def eql? other %w{ Bin + Cube + DistinctOn Group + GroupingElement + GroupingSet Limit + Lock Not Offset On Ordering + RollUp Top - Lock - DistinctOn }.each do |name| const_set(name, Class.new(Unary)) end diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index fb21fb1e700a7..d38795e6403e9 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -18,6 +18,10 @@ def unary o end alias :visit_Arel_Nodes_Else :unary alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Cube :unary + alias :visit_Arel_Nodes_RollUp :unary + alias :visit_Arel_Nodes_GroupingSet :unary + alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index da75423523449..95da65227812e 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -69,6 +69,10 @@ def unary o visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Cube :unary + alias :visit_Arel_Nodes_RollUp :unary + alias :visit_Arel_Nodes_GroupingSet :unary + alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index 1ef0261bdde2c..ef0f0ea2ef441 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -1,6 +1,10 @@ module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql + CUBE = 'CUBE' + ROLLUP = 'ROLLUP' + GROUPING_SET = 'GROUPING SET' + private def visit_Arel_Nodes_Matches o, collector @@ -43,6 +47,38 @@ def visit_Arel_Nodes_DistinctOn o, collector def visit_Arel_Nodes_BindParam o, collector collector.add_bind(o) { |i| "$#{i}" } end + + def visit_Arel_Nodes_GroupingElement o, collector + collector << "( " + visit(o.expr, collector) << " )" + end + + def visit_Arel_Nodes_Cube o, collector + collector << CUBE + grouping_array_or_grouping_element o, collector + end + + def visit_Arel_Nodes_RollUp o, collector + collector << ROLLUP + grouping_array_or_grouping_element o, collector + end + + def visit_Arel_Nodes_GroupingSet o, collector + collector << GROUPING_SET + grouping_array_or_grouping_element o, collector + end + + # Utilized by GroupingSet, Cube & RollUp visitors to + # handle grouping aggregation semantics + def grouping_array_or_grouping_element o, collector + if o.expr.is_a? Array + collector << "( " + visit o.expr, collector + collector << " )" + else + visit o.expr, collector + end + end end end end diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 4b7dbe367f45c..f97b734b7dfa6 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -182,6 +182,84 @@ def compile node } end end + + describe "Nodes::Cube" do + it "should know how to visit with array arguments" do + node = Arel::Nodes::Cube.new([@table[:name], @table[:bool]]) + compile(node).must_be_like %{ + CUBE( "users"."name", "users"."bool" ) + } + end + + it "should know how to visit with CubeDimension Argument" do + dimensions = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) + node = Arel::Nodes::Cube.new(dimensions) + compile(node).must_be_like %{ + CUBE( "users"."name", "users"."bool" ) + } + end + + it "should know how to generate paranthesis when supplied with many Dimensions" do + dim1 = Arel::Nodes::GroupingElement.new(@table[:name]) + dim2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) + node = Arel::Nodes::Cube.new([dim1, dim2]) + compile(node).must_be_like %{ + CUBE( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + } + end + end + + describe "Nodes::GroupingSet" do + it "should know how to visit with array arguments" do + node = Arel::Nodes::GroupingSet.new([@table[:name], @table[:bool]]) + compile(node).must_be_like %{ + GROUPING SET( "users"."name", "users"."bool" ) + } + end + + it "should know how to visit with CubeDimension Argument" do + group = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) + node = Arel::Nodes::GroupingSet.new(group) + compile(node).must_be_like %{ + GROUPING SET( "users"."name", "users"."bool" ) + } + end + + it "should know how to generate paranthesis when supplied with many Dimensions" do + group1 = Arel::Nodes::GroupingElement.new(@table[:name]) + group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) + node = Arel::Nodes::GroupingSet.new([group1, group2]) + compile(node).must_be_like %{ + GROUPING SET( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + } + end + end + + describe "Nodes::RollUp" do + it "should know how to visit with array arguments" do + node = Arel::Nodes::RollUp.new([@table[:name], @table[:bool]]) + compile(node).must_be_like %{ + ROLLUP( "users"."name", "users"."bool" ) + } + end + + it "should know how to visit with CubeDimension Argument" do + group = Arel::Nodes::GroupingElement.new([@table[:name], @table[:bool]]) + node = Arel::Nodes::RollUp.new(group) + compile(node).must_be_like %{ + ROLLUP( "users"."name", "users"."bool" ) + } + end + + it "should know how to generate paranthesis when supplied with many Dimensions" do + group1 = Arel::Nodes::GroupingElement.new(@table[:name]) + group2 = Arel::Nodes::GroupingElement.new([@table[:bool], @table[:created_at]]) + node = Arel::Nodes::RollUp.new([group1, group2]) + compile(node).must_be_like %{ + ROLLUP( ( "users"."name" ), ( "users"."bool", "users"."created_at" ) ) + } + end + end end end end From dc85a6e9c74942945ad696f5da4d82490a85b865 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Mon, 30 May 2016 00:39:56 +0900 Subject: [PATCH 1414/1492] Support for unified Integer class in Ruby 2.4+ Ruby 2.4 unifies Fixnum and Bignum into Integer: https://bugs.ruby-lang.org/issues/12005 Ruby ~2.3 `1234.class` is `Fixnum` and `123456789012345678901234567890.class` is `Bignum`. Ruby 2.4+ `1234.class` is `Integer` and `123456789012345678901234567890.class` is `Integer`. So what we should do is defining `visit_Integer` method to visitors. --- lib/arel/visitors/depth_first.rb | 1 + lib/arel/visitors/dot.rb | 1 + lib/arel/visitors/to_sql.rb | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index d38795e6403e9..80b3c3c346ead 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -141,6 +141,7 @@ def terminal o alias :visit_FalseClass :terminal alias :visit_Fixnum :terminal alias :visit_Float :terminal + alias :visit_Integer :terminal alias :visit_NilClass :terminal alias :visit_String :terminal alias :visit_Symbol :terminal diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 95da65227812e..ca8d2b0bd0551 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -205,6 +205,7 @@ def visit_String o alias :visit_TrueClass :visit_String alias :visit_FalseClass :visit_String alias :visit_Arel_Nodes_BindParam :visit_String + alias :visit_Integer :visit_String alias :visit_Fixnum :visit_String alias :visit_BigDecimal :visit_String alias :visit_Float :visit_String diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f2a3d5aa0cae1..97bade186a01a 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -762,6 +762,7 @@ def visit_Arel_Nodes_BindParam o, collector alias :visit_Arel_Nodes_SqlLiteral :literal alias :visit_Bignum :literal alias :visit_Fixnum :literal + alias :visit_Integer :literal def quoted o, a if a && a.able_to_type_cast? From 7e7db4bb9592edce3fb887558e1da34b35bdf773 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Sun, 29 May 2016 12:02:27 -0700 Subject: [PATCH 1415/1492] CI: test JRuby 9.0.5.0. Allow failures due to flaky Travis bundler situation. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 31d4b9ed3abca..cbb55b95820a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ env: - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - rbx-2 + - jruby-9.0.5.0 - jruby-head - 2.0.0 - 2.1 @@ -18,6 +19,8 @@ rvm: matrix: fast_finish: true allow_failures: + - rvm: jruby-9.0.5.0 + - rvm: jruby-head - rvm: ruby-head bundler_args: --jobs 3 --retry 3 notifications: From 56c5126157a8a2e084e2ba1285d33238422c9129 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Sun, 29 May 2016 12:03:56 -0700 Subject: [PATCH 1416/1492] CI: bump Ruby 2.2.4->2.2.5, 2.3.0->2.3.1 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index cbb55b95820a0..640ed8678e9ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,8 +13,8 @@ rvm: - jruby-head - 2.0.0 - 2.1 - - 2.2.4 - - 2.3.0 + - 2.2.5 + - 2.3.1 - ruby-head matrix: fast_finish: true From 6d2254ae4ac5a361c041783d742292acfa58e363 Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Sun, 29 May 2016 12:19:17 -0700 Subject: [PATCH 1417/1492] Bump to 7.0.1.pre in anticipation of next release [ci skip] --- History.txt | 6 ++++++ lib/arel.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index 9d4cd32461dcc..07cb9024fd04a 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +=== 7.0.1 / unreleased + +* Enhancements + + * Support Ruby 2.4 unified Integer class + === 7.0.0 / 2015-12-17 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index f32929e70f083..2bd56372ef531 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '7.0.0' + VERSION = '7.0.1.pre' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 0d70b57978035350672da41074535970272fac95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 19 Jul 2016 21:56:54 -0300 Subject: [PATCH 1418/1492] Release 7.1.0 --- History.txt | 4 +++- lib/arel.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/History.txt b/History.txt index 07cb9024fd04a..e302920c14189 100644 --- a/History.txt +++ b/History.txt @@ -1,8 +1,10 @@ -=== 7.0.1 / unreleased +=== 7.1.0 / 2016-07-19 * Enhancements * Support Ruby 2.4 unified Integer class + * Implement `CASE` conditional expression + * Support for Bitwise Operations as `InfixOperations` === 7.0.0 / 2015-12-17 diff --git a/lib/arel.rb b/lib/arel.rb index 2bd56372ef531..c320f104d8476 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '7.0.1.pre' + VERSION = '7.1.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From f91d657c09ca4adf34327466c391e3c5e41133af Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Thu, 28 Jul 2016 00:43:01 +0930 Subject: [PATCH 1419/1492] Fix Casted#hash There is no @class variable. --- lib/arel/nodes/casted.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb index 543374d695071..6b15f9e4b3a17 100644 --- a/lib/arel/nodes/casted.rb +++ b/lib/arel/nodes/casted.rb @@ -11,7 +11,7 @@ def initialize val, attribute def nil?; @val.nil?; end def hash - [@class, @val, @attribute].hash + [self.class, val, attribute].hash end def eql? other From 09827f361d4bc73e6ff157d9feb74a465e4e4cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 27 Jul 2016 20:17:41 -0300 Subject: [PATCH 1420/1492] Release 7.1.1 --- History.txt | 6 ++++++ lib/arel.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index e302920c14189..ccc170c4a2ad0 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +=== 7.1.1 / 2016-07-27 + +* Bug Fixes + + * Fix warning in `Casted#hash` + === 7.1.0 / 2016-07-19 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index c320f104d8476..41173787ed78f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '7.1.0' + VERSION = '7.1.1' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 52d0b7338852fcc5cccfe5282d68ee058c62b4ed Mon Sep 17 00:00:00 2001 From: Michael Batchelor Date: Fri, 19 Aug 2016 16:37:45 -0700 Subject: [PATCH 1421/1492] remove union mapping as :binary node when performing DepthFirst enumeration --- lib/arel/visitors/depth_first.rb | 1 - test/attributes/test_attribute.rb | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 80b3c3c346ead..69ed345aea707 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -98,7 +98,6 @@ def binary o alias :visit_Arel_Nodes_Regexp :binary alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary - alias :visit_Arel_Nodes_Union :binary alias :visit_Arel_Nodes_Values :binary alias :visit_Arel_Nodes_When :binary diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 4e55069df48a6..f6b73adf6aa55 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -834,6 +834,18 @@ def quoted_range(begin_val, end_val, exclude) node.must_equal Nodes::NotIn.new(attribute, mgr.ast) end + it 'can be constructed with a Union' do + relation = Table.new(:users) + mgr1 = relation.project(relation[:id]) + mgr2 = relation.project(relation[:id]) + + union = mgr1.union(mgr2) + node = relation[:id].in(union) + node.to_sql.must_be_like %{ + "users"."id" IN (( SELECT "users"."id" FROM "users" UNION SELECT "users"."id" FROM "users" )) + } + end + it 'can be constructed with a list' do attribute = Attribute.new nil, nil node = attribute.not_in([1, 2, 3]) From b7e91eff47d367e25351e20bc1cb660b1493f2f9 Mon Sep 17 00:00:00 2001 From: Adam Lassek Date: Fri, 26 Aug 2016 17:28:12 -0500 Subject: [PATCH 1422/1492] Add failing test for Dot visitor and BindParam Since BindParam has no value, treating it like a string causes it to fallback to Object#to_s, leading to output like `#`. Since angle brackets are significant in Dot labels, this causes `Error: bad label format` when passing the graph into dot. --- test/visitors/test_dot.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 4dc3c9c6c5a76..6db9b9b6de4cb 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -70,6 +70,12 @@ def test_named_function @visitor.accept binary, Collectors::PlainString.new end end + + def test_Arel_Nodes_BindParam + node = Arel::Nodes::BindParam.new + collector = Collectors::PlainString.new + assert_match '[label="Arel::Nodes::BindParam"]', @visitor.accept(node, collector).value + end end end end From 63d180c96ff0096d417c6ddac56ec074a51e41a5 Mon Sep 17 00:00:00 2001 From: Adam Lassek Date: Fri, 26 Aug 2016 17:33:08 -0500 Subject: [PATCH 1423/1492] Change BindParam visit method for Dot to a noop Since BindParam contains no information, treating it like a string adds no useful information to the graph, and results in an invalid label format. --- lib/arel/visitors/dot.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index ca8d2b0bd0551..31e4a66a1f5e1 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -204,7 +204,6 @@ def visit_String o alias :visit_NilClass :visit_String alias :visit_TrueClass :visit_String alias :visit_FalseClass :visit_String - alias :visit_Arel_Nodes_BindParam :visit_String alias :visit_Integer :visit_String alias :visit_Fixnum :visit_String alias :visit_BigDecimal :visit_String @@ -212,6 +211,8 @@ def visit_String o alias :visit_Symbol :visit_String alias :visit_Arel_Nodes_SqlLiteral :visit_String + def visit_Arel_Nodes_BindParam o; end + def visit_Hash o o.each_with_index do |pair, i| edge("pair_#{i}") { visit pair } From fbbe05e409c5f24ac58095426d9c729ee611df00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20G=C3=BCnther?= Date: Sat, 27 Aug 2016 14:39:52 +0200 Subject: [PATCH 1424/1492] Add Arel::Nodes::Casted to dot visitor Adds casted node to the dot visitor with outgoing edges to val and attribute. Fixes #419 --- lib/arel/visitors/dot.rb | 5 +++++ test/visitors/test_dot.rb | 1 + 2 files changed, 6 insertions(+) diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index ca8d2b0bd0551..3faa126732c63 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -155,6 +155,11 @@ def visit_Arel_Table o visit_edge o, "name" end + def visit_Arel_Nodes_Casted o + visit_edge o, 'val' + visit_edge o, 'attribute' + end + def visit_Arel_Attribute o visit_edge o, "relation" visit_edge o, "name" diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 4dc3c9c6c5a76..fa1c69e10dbe4 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -64,6 +64,7 @@ def test_named_function Arel::Nodes::As, Arel::Nodes::DeleteStatement, Arel::Nodes::JoinSource, + Arel::Nodes::Casted, ].each do |klass| define_method("test_#{klass.name.gsub('::', '_')}") do binary = klass.new(:a, :b) From 685825cdfc3c5595b504ae5dd0fc45638c47aeec Mon Sep 17 00:00:00 2001 From: ojab Date: Wed, 31 Aug 2016 15:20:36 +0000 Subject: [PATCH 1425/1492] Freeze all the strings in visitors --- lib/arel/visitors/bind_visitor.rb | 1 + lib/arel/visitors/dot.rb | 3 ++- lib/arel/visitors/ibm_db.rb | 1 + lib/arel/visitors/informix.rb | 1 + lib/arel/visitors/mssql.rb | 1 + lib/arel/visitors/mysql.rb | 1 + lib/arel/visitors/oracle.rb | 3 ++- lib/arel/visitors/oracle12.rb | 1 + lib/arel/visitors/postgresql.rb | 1 + lib/arel/visitors/sqlite.rb | 1 + lib/arel/visitors/to_sql.rb | 1 + lib/arel/visitors/where_sql.rb | 1 + 12 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb index c336e87395af3..8a5570cf5cfbb 100644 --- a/lib/arel/visitors/bind_visitor.rb +++ b/lib/arel/visitors/bind_visitor.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors module BindVisitor diff --git a/lib/arel/visitors/dot.rb b/lib/arel/visitors/dot.rb index 31e4a66a1f5e1..85edc50eb7ab5 100644 --- a/lib/arel/visitors/dot.rb +++ b/lib/arel/visitors/dot.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class Dot < Arel::Visitors::Visitor @@ -272,7 +273,7 @@ def to_dot label = "#{node.name}" node.fields.each_with_index do |field, i| - label << "|#{quote field}" + label += "|#{quote field}" end "#{node.id} [label=\"#{label}\"];" diff --git a/lib/arel/visitors/ibm_db.rb b/lib/arel/visitors/ibm_db.rb index f1d126790db53..e85a5a08a7fcc 100644 --- a/lib/arel/visitors/ibm_db.rb +++ b/lib/arel/visitors/ibm_db.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class IBM_DB < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index c33ef5055454a..b53ab18b82233 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class Informix < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/mssql.rb b/lib/arel/visitors/mssql.rb index 92362a0c5fc7a..8347d05d067b0 100644 --- a/lib/arel/visitors/mssql.rb +++ b/lib/arel/visitors/mssql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class MSSQL < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/mysql.rb b/lib/arel/visitors/mysql.rb index ac3ad7b470a14..4c734f6292eea 100644 --- a/lib/arel/visitors/mysql.rb +++ b/lib/arel/visitors/mysql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class MySQL < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 875b0e5b6a6c7..99075b3e27f8e 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class Oracle < Arel::Visitors::ToSql @@ -125,7 +126,7 @@ def split_order_string(string) array[i] << ',' << part else # to ensure that array[i] will be String and not Arel::Nodes::SqlLiteral - array[i] = '' << part + array[i] = part.to_s end i += 1 if array[i].count('(') == array[i].count(')') end diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb index 9b722e8c0c36d..ce90e994aea69 100644 --- a/lib/arel/visitors/oracle12.rb +++ b/lib/arel/visitors/oracle12.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class Oracle12 < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index ef0f0ea2ef441..f0991a2f11222 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/sqlite.rb b/lib/arel/visitors/sqlite.rb index 165e9cb6db5c5..4ae093968bace 100644 --- a/lib/arel/visitors/sqlite.rb +++ b/lib/arel/visitors/sqlite.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class SQLite < Arel::Visitors::ToSql diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 5429bf4ee8e5c..3f61842c3fb90 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'bigdecimal' require 'date' require 'arel/visitors/reduce' diff --git a/lib/arel/visitors/where_sql.rb b/lib/arel/visitors/where_sql.rb index 41972d5836136..55e6ca9a2193d 100644 --- a/lib/arel/visitors/where_sql.rb +++ b/lib/arel/visitors/where_sql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class WhereSql < Arel::Visitors::ToSql From a091539febd3a5a9e5306924b38e0dd681de4a07 Mon Sep 17 00:00:00 2001 From: ojab Date: Wed, 31 Aug 2016 15:28:39 +0000 Subject: [PATCH 1426/1492] Drop unneeded assignment --- test/visitors/test_oracle12.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index 5dac2994cf663..43235fd72cab8 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -35,7 +35,7 @@ def compile node stmt.limit = Nodes::Limit.new(10) stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE')) assert_raises ArgumentError do - sql = compile(stmt) + compile(stmt) end end From 44d2ef9623847dea5cbf6208ae7b5168b374c720 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 13 Sep 2016 14:06:17 -0400 Subject: [PATCH 1427/1492] Don't store all aliases to a table The aliases property of a table is never used other than for equality. However, the aliases that have been created for a table aren't really something that should affect whether a table is considered to be the same table or not. This removal does not appear to have any affect within Active Record or within Arel. --- lib/arel/table.rb | 8 ++------ test/test_table.rb | 9 +-------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index b4b4a861b83b4..0e7214f2694bf 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -6,7 +6,7 @@ class Table @engine = nil class << self; attr_accessor :engine; end - attr_accessor :name, :aliases, :table_alias + attr_accessor :name, :table_alias # TableAlias and Table both have a #table_name which is the name of the underlying table alias :table_name :name @@ -14,7 +14,6 @@ class << self; attr_accessor :engine; end def initialize(name, as: nil, type_caster: nil) @name = name.to_s @columns = nil - @aliases = [] @type_caster = type_caster # Sometime AR sends an :as parameter to table, to let the table know @@ -27,9 +26,7 @@ def initialize(name, as: nil, type_caster: nil) end def alias name = "#{self.name}_2" - Nodes::TableAlias.new(self, name).tap do |node| - @aliases << node - end + Nodes::TableAlias.new(self, name) end def from @@ -94,7 +91,6 @@ def hash def eql? other self.class == other.class && self.name == other.name && - self.aliases == other.aliases && self.table_alias == other.table_alias end alias :== :eql? diff --git a/test/test_table.rb b/test/test_table.rb index e8eaf901cc981..168fde370db57 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -110,10 +110,7 @@ module Arel 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 @@ -191,10 +188,8 @@ module Arel describe 'equality' do it 'is equal with equal ivars' do relation1 = Table.new(:users) - relation1.aliases = %w[a b c] relation1.table_alias = 'zomg' relation2 = Table.new(:users) - relation2.aliases = %w[a b c] relation2.table_alias = 'zomg' array = [relation1, relation2] assert_equal 1, array.uniq.size @@ -202,11 +197,9 @@ module Arel it 'is not equal with different ivars' do relation1 = Table.new(:users) - relation1.aliases = %w[a b c] relation1.table_alias = 'zomg' relation2 = Table.new(:users) - relation2.aliases = %w[x y z] - relation2.table_alias = 'zomg' + relation2.table_alias = 'zomg2' array = [relation1, relation2] assert_equal 2, array.uniq.size end From 9d6e569ddfed10b437494ecb6e995048737beb44 Mon Sep 17 00:00:00 2001 From: Rodrigo Castro Date: Fri, 7 Oct 2016 11:53:47 -0300 Subject: [PATCH 1428/1492] Fix issue #438 when oracle visitor gets BindParams --- lib/arel/visitors/oracle.rb | 15 +++++++++++++-- test/visitors/test_oracle.rb | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 875b0e5b6a6c7..4c79c4b038911 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -26,11 +26,22 @@ def visit_Arel_Nodes_SelectStatement o, collector FROM (" collector = super(o, collector) - collector << ") raw_sql_ + + if offset.expr.is_a? Nodes::BindParam + offset_bind = nil + collector << ') raw_sql_ WHERE rownum <= (' + collector.add_bind(offset.expr) { |i| offset_bind = ":a#{i}" } + collector << ' + ' + collector.add_bind(limit) { |i| ":a#{i}" } + collector << ") ) WHERE raw_rnum_ > #{offset_bind}" + return collector + else + collector << ") raw_sql_ WHERE rownum <= #{offset.expr.to_i + limit} ) WHERE " - return visit(offset, collector) + return visit(offset, collector) + end end if o.limit diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index e9ed9d76b3a63..4c22be5cbb93a 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -124,6 +124,21 @@ def compile node } end + it 'creates a subquery when there is limit and offset with BindParams' do + stmt = Nodes::SelectStatement.new + stmt.limit = Nodes::Limit.new(Nodes::BindParam.new) + stmt.offset = Nodes::Offset.new(Nodes::BindParam.new) + sql = compile stmt + sql.must_be_like %{ + SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (SELECT ) raw_sql_ + WHERE rownum <= (:a1 + :a2) + ) + WHERE raw_rnum_ > :a1 + } + end + it 'is idempotent with different subquery' do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) @@ -148,7 +163,6 @@ def compile node } end end - end it 'modified except to be minus' do From 95ff347b1743b6c7d8100ced81fb7b88a3cc2c8f Mon Sep 17 00:00:00 2001 From: Alexander Baronec Date: Wed, 31 Aug 2016 18:25:03 +0300 Subject: [PATCH 1429/1492] use #data_source_exists? instead of deprecated #table_exists? --- lib/arel/visitors/to_sql.rb | 2 +- test/support/fake_record.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 3f61842c3fb90..506b33f4b61a4 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -171,7 +171,7 @@ def visit_Arel_Nodes_False o, collector end def table_exists? name - schema_cache.table_exists? name + schema_cache.data_source_exists?(name) end def column_for attr diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 035a7a46cfd6c..3d4c7d563037d 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -39,7 +39,7 @@ def primary_key name @primary_keys[name.to_s] end - def table_exists? name + def data_source_exists? name @tables.include? name.to_s end From 090e6b6e05af2ab88c068ded5d056cab1b82cdbd Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Fri, 14 Oct 2016 13:59:13 -0400 Subject: [PATCH 1430/1492] Allow failures from rubinius Per https://github.com/travis-ci/travis-ci/issues/5294 It looks like rvm is having trouble installing rubinius ``` rvm use rbx-2 --install --binary --fuzzy ``` I think this is the culpret for all builds failing since September --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 363f53f6ce5b5..ee72f36a89641 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ matrix: - rvm: jruby-head - rvm: ruby-head - rvm: jruby-head + - rvm: rbx-2 bundler_args: --jobs 3 --retry 3 notifications: email: false From be4254d507e60b6bf88c774bf3b30d655f202dc8 Mon Sep 17 00:00:00 2001 From: Maarten Claes Date: Thu, 1 Dec 2016 12:49:27 +0100 Subject: [PATCH 1431/1492] Link to the API docs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ce2624404e663..48882baec36de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Arel * http://github.com/rails/arel +* [API Documentation](http://www.rubydoc.info/github/rails/arel) ## DESCRIPTION From 06ab379d8c41ee3699cb3d0b5bc865272a921d43 Mon Sep 17 00:00:00 2001 From: "Daniel P. Clark" <6ftdan@gmail.com> Date: Mon, 19 Dec 2016 18:50:55 -0500 Subject: [PATCH 1432/1492] missing asterisk --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48882baec36de..292b7fdbcac44 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" >> 1) > 0 users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*')) -# => SELECT FROM "users" WHERE ~ "users"."bitmap" > 0 +# => SELECT * FROM "users" WHERE ~ "users"."bitmap" > 0 ``` Joins resemble SQL strongly: From 1f5e99bb9c0da87deee796dd31f8e130a4cfd40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 28 Dec 2016 20:01:25 -0500 Subject: [PATCH 1433/1492] Arel master is alre 7.2 closes #461 --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 41173787ed78f..2069cec7ce987 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '7.1.1' + VERSION = '7.2.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 6ef13ec5d29b3ec66900c60bcfdf1ac5be8d20ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 29 Dec 2016 01:07:40 -0500 Subject: [PATCH 1434/1492] Remove dead code --- lib/arel/table.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 0e7214f2694bf..3e06f942729a0 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -13,7 +13,6 @@ class << self; attr_accessor :engine; end def initialize(name, as: nil, type_caster: nil) @name = name.to_s - @columns = nil @type_caster = type_caster # Sometime AR sends an :as parameter to table, to let the table know @@ -106,16 +105,5 @@ def able_to_type_cast? protected attr_reader :type_caster - - private - - def attributes_for columns - return nil unless columns - - columns.map do |column| - Attributes.for(column).new self, column.name.to_sym - end - end - end end From 1e24cd4525c7ff58f9f2d1323292c2d67244ec01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 29 Dec 2016 01:14:01 -0500 Subject: [PATCH 1435/1492] Remove deprecated type cast support in Arel --- History.txt | 4 ++ lib/arel/visitors/to_sql.rb | 49 +++------------------ test/attributes/test_attribute.rb | 8 ---- test/helper.rb | 2 - test/support/fake_record.rb | 15 ++----- test/visitors/test_to_sql.rb | 73 +------------------------------ 6 files changed, 14 insertions(+), 137 deletions(-) diff --git a/History.txt b/History.txt index ccc170c4a2ad0..aacf6d7a16374 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,7 @@ +* Enhancements + + * Remove deprecated type casting support in Arel + === 7.1.1 / 2016-07-27 * Bug Fixes diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 506b33f4b61a4..ad2666fb101c1 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -76,10 +76,6 @@ def compile node, &block private - def schema_cache - @connection.schema_cache - end - def visit_Arel_Nodes_DeleteStatement o, collector collector << 'DELETE FROM ' collector = visit o.relation, collector @@ -170,24 +166,6 @@ def visit_Arel_Nodes_False o, collector collector << "FALSE" end - def table_exists? name - schema_cache.data_source_exists?(name) - end - - def column_for attr - return unless 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, collector collector << "VALUES (" @@ -197,7 +175,7 @@ def visit_Arel_Nodes_Values o, collector when Nodes::SqlLiteral, Nodes::BindParam collector = visit value, collector else - collector << quote(value, attr && column_for(attr)).to_s + collector << quote(value).to_s end unless i == len collector << COMMA @@ -653,7 +631,7 @@ def visit_Arel_Nodes_Assignment o, collector else collector = visit o.left, collector collector << " = " - collector << quote(o.right, column_for(o.left)).to_s + collector << quote(o.right).to_s end end @@ -749,7 +727,7 @@ def quoted o, a if a && a.able_to_type_cast? quote(a.type_cast_for_database(o)) else - quote(o, column_for(a)) + quote(o) end end @@ -793,12 +771,9 @@ def visit_Array o, collector end alias :visit_Set :visit_Array - def quote value, column = nil + def quote value return value if Arel::Nodes::SqlLiteral === value - if column - print_type_cast_deprecation - end - @connection.quote value, column + @connection.quote value end def quote_table_name name @@ -847,20 +822,6 @@ def aggregate name, o, collector collector end end - - def print_type_cast_deprecation - unless defined?($arel_silence_type_casting_deprecation) && $arel_silence_type_casting_deprecation - warn <<-eowarn -Arel performing automatic type casting is deprecated, and will be removed in Arel 8.0. If you are seeing this, it is because you are manually passing a value to an Arel predicate, and the `Arel::Table` object was constructed manually. The easiest way to remove this warning is to use an `Arel::Table` object returned from calling `arel_table` on an ActiveRecord::Base subclass. - -If you're certain the value is already of the right type, change `attribute.eq(value)` to `attribute.eq(Arel::Nodes::Quoted.new(value))` (you will be able to remove that in Arel 8.0, it is only required to silence this deprecation warning). - -You can also silence this warning globally by setting `$arel_silence_type_casting_deprecation` to `true`. (Do NOT do this if you are a library author) - -If you are passing user input to a predicate, you must either give an appropriate type caster object to the `Arel::Table`, or manually cast the value before passing it to Arel. - eowarn - end - end end end end diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index f6b73adf6aa55..928b23ed7bb9f 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -996,14 +996,6 @@ def fake_caster.type_cast_for_database(attr_name, value) assert table.able_to_type_cast? condition.to_sql.must_equal %("foo"."id" = 1 AND "foo"."other_id" = '2') end - - it 'falls back to using the connection adapter for type casting' do - table = Table.new(:users) - condition = table["id"].eq("1") - - refute table.able_to_type_cast? - condition.to_sql.must_equal %("users"."id" = 1) - end end end end diff --git a/test/helper.rb b/test/helper.rb index 87f5756d24fe5..6e8ac836fcf63 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -6,8 +6,6 @@ require 'support/fake_record' Arel::Table.engine = FakeRecord::Base.new -$arel_silence_type_casting_deprecation = true - class Object def must_be_like other gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 3d4c7d563037d..4867dad5dc527 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -59,16 +59,7 @@ def schema_cache self end - def quote thing, column = nil - if column && !thing.nil? - case column.type - when :integer - thing = thing.to_i - when :string - thing = thing.to_s - end - end - + def quote thing case thing when DateTime "'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'" @@ -116,8 +107,8 @@ def schema_cache connection end - def quote thing, column = nil - connection.quote thing, column + def quote thing + connection.quote thing end end diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 6833d4e8f5669..451c267b34d6a 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -120,19 +120,6 @@ def dispatch sql.must_be_like %{ 'f' = 'f' } end - it 'should use the column to quote' do - table = Table.new(:users) - val = Nodes.build_quoted('1-fooo', table[:id]) - sql = compile Nodes::Equality.new(table[:id], val) - sql.must_be_like %{ "users"."id" = 1 } - end - - it 'should use the column to quote integers' do - table = Table.new(:users) - sql = compile table[:name].eq(0) - sql.must_be_like %{ "users"."name" = '0' } - end - it 'should handle nil' do sql = compile Nodes::Equality.new(@table[:name], nil) sql.must_be_like %{ "users"."name" IS NULL } @@ -191,24 +178,15 @@ def dispatch it "should quote LIMIT without column type coercion" do table = Table.new(:users) sc = table.where(table[:name].eq(0)).take(1).ast - assert_match(/WHERE "users"."name" = '0' LIMIT 1/, compile(sc)) + assert_match(/WHERE "users"."name" = 0 LIMIT 1/, compile(sc)) end it "should visit_DateTime" do - called_with = nil - @conn.connection.extend(Module.new { - define_method(:quote) do |thing, column| - called_with = column - super(thing, column) - end - }) - dt = DateTime.now table = Table.new(:users) test = table[:created_at].eq dt sql = compile test - assert_equal "created_at", called_with.name sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d %H:%M:%S")}'} end @@ -252,20 +230,11 @@ def dispatch end it "should visit_Date" do - called_with = nil - @conn.connection.extend(Module.new { - define_method(:quote) do |thing, column| - called_with = column - super(thing, column) - end - }) - dt = Date.today table = Table.new(:users) test = table[:created_at].eq dt sql = compile test - assert_equal "created_at", called_with.name sql.must_be_like %{"users"."created_at" = '#{dt.strftime("%Y-%m-%d")}'} end @@ -427,25 +396,6 @@ def dispatch "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') } end - - it 'uses the same column for escaping values' do - @attr = Table.new(:users)[:name] - visitor = Class.new(ToSql) do - attr_accessor :expected - - def quote value, column = nil - raise unless column == expected - super - end - end - vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) } - in_node = Nodes::In.new @attr, vals - visitor = visitor.new(Table.engine.connection) - visitor.expected = Table.engine.connection.columns(:users).find { |x| - x.name == 'name' - } - visitor.accept(in_node, Collectors::SQLString.new).value.must_equal %("users"."name" IN ('a', 'b', 'c')) - end end describe "Nodes::InfixOperation" do @@ -574,25 +524,6 @@ def quote value, column = nil "users"."id" NOT IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') } end - - it 'uses the same column for escaping values' do - @attr = Table.new(:users)[:name] - visitor = Class.new(ToSql) do - attr_accessor :expected - - def quote value, column = nil - raise unless column == expected - super - end - end - vals = %w{ a b c }.map { |x| Nodes.build_quoted(x, @attr) } - in_node = Nodes::NotIn.new @attr, vals - visitor = visitor.new(Table.engine.connection) - visitor.expected = Table.engine.connection.columns(:users).find { |x| - x.name == 'name' - } - compile(in_node).must_equal %("users"."name" NOT IN ('a', 'b', 'c')) - end end describe 'Constants' do @@ -615,7 +546,7 @@ def quote value, column = nil it "should use the underlying table for checking columns" do test = Table.new(:users).alias('zomgusers')[:id].eq '3' compile(test).must_be_like %{ - "zomgusers"."id" = 3 + "zomgusers"."id" = '3' } end end From ce700cb9bd750703f19d71c47e7c709f76773b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 29 Dec 2016 01:14:54 -0500 Subject: [PATCH 1436/1492] Bump arel to 8.0.0 --- lib/arel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel.rb b/lib/arel.rb index 2069cec7ce987..e04999ed92a7f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -21,7 +21,7 @@ require 'arel/nodes' module Arel - VERSION = '7.2.0' + VERSION = '8.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 674cbdbc1ec7b63726b38c067b3c2baadda01b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 29 Dec 2016 01:15:43 -0500 Subject: [PATCH 1437/1492] Fix identation --- test/visitors/test_to_sql.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 451c267b34d6a..e31d60366b1d1 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -267,14 +267,14 @@ def dispatch end it "should visit_Arel_Nodes_Assignment" do - column = @table["id"] - node = Nodes::Assignment.new( - Nodes::UnqualifiedColumn.new(column), - Nodes::UnqualifiedColumn.new(column) - ) + column = @table["id"] + node = Nodes::Assignment.new( + Nodes::UnqualifiedColumn.new(column), + Nodes::UnqualifiedColumn.new(column) + ) compile(node).must_be_like %{ - "id" = "id" - } + "id" = "id" + } end it "should visit visit_Arel_Attributes_Time" do From 3b1689f98c89f7e7a74c61e2894ed2bf81b2d56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 29 Dec 2016 01:17:40 -0500 Subject: [PATCH 1438/1492] Test with Ruby 2.4 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ee72f36a89641..32aeb83ea9aa4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ rvm: - 2.1 - 2.2.5 - 2.3.1 + - 2.4.0 - ruby-head matrix: fast_finish: true From b26638ef041953992010590b31615c519fa0ea7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 29 Dec 2016 01:37:27 -0500 Subject: [PATCH 1439/1492] Remove dead code now that attr is not used anymore --- lib/arel/visitors/to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ad2666fb101c1..ce9f8bca5985f 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -170,7 +170,7 @@ def visit_Arel_Nodes_Values o, collector collector << "VALUES (" len = o.expressions.length - 1 - o.expressions.zip(o.columns).each_with_index { |(value, attr), i| + o.expressions.each_with_index { |value, i| case value when Nodes::SqlLiteral, Nodes::BindParam collector = visit value, collector From bb74794d85a68baee793bdad245ee4abbdc1fd41 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Fri, 30 Dec 2016 20:19:11 +0000 Subject: [PATCH 1440/1492] Address `Use assert_nil if expecting nil` warnings --- test/test_select_manager.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index e6b13e748dd3f..9a225edeec090 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1198,7 +1198,7 @@ def test_manager_stores_bind_values manager.ast.cores.last.set_quantifier.class.must_equal Arel::Nodes::Distinct manager.distinct(false) - manager.ast.cores.last.set_quantifier.must_equal nil + manager.ast.cores.last.set_quantifier.must_be_nil end it "chains" do @@ -1217,7 +1217,7 @@ def test_manager_stores_bind_values manager.ast.cores.last.set_quantifier.must_equal Arel::Nodes::DistinctOn.new(table['id']) manager.distinct_on(false) - manager.ast.cores.last.set_quantifier.must_equal nil + manager.ast.cores.last.set_quantifier.must_be_nil end it "chains" do From 33d0d962b777a98f3bdda0be41ee03acc0410676 Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Tue, 17 Jan 2017 23:13:37 -0500 Subject: [PATCH 1441/1492] Raise custom error on empty join --- lib/arel.rb | 2 ++ lib/arel/errors.rb | 7 +++++++ lib/arel/select_manager.rb | 2 +- lib/arel/table.rb | 2 +- test/test_select_manager.rb | 10 ++++++++++ test/test_table.rb | 6 ++++++ 6 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 lib/arel/errors.rb diff --git a/lib/arel.rb b/lib/arel.rb index e04999ed92a7f..710914a2e323c 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,3 +1,5 @@ +require 'arel/errors' + require 'arel/crud' require 'arel/factory_methods' diff --git a/lib/arel/errors.rb b/lib/arel/errors.rb new file mode 100644 index 0000000000000..c8a6af9f7771e --- /dev/null +++ b/lib/arel/errors.rb @@ -0,0 +1,7 @@ +module Arel + class ArelError < StandardError + end + + class EmptyJoinError < ArelError + end +end diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index eae3bc8cbc0b9..6af9b6fbe6f80 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -106,7 +106,7 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral - raise if relation.empty? + raise EmptyJoinError if relation.empty? klass = Nodes::StringJoin end diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 3e06f942729a0..130b7ea028509 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -37,7 +37,7 @@ def join relation, klass = Nodes::InnerJoin case relation when String, Nodes::SqlLiteral - raise if relation.empty? + raise EmptyJoinError if relation.empty? klass = Nodes::StringJoin end diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 9a225edeec090..e88f0e8e118e7 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -618,6 +618,16 @@ def test_manager_stores_bind_values manager = Arel::SelectManager.new manager.join(nil).must_equal manager end + + it 'raises EmptyJoinError on empty' do + left = Table.new :users + manager = Arel::SelectManager.new + + manager.from left + assert_raises(EmptyJoinError) do + manager.join("") + end + end end describe 'outer join' do diff --git a/test/test_table.rb b/test/test_table.rb index 168fde370db57..e36a6e3a4120d 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -71,6 +71,12 @@ module Arel mgr.to_sql.must_be_like %{ SELECT FROM "users" } end + it 'raises EmptyJoinError on empty' do + assert_raises(EmptyJoinError) do + @relation.join "" + end + end + it 'takes a second argument for join type' do right = @relation.alias predicate = @relation[:id].eq(right[:id]) From 9dbd97e8e2361de2769c2bc5737b64cdf27025ea Mon Sep 17 00:00:00 2001 From: zhufenggood Date: Fri, 27 Jan 2017 18:43:34 +0800 Subject: [PATCH 1442/1492] Performance improvement. --- lib/arel/visitors/to_sql.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index ce9f8bca5985f..486c51a183976 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -80,7 +80,7 @@ def visit_Arel_Nodes_DeleteStatement o, collector collector << 'DELETE FROM ' collector = visit o.relation, collector if o.wheres.any? - collector << ' WHERE ' + collector << WHERE collector = inject_join o.wheres, collector, AND end @@ -265,12 +265,12 @@ def visit_Arel_Nodes_DistinctOn o, collector def visit_Arel_Nodes_With o, collector collector << "WITH " - inject_join o.children, collector, ', ' + inject_join o.children, collector, COMMA end def visit_Arel_Nodes_WithRecursive o, collector collector << "WITH RECURSIVE " - inject_join o.children, collector, ', ' + inject_join o.children, collector, COMMA end def visit_Arel_Nodes_Union o, collector @@ -524,7 +524,7 @@ def visit_Arel_Nodes_JoinSource o, collector end if o.right.any? collector << SPACE if o.left - collector = inject_join o.right, collector, ' ' + collector = inject_join o.right, collector, SPACE end collector end From d8a41890e0135666606167e8ea7e62b951863de6 Mon Sep 17 00:00:00 2001 From: Thomas Kienlen Date: Thu, 2 Feb 2017 15:16:22 +0100 Subject: [PATCH 1443/1492] named functions compared to nil --- test/visitors/test_to_sql.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index e31d60366b1d1..e7734e2814dd7 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -61,6 +61,12 @@ def dispatch sql.must_be_like %{ omg(*) = 2 } end + it 'should handle nil with named functions' do + function = Nodes::NamedFunction.new('omg', [Arel.star]) + sql = compile(function.eq(nil)) + sql.must_be_like %{ omg(*) IS NULL } + end + it 'should visit built-in functions' do function = Nodes::Count.new([Arel.star]) assert_equal 'COUNT(*)', compile(function) From c2bc569d2d538584cfc081e5775de17cdf2f054b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Mon, 13 Feb 2017 15:58:58 -0300 Subject: [PATCH 1444/1492] Enable frozen_string_literal in all files in arel --- .rubocop.yml | 6 ++++++ Gemfile | 1 + Rakefile | 1 + arel.gemspec | 1 + arel.gemspec.erb | 1 + lib/arel.rb | 1 + lib/arel/alias_predication.rb | 1 + lib/arel/attributes.rb | 1 + lib/arel/attributes/attribute.rb | 1 + lib/arel/collectors/bind.rb | 1 + lib/arel/collectors/plain_string.rb | 3 ++- lib/arel/collectors/sql_string.rb | 1 + lib/arel/compatibility/wheres.rb | 1 + lib/arel/crud.rb | 1 + lib/arel/delete_manager.rb | 1 + lib/arel/errors.rb | 1 + lib/arel/expressions.rb | 1 + lib/arel/factory_methods.rb | 1 + lib/arel/insert_manager.rb | 1 + lib/arel/math.rb | 1 + lib/arel/nodes.rb | 1 + lib/arel/nodes/and.rb | 1 + lib/arel/nodes/ascending.rb | 1 + lib/arel/nodes/binary.rb | 1 + lib/arel/nodes/bind_param.rb | 1 + lib/arel/nodes/case.rb | 1 + lib/arel/nodes/casted.rb | 1 + lib/arel/nodes/count.rb | 1 + lib/arel/nodes/delete_statement.rb | 1 + lib/arel/nodes/descending.rb | 1 + lib/arel/nodes/equality.rb | 1 + lib/arel/nodes/extract.rb | 1 + lib/arel/nodes/false.rb | 1 + lib/arel/nodes/full_outer_join.rb | 1 + lib/arel/nodes/function.rb | 1 + lib/arel/nodes/grouping.rb | 1 + lib/arel/nodes/in.rb | 1 + lib/arel/nodes/infix_operation.rb | 1 + lib/arel/nodes/inner_join.rb | 1 + lib/arel/nodes/insert_statement.rb | 1 + lib/arel/nodes/join_source.rb | 1 + lib/arel/nodes/matches.rb | 1 + lib/arel/nodes/named_function.rb | 1 + lib/arel/nodes/node.rb | 1 + lib/arel/nodes/outer_join.rb | 1 + lib/arel/nodes/over.rb | 1 + lib/arel/nodes/regexp.rb | 1 + lib/arel/nodes/right_outer_join.rb | 1 + lib/arel/nodes/select_core.rb | 1 + lib/arel/nodes/select_statement.rb | 1 + lib/arel/nodes/sql_literal.rb | 1 + lib/arel/nodes/string_join.rb | 1 + lib/arel/nodes/table_alias.rb | 1 + lib/arel/nodes/terminal.rb | 1 + lib/arel/nodes/true.rb | 1 + lib/arel/nodes/unary.rb | 1 + lib/arel/nodes/unary_operation.rb | 1 + lib/arel/nodes/unqualified_column.rb | 1 + lib/arel/nodes/update_statement.rb | 1 + lib/arel/nodes/values.rb | 1 + lib/arel/nodes/window.rb | 1 + lib/arel/nodes/with.rb | 1 + lib/arel/order_predications.rb | 1 + lib/arel/predications.rb | 1 + lib/arel/select_manager.rb | 1 + lib/arel/table.rb | 1 + lib/arel/tree_manager.rb | 1 + lib/arel/update_manager.rb | 1 + lib/arel/visitors.rb | 1 + lib/arel/visitors/bind_substitute.rb | 1 + lib/arel/visitors/depth_first.rb | 1 + lib/arel/visitors/reduce.rb | 1 + lib/arel/visitors/visitor.rb | 1 + lib/arel/window_predications.rb | 1 + test/attributes/test_attribute.rb | 1 + test/collectors/test_bind_collector.rb | 1 + test/collectors/test_sql_string.rb | 1 + test/helper.rb | 1 + test/nodes/test_and.rb | 1 + test/nodes/test_as.rb | 1 + test/nodes/test_ascending.rb | 1 + test/nodes/test_bin.rb | 1 + test/nodes/test_binary.rb | 1 + test/nodes/test_bind_param.rb | 1 + test/nodes/test_case.rb | 1 + test/nodes/test_casted.rb | 1 + test/nodes/test_count.rb | 1 + test/nodes/test_delete_statement.rb | 1 + test/nodes/test_descending.rb | 1 + test/nodes/test_distinct.rb | 1 + test/nodes/test_equality.rb | 1 + test/nodes/test_extract.rb | 1 + test/nodes/test_false.rb | 1 + test/nodes/test_grouping.rb | 1 + test/nodes/test_infix_operation.rb | 1 + test/nodes/test_insert_statement.rb | 1 + test/nodes/test_named_function.rb | 1 + test/nodes/test_node.rb | 1 + test/nodes/test_not.rb | 1 + test/nodes/test_or.rb | 1 + test/nodes/test_over.rb | 1 + test/nodes/test_select_core.rb | 1 + test/nodes/test_select_statement.rb | 1 + test/nodes/test_sql_literal.rb | 1 + test/nodes/test_sum.rb | 1 + test/nodes/test_table_alias.rb | 1 + test/nodes/test_true.rb | 1 + test/nodes/test_unary_operation.rb | 1 + test/nodes/test_update_statement.rb | 1 + test/nodes/test_window.rb | 1 + test/support/fake_record.rb | 1 + test/test_attributes.rb | 1 + test/test_crud.rb | 1 + test/test_delete_manager.rb | 1 + test/test_factory_methods.rb | 1 + test/test_insert_manager.rb | 1 + test/test_select_manager.rb | 1 + test/test_table.rb | 1 + test/test_update_manager.rb | 1 + test/visitors/test_bind_visitor.rb | 1 + test/visitors/test_depth_first.rb | 1 + test/visitors/test_dispatch_contamination.rb | 1 + test/visitors/test_dot.rb | 1 + test/visitors/test_ibm_db.rb | 1 + test/visitors/test_informix.rb | 1 + test/visitors/test_mssql.rb | 1 + test/visitors/test_mysql.rb | 1 + test/visitors/test_oracle.rb | 1 + test/visitors/test_oracle12.rb | 1 + test/visitors/test_postgres.rb | 1 + test/visitors/test_sqlite.rb | 1 + test/visitors/test_to_sql.rb | 1 + 132 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 .rubocop.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000000000..2379a2afd0966 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,6 @@ +AllCops: + DisabledByDefault: true + +Style/FrozenStringLiteralComment: + Enabled: true + EnforcedStyle: always diff --git a/Gemfile b/Gemfile index 07483b27d32f3..3b791743de426 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,4 @@ +# frozen_string_literal: true source "https://rubygems.org/" gemspec diff --git a/Rakefile b/Rakefile index 02b92e0b44a85..2625ee9506ca8 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'bundler' Bundler::GemHelper.install_tasks diff --git a/arel.gemspec b/arel.gemspec index 68b5a72101e8b..9cbf991ab7191 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,4 +1,5 @@ # # -*- encoding: utf-8 -*- +# frozen_string_literal: true $:.push File.expand_path("../lib", __FILE__) require "arel" diff --git a/arel.gemspec.erb b/arel.gemspec.erb index a64e585a28483..f7ff99469cffe 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -1,4 +1,5 @@ # # -*- encoding: utf-8 -*- +# frozen_string_literal: true $:.push File.expand_path("../lib", __FILE__) require "arel" diff --git a/lib/arel.rb b/lib/arel.rb index 710914a2e323c..f0d2bdce7894f 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/errors' require 'arel/crud' diff --git a/lib/arel/alias_predication.rb b/lib/arel/alias_predication.rb index f42e9ee1a6afb..cb50fb95be1dc 100644 --- a/lib/arel/alias_predication.rb +++ b/lib/arel/alias_predication.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module AliasPredication def as other diff --git a/lib/arel/attributes.rb b/lib/arel/attributes.rb index 92cc041f83035..ed4739ebeddc5 100644 --- a/lib/arel/attributes.rb +++ b/lib/arel/attributes.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/attributes/attribute' module Arel diff --git a/lib/arel/attributes/attribute.rb b/lib/arel/attributes/attribute.rb index cda5a5a3db636..41bc0c32c7d88 100644 --- a/lib/arel/attributes/attribute.rb +++ b/lib/arel/attributes/attribute.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Attributes class Attribute < Struct.new :relation, :name diff --git a/lib/arel/collectors/bind.rb b/lib/arel/collectors/bind.rb index 05cd9665096ea..dfa79d1001a63 100644 --- a/lib/arel/collectors/bind.rb +++ b/lib/arel/collectors/bind.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Collectors class Bind diff --git a/lib/arel/collectors/plain_string.rb b/lib/arel/collectors/plain_string.rb index 2505bc376efa9..1e8d2a2152d4e 100644 --- a/lib/arel/collectors/plain_string.rb +++ b/lib/arel/collectors/plain_string.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true module Arel module Collectors class PlainString def initialize - @str = '' + @str = ''.dup end def value diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index fd2faaef3ab4f..5f421173312b2 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -1,4 +1,5 @@ # encoding: utf-8 +# frozen_string_literal: true require 'arel/collectors/plain_string' diff --git a/lib/arel/compatibility/wheres.rb b/lib/arel/compatibility/wheres.rb index b73b1786514c7..3e60894bd80d2 100644 --- a/lib/arel/compatibility/wheres.rb +++ b/lib/arel/compatibility/wheres.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Compatibility # :nodoc: class Wheres # :nodoc: diff --git a/lib/arel/crud.rb b/lib/arel/crud.rb index d310c7381f0e9..2d104322058f4 100644 --- a/lib/arel/crud.rb +++ b/lib/arel/crud.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel ### # FIXME hopefully we can remove this diff --git a/lib/arel/delete_manager.rb b/lib/arel/delete_manager.rb index 20e988e01f26a..aee4511249d41 100644 --- a/lib/arel/delete_manager.rb +++ b/lib/arel/delete_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel class DeleteManager < Arel::TreeManager def initialize diff --git a/lib/arel/errors.rb b/lib/arel/errors.rb index c8a6af9f7771e..86fbb80461d32 100644 --- a/lib/arel/errors.rb +++ b/lib/arel/errors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel class ArelError < StandardError end diff --git a/lib/arel/expressions.rb b/lib/arel/expressions.rb index d40268c2925ad..612a0942f1319 100644 --- a/lib/arel/expressions.rb +++ b/lib/arel/expressions.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Expressions def count distinct = false diff --git a/lib/arel/factory_methods.rb b/lib/arel/factory_methods.rb index cb66f6f888419..6647c5ac44c54 100644 --- a/lib/arel/factory_methods.rb +++ b/lib/arel/factory_methods.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel ### # Methods for creating various nodes diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index 7829c3f4f9f15..d0a49842de1bb 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel class InsertManager < Arel::TreeManager def initialize diff --git a/lib/arel/math.rb b/lib/arel/math.rb index 04cae845984f3..9e6549b58fbdc 100644 --- a/lib/arel/math.rb +++ b/lib/arel/math.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Math def *(other) diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index ff27bb9aa822f..8c9815a96b320 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # node require 'arel/nodes/node' require 'arel/nodes/select_statement' diff --git a/lib/arel/nodes/and.rb b/lib/arel/nodes/and.rb index 8e1afda709014..1e2f61cf43dc5 100644 --- a/lib/arel/nodes/and.rb +++ b/lib/arel/nodes/and.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class And < Arel::Nodes::Node diff --git a/lib/arel/nodes/ascending.rb b/lib/arel/nodes/ascending.rb index bca00a833911f..adadab55e42d8 100644 --- a/lib/arel/nodes/ascending.rb +++ b/lib/arel/nodes/ascending.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Ascending < Ordering diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 763091c26708a..3001788774889 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Binary < Arel::Nodes::Node diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb index 3a4aedc4baf33..9e297831cd3a8 100644 --- a/lib/arel/nodes/bind_param.rb +++ b/lib/arel/nodes/bind_param.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class BindParam < Node diff --git a/lib/arel/nodes/case.rb b/lib/arel/nodes/case.rb index 85f8851dbe900..1edca400018b7 100644 --- a/lib/arel/nodes/case.rb +++ b/lib/arel/nodes/case.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Case < Arel::Nodes::Node diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb index 6b15f9e4b3a17..290e4dd38c16e 100644 --- a/lib/arel/nodes/casted.rb +++ b/lib/arel/nodes/casted.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Casted < Arel::Nodes::Node # :nodoc: diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index 5c8ade1cf98fb..a7c6236a223af 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Count < Arel::Nodes::Function diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index 8aaf8ca0b6704..593ce9bddf618 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class DeleteStatement < Arel::Nodes::Binary diff --git a/lib/arel/nodes/descending.rb b/lib/arel/nodes/descending.rb index d886bdcb5f759..d7261ab58323f 100644 --- a/lib/arel/nodes/descending.rb +++ b/lib/arel/nodes/descending.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Descending < Ordering diff --git a/lib/arel/nodes/equality.rb b/lib/arel/nodes/equality.rb index f29344e5806db..ef44725e24ea2 100644 --- a/lib/arel/nodes/equality.rb +++ b/lib/arel/nodes/equality.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Equality < Arel::Nodes::Binary diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb index 7ed678ca08b9e..4e797b6770769 100644 --- a/lib/arel/nodes/extract.rb +++ b/lib/arel/nodes/extract.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Extract < Arel::Nodes::Unary diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb index 6df70e43cef07..26b4e5db97a7b 100644 --- a/lib/arel/nodes/false.rb +++ b/lib/arel/nodes/false.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class False < Arel::Nodes::Node diff --git a/lib/arel/nodes/full_outer_join.rb b/lib/arel/nodes/full_outer_join.rb index 708f161c9a7f3..12a02d8cd9bc9 100644 --- a/lib/arel/nodes/full_outer_join.rb +++ b/lib/arel/nodes/full_outer_join.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class FullOuterJoin < Arel::Nodes::Join diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 182dfa73296bf..28a394e9f3921 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Function < Arel::Nodes::Node diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb index e7f4bd9cd5c4f..16911eb3b62d9 100644 --- a/lib/arel/nodes/grouping.rb +++ b/lib/arel/nodes/grouping.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Grouping < Unary diff --git a/lib/arel/nodes/in.rb b/lib/arel/nodes/in.rb index 6ccf37a053f2b..30cd771c4093d 100644 --- a/lib/arel/nodes/in.rb +++ b/lib/arel/nodes/in.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class In < Equality diff --git a/lib/arel/nodes/infix_operation.rb b/lib/arel/nodes/infix_operation.rb index 55ac715f73907..4eb7c5356fb73 100644 --- a/lib/arel/nodes/infix_operation.rb +++ b/lib/arel/nodes/infix_operation.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes diff --git a/lib/arel/nodes/inner_join.rb b/lib/arel/nodes/inner_join.rb index bf10eeac18684..4e398267c3731 100644 --- a/lib/arel/nodes/inner_join.rb +++ b/lib/arel/nodes/inner_join.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class InnerJoin < Arel::Nodes::Join diff --git a/lib/arel/nodes/insert_statement.rb b/lib/arel/nodes/insert_statement.rb index ada4fcc5622d3..72793bc1ad841 100644 --- a/lib/arel/nodes/insert_statement.rb +++ b/lib/arel/nodes/insert_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class InsertStatement < Arel::Nodes::Node diff --git a/lib/arel/nodes/join_source.rb b/lib/arel/nodes/join_source.rb index da828cf9eeee9..428ce8183eace 100644 --- a/lib/arel/nodes/join_source.rb +++ b/lib/arel/nodes/join_source.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes ### diff --git a/lib/arel/nodes/matches.rb b/lib/arel/nodes/matches.rb index 0d9c1925dc9c7..3ad3850a8ea3e 100644 --- a/lib/arel/nodes/matches.rb +++ b/lib/arel/nodes/matches.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Matches < Binary diff --git a/lib/arel/nodes/named_function.rb b/lib/arel/nodes/named_function.rb index c792f0af985d1..173838a7fd20f 100644 --- a/lib/arel/nodes/named_function.rb +++ b/lib/arel/nodes/named_function.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class NamedFunction < Arel::Nodes::Function diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 239c4fd766af2..34e71063aff92 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/collectors/sql_string' module Arel diff --git a/lib/arel/nodes/outer_join.rb b/lib/arel/nodes/outer_join.rb index bea5578b95c69..c568655fe6612 100644 --- a/lib/arel/nodes/outer_join.rb +++ b/lib/arel/nodes/outer_join.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class OuterJoin < Arel::Nodes::Join diff --git a/lib/arel/nodes/over.rb b/lib/arel/nodes/over.rb index 21d1b5029e096..47a34e69eaada 100644 --- a/lib/arel/nodes/over.rb +++ b/lib/arel/nodes/over.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes diff --git a/lib/arel/nodes/regexp.rb b/lib/arel/nodes/regexp.rb index 784368f5bfacb..8a76185ef00d8 100644 --- a/lib/arel/nodes/regexp.rb +++ b/lib/arel/nodes/regexp.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Regexp < Binary diff --git a/lib/arel/nodes/right_outer_join.rb b/lib/arel/nodes/right_outer_join.rb index ea1ddb7d52080..04ab31ebf09e1 100644 --- a/lib/arel/nodes/right_outer_join.rb +++ b/lib/arel/nodes/right_outer_join.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class RightOuterJoin < Arel::Nodes::Join diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 3696dd20af004..264fa46591963 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class SelectCore < Arel::Nodes::Node diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 830ac27046ac4..641a08405df0f 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class SelectStatement < Arel::Nodes::Node diff --git a/lib/arel/nodes/sql_literal.rb b/lib/arel/nodes/sql_literal.rb index 2c56644b99514..73575a7d49223 100644 --- a/lib/arel/nodes/sql_literal.rb +++ b/lib/arel/nodes/sql_literal.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class SqlLiteral < String diff --git a/lib/arel/nodes/string_join.rb b/lib/arel/nodes/string_join.rb index 7fb0033c0f0cd..21d6845c45eec 100644 --- a/lib/arel/nodes/string_join.rb +++ b/lib/arel/nodes/string_join.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class StringJoin < Arel::Nodes::Join diff --git a/lib/arel/nodes/table_alias.rb b/lib/arel/nodes/table_alias.rb index a5adc0766ab7e..78deb175b66ae 100644 --- a/lib/arel/nodes/table_alias.rb +++ b/lib/arel/nodes/table_alias.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class TableAlias < Arel::Nodes::Binary diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb index f4cdfdfe17273..6f60fe006fdc9 100644 --- a/lib/arel/nodes/terminal.rb +++ b/lib/arel/nodes/terminal.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Distinct < Arel::Nodes::Node diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb index 082963e5e6b99..796b5b9348d80 100644 --- a/lib/arel/nodes/true.rb +++ b/lib/arel/nodes/true.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class True < Arel::Nodes::Node diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index 50946980b4a67..a42744b1d5ebf 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Unary < Arel::Nodes::Node diff --git a/lib/arel/nodes/unary_operation.rb b/lib/arel/nodes/unary_operation.rb index 1636c012792fe..3c56ef20263a7 100644 --- a/lib/arel/nodes/unary_operation.rb +++ b/lib/arel/nodes/unary_operation.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes diff --git a/lib/arel/nodes/unqualified_column.rb b/lib/arel/nodes/unqualified_column.rb index 2820dba9d2266..f9017238c8aaa 100644 --- a/lib/arel/nodes/unqualified_column.rb +++ b/lib/arel/nodes/unqualified_column.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class UnqualifiedColumn < Arel::Nodes::Unary diff --git a/lib/arel/nodes/update_statement.rb b/lib/arel/nodes/update_statement.rb index d6831dc2424f5..286f0bd3cecf2 100644 --- a/lib/arel/nodes/update_statement.rb +++ b/lib/arel/nodes/update_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class UpdateStatement < Arel::Nodes::Node diff --git a/lib/arel/nodes/values.rb b/lib/arel/nodes/values.rb index 814e843dab849..b32d5063a20c9 100644 --- a/lib/arel/nodes/values.rb +++ b/lib/arel/nodes/values.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Values < Arel::Nodes::Binary diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index fee8eeff7a9ae..535c0c6238ada 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class Window < Arel::Nodes::Node diff --git a/lib/arel/nodes/with.rb b/lib/arel/nodes/with.rb index 7f08abe47daab..def7840ea3720 100644 --- a/lib/arel/nodes/with.rb +++ b/lib/arel/nodes/with.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Nodes class With < Arel::Nodes::Unary diff --git a/lib/arel/order_predications.rb b/lib/arel/order_predications.rb index 153fcffb41d20..d84be82bb6ba8 100644 --- a/lib/arel/order_predications.rb +++ b/lib/arel/order_predications.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module OrderPredications diff --git a/lib/arel/predications.rb b/lib/arel/predications.rb index 81bf3b4d954cf..799c7c67b82ea 100644 --- a/lib/arel/predications.rb +++ b/lib/arel/predications.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Predications def not_eq other diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 6af9b6fbe6f80..0b35176842275 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/collectors/sql_string' module Arel diff --git a/lib/arel/table.rb b/lib/arel/table.rb index 130b7ea028509..b3f2d79e5ffb6 100644 --- a/lib/arel/table.rb +++ b/lib/arel/table.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel class Table include Arel::Crud diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 5278ab06a14e9..cc3f1eeee4fe9 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/collectors/sql_string' module Arel diff --git a/lib/arel/update_manager.rb b/lib/arel/update_manager.rb index 36fb74fe7c6d1..eac414eafb97b 100644 --- a/lib/arel/update_manager.rb +++ b/lib/arel/update_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel class UpdateManager < Arel::TreeManager def initialize diff --git a/lib/arel/visitors.rb b/lib/arel/visitors.rb index 9bf5170463a65..a3404cf99207f 100644 --- a/lib/arel/visitors.rb +++ b/lib/arel/visitors.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/visitors/visitor' require 'arel/visitors/depth_first' require 'arel/visitors/to_sql' diff --git a/lib/arel/visitors/bind_substitute.rb b/lib/arel/visitors/bind_substitute.rb index ce0fb5c924602..52c96b0d72497 100644 --- a/lib/arel/visitors/bind_substitute.rb +++ b/lib/arel/visitors/bind_substitute.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class BindSubstitute diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 69ed345aea707..5416a285f5c79 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class DepthFirst < Arel::Visitors::Visitor diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb index 9670cad27cb4a..7948758e2fa01 100644 --- a/lib/arel/visitors/reduce.rb +++ b/lib/arel/visitors/reduce.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'arel/visitors/visitor' module Arel diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index bfe7342f0414a..b96b8238a7ca9 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module Visitors class Visitor diff --git a/lib/arel/window_predications.rb b/lib/arel/window_predications.rb index 71844eab53131..f93dede0360db 100644 --- a/lib/arel/window_predications.rb +++ b/lib/arel/window_predications.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Arel module WindowPredications diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 928b23ed7bb9f..2b971ce54ae46 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'ostruct' diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb index fc7df2fc45521..877aa20043f84 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_bind_collector.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'arel/collectors/bind' diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index 37a9e41f71049..92f1bf0fbac38 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'arel/collectors/bind' diff --git a/test/helper.rb b/test/helper.rb index 6e8ac836fcf63..022ba1dae66e5 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'rubygems' require 'minitest/autorun' require 'fileutils' diff --git a/test/nodes/test_and.rb b/test/nodes/test_and.rb index 88d6d61531d70..8d1980269ce46 100644 --- a/test/nodes/test_and.rb +++ b/test/nodes/test_and.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_as.rb b/test/nodes/test_as.rb index b1dcccf7c7b3a..1240d2333fe1f 100644 --- a/test/nodes/test_as.rb +++ b/test/nodes/test_as.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_ascending.rb b/test/nodes/test_ascending.rb index 2991d46583caa..9b0e5f0c18664 100644 --- a/test/nodes/test_ascending.rb +++ b/test/nodes/test_ascending.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_bin.rb b/test/nodes/test_bin.rb index 0dcc5f7bb8d0f..af27d827fd145 100644 --- a/test/nodes/test_bin.rb +++ b/test/nodes/test_bin.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_binary.rb b/test/nodes/test_binary.rb index 7e25a21151fcc..8e3025a4404c2 100644 --- a/test/nodes/test_binary.rb +++ b/test/nodes/test_binary.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'set' diff --git a/test/nodes/test_bind_param.rb b/test/nodes/test_bind_param.rb index ea008f4c996dc..011de6410c3bb 100644 --- a/test/nodes/test_bind_param.rb +++ b/test/nodes/test_bind_param.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_case.rb b/test/nodes/test_case.rb index a813ec7e695ea..21ff670e05b70 100644 --- a/test/nodes/test_case.rb +++ b/test/nodes/test_case.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_casted.rb b/test/nodes/test_casted.rb index 6d775e17ecc43..748879a538998 100644 --- a/test/nodes/test_casted.rb +++ b/test/nodes/test_casted.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index a9a329420ebd1..85e93b192709a 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::Count do diff --git a/test/nodes/test_delete_statement.rb b/test/nodes/test_delete_statement.rb index 4bd5446ba2dc9..5ce51a9ae8b1a 100644 --- a/test/nodes/test_delete_statement.rb +++ b/test/nodes/test_delete_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::DeleteStatement do diff --git a/test/nodes/test_descending.rb b/test/nodes/test_descending.rb index fce71d69e90db..98de94910f7d7 100644 --- a/test/nodes/test_descending.rb +++ b/test/nodes/test_descending.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_distinct.rb b/test/nodes/test_distinct.rb index ffa8a68e6c77c..6c51b999461e0 100644 --- a/test/nodes/test_distinct.rb +++ b/test/nodes/test_distinct.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_equality.rb b/test/nodes/test_equality.rb index 42a156b051a29..83f73f1789b2f 100644 --- a/test/nodes/test_equality.rb +++ b/test/nodes/test_equality.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_extract.rb b/test/nodes/test_extract.rb index eb9855326845e..307ef2572c57a 100644 --- a/test/nodes/test_extract.rb +++ b/test/nodes/test_extract.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::Extract do diff --git a/test/nodes/test_false.rb b/test/nodes/test_false.rb index a2a88666803f0..da65e7154720b 100644 --- a/test/nodes/test_false.rb +++ b/test/nodes/test_false.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_grouping.rb b/test/nodes/test_grouping.rb index febf0bee40623..8379336109b95 100644 --- a/test/nodes/test_grouping.rb +++ b/test/nodes/test_grouping.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_infix_operation.rb b/test/nodes/test_infix_operation.rb index 40616024e5988..b6c891a5c0645 100644 --- a/test/nodes/test_infix_operation.rb +++ b/test/nodes/test_infix_operation.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_insert_statement.rb b/test/nodes/test_insert_statement.rb index e0a5696ea45ac..af2c9541cb663 100644 --- a/test/nodes/test_insert_statement.rb +++ b/test/nodes/test_insert_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::InsertStatement do diff --git a/test/nodes/test_named_function.rb b/test/nodes/test_named_function.rb index 33830d9d4369e..1f765e822d5c2 100644 --- a/test/nodes/test_named_function.rb +++ b/test/nodes/test_named_function.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_node.rb b/test/nodes/test_node.rb index 056df7a584352..2fd27600bea97 100644 --- a/test/nodes/test_node.rb +++ b/test/nodes/test_node.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_not.rb b/test/nodes/test_not.rb index a08d0374456ff..cd027cec16053 100644 --- a/test/nodes/test_not.rb +++ b/test/nodes/test_not.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_or.rb b/test/nodes/test_or.rb index 3e7bcc9379066..6bc02c0ad3c7b 100644 --- a/test/nodes/test_or.rb +++ b/test/nodes/test_or.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_over.rb b/test/nodes/test_over.rb index 0aac00b23034e..183c02fad3328 100644 --- a/test/nodes/test_over.rb +++ b/test/nodes/test_over.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::Over do diff --git a/test/nodes/test_select_core.rb b/test/nodes/test_select_core.rb index 4114bcf4ffa42..f868a2f940957 100644 --- a/test/nodes/test_select_core.rb +++ b/test/nodes/test_select_core.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_select_statement.rb b/test/nodes/test_select_statement.rb index 3e4fcc0c079e6..ae209b86fd168 100644 --- a/test/nodes/test_select_statement.rb +++ b/test/nodes/test_select_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::SelectStatement do diff --git a/test/nodes/test_sql_literal.rb b/test/nodes/test_sql_literal.rb index c09e5882d5ca4..74e4f2cc90e57 100644 --- a/test/nodes/test_sql_literal.rb +++ b/test/nodes/test_sql_literal.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'yaml' diff --git a/test/nodes/test_sum.rb b/test/nodes/test_sum.rb index d387e7f9efe82..e1b65abbef310 100644 --- a/test/nodes/test_sum.rb +++ b/test/nodes/test_sum.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::Sum do diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb index 57c9a42fc660f..39040e63526da 100644 --- a/test/nodes/test_table_alias.rb +++ b/test/nodes/test_table_alias.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'ostruct' diff --git a/test/nodes/test_true.rb b/test/nodes/test_true.rb index ed4743a63b382..35b4d0a14d6d8 100644 --- a/test/nodes/test_true.rb +++ b/test/nodes/test_true.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_unary_operation.rb b/test/nodes/test_unary_operation.rb index d89c10b43118b..bde9594a2c483 100644 --- a/test/nodes/test_unary_operation.rb +++ b/test/nodes/test_unary_operation.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/nodes/test_update_statement.rb b/test/nodes/test_update_statement.rb index 920dc6e3efee8..09a4a0907472b 100644 --- a/test/nodes/test_update_statement.rb +++ b/test/nodes/test_update_statement.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' describe Arel::Nodes::UpdateStatement do diff --git a/test/nodes/test_window.rb b/test/nodes/test_window.rb index 9ec42be59fb9c..b4ad22edb5ebc 100644 --- a/test/nodes/test_window.rb +++ b/test/nodes/test_window.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 4867dad5dc527..03116ff2ee01c 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module FakeRecord class Column < Struct.new(:name, :type) end diff --git a/test/test_attributes.rb b/test/test_attributes.rb index d0b00d4333010..754fc0c1341b0 100644 --- a/test/test_attributes.rb +++ b/test/test_attributes.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_crud.rb b/test/test_crud.rb index 5c470155acfb3..0832f82aee20c 100644 --- a/test/test_crud.rb +++ b/test/test_crud.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_delete_manager.rb b/test/test_delete_manager.rb index ece2389d8844e..2d068d3b8b8e1 100644 --- a/test/test_delete_manager.rb +++ b/test/test_delete_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_factory_methods.rb b/test/test_factory_methods.rb index 3e23b090b4732..3dbe2d615d726 100644 --- a/test/test_factory_methods.rb +++ b/test/test_factory_methods.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 4289b0fa8cf73..f6a76fc20fd54 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index e88f0e8e118e7..076b732984a50 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_table.rb b/test/test_table.rb index e36a6e3a4120d..9877d245412a5 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index f41dc46e7dfd6..85abbf3875b12 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb index f0007cabbfd98..3e0578a6a1835 100644 --- a/test/visitors/test_bind_visitor.rb +++ b/test/visitors/test_bind_visitor.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'arel/visitors/bind_visitor' require 'support/fake_record' diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 81220b63a4d52..0c7f7ccd34bc3 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'set' diff --git a/test/visitors/test_dispatch_contamination.rb b/test/visitors/test_dispatch_contamination.rb index d3c9e8af2edb3..6422a6dff38ff 100644 --- a/test/visitors/test_dispatch_contamination.rb +++ b/test/visitors/test_dispatch_contamination.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 179a2c297c59b..1d27d1a5cb1e7 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_ibm_db.rb b/test/visitors/test_ibm_db.rb index f1aa7612be09e..81a5713183342 100644 --- a/test/visitors/test_ibm_db.rb +++ b/test/visitors/test_ibm_db.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_informix.rb b/test/visitors/test_informix.rb index 04c42f8f609eb..9d15979219981 100644 --- a/test/visitors/test_informix.rb +++ b/test/visitors/test_informix.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_mssql.rb b/test/visitors/test_mssql.rb index fe228bce4b2b0..0d0753b14b956 100644 --- a/test/visitors/test_mssql.rb +++ b/test/visitors/test_mssql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_mysql.rb b/test/visitors/test_mysql.rb index 30dcea3d36b40..9a205311d4994 100644 --- a/test/visitors/test_mysql.rb +++ b/test/visitors/test_mysql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 4c22be5cbb93a..b1921f0cbc451 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index 43235fd72cab8..c908a51d4f3fc 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index f97b734b7dfa6..26cc72187173e 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_sqlite.rb b/test/visitors/test_sqlite.rb index a9f3501f20198..2e145b3faad7e 100644 --- a/test/visitors/test_sqlite.rb +++ b/test/visitors/test_sqlite.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' module Arel diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index e31d60366b1d1..07458c1dc5a3d 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'helper' require 'set' From dba166bfd317bfeaba7211d2e65fbd760a184f6c Mon Sep 17 00:00:00 2001 From: Garrett Thornburg Date: Fri, 17 Feb 2017 11:40:29 -0700 Subject: [PATCH 1445/1492] Make Visitor visit thread safe by holding dispatch method reference --- lib/arel/visitors/reduce.rb | 5 +++-- lib/arel/visitors/visitor.rb | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb index 7948758e2fa01..1156b780f0f36 100644 --- a/lib/arel/visitors/reduce.rb +++ b/lib/arel/visitors/reduce.rb @@ -11,9 +11,10 @@ def accept object, collector private def visit object, collector - send dispatch[object.class], object, collector + dispatch_method = dispatch[object.class] + send dispatch_method, object, collector rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class], true) + raise e if respond_to?(dispatch_method, true) superklass = object.class.ancestors.find { |klass| respond_to?(dispatch[klass], true) } diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index b96b8238a7ca9..2690c98e3c402 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -27,9 +27,10 @@ def dispatch end def visit object - send dispatch[object.class], object + dispatch_method = dispatch[object.class] + send dispatch_method, object rescue NoMethodError => e - raise e if respond_to?(dispatch[object.class], true) + raise e if respond_to?(dispatch_method, true) superklass = object.class.ancestors.find { |klass| respond_to?(dispatch[klass], true) } From 668da2dfa951ea43f9b2c1171b225b10dba50a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 21 Feb 2017 11:39:57 -0500 Subject: [PATCH 1446/1492] Prepare to 8.0.0 --- History.txt | 3 +++ arel.gemspec | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index aacf6d7a16374..6985da4f49e52 100644 --- a/History.txt +++ b/History.txt @@ -1,6 +1,9 @@ +=== 8.0.0 / 2017-02-21 + * Enhancements * Remove deprecated type casting support in Arel + * Frozen all string literals in Arel === 7.1.1 / 2016-07-27 diff --git a/arel.gemspec b/arel.gemspec index 9cbf991ab7191..3924bd15d213d 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') From 1ee6710b54c013d31951ce22c74ac72377ebbbf6 Mon Sep 17 00:00:00 2001 From: Jason Kurian Date: Wed, 22 Feb 2017 18:20:06 -0500 Subject: [PATCH 1447/1492] docs: add distinct to README --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 292b7fdbcac44..2872589524048 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,14 @@ The `OR` operator works like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) ``` -The `AND` operator behaves similarly. +The `AND` operator behaves similarly. The exception is the `DISTINCT` operator, which is not chainable: + +``` +posts = Arel::Table.new(:posts) +posts.project(posts[:title]) +posts.distinct +posts.to_sql # => 'SELECT DISTINCT "posts"."title" FROM "posts"' +``` Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: From 5a5170a8d2a1444ace4d7d4346516a84b4fd4ef9 Mon Sep 17 00:00:00 2001 From: Jason Kurian Date: Wed, 22 Feb 2017 18:22:22 -0500 Subject: [PATCH 1448/1492] docs(distinct): fix distinct example [skip ci] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2872589524048..b2a586375489e 100644 --- a/README.md +++ b/README.md @@ -150,9 +150,9 @@ The `OR` operator works like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) ``` -The `AND` operator behaves similarly. The exception is the `DISTINCT` operator, which is not chainable: +The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator, which as of v6 is also chainable: -``` +```ruby posts = Arel::Table.new(:posts) posts.project(posts[:title]) posts.distinct From 59e0d5fcb73bffbf4de2262d7629cf4f8e580eda Mon Sep 17 00:00:00 2001 From: Jason Kurian Date: Wed, 22 Feb 2017 18:51:13 -0500 Subject: [PATCH 1449/1492] docs(distinct): tweaks [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2a586375489e..af768361ab5b8 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ The `OR` operator works like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) ``` -The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator, which as of v6 is also chainable: +The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator: ```ruby posts = Arel::Table.new(:posts) From 95ffacb33d463df8afcb102b3efebe75827dbe03 Mon Sep 17 00:00:00 2001 From: Pedro Sena Date: Tue, 28 Feb 2017 18:10:40 -0300 Subject: [PATCH 1450/1492] Made InsertManager#insert chainable --- lib/arel/insert_manager.rb | 1 + test/test_insert_manager.rb | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index d0a49842de1bb..f9a598e8b74eb 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -34,6 +34,7 @@ def insert fields end @ast.values = create_values values, @ast.columns end + self end def create_values values, columns diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index f6a76fc20fd54..b9ee6f76ac827 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -88,6 +88,13 @@ module Arel INSERT INTO "users" ("id") VALUES (1) } end + + it 'is chainable' do + table = Table.new(:users) + manager = Arel::InsertManager.new + insert_result = manager.insert [[table[:id],1]] + assert_equal manager, insert_result + end end describe 'into' do From 6a9f79ad876b930ab8cb17acf70b95c1cc800f8d Mon Sep 17 00:00:00 2001 From: Ville Lautanala Date: Tue, 25 Apr 2017 07:41:52 +0300 Subject: [PATCH 1451/1492] Fix link to SQL-92 grammar --- lib/arel/nodes/select_core.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arel/nodes/select_core.rb b/lib/arel/nodes/select_core.rb index 264fa46591963..fa1c026107a3c 100644 --- a/lib/arel/nodes/select_core.rb +++ b/lib/arel/nodes/select_core.rb @@ -10,7 +10,7 @@ def initialize @source = JoinSource.new nil @top = nil - # http://savage.net.au/SQL/sql-92.bnf.html#set%20quantifier + # https://ronsavage.github.io/SQL/sql-92.bnf.html#set%20quantifier @set_quantifier = nil @projections = [] @wheres = [] From d8f463a3b87ff9f69eef2a3ed5718b198c2072a1 Mon Sep 17 00:00:00 2001 From: Ville Lautanala Date: Tue, 25 Apr 2017 07:41:52 +0300 Subject: [PATCH 1452/1492] PostgreSQL lateral expressions Support for PostgreSQL lateral expressions. This is treated as an unary function applied to a query expression. Lateral is a separate function to provide interoperability with aliases and unions. These are also separate node types that wrap SelectStatements. The lateral option would need to be implemented in these nodes separately if lateral was an option of SelectStatement. When building the query, an alias can be given as an argument. This enables building a lateral query with an table alias without using either Nodes::TableAlias or Nodes::Lateral directly. --- lib/arel/nodes/unary.rb | 1 + lib/arel/select_manager.rb | 5 +++++ lib/arel/visitors/depth_first.rb | 1 + lib/arel/visitors/postgresql.rb | 18 ++++++++++++++++++ test/visitors/test_postgres.rb | 14 ++++++++++++++ 5 files changed, 39 insertions(+) diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index a42744b1d5ebf..60cff1defe97a 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -28,6 +28,7 @@ def eql? other Group GroupingElement GroupingSet + Lateral Limit Lock Not diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 0b35176842275..73fa5da6ed166 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -204,6 +204,11 @@ def except other end alias :minus :except + def lateral table_name = nil + base = table_name.nil? ? ast : as(table_name) + Nodes::Lateral.new(base) + end + def with *subqueries if subqueries.first.is_a? Symbol node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") diff --git a/lib/arel/visitors/depth_first.rb b/lib/arel/visitors/depth_first.rb index 5416a285f5c79..b3bbc9bd40711 100644 --- a/lib/arel/visitors/depth_first.rb +++ b/lib/arel/visitors/depth_first.rb @@ -25,6 +25,7 @@ def unary o alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary + alias :visit_Arel_Nodes_Lateral :unary alias :visit_Arel_Nodes_Limit :unary alias :visit_Arel_Nodes_Not :unary alias :visit_Arel_Nodes_Offset :unary diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index f0991a2f11222..bd4421bd5869a 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -5,6 +5,7 @@ class PostgreSQL < Arel::Visitors::ToSql CUBE = 'CUBE' ROLLUP = 'ROLLUP' GROUPING_SET = 'GROUPING SET' + LATERAL = 'LATERAL' private @@ -69,6 +70,23 @@ def visit_Arel_Nodes_GroupingSet o, collector grouping_array_or_grouping_element o, collector end + def visit_Arel_Nodes_Lateral o, collector + collector << LATERAL + collector << SPACE + grouping_parentheses o, collector + end + + # Used by Lateral visitor to enclose select queries in parentheses + def grouping_parentheses o, collector + if o.expr.is_a? Nodes::SelectStatement + collector << "(" + visit o.expr, collector + collector << ")" + else + visit o.expr, collector + end + end + # Utilized by GroupingSet, Cube & RollUp visitors to # handle grouping aggregation semantics def grouping_array_or_grouping_element o, collector diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 26cc72187173e..d3cab623c4b9c 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -51,6 +51,20 @@ def compile node assert_equal 'SELECT DISTINCT', compile(core) end + it 'encloses LATERAL queries in parens' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + compile(subquery.lateral).must_be_like %{ + LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') + } + end + + it 'produces LATERAL queries with alias' do + subquery = @table.project(:id).where(@table[:name].matches('foo%')) + compile(subquery.lateral('bar')).must_be_like %{ + LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') bar + } + end + describe "Nodes::Matches" do it "should know how to visit" do node = @table[:name].matches('foo%') From 5d6d14cb6be217abc04253da0fe49721d09e9575 Mon Sep 17 00:00:00 2001 From: Kir Shatrov Date: Sun, 30 Apr 2017 22:19:09 -0400 Subject: [PATCH 1453/1492] Support multiple inserts --- lib/arel/insert_manager.rb | 6 +++++- lib/arel/nodes.rb | 1 + lib/arel/nodes/tuple.rb | 13 +++++++++++++ lib/arel/visitors/to_sql.rb | 14 +++++++++++++- test/test_insert_manager.rb | 19 +++++++++++++++++++ test/test_table.rb | 4 ++-- test/visitors/test_to_sql.rb | 2 +- 7 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 lib/arel/nodes/tuple.rb diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index f9a598e8b74eb..3c95ca6443db5 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -37,8 +37,12 @@ def insert fields self end - def create_values values, columns + def create_values values, columns = nil Nodes::Values.new values, columns end + + def create_tuple values + Nodes::Tuple.new values + end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 8c9815a96b320..d178e8d2ed775 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -6,6 +6,7 @@ require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' require 'arel/nodes/bind_param' +require 'arel/nodes/tuple' # terminal diff --git a/lib/arel/nodes/tuple.rb b/lib/arel/nodes/tuple.rb new file mode 100644 index 0000000000000..4e088a79aa885 --- /dev/null +++ b/lib/arel/nodes/tuple.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Arel + module Nodes + class Tuple < Node + attr_reader :values + + def initialize(values) + @values = values + super() + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 486c51a183976..7143d4e76adce 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -131,6 +131,7 @@ def visit_Arel_Nodes_InsertStatement o, collector end if o.values + collector << " VALUES" maybe_visit o.values, collector elsif o.select maybe_visit o.select, collector @@ -166,8 +167,19 @@ def visit_Arel_Nodes_False o, collector collector << "FALSE" end + def visit_Arel_Nodes_Tuple o, collector + len = o.values.length - 1 + o.values.each_with_index { |value, i| + collector = visit value, collector + unless i == len + collector << COMMA + end + } + collector + end + def visit_Arel_Nodes_Values o, collector - collector << "VALUES (" + collector << "(" len = o.expressions.length - 1 o.expressions.each_with_index { |value, i| diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index b9ee6f76ac827..46549c1ae49ae 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -28,6 +28,25 @@ module Arel } end + it 'inserts multiple values' do + table = Table.new(:users) + manager = Arel::InsertManager.new + manager.into table + + manager.columns << table[:id] + manager.columns << table[:name] + + manager.values = manager.create_tuple([ + manager.create_values(%w{ 1 david }), + manager.create_values(%w{ 2 kirs }), + manager.create_values(["3", Arel.sql('DEFAULT')], []), + ]) + + manager.to_sql.must_be_like %{ + INSERT INTO \"users\" (\"id\", \"name\") VALUES ('1', 'david'), ('2', 'kirs'), ('3', DEFAULT) + } + end + it "inserts false" do table = Table.new(:users) manager = Arel::InsertManager.new diff --git a/test/test_table.rb b/test/test_table.rb index 9877d245412a5..e83d04d2bd302 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -42,10 +42,10 @@ module Arel end it 'should return an insert manager' do - im = @relation.compile_insert 'VALUES(NULL)' + im = @relation.compile_insert '(NULL)' assert_kind_of Arel::InsertManager, im im.into Table.new(:users) - assert_equal "INSERT INTO \"users\" VALUES(NULL)", im.to_sql + assert_equal "INSERT INTO \"users\" VALUES (NULL)", im.to_sql end describe 'skip' do diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 31279b0ae2ab8..52f9855545a0d 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -26,7 +26,7 @@ def compile node bp = Nodes::BindParam.new values = Nodes::Values.new([bp]) sql = compile values - sql.must_be_like 'VALUES (?)' + sql.must_be_like '(?)' end it 'can define a dispatch method' do From a0bebf352629010103ff7e3cc003ce69a2d9b2df Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Thu, 4 May 2017 18:04:24 +0900 Subject: [PATCH 1454/1492] Remove unused `engine` Follow up of 98fc25991137ee09b6800578117f8c1c322680f2. `engine` is only used for `to_sql` and `where_sql` now. --- lib/arel/tree_manager.rb | 2 +- test/test_select_manager.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index cc3f1eeee4fe9..a8dbb4c87a450 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -5,7 +5,7 @@ module Arel class TreeManager include Arel::FactoryMethods - attr_reader :ast, :engine + attr_reader :ast attr_accessor :bind_values diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 076b732984a50..9a49fbcd566ee 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -226,7 +226,7 @@ def test_manager_stores_bind_values table = Table.new(:users) manager = Arel::SelectManager.new table manager.project Nodes::SqlLiteral.new '*' - m2 = Arel::SelectManager.new(manager.engine) + m2 = Arel::SelectManager.new m2.project manager.exists m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) } end @@ -235,7 +235,7 @@ def test_manager_stores_bind_values table = Table.new(:users) manager = Arel::SelectManager.new table manager.project Nodes::SqlLiteral.new '*' - m2 = Arel::SelectManager.new(manager.engine) + m2 = Arel::SelectManager.new m2.project manager.exists.as('foo') m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo } end From a98c9bdbdd233ff60457450deea80d2015ee1193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 4 May 2017 15:13:58 -0700 Subject: [PATCH 1455/1492] Revert "Merge pull request #482 from kirs/multiple-insert" This reverts commit 6d105c7f891a14316eab47dfff3bf1b94f3204e7, reversing changes made to 437aa3a4bb8ad4f3f4eba299dbb1112852f9c7ac. This broke Active Record when the values are sql literals --- lib/arel/insert_manager.rb | 6 +----- lib/arel/nodes.rb | 1 - lib/arel/nodes/tuple.rb | 13 ------------- lib/arel/visitors/to_sql.rb | 14 +------------- test/test_insert_manager.rb | 19 ------------------- test/test_table.rb | 4 ++-- test/visitors/test_to_sql.rb | 2 +- 7 files changed, 5 insertions(+), 54 deletions(-) delete mode 100644 lib/arel/nodes/tuple.rb diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index 3c95ca6443db5..f9a598e8b74eb 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -37,12 +37,8 @@ def insert fields self end - def create_values values, columns = nil + def create_values values, columns Nodes::Values.new values, columns end - - def create_tuple values - Nodes::Tuple.new values - end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index d178e8d2ed775..8c9815a96b320 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -6,7 +6,6 @@ require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' require 'arel/nodes/bind_param' -require 'arel/nodes/tuple' # terminal diff --git a/lib/arel/nodes/tuple.rb b/lib/arel/nodes/tuple.rb deleted file mode 100644 index 4e088a79aa885..0000000000000 --- a/lib/arel/nodes/tuple.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true -module Arel - module Nodes - class Tuple < Node - attr_reader :values - - def initialize(values) - @values = values - super() - end - end - end -end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 7143d4e76adce..486c51a183976 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -131,7 +131,6 @@ def visit_Arel_Nodes_InsertStatement o, collector end if o.values - collector << " VALUES" maybe_visit o.values, collector elsif o.select maybe_visit o.select, collector @@ -167,19 +166,8 @@ def visit_Arel_Nodes_False o, collector collector << "FALSE" end - def visit_Arel_Nodes_Tuple o, collector - len = o.values.length - 1 - o.values.each_with_index { |value, i| - collector = visit value, collector - unless i == len - collector << COMMA - end - } - collector - end - def visit_Arel_Nodes_Values o, collector - collector << "(" + collector << "VALUES (" len = o.expressions.length - 1 o.expressions.each_with_index { |value, i| diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 46549c1ae49ae..b9ee6f76ac827 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -28,25 +28,6 @@ module Arel } end - it 'inserts multiple values' do - table = Table.new(:users) - manager = Arel::InsertManager.new - manager.into table - - manager.columns << table[:id] - manager.columns << table[:name] - - manager.values = manager.create_tuple([ - manager.create_values(%w{ 1 david }), - manager.create_values(%w{ 2 kirs }), - manager.create_values(["3", Arel.sql('DEFAULT')], []), - ]) - - manager.to_sql.must_be_like %{ - INSERT INTO \"users\" (\"id\", \"name\") VALUES ('1', 'david'), ('2', 'kirs'), ('3', DEFAULT) - } - end - it "inserts false" do table = Table.new(:users) manager = Arel::InsertManager.new diff --git a/test/test_table.rb b/test/test_table.rb index e83d04d2bd302..9877d245412a5 100644 --- a/test/test_table.rb +++ b/test/test_table.rb @@ -42,10 +42,10 @@ module Arel end it 'should return an insert manager' do - im = @relation.compile_insert '(NULL)' + im = @relation.compile_insert 'VALUES(NULL)' assert_kind_of Arel::InsertManager, im im.into Table.new(:users) - assert_equal "INSERT INTO \"users\" VALUES (NULL)", im.to_sql + assert_equal "INSERT INTO \"users\" VALUES(NULL)", im.to_sql end describe 'skip' do diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 52f9855545a0d..31279b0ae2ab8 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -26,7 +26,7 @@ def compile node bp = Nodes::BindParam.new values = Nodes::Values.new([bp]) sql = compile values - sql.must_be_like '(?)' + sql.must_be_like 'VALUES (?)' end it 'can define a dispatch method' do From 5db56a513286814991c27000af2c0243cc19d1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 4 May 2017 15:14:33 -0700 Subject: [PATCH 1456/1492] Add regression test --- test/test_insert_manager.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index b9ee6f76ac827..97317791fedb3 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -136,6 +136,17 @@ module Arel INSERT INTO "users" VALUES (1) } end + + it "accepts sql literals" do + table = Table.new :users + manager = Arel::InsertManager.new + manager.into table + + manager.values = Arel.sql("DEFAULT VALUES") + manager.to_sql.must_be_like %{ + INSERT INTO "users" DEFAULT VALUES + } + end end describe "combo" do From 5e6312e1745dc278ba0a99bf2bc7b78977785d35 Mon Sep 17 00:00:00 2001 From: Kir Shatrov Date: Sun, 21 May 2017 13:12:08 +0100 Subject: [PATCH 1457/1492] Support INSERT with multiple values --- lib/arel/insert_manager.rb | 4 +++ lib/arel/nodes.rb | 1 + lib/arel/nodes/values_list.rb | 13 +++++++++ lib/arel/visitors/to_sql.rb | 22 ++++++++++++++ test/test_insert_manager.rb | 54 +++++++++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 lib/arel/nodes/values_list.rb diff --git a/lib/arel/insert_manager.rb b/lib/arel/insert_manager.rb index f9a598e8b74eb..dcbac6cb43d2f 100644 --- a/lib/arel/insert_manager.rb +++ b/lib/arel/insert_manager.rb @@ -40,5 +40,9 @@ def insert fields def create_values values, columns Nodes::Values.new values, columns end + + def create_values_list(rows) + Nodes::ValuesList.new(rows) + end end end diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index 8c9815a96b320..bb8ad6500b8ea 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -44,6 +44,7 @@ require 'arel/nodes/count' require 'arel/nodes/extract' require 'arel/nodes/values' +require 'arel/nodes/values_list' require 'arel/nodes/named_function' # windows diff --git a/lib/arel/nodes/values_list.rb b/lib/arel/nodes/values_list.rb new file mode 100644 index 0000000000000..b39aaa14654b3 --- /dev/null +++ b/lib/arel/nodes/values_list.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true +module Arel + module Nodes + class ValuesList < Node + attr_reader :rows + + def initialize(rows) + @rows = rows + super() + end + end + end +end diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 486c51a183976..3f1e390dccdcd 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -166,6 +166,28 @@ def visit_Arel_Nodes_False o, collector collector << "FALSE" end + def visit_Arel_Nodes_ValuesList o, collector + collector << "VALUES " + + len = o.rows.length - 1 + o.rows.each_with_index { |row, i| + collector << '(' + row_len = row.length - 1 + row.each_with_index do |value, k| + case value + when Nodes::SqlLiteral, Nodes::BindParam + collector = visit(value, collector) + else + collector << quote(value) + end + collector << COMMA unless k == row_len + end + collector << ')' + collector << COMMA unless i == len + } + collector + end + def visit_Arel_Nodes_Values o, collector collector << "VALUES (" diff --git a/test/test_insert_manager.rb b/test/test_insert_manager.rb index 97317791fedb3..8b61a2791e8dc 100644 --- a/test/test_insert_manager.rb +++ b/test/test_insert_manager.rb @@ -28,6 +28,60 @@ module Arel } end + it 'works with multiple values' do + table = Table.new(:users) + manager = Arel::InsertManager.new + manager.into table + + manager.columns << table[:id] + manager.columns << table[:name] + + manager.values = manager.create_values_list([ + %w{1 david}, + %w{2 kir}, + ["3", Arel.sql('DEFAULT')], + ]) + + manager.to_sql.must_be_like %{ + INSERT INTO \"users\" (\"id\", \"name\") VALUES ('1', 'david'), ('2', 'kir'), ('3', DEFAULT) + } + end + + it 'literals in multiple values are not escaped' do + table = Table.new(:users) + manager = Arel::InsertManager.new + manager.into table + + manager.columns << table[:name] + + manager.values = manager.create_values_list([ + [Arel.sql('*')], + [Arel.sql('DEFAULT')], + ]) + + manager.to_sql.must_be_like %{ + INSERT INTO \"users\" (\"name\") VALUES (*), (DEFAULT) + } + end + + it 'works with multiple single values' do + table = Table.new(:users) + manager = Arel::InsertManager.new + manager.into table + + manager.columns << table[:name] + + manager.values = manager.create_values_list([ + %w{david}, + %w{kir}, + [Arel.sql('DEFAULT')], + ]) + + manager.to_sql.must_be_like %{ + INSERT INTO \"users\" (\"name\") VALUES ('david'), ('kir'), (DEFAULT) + } + end + it "inserts false" do table = Table.new(:users) manager = Arel::InsertManager.new From f509ad3c72ed55d9fb35848664a771815aa4599b Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Mon, 5 Jun 2017 06:25:46 +0930 Subject: [PATCH 1458/1492] Test concurrency of visitor superclass fallback --- arel.gemspec | 1 + arel.gemspec.erb | 1 + test/visitors/test_dispatch_contamination.rb | 49 ++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/arel.gemspec b/arel.gemspec index 9cbf991ab7191..1e3fbfd49aab1 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -23,4 +23,5 @@ Gem::Specification.new do |s| s.add_development_dependency('minitest', '~> 5.4') s.add_development_dependency('rdoc', '~> 4.0') s.add_development_dependency('rake') + s.add_development_dependency('concurrent-ruby', '~> 1.0') end diff --git a/arel.gemspec.erb b/arel.gemspec.erb index f7ff99469cffe..58f07898d3314 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -23,4 +23,5 @@ Gem::Specification.new do |s| s.add_development_dependency('minitest', '~> 5.4') s.add_development_dependency('rdoc', '~> 4.0') s.add_development_dependency('rake') + s.add_development_dependency('concurrent-ruby', '~> 1.0') end diff --git a/test/visitors/test_dispatch_contamination.rb b/test/visitors/test_dispatch_contamination.rb index 6422a6dff38ff..71792594d6544 100644 --- a/test/visitors/test_dispatch_contamination.rb +++ b/test/visitors/test_dispatch_contamination.rb @@ -1,8 +1,42 @@ # frozen_string_literal: true require 'helper' +require 'concurrent' module Arel module Visitors + class DummyVisitor < Visitor + def initialize + super + @barrier = Concurrent::CyclicBarrier.new(2) + end + + def visit_Arel_Visitors_DummySuperNode node + 42 + end + + # This is terrible, but it's the only way to reliably reproduce + # the possible race where two threads attempt to correct the + # dispatch hash at the same time. + def send *args + super + rescue + # Both threads try (and fail) to dispatch to the subclass's name + @barrier.wait + raise + ensure + # Then one thread successfully completes (updating the dispatch + # table in the process) before the other finishes raising its + # exception. + Thread.current[:delay].wait if Thread.current[:delay] + end + end + + class DummySuperNode + end + + class DummySubNode < DummySuperNode + end + describe 'avoiding contamination between visitor dispatch tables' do before do @connection = Table.engine.connection @@ -17,6 +51,21 @@ module Visitors assert_equal "( TRUE UNION FALSE )", node.to_sql end + + it 'is threadsafe when implementing superclass fallback' do + visitor = DummyVisitor.new + main_thread_finished = Concurrent::Event.new + + racing_thread = Thread.new do + Thread.current[:delay] = main_thread_finished + visitor.accept DummySubNode.new + end + + assert_equal 42, visitor.accept(DummySubNode.new) + main_thread_finished.set + + assert_equal 42, racing_thread.value + end end end end From f031a3b9aa6a8093802e0188abce58e0b997078e Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 21 Jul 2017 08:02:58 -0400 Subject: [PATCH 1459/1492] Rename `Collectors::Bind` The "bind collector" does not actually collect bind params at all, it substitutes them out of the final AST, replacing them with a quoted value. --- arel.gemspec | 2 +- lib/arel/collectors/{bind.rb => substitute_binds.rb} | 2 +- lib/arel/visitors/bind_substitute.rb | 10 ---------- test/collectors/test_bind_collector.rb | 4 ++-- test/collectors/test_sql_string.rb | 1 - 5 files changed, 4 insertions(+), 15 deletions(-) rename lib/arel/collectors/{bind.rb => substitute_binds.rb} (95%) delete mode 100644 lib/arel/visitors/bind_substitute.rb diff --git a/arel.gemspec b/arel.gemspec index f0d2f6688768c..a1bc944f708e4 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_substitute.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/lib/arel/collectors/bind.rb b/lib/arel/collectors/substitute_binds.rb similarity index 95% rename from lib/arel/collectors/bind.rb rename to lib/arel/collectors/substitute_binds.rb index dfa79d1001a63..62589c44e8db1 100644 --- a/lib/arel/collectors/bind.rb +++ b/lib/arel/collectors/substitute_binds.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Collectors - class Bind + class SubstituteBinds def initialize @parts = [] end diff --git a/lib/arel/visitors/bind_substitute.rb b/lib/arel/visitors/bind_substitute.rb deleted file mode 100644 index 52c96b0d72497..0000000000000 --- a/lib/arel/visitors/bind_substitute.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true -module Arel - module Visitors - class BindSubstitute - def initialize delegate - @delegate = delegate - end - end - end -end diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_bind_collector.rb index 877aa20043f84..fef157782ba63 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_bind_collector.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true require 'helper' -require 'arel/collectors/bind' +require 'arel/collectors/substitute_binds' module Arel module Collectors @@ -12,7 +12,7 @@ def setup end def collect node - @visitor.accept(node, Collectors::Bind.new) + @visitor.accept(node, Collectors::SubstituteBinds.new) end def compile node diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index 92f1bf0fbac38..769c2e6d5334c 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true require 'helper' -require 'arel/collectors/bind' module Arel module Collectors From db1bb4e9a728a437d16f8bdb48c3b772c3e4edb0 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 21 Jul 2017 08:33:09 -0400 Subject: [PATCH 1460/1492] Add a value field `Nodes::BindParam` This is part of a greater refactoring to have the `BindParam` nodes hold onto their values. We want to generally keep the AST decoupled from what you're actually doing with those values, but ultimately the usage of `BindParam` is almost identical to how you'd use `Casted` or `Quoted`. Forcing consumers of Arel's API to maintain the bind values separately from the AST makes manipulating the AST essentially impossible, as you would need to perform a full walk of the AST to determine whether a given node contains bind parameters, and which value it maps to. By storing the value on the bind parameter directly, we can collect them in another AST pass (realistically it'll be part of the same pass that performs SQL construction for performance reasons). This will dramatically simplify AST manipulation for Rails or any other consumers that work with bind params. As part of this change I've removed the `BindVisitor`, which appears to be dead code, and had tests break from this change. --- arel.gemspec | 2 +- lib/arel/collectors/plain_string.rb | 2 +- lib/arel/nodes/bind_param.rb | 10 ++- lib/arel/visitors/bind_visitor.rb | 40 ------------ test/collectors/test_sql_string.rb | 2 +- ...r.rb => test_substitute_bind_collector.rb} | 10 +-- test/nodes/test_bind_param.rb | 11 +++- test/test_update_manager.rb | 2 +- test/visitors/test_bind_visitor.rb | 61 ------------------- test/visitors/test_dot.rb | 2 +- test/visitors/test_oracle.rb | 8 +-- test/visitors/test_oracle12.rb | 4 +- test/visitors/test_postgres.rb | 4 +- test/visitors/test_to_sql.rb | 4 +- 14 files changed, 37 insertions(+), 125 deletions(-) delete mode 100644 lib/arel/visitors/bind_visitor.rb rename test/collectors/{test_bind_collector.rb => test_substitute_bind_collector.rb} (89%) delete mode 100644 test/visitors/test_bind_visitor.rb diff --git a/arel.gemspec b/arel.gemspec index a1bc944f708e4..d953512bf375a 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/bind_visitor.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/lib/arel/collectors/plain_string.rb b/lib/arel/collectors/plain_string.rb index 1e8d2a2152d4e..4c8c15cc9c75b 100644 --- a/lib/arel/collectors/plain_string.rb +++ b/lib/arel/collectors/plain_string.rb @@ -3,7 +3,7 @@ module Arel module Collectors class PlainString def initialize - @str = ''.dup + @str = String.new end def value diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb index 9e297831cd3a8..d55f4c1c8e01b 100644 --- a/lib/arel/nodes/bind_param.rb +++ b/lib/arel/nodes/bind_param.rb @@ -2,8 +2,16 @@ module Arel module Nodes class BindParam < Node + attr_reader :value + + def initialize(value) + @value = value + super() + end + def ==(other) - other.is_a?(BindParam) + other.is_a?(BindParam) && + value == other.value end end end diff --git a/lib/arel/visitors/bind_visitor.rb b/lib/arel/visitors/bind_visitor.rb deleted file mode 100644 index 8a5570cf5cfbb..0000000000000 --- a/lib/arel/visitors/bind_visitor.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true -module Arel - module Visitors - module BindVisitor - def initialize target - @block = nil - super - end - - def accept node, collector, &block - @block = block if block_given? - super - end - - private - - def visit_Arel_Nodes_Assignment o, collector - if o.right.is_a? Arel::Nodes::BindParam - collector = visit o.left, collector - collector << " = " - visit o.right, collector - else - super - end - end - - def visit_Arel_Nodes_BindParam o, collector - if @block - val = @block.call - if String === val - collector << val - end - else - super - end - end - - end - end -end diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index 769c2e6d5334c..8651296ff843a 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -27,7 +27,7 @@ def ast_with_binds bv end def test_compile - bv = Nodes::BindParam.new + bv = Nodes::BindParam.new(nil) collector = collect ast_with_binds bv sql = collector.compile ["hello", "world"] diff --git a/test/collectors/test_bind_collector.rb b/test/collectors/test_substitute_bind_collector.rb similarity index 89% rename from test/collectors/test_bind_collector.rb rename to test/collectors/test_substitute_bind_collector.rb index fef157782ba63..adcaf98319b54 100644 --- a/test/collectors/test_bind_collector.rb +++ b/test/collectors/test_substitute_bind_collector.rb @@ -4,7 +4,7 @@ module Arel module Collectors - class TestBindCollector < Arel::Test + class TestSubstituteBindCollector < Arel::Test def setup @conn = FakeRecord::Base.new @visitor = Visitors::ToSql.new @conn.connection @@ -28,14 +28,14 @@ def ast_with_binds bv end def test_leaves_binds - node = Nodes::BindParam.new + node = Nodes::BindParam.new(nil) list = compile node assert_equal node, list.first assert_equal node.class, list.first.class end def test_adds_strings - bv = Nodes::BindParam.new + bv = Nodes::BindParam.new(nil) list = compile ast_with_binds bv assert_operator list.length, :>, 0 assert_equal bv, list.grep(Nodes::BindParam).first @@ -43,7 +43,7 @@ def test_adds_strings end def test_substitute_binds - bv = Nodes::BindParam.new + bv = Nodes::BindParam.new(nil) collector = collect ast_with_binds bv values = collector.value @@ -60,7 +60,7 @@ def test_substitute_binds end def test_compile - bv = Nodes::BindParam.new + bv = Nodes::BindParam.new(nil) collector = collect ast_with_binds bv sql = collector.compile ["hello", "world"] diff --git a/test/nodes/test_bind_param.rb b/test/nodes/test_bind_param.rb index 011de6410c3bb..482bb24f33380 100644 --- a/test/nodes/test_bind_param.rb +++ b/test/nodes/test_bind_param.rb @@ -4,12 +4,17 @@ module Arel module Nodes describe 'BindParam' do - it 'is equal to other bind params' do - BindParam.new.must_equal(BindParam.new) + it 'is equal to other bind params with the same value' do + BindParam.new(1).must_equal(BindParam.new(1)) + BindParam.new("foo").must_equal(BindParam.new("foo")) end it 'is not equal to other nodes' do - BindParam.new.wont_equal(Node.new) + BindParam.new(nil).wont_equal(Node.new) + end + + it 'is not equal to bind params with different values' do + BindParam.new(1).wont_equal(BindParam.new(2)) end end end diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 85abbf3875b12..187ded12f6efe 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -13,7 +13,7 @@ module Arel table = Table.new(:users) um = Arel::UpdateManager.new um.table table - um.set [[table[:name], Arel::Nodes::BindParam.new]] + um.set [[table[:name], Arel::Nodes::BindParam.new(nil)]] um.to_sql.must_be_like %{ UPDATE "users" SET "name" = ? } end diff --git a/test/visitors/test_bind_visitor.rb b/test/visitors/test_bind_visitor.rb deleted file mode 100644 index 3e0578a6a1835..0000000000000 --- a/test/visitors/test_bind_visitor.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true -require 'helper' -require 'arel/visitors/bind_visitor' -require 'support/fake_record' - -module Arel - module Visitors - class TestBindVisitor < Arel::Test - attr_reader :collector - - def setup - @collector = Collectors::SQLString.new - super - end - - ## - # Tests visit_Arel_Nodes_Assignment correctly - # substitutes binds with values from block - def test_assignment_binds_are_substituted - table = Table.new(:users) - um = Arel::UpdateManager.new - bp = Nodes::BindParam.new - um.set [[table[:name], bp]] - visitor = Class.new(Arel::Visitors::ToSql) { - include Arel::Visitors::BindVisitor - }.new Table.engine.connection - - assignment = um.ast.values[0] - actual = visitor.accept(assignment, collector) { - "replace" - } - assert actual - value = actual.value - assert_like "\"name\" = replace", value - end - - def test_visitor_yields_on_binds - visitor = Class.new(Arel::Visitors::ToSql) { - include Arel::Visitors::BindVisitor - }.new nil - - bp = Nodes::BindParam.new - called = false - visitor.accept(bp, collector) { called = true } - assert called - end - - def test_visitor_only_yields_on_binds - visitor = Class.new(Arel::Visitors::ToSql) { - include Arel::Visitors::BindVisitor - }.new(nil) - - bp = Arel.sql 'omg' - called = false - - visitor.accept(bp, collector) { called = true } - refute called - end - end - end -end diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 1d27d1a5cb1e7..8067ff5b49079 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -74,7 +74,7 @@ def test_named_function end def test_Arel_Nodes_BindParam - node = Arel::Nodes::BindParam.new + node = Arel::Nodes::BindParam.new(nil) collector = Collectors::PlainString.new assert_match '[label="Arel::Nodes::BindParam"]', @visitor.accept(node, collector).value end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index b1921f0cbc451..cdadec8b15c91 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -127,8 +127,8 @@ def compile node it 'creates a subquery when there is limit and offset with BindParams' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(Nodes::BindParam.new) - stmt.offset = Nodes::Offset.new(Nodes::BindParam.new) + stmt.limit = Nodes::Limit.new(Nodes::BindParam.new(nil)) + stmt.offset = Nodes::Offset.new(Nodes::BindParam.new(nil)) sql = compile stmt sql.must_be_like %{ SELECT * FROM ( @@ -184,8 +184,8 @@ def compile node describe "Nodes::BindParam" do it "increments each bind param" do - query = @table[:name].eq(Arel::Nodes::BindParam.new) - .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + query = @table[:name].eq(Arel::Nodes::BindParam.new(nil)) + .and(@table[:id].eq(Arel::Nodes::BindParam.new(nil))) compile(query).must_be_like %{ "users"."name" = :a1 AND "users"."id" = :a2 } diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index c908a51d4f3fc..a6bbfe3077897 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -48,8 +48,8 @@ def compile node describe "Nodes::BindParam" do it "increments each bind param" do - query = @table[:name].eq(Arel::Nodes::BindParam.new) - .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + query = @table[:name].eq(Arel::Nodes::BindParam.new(nil)) + .and(@table[:id].eq(Arel::Nodes::BindParam.new(nil))) compile(query).must_be_like %{ "users"."name" = :a1 AND "users"."id" = :a2 } diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 26cc72187173e..3b4fdc04279b8 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -176,8 +176,8 @@ def compile node describe "Nodes::BindParam" do it "increments each bind param" do - query = @table[:name].eq(Arel::Nodes::BindParam.new) - .and(@table[:id].eq(Arel::Nodes::BindParam.new)) + query = @table[:name].eq(Arel::Nodes::BindParam.new(nil)) + .and(@table[:id].eq(Arel::Nodes::BindParam.new(nil))) compile(query).must_be_like %{ "users"."name" = $1 AND "users"."id" = $2 } diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 31279b0ae2ab8..445d9c476c3ed 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -17,13 +17,13 @@ def compile node end it 'works with BindParams' do - node = Nodes::BindParam.new + node = Nodes::BindParam.new(nil) sql = compile node sql.must_be_like '?' end it 'does not quote BindParams used as part of a Values' do - bp = Nodes::BindParam.new + bp = Nodes::BindParam.new(nil) values = Nodes::Values.new([bp]) sql = compile values sql.must_be_like 'VALUES (?)' From 53521a9e39b9d8af4165d7703c36dc905f1f8f67 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 21 Jul 2017 09:11:47 -0400 Subject: [PATCH 1461/1492] Refactor `substitute_binds` to perform substitution immediately I'm honestly not sure if replacing bind params with their concrete values is something that belongs in Arel at all, as it's something that will need to be coupled to the quoting mechanism of the caller, and could just be accomplished by using `Quoted` instead. Still, with the new structure we can provide a much simpler API around substitution. The expectation of the quoter responding to `quote` is a reasonably minimal API. I originally used `DelegateClass` here, with the one line override of `add_bind`, but realized that we have some funky code going on where the collector returns the next collector to use (in practice `self` is always returned, and I don't see why we'd ever want to do this). Removing that would likely be worthwhile, but would be a larger refactoring --- lib/arel/collectors/substitute_binds.rb | 29 +++----- lib/arel/visitors/oracle.rb | 2 +- lib/arel/visitors/oracle12.rb | 2 +- lib/arel/visitors/postgresql.rb | 2 +- lib/arel/visitors/to_sql.rb | 2 +- .../test_substitute_bind_collector.rb | 66 ++++++------------- 6 files changed, 35 insertions(+), 68 deletions(-) diff --git a/lib/arel/collectors/substitute_binds.rb b/lib/arel/collectors/substitute_binds.rb index 62589c44e8db1..99d2215aaaf6c 100644 --- a/lib/arel/collectors/substitute_binds.rb +++ b/lib/arel/collectors/substitute_binds.rb @@ -2,36 +2,27 @@ module Arel module Collectors class SubstituteBinds - def initialize - @parts = [] + def initialize(quoter, delegate_collector) + @quoter = quoter + @delegate = delegate_collector end def << str - @parts << str + delegate << str self end def add_bind bind - @parts << bind - self + self << quoter.quote(bind) end - def value; @parts; end - - def substitute_binds bvs - bvs = bvs.dup - @parts.map do |val| - if Arel::Nodes::BindParam === val - bvs.shift - else - val - end - end + def value + delegate.value end - def compile bvs - substitute_binds(bvs).join - end + protected + + attr_reader :quoter, :delegate end end end diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 3b452836dbc8e..c1e41be66f975 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -145,7 +145,7 @@ def split_order_string(string) end def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o) { |i| ":a#{i}" } + collector.add_bind(o.value) { |i| ":a#{i}" } end end diff --git a/lib/arel/visitors/oracle12.rb b/lib/arel/visitors/oracle12.rb index ce90e994aea69..648047ae6184a 100644 --- a/lib/arel/visitors/oracle12.rb +++ b/lib/arel/visitors/oracle12.rb @@ -53,7 +53,7 @@ def visit_Arel_Nodes_UpdateStatement o, collector end def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o) { |i| ":a#{i}" } + collector.add_bind(o.value) { |i| ":a#{i}" } end end end diff --git a/lib/arel/visitors/postgresql.rb b/lib/arel/visitors/postgresql.rb index f0991a2f11222..2a935e4318c6b 100644 --- a/lib/arel/visitors/postgresql.rb +++ b/lib/arel/visitors/postgresql.rb @@ -46,7 +46,7 @@ def visit_Arel_Nodes_DistinctOn o, collector end def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o) { |i| "$#{i}" } + collector.add_bind(o.value) { |i| "$#{i}" } end def visit_Arel_Nodes_GroupingElement o, collector diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 3f1e390dccdcd..3ed80c8f06b02 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -737,7 +737,7 @@ def visit_Arel_Attributes_Attribute o, collector def literal o, collector; collector << o.to_s; end def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o) { "?" } + collector.add_bind(o.value) { "?" } end alias :visit_Arel_Nodes_SqlLiteral :literal diff --git a/test/collectors/test_substitute_bind_collector.rb b/test/collectors/test_substitute_bind_collector.rb index adcaf98319b54..de3e3655da9a2 100644 --- a/test/collectors/test_substitute_bind_collector.rb +++ b/test/collectors/test_substitute_bind_collector.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'helper' require 'arel/collectors/substitute_binds' +require 'arel/collectors/sql_string' module Arel module Collectors @@ -11,61 +12,36 @@ def setup super end - def collect node - @visitor.accept(node, Collectors::SubstituteBinds.new) - end - - def compile node - collect(node).value - end - - def ast_with_binds bv + def ast_with_binds table = Table.new(:users) manager = Arel::SelectManager.new table - manager.where(table[:age].eq(bv)) - manager.where(table[:name].eq(bv)) + manager.where(table[:age].eq(Nodes::BindParam.new("hello"))) + manager.where(table[:name].eq(Nodes::BindParam.new("world"))) manager.ast end - def test_leaves_binds - node = Nodes::BindParam.new(nil) - list = compile node - assert_equal node, list.first - assert_equal node.class, list.first.class - end - - def test_adds_strings - bv = Nodes::BindParam.new(nil) - list = compile ast_with_binds bv - assert_operator list.length, :>, 0 - assert_equal bv, list.grep(Nodes::BindParam).first - assert_equal bv.class, list.grep(Nodes::BindParam).first.class - end - - def test_substitute_binds - bv = Nodes::BindParam.new(nil) - collector = collect ast_with_binds bv - - values = collector.value - - offsets = values.map.with_index { |v,i| - [v,i] - }.find_all { |(v,_)| Nodes::BindParam === v }.map(&:last) - - list = collector.substitute_binds ["hello", "world"] - assert_equal "hello", list[offsets[0]] - assert_equal "world", list[offsets[1]] - - assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', list.join + def compile(node, quoter) + collector = Collectors::SubstituteBinds.new(quoter, Collectors::SQLString.new) + @visitor.accept(node, collector).value end def test_compile - bv = Nodes::BindParam.new(nil) - collector = collect ast_with_binds bv - - sql = collector.compile ["hello", "world"] + quoter = Object.new + def quoter.quote(val) + val.to_s + end + sql = compile(ast_with_binds, quoter) assert_equal 'SELECT FROM "users" WHERE "users"."age" = hello AND "users"."name" = world', sql end + + def test_quoting_is_delegated_to_quoter + quoter = Object.new + def quoter.quote(val) + val.inspect + end + sql = compile(ast_with_binds, quoter) + assert_equal 'SELECT FROM "users" WHERE "users"."age" = "hello" AND "users"."name" = "world"', sql + end end end end From 7ca5c37f484edebd169e4136331500d4b5c31cbe Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 21 Jul 2017 09:23:24 -0400 Subject: [PATCH 1462/1492] Ensure `ToSql` collector returns a UTF-8 string Switching from `''.dup` to `String.new` had the side effect of changing the encoding on Ruby 2.4 and later. Oddly, `String.new(encoding: Encoding::UTF_8)` is significantly slower than `''.dup`. This seems like a bug in Ruby, but not something we're going to address right now. A test has been added to ensure this regression doesn't occur again. --- lib/arel/collectors/plain_string.rb | 2 +- test/collectors/test_sql_string.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/arel/collectors/plain_string.rb b/lib/arel/collectors/plain_string.rb index 4c8c15cc9c75b..1e8d2a2152d4e 100644 --- a/lib/arel/collectors/plain_string.rb +++ b/lib/arel/collectors/plain_string.rb @@ -3,7 +3,7 @@ module Arel module Collectors class PlainString def initialize - @str = String.new + @str = ''.dup end def value diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index 8651296ff843a..debec8e9c9b45 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -33,6 +33,14 @@ def test_compile sql = collector.compile ["hello", "world"] assert_equal 'SELECT FROM "users" WHERE "users"."age" = ? AND "users"."name" = ?', sql end + + def test_returned_sql_uses_utf8_encoding + bv = Nodes::BindParam.new(nil) + collector = collect ast_with_binds bv + + sql = collector.compile ["hello", "world"] + assert_equal sql.encoding, Encoding::UTF_8 + end end end end From ecec50da1d709f9b442c88c2f53a8065e2ed6548 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 21 Jul 2017 09:41:07 -0400 Subject: [PATCH 1463/1492] Add a collector to grab the bind values off the AST Now that the bind values are being stored on the actual AST, we need a way to pull them off into the array that we were previously maintaining separately. This requires a full walk of the AST. This is an expensive operation, so I've also added a visitor for delegating to more than one visitor in a single pass. --- lib/arel/collectors/bind.rb | 24 ++++++++++++++++ lib/arel/collectors/composite.rb | 32 +++++++++++++++++++++ test/collectors/test_bind.rb | 40 ++++++++++++++++++++++++++ test/collectors/test_composite.rb | 47 +++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 lib/arel/collectors/bind.rb create mode 100644 lib/arel/collectors/composite.rb create mode 100644 test/collectors/test_bind.rb create mode 100644 test/collectors/test_composite.rb diff --git a/lib/arel/collectors/bind.rb b/lib/arel/collectors/bind.rb new file mode 100644 index 0000000000000..d816aed90d64e --- /dev/null +++ b/lib/arel/collectors/bind.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Arel + module Collectors + class Bind + def initialize + @binds = [] + end + + def << str + self + end + + def add_bind bind + @binds << bind + self + end + + def value + @binds + end + end + end +end diff --git a/lib/arel/collectors/composite.rb b/lib/arel/collectors/composite.rb new file mode 100644 index 0000000000000..4f6156fe27518 --- /dev/null +++ b/lib/arel/collectors/composite.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Arel + module Collectors + class Composite + def initialize(left, right) + @left = left + @right = right + end + + def << str + left << str + right << str + self + end + + def add_bind bind, &block + left.add_bind bind, &block + right.add_bind bind, &block + self + end + + def value + [left.value, right.value] + end + + protected + + attr_reader :left, :right + end + end +end diff --git a/test/collectors/test_bind.rb b/test/collectors/test_bind.rb new file mode 100644 index 0000000000000..6b4b651cf72fe --- /dev/null +++ b/test/collectors/test_bind.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +require 'helper' + +require 'arel/collectors/bind' + +module Arel + module Collectors + class TestBind < Arel::Test + def setup + @conn = FakeRecord::Base.new + @visitor = Visitors::ToSql.new @conn.connection + super + end + + def collect node + @visitor.accept(node, Collectors::Bind.new) + end + + def compile node + collect(node).value + end + + def ast_with_binds bvs + table = Table.new(:users) + manager = Arel::SelectManager.new table + manager.where(table[:age].eq(Nodes::BindParam.new(bvs.shift))) + manager.where(table[:name].eq(Nodes::BindParam.new(bvs.shift))) + manager.ast + end + + def test_compile_gathers_all_bind_params + binds = compile(ast_with_binds(["hello", "world"])) + assert_equal ["hello", "world"], binds + + binds = compile(ast_with_binds(["hello2", "world3"])) + assert_equal ["hello2", "world3"], binds + end + end + end +end diff --git a/test/collectors/test_composite.rb b/test/collectors/test_composite.rb new file mode 100644 index 0000000000000..b47c37db736be --- /dev/null +++ b/test/collectors/test_composite.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true +require 'helper' + +require 'arel/collectors/bind' +require 'arel/collectors/composite' +require 'arel/collectors/sql_string' + +module Arel + module Collectors + class TestComposite < Arel::Test + def setup + @conn = FakeRecord::Base.new + @visitor = Visitors::ToSql.new @conn.connection + super + end + + def collect node + sql_collector = Collectors::SQLString.new + bind_collector = Collectors::Bind.new + collector = Collectors::Composite.new(sql_collector, bind_collector) + @visitor.accept(node, collector) + end + + def compile node + collect(node).value + end + + def ast_with_binds bvs + table = Table.new(:users) + manager = Arel::SelectManager.new table + manager.where(table[:age].eq(Nodes::BindParam.new(bvs.shift))) + manager.where(table[:name].eq(Nodes::BindParam.new(bvs.shift))) + manager.ast + end + + def test_composite_collector_performs_multiple_collections_at_once + sql, binds = compile(ast_with_binds(["hello", "world"])) + assert_equal 'SELECT FROM "users" WHERE "users"."age" = ? AND "users"."name" = ?', sql + assert_equal ["hello", "world"], binds + + sql, binds = compile(ast_with_binds(["hello2", "world3"])) + assert_equal 'SELECT FROM "users" WHERE "users"."age" = ? AND "users"."name" = ?', sql + assert_equal ["hello2", "world3"], binds + end + end + end +end From 7a29220c689feb0581e21d5324b85fc2f201ac5e Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 24 Jul 2017 08:04:56 -0400 Subject: [PATCH 1464/1492] Adjust `BindParam` as needed for AR We need `value` to have a writer for `StatementCache` to work when prepared statements are disabled. This is something I'd like to revert eventually, either by disabling that form of caching in that case or re-introducing something like the old `Bind` collector. The addition of `nil?` is to make `IS NULL` be inserted correctly, similar to what we already do with quoted and casted nodes --- lib/arel/nodes/bind_param.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb index d55f4c1c8e01b..225fcc4798160 100644 --- a/lib/arel/nodes/bind_param.rb +++ b/lib/arel/nodes/bind_param.rb @@ -2,7 +2,7 @@ module Arel module Nodes class BindParam < Node - attr_reader :value + attr_accessor :value def initialize(value) @value = value @@ -13,6 +13,10 @@ def ==(other) other.is_a?(BindParam) && value == other.value end + + def nil? + value.nil? + end end end end From bfb770dbcc8432b8d4c1824be0fb2b1ab1ce5d68 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 24 Jul 2017 09:08:24 -0400 Subject: [PATCH 1465/1492] Fix test failures --- test/collectors/test_sql_string.rb | 4 ++-- test/test_update_manager.rb | 2 +- test/visitors/test_dot.rb | 2 +- test/visitors/test_oracle.rb | 8 ++++---- test/visitors/test_oracle12.rb | 4 ++-- test/visitors/test_postgres.rb | 4 ++-- test/visitors/test_to_sql.rb | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/collectors/test_sql_string.rb b/test/collectors/test_sql_string.rb index debec8e9c9b45..0185f2ab1738a 100644 --- a/test/collectors/test_sql_string.rb +++ b/test/collectors/test_sql_string.rb @@ -27,7 +27,7 @@ def ast_with_binds bv end def test_compile - bv = Nodes::BindParam.new(nil) + bv = Nodes::BindParam.new(1) collector = collect ast_with_binds bv sql = collector.compile ["hello", "world"] @@ -35,7 +35,7 @@ def test_compile end def test_returned_sql_uses_utf8_encoding - bv = Nodes::BindParam.new(nil) + bv = Nodes::BindParam.new(1) collector = collect ast_with_binds bv sql = collector.compile ["hello", "world"] diff --git a/test/test_update_manager.rb b/test/test_update_manager.rb index 187ded12f6efe..4a373d1ff7320 100644 --- a/test/test_update_manager.rb +++ b/test/test_update_manager.rb @@ -13,7 +13,7 @@ module Arel table = Table.new(:users) um = Arel::UpdateManager.new um.table table - um.set [[table[:name], Arel::Nodes::BindParam.new(nil)]] + um.set [[table[:name], Arel::Nodes::BindParam.new(1)]] um.to_sql.must_be_like %{ UPDATE "users" SET "name" = ? } end diff --git a/test/visitors/test_dot.rb b/test/visitors/test_dot.rb index 8067ff5b49079..3c4a038116c87 100644 --- a/test/visitors/test_dot.rb +++ b/test/visitors/test_dot.rb @@ -74,7 +74,7 @@ def test_named_function end def test_Arel_Nodes_BindParam - node = Arel::Nodes::BindParam.new(nil) + node = Arel::Nodes::BindParam.new(1) collector = Collectors::PlainString.new assert_match '[label="Arel::Nodes::BindParam"]', @visitor.accept(node, collector).value end diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index cdadec8b15c91..603d0f1184d39 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -127,8 +127,8 @@ def compile node it 'creates a subquery when there is limit and offset with BindParams' do stmt = Nodes::SelectStatement.new - stmt.limit = Nodes::Limit.new(Nodes::BindParam.new(nil)) - stmt.offset = Nodes::Offset.new(Nodes::BindParam.new(nil)) + stmt.limit = Nodes::Limit.new(Nodes::BindParam.new(1)) + stmt.offset = Nodes::Offset.new(Nodes::BindParam.new(1)) sql = compile stmt sql.must_be_like %{ SELECT * FROM ( @@ -184,8 +184,8 @@ def compile node describe "Nodes::BindParam" do it "increments each bind param" do - query = @table[:name].eq(Arel::Nodes::BindParam.new(nil)) - .and(@table[:id].eq(Arel::Nodes::BindParam.new(nil))) + query = @table[:name].eq(Arel::Nodes::BindParam.new(1)) + .and(@table[:id].eq(Arel::Nodes::BindParam.new(1))) compile(query).must_be_like %{ "users"."name" = :a1 AND "users"."id" = :a2 } diff --git a/test/visitors/test_oracle12.rb b/test/visitors/test_oracle12.rb index a6bbfe3077897..62658bc595dd9 100644 --- a/test/visitors/test_oracle12.rb +++ b/test/visitors/test_oracle12.rb @@ -48,8 +48,8 @@ def compile node describe "Nodes::BindParam" do it "increments each bind param" do - query = @table[:name].eq(Arel::Nodes::BindParam.new(nil)) - .and(@table[:id].eq(Arel::Nodes::BindParam.new(nil))) + query = @table[:name].eq(Arel::Nodes::BindParam.new(1)) + .and(@table[:id].eq(Arel::Nodes::BindParam.new(1))) compile(query).must_be_like %{ "users"."name" = :a1 AND "users"."id" = :a2 } diff --git a/test/visitors/test_postgres.rb b/test/visitors/test_postgres.rb index 3b4fdc04279b8..beae117ef54b8 100644 --- a/test/visitors/test_postgres.rb +++ b/test/visitors/test_postgres.rb @@ -176,8 +176,8 @@ def compile node describe "Nodes::BindParam" do it "increments each bind param" do - query = @table[:name].eq(Arel::Nodes::BindParam.new(nil)) - .and(@table[:id].eq(Arel::Nodes::BindParam.new(nil))) + query = @table[:name].eq(Arel::Nodes::BindParam.new(1)) + .and(@table[:id].eq(Arel::Nodes::BindParam.new(1))) compile(query).must_be_like %{ "users"."name" = $1 AND "users"."id" = $2 } diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 445d9c476c3ed..e95c0666b4e20 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -17,13 +17,13 @@ def compile node end it 'works with BindParams' do - node = Nodes::BindParam.new(nil) + node = Nodes::BindParam.new(1) sql = compile node sql.must_be_like '?' end it 'does not quote BindParams used as part of a Values' do - bp = Nodes::BindParam.new(nil) + bp = Nodes::BindParam.new(1) values = Nodes::Values.new([bp]) sql = compile values sql.must_be_like 'VALUES (?)' From e6b707fe75b756a89ec08c9f2368697452f30c68 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Tue, 25 Jul 2017 18:16:21 +0900 Subject: [PATCH 1466/1492] Remove unused `bind_values` Since https://github.com/rails/rails/commit/213796f, `bind_values` is no longer used from Active Record. --- lib/arel/tree_manager.rb | 5 +---- test/test_select_manager.rb | 7 ------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index a8dbb4c87a450..054244240419c 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -7,11 +7,8 @@ class TreeManager attr_reader :ast - attr_accessor :bind_values - def initialize - @ctx = nil - @bind_values = [] + @ctx = nil end def to_dot diff --git a/test/test_select_manager.rb b/test/test_select_manager.rb index 9a49fbcd566ee..cc7452c239f70 100644 --- a/test/test_select_manager.rb +++ b/test/test_select_manager.rb @@ -10,13 +10,6 @@ def test_join_sources assert_equal "SELECT FROM 'foo'", manager.to_sql end - def test_manager_stores_bind_values - manager = Arel::SelectManager.new - assert_equal [], manager.bind_values - manager.bind_values = [1] - assert_equal [1], manager.bind_values - end - describe 'backwards compatibility' do describe 'project' do it 'accepts symbols as sql literals' do From 6d225a9870aea1fa25ab71774206d08d5b216355 Mon Sep 17 00:00:00 2001 From: Maxime Lapointe Date: Tue, 25 Jul 2017 09:12:11 -0400 Subject: [PATCH 1467/1492] Add missing hash, eql?, == to various node classes Some of the nodes classes are missing either one or many of the common comparison methods #hash, #eql? and #==. This makes comparision and working with the ast sometimes painful, as equality or operations likes array differences (which uses a hash behind the scene) produces unexpected results. A test has been added that ensures that every descendants of Node: * have all 3 methods * that all 3 methods were defined from the same class * that the class defining all 3 is also a descendant of Node, to avoid the default ones that rely on identity only --- lib/arel/nodes/bind_param.rb | 7 ++++++- lib/arel/nodes/false.rb | 1 + lib/arel/nodes/function.rb | 2 ++ lib/arel/nodes/terminal.rb | 1 + lib/arel/nodes/true.rb | 1 + lib/arel/nodes/values_list.rb | 10 ++++++++++ lib/arel/nodes/window.rb | 1 + test/test_nodes.rb | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 test/test_nodes.rb diff --git a/lib/arel/nodes/bind_param.rb b/lib/arel/nodes/bind_param.rb index 225fcc4798160..efa4f452d43a5 100644 --- a/lib/arel/nodes/bind_param.rb +++ b/lib/arel/nodes/bind_param.rb @@ -9,10 +9,15 @@ def initialize(value) super() end - def ==(other) + def hash + [self.class, self.value].hash + end + + def eql?(other) other.is_a?(BindParam) && value == other.value end + alias :== :eql? def nil? value.nil? diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb index 26b4e5db97a7b..fb821dd52290d 100644 --- a/lib/arel/nodes/false.rb +++ b/lib/arel/nodes/false.rb @@ -9,6 +9,7 @@ def hash def eql? other self.class == other.class end + alias :== :eql? end end end diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index 28a394e9f3921..b2b89ee9ffd2f 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -29,6 +29,8 @@ def eql? other self.alias == other.alias && self.distinct == other.distinct end + alias :== :eql? + end %w{ diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb index 6f60fe006fdc9..421f039904c9a 100644 --- a/lib/arel/nodes/terminal.rb +++ b/lib/arel/nodes/terminal.rb @@ -9,6 +9,7 @@ def hash def eql? other self.class == other.class end + alias :== :eql? end end end diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb index 796b5b9348d80..bb9d8c1414cd5 100644 --- a/lib/arel/nodes/true.rb +++ b/lib/arel/nodes/true.rb @@ -9,6 +9,7 @@ def hash def eql? other self.class == other.class end + alias :== :eql? end end end diff --git a/lib/arel/nodes/values_list.rb b/lib/arel/nodes/values_list.rb index b39aaa14654b3..89cea1790d0d4 100644 --- a/lib/arel/nodes/values_list.rb +++ b/lib/arel/nodes/values_list.rb @@ -8,6 +8,16 @@ def initialize(rows) @rows = rows super() end + + def hash + @rows.hash + end + + def eql? other + self.class == other.class && + self.rows == other.rows + end + alias :== :eql? end end end diff --git a/lib/arel/nodes/window.rb b/lib/arel/nodes/window.rb index 535c0c6238ada..23a005daba2f0 100644 --- a/lib/arel/nodes/window.rb +++ b/lib/arel/nodes/window.rb @@ -107,6 +107,7 @@ def hash def eql? other self.class == other.class end + alias :== :eql? end class Preceding < Unary diff --git a/test/test_nodes.rb b/test/test_nodes.rb new file mode 100644 index 0000000000000..bf0082396d33f --- /dev/null +++ b/test/test_nodes.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +require 'helper' + +module Arel + module Nodes + class TestNodes < Minitest::Test + def test_every_arel_nodes_have_hash_eql_eqeq_from_same_class + # #descendants code from activesupport + node_descendants = [] + ObjectSpace.each_object(Arel::Nodes::Node.singleton_class) do |k| + next if k.respond_to?(:singleton_class?) && k.singleton_class? + node_descendants.unshift k unless k == self + end + node_descendants.delete(Arel::Nodes::Node) + + bad_node_descendants = node_descendants.reject do |subnode| + eqeq_owner = subnode.instance_method(:==).owner + eql_owner = subnode.instance_method(:eql?).owner + hash_owner = subnode.instance_method(:hash).owner + + eqeq_owner < Arel::Nodes::Node && + eqeq_owner == eql_owner && + eqeq_owner == hash_owner + end + + problem_msg = 'Some subclasses of Arel::Nodes::Node do not have a' \ + ' #== or #eql? or #hash defined from the same class as the others' + assert_empty bad_node_descendants, problem_msg + end + + + end + end +end From f4227bf20a16a1d688afc24cf0038e2f98905dd4 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 25 Jul 2017 13:19:01 -0400 Subject: [PATCH 1468/1492] Change the verison to 9.0.0.alpha --- arel.gemspec | 2 +- lib/arel.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index d953512bf375a..450afe9e7cc75 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/composite.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/values_list.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/lib/arel.rb b/lib/arel.rb index f0d2bdce7894f..80cc95985f944 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -24,7 +24,7 @@ require 'arel/nodes' module Arel - VERSION = '8.0.0' + VERSION = '9.0.0.alpha' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From f25ee14a470d7505098fd3fdae04ddcffe70f2e2 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Tue, 25 Jul 2017 19:00:12 +0000 Subject: [PATCH 1469/1492] Address `undefined method `value_for_database'` in Oracle visitor Here `offset` is bound twice. It used to be `:b1` appeared twice. This commit changes the second `offset` name changed from `:b1` to `:b3` which should not affect the actual bind values for offset. --- lib/arel/visitors/oracle.rb | 7 ++++--- test/visitors/test_oracle.rb | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index c1e41be66f975..95c37eba6b802 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -31,10 +31,11 @@ def visit_Arel_Nodes_SelectStatement o, collector if offset.expr.is_a? Nodes::BindParam offset_bind = nil collector << ') raw_sql_ WHERE rownum <= (' - collector.add_bind(offset.expr) { |i| offset_bind = ":a#{i}" } + collector = visit offset.expr, collector collector << ' + ' - collector.add_bind(limit) { |i| ":a#{i}" } - collector << ") ) WHERE raw_rnum_ > #{offset_bind}" + collector = visit limit, collector + collector << ") ) WHERE raw_rnum_ > " + collector = visit offset.expr, collector return collector else collector << ") raw_sql_ diff --git a/test/visitors/test_oracle.rb b/test/visitors/test_oracle.rb index 603d0f1184d39..fce6606d35a35 100644 --- a/test/visitors/test_oracle.rb +++ b/test/visitors/test_oracle.rb @@ -136,7 +136,7 @@ def compile node FROM (SELECT ) raw_sql_ WHERE rownum <= (:a1 + :a2) ) - WHERE raw_rnum_ > :a1 + WHERE raw_rnum_ > :a3 } end From 8a77c667f54a023525505cabf271c8ae125d50a1 Mon Sep 17 00:00:00 2001 From: Koji Mikami Date: Thu, 27 Jul 2017 19:15:10 +0900 Subject: [PATCH 1470/1492] CI against 2.4.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 32aeb83ea9aa4..b35bec1c30b46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ rvm: - 2.1 - 2.2.5 - 2.3.1 - - 2.4.0 + - 2.4.1 - ruby-head matrix: fast_finish: true From f2d66cddce16e6fb6a91085f01e79044dd5f7db7 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Sat, 29 Jul 2017 20:08:30 +0530 Subject: [PATCH 1471/1492] Remove Unused variable - offset_bind Fixes warning in Rails tests: ``` /home/travis/build/rails/rails/vendor/bundle/ruby/2.4.0/bundler/gems/arel-b9ca36f09d5e/lib/arel/visitors/oracle.rb:32: warning: assigned but unused variable - offset_bind `` --- lib/arel/visitors/oracle.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/arel/visitors/oracle.rb b/lib/arel/visitors/oracle.rb index 95c37eba6b802..d4749bbae327b 100644 --- a/lib/arel/visitors/oracle.rb +++ b/lib/arel/visitors/oracle.rb @@ -29,7 +29,6 @@ def visit_Arel_Nodes_SelectStatement o, collector collector = super(o, collector) if offset.expr.is_a? Nodes::BindParam - offset_bind = nil collector << ') raw_sql_ WHERE rownum <= (' collector = visit offset.expr, collector collector << ' + ' From e0ecf06dad4de3fac543dfee5ebb98d42acb46f2 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Wed, 9 Aug 2017 17:22:55 +0900 Subject: [PATCH 1472/1492] Remove encoding utf-8 magic comment --- arel.gemspec | 1 - arel.gemspec.erb | 1 - lib/arel/collectors/sql_string.rb | 1 - 3 files changed, 3 deletions(-) diff --git a/arel.gemspec b/arel.gemspec index 450afe9e7cc75..2ca136deec2db 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -1,4 +1,3 @@ -# # -*- encoding: utf-8 -*- # frozen_string_literal: true $:.push File.expand_path("../lib", __FILE__) require "arel" diff --git a/arel.gemspec.erb b/arel.gemspec.erb index 58f07898d3314..15c5a3d75823f 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -1,4 +1,3 @@ -# # -*- encoding: utf-8 -*- # frozen_string_literal: true $:.push File.expand_path("../lib", __FILE__) require "arel" diff --git a/lib/arel/collectors/sql_string.rb b/lib/arel/collectors/sql_string.rb index 5f421173312b2..bcb941f6d4372 100644 --- a/lib/arel/collectors/sql_string.rb +++ b/lib/arel/collectors/sql_string.rb @@ -1,4 +1,3 @@ -# encoding: utf-8 # frozen_string_literal: true require 'arel/collectors/plain_string' From 2c450acb5e575bf3ae3c84300acca8a6cc932db0 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Mon, 14 Aug 2017 02:14:18 +0900 Subject: [PATCH 1473/1492] Add required_ruby_version to gemspec --- arel.gemspec | 1 + arel.gemspec.erb | 1 + 2 files changed, 2 insertions(+) diff --git a/arel.gemspec b/arel.gemspec index 2ca136deec2db..f914d1a5ca512 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" s.license = %q{MIT} + s.required_ruby_version = ">= 2.2.2" s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] diff --git a/arel.gemspec.erb b/arel.gemspec.erb index 15c5a3d75823f..4698e8bae7959 100644 --- a/arel.gemspec.erb +++ b/arel.gemspec.erb @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation." s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby" s.license = %q{MIT} + s.required_ruby_version = ">= 2.2.2" s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] From 04c79c9743b5b14607791a7b6eac5e94fcfa2b9e Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Mon, 14 Aug 2017 20:50:31 +0900 Subject: [PATCH 1474/1492] Update travis.yml travis.yml made it follow Rails (AR). The summary is as follows. - Drop MRI 2.2.1 or lower and updated with latest MRI versions - Drop rbx-2. This build has failed since before - Update JRuby version to 9.1.12.0 --- .travis.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index b35bec1c30b46..352e12793ad1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,23 +8,18 @@ env: global: - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - - rbx-2 - - jruby-9.0.5.0 - - jruby-head - - 2.0.0 - - 2.1 - - 2.2.5 - - 2.3.1 + - 2.2.7 + - 2.3.4 - 2.4.1 - ruby-head + - jruby-9.1.12.0 + - jruby-head matrix: fast_finish: true allow_failures: - - rvm: jruby-9.0.5.0 - - rvm: jruby-head - rvm: ruby-head + - rvm: jruby-9.1.12.0 - rvm: jruby-head - - rvm: rbx-2 bundler_args: --jobs 3 --retry 3 notifications: email: false From 95dce3c7169f29a6636919b9abb0c33937cbbcb6 Mon Sep 17 00:00:00 2001 From: Akira Matsuda Date: Fri, 1 Sep 2017 17:50:50 +0900 Subject: [PATCH 1475/1492] Unused variables --- lib/arel/visitors/informix.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/arel/visitors/informix.rb b/lib/arel/visitors/informix.rb index b53ab18b82233..44b18b550ef59 100644 --- a/lib/arel/visitors/informix.rb +++ b/lib/arel/visitors/informix.rb @@ -18,9 +18,7 @@ def visit_Arel_Nodes_SelectStatement o, collector end def visit_Arel_Nodes_SelectCore o, collector collector = inject_join o.projections, collector, ", " - froms = false if o.source && !o.source.empty? - froms = true collector << " FROM " collector = visit o.source, collector end From 88336b736b1de9818400239a7ad0b4e5e3056ba8 Mon Sep 17 00:00:00 2001 From: Yoshiyuki Hirano Date: Fri, 15 Sep 2017 12:52:25 +0900 Subject: [PATCH 1476/1492] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 352e12793ad1a..4e1bca45c7103 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,9 @@ env: global: - JRUBY_OPTS='--dev -J-Xmx1024M' rvm: - - 2.2.7 - - 2.3.4 - - 2.4.1 + - 2.2.8 + - 2.3.5 + - 2.4.2 - ruby-head - jruby-9.1.12.0 - jruby-head From 024c6f35834ecae5dfee4bae4fb96396ad1520ef Mon Sep 17 00:00:00 2001 From: Jan Graichen Date: Tue, 19 Sep 2017 23:48:17 +0200 Subject: [PATCH 1477/1492] Support BindParams in subqueries When an Arel AST contains a SelectManager as a component, e.g. as a CTE expression, the SelectManager is converted to SQL with `#to_sql`. This uses a new collector that leads to invalid expressions when using bind parameters. For example, when generating PostgreSQL queries, the bind parameter number starts from one again. When using the SubstituteBinds collector, binds in the subquery are not substituted. This commit changes the ToSql visitor to visit the SelectManager ast itself. --- lib/arel/visitors/to_sql.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 3ed80c8f06b02..6aaaa19e6e290 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -427,7 +427,8 @@ def visit_Arel_Nodes_Grouping o, collector end def visit_Arel_SelectManager o, collector - collector << "(#{o.to_sql.rstrip})" + collector << '(' + visit(o.ast, collector) << ')' end def visit_Arel_Nodes_Ascending o, collector From b416fca38780fb3305d836944ff8880f7097b4b3 Mon Sep 17 00:00:00 2001 From: James Coleman Date: Fri, 29 Sep 2017 16:29:50 -0500 Subject: [PATCH 1478/1492] Type-castable attributes should not try to cast SqlLiteral nodes --- lib/arel/nodes/casted.rb | 2 +- test/attributes/test_attribute.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb index 290e4dd38c16e..1d7385d01b9e3 100644 --- a/lib/arel/nodes/casted.rb +++ b/lib/arel/nodes/casted.rb @@ -30,7 +30,7 @@ def nil?; val.nil?; end def self.build_quoted other, attribute = nil case other - when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted, Arel::Nodes::SqlLiteral other else case attribute diff --git a/test/attributes/test_attribute.rb b/test/attributes/test_attribute.rb index 2b971ce54ae46..a67ef53a4cf82 100644 --- a/test/attributes/test_attribute.rb +++ b/test/attributes/test_attribute.rb @@ -997,6 +997,18 @@ def fake_caster.type_cast_for_database(attr_name, value) assert table.able_to_type_cast? condition.to_sql.must_equal %("foo"."id" = 1 AND "foo"."other_id" = '2') end + + it 'does not type cast SqlLiteral nodes' do + fake_caster = Object.new + def fake_caster.type_cast_for_database(attr_name, value) + value.to_i + end + table = Table.new(:foo, type_caster: fake_caster) + condition = table["id"].eq(Arel.sql("(select 1)")) + + assert table.able_to_type_cast? + condition.to_sql.must_equal %("foo"."id" = (select 1)) + end end end end From 27a7af81bd274f8036f42638acdb47e85e76c5aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylvain=20Ab=C3=A9lard?= Date: Sun, 15 Oct 2017 20:30:27 +0200 Subject: [PATCH 1479/1492] Update README.md * s/crazy/advanced/ to avoid ableist words * last sections didn't have titles to separate topics I have written a bit more examples of "less trivial" Arel code here, perhaps we can add some of that here: https://github.com/rstacruz/cheatsheets/pull/92/files --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af768361ab5b8..065bfea26c72c 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ users.project(users[:age].average.as("mean_age")) # => SELECT AVG(users.age) AS mean_age FROM users ``` -### The Crazy Features +### The Advanced 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). @@ -215,6 +215,7 @@ products. #### Complex Joins +##### Alias Where Arel really shines is 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: ```ruby @@ -240,6 +241,7 @@ comments_with_replies = \ This will return the reply for the first comment. +##### CTE [Common Table Expressions (CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: Create a `CTE` @@ -262,6 +264,7 @@ users. # FROM users INNER JOIN cte_table ON users.id = cte_table.user_id ``` +#### Write SQL strings When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: ```ruby From 1aeefa68bc93fddfba1d6549bb870d3829dfe0e2 Mon Sep 17 00:00:00 2001 From: Kevin Deisz Date: Fri, 27 Oct 2017 10:42:09 -0400 Subject: [PATCH 1480/1492] Allow count nodes to have math functions --- lib/arel/nodes/count.rb | 2 ++ test/nodes/test_count.rb | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/arel/nodes/count.rb b/lib/arel/nodes/count.rb index a7c6236a223af..4dd9be453fa8e 100644 --- a/lib/arel/nodes/count.rb +++ b/lib/arel/nodes/count.rb @@ -2,6 +2,8 @@ module Arel module Nodes class Count < Arel::Nodes::Function + include Math + def initialize expr, distinct = false, aliaz = nil super(expr, aliaz) @distinct = distinct diff --git a/test/nodes/test_count.rb b/test/nodes/test_count.rb index 85e93b192709a..29883df681943 100644 --- a/test/nodes/test_count.rb +++ b/test/nodes/test_count.rb @@ -31,4 +31,13 @@ assert_equal 2, array.uniq.size end end + + describe 'math' do + it 'allows mathematical functions' do + table = Arel::Table.new :users + (table[:id].count + 1).to_sql.must_be_like %{ + (COUNT("users"."id") + 1) + } + end + end end From 8f1db57f2d0f7d2cbb407f2c141dfd61ba8a599b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 14 Nov 2017 14:05:17 -0500 Subject: [PATCH 1481/1492] Prepare for 9.0.0 --- History.txt | 6 ++++++ lib/arel.rb | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.txt b/History.txt index 6985da4f49e52..11ca9e865921d 100644 --- a/History.txt +++ b/History.txt @@ -1,3 +1,9 @@ +=== 9.0.0 / 2017-11-14 + +* Enhancements + * `InsertManager#insert` is now chainable + * Support multiple inserts + === 8.0.0 / 2017-02-21 * Enhancements diff --git a/lib/arel.rb b/lib/arel.rb index 80cc95985f944..e7c6fc7fd34e2 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -24,7 +24,7 @@ require 'arel/nodes' module Arel - VERSION = '9.0.0.alpha' + VERSION = '9.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql From 2d78e3a160068d7a024e30b2178084d16cea9807 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Tue, 4 Oct 2016 18:28:49 -0400 Subject: [PATCH 1482/1492] Introduce NodeExpression as parent of scalar nodes SQL is very powerful. Many nodes can be used as a sub expression or query. grouping all of these possible nodes together --- lib/arel/nodes.rb | 1 + lib/arel/nodes/binary.rb | 2 +- lib/arel/nodes/case.rb | 4 ---- lib/arel/nodes/casted.rb | 2 +- lib/arel/nodes/extract.rb | 3 --- lib/arel/nodes/false.rb | 2 +- lib/arel/nodes/function.rb | 4 +--- lib/arel/nodes/grouping.rb | 1 - lib/arel/nodes/node_expression.rb | 11 +++++++++++ lib/arel/nodes/select_statement.rb | 2 +- lib/arel/nodes/terminal.rb | 2 +- lib/arel/nodes/true.rb | 2 +- lib/arel/nodes/unary.rb | 2 +- lib/arel/nodes/unary_operation.rb | 8 +------- test/test_nodes.rb | 1 + 15 files changed, 22 insertions(+), 25 deletions(-) create mode 100644 lib/arel/nodes/node_expression.rb diff --git a/lib/arel/nodes.rb b/lib/arel/nodes.rb index bb8ad6500b8ea..8c6572dd6af84 100644 --- a/lib/arel/nodes.rb +++ b/lib/arel/nodes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true # node require 'arel/nodes/node' +require 'arel/nodes/node_expression' require 'arel/nodes/select_statement' require 'arel/nodes/select_core' require 'arel/nodes/insert_statement' diff --git a/lib/arel/nodes/binary.rb b/lib/arel/nodes/binary.rb index 3001788774889..a86d4e4696508 100644 --- a/lib/arel/nodes/binary.rb +++ b/lib/arel/nodes/binary.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class Binary < Arel::Nodes::Node + class Binary < Arel::Nodes::NodeExpression attr_accessor :left, :right def initialize left, right diff --git a/lib/arel/nodes/case.rb b/lib/arel/nodes/case.rb index 1edca400018b7..50ea1e0be2c03 100644 --- a/lib/arel/nodes/case.rb +++ b/lib/arel/nodes/case.rb @@ -2,10 +2,6 @@ module Arel module Nodes class Case < Arel::Nodes::Node - include Arel::OrderPredications - include Arel::Predications - include Arel::AliasPredication - attr_accessor :case, :conditions, :default def initialize expression = nil, default = nil diff --git a/lib/arel/nodes/casted.rb b/lib/arel/nodes/casted.rb index 1d7385d01b9e3..f945063dd2923 100644 --- a/lib/arel/nodes/casted.rb +++ b/lib/arel/nodes/casted.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class Casted < Arel::Nodes::Node # :nodoc: + class Casted < Arel::Nodes::NodeExpression # :nodoc: attr_reader :val, :attribute def initialize val, attribute @val = val diff --git a/lib/arel/nodes/extract.rb b/lib/arel/nodes/extract.rb index 4e797b6770769..fdf3004c6ae2a 100644 --- a/lib/arel/nodes/extract.rb +++ b/lib/arel/nodes/extract.rb @@ -2,9 +2,6 @@ module Arel module Nodes class Extract < Arel::Nodes::Unary - include Arel::AliasPredication - include Arel::Predications - attr_accessor :field def initialize expr, field diff --git a/lib/arel/nodes/false.rb b/lib/arel/nodes/false.rb index fb821dd52290d..58132a2f90124 100644 --- a/lib/arel/nodes/false.rb +++ b/lib/arel/nodes/false.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class False < Arel::Nodes::Node + class False < Arel::Nodes::NodeExpression def hash self.class.hash end diff --git a/lib/arel/nodes/function.rb b/lib/arel/nodes/function.rb index b2b89ee9ffd2f..b3bf8f3e51c62 100644 --- a/lib/arel/nodes/function.rb +++ b/lib/arel/nodes/function.rb @@ -1,10 +1,8 @@ # frozen_string_literal: true module Arel module Nodes - class Function < Arel::Nodes::Node - include Arel::Predications + class Function < Arel::Nodes::NodeExpression include Arel::WindowPredications - include Arel::OrderPredications attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil diff --git a/lib/arel/nodes/grouping.rb b/lib/arel/nodes/grouping.rb index 16911eb3b62d9..ffe66654ce9c1 100644 --- a/lib/arel/nodes/grouping.rb +++ b/lib/arel/nodes/grouping.rb @@ -2,7 +2,6 @@ module Arel module Nodes class Grouping < Unary - include Arel::Predications end end end diff --git a/lib/arel/nodes/node_expression.rb b/lib/arel/nodes/node_expression.rb new file mode 100644 index 0000000000000..c4d4c8f428a0e --- /dev/null +++ b/lib/arel/nodes/node_expression.rb @@ -0,0 +1,11 @@ +module Arel + module Nodes + class NodeExpression < Arel::Nodes::Node + include Arel::Expressions + include Arel::Predications + include Arel::AliasPredication + include Arel::OrderPredications + include Arel::Math + end + end +end diff --git a/lib/arel/nodes/select_statement.rb b/lib/arel/nodes/select_statement.rb index 641a08405df0f..79176d4be5cea 100644 --- a/lib/arel/nodes/select_statement.rb +++ b/lib/arel/nodes/select_statement.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class SelectStatement < Arel::Nodes::Node + class SelectStatement < Arel::Nodes::NodeExpression attr_reader :cores attr_accessor :limit, :orders, :lock, :offset, :with diff --git a/lib/arel/nodes/terminal.rb b/lib/arel/nodes/terminal.rb index 421f039904c9a..3a1cd7f0e13af 100644 --- a/lib/arel/nodes/terminal.rb +++ b/lib/arel/nodes/terminal.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class Distinct < Arel::Nodes::Node + class Distinct < Arel::Nodes::NodeExpression def hash self.class.hash end diff --git a/lib/arel/nodes/true.rb b/lib/arel/nodes/true.rb index bb9d8c1414cd5..fdb8ed2095d0c 100644 --- a/lib/arel/nodes/true.rb +++ b/lib/arel/nodes/true.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class True < Arel::Nodes::Node + class True < Arel::Nodes::NodeExpression def hash self.class.hash end diff --git a/lib/arel/nodes/unary.rb b/lib/arel/nodes/unary.rb index a42744b1d5ebf..5711d91dcefd8 100644 --- a/lib/arel/nodes/unary.rb +++ b/lib/arel/nodes/unary.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Arel module Nodes - class Unary < Arel::Nodes::Node + class Unary < Arel::Nodes::NodeExpression attr_accessor :expr alias :value :expr diff --git a/lib/arel/nodes/unary_operation.rb b/lib/arel/nodes/unary_operation.rb index 3c56ef20263a7..be4e270e763cf 100644 --- a/lib/arel/nodes/unary_operation.rb +++ b/lib/arel/nodes/unary_operation.rb @@ -3,12 +3,6 @@ module Arel module Nodes class UnaryOperation < Unary - include Arel::Expressions - include Arel::Predications - include Arel::OrderPredications - include Arel::AliasPredication - include Arel::Math - attr_reader :operator def initialize operator, operand @@ -23,4 +17,4 @@ def initialize operand end end end -end \ No newline at end of file +end diff --git a/test/test_nodes.rb b/test/test_nodes.rb index bf0082396d33f..1060f150ff207 100644 --- a/test/test_nodes.rb +++ b/test/test_nodes.rb @@ -12,6 +12,7 @@ def test_every_arel_nodes_have_hash_eql_eqeq_from_same_class node_descendants.unshift k unless k == self end node_descendants.delete(Arel::Nodes::Node) + node_descendants.delete(Arel::Nodes::NodeExpression) bad_node_descendants = node_descendants.reject do |subnode| eqeq_owner = subnode.instance_method(:==).owner From ff53df96875de84ee02895772b59448f35a5a0c2 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Tue, 4 Oct 2016 18:31:01 -0400 Subject: [PATCH 1483/1492] Delete is not a NodeExpression, change parent This requires a little cut and paste from the Binary node, but it is used in different parts of sql --- lib/arel/nodes/delete_statement.rb | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/arel/nodes/delete_statement.rb b/lib/arel/nodes/delete_statement.rb index 593ce9bddf618..063a5341e5ea8 100644 --- a/lib/arel/nodes/delete_statement.rb +++ b/lib/arel/nodes/delete_statement.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true module Arel module Nodes - class DeleteStatement < Arel::Nodes::Binary + class DeleteStatement < Arel::Nodes::Node + attr_accessor :left, :right attr_accessor :limit alias :relation :left @@ -10,13 +11,27 @@ class DeleteStatement < Arel::Nodes::Binary alias :wheres= :right= def initialize relation = nil, wheres = [] - super + super() + @left = relation + @right = wheres end def initialize_copy other super - @right = @right.clone + @left = @left.clone if @left + @right = @right.clone if @right + end + + def hash + [self.class, @left, @right].hash + end + + def eql? other + self.class == other.class && + self.left == other.left && + self.right == other.right end + alias :== :eql? end end end From 19c3c1c38f9500dee897d6e12d558d43e3fc4af0 Mon Sep 17 00:00:00 2001 From: Evan Brodie Date: Tue, 5 Dec 2017 13:48:34 -0500 Subject: [PATCH 1484/1492] Explicitly mentions the #and operator --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 065bfea26c72c..3214dc16b3a9a 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,13 @@ The `OR` operator works like this: users.where(users[:name].eq('bob').or(users[:age].lt(25))) ``` -The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator: +The `AND` operator behaves similarly (same exact behaviour as chained calls to `.where`): + +```ruby +users.where(users[:name].eq('bob').and(users[:age].lt(25))) +``` + +Here is an example of the `DISTINCT` operator: ```ruby posts = Arel::Table.new(:posts) From c41c909decde88156215e07e5d1d52898a3d5aa4 Mon Sep 17 00:00:00 2001 From: Nikolay Ponomarev Date: Wed, 27 Dec 2017 22:21:32 +0300 Subject: [PATCH 1485/1492] Reduce `Reduce` Remove `Arel::Visitors::Reduce` because it almost completely duplicates `Arel::Visitors::Visitor` --- arel.gemspec | 2 +- lib/arel/visitors/reduce.rb | 27 --------------------------- lib/arel/visitors/to_sql.rb | 3 +-- lib/arel/visitors/visitor.rb | 14 ++++++-------- test/visitors/test_to_sql.rb | 2 +- 5 files changed, 9 insertions(+), 39 deletions(-) delete mode 100644 lib/arel/visitors/reduce.rb diff --git a/arel.gemspec b/arel.gemspec index f914d1a5ca512..4ed41c3d4cffd 100644 --- a/arel.gemspec +++ b/arel.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.rdoc_options = ["--main", "README.md"] s.extra_rdoc_files = ["History.txt", "MIT-LICENSE.txt", "README.md"] - s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/composite.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/values_list.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/reduce.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] + s.files = ["History.txt","MIT-LICENSE.txt","README.md","lib/arel.rb","lib/arel/alias_predication.rb","lib/arel/attributes.rb","lib/arel/attributes/attribute.rb","lib/arel/collectors/bind.rb","lib/arel/collectors/composite.rb","lib/arel/collectors/plain_string.rb","lib/arel/collectors/sql_string.rb","lib/arel/collectors/substitute_binds.rb","lib/arel/compatibility/wheres.rb","lib/arel/crud.rb","lib/arel/delete_manager.rb","lib/arel/errors.rb","lib/arel/expressions.rb","lib/arel/factory_methods.rb","lib/arel/insert_manager.rb","lib/arel/math.rb","lib/arel/nodes.rb","lib/arel/nodes/and.rb","lib/arel/nodes/ascending.rb","lib/arel/nodes/binary.rb","lib/arel/nodes/bind_param.rb","lib/arel/nodes/case.rb","lib/arel/nodes/casted.rb","lib/arel/nodes/count.rb","lib/arel/nodes/delete_statement.rb","lib/arel/nodes/descending.rb","lib/arel/nodes/equality.rb","lib/arel/nodes/extract.rb","lib/arel/nodes/false.rb","lib/arel/nodes/full_outer_join.rb","lib/arel/nodes/function.rb","lib/arel/nodes/grouping.rb","lib/arel/nodes/in.rb","lib/arel/nodes/infix_operation.rb","lib/arel/nodes/inner_join.rb","lib/arel/nodes/insert_statement.rb","lib/arel/nodes/join_source.rb","lib/arel/nodes/matches.rb","lib/arel/nodes/named_function.rb","lib/arel/nodes/node.rb","lib/arel/nodes/outer_join.rb","lib/arel/nodes/over.rb","lib/arel/nodes/regexp.rb","lib/arel/nodes/right_outer_join.rb","lib/arel/nodes/select_core.rb","lib/arel/nodes/select_statement.rb","lib/arel/nodes/sql_literal.rb","lib/arel/nodes/string_join.rb","lib/arel/nodes/table_alias.rb","lib/arel/nodes/terminal.rb","lib/arel/nodes/true.rb","lib/arel/nodes/unary.rb","lib/arel/nodes/unary_operation.rb","lib/arel/nodes/unqualified_column.rb","lib/arel/nodes/update_statement.rb","lib/arel/nodes/values.rb","lib/arel/nodes/values_list.rb","lib/arel/nodes/window.rb","lib/arel/nodes/with.rb","lib/arel/order_predications.rb","lib/arel/predications.rb","lib/arel/select_manager.rb","lib/arel/table.rb","lib/arel/tree_manager.rb","lib/arel/update_manager.rb","lib/arel/visitors.rb","lib/arel/visitors/depth_first.rb","lib/arel/visitors/dot.rb","lib/arel/visitors/ibm_db.rb","lib/arel/visitors/informix.rb","lib/arel/visitors/mssql.rb","lib/arel/visitors/mysql.rb","lib/arel/visitors/oracle.rb","lib/arel/visitors/oracle12.rb","lib/arel/visitors/postgresql.rb","lib/arel/visitors/sqlite.rb","lib/arel/visitors/to_sql.rb","lib/arel/visitors/visitor.rb","lib/arel/visitors/where_sql.rb","lib/arel/window_predications.rb"] s.require_paths = ["lib"] s.add_development_dependency('minitest', '~> 5.4') diff --git a/lib/arel/visitors/reduce.rb b/lib/arel/visitors/reduce.rb deleted file mode 100644 index 1156b780f0f36..0000000000000 --- a/lib/arel/visitors/reduce.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true -require 'arel/visitors/visitor' - -module Arel - module Visitors - class Reduce < Arel::Visitors::Visitor - def accept object, collector - visit object, collector - end - - private - - def visit object, collector - dispatch_method = dispatch[object.class] - send dispatch_method, object, collector - rescue NoMethodError => e - raise e if respond_to?(dispatch_method, 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 diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index 6aaaa19e6e290..f8c239e8efa85 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'bigdecimal' require 'date' -require 'arel/visitors/reduce' module Arel module Visitors @@ -11,7 +10,7 @@ def initialize(object) end end - class ToSql < Arel::Visitors::Reduce + 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 diff --git a/lib/arel/visitors/visitor.rb b/lib/arel/visitors/visitor.rb index 2690c98e3c402..f156be9a0aa4a 100644 --- a/lib/arel/visitors/visitor.rb +++ b/lib/arel/visitors/visitor.rb @@ -6,12 +6,14 @@ def initialize @dispatch = get_dispatch_cache end - def accept object - visit object + def accept object, *args + visit object, *args end private + attr_reader :dispatch + def self.dispatch_cache Hash.new do |hash, klass| hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" @@ -22,13 +24,9 @@ def get_dispatch_cache self.class.dispatch_cache end - def dispatch - @dispatch - end - - def visit object + def visit object, *args dispatch_method = dispatch[object.class] - send dispatch_method, object + send dispatch_method, object, *args rescue NoMethodError => e raise e if respond_to?(dispatch_method, true) superklass = object.class.ancestors.find { |klass| diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index e95c0666b4e20..eb6eedc55d8d2 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -31,7 +31,7 @@ def compile node it 'can define a dispatch method' do visited = false - viz = Class.new(Arel::Visitors::Reduce) { + viz = Class.new(Arel::Visitors::Visitor) { define_method(:hello) do |node, c| visited = true end From 773f5e5a0b172754289de527bcba6b923bbc3d0e Mon Sep 17 00:00:00 2001 From: Nikolay Ponomarev Date: Wed, 27 Dec 2017 23:33:54 +0300 Subject: [PATCH 1486/1492] Remove Unused `require` It looks like they are left from old design --- lib/arel/nodes/node.rb | 2 -- lib/arel/select_manager.rb | 2 -- lib/arel/tree_manager.rb | 2 -- lib/arel/visitors/to_sql.rb | 3 --- test/collectors/test_bind.rb | 2 -- test/collectors/test_composite.rb | 1 - test/helper.rb | 1 - test/nodes/test_binary.rb | 1 - test/nodes/test_table_alias.rb | 1 - test/visitors/test_depth_first.rb | 1 - test/visitors/test_to_sql.rb | 2 +- 11 files changed, 1 insertion(+), 17 deletions(-) diff --git a/lib/arel/nodes/node.rb b/lib/arel/nodes/node.rb index 34e71063aff92..d2e6313dda192 100644 --- a/lib/arel/nodes/node.rb +++ b/lib/arel/nodes/node.rb @@ -1,6 +1,4 @@ # frozen_string_literal: true -require 'arel/collectors/sql_string' - module Arel module Nodes ### diff --git a/lib/arel/select_manager.rb b/lib/arel/select_manager.rb index 0b35176842275..a88dcd320c614 100644 --- a/lib/arel/select_manager.rb +++ b/lib/arel/select_manager.rb @@ -1,6 +1,4 @@ # frozen_string_literal: true -require 'arel/collectors/sql_string' - module Arel class SelectManager < Arel::TreeManager include Arel::Crud diff --git a/lib/arel/tree_manager.rb b/lib/arel/tree_manager.rb index 054244240419c..b237bf368d2ed 100644 --- a/lib/arel/tree_manager.rb +++ b/lib/arel/tree_manager.rb @@ -1,6 +1,4 @@ # frozen_string_literal: true -require 'arel/collectors/sql_string' - module Arel class TreeManager include Arel::FactoryMethods diff --git a/lib/arel/visitors/to_sql.rb b/lib/arel/visitors/to_sql.rb index f8c239e8efa85..2b5c43b17389b 100644 --- a/lib/arel/visitors/to_sql.rb +++ b/lib/arel/visitors/to_sql.rb @@ -1,7 +1,4 @@ # frozen_string_literal: true -require 'bigdecimal' -require 'date' - module Arel module Visitors class UnsupportedVisitError < StandardError diff --git a/test/collectors/test_bind.rb b/test/collectors/test_bind.rb index 6b4b651cf72fe..62fd911a0fce3 100644 --- a/test/collectors/test_bind.rb +++ b/test/collectors/test_bind.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true require 'helper' -require 'arel/collectors/bind' - module Arel module Collectors class TestBind < Arel::Test diff --git a/test/collectors/test_composite.rb b/test/collectors/test_composite.rb index b47c37db736be..3d49b390e8b44 100644 --- a/test/collectors/test_composite.rb +++ b/test/collectors/test_composite.rb @@ -3,7 +3,6 @@ require 'arel/collectors/bind' require 'arel/collectors/composite' -require 'arel/collectors/sql_string' module Arel module Collectors diff --git a/test/helper.rb b/test/helper.rb index 022ba1dae66e5..3eecfb79b6254 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'rubygems' require 'minitest/autorun' -require 'fileutils' require 'arel' require 'support/fake_record' diff --git a/test/nodes/test_binary.rb b/test/nodes/test_binary.rb index 8e3025a4404c2..ef23a3930b568 100644 --- a/test/nodes/test_binary.rb +++ b/test/nodes/test_binary.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true require 'helper' -require 'set' module Arel module Nodes diff --git a/test/nodes/test_table_alias.rb b/test/nodes/test_table_alias.rb index 39040e63526da..911114d9388c9 100644 --- a/test/nodes/test_table_alias.rb +++ b/test/nodes/test_table_alias.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true require 'helper' -require 'ostruct' module Arel module Nodes diff --git a/test/visitors/test_depth_first.rb b/test/visitors/test_depth_first.rb index 0c7f7ccd34bc3..832843265cb74 100644 --- a/test/visitors/test_depth_first.rb +++ b/test/visitors/test_depth_first.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true require 'helper' -require 'set' module Arel module Visitors diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index eb6eedc55d8d2..77756b9e99a15 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true require 'helper' -require 'set' +require 'bigdecimal' module Arel module Visitors From 8a2a3232e772ebee94d7ac155f1d7c91accccf64 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 6 Jan 2018 19:06:35 +0000 Subject: [PATCH 1487/1492] CI with Ruby 2.5.0 https://www.ruby-lang.org/en/news/2017/12/25/ruby-2-5-0-released/ --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4e1bca45c7103..da8eac13bbc49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ rvm: - 2.2.8 - 2.3.5 - 2.4.2 + - 2.5.0 - ruby-head - jruby-9.1.12.0 - jruby-head From f870164839d4bca4795342f179bd4a581deb5ac7 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 6 Jan 2018 19:31:44 +0000 Subject: [PATCH 1488/1492] Use the latest RubyGems 2.7.4 or higher Refer https://github.com/rubygems/rubygems/issues/2123 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index da8eac13bbc49..081b586eb4972 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ matrix: - rvm: jruby-9.1.12.0 - rvm: jruby-head bundler_args: --jobs 3 --retry 3 +before_install: + - "travis_retry gem update --system" notifications: email: false irc: From f4477d631f19e7a9e09f77062a0992121d0bca16 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 7 Jan 2018 23:39:35 +0000 Subject: [PATCH 1489/1492] require 'date' to address for Ruby 2.5 Address #517 --- test/support/fake_record.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/support/fake_record.rb b/test/support/fake_record.rb index 03116ff2ee01c..75ac1e072fbd7 100644 --- a/test/support/fake_record.rb +++ b/test/support/fake_record.rb @@ -1,4 +1,6 @@ # frozen_string_literal: true + +require 'date' module FakeRecord class Column < Struct.new(:name, :type) end From cbbe9ed392bfe146fc0871653aad9b619cef8509 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 7 Jan 2018 23:43:51 +0000 Subject: [PATCH 1490/1492] BigDecimal.new is deprecated in Ruby 2.5 Refer https://github.com/ruby/bigdecimal/pull/86 --- test/visitors/test_to_sql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/visitors/test_to_sql.rb b/test/visitors/test_to_sql.rb index 77756b9e99a15..4416a11b8d49b 100644 --- a/test/visitors/test_to_sql.rb +++ b/test/visitors/test_to_sql.rb @@ -233,7 +233,7 @@ def dispatch end it "should visit_BigDecimal" do - compile Nodes.build_quoted(BigDecimal.new('2.14')) + compile Nodes.build_quoted(BigDecimal('2.14')) end it "should visit_Date" do From 4c0a3d48804a363c7e9272519665a21f601b5248 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Sat, 24 Feb 2018 17:15:50 +1030 Subject: [PATCH 1491/1492] Arel: rubocop -a --- .rubocop.yml | 3 - activerecord/lib/arel.rb | 55 +- activerecord/lib/arel/alias_predication.rb | 5 +- activerecord/lib/arel/attributes.rb | 5 +- activerecord/lib/arel/attributes/attribute.rb | 1 + activerecord/lib/arel/collectors/bind.rb | 4 +- activerecord/lib/arel/collectors/composite.rb | 6 +- .../lib/arel/collectors/plain_string.rb | 5 +- .../lib/arel/collectors/sql_string.rb | 6 +- .../lib/arel/collectors/substitute_binds.rb | 7 +- activerecord/lib/arel/compatibility/wheres.rb | 3 +- activerecord/lib/arel/crud.rb | 6 +- activerecord/lib/arel/delete_manager.rb | 7 +- activerecord/lib/arel/errors.rb | 1 + activerecord/lib/arel/expressions.rb | 6 +- activerecord/lib/arel/factory_methods.rb | 17 +- activerecord/lib/arel/insert_manager.rb | 11 +- activerecord/lib/arel/math.rb | 1 + activerecord/lib/arel/nodes.rb | 87 +- activerecord/lib/arel/nodes/and.rb | 5 +- activerecord/lib/arel/nodes/ascending.rb | 3 +- activerecord/lib/arel/nodes/binary.rb | 7 +- activerecord/lib/arel/nodes/bind_param.rb | 1 + activerecord/lib/arel/nodes/case.rb | 13 +- activerecord/lib/arel/nodes/casted.rb | 23 +- activerecord/lib/arel/nodes/count.rb | 3 +- .../lib/arel/nodes/delete_statement.rb | 7 +- activerecord/lib/arel/nodes/descending.rb | 3 +- activerecord/lib/arel/nodes/equality.rb | 1 + activerecord/lib/arel/nodes/extract.rb | 5 +- activerecord/lib/arel/nodes/false.rb | 3 +- .../lib/arel/nodes/full_outer_join.rb | 1 + activerecord/lib/arel/nodes/function.rb | 8 +- activerecord/lib/arel/nodes/grouping.rb | 1 + activerecord/lib/arel/nodes/in.rb | 1 + .../lib/arel/nodes/infix_operation.rb | 26 +- activerecord/lib/arel/nodes/inner_join.rb | 1 + .../lib/arel/nodes/insert_statement.rb | 5 +- activerecord/lib/arel/nodes/join_source.rb | 3 +- activerecord/lib/arel/nodes/matches.rb | 1 + activerecord/lib/arel/nodes/named_function.rb | 5 +- activerecord/lib/arel/nodes/node.rb | 9 +- .../lib/arel/nodes/node_expression.rb | 2 + activerecord/lib/arel/nodes/outer_join.rb | 1 + activerecord/lib/arel/nodes/over.rb | 7 +- activerecord/lib/arel/nodes/regexp.rb | 1 + .../lib/arel/nodes/right_outer_join.rb | 1 + activerecord/lib/arel/nodes/select_core.rb | 7 +- .../lib/arel/nodes/select_statement.rb | 7 +- activerecord/lib/arel/nodes/sql_literal.rb | 1 + activerecord/lib/arel/nodes/string_join.rb | 3 +- activerecord/lib/arel/nodes/table_alias.rb | 3 +- activerecord/lib/arel/nodes/terminal.rb | 3 +- activerecord/lib/arel/nodes/true.rb | 3 +- activerecord/lib/arel/nodes/unary.rb | 5 +- .../lib/arel/nodes/unary_operation.rb | 6 +- .../lib/arel/nodes/unqualified_column.rb | 1 + .../lib/arel/nodes/update_statement.rb | 5 +- activerecord/lib/arel/nodes/values.rb | 3 +- activerecord/lib/arel/nodes/values_list.rb | 3 +- activerecord/lib/arel/nodes/window.rb | 17 +- activerecord/lib/arel/nodes/with.rb | 2 +- activerecord/lib/arel/order_predications.rb | 3 +- activerecord/lib/arel/predications.rb | 117 +- activerecord/lib/arel/select_manager.rb | 81 +- activerecord/lib/arel/table.rb | 29 +- activerecord/lib/arel/tree_manager.rb | 7 +- activerecord/lib/arel/update_manager.rb | 17 +- activerecord/lib/arel/visitors.rb | 27 +- activerecord/lib/arel/visitors/depth_first.rb | 373 ++--- activerecord/lib/arel/visitors/dot.rb | 447 +++--- activerecord/lib/arel/visitors/ibm_db.rb | 12 +- activerecord/lib/arel/visitors/informix.rb | 82 +- activerecord/lib/arel/visitors/mssql.rb | 177 +-- activerecord/lib/arel/visitors/mysql.rb | 127 +- activerecord/lib/arel/visitors/oracle.rb | 250 ++-- activerecord/lib/arel/visitors/oracle12.rb | 87 +- activerecord/lib/arel/visitors/postgresql.rb | 155 ++- activerecord/lib/arel/visitors/sqlite.rb | 30 +- activerecord/lib/arel/visitors/to_sql.rb | 1239 +++++++++-------- activerecord/lib/arel/visitors/visitor.rb | 43 +- activerecord/lib/arel/visitors/where_sql.rb | 15 +- activerecord/lib/arel/window_predications.rb | 5 +- .../cases/arel/attributes/attribute_test.rb | 445 +++--- .../test/cases/arel/attributes_test.rb | 35 +- .../test/cases/arel/collectors/bind_test.rb | 9 +- .../cases/arel/collectors/composite_test.rb | 13 +- .../cases/arel/collectors/sql_string_test.rb | 9 +- .../substitute_bind_collector_test.rb | 7 +- activerecord/test/cases/arel/crud_test.rb | 27 +- .../test/cases/arel/delete_manager_test.rb | 21 +- .../test/cases/arel/factory_methods_test.rb | 5 +- activerecord/test/cases/arel/helper.rb | 19 +- .../test/cases/arel/insert_manager_test.rb | 58 +- .../test/cases/arel/nodes/and_test.rb | 16 +- activerecord/test/cases/arel/nodes/as_test.rb | 27 +- .../test/cases/arel/nodes/ascending_test.rb | 19 +- .../test/cases/arel/nodes/bin_test.rb | 17 +- .../test/cases/arel/nodes/binary_test.rb | 21 +- .../test/cases/arel/nodes/bind_param_test.rb | 11 +- .../test/cases/arel/nodes/case_test.rb | 37 +- .../test/cases/arel/nodes/casted_test.rb | 7 +- .../test/cases/arel/nodes/count_test.rb | 21 +- .../cases/arel/nodes/delete_statement_test.rb | 9 +- .../test/cases/arel/nodes/descending_test.rb | 19 +- .../test/cases/arel/nodes/distinct_test.rb | 12 +- .../test/cases/arel/nodes/equality_test.rb | 41 +- .../test/cases/arel/nodes/extract_test.rb | 25 +- .../test/cases/arel/nodes/false_test.rb | 12 +- .../test/cases/arel/nodes/grouping_test.rb | 20 +- .../cases/arel/nodes/infix_operation_test.rb | 7 +- .../cases/arel/nodes/insert_statement_test.rb | 9 +- .../cases/arel/nodes/named_function_test.rb | 35 +- .../test/cases/arel/nodes/node_test.rb | 3 +- .../test/cases/arel/nodes/not_test.rb | 19 +- activerecord/test/cases/arel/nodes/or_test.rb | 19 +- .../test/cases/arel/nodes/over_test.rb | 45 +- .../test/cases/arel/nodes/select_core_test.rb | 5 +- .../cases/arel/nodes/select_statement_test.rb | 17 +- .../test/cases/arel/nodes/sql_literal_test.rb | 53 +- .../test/cases/arel/nodes/sum_test.rb | 23 +- .../test/cases/arel/nodes/table_alias_test.rb | 11 +- .../test/cases/arel/nodes/true_test.rb | 13 +- .../cases/arel/nodes/unary_operation_test.rb | 7 +- .../cases/arel/nodes/update_statement_test.rb | 25 +- .../test/cases/arel/nodes/window_test.rb | 35 +- activerecord/test/cases/arel/nodes_test.rb | 9 +- .../test/cases/arel/select_manager_test.rb | 488 +++---- .../test/cases/arel/support/fake_record.rb | 48 +- activerecord/test/cases/arel/table_test.rb | 129 +- .../test/cases/arel/update_manager_test.rb | 43 +- .../cases/arel/visitors/depth_first_test.rb | 7 +- .../visitors/dispatch_contamination_test.rb | 14 +- .../test/cases/arel/visitors/dot_test.rb | 5 +- .../test/cases/arel/visitors/ibm_db_test.rb | 10 +- .../test/cases/arel/visitors/informix_test.rb | 16 +- .../test/cases/arel/visitors/mssql_test.rb | 30 +- .../test/cases/arel/visitors/mysql_test.rb | 35 +- .../test/cases/arel/visitors/oracle12_test.rb | 19 +- .../test/cases/arel/visitors/oracle_test.rb | 61 +- .../test/cases/arel/visitors/postgres_test.rb | 77 +- .../test/cases/arel/visitors/sqlite_test.rb | 17 +- .../test/cases/arel/visitors/to_sql_test.rb | 185 +-- 143 files changed, 3179 insertions(+), 3077 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index aa998b8f26731..3c765d5b1dbfa 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,9 +7,6 @@ AllCops: - '**/templates/**/*' - '**/vendor/**/*' - 'actionpack/lib/action_dispatch/journey/parser.rb' - - 'activerecord/lib/arel.rb' - - 'activerecord/lib/arel/**/*' - - 'activerecord/test/cases/arel/**/*' # Prefer &&/|| over and/or. Style/AndOr: diff --git a/activerecord/lib/arel.rb b/activerecord/lib/arel.rb index c327caeac08e7..2d5cfa4d5c4e5 100644 --- a/activerecord/lib/arel.rb +++ b/activerecord/lib/arel.rb @@ -1,38 +1,39 @@ # frozen_string_literal: true -require 'arel/errors' - -require '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' - -require 'arel/visitors' -require 'arel/collectors/sql_string' - -require 'arel/tree_manager' -require 'arel/insert_manager' -require 'arel/select_manager' -require 'arel/update_manager' -require 'arel/delete_manager' -require 'arel/nodes' + +require "arel/errors" + +require "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" + +require "arel/visitors" +require "arel/collectors/sql_string" + +require "arel/tree_manager" +require "arel/insert_manager" +require "arel/select_manager" +require "arel/update_manager" +require "arel/delete_manager" +require "arel/nodes" module Arel - VERSION = '10.0.0' + VERSION = "10.0.0" - def self.sql raw_sql + def self.sql(raw_sql) Arel::Nodes::SqlLiteral.new raw_sql end def self.star - sql '*' + sql "*" end ## Convenience Alias Node = Arel::Nodes::Node diff --git a/activerecord/lib/arel/alias_predication.rb b/activerecord/lib/arel/alias_predication.rb index cb50fb95be1dc..ae44157b9a5b0 100644 --- a/activerecord/lib/arel/alias_predication.rb +++ b/activerecord/lib/arel/alias_predication.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true + module Arel module AliasPredication - def as other + def as(other) Nodes::As.new self, Nodes::SqlLiteral.new(other) end end -end \ No newline at end of file +end diff --git a/activerecord/lib/arel/attributes.rb b/activerecord/lib/arel/attributes.rb index ed4739ebeddc5..c81a7b941b5ab 100644 --- a/activerecord/lib/arel/attributes.rb +++ b/activerecord/lib/arel/attributes.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require 'arel/attributes/attribute' + +require "arel/attributes/attribute" module Arel module Attributes ### # Factory method to wrap a raw database +column+ to an Arel Attribute. - def self.for column + def self.for(column) case column.type when :string, :text, :binary then String when :integer then Integer diff --git a/activerecord/lib/arel/attributes/attribute.rb b/activerecord/lib/arel/attributes/attribute.rb index 41bc0c32c7d88..71f839479ae2c 100644 --- a/activerecord/lib/arel/attributes/attribute.rb +++ b/activerecord/lib/arel/attributes/attribute.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Attributes class Attribute < Struct.new :relation, :name diff --git a/activerecord/lib/arel/collectors/bind.rb b/activerecord/lib/arel/collectors/bind.rb index d816aed90d64e..8d19e7446d5c1 100644 --- a/activerecord/lib/arel/collectors/bind.rb +++ b/activerecord/lib/arel/collectors/bind.rb @@ -7,11 +7,11 @@ def initialize @binds = [] end - def << str + def <<(str) self end - def add_bind bind + def add_bind(bind) @binds << bind self end diff --git a/activerecord/lib/arel/collectors/composite.rb b/activerecord/lib/arel/collectors/composite.rb index 4f6156fe27518..675a81959637c 100644 --- a/activerecord/lib/arel/collectors/composite.rb +++ b/activerecord/lib/arel/collectors/composite.rb @@ -8,13 +8,13 @@ def initialize(left, right) @right = right end - def << str + def <<(str) left << str right << str self end - def add_bind bind, &block + def add_bind(bind, &block) left.add_bind bind, &block right.add_bind bind, &block self @@ -26,7 +26,7 @@ def value protected - attr_reader :left, :right + attr_reader :left, :right end end end diff --git a/activerecord/lib/arel/collectors/plain_string.rb b/activerecord/lib/arel/collectors/plain_string.rb index 1e8d2a2152d4e..b98802c44a9f4 100644 --- a/activerecord/lib/arel/collectors/plain_string.rb +++ b/activerecord/lib/arel/collectors/plain_string.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true + module Arel module Collectors class PlainString def initialize - @str = ''.dup + @str = "".dup end def value @str end - def << str + def <<(str) @str << str self end diff --git a/activerecord/lib/arel/collectors/sql_string.rb b/activerecord/lib/arel/collectors/sql_string.rb index bcb941f6d4372..78c9e48aab601 100644 --- a/activerecord/lib/arel/collectors/sql_string.rb +++ b/activerecord/lib/arel/collectors/sql_string.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'arel/collectors/plain_string' +require "arel/collectors/plain_string" module Arel module Collectors @@ -10,13 +10,13 @@ def initialize(*) @bind_index = 1 end - def add_bind bind + def add_bind(bind) self << yield(@bind_index) @bind_index += 1 self end - def compile bvs + def compile(bvs) value end end diff --git a/activerecord/lib/arel/collectors/substitute_binds.rb b/activerecord/lib/arel/collectors/substitute_binds.rb index 99d2215aaaf6c..ee6635f914f4c 100644 --- a/activerecord/lib/arel/collectors/substitute_binds.rb +++ b/activerecord/lib/arel/collectors/substitute_binds.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Collectors class SubstituteBinds @@ -7,12 +8,12 @@ def initialize(quoter, delegate_collector) @delegate = delegate_collector end - def << str + def <<(str) delegate << str self end - def add_bind bind + def add_bind(bind) self << quoter.quote(bind) end @@ -22,7 +23,7 @@ def value protected - attr_reader :quoter, :delegate + attr_reader :quoter, :delegate end end end diff --git a/activerecord/lib/arel/compatibility/wheres.rb b/activerecord/lib/arel/compatibility/wheres.rb index 3e60894bd80d2..2ffb2e0ad8508 100644 --- a/activerecord/lib/arel/compatibility/wheres.rb +++ b/activerecord/lib/arel/compatibility/wheres.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Compatibility # :nodoc: class Wheres # :nodoc: @@ -15,7 +16,7 @@ def name end end - def initialize engine, collection + def initialize(engine, collection) @engine = engine @collection = collection end diff --git a/activerecord/lib/arel/crud.rb b/activerecord/lib/arel/crud.rb index 2d104322058f4..e2427b730c1bc 100644 --- a/activerecord/lib/arel/crud.rb +++ b/activerecord/lib/arel/crud.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true + module Arel ### # FIXME hopefully we can remove this module Crud - def compile_update values, pk + def compile_update(values, pk) um = UpdateManager.new if Nodes::SqlLiteral === values @@ -20,7 +21,7 @@ def compile_update values, pk um end - def compile_insert values + def compile_insert(values) im = create_insert im.insert values im @@ -37,6 +38,5 @@ def compile_delete dm.from @ctx.froms dm end - end end diff --git a/activerecord/lib/arel/delete_manager.rb b/activerecord/lib/arel/delete_manager.rb index aee4511249d41..df1f92bd23196 100644 --- a/activerecord/lib/arel/delete_manager.rb +++ b/activerecord/lib/arel/delete_manager.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel class DeleteManager < Arel::TreeManager def initialize @@ -7,17 +8,17 @@ def initialize @ctx = @ast end - def from relation + def from(relation) @ast.relation = relation self end - def take limit + def take(limit) @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit self end - def wheres= list + def wheres=(list) @ast.wheres = list end end diff --git a/activerecord/lib/arel/errors.rb b/activerecord/lib/arel/errors.rb index 86fbb80461d32..8733b7ff5a7a7 100644 --- a/activerecord/lib/arel/errors.rb +++ b/activerecord/lib/arel/errors.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel class ArelError < StandardError end diff --git a/activerecord/lib/arel/expressions.rb b/activerecord/lib/arel/expressions.rb index 612a0942f1319..597b861b6c44a 100644 --- a/activerecord/lib/arel/expressions.rb +++ b/activerecord/lib/arel/expressions.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true + module Arel module Expressions - def count distinct = false + def count(distinct = false) Nodes::Count.new [self], distinct end @@ -21,9 +22,8 @@ def average Nodes::Avg.new [self] end - def extract field + def extract(field) Nodes::Extract.new [self], field end - end end diff --git a/activerecord/lib/arel/factory_methods.rb b/activerecord/lib/arel/factory_methods.rb index 6647c5ac44c54..55aea3ecd7259 100644 --- a/activerecord/lib/arel/factory_methods.rb +++ b/activerecord/lib/arel/factory_methods.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel ### # Methods for creating various nodes @@ -11,34 +12,34 @@ def create_false Arel::Nodes::False.new end - def create_table_alias relation, name + def create_table_alias(relation, name) Nodes::TableAlias.new(relation, name) end - def create_join to, constraint = nil, klass = Nodes::InnerJoin + def create_join(to, constraint = nil, klass = Nodes::InnerJoin) klass.new(to, constraint) end - def create_string_join to + def create_string_join(to) create_join to, nil, Nodes::StringJoin end - def create_and clauses + def create_and(clauses) Nodes::And.new clauses end - def create_on expr + def create_on(expr) Nodes::On.new expr end - def grouping expr + def grouping(expr) Nodes::Grouping.new expr end ### # Create a LOWER() function - def lower column - Nodes::NamedFunction.new 'LOWER', [Nodes.build_quoted(column)] + def lower(column) + Nodes::NamedFunction.new "LOWER", [Nodes.build_quoted(column)] end end end diff --git a/activerecord/lib/arel/insert_manager.rb b/activerecord/lib/arel/insert_manager.rb index dcbac6cb43d2f..47b52d6515b4d 100644 --- a/activerecord/lib/arel/insert_manager.rb +++ b/activerecord/lib/arel/insert_manager.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel class InsertManager < Arel::TreeManager def initialize @@ -6,19 +7,19 @@ def initialize @ast = Nodes::InsertStatement.new end - def into table + def into(table) @ast.relation = table self end def columns; @ast.columns end - def values= val; @ast.values = val; end + def values=(val); @ast.values = val; end - def select select + def select(select) @ast.select = select end - def insert fields + def insert(fields) return if fields.empty? if String === fields @@ -37,7 +38,7 @@ def insert fields self end - def create_values values, columns + def create_values(values, columns) Nodes::Values.new values, columns end diff --git a/activerecord/lib/arel/math.rb b/activerecord/lib/arel/math.rb index 9e6549b58fbdc..671457efff3ad 100644 --- a/activerecord/lib/arel/math.rb +++ b/activerecord/lib/arel/math.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Math def *(other) diff --git a/activerecord/lib/arel/nodes.rb b/activerecord/lib/arel/nodes.rb index 8c6572dd6af84..5af0e532e26c5 100644 --- a/activerecord/lib/arel/nodes.rb +++ b/activerecord/lib/arel/nodes.rb @@ -1,66 +1,67 @@ # frozen_string_literal: true + # node -require 'arel/nodes/node' -require 'arel/nodes/node_expression' -require 'arel/nodes/select_statement' -require 'arel/nodes/select_core' -require 'arel/nodes/insert_statement' -require 'arel/nodes/update_statement' -require 'arel/nodes/bind_param' +require "arel/nodes/node" +require "arel/nodes/node_expression" +require "arel/nodes/select_statement" +require "arel/nodes/select_core" +require "arel/nodes/insert_statement" +require "arel/nodes/update_statement" +require "arel/nodes/bind_param" # terminal -require 'arel/nodes/terminal' -require 'arel/nodes/true' -require 'arel/nodes/false' +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' +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/unary_operation' -require 'arel/nodes/over' -require 'arel/nodes/matches' -require 'arel/nodes/regexp' +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/unary_operation" +require "arel/nodes/over" +require "arel/nodes/matches" +require "arel/nodes/regexp" # nary -require 'arel/nodes/and' +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/values_list' -require 'arel/nodes/named_function' +require "arel/nodes/function" +require "arel/nodes/count" +require "arel/nodes/extract" +require "arel/nodes/values" +require "arel/nodes/values_list" +require "arel/nodes/named_function" # windows -require 'arel/nodes/window' +require "arel/nodes/window" # conditional expressions -require 'arel/nodes/case' +require "arel/nodes/case" # joins -require 'arel/nodes/full_outer_join' -require 'arel/nodes/inner_join' -require 'arel/nodes/outer_join' -require 'arel/nodes/right_outer_join' -require 'arel/nodes/string_join' +require "arel/nodes/full_outer_join" +require "arel/nodes/inner_join" +require "arel/nodes/outer_join" +require "arel/nodes/right_outer_join" +require "arel/nodes/string_join" -require 'arel/nodes/sql_literal' +require "arel/nodes/sql_literal" -require 'arel/nodes/casted' +require "arel/nodes/casted" diff --git a/activerecord/lib/arel/nodes/and.rb b/activerecord/lib/arel/nodes/and.rb index 1e2f61cf43dc5..e76d4f3933d45 100644 --- a/activerecord/lib/arel/nodes/and.rb +++ b/activerecord/lib/arel/nodes/and.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true + module Arel module Nodes class And < Arel::Nodes::Node attr_reader :children - def initialize children + def initialize(children) super() @children = children end @@ -21,7 +22,7 @@ def hash children.hash end - def eql? other + def eql?(other) self.class == other.class && self.children == other.children end diff --git a/activerecord/lib/arel/nodes/ascending.rb b/activerecord/lib/arel/nodes/ascending.rb index adadab55e42d8..7ee531734fd03 100644 --- a/activerecord/lib/arel/nodes/ascending.rb +++ b/activerecord/lib/arel/nodes/ascending.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true + module Arel module Nodes class Ascending < Ordering - def reverse Descending.new(expr) end @@ -18,7 +18,6 @@ def ascending? def descending? false end - end end end diff --git a/activerecord/lib/arel/nodes/binary.rb b/activerecord/lib/arel/nodes/binary.rb index a86d4e4696508..e6a5cb63dff22 100644 --- a/activerecord/lib/arel/nodes/binary.rb +++ b/activerecord/lib/arel/nodes/binary.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true + module Arel module Nodes class Binary < Arel::Nodes::NodeExpression attr_accessor :left, :right - def initialize left, right + def initialize(left, right) super() @left = left @right = right end - def initialize_copy other + def initialize_copy(other) super @left = @left.clone if @left @right = @right.clone if @right @@ -20,7 +21,7 @@ def hash [self.class, @left, @right].hash end - def eql? other + def eql?(other) self.class == other.class && self.left == other.left && self.right == other.right diff --git a/activerecord/lib/arel/nodes/bind_param.rb b/activerecord/lib/arel/nodes/bind_param.rb index efa4f452d43a5..1cc1886c2abb4 100644 --- a/activerecord/lib/arel/nodes/bind_param.rb +++ b/activerecord/lib/arel/nodes/bind_param.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class BindParam < Node diff --git a/activerecord/lib/arel/nodes/case.rb b/activerecord/lib/arel/nodes/case.rb index 50ea1e0be2c03..22c2da98ddddd 100644 --- a/activerecord/lib/arel/nodes/case.rb +++ b/activerecord/lib/arel/nodes/case.rb @@ -1,31 +1,32 @@ # frozen_string_literal: true + module Arel module Nodes class Case < Arel::Nodes::Node attr_accessor :case, :conditions, :default - def initialize expression = nil, default = nil + def initialize(expression = nil, default = nil) @case = expression @conditions = [] @default = default end - def when condition, expression = nil + def when(condition, expression = nil) @conditions << When.new(Nodes.build_quoted(condition), expression) self end - def then expression + def then(expression) @conditions.last.right = Nodes.build_quoted(expression) self end - def else expression + def else(expression) @default = Else.new Nodes.build_quoted(expression) self end - def initialize_copy other + def initialize_copy(other) super @case = @case.clone if @case @conditions = @conditions.map { |x| x.clone } @@ -36,7 +37,7 @@ def hash [@case, @conditions, @default].hash end - def eql? other + def eql?(other) self.class == other.class && self.case == other.case && self.conditions == other.conditions && diff --git a/activerecord/lib/arel/nodes/casted.rb b/activerecord/lib/arel/nodes/casted.rb index f945063dd2923..c701e7ff41f96 100644 --- a/activerecord/lib/arel/nodes/casted.rb +++ b/activerecord/lib/arel/nodes/casted.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true + module Arel module Nodes class Casted < Arel::Nodes::NodeExpression # :nodoc: attr_reader :val, :attribute - def initialize val, attribute + def initialize(val, attribute) @val = val @attribute = attribute super() @@ -15,7 +16,7 @@ def hash [self.class, val, attribute].hash end - def eql? other + def eql?(other) self.class == other.class && self.val == other.val && self.attribute == other.attribute @@ -28,17 +29,17 @@ class Quoted < Arel::Nodes::Unary # :nodoc: def nil?; val.nil?; end end - def self.build_quoted other, attribute = nil + def self.build_quoted(other, attribute = nil) case other - when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted, Arel::Nodes::SqlLiteral - other + when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted, Arel::Nodes::SqlLiteral + other + else + case attribute + when Arel::Attributes::Attribute + Casted.new other, attribute else - case attribute - when Arel::Attributes::Attribute - Casted.new other, attribute - else - Quoted.new other - end + Quoted.new other + end end end end diff --git a/activerecord/lib/arel/nodes/count.rb b/activerecord/lib/arel/nodes/count.rb index 4dd9be453fa8e..3f138738efeef 100644 --- a/activerecord/lib/arel/nodes/count.rb +++ b/activerecord/lib/arel/nodes/count.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true + module Arel module Nodes class Count < Arel::Nodes::Function include Math - def initialize expr, distinct = false, aliaz = nil + def initialize(expr, distinct = false, aliaz = nil) super(expr, aliaz) @distinct = distinct end diff --git a/activerecord/lib/arel/nodes/delete_statement.rb b/activerecord/lib/arel/nodes/delete_statement.rb index 063a5341e5ea8..1aad4199cd23b 100644 --- a/activerecord/lib/arel/nodes/delete_statement.rb +++ b/activerecord/lib/arel/nodes/delete_statement.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class DeleteStatement < Arel::Nodes::Node @@ -10,13 +11,13 @@ class DeleteStatement < Arel::Nodes::Node alias :wheres :right alias :wheres= :right= - def initialize relation = nil, wheres = [] + def initialize(relation = nil, wheres = []) super() @left = relation @right = wheres end - def initialize_copy other + def initialize_copy(other) super @left = @left.clone if @left @right = @right.clone if @right @@ -26,7 +27,7 @@ def hash [self.class, @left, @right].hash end - def eql? other + def eql?(other) self.class == other.class && self.left == other.left && self.right == other.right diff --git a/activerecord/lib/arel/nodes/descending.rb b/activerecord/lib/arel/nodes/descending.rb index d7261ab58323f..afcb6b1b71b44 100644 --- a/activerecord/lib/arel/nodes/descending.rb +++ b/activerecord/lib/arel/nodes/descending.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true + module Arel module Nodes class Descending < Ordering - def reverse Ascending.new(expr) end @@ -18,7 +18,6 @@ def ascending? def descending? true end - end end end diff --git a/activerecord/lib/arel/nodes/equality.rb b/activerecord/lib/arel/nodes/equality.rb index ef44725e24ea2..4ed545ae172ac 100644 --- a/activerecord/lib/arel/nodes/equality.rb +++ b/activerecord/lib/arel/nodes/equality.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Equality < Arel::Nodes::Binary diff --git a/activerecord/lib/arel/nodes/extract.rb b/activerecord/lib/arel/nodes/extract.rb index fdf3004c6ae2a..56069cd05a9b0 100644 --- a/activerecord/lib/arel/nodes/extract.rb +++ b/activerecord/lib/arel/nodes/extract.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true + module Arel module Nodes class Extract < Arel::Nodes::Unary attr_accessor :field - def initialize expr, field + def initialize(expr, field) super(expr) @field = field end @@ -13,7 +14,7 @@ def hash super ^ @field.hash end - def eql? other + def eql?(other) super && self.field == other.field end diff --git a/activerecord/lib/arel/nodes/false.rb b/activerecord/lib/arel/nodes/false.rb index 58132a2f90124..1759a323e381b 100644 --- a/activerecord/lib/arel/nodes/false.rb +++ b/activerecord/lib/arel/nodes/false.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class False < Arel::Nodes::NodeExpression @@ -6,7 +7,7 @@ def hash self.class.hash end - def eql? other + def eql?(other) self.class == other.class end alias :== :eql? diff --git a/activerecord/lib/arel/nodes/full_outer_join.rb b/activerecord/lib/arel/nodes/full_outer_join.rb index 12a02d8cd9bc9..3551855201f33 100644 --- a/activerecord/lib/arel/nodes/full_outer_join.rb +++ b/activerecord/lib/arel/nodes/full_outer_join.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class FullOuterJoin < Arel::Nodes::Join diff --git a/activerecord/lib/arel/nodes/function.rb b/activerecord/lib/arel/nodes/function.rb index b3bf8f3e51c62..f3415da12b39d 100644 --- a/activerecord/lib/arel/nodes/function.rb +++ b/activerecord/lib/arel/nodes/function.rb @@ -1,18 +1,19 @@ # frozen_string_literal: true + module Arel module Nodes class Function < Arel::Nodes::NodeExpression include Arel::WindowPredications attr_accessor :expressions, :alias, :distinct - def initialize expr, aliaz = nil + def initialize(expr, aliaz = nil) super() @expressions = expr @alias = aliaz && SqlLiteral.new(aliaz) @distinct = false end - def as aliaz + def as(aliaz) self.alias = SqlLiteral.new(aliaz) self end @@ -21,14 +22,13 @@ def hash [@expressions, @alias, @distinct].hash end - def eql? other + def eql?(other) self.class == other.class && self.expressions == other.expressions && self.alias == other.alias && self.distinct == other.distinct end alias :== :eql? - end %w{ diff --git a/activerecord/lib/arel/nodes/grouping.rb b/activerecord/lib/arel/nodes/grouping.rb index ffe66654ce9c1..b371b01612d87 100644 --- a/activerecord/lib/arel/nodes/grouping.rb +++ b/activerecord/lib/arel/nodes/grouping.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Grouping < Unary diff --git a/activerecord/lib/arel/nodes/in.rb b/activerecord/lib/arel/nodes/in.rb index 30cd771c4093d..5d24d345288bd 100644 --- a/activerecord/lib/arel/nodes/in.rb +++ b/activerecord/lib/arel/nodes/in.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class In < Equality diff --git a/activerecord/lib/arel/nodes/infix_operation.rb b/activerecord/lib/arel/nodes/infix_operation.rb index 4eb7c5356fb73..501da1173078a 100644 --- a/activerecord/lib/arel/nodes/infix_operation.rb +++ b/activerecord/lib/arel/nodes/infix_operation.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true + module Arel module Nodes - class InfixOperation < Binary include Arel::Expressions include Arel::Predications @@ -11,68 +11,68 @@ class InfixOperation < Binary attr_reader :operator - def initialize operator, left, right + def initialize(operator, left, right) super(left, right) @operator = operator end end class Multiplication < InfixOperation - def initialize left, right + def initialize(left, right) super(:*, left, right) end end class Division < InfixOperation - def initialize left, right + def initialize(left, right) super(:/, left, right) end end class Addition < InfixOperation - def initialize left, right + def initialize(left, right) super(:+, left, right) end end class Subtraction < InfixOperation - def initialize left, right + def initialize(left, right) super(:-, left, right) end end class Concat < InfixOperation - def initialize left, right - super('||', left, right) + def initialize(left, right) + super("||", left, right) end end class BitwiseAnd < InfixOperation - def initialize left, right + def initialize(left, right) super(:&, left, right) end end class BitwiseOr < InfixOperation - def initialize left, right + def initialize(left, right) super(:|, left, right) end end class BitwiseXor < InfixOperation - def initialize left, right + def initialize(left, right) super(:^, left, right) end end class BitwiseShiftLeft < InfixOperation - def initialize left, right + def initialize(left, right) super(:<<, left, right) end end class BitwiseShiftRight < InfixOperation - def initialize left, right + def initialize(left, right) super(:>>, left, right) end end diff --git a/activerecord/lib/arel/nodes/inner_join.rb b/activerecord/lib/arel/nodes/inner_join.rb index 4e398267c3731..8af99c2daeab0 100644 --- a/activerecord/lib/arel/nodes/inner_join.rb +++ b/activerecord/lib/arel/nodes/inner_join.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class InnerJoin < Arel::Nodes::Join diff --git a/activerecord/lib/arel/nodes/insert_statement.rb b/activerecord/lib/arel/nodes/insert_statement.rb index 72793bc1ad841..206d05e74fc0c 100644 --- a/activerecord/lib/arel/nodes/insert_statement.rb +++ b/activerecord/lib/arel/nodes/insert_statement.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class InsertStatement < Arel::Nodes::Node @@ -12,7 +13,7 @@ def initialize @select = nil end - def initialize_copy other + def initialize_copy(other) super @columns = @columns.clone @values = @values.clone if @values @@ -23,7 +24,7 @@ def hash [@relation, @columns, @values, @select].hash end - def eql? other + def eql?(other) self.class == other.class && self.relation == other.relation && self.columns == other.columns && diff --git a/activerecord/lib/arel/nodes/join_source.rb b/activerecord/lib/arel/nodes/join_source.rb index 428ce8183eace..9d009e8081787 100644 --- a/activerecord/lib/arel/nodes/join_source.rb +++ b/activerecord/lib/arel/nodes/join_source.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes ### @@ -7,7 +8,7 @@ module Nodes # http://www.sqlite.org/syntaxdiagrams.html#join-source class JoinSource < Arel::Nodes::Binary - def initialize single_source, joinop = [] + def initialize(single_source, joinop = []) super end diff --git a/activerecord/lib/arel/nodes/matches.rb b/activerecord/lib/arel/nodes/matches.rb index 3ad3850a8ea3e..607efe86dcdb3 100644 --- a/activerecord/lib/arel/nodes/matches.rb +++ b/activerecord/lib/arel/nodes/matches.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Matches < Binary diff --git a/activerecord/lib/arel/nodes/named_function.rb b/activerecord/lib/arel/nodes/named_function.rb index 173838a7fd20f..1d0baf2885c4e 100644 --- a/activerecord/lib/arel/nodes/named_function.rb +++ b/activerecord/lib/arel/nodes/named_function.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true + module Arel module Nodes class NamedFunction < Arel::Nodes::Function attr_accessor :name - def initialize name, expr, aliaz = nil + def initialize(name, expr, aliaz = nil) super(expr, aliaz) @name = name end @@ -13,7 +14,7 @@ def hash super ^ @name.hash end - def eql? other + def eql?(other) super && self.name == other.name end alias :== :eql? diff --git a/activerecord/lib/arel/nodes/node.rb b/activerecord/lib/arel/nodes/node.rb index d2e6313dda192..e2ce0a676d5cd 100644 --- a/activerecord/lib/arel/nodes/node.rb +++ b/activerecord/lib/arel/nodes/node.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes ### @@ -27,13 +28,13 @@ def not ### # Factory method to create a Nodes::Grouping node that has an Nodes::Or # node as a child. - def or right + def or(right) Nodes::Grouping.new Nodes::Or.new(self, right) end ### # Factory method to create an Nodes::And node. - def and right + def and(right) Nodes::And.new [self, right] end @@ -42,14 +43,14 @@ def and right # can find a node that has a "relation" member. # # Maybe we should just use `Table.engine`? :'( - def to_sql engine = Table.engine + def to_sql(engine = Table.engine) collector = Arel::Collectors::SQLString.new collector = engine.connection.visitor.accept self, collector collector.value end # Iterate through AST, nodes will be yielded depth-first - def each &block + def each(&block) return enum_for(:each) unless block_given? ::Arel::Visitors::DepthFirst.new(block).accept self diff --git a/activerecord/lib/arel/nodes/node_expression.rb b/activerecord/lib/arel/nodes/node_expression.rb index c4d4c8f428a0e..e69e3262d59e7 100644 --- a/activerecord/lib/arel/nodes/node_expression.rb +++ b/activerecord/lib/arel/nodes/node_expression.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Arel module Nodes class NodeExpression < Arel::Nodes::Node diff --git a/activerecord/lib/arel/nodes/outer_join.rb b/activerecord/lib/arel/nodes/outer_join.rb index c568655fe6612..2440be1f03519 100644 --- a/activerecord/lib/arel/nodes/outer_join.rb +++ b/activerecord/lib/arel/nodes/outer_join.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class OuterJoin < Arel::Nodes::Join diff --git a/activerecord/lib/arel/nodes/over.rb b/activerecord/lib/arel/nodes/over.rb index 47a34e69eaada..57baebe9b3897 100644 --- a/activerecord/lib/arel/nodes/over.rb +++ b/activerecord/lib/arel/nodes/over.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true + module Arel module Nodes - class Over < Binary include Arel::AliasPredication @@ -9,8 +9,7 @@ def initialize(left, right = nil) super(left, right) end - def operator; 'OVER' end + def operator; "OVER" end end - end -end \ No newline at end of file +end diff --git a/activerecord/lib/arel/nodes/regexp.rb b/activerecord/lib/arel/nodes/regexp.rb index 8a76185ef00d8..a2da51c135737 100644 --- a/activerecord/lib/arel/nodes/regexp.rb +++ b/activerecord/lib/arel/nodes/regexp.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Regexp < Binary diff --git a/activerecord/lib/arel/nodes/right_outer_join.rb b/activerecord/lib/arel/nodes/right_outer_join.rb index 04ab31ebf09e1..910eb0fa1fd8b 100644 --- a/activerecord/lib/arel/nodes/right_outer_join.rb +++ b/activerecord/lib/arel/nodes/right_outer_join.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class RightOuterJoin < Arel::Nodes::Join diff --git a/activerecord/lib/arel/nodes/select_core.rb b/activerecord/lib/arel/nodes/select_core.rb index fa1c026107a3c..1686761bd5d3a 100644 --- a/activerecord/lib/arel/nodes/select_core.rb +++ b/activerecord/lib/arel/nodes/select_core.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class SelectCore < Arel::Nodes::Node @@ -23,14 +24,14 @@ def from @source.left end - def from= value + def from=(value) @source.left = value end alias :froms= :from= alias :froms :from - def initialize_copy other + def initialize_copy(other) super @source = @source.clone if @source @projections = @projections.clone @@ -47,7 +48,7 @@ def hash ].hash end - def eql? other + def eql?(other) self.class == other.class && self.source == other.source && self.top == other.top && diff --git a/activerecord/lib/arel/nodes/select_statement.rb b/activerecord/lib/arel/nodes/select_statement.rb index 79176d4be5cea..d1c42dba3b826 100644 --- a/activerecord/lib/arel/nodes/select_statement.rb +++ b/activerecord/lib/arel/nodes/select_statement.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true + module Arel module Nodes class SelectStatement < Arel::Nodes::NodeExpression attr_reader :cores attr_accessor :limit, :orders, :lock, :offset, :with - def initialize cores = [SelectCore.new] + def initialize(cores = [SelectCore.new]) super() @cores = cores @orders = [] @@ -15,7 +16,7 @@ def initialize cores = [SelectCore.new] @with = nil end - def initialize_copy other + def initialize_copy(other) super @cores = @cores.map { |x| x.clone } @orders = @orders.map { |x| x.clone } @@ -25,7 +26,7 @@ def hash [@cores, @orders, @limit, @lock, @offset, @with].hash end - def eql? other + def eql?(other) self.class == other.class && self.cores == other.cores && self.orders == other.orders && diff --git a/activerecord/lib/arel/nodes/sql_literal.rb b/activerecord/lib/arel/nodes/sql_literal.rb index 73575a7d49223..1ee496f285c38 100644 --- a/activerecord/lib/arel/nodes/sql_literal.rb +++ b/activerecord/lib/arel/nodes/sql_literal.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class SqlLiteral < String diff --git a/activerecord/lib/arel/nodes/string_join.rb b/activerecord/lib/arel/nodes/string_join.rb index 21d6845c45eec..ba3f5f9535451 100644 --- a/activerecord/lib/arel/nodes/string_join.rb +++ b/activerecord/lib/arel/nodes/string_join.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true + module Arel module Nodes class StringJoin < Arel::Nodes::Join - def initialize left, right = nil + def initialize(left, right = nil) super end end diff --git a/activerecord/lib/arel/nodes/table_alias.rb b/activerecord/lib/arel/nodes/table_alias.rb index 78deb175b66ae..37ad786d44851 100644 --- a/activerecord/lib/arel/nodes/table_alias.rb +++ b/activerecord/lib/arel/nodes/table_alias.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class TableAlias < Arel::Nodes::Binary @@ -6,7 +7,7 @@ class TableAlias < Arel::Nodes::Binary alias :relation :left alias :table_alias :name - def [] name + def [](name) Attribute.new(self, name) end diff --git a/activerecord/lib/arel/nodes/terminal.rb b/activerecord/lib/arel/nodes/terminal.rb index 3a1cd7f0e13af..7cfd2eba4b4fe 100644 --- a/activerecord/lib/arel/nodes/terminal.rb +++ b/activerecord/lib/arel/nodes/terminal.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Distinct < Arel::Nodes::NodeExpression @@ -6,7 +7,7 @@ def hash self.class.hash end - def eql? other + def eql?(other) self.class == other.class end alias :== :eql? diff --git a/activerecord/lib/arel/nodes/true.rb b/activerecord/lib/arel/nodes/true.rb index fdb8ed2095d0c..8de1f7522f7f2 100644 --- a/activerecord/lib/arel/nodes/true.rb +++ b/activerecord/lib/arel/nodes/true.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class True < Arel::Nodes::NodeExpression @@ -6,7 +7,7 @@ def hash self.class.hash end - def eql? other + def eql?(other) self.class == other.class end alias :== :eql? diff --git a/activerecord/lib/arel/nodes/unary.rb b/activerecord/lib/arel/nodes/unary.rb index e458d87ab3bec..27dd2c1ddf4c0 100644 --- a/activerecord/lib/arel/nodes/unary.rb +++ b/activerecord/lib/arel/nodes/unary.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true + module Arel module Nodes class Unary < Arel::Nodes::NodeExpression attr_accessor :expr alias :value :expr - def initialize expr + def initialize(expr) super() @expr = expr end @@ -14,7 +15,7 @@ def hash @expr.hash end - def eql? other + def eql?(other) self.class == other.class && self.expr == other.expr end diff --git a/activerecord/lib/arel/nodes/unary_operation.rb b/activerecord/lib/arel/nodes/unary_operation.rb index be4e270e763cf..a64346d278723 100644 --- a/activerecord/lib/arel/nodes/unary_operation.rb +++ b/activerecord/lib/arel/nodes/unary_operation.rb @@ -1,18 +1,18 @@ # frozen_string_literal: true + module Arel module Nodes - class UnaryOperation < Unary attr_reader :operator - def initialize operator, operand + def initialize(operator, operand) super(operand) @operator = operator end end class BitwiseNot < UnaryOperation - def initialize operand + def initialize(operand) super(:~, operand) end end diff --git a/activerecord/lib/arel/nodes/unqualified_column.rb b/activerecord/lib/arel/nodes/unqualified_column.rb index f9017238c8aaa..216a35bc305d8 100644 --- a/activerecord/lib/arel/nodes/unqualified_column.rb +++ b/activerecord/lib/arel/nodes/unqualified_column.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class UnqualifiedColumn < Arel::Nodes::Unary diff --git a/activerecord/lib/arel/nodes/update_statement.rb b/activerecord/lib/arel/nodes/update_statement.rb index 286f0bd3cecf2..5cce1e3615470 100644 --- a/activerecord/lib/arel/nodes/update_statement.rb +++ b/activerecord/lib/arel/nodes/update_statement.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class UpdateStatement < Arel::Nodes::Node @@ -14,7 +15,7 @@ def initialize @key = nil end - def initialize_copy other + def initialize_copy(other) super @wheres = @wheres.clone @values = @values.clone @@ -24,7 +25,7 @@ def hash [@relation, @wheres, @values, @orders, @limit, @key].hash end - def eql? other + def eql?(other) self.class == other.class && self.relation == other.relation && self.wheres == other.wheres && diff --git a/activerecord/lib/arel/nodes/values.rb b/activerecord/lib/arel/nodes/values.rb index b32d5063a20c9..8554440be6bba 100644 --- a/activerecord/lib/arel/nodes/values.rb +++ b/activerecord/lib/arel/nodes/values.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Values < Arel::Nodes::Binary @@ -7,7 +8,7 @@ class Values < Arel::Nodes::Binary alias :columns :right alias :columns= :right= - def initialize exprs, columns = [] + def initialize(exprs, columns = []) super end end diff --git a/activerecord/lib/arel/nodes/values_list.rb b/activerecord/lib/arel/nodes/values_list.rb index 89cea1790d0d4..e68518d6841f3 100644 --- a/activerecord/lib/arel/nodes/values_list.rb +++ b/activerecord/lib/arel/nodes/values_list.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class ValuesList < Node @@ -13,7 +14,7 @@ def hash @rows.hash end - def eql? other + def eql?(other) self.class == other.class && self.rows == other.rows end diff --git a/activerecord/lib/arel/nodes/window.rb b/activerecord/lib/arel/nodes/window.rb index 23a005daba2f0..1f14630c81786 100644 --- a/activerecord/lib/arel/nodes/window.rb +++ b/activerecord/lib/arel/nodes/window.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class Window < Arel::Nodes::Node @@ -10,7 +11,7 @@ def initialize @framing = nil end - def order *expr + 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 @@ -18,7 +19,7 @@ def order *expr self end - def partition *expr + def partition(*expr) # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @partitions.concat expr.map { |x| String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x @@ -46,7 +47,7 @@ def range(expr = nil) end end - def initialize_copy other + def initialize_copy(other) super @orders = @orders.map { |x| x.clone } end @@ -55,7 +56,7 @@ def hash [@orders, @framing].hash end - def eql? other + def eql?(other) self.class == other.class && self.orders == other.orders && self.framing == other.framing && @@ -67,12 +68,12 @@ def eql? other class NamedWindow < Window attr_accessor :name - def initialize name + def initialize(name) super() @name = name end - def initialize_copy other + def initialize_copy(other) super @name = other.name.clone end @@ -81,7 +82,7 @@ def hash super ^ @name.hash end - def eql? other + def eql?(other) super && self.name == other.name end alias :== :eql? @@ -104,7 +105,7 @@ def hash self.class.hash end - def eql? other + def eql?(other) self.class == other.class end alias :== :eql? diff --git a/activerecord/lib/arel/nodes/with.rb b/activerecord/lib/arel/nodes/with.rb index def7840ea3720..a0fbf87e8e9c7 100644 --- a/activerecord/lib/arel/nodes/with.rb +++ b/activerecord/lib/arel/nodes/with.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Nodes class With < Arel::Nodes::Unary @@ -8,4 +9,3 @@ class With < Arel::Nodes::Unary class WithRecursive < With; end end end - diff --git a/activerecord/lib/arel/order_predications.rb b/activerecord/lib/arel/order_predications.rb index d84be82bb6ba8..a0f15cb4d6211 100644 --- a/activerecord/lib/arel/order_predications.rb +++ b/activerecord/lib/arel/order_predications.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true + module Arel module OrderPredications - def asc Nodes::Ascending.new self end @@ -9,6 +9,5 @@ def asc def desc Nodes::Descending.new self end - end end diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 799c7c67b82ea..1e701586a4bda 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -1,31 +1,32 @@ # frozen_string_literal: true + module Arel module Predications - def not_eq other + def not_eq(other) Nodes::NotEqual.new self, quoted_node(other) end - def not_eq_any others + def not_eq_any(others) grouping_any :not_eq, others end - def not_eq_all others + def not_eq_all(others) grouping_all :not_eq, others end - def eq other + def eq(other) Nodes::Equality.new self, quoted_node(other) end - def eq_any others + def eq_any(others) grouping_any :eq, others end - def eq_all others + def eq_all(others) grouping_all :eq, quoted_array(others) end - def between other + def between(other) if equals_quoted?(other.begin, -Float::INFINITY) if equals_quoted?(other.end, Float::INFINITY) not_in([]) @@ -45,7 +46,7 @@ def between other end end - def in other + def in(other) case other when Arel::SelectManager Arel::Nodes::In.new(self, other.ast) @@ -63,15 +64,15 @@ def in other end end - def in_any others + def in_any(others) grouping_any :in, others end - def in_all others + def in_all(others) grouping_all :in, others end - def not_between other + def not_between(other) if equals_quoted?(other.begin, -Float::INFINITY) if equals_quoted?(other.end, Float::INFINITY) self.in([]) @@ -93,7 +94,7 @@ def not_between other end end - def not_in other + def not_in(other) case other when Arel::SelectManager Arel::Nodes::NotIn.new(self, other.ast) @@ -111,130 +112,130 @@ def not_in other end end - def not_in_any others + def not_in_any(others) grouping_any :not_in, others end - def not_in_all others + def not_in_all(others) grouping_all :not_in, others end - def matches other, escape = nil, case_sensitive = false + def matches(other, escape = nil, case_sensitive = false) Nodes::Matches.new self, quoted_node(other), escape, case_sensitive end - def matches_regexp other, case_sensitive = true + def matches_regexp(other, case_sensitive = true) Nodes::Regexp.new self, quoted_node(other), case_sensitive end - def matches_any others, escape = nil, case_sensitive = false + def matches_any(others, escape = nil, case_sensitive = false) grouping_any :matches, others, escape, case_sensitive end - def matches_all others, escape = nil, case_sensitive = false + def matches_all(others, escape = nil, case_sensitive = false) grouping_all :matches, others, escape, case_sensitive end - def does_not_match other, escape = nil, case_sensitive = false + def does_not_match(other, escape = nil, case_sensitive = false) Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive end - def does_not_match_regexp other, case_sensitive = true + def does_not_match_regexp(other, case_sensitive = true) Nodes::NotRegexp.new self, quoted_node(other), case_sensitive end - def does_not_match_any others, escape = nil + def does_not_match_any(others, escape = nil) grouping_any :does_not_match, others, escape end - def does_not_match_all others, escape = nil + def does_not_match_all(others, escape = nil) grouping_all :does_not_match, others, escape end - def gteq right + def gteq(right) Nodes::GreaterThanOrEqual.new self, quoted_node(right) end - def gteq_any others + def gteq_any(others) grouping_any :gteq, others end - def gteq_all others + def gteq_all(others) grouping_all :gteq, others end - def gt right + def gt(right) Nodes::GreaterThan.new self, quoted_node(right) end - def gt_any others + def gt_any(others) grouping_any :gt, others end - def gt_all others + def gt_all(others) grouping_all :gt, others end - def lt right + def lt(right) Nodes::LessThan.new self, quoted_node(right) end - def lt_any others + def lt_any(others) grouping_any :lt, others end - def lt_all others + def lt_all(others) grouping_all :lt, others end - def lteq right + def lteq(right) Nodes::LessThanOrEqual.new self, quoted_node(right) end - def lteq_any others + def lteq_any(others) grouping_any :lteq, others end - def lteq_all others + def lteq_all(others) grouping_all :lteq, others end - def when right + def when(right) Nodes::Case.new(self).when quoted_node(right) end - def concat other + def concat(other) Nodes::Concat.new self, other end private - def grouping_any method_id, others, *extras - nodes = others.map {|expr| send(method_id, expr, *extras)} - Nodes::Grouping.new nodes.inject { |memo,node| - Nodes::Or.new(memo, node) - } - end + def grouping_any(method_id, others, *extras) + nodes = others.map { |expr| send(method_id, expr, *extras) } + Nodes::Grouping.new nodes.inject { |memo, node| + Nodes::Or.new(memo, node) + } + end - def grouping_all method_id, others, *extras - nodes = others.map {|expr| send(method_id, expr, *extras)} - Nodes::Grouping.new Nodes::And.new(nodes) - end + def grouping_all(method_id, others, *extras) + nodes = others.map { |expr| send(method_id, expr, *extras) } + Nodes::Grouping.new Nodes::And.new(nodes) + end - def quoted_node(other) - Nodes.build_quoted(other, self) - end + def quoted_node(other) + Nodes.build_quoted(other, self) + end - def quoted_array(others) - others.map { |v| quoted_node(v) } - end + def quoted_array(others) + others.map { |v| quoted_node(v) } + end - def equals_quoted?(maybe_quoted, value) - if maybe_quoted.is_a?(Nodes::Quoted) - maybe_quoted.val == value - else - maybe_quoted == value + def equals_quoted?(maybe_quoted, value) + if maybe_quoted.is_a?(Nodes::Quoted) + maybe_quoted.val == value + else + maybe_quoted == value + end end - end end end diff --git a/activerecord/lib/arel/select_manager.rb b/activerecord/lib/arel/select_manager.rb index 0f3b0dc6a0481..dc61447d01c93 100644 --- a/activerecord/lib/arel/select_manager.rb +++ b/activerecord/lib/arel/select_manager.rb @@ -1,18 +1,19 @@ # frozen_string_literal: true + module Arel class SelectManager < Arel::TreeManager include Arel::Crud STRING_OR_SYMBOL_CLASS = [Symbol, String] - def initialize table = nil + def initialize(table = nil) super() - @ast = Nodes::SelectStatement.new - @ctx = @ast.cores.last + @ast = Nodes::SelectStatement.new + @ctx = @ast.cores.last from table end - def initialize_copy other + def initialize_copy(other) super @ctx = @ast.cores.last end @@ -30,7 +31,7 @@ def offset @ast.offset && @ast.offset.expr end - def skip amount + def skip(amount) if amount @ast.offset = Nodes::Offset.new(amount) else @@ -46,14 +47,14 @@ def exists Arel::Nodes::Exists.new @ast end - def as other + def as(other) create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other) end - def lock locking = Arel.sql('FOR UPDATE') + def lock(locking = Arel.sql("FOR UPDATE")) case locking when true - locking = Arel.sql('FOR UPDATE') + locking = Arel.sql("FOR UPDATE") when Arel::Nodes::SqlLiteral when String locking = Arel.sql locking @@ -67,12 +68,12 @@ def locked @ast.lock end - def on *exprs + def on(*exprs) @ctx.source.right.last.right = Nodes::On.new(collapse(exprs)) self end - def group *columns + def group(*columns) columns.each do |column| # FIXME: backwards compat column = Nodes::SqlLiteral.new(column) if String === column @@ -83,7 +84,7 @@ def group *columns self end - def from table + def from(table) table = Nodes::SqlLiteral.new(table) if String === table case table @@ -100,7 +101,7 @@ def froms @ast.cores.map { |x| x.from }.compact end - def join relation, klass = Nodes::InnerJoin + def join(relation, klass = Nodes::InnerJoin) return self unless relation case relation @@ -113,22 +114,22 @@ def join relation, klass = Nodes::InnerJoin self end - def outer_join relation + def outer_join(relation) join(relation, Nodes::OuterJoin) end - def having expr + def having(expr) @ctx.havings << expr self end - def window name + def window(name) window = Nodes::NamedWindow.new(name) @ctx.windows.push window window end - def project *projections + def project(*projections) # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. @ctx.projections.concat projections.map { |x| @@ -141,7 +142,7 @@ def projections @ctx.projections end - def projections= projections + def projections=(projections) @ctx.projections = projections end @@ -163,7 +164,7 @@ def distinct_on(value) self end - def order *expr + def order(*expr) # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x @@ -175,14 +176,14 @@ def orders @ast.orders end - def where_sql engine = Table.engine + def where_sql(engine = Table.engine) return if @ctx.wheres.empty? viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection) Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value end - def union operation, other = nil + def union(operation, other = nil) if other node_class = Nodes.const_get("Union#{operation.to_s.capitalize}") else @@ -193,21 +194,21 @@ def union operation, other = nil node_class.new self.ast, other.ast end - def intersect other + def intersect(other) Nodes::Intersect.new ast, other.ast end - def except other + def except(other) Nodes::Except.new ast, other.ast end alias :minus :except - def lateral table_name = nil + def lateral(table_name = nil) base = table_name.nil? ? ast : as(table_name) Nodes::Lateral.new(base) end - def with *subqueries + def with(*subqueries) if subqueries.first.is_a? Symbol node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") else @@ -218,7 +219,7 @@ def with *subqueries self end - def take limit + def take(limit) if limit @ast.limit = Nodes::Limit.new(limit) @ctx.top = Nodes::Top.new(limit) @@ -240,7 +241,7 @@ def source class Row < Struct.new(:data) # :nodoc: def id - data['id'] + data["id"] end def method_missing(name, *args) @@ -251,22 +252,22 @@ def method_missing(name, *args) 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) + 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 - expr + create_and exprs end - } - - if exprs.length == 1 - exprs.first - else - create_and exprs end - end end end diff --git a/activerecord/lib/arel/table.rb b/activerecord/lib/arel/table.rb index b3f2d79e5ffb6..2df2c4c514759 100644 --- a/activerecord/lib/arel/table.rb +++ b/activerecord/lib/arel/table.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel class Table include Arel::Crud @@ -13,7 +14,7 @@ class << self; attr_accessor :engine; end alias :table_name :name def initialize(name, as: nil, type_caster: nil) - @name = name.to_s + @name = name.to_s @type_caster = type_caster # Sometime AR sends an :as parameter to table, to let the table know @@ -25,7 +26,7 @@ def initialize(name, as: nil, type_caster: nil) @table_alias = as end - def alias name = "#{self.name}_2" + def alias(name = "#{self.name}_2") Nodes::TableAlias.new(self, name) end @@ -33,7 +34,7 @@ def from SelectManager.new(self) end - def join relation, klass = Nodes::InnerJoin + def join(relation, klass = Nodes::InnerJoin) return from unless relation case relation @@ -45,39 +46,39 @@ def join relation, klass = Nodes::InnerJoin from.join(relation, klass) end - def outer_join relation + def outer_join(relation) join(relation, Nodes::OuterJoin) end - def group *columns + def group(*columns) from.group(*columns) end - def order *expr + def order(*expr) from.order(*expr) end - def where condition + def where(condition) from.where condition end - def project *things + def project(*things) from.project(*things) end - def take amount + def take(amount) from.take amount end - def skip amount + def skip(amount) from.skip amount end - def having expr + def having(expr) from.having expr end - def [] name + def [](name) ::Arel::Attribute.new self, name end @@ -88,7 +89,7 @@ def hash @name.hash end - def eql? other + def eql?(other) self.class == other.class && self.name == other.name && self.table_alias == other.table_alias @@ -105,6 +106,6 @@ def able_to_type_cast? protected - attr_reader :type_caster + attr_reader :type_caster end end diff --git a/activerecord/lib/arel/tree_manager.rb b/activerecord/lib/arel/tree_manager.rb index b237bf368d2ed..f6ec1415fa08b 100644 --- a/activerecord/lib/arel/tree_manager.rb +++ b/activerecord/lib/arel/tree_manager.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel class TreeManager include Arel::FactoryMethods @@ -15,18 +16,18 @@ def to_dot collector.value end - def to_sql engine = Table.engine + def to_sql(engine = Table.engine) collector = Arel::Collectors::SQLString.new collector = engine.connection.visitor.accept @ast, collector collector.value end - def initialize_copy other + def initialize_copy(other) super @ast = @ast.clone end - def where expr + def where(expr) if Arel::TreeManager === expr expr = expr.ast end diff --git a/activerecord/lib/arel/update_manager.rb b/activerecord/lib/arel/update_manager.rb index eac414eafb97b..6e36e82cf9a87 100644 --- a/activerecord/lib/arel/update_manager.rb +++ b/activerecord/lib/arel/update_manager.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel class UpdateManager < Arel::TreeManager def initialize @@ -7,12 +8,12 @@ def initialize @ctx = @ast end - def take limit + def take(limit) @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit self end - def key= key + def key=(key) @ast.key = Nodes.build_quoted(key) end @@ -20,32 +21,32 @@ def key @ast.key end - def order *expr + def order(*expr) @ast.orders = expr self end ### # UPDATE +table+ - def table table + def table(table) @ast.relation = table self end - def wheres= exprs + def wheres=(exprs) @ast.wheres = exprs end - def where expr + def where(expr) @ast.wheres << expr self end - def set values + def set(values) if String === values @ast.values = [values] else - @ast.values = values.map { |column,value| + @ast.values = values.map { |column, value| Nodes::Assignment.new( Nodes::UnqualifiedColumn.new(column), value diff --git a/activerecord/lib/arel/visitors.rb b/activerecord/lib/arel/visitors.rb index a3404cf99207f..fb44721117485 100644 --- a/activerecord/lib/arel/visitors.rb +++ b/activerecord/lib/arel/visitors.rb @@ -1,17 +1,18 @@ # frozen_string_literal: true -require '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/oracle12' -require 'arel/visitors/where_sql' -require 'arel/visitors/dot' -require 'arel/visitors/ibm_db' -require 'arel/visitors/informix' + +require "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/oracle12" +require "arel/visitors/where_sql" +require "arel/visitors/dot" +require "arel/visitors/ibm_db" +require "arel/visitors/informix" module Arel module Visitors diff --git a/activerecord/lib/arel/visitors/depth_first.rb b/activerecord/lib/arel/visitors/depth_first.rb index b3bbc9bd40711..fb32ef59ade62 100644 --- a/activerecord/lib/arel/visitors/depth_first.rb +++ b/activerecord/lib/arel/visitors/depth_first.rb @@ -1,199 +1,200 @@ # frozen_string_literal: true + module Arel module Visitors class DepthFirst < Arel::Visitors::Visitor - def initialize block = nil + def initialize(block = nil) @block = block || Proc.new super() end private - def visit o - super - @block.call o - end - - def unary o - visit o.expr - end - alias :visit_Arel_Nodes_Else :unary - alias :visit_Arel_Nodes_Group :unary - alias :visit_Arel_Nodes_Cube :unary - alias :visit_Arel_Nodes_RollUp :unary - alias :visit_Arel_Nodes_GroupingSet :unary - alias :visit_Arel_Nodes_GroupingElement :unary - alias :visit_Arel_Nodes_Grouping :unary - alias :visit_Arel_Nodes_Having :unary - alias :visit_Arel_Nodes_Lateral :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 visit_Arel_Nodes_Case o - visit o.case - visit o.conditions - visit o.default - 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_Concat :binary - alias :visit_Arel_Nodes_DeleteStatement :binary - alias :visit_Arel_Nodes_DoesNotMatch :binary - alias :visit_Arel_Nodes_Equality :binary - alias :visit_Arel_Nodes_FullOuterJoin :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_NotRegexp :binary - alias :visit_Arel_Nodes_Or :binary - alias :visit_Arel_Nodes_OuterJoin :binary - alias :visit_Arel_Nodes_Regexp :binary - alias :visit_Arel_Nodes_RightOuterJoin :binary - alias :visit_Arel_Nodes_TableAlias :binary - alias :visit_Arel_Nodes_Values :binary - alias :visit_Arel_Nodes_When :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_Nodes_True :terminal - alias :visit_Arel_Nodes_False :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_Integer :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.havings - 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 - alias :visit_Set :visit_Array - - def visit_Hash o - o.each { |k,v| visit(k); visit(v) } - end - - DISPATCH = dispatch_cache - - def get_dispatch_cache - DISPATCH - end + def visit(o) + super + @block.call o + end + + def unary(o) + visit o.expr + end + alias :visit_Arel_Nodes_Else :unary + alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Cube :unary + alias :visit_Arel_Nodes_RollUp :unary + alias :visit_Arel_Nodes_GroupingSet :unary + alias :visit_Arel_Nodes_GroupingElement :unary + alias :visit_Arel_Nodes_Grouping :unary + alias :visit_Arel_Nodes_Having :unary + alias :visit_Arel_Nodes_Lateral :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 visit_Arel_Nodes_Case(o) + visit o.case + visit o.conditions + visit o.default + 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_Concat :binary + alias :visit_Arel_Nodes_DeleteStatement :binary + alias :visit_Arel_Nodes_DoesNotMatch :binary + alias :visit_Arel_Nodes_Equality :binary + alias :visit_Arel_Nodes_FullOuterJoin :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_NotRegexp :binary + alias :visit_Arel_Nodes_Or :binary + alias :visit_Arel_Nodes_OuterJoin :binary + alias :visit_Arel_Nodes_Regexp :binary + alias :visit_Arel_Nodes_RightOuterJoin :binary + alias :visit_Arel_Nodes_TableAlias :binary + alias :visit_Arel_Nodes_Values :binary + alias :visit_Arel_Nodes_When :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_Nodes_True :terminal + alias :visit_Arel_Nodes_False :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_Integer :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.havings + 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 + alias :visit_Set :visit_Array + + def visit_Hash(o) + o.each { |k, v| visit(k); visit(v) } + end + + DISPATCH = dispatch_cache + + def get_dispatch_cache + DISPATCH + end end end end diff --git a/activerecord/lib/arel/visitors/dot.rb b/activerecord/lib/arel/visitors/dot.rb index 9aa22d33f632f..2b285ac775819 100644 --- a/activerecord/lib/arel/visitors/dot.rb +++ b/activerecord/lib/arel/visitors/dot.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true + module Arel module Visitors class Dot < Arel::Visitors::Visitor class Node # :nodoc: attr_accessor :name, :id, :fields - def initialize name, id, fields = [] + def initialize(name, id, fields = []) @name = name @id = id @fields = fields @@ -24,268 +25,268 @@ def initialize @seen = {} end - def accept object, collector + def accept(object, collector) visit object collector << 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_Ordering(o) + visit_edge o, "expr" + end - def visit_Arel_Nodes_Count o - visit_edge o, "expressions" - visit_edge o, "distinct" - end + def visit_Arel_Nodes_TableAlias(o) + visit_edge o, "name" + visit_edge o, "relation" + end - def visit_Arel_Nodes_Values o - visit_edge o, "expressions" - end + def visit_Arel_Nodes_Count(o) + visit_edge o, "expressions" + visit_edge o, "distinct" + end - def visit_Arel_Nodes_StringJoin o - visit_edge o, "left" - end + def visit_Arel_Nodes_Values(o) + visit_edge o, "expressions" + end - def visit_Arel_Nodes_InnerJoin o - visit_edge o, "left" - visit_edge o, "right" - end - alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin - alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin - alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin + def visit_Arel_Nodes_StringJoin(o) + visit_edge o, "left" + end - def visit_Arel_Nodes_DeleteStatement o - visit_edge o, "relation" - visit_edge o, "wheres" - end + def visit_Arel_Nodes_InnerJoin(o) + visit_edge o, "left" + visit_edge o, "right" + end + alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin + alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin - def unary o - visit_edge o, "expr" - end - alias :visit_Arel_Nodes_Group :unary - alias :visit_Arel_Nodes_Cube :unary - alias :visit_Arel_Nodes_RollUp :unary - alias :visit_Arel_Nodes_GroupingSet :unary - alias :visit_Arel_Nodes_GroupingElement :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, "partitions" - visit_edge o, "orders" - visit_edge o, "framing" - end - alias :visit_Arel_Nodes_Window :window + def visit_Arel_Nodes_DeleteStatement(o) + visit_edge o, "relation" + visit_edge o, "wheres" + end - def named_window o - visit_edge o, "partitions" - visit_edge o, "orders" - visit_edge o, "framing" - visit_edge o, "name" - end - alias :visit_Arel_Nodes_NamedWindow :named_window + def unary(o) + visit_edge o, "expr" + end + alias :visit_Arel_Nodes_Group :unary + alias :visit_Arel_Nodes_Cube :unary + alias :visit_Arel_Nodes_RollUp :unary + alias :visit_Arel_Nodes_GroupingSet :unary + alias :visit_Arel_Nodes_GroupingElement :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, "partitions" + visit_edge o, "orders" + visit_edge o, "framing" + end + alias :visit_Arel_Nodes_Window :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 named_window(o) + visit_edge o, "partitions" + visit_edge o, "orders" + visit_edge o, "framing" + visit_edge o, "name" + end + alias :visit_Arel_Nodes_NamedWindow :named_window - def visit_Arel_Nodes_NamedFunction o - visit_edge o, "name" - visit_edge o, "expressions" - visit_edge o, "distinct" - visit_edge o, "alias" - end + 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_InsertStatement o - visit_edge o, "relation" - visit_edge o, "columns" - visit_edge o, "values" - end + 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_SelectCore o - visit_edge o, "source" - visit_edge o, "projections" - visit_edge o, "wheres" - visit_edge o, "windows" - end + def visit_Arel_Nodes_InsertStatement(o) + visit_edge o, "relation" + visit_edge o, "columns" + visit_edge o, "values" + 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_SelectCore(o) + visit_edge o, "source" + visit_edge o, "projections" + visit_edge o, "wheres" + visit_edge o, "windows" + end - def visit_Arel_Nodes_UpdateStatement o - visit_edge o, "relation" - visit_edge o, "wheres" - visit_edge o, "values" - 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_Table o - visit_edge o, "name" - end + def visit_Arel_Nodes_UpdateStatement(o) + visit_edge o, "relation" + visit_edge o, "wheres" + visit_edge o, "values" + end - def visit_Arel_Nodes_Casted o - visit_edge o, 'val' - visit_edge o, 'attribute' - 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 visit_Arel_Nodes_Casted(o) + visit_edge o, "val" + visit_edge o, "attribute" + end - def nary o - o.children.each_with_index do |x,i| - edge(i) { visit x } + def visit_Arel_Attribute(o) + visit_edge o, "relation" + visit_edge o, "name" end - end - alias :visit_Arel_Nodes_And :nary + 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_Concat :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_Integer :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_Arel_Nodes_BindParam o; end - - def visit_Hash o - o.each_with_index do |pair, i| - edge("pair_#{i}") { visit pair } + 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_Concat :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_Integer :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_Arel_Nodes_BindParam(o); end + + def visit_Hash(o) + o.each_with_index do |pair, i| + edge("pair_#{i}") { visit pair } + end end - end - def visit_Array o - o.each_with_index do |x,i| - edge(i) { visit x } + def visit_Array(o) + o.each_with_index do |x, i| + edge(i) { visit x } + end end - end - alias :visit_Set :visit_Array + alias :visit_Set :visit_Array - def visit_edge o, method - edge(method) { visit o.send(method) } - 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 + 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 - node = Node.new(o.class.name, o.object_id) - @seen[node.id] = node - @nodes << node - with_node node do - super + def edge(name) + edge = Edge.new(name, @node_stack.last) + @edge_stack.push edge + @edges << edge + yield + @edge_stack.pop 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 - def with_node node - if edge = @edge_stack.last - edge.to = node + @node_stack.push node + yield + @node_stack.pop end - @node_stack.push node - yield - @node_stack.pop - end - - def quote string - string.to_s.gsub('"', '\"') - 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}" + 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.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 + "#{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 diff --git a/activerecord/lib/arel/visitors/ibm_db.rb b/activerecord/lib/arel/visitors/ibm_db.rb index e85a5a08a7fcc..0291e434c90a8 100644 --- a/activerecord/lib/arel/visitors/ibm_db.rb +++ b/activerecord/lib/arel/visitors/ibm_db.rb @@ -1,15 +1,15 @@ # frozen_string_literal: true + module Arel module Visitors class IBM_DB < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Limit o, collector - collector << "FETCH FIRST " - collector = visit o.expr, collector - collector << " ROWS ONLY" - end - + def visit_Arel_Nodes_Limit(o, collector) + collector << "FETCH FIRST " + collector = visit o.expr, collector + collector << " ROWS ONLY" + end end end end diff --git a/activerecord/lib/arel/visitors/informix.rb b/activerecord/lib/arel/visitors/informix.rb index 44b18b550ef59..9df5a60bc2c17 100644 --- a/activerecord/lib/arel/visitors/informix.rb +++ b/activerecord/lib/arel/visitors/informix.rb @@ -1,55 +1,55 @@ # frozen_string_literal: true + module Arel module Visitors class Informix < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o, collector - collector << "SELECT " - collector = maybe_visit o.offset, collector - collector = maybe_visit o.limit, collector - collector = o.cores.inject(collector) { |c,x| - visit_Arel_Nodes_SelectCore x, c - } - if o.orders.any? - collector << "ORDER BY " - collector = inject_join o.orders, collector, ", " - end - collector = maybe_visit o.lock, collector - end - def visit_Arel_Nodes_SelectCore o, collector - collector = inject_join o.projections, collector, ", " - if o.source && !o.source.empty? - collector << " FROM " - collector = visit o.source, collector + def visit_Arel_Nodes_SelectStatement(o, collector) + collector << "SELECT " + collector = maybe_visit o.offset, collector + collector = maybe_visit o.limit, collector + collector = o.cores.inject(collector) { |c, x| + visit_Arel_Nodes_SelectCore x, c + } + if o.orders.any? + collector << "ORDER BY " + collector = inject_join o.orders, collector, ", " + end + collector = maybe_visit o.lock, collector end + def visit_Arel_Nodes_SelectCore(o, collector) + collector = inject_join o.projections, collector, ", " + if o.source && !o.source.empty? + collector << " FROM " + collector = visit o.source, collector + end - if o.wheres.any? - collector << " WHERE " - collector = inject_join o.wheres, collector, " AND " - end + if o.wheres.any? + collector << " WHERE " + collector = inject_join o.wheres, collector, " AND " + end - if o.groups.any? - collector << "GROUP BY " - collector = inject_join o.groups, collector, ", " - end + if o.groups.any? + collector << "GROUP BY " + collector = inject_join o.groups, collector, ", " + end - if o.havings.any? - collector << " HAVING " - collector = inject_join o.havings, collector, " AND " + if o.havings.any? + collector << " HAVING " + collector = inject_join o.havings, collector, " AND " + end + collector end - collector - end - def visit_Arel_Nodes_Offset o, collector - collector << "SKIP " - visit o.expr, collector - end - def visit_Arel_Nodes_Limit o, collector - collector << "FIRST " - visit o.expr, collector - collector << " " - end + def visit_Arel_Nodes_Offset(o, collector) + collector << "SKIP " + visit o.expr, collector + end + def visit_Arel_Nodes_Limit(o, collector) + collector << "FIRST " + visit o.expr, collector + collector << " " + end end end end - diff --git a/activerecord/lib/arel/visitors/mssql.rb b/activerecord/lib/arel/visitors/mssql.rb index 8347d05d067b0..4f2945e3a4ef9 100644 --- a/activerecord/lib/arel/visitors/mssql.rb +++ b/activerecord/lib/arel/visitors/mssql.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Visitors class MSSQL < Arel::Visitors::ToSql @@ -11,114 +12,114 @@ def initialize(*) 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_Visitors_MSSQL_RowNumber o, collector - collector << "ROW_NUMBER() OVER (ORDER BY " - inject_join(o.children, collector, ', ') << ") as _row_num" - end + # `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, collector - if !o.limit && !o.offset - return super + def visit_Arel_Visitors_MSSQL_RowNumber(o, collector) + collector << "ROW_NUMBER() OVER (ORDER BY " + inject_join(o.children, collector, ", ") << ") as _row_num" end - is_select_count = false - o.cores.each { |x| - core_order_by = row_num_literal determine_order_by(o.orders, x) - if select_count? x - x.projections = [core_order_by] - is_select_count = true - else - x.projections << core_order_by + def visit_Arel_Nodes_SelectStatement(o, collector) + if !o.limit && !o.offset + return super end - } - if is_select_count - # fixme count distinct wouldn't work with limit or offset - collector << "SELECT COUNT(1) as count_id FROM (" - end + is_select_count = false + o.cores.each { |x| + core_order_by = row_num_literal determine_order_by(o.orders, x) + if select_count? x + x.projections = [core_order_by] + is_select_count = true + else + x.projections << core_order_by + end + } + + if is_select_count + # fixme count distinct wouldn't work with limit or offset + collector << "SELECT COUNT(1) as count_id FROM (" + end - collector << "SELECT _t.* FROM (" - collector = o.cores.inject(collector) { |c,x| - visit_Arel_Nodes_SelectCore x, c - } - collector << ") as _t WHERE #{get_offset_limit_clause(o)}" + collector << "SELECT _t.* FROM (" + collector = o.cores.inject(collector) { |c, x| + visit_Arel_Nodes_SelectCore x, c + } + collector << ") as _t WHERE #{get_offset_limit_clause(o)}" - if is_select_count - collector << ") AS subquery" - else - collector + if is_select_count + collector << ") AS subquery" + else + collector + end end - 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}" + 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 - end - def visit_Arel_Nodes_DeleteStatement o, collector - collector << 'DELETE ' - if o.limit - collector << 'TOP (' - visit o.limit.expr, collector - collector << ') ' - end - collector << 'FROM ' - collector = visit o.relation, collector - if o.wheres.any? - collector << ' WHERE ' - inject_join o.wheres, collector, AND - else - collector + def visit_Arel_Nodes_DeleteStatement(o, collector) + collector << "DELETE " + if o.limit + collector << "TOP (" + visit o.limit.expr, collector + collector << ") " + end + collector << "FROM " + collector = visit o.relation, collector + if o.wheres.any? + collector << " WHERE " + inject_join o.wheres, collector, AND + else + collector + end end - end - def determine_order_by orders, x - if orders.any? - orders - elsif x.groups.any? - x.groups - else - pk = find_left_table_pk(x.froms) - pk ? [pk] : [] + def determine_order_by(orders, x) + if orders.any? + orders + elsif x.groups.any? + x.groups + else + pk = find_left_table_pk(x.froms) + pk ? [pk] : [] + end end - end - def row_num_literal order_by - RowNumber.new order_by - end + def row_num_literal(order_by) + RowNumber.new order_by + end - def select_count? x - x.projections.length == 1 && Arel::Nodes::Count === x.projections.first - end + def select_count?(x) + x.projections.length == 1 && Arel::Nodes::Count === x.projections.first + end - # FIXME raise exception of there is no pk? - def find_left_table_pk o - if o.kind_of?(Arel::Nodes::Join) - find_left_table_pk(o.left) - elsif o.instance_of?(Arel::Table) - find_primary_key(o) + # FIXME raise exception of there is no pk? + def find_left_table_pk(o) + if o.kind_of?(Arel::Nodes::Join) + find_left_table_pk(o.left) + elsif o.instance_of?(Arel::Table) + find_primary_key(o) + end end - end - def find_primary_key(o) - @primary_keys[o.name] ||= begin - primary_key_name = @connection.primary_key(o.name) - # some tables might be without primary key - primary_key_name && o[primary_key_name] + def find_primary_key(o) + @primary_keys[o.name] ||= begin + primary_key_name = @connection.primary_key(o.name) + # some tables might be without primary key + primary_key_name && o[primary_key_name] + end end - end end end end diff --git a/activerecord/lib/arel/visitors/mysql.rb b/activerecord/lib/arel/visitors/mysql.rb index 4c734f6292eea..7b32988be69d9 100644 --- a/activerecord/lib/arel/visitors/mysql.rb +++ b/activerecord/lib/arel/visitors/mysql.rb @@ -1,86 +1,87 @@ # frozen_string_literal: true + module Arel module Visitors class MySQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Union o, collector, suppress_parens = false - unless suppress_parens - collector << "( " - end + def visit_Arel_Nodes_Union(o, collector, suppress_parens = false) + unless suppress_parens + collector << "( " + end - collector = case o.left - when Arel::Nodes::Union - visit_Arel_Nodes_Union o.left, collector, true - else - visit o.left, collector - end + collector = case o.left + when Arel::Nodes::Union + visit_Arel_Nodes_Union o.left, collector, true + else + visit o.left, collector + end - collector << " UNION " + collector << " UNION " - collector = case o.right - when Arel::Nodes::Union - visit_Arel_Nodes_Union o.right, collector, true - else - visit o.right, collector - end + collector = case o.right + when Arel::Nodes::Union + visit_Arel_Nodes_Union o.right, collector, true + else + visit o.right, collector + end - if suppress_parens - collector - else - collector << " )" + if suppress_parens + collector + else + collector << " )" + end end - end - def visit_Arel_Nodes_Bin o, collector - collector << "BINARY " - visit o.expr, collector - end + def visit_Arel_Nodes_Bin(o, collector) + collector << "BINARY " + visit o.expr, collector + end - ### - # :'( - # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 - def visit_Arel_Nodes_SelectStatement o, collector - if o.offset && !o.limit - o.limit = Arel::Nodes::Limit.new(18446744073709551615) + ### + # :'( + # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 + def visit_Arel_Nodes_SelectStatement(o, collector) + if o.offset && !o.limit + o.limit = Arel::Nodes::Limit.new(18446744073709551615) + end + super end - super - end - def visit_Arel_Nodes_SelectCore o, collector - o.froms ||= Arel.sql('DUAL') - super - end + def visit_Arel_Nodes_SelectCore(o, collector) + o.froms ||= Arel.sql("DUAL") + super + end - def visit_Arel_Nodes_UpdateStatement o, collector - collector << "UPDATE " - collector = visit o.relation, collector + def visit_Arel_Nodes_UpdateStatement(o, collector) + collector << "UPDATE " + collector = visit o.relation, collector - unless o.values.empty? - collector << " SET " - collector = inject_join o.values, collector, ', ' - end + unless o.values.empty? + collector << " SET " + collector = inject_join o.values, collector, ", " + end - unless o.wheres.empty? - collector << " WHERE " - collector = inject_join o.wheres, collector, ' AND ' - end + unless o.wheres.empty? + collector << " WHERE " + collector = inject_join o.wheres, collector, " AND " + end - unless o.orders.empty? - collector << " ORDER BY " - collector = inject_join o.orders, collector, ', ' - end + unless o.orders.empty? + collector << " ORDER BY " + collector = inject_join o.orders, collector, ", " + end - maybe_visit o.limit, collector - end + maybe_visit o.limit, collector + end - def visit_Arel_Nodes_Concat o, collector - collector << " CONCAT(" - visit o.left, collector - collector << ", " - visit o.right, collector - collector << ") " - collector - end + def visit_Arel_Nodes_Concat(o, collector) + collector << " CONCAT(" + visit o.left, collector + collector << ", " + visit o.right, collector + collector << ") " + collector + end end end end diff --git a/activerecord/lib/arel/visitors/oracle.rb b/activerecord/lib/arel/visitors/oracle.rb index d4749bbae327b..7811c18a8c8c3 100644 --- a/activerecord/lib/arel/visitors/oracle.rb +++ b/activerecord/lib/arel/visitors/oracle.rb @@ -1,153 +1,153 @@ # frozen_string_literal: true + module Arel module Visitors class Oracle < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o, collector - o = order_hacks(o) + def visit_Arel_Nodes_SelectStatement(o, collector) + 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.cores.first.groups.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /Distinct/ - o.cores.last.wheres.push Nodes::LessThanOrEqual.new( - Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr - ) - return super - end + # 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.cores.first.groups.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /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 + offset = o.offset + o.offset = nil + collector << " + SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (" + + collector = super(o, collector) + + if offset.expr.is_a? Nodes::BindParam + collector << ") raw_sql_ WHERE rownum <= (" + collector = visit offset.expr, collector + collector << " + " + collector = visit limit, collector + collector << ") ) WHERE raw_rnum_ > " + collector = visit offset.expr, collector + return collector + else + collector << ") raw_sql_ + WHERE rownum <= #{offset.expr.to_i + limit} + ) + WHERE " + return visit(offset, collector) + end + end - if o.limit && o.offset - o = o.dup - limit = o.limit.expr - offset = o.offset - o.offset = nil - collector << " - SELECT * FROM ( - SELECT raw_sql_.*, rownum raw_rnum_ - FROM (" - - collector = super(o, collector) - - if offset.expr.is_a? Nodes::BindParam - collector << ') raw_sql_ WHERE rownum <= (' - collector = visit offset.expr, collector - collector << ' + ' - collector = visit limit, collector - collector << ") ) WHERE raw_rnum_ > " - collector = visit offset.expr, collector - return collector - else + if o.limit + o = o.dup + limit = o.limit.expr + collector << "SELECT * FROM (" + collector = super(o, collector) + collector << ") WHERE ROWNUM <= " + return visit limit, collector + end + + if o.offset + o = o.dup + offset = o.offset + o.offset = nil + collector << "SELECT * FROM ( + SELECT raw_sql_.*, rownum raw_rnum_ + FROM (" + collector = super(o, collector) collector << ") raw_sql_ - WHERE rownum <= #{offset.expr.to_i + limit} - ) - WHERE " - return visit(offset, collector) + ) + WHERE " + return visit offset, collector end - end - if o.limit - o = o.dup - limit = o.limit.expr - collector << "SELECT * FROM (" - collector = super(o, collector) - collector << ") WHERE ROWNUM <= " - return visit limit, collector + super end - if o.offset - o = o.dup - offset = o.offset - o.offset = nil - collector << "SELECT * FROM ( - SELECT raw_sql_.*, rownum raw_rnum_ - FROM (" - collector = super(o, collector) - collector << ") raw_sql_ - ) - WHERE " - return visit offset, collector + def visit_Arel_Nodes_Limit(o, collector) + collector end - super - end - - def visit_Arel_Nodes_Limit o, collector - collector - end - - def visit_Arel_Nodes_Offset o, collector - collector << "raw_rnum_ > " - visit o.expr, collector - end - - def visit_Arel_Nodes_Except o, collector - collector << "( " - collector = infix_value o, collector, " MINUS " - collector << " )" - end - - def visit_Arel_Nodes_UpdateStatement o, collector - # Oracle does not allow ORDER BY/LIMIT in UPDATEs. - if o.orders.any? && o.limit.nil? - # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, - # otherwise let the user deal with the error - o = o.dup - o.orders = [] + def visit_Arel_Nodes_Offset(o, collector) + collector << "raw_rnum_ > " + visit o.expr, collector end - super - end + def visit_Arel_Nodes_Except(o, collector) + collector << "( " + collector = infix_value o, collector, " MINUS " + collector << " )" + 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| - /FIRST_VALUE/ === projection + def visit_Arel_Nodes_UpdateStatement(o, collector) + # Oracle does not allow ORDER BY/LIMIT in UPDATEs. + if o.orders.any? && o.limit.nil? + # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, + # otherwise let the user deal with the error + o = o.dup + o.orders = [] end + + super end - # 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, Arel::Collectors::SQLString.new).value - if string.include?(',') - split_order_string(string) - else - string + + ### + # 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| + /FIRST_VALUE/ === projection + end 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.to_s + # 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, Arel::Collectors::SQLString.new).value + 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 - i += 1 if array[i].count('(') == array[i].count(')') + o end - array - end - def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o.value) { |i| ":a#{i}" } - 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.to_s + end + i += 1 if array[i].count("(") == array[i].count(")") + end + array + end + def visit_Arel_Nodes_BindParam(o, collector) + collector.add_bind(o.value) { |i| ":a#{i}" } + end end end end diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb index 648047ae6184a..e312ba96bb385 100644 --- a/activerecord/lib/arel/visitors/oracle12.rb +++ b/activerecord/lib/arel/visitors/oracle12.rb @@ -1,60 +1,61 @@ # frozen_string_literal: true + module Arel module Visitors class Oracle12 < Arel::Visitors::ToSql private - def visit_Arel_Nodes_SelectStatement o, collector - # Oracle does not allow LIMIT clause with select for update - if o.limit && o.lock - raise ArgumentError, <<-MSG + def visit_Arel_Nodes_SelectStatement(o, collector) + # Oracle does not allow LIMIT clause with select for update + if o.limit && o.lock + raise ArgumentError, <<-MSG 'Combination of limit and lock is not supported. because generated SQL statements `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.` MSG + end + super + end + + def visit_Arel_Nodes_SelectOptions(o, collector) + collector = maybe_visit o.offset, collector + collector = maybe_visit o.limit, collector + collector = maybe_visit o.lock, collector end - super - end - - def visit_Arel_Nodes_SelectOptions o, collector - collector = maybe_visit o.offset, collector - collector = maybe_visit o.limit, collector - collector = maybe_visit o.lock, collector - end - - def visit_Arel_Nodes_Limit o, collector - collector << "FETCH FIRST " - collector = visit o.expr, collector - collector << " ROWS ONLY" - end - - def visit_Arel_Nodes_Offset o, collector - collector << "OFFSET " - visit o.expr, collector - collector << " ROWS" - end - - def visit_Arel_Nodes_Except o, collector - collector << "( " - collector = infix_value o, collector, " MINUS " - collector << " )" - end - - def visit_Arel_Nodes_UpdateStatement o, collector - # Oracle does not allow ORDER BY/LIMIT in UPDATEs. - if o.orders.any? && o.limit.nil? - # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, - # otherwise let the user deal with the error - o = o.dup - o.orders = [] + + def visit_Arel_Nodes_Limit(o, collector) + collector << "FETCH FIRST " + collector = visit o.expr, collector + collector << " ROWS ONLY" end - super - end + def visit_Arel_Nodes_Offset(o, collector) + collector << "OFFSET " + visit o.expr, collector + collector << " ROWS" + end - def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o.value) { |i| ":a#{i}" } - end + def visit_Arel_Nodes_Except(o, collector) + collector << "( " + collector = infix_value o, collector, " MINUS " + collector << " )" + end + + def visit_Arel_Nodes_UpdateStatement(o, collector) + # Oracle does not allow ORDER BY/LIMIT in UPDATEs. + if o.orders.any? && o.limit.nil? + # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, + # otherwise let the user deal with the error + o = o.dup + o.orders = [] + end + + super + end + + def visit_Arel_Nodes_BindParam(o, collector) + collector.add_bind(o.value) { |i| ":a#{i}" } + end end end end diff --git a/activerecord/lib/arel/visitors/postgresql.rb b/activerecord/lib/arel/visitors/postgresql.rb index 047f71aaa6952..e7ed888ed8e4c 100644 --- a/activerecord/lib/arel/visitors/postgresql.rb +++ b/activerecord/lib/arel/visitors/postgresql.rb @@ -1,103 +1,104 @@ # frozen_string_literal: true + module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql - CUBE = 'CUBE' - ROLLUP = 'ROLLUP' - GROUPING_SET = 'GROUPING SET' - LATERAL = 'LATERAL' + CUBE = "CUBE" + ROLLUP = "ROLLUP" + GROUPING_SET = "GROUPING SET" + LATERAL = "LATERAL" private - def visit_Arel_Nodes_Matches o, collector - op = o.case_sensitive ? ' LIKE ' : ' ILIKE ' - collector = infix_value o, collector, op - if o.escape - collector << ' ESCAPE ' - visit o.escape, collector - else - collector + def visit_Arel_Nodes_Matches(o, collector) + op = o.case_sensitive ? " LIKE " : " ILIKE " + collector = infix_value o, collector, op + if o.escape + collector << " ESCAPE " + visit o.escape, collector + else + collector + end end - end - def visit_Arel_Nodes_DoesNotMatch o, collector - op = o.case_sensitive ? ' NOT LIKE ' : ' NOT ILIKE ' - collector = infix_value o, collector, op - if o.escape - collector << ' ESCAPE ' - visit o.escape, collector - else - collector + def visit_Arel_Nodes_DoesNotMatch(o, collector) + op = o.case_sensitive ? " NOT LIKE " : " NOT ILIKE " + collector = infix_value o, collector, op + if o.escape + collector << " ESCAPE " + visit o.escape, collector + else + collector + end end - end - def visit_Arel_Nodes_Regexp o, collector - op = o.case_sensitive ? ' ~ ' : ' ~* ' - infix_value o, collector, op - end + def visit_Arel_Nodes_Regexp(o, collector) + op = o.case_sensitive ? " ~ " : " ~* " + infix_value o, collector, op + end - def visit_Arel_Nodes_NotRegexp o, collector - op = o.case_sensitive ? ' !~ ' : ' !~* ' - infix_value o, collector, op - end + def visit_Arel_Nodes_NotRegexp(o, collector) + op = o.case_sensitive ? " !~ " : " !~* " + infix_value o, collector, op + end - def visit_Arel_Nodes_DistinctOn o, collector - collector << "DISTINCT ON ( " - visit(o.expr, collector) << " )" - end + def visit_Arel_Nodes_DistinctOn(o, collector) + collector << "DISTINCT ON ( " + visit(o.expr, collector) << " )" + end - def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o.value) { |i| "$#{i}" } - end + def visit_Arel_Nodes_BindParam(o, collector) + collector.add_bind(o.value) { |i| "$#{i}" } + end - def visit_Arel_Nodes_GroupingElement o, collector - collector << "( " - visit(o.expr, collector) << " )" - end + def visit_Arel_Nodes_GroupingElement(o, collector) + collector << "( " + visit(o.expr, collector) << " )" + end - def visit_Arel_Nodes_Cube o, collector - collector << CUBE - grouping_array_or_grouping_element o, collector - end + def visit_Arel_Nodes_Cube(o, collector) + collector << CUBE + grouping_array_or_grouping_element o, collector + end - def visit_Arel_Nodes_RollUp o, collector - collector << ROLLUP - grouping_array_or_grouping_element o, collector - end + def visit_Arel_Nodes_RollUp(o, collector) + collector << ROLLUP + grouping_array_or_grouping_element o, collector + end - def visit_Arel_Nodes_GroupingSet o, collector - collector << GROUPING_SET - grouping_array_or_grouping_element o, collector - end + def visit_Arel_Nodes_GroupingSet(o, collector) + collector << GROUPING_SET + grouping_array_or_grouping_element o, collector + end - def visit_Arel_Nodes_Lateral o, collector - collector << LATERAL - collector << SPACE - grouping_parentheses o, collector - end + def visit_Arel_Nodes_Lateral(o, collector) + collector << LATERAL + collector << SPACE + grouping_parentheses o, collector + end - # Used by Lateral visitor to enclose select queries in parentheses - def grouping_parentheses o, collector - if o.expr.is_a? Nodes::SelectStatement - collector << "(" - visit o.expr, collector - collector << ")" - else - visit o.expr, collector + # Used by Lateral visitor to enclose select queries in parentheses + def grouping_parentheses(o, collector) + if o.expr.is_a? Nodes::SelectStatement + collector << "(" + visit o.expr, collector + collector << ")" + else + visit o.expr, collector + end end - end - # Utilized by GroupingSet, Cube & RollUp visitors to - # handle grouping aggregation semantics - def grouping_array_or_grouping_element o, collector - if o.expr.is_a? Array - collector << "( " - visit o.expr, collector - collector << " )" - else - visit o.expr, collector + # Utilized by GroupingSet, Cube & RollUp visitors to + # handle grouping aggregation semantics + def grouping_array_or_grouping_element(o, collector) + if o.expr.is_a? Array + collector << "( " + visit o.expr, collector + collector << " )" + else + visit o.expr, collector + end end - end end end end diff --git a/activerecord/lib/arel/visitors/sqlite.rb b/activerecord/lib/arel/visitors/sqlite.rb index 4ae093968bace..8d4152c428fe3 100644 --- a/activerecord/lib/arel/visitors/sqlite.rb +++ b/activerecord/lib/arel/visitors/sqlite.rb @@ -1,27 +1,27 @@ # frozen_string_literal: true + module Arel module Visitors class SQLite < Arel::Visitors::ToSql private - # Locks are not supported in SQLite - def visit_Arel_Nodes_Lock o, collector - collector - end - - def visit_Arel_Nodes_SelectStatement o, collector - o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit - super - end + # Locks are not supported in SQLite + def visit_Arel_Nodes_Lock(o, collector) + collector + end - def visit_Arel_Nodes_True o, collector - collector << "1" - end + def visit_Arel_Nodes_SelectStatement(o, collector) + o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit + super + end - def visit_Arel_Nodes_False o, collector - collector << "0" - end + def visit_Arel_Nodes_True(o, collector) + collector << "1" + end + def visit_Arel_Nodes_False(o, collector) + collector << "0" + end end end end diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index 2b5c43b17389b..24db04200a9c6 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Visitors class UnsupportedVisitError < StandardError @@ -51,796 +52,796 @@ class ToSql < Arel::Visitors::Visitor # specialized for specific databases when necessary. # - WHERE = ' WHERE ' # :nodoc: - SPACE = ' ' # :nodoc: - COMMA = ', ' # :nodoc: - GROUP_BY = ' GROUP BY ' # :nodoc: - ORDER_BY = ' ORDER BY ' # :nodoc: - WINDOW = ' WINDOW ' # :nodoc: - AND = ' AND ' # :nodoc: + 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: + DISTINCT = "DISTINCT" # :nodoc: - def initialize connection + def initialize(connection) super() - @connection = connection + @connection = connection end - def compile node, &block + def compile(node, &block) accept(node, Arel::Collectors::SQLString.new, &block).value end private - def visit_Arel_Nodes_DeleteStatement o, collector - collector << 'DELETE FROM ' - collector = visit o.relation, collector - if o.wheres.any? - collector << WHERE - collector = inject_join o.wheres, collector, AND + def visit_Arel_Nodes_DeleteStatement(o, collector) + collector << "DELETE FROM " + collector = visit o.relation, collector + if o.wheres.any? + collector << WHERE + collector = inject_join o.wheres, collector, AND + end + + maybe_visit o.limit, collector end - maybe_visit o.limit, collector - 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 - # 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, collector) + if o.orders.empty? && o.limit.nil? + wheres = o.wheres + else + wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])] + end - def visit_Arel_Nodes_UpdateStatement o, collector - if o.orders.empty? && o.limit.nil? - wheres = o.wheres - else - wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])] - end + collector << "UPDATE " + collector = visit o.relation, collector + unless o.values.empty? + collector << " SET " + collector = inject_join o.values, collector, ", " + end - collector << "UPDATE " - collector = visit o.relation, collector - unless o.values.empty? - collector << " SET " - collector = inject_join o.values, collector, ", " - end + unless wheres.empty? + collector << " WHERE " + collector = inject_join wheres, collector, " AND " + end - unless wheres.empty? - collector << " WHERE " - collector = inject_join wheres, collector, " AND " + collector end - collector - end + def visit_Arel_Nodes_InsertStatement(o, collector) + collector << "INSERT INTO " + collector = visit o.relation, collector + if o.columns.any? + collector << " (#{o.columns.map { |x| + quote_column_name x.name + }.join ', '})" + end - def visit_Arel_Nodes_InsertStatement o, collector - collector << "INSERT INTO " - collector = visit o.relation, collector - if o.columns.any? - collector << " (#{o.columns.map { |x| - quote_column_name x.name - }.join ', '})" + if o.values + maybe_visit o.values, collector + elsif o.select + maybe_visit o.select, collector + else + collector + end end - if o.values - maybe_visit o.values, collector - elsif o.select - maybe_visit o.select, collector - else - collector + def visit_Arel_Nodes_Exists(o, collector) + collector << "EXISTS (" + collector = visit(o.expressions, collector) << ")" + if o.alias + collector << " AS " + visit o.alias, collector + else + collector + end end - end - def visit_Arel_Nodes_Exists o, collector - collector << "EXISTS (" - collector = visit(o.expressions, collector) << ")" - if o.alias - collector << " AS " - visit o.alias, collector - else - collector + def visit_Arel_Nodes_Casted(o, collector) + collector << quoted(o.val, o.attribute).to_s end - end - def visit_Arel_Nodes_Casted o, collector - collector << quoted(o.val, o.attribute).to_s - end + def visit_Arel_Nodes_Quoted(o, collector) + collector << quoted(o.expr, nil).to_s + end - def visit_Arel_Nodes_Quoted o, collector - collector << quoted(o.expr, nil).to_s - end + def visit_Arel_Nodes_True(o, collector) + collector << "TRUE" + end - def visit_Arel_Nodes_True o, collector - collector << "TRUE" - end + def visit_Arel_Nodes_False(o, collector) + collector << "FALSE" + end - def visit_Arel_Nodes_False o, collector - collector << "FALSE" - end + def visit_Arel_Nodes_ValuesList(o, collector) + collector << "VALUES " - def visit_Arel_Nodes_ValuesList o, collector - collector << "VALUES " + len = o.rows.length - 1 + o.rows.each_with_index { |row, i| + collector << "(" + row_len = row.length - 1 + row.each_with_index do |value, k| + case value + when Nodes::SqlLiteral, Nodes::BindParam + collector = visit(value, collector) + else + collector << quote(value) + end + collector << COMMA unless k == row_len + end + collector << ")" + collector << COMMA unless i == len + } + collector + end + + def visit_Arel_Nodes_Values(o, collector) + collector << "VALUES (" - len = o.rows.length - 1 - o.rows.each_with_index { |row, i| - collector << '(' - row_len = row.length - 1 - row.each_with_index do |value, k| + len = o.expressions.length - 1 + o.expressions.each_with_index { |value, i| case value when Nodes::SqlLiteral, Nodes::BindParam - collector = visit(value, collector) + collector = visit value, collector else - collector << quote(value) + collector << quote(value).to_s end - collector << COMMA unless k == row_len - end - collector << ')' - collector << COMMA unless i == len - } - collector - end + unless i == len + collector << COMMA + end + } - def visit_Arel_Nodes_Values o, collector - collector << "VALUES (" + collector << ")" + end - len = o.expressions.length - 1 - o.expressions.each_with_index { |value, i| - case value - when Nodes::SqlLiteral, Nodes::BindParam - collector = visit value, collector - else - collector << quote(value).to_s + def visit_Arel_Nodes_SelectStatement(o, collector) + if o.with + collector = visit o.with, collector + collector << SPACE end - unless i == len - collector << COMMA + + collector = o.cores.inject(collector) { |c, x| + visit_Arel_Nodes_SelectCore(x, c) + } + + unless o.orders.empty? + collector << ORDER_BY + len = o.orders.length - 1 + o.orders.each_with_index { |x, i| + collector = visit(x, collector) + collector << COMMA unless len == i + } end - } - collector << ")" - end + visit_Arel_Nodes_SelectOptions(o, collector) - def visit_Arel_Nodes_SelectStatement o, collector - if o.with - collector = visit o.with, collector - collector << SPACE + collector end - collector = o.cores.inject(collector) { |c,x| - visit_Arel_Nodes_SelectCore(x, c) - } - - unless o.orders.empty? - collector << ORDER_BY - len = o.orders.length - 1 - o.orders.each_with_index { |x, i| - collector = visit(x, collector) - collector << COMMA unless len == i - } + def visit_Arel_Nodes_SelectOptions(o, collector) + collector = maybe_visit o.limit, collector + collector = maybe_visit o.offset, collector + collector = maybe_visit o.lock, collector end - visit_Arel_Nodes_SelectOptions(o, collector) + def visit_Arel_Nodes_SelectCore(o, collector) + collector << "SELECT" - collector - end + collector = maybe_visit o.top, collector - def visit_Arel_Nodes_SelectOptions o, collector - collector = maybe_visit o.limit, collector - collector = maybe_visit o.offset, collector - collector = maybe_visit o.lock, collector - end + collector = maybe_visit o.set_quantifier, collector - def visit_Arel_Nodes_SelectCore o, collector - collector << "SELECT" + collect_nodes_for o.projections, collector, SPACE - collector = maybe_visit o.top, collector + if o.source && !o.source.empty? + collector << " FROM " + collector = visit o.source, collector + end - collector = maybe_visit o.set_quantifier, collector + collect_nodes_for o.wheres, collector, WHERE, AND + collect_nodes_for o.groups, collector, GROUP_BY + unless o.havings.empty? + collector << " HAVING " + inject_join o.havings, collector, AND + end + collect_nodes_for o.windows, collector, WINDOW - collect_nodes_for o.projections, collector, SPACE + collector + end - if o.source && !o.source.empty? - collector << " FROM " - collector = visit o.source, collector + def collect_nodes_for(nodes, collector, spacer, connector = COMMA) + unless nodes.empty? + collector << spacer + len = nodes.length - 1 + nodes.each_with_index do |x, i| + collector = visit(x, collector) + collector << connector unless len == i + end + end end - collect_nodes_for o.wheres, collector, WHERE, AND - collect_nodes_for o.groups, collector, GROUP_BY - unless o.havings.empty? - collector << " HAVING " - inject_join o.havings, collector, AND + def visit_Arel_Nodes_Bin(o, collector) + visit o.expr, collector end - collect_nodes_for o.windows, collector, WINDOW - collector - end + def visit_Arel_Nodes_Distinct(o, collector) + collector << DISTINCT + end - def collect_nodes_for nodes, collector, spacer, connector = COMMA - unless nodes.empty? - collector << spacer - len = nodes.length - 1 - nodes.each_with_index do |x, i| - collector = visit(x, collector) - collector << connector unless len == i - end + def visit_Arel_Nodes_DistinctOn(o, collector) + raise NotImplementedError, "DISTINCT ON not implemented for this db" end - end - def visit_Arel_Nodes_Bin o, collector - visit o.expr, collector - end + def visit_Arel_Nodes_With(o, collector) + collector << "WITH " + inject_join o.children, collector, COMMA + end - def visit_Arel_Nodes_Distinct o, collector - collector << DISTINCT - end + def visit_Arel_Nodes_WithRecursive(o, collector) + collector << "WITH RECURSIVE " + inject_join o.children, collector, COMMA + end - def visit_Arel_Nodes_DistinctOn o, collector - raise NotImplementedError, 'DISTINCT ON not implemented for this db' - end + def visit_Arel_Nodes_Union(o, collector) + collector << "( " + infix_value(o, collector, " UNION ") << " )" + end - def visit_Arel_Nodes_With o, collector - collector << "WITH " - inject_join o.children, collector, COMMA - end + def visit_Arel_Nodes_UnionAll(o, collector) + collector << "( " + infix_value(o, collector, " UNION ALL ") << " )" + end - def visit_Arel_Nodes_WithRecursive o, collector - collector << "WITH RECURSIVE " - inject_join o.children, collector, COMMA - end + def visit_Arel_Nodes_Intersect(o, collector) + collector << "( " + infix_value(o, collector, " INTERSECT ") << " )" + end - def visit_Arel_Nodes_Union o, collector - collector << "( " - infix_value(o, collector, " UNION ") << " )" - end + def visit_Arel_Nodes_Except(o, collector) + collector << "( " + infix_value(o, collector, " EXCEPT ") << " )" + end - def visit_Arel_Nodes_UnionAll o, collector - collector << "( " - infix_value(o, collector, " UNION ALL ") << " )" - end + def visit_Arel_Nodes_NamedWindow(o, collector) + collector << quote_column_name(o.name) + collector << " AS " + visit_Arel_Nodes_Window o, collector + end - def visit_Arel_Nodes_Intersect o, collector - collector << "( " - infix_value(o, collector, " INTERSECT ") << " )" - end + def visit_Arel_Nodes_Window(o, collector) + collector << "(" - def visit_Arel_Nodes_Except o, collector - collector << "( " - infix_value(o, collector, " EXCEPT ") << " )" - end + if o.partitions.any? + collector << "PARTITION BY " + collector = inject_join o.partitions, collector, ", " + end - def visit_Arel_Nodes_NamedWindow o, collector - collector << quote_column_name(o.name) - collector << " AS " - visit_Arel_Nodes_Window o, collector - end + if o.orders.any? + collector << SPACE if o.partitions.any? + collector << "ORDER BY " + collector = inject_join o.orders, collector, ", " + end - def visit_Arel_Nodes_Window o, collector - collector << "(" + if o.framing + collector << SPACE if o.partitions.any? || o.orders.any? + collector = visit o.framing, collector + end - if o.partitions.any? - collector << "PARTITION BY " - collector = inject_join o.partitions, collector, ", " + collector << ")" end - if o.orders.any? - collector << SPACE if o.partitions.any? - collector << "ORDER BY " - collector = inject_join o.orders, collector, ", " + def visit_Arel_Nodes_Rows(o, collector) + if o.expr + collector << "ROWS " + visit o.expr, collector + else + collector << "ROWS" + end end - if o.framing - collector << SPACE if o.partitions.any? or o.orders.any? - collector = visit o.framing, collector + def visit_Arel_Nodes_Range(o, collector) + if o.expr + collector << "RANGE " + visit o.expr, collector + else + collector << "RANGE" + end end - collector << ")" - end - - def visit_Arel_Nodes_Rows o, collector - if o.expr - collector << "ROWS " - visit o.expr, collector - else - collector << "ROWS" - end - end + def visit_Arel_Nodes_Preceding(o, collector) + collector = if o.expr + visit o.expr, collector + else + collector << "UNBOUNDED" + end - def visit_Arel_Nodes_Range o, collector - if o.expr - collector << "RANGE " - visit o.expr, collector - else - collector << "RANGE" + collector << " PRECEDING" end - end - def visit_Arel_Nodes_Preceding o, collector - collector = if o.expr - visit o.expr, collector - else - collector << "UNBOUNDED" - end - - collector << " PRECEDING" - end + def visit_Arel_Nodes_Following(o, collector) + collector = if o.expr + visit o.expr, collector + else + collector << "UNBOUNDED" + end - def visit_Arel_Nodes_Following o, collector - collector = if o.expr - visit o.expr, collector - else - collector << "UNBOUNDED" - end + collector << " FOLLOWING" + end - collector << " FOLLOWING" - end + def visit_Arel_Nodes_CurrentRow(o, collector) + collector << "CURRENT ROW" + end - def visit_Arel_Nodes_CurrentRow o, collector - collector << "CURRENT ROW" - end + def visit_Arel_Nodes_Over(o, collector) + case o.right + when nil + visit(o.left, collector) << " OVER ()" + when Arel::Nodes::SqlLiteral + infix_value o, collector, " OVER " + when String, Symbol + visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}" + else + infix_value o, collector, " OVER " + end + end - def visit_Arel_Nodes_Over o, collector - case o.right - when nil - visit(o.left, collector) << " OVER ()" - when Arel::Nodes::SqlLiteral - infix_value o, collector, " OVER " - when String, Symbol - visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}" - else - infix_value o, collector, " OVER " + def visit_Arel_Nodes_Offset(o, collector) + collector << "OFFSET " + visit o.expr, collector end - end - def visit_Arel_Nodes_Offset o, collector - collector << "OFFSET " - visit o.expr, collector - end + def visit_Arel_Nodes_Limit(o, collector) + collector << "LIMIT " + visit o.expr, collector + end - def visit_Arel_Nodes_Limit o, collector - collector << "LIMIT " - visit o.expr, collector - end + # FIXME: this does nothing on most databases, but does on MSSQL + def visit_Arel_Nodes_Top(o, collector) + collector + end - # FIXME: this does nothing on most databases, but does on MSSQL - def visit_Arel_Nodes_Top o, collector - collector - end + def visit_Arel_Nodes_Lock(o, collector) + visit o.expr, collector + end - def visit_Arel_Nodes_Lock o, collector - visit o.expr, collector - end + def visit_Arel_Nodes_Grouping(o, collector) + if o.expr.is_a? Nodes::Grouping + visit(o.expr, collector) + else + collector << "(" + visit(o.expr, collector) << ")" + end + end - def visit_Arel_Nodes_Grouping o, collector - if o.expr.is_a? Nodes::Grouping - visit(o.expr, collector) - else + def visit_Arel_SelectManager(o, collector) collector << "(" - visit(o.expr, collector) << ")" + visit(o.ast, collector) << ")" end - end - - def visit_Arel_SelectManager o, collector - collector << '(' - visit(o.ast, collector) << ')' - end - - def visit_Arel_Nodes_Ascending o, collector - visit(o.expr, collector) << " ASC" - end - def visit_Arel_Nodes_Descending o, collector - visit(o.expr, collector) << " DESC" - end - - def visit_Arel_Nodes_Group o, collector - visit o.expr, collector - end + def visit_Arel_Nodes_Ascending(o, collector) + visit(o.expr, collector) << " ASC" + end - def visit_Arel_Nodes_NamedFunction o, collector - collector << o.name - collector << "(" - collector << "DISTINCT " if o.distinct - collector = inject_join(o.expressions, collector, ", ") << ")" - if o.alias - collector << " AS " - visit o.alias, collector - else - collector + def visit_Arel_Nodes_Descending(o, collector) + visit(o.expr, collector) << " DESC" end - end - def visit_Arel_Nodes_Extract o, collector - collector << "EXTRACT(#{o.field.to_s.upcase} FROM " - visit(o.expr, collector) << ")" - end + def visit_Arel_Nodes_Group(o, collector) + visit o.expr, collector + end - def visit_Arel_Nodes_Count o, collector - aggregate "COUNT", o, collector - end + def visit_Arel_Nodes_NamedFunction(o, collector) + collector << o.name + collector << "(" + collector << "DISTINCT " if o.distinct + collector = inject_join(o.expressions, collector, ", ") << ")" + if o.alias + collector << " AS " + visit o.alias, collector + else + collector + end + end - def visit_Arel_Nodes_Sum o, collector - aggregate "SUM", o, collector - end + def visit_Arel_Nodes_Extract(o, collector) + collector << "EXTRACT(#{o.field.to_s.upcase} FROM " + visit(o.expr, collector) << ")" + end - def visit_Arel_Nodes_Max o, collector - aggregate "MAX", o, collector - end + def visit_Arel_Nodes_Count(o, collector) + aggregate "COUNT", o, collector + end - def visit_Arel_Nodes_Min o, collector - aggregate "MIN", o, collector - end + def visit_Arel_Nodes_Sum(o, collector) + aggregate "SUM", o, collector + end - def visit_Arel_Nodes_Avg o, collector - aggregate "AVG", o, collector - end + def visit_Arel_Nodes_Max(o, collector) + aggregate "MAX", o, collector + end - def visit_Arel_Nodes_TableAlias o, collector - collector = visit o.relation, collector - collector << " " - collector << quote_table_name(o.name) - end + def visit_Arel_Nodes_Min(o, collector) + aggregate "MIN", o, collector + end - def visit_Arel_Nodes_Between o, collector - collector = visit o.left, collector - collector << " BETWEEN " - visit o.right, collector - end + def visit_Arel_Nodes_Avg(o, collector) + aggregate "AVG", o, collector + end - def visit_Arel_Nodes_GreaterThanOrEqual o, collector - collector = visit o.left, collector - collector << " >= " - visit o.right, collector - end + def visit_Arel_Nodes_TableAlias(o, collector) + collector = visit o.relation, collector + collector << " " + collector << quote_table_name(o.name) + end - def visit_Arel_Nodes_GreaterThan o, collector - collector = visit o.left, collector - collector << " > " - visit o.right, collector - end + def visit_Arel_Nodes_Between(o, collector) + collector = visit o.left, collector + collector << " BETWEEN " + visit o.right, collector + end - def visit_Arel_Nodes_LessThanOrEqual o, collector - collector = visit o.left, collector - collector << " <= " - visit o.right, collector - end + def visit_Arel_Nodes_GreaterThanOrEqual(o, collector) + collector = visit o.left, collector + collector << " >= " + visit o.right, collector + end - def visit_Arel_Nodes_LessThan o, collector - collector = visit o.left, collector - collector << " < " - visit o.right, collector - end + def visit_Arel_Nodes_GreaterThan(o, collector) + collector = visit o.left, collector + collector << " > " + visit o.right, collector + end - def visit_Arel_Nodes_Matches o, collector - collector = visit o.left, collector - collector << " LIKE " - collector = visit o.right, collector - if o.escape - collector << ' ESCAPE ' - visit o.escape, collector - else - collector + def visit_Arel_Nodes_LessThanOrEqual(o, collector) + collector = visit o.left, collector + collector << " <= " + visit o.right, collector end - end - def visit_Arel_Nodes_DoesNotMatch o, collector - collector = visit o.left, collector - collector << " NOT LIKE " - collector = visit o.right, collector - if o.escape - collector << ' ESCAPE ' - visit o.escape, collector - else - collector + def visit_Arel_Nodes_LessThan(o, collector) + collector = visit o.left, collector + collector << " < " + visit o.right, collector end - end - def visit_Arel_Nodes_JoinSource o, collector - if o.left + def visit_Arel_Nodes_Matches(o, collector) collector = visit o.left, collector + collector << " LIKE " + collector = visit o.right, collector + if o.escape + collector << " ESCAPE " + visit o.escape, collector + else + collector + end end - if o.right.any? - collector << SPACE if o.left - collector = inject_join o.right, collector, SPACE + + def visit_Arel_Nodes_DoesNotMatch(o, collector) + collector = visit o.left, collector + collector << " NOT LIKE " + collector = visit o.right, collector + if o.escape + collector << " ESCAPE " + visit o.escape, collector + else + collector + end end - collector - end - def visit_Arel_Nodes_Regexp o, collector - raise NotImplementedError, '~ not implemented for this db' - end + def visit_Arel_Nodes_JoinSource(o, collector) + if o.left + collector = visit o.left, collector + end + if o.right.any? + collector << SPACE if o.left + collector = inject_join o.right, collector, SPACE + end + collector + end - def visit_Arel_Nodes_NotRegexp o, collector - raise NotImplementedError, '!~ not implemented for this db' - end + def visit_Arel_Nodes_Regexp(o, collector) + raise NotImplementedError, "~ not implemented for this db" + end - def visit_Arel_Nodes_StringJoin o, collector - visit o.left, collector - end + def visit_Arel_Nodes_NotRegexp(o, collector) + raise NotImplementedError, "!~ not implemented for this db" + end - def visit_Arel_Nodes_FullOuterJoin o, collector - collector << "FULL OUTER JOIN " - collector = visit o.left, collector - collector << SPACE - visit o.right, collector - end + def visit_Arel_Nodes_StringJoin(o, collector) + visit o.left, collector + end - def visit_Arel_Nodes_OuterJoin o, collector - collector << "LEFT OUTER JOIN " - collector = visit o.left, collector - collector << " " - visit o.right, collector - end + def visit_Arel_Nodes_FullOuterJoin(o, collector) + collector << "FULL OUTER JOIN " + collector = visit o.left, collector + collector << SPACE + visit o.right, collector + end - def visit_Arel_Nodes_RightOuterJoin o, collector - collector << "RIGHT OUTER JOIN " - collector = visit o.left, collector - collector << SPACE - visit o.right, collector - end + def visit_Arel_Nodes_OuterJoin(o, collector) + collector << "LEFT OUTER JOIN " + collector = visit o.left, collector + collector << " " + visit o.right, collector + end - def visit_Arel_Nodes_InnerJoin o, collector - collector << "INNER JOIN " - collector = visit o.left, collector - if o.right + def visit_Arel_Nodes_RightOuterJoin(o, collector) + collector << "RIGHT OUTER JOIN " + collector = visit o.left, collector collector << SPACE - visit(o.right, collector) - else - collector + visit o.right, collector end - end - def visit_Arel_Nodes_On o, collector - collector << "ON " - visit o.expr, collector - end + def visit_Arel_Nodes_InnerJoin(o, collector) + collector << "INNER JOIN " + collector = visit o.left, collector + if o.right + collector << SPACE + visit(o.right, collector) + else + collector + end + end - def visit_Arel_Nodes_Not o, collector - collector << "NOT (" - visit(o.expr, collector) << ")" - end + def visit_Arel_Nodes_On(o, collector) + collector << "ON " + visit o.expr, collector + end - def visit_Arel_Table o, collector - if o.table_alias - collector << "#{quote_table_name o.name} #{quote_table_name o.table_alias}" - else - collector << quote_table_name(o.name) + def visit_Arel_Nodes_Not(o, collector) + collector << "NOT (" + visit(o.expr, collector) << ")" end - end - def visit_Arel_Nodes_In o, collector - if Array === o.right && o.right.empty? - collector << '1=0' - else - collector = visit o.left, collector - collector << " IN (" - visit(o.right, collector) << ")" + def visit_Arel_Table(o, collector) + if o.table_alias + collector << "#{quote_table_name o.name} #{quote_table_name o.table_alias}" + else + collector << quote_table_name(o.name) + end end - end - def visit_Arel_Nodes_NotIn o, collector - if Array === o.right && o.right.empty? - collector << '1=1' - else - collector = visit o.left, collector - collector << " NOT IN (" - collector = visit o.right, collector - collector << ")" + def visit_Arel_Nodes_In(o, collector) + if Array === o.right && o.right.empty? + collector << "1=0" + else + collector = visit o.left, collector + collector << " IN (" + visit(o.right, collector) << ")" + end end - end - def visit_Arel_Nodes_And o, collector - inject_join o.children, collector, " AND " - end + def visit_Arel_Nodes_NotIn(o, collector) + if Array === o.right && o.right.empty? + collector << "1=1" + else + collector = visit o.left, collector + collector << " NOT IN (" + collector = visit o.right, collector + collector << ")" + end + end - def visit_Arel_Nodes_Or o, collector - collector = visit o.left, collector - collector << " OR " - visit o.right, collector - end + def visit_Arel_Nodes_And(o, collector) + inject_join o.children, collector, " AND " + end - def visit_Arel_Nodes_Assignment o, collector - case o.right - when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute, Arel::Nodes::BindParam + def visit_Arel_Nodes_Or(o, collector) collector = visit o.left, collector - collector << " = " + collector << " OR " visit o.right, collector - else - collector = visit o.left, collector - collector << " = " - collector << quote(o.right).to_s end - end - def visit_Arel_Nodes_Equality o, collector - right = o.right + def visit_Arel_Nodes_Assignment(o, collector) + case o.right + when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute, Arel::Nodes::BindParam + collector = visit o.left, collector + collector << " = " + visit o.right, collector + else + collector = visit o.left, collector + collector << " = " + collector << quote(o.right).to_s + end + end + + def visit_Arel_Nodes_Equality(o, collector) + right = o.right - collector = visit o.left, collector + collector = visit o.left, collector - if right.nil? - collector << " IS NULL" - else - collector << " = " - visit right, collector + if right.nil? + collector << " IS NULL" + else + collector << " = " + visit right, collector + end end - end - def visit_Arel_Nodes_NotEqual o, collector - right = o.right + def visit_Arel_Nodes_NotEqual(o, collector) + right = o.right - collector = visit o.left, collector + collector = visit o.left, collector - if right.nil? - collector << " IS NOT NULL" - else - collector << " != " - visit right, collector + if right.nil? + collector << " IS NOT NULL" + else + collector << " != " + visit right, collector + end end - end - def visit_Arel_Nodes_As o, collector - collector = visit o.left, collector - collector << " AS " - visit o.right, collector - end + def visit_Arel_Nodes_As(o, collector) + collector = visit o.left, collector + collector << " AS " + visit o.right, collector + end - def visit_Arel_Nodes_Case o, collector - collector << "CASE " - if o.case - visit o.case, collector - collector << " " + def visit_Arel_Nodes_Case(o, collector) + collector << "CASE " + if o.case + visit o.case, collector + collector << " " + end + o.conditions.each do |condition| + visit condition, collector + collector << " " + end + if o.default + visit o.default, collector + collector << " " + end + collector << "END" end - o.conditions.each do |condition| - visit condition, collector - collector << " " + + def visit_Arel_Nodes_When(o, collector) + collector << "WHEN " + visit o.left, collector + collector << " THEN " + visit o.right, collector end - if o.default - visit o.default, collector - collector << " " + + def visit_Arel_Nodes_Else(o, collector) + collector << "ELSE " + visit o.expr, collector end - collector << "END" - end - def visit_Arel_Nodes_When o, collector - collector << "WHEN " - visit o.left, collector - collector << " THEN " - visit o.right, collector - end + def visit_Arel_Nodes_UnqualifiedColumn(o, collector) + collector << "#{quote_column_name o.name}" + collector + end - def visit_Arel_Nodes_Else o, collector - collector << "ELSE " - visit o.expr, collector - end + def visit_Arel_Attributes_Attribute(o, collector) + join_name = o.relation.table_alias || o.relation.name + collector << "#{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 visit_Arel_Nodes_UnqualifiedColumn o, collector - collector << "#{quote_column_name o.name}" - collector - end + def literal(o, collector); collector << o.to_s; end - def visit_Arel_Attributes_Attribute o, collector - join_name = o.relation.table_alias || o.relation.name - collector << "#{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 visit_Arel_Nodes_BindParam(o, collector) + collector.add_bind(o.value) { "?" } + end - def literal o, collector; collector << o.to_s; end + alias :visit_Arel_Nodes_SqlLiteral :literal + alias :visit_Bignum :literal + alias :visit_Fixnum :literal + alias :visit_Integer :literal - def visit_Arel_Nodes_BindParam o, collector - collector.add_bind(o.value) { "?" } - end + def quoted(o, a) + if a && a.able_to_type_cast? + quote(a.type_cast_for_database(o)) + else + quote(o) + end + end + + def unsupported(o, collector) + raise UnsupportedVisitError.new(o) + end - alias :visit_Arel_Nodes_SqlLiteral :literal - alias :visit_Bignum :literal - alias :visit_Fixnum :literal - alias :visit_Integer :literal + alias :visit_ActiveSupport_Multibyte_Chars :unsupported + alias :visit_ActiveSupport_StringInquirer :unsupported + alias :visit_BigDecimal :unsupported + alias :visit_Class :unsupported + alias :visit_Date :unsupported + alias :visit_DateTime :unsupported + alias :visit_FalseClass :unsupported + alias :visit_Float :unsupported + alias :visit_Hash :unsupported + alias :visit_NilClass :unsupported + alias :visit_String :unsupported + alias :visit_Symbol :unsupported + alias :visit_Time :unsupported + alias :visit_TrueClass :unsupported - def quoted o, a - if a && a.able_to_type_cast? - quote(a.type_cast_for_database(o)) - else - quote(o) + def visit_Arel_Nodes_InfixOperation(o, collector) + collector = visit o.left, collector + collector << " #{o.operator} " + visit o.right, collector end - end - def unsupported o, collector - raise UnsupportedVisitError.new(o) - 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 - alias :visit_ActiveSupport_Multibyte_Chars :unsupported - alias :visit_ActiveSupport_StringInquirer :unsupported - alias :visit_BigDecimal :unsupported - alias :visit_Class :unsupported - alias :visit_Date :unsupported - alias :visit_DateTime :unsupported - alias :visit_FalseClass :unsupported - alias :visit_Float :unsupported - alias :visit_Hash :unsupported - alias :visit_NilClass :unsupported - alias :visit_String :unsupported - alias :visit_Symbol :unsupported - alias :visit_Time :unsupported - alias :visit_TrueClass :unsupported - - def visit_Arel_Nodes_InfixOperation o, collector - collector = visit o.left, collector - collector << " #{o.operator} " - visit o.right, collector - end + def visit_Arel_Nodes_UnaryOperation(o, collector) + collector << " #{o.operator} " + visit o.expr, collector + 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, collector) + inject_join o, collector, ", " + end + alias :visit_Set :visit_Array - def visit_Arel_Nodes_UnaryOperation o, collector - collector << " #{o.operator} " - visit o.expr, collector - end + def quote(value) + return value if Arel::Nodes::SqlLiteral === value + @connection.quote value + end - def visit_Array o, collector - inject_join o, collector, ", " - end - alias :visit_Set :visit_Array + def quote_table_name(name) + return name if Arel::Nodes::SqlLiteral === name + @connection.quote_table_name(name) + end - def quote value - return value if Arel::Nodes::SqlLiteral === value - @connection.quote value - end + def quote_column_name(name) + return name if Arel::Nodes::SqlLiteral === name + @connection.quote_column_name(name) + end - def quote_table_name name - return name if Arel::Nodes::SqlLiteral === name - @connection.quote_table_name(name) - end + def maybe_visit(thing, collector) + return collector unless thing + collector << " " + visit thing, collector + end - def quote_column_name name - return name if Arel::Nodes::SqlLiteral === name - @connection.quote_column_name(name) - end + def inject_join(list, collector, join_str) + len = list.length - 1 + list.each_with_index.inject(collector) { |c, (x, i)| + if i == len + visit x, c + else + visit(x, c) << join_str + end + } + end - def maybe_visit thing, collector - return collector unless thing - collector << " " - visit thing, collector - end + def infix_value(o, collector, value) + collector = visit o.left, collector + collector << value + visit o.right, collector + end - def inject_join list, collector, join_str - len = list.length - 1 - list.each_with_index.inject(collector) { |c, (x,i)| - if i == len - visit x, c + def aggregate(name, o, collector) + collector << "#{name}(" + if o.distinct + collector << "DISTINCT " + end + collector = inject_join(o.expressions, collector, ", ") << ")" + if o.alias + collector << " AS " + visit o.alias, collector else - visit(x, c) << join_str + collector end - } - end - - def infix_value o, collector, value - collector = visit o.left, collector - collector << value - visit o.right, collector - end - - def aggregate name, o, collector - collector << "#{name}(" - if o.distinct - collector << "DISTINCT " end - collector = inject_join(o.expressions, collector, ", ") << ")" - if o.alias - collector << " AS " - visit o.alias, collector - else - collector - end - end end end end diff --git a/activerecord/lib/arel/visitors/visitor.rb b/activerecord/lib/arel/visitors/visitor.rb index f156be9a0aa4a..6cbe5caf8c51e 100644 --- a/activerecord/lib/arel/visitors/visitor.rb +++ b/activerecord/lib/arel/visitors/visitor.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Visitors class Visitor @@ -6,36 +7,36 @@ def initialize @dispatch = get_dispatch_cache end - def accept object, *args + def accept(object, *args) visit object, *args end private - attr_reader :dispatch + attr_reader :dispatch - def self.dispatch_cache - Hash.new do |hash, klass| - hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" + def self.dispatch_cache + Hash.new do |hash, klass| + hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" + end end - end - def get_dispatch_cache - self.class.dispatch_cache - end + def get_dispatch_cache + self.class.dispatch_cache + end - def visit object, *args - dispatch_method = dispatch[object.class] - send dispatch_method, object, *args - rescue NoMethodError => e - raise e if respond_to?(dispatch_method, 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 + def visit(object, *args) + dispatch_method = dispatch[object.class] + send dispatch_method, object, *args + rescue NoMethodError => e + raise e if respond_to?(dispatch_method, 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 diff --git a/activerecord/lib/arel/visitors/where_sql.rb b/activerecord/lib/arel/visitors/where_sql.rb index 55e6ca9a2193d..d9c87f0130417 100644 --- a/activerecord/lib/arel/visitors/where_sql.rb +++ b/activerecord/lib/arel/visitors/where_sql.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Arel module Visitors class WhereSql < Arel::Visitors::ToSql @@ -9,14 +10,14 @@ def initialize(inner_visitor, *args, &block) private - def visit_Arel_Nodes_SelectCore o, collector - collector << "WHERE " - wheres = o.wheres.map do |where| - Nodes::SqlLiteral.new(@inner_visitor.accept(where, collector.class.new).value) - end + def visit_Arel_Nodes_SelectCore(o, collector) + collector << "WHERE " + wheres = o.wheres.map do |where| + Nodes::SqlLiteral.new(@inner_visitor.accept(where, collector.class.new).value) + end - inject_join wheres, collector, ' AND ' - end + inject_join wheres, collector, " AND " + end end end end diff --git a/activerecord/lib/arel/window_predications.rb b/activerecord/lib/arel/window_predications.rb index f93dede0360db..60d8f05b3cdc6 100644 --- a/activerecord/lib/arel/window_predications.rb +++ b/activerecord/lib/arel/window_predications.rb @@ -1,10 +1,9 @@ # frozen_string_literal: true + module Arel module WindowPredications - def over(expr = nil) Nodes::Over.new(self, expr) end - end -end \ No newline at end of file +end diff --git a/activerecord/test/cases/arel/attributes/attribute_test.rb b/activerecord/test/cases/arel/attributes/attribute_test.rb index 802d6e743fb43..52573021a59f6 100644 --- a/activerecord/test/cases/arel/attributes/attribute_test.rb +++ b/activerecord/test/cases/arel/attributes/attribute_test.rb @@ -1,17 +1,18 @@ # frozen_string_literal: true -require_relative '../helper' -require 'ostruct' + +require_relative "../helper" +require "ostruct" module Arel module Attributes class AttributeTest < Arel::Spec - describe '#not_eq' do - it 'should create a NotEqual node' 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 + it "should generate != in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].not_eq(10) @@ -20,7 +21,7 @@ class AttributeTest < Arel::Spec } end - it 'should handle nil' do + it "should handle nil" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].not_eq(nil) @@ -30,45 +31,45 @@ class AttributeTest < Arel::Spec end end - describe '#not_eq_any' do - it 'should create a Grouping node' do + 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 + relation[:id].not_eq_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].not_eq_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + it "should generate > in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].gt(10) @@ -77,7 +78,7 @@ class AttributeTest < Arel::Spec } end - it 'should handle comparing with a subquery' do + it "should handle comparing with a subquery" do users = Table.new(:users) avg = users.project(users[:karma].average) @@ -88,10 +89,10 @@ class AttributeTest < Arel::Spec } end - it 'should accept various data types.' do + it "should accept various data types." do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].gt('fake_name') + mgr.where relation[:name].gt("fake_name") mgr.to_sql.must_match %{"users"."name" > 'fake_name'} current_time = ::Time.now @@ -100,45 +101,45 @@ class AttributeTest < Arel::Spec end end - describe '#gt_any' do - it 'should create a Grouping node' do + 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 + relation[:id].gt_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].gt_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + it "should generate >= in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].gteq(10) @@ -147,10 +148,10 @@ class AttributeTest < Arel::Spec } end - it 'should accept various data types.' do + it "should accept various data types." do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].gteq('fake_name') + mgr.where relation[:name].gteq("fake_name") mgr.to_sql.must_match %{"users"."name" >= 'fake_name'} current_time = ::Time.now @@ -159,45 +160,45 @@ class AttributeTest < Arel::Spec end end - describe '#gteq_any' do - it 'should create a Grouping node' do + 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 + relation[:id].gteq_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].gteq_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + it "should generate < in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].lt(10) @@ -206,10 +207,10 @@ class AttributeTest < Arel::Spec } end - it 'should accept various data types.' do + it "should accept various data types." do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].lt('fake_name') + mgr.where relation[:name].lt("fake_name") mgr.to_sql.must_match %{"users"."name" < 'fake_name'} current_time = ::Time.now @@ -218,45 +219,45 @@ class AttributeTest < Arel::Spec end end - describe '#lt_any' do - it 'should create a Grouping node' do + 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 + relation[:id].lt_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].lt_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + it "should generate <= in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].lteq(10) @@ -265,10 +266,10 @@ class AttributeTest < Arel::Spec } end - it 'should accept various data types.' do + it "should accept various data types." do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].lteq('fake_name') + mgr.where relation[:name].lteq("fake_name") mgr.to_sql.must_match %{"users"."name" <= 'fake_name'} current_time = ::Time.now @@ -277,45 +278,45 @@ class AttributeTest < Arel::Spec end end - describe '#lteq_any' do - it 'should create a Grouping node' do + 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 + relation[:id].lteq_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].lteq_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + describe "#average" do + it "should create a AVG node" do relation = Table.new(:users) relation[:id].average.must_be_kind_of Nodes::Avg end - it 'should generate the proper SQL' do + it "should generate the proper SQL" do relation = Table.new(:users) mgr = relation.project relation[:id].average mgr.to_sql.must_be_like %{ @@ -325,13 +326,13 @@ class AttributeTest < Arel::Spec end end - describe '#maximum' do - it 'should create a MAX node' do + describe "#maximum" do + it "should create a MAX node" do relation = Table.new(:users) relation[:id].maximum.must_be_kind_of Nodes::Max end - it 'should generate proper SQL' do + it "should generate proper SQL" do relation = Table.new(:users) mgr = relation.project relation[:id].maximum mgr.to_sql.must_be_like %{ @@ -341,13 +342,13 @@ class AttributeTest < Arel::Spec end end - describe '#minimum' do - it 'should create a Min node' do + describe "#minimum" do + it "should create a Min node" do relation = Table.new(:users) relation[:id].minimum.must_be_kind_of Nodes::Min end - it 'should generate proper SQL' do + it "should generate proper SQL" do relation = Table.new(:users) mgr = relation.project relation[:id].minimum mgr.to_sql.must_be_like %{ @@ -357,13 +358,13 @@ class AttributeTest < Arel::Spec end end - describe '#sum' do - it 'should create a SUM node' do + describe "#sum" do + it "should create a SUM node" do relation = Table.new(:users) relation[:id].sum.must_be_kind_of Nodes::Sum end - it 'should generate the proper SQL' do + it "should generate the proper SQL" do relation = Table.new(:users) mgr = relation.project relation[:id].sum mgr.to_sql.must_be_like %{ @@ -373,13 +374,13 @@ class AttributeTest < Arel::Spec end end - describe '#count' do - it 'should return a count node' do + 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 + it "should take a distinct param" do relation = Table.new(:users) count = relation[:id].count(nil) count.must_be_kind_of Nodes::Count @@ -387,8 +388,8 @@ class AttributeTest < Arel::Spec end end - describe '#eq' do - it 'should return an equality node' do + describe "#eq" do + it "should return an equality node" do attribute = Attribute.new nil, nil equality = attribute.eq 1 equality.left.must_equal attribute @@ -396,7 +397,7 @@ class AttributeTest < Arel::Spec equality.must_be_kind_of Nodes::Equality end - it 'should generate = in sql' do + it "should generate = in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].eq(10) @@ -405,7 +406,7 @@ class AttributeTest < Arel::Spec } end - it 'should handle nil' do + it "should handle nil" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.where relation[:id].eq(nil) @@ -415,152 +416,152 @@ class AttributeTest < Arel::Spec end end - describe '#eq_any' do - it 'should create a Grouping node' do + 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 + relation[:id].eq_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + it "should not eat input" do relation = Table.new(:users) mgr = relation.project relation[:id] - values = [1,2] + values = [1, 2] mgr.where relation[:id].eq_any(values) - values.must_equal [1,2] + values.must_equal [1, 2] end end - describe '#eq_all' do - it 'should create a Grouping node' do + 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 + relation[:id].eq_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + it "should not eat input" do relation = Table.new(:users) mgr = relation.project relation[:id] - values = [1,2] + values = [1, 2] mgr.where relation[:id].eq_all(values) - values.must_equal [1,2] + values.must_equal [1, 2] end end - describe '#matches' do - it 'should create a Matches node' do + describe "#matches" do + it "should create a Matches node" do relation = Table.new(:users) - relation[:name].matches('%bacon%').must_be_kind_of Nodes::Matches + relation[:name].matches("%bacon%").must_be_kind_of Nodes::Matches end - it 'should generate LIKE in sql' do + it "should generate LIKE in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].matches('%bacon%') + 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 + 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 + relation[:name].matches_any(["%chunky%", "%bacon%"]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:name].matches_all(["%chunky%", "%bacon%"]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + relation[:name].does_not_match("%bacon%").must_be_kind_of Nodes::DoesNotMatch end - it 'should generate NOT LIKE in sql' do + 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.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 + 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 + relation[:name].does_not_match_any(["%chunky%", "%bacon%"]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:name].does_not_match_all(["%chunky%", "%bacon%"]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.where relation[:name].does_not_match_all(["%chunky%", "%bacon%"]) mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."name" NOT LIKE '%chunky%' AND "users"."name" NOT LIKE '%bacon%') } end end - describe 'with a range' do - it 'can be constructed with a standard range' do + describe "with a range" do + it "can be constructed with a standard range" do attribute = Attribute.new nil, nil node = attribute.between(1..3) @@ -573,7 +574,7 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with a range starting from -Infinity' do + it "can be constructed with a range starting from -Infinity" do attribute = Attribute.new nil, nil node = attribute.between(-::Float::INFINITY..3) @@ -583,7 +584,7 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with a quoted range starting from -Infinity' do + it "can be constructed with a quoted range starting from -Infinity" do attribute = Attribute.new nil, nil node = attribute.between(quoted_range(-::Float::INFINITY, 3, false)) @@ -593,7 +594,7 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with an exclusive range starting from -Infinity' do + it "can be constructed with an exclusive range starting from -Infinity" do attribute = Attribute.new nil, nil node = attribute.between(-::Float::INFINITY...3) @@ -603,7 +604,7 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with a quoted exclusive range starting from -Infinity' do + it "can be constructed with a quoted exclusive range starting from -Infinity" do attribute = Attribute.new nil, nil node = attribute.between(quoted_range(-::Float::INFINITY, 3, true)) @@ -613,14 +614,14 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with an infinite range' do + it "can be constructed with an infinite range" do attribute = Attribute.new nil, nil node = attribute.between(-::Float::INFINITY..::Float::INFINITY) node.must_equal Nodes::NotIn.new(attribute, []) end - it 'can be constructed with a quoted infinite range' do + it "can be constructed with a quoted infinite range" do attribute = Attribute.new nil, nil node = attribute.between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false)) @@ -628,7 +629,7 @@ class AttributeTest < Arel::Spec end - it 'can be constructed with a range ending at Infinity' do + it "can be constructed with a range ending at Infinity" do attribute = Attribute.new nil, nil node = attribute.between(0..::Float::INFINITY) @@ -638,7 +639,7 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with a quoted range ending at Infinity' do + it "can be constructed with a quoted range ending at Infinity" do attribute = Attribute.new nil, nil node = attribute.between(quoted_range(0, ::Float::INFINITY, false)) @@ -648,7 +649,7 @@ class AttributeTest < Arel::Spec ) end - it 'can be constructed with an exclusive range' do + it "can be constructed with an exclusive range" do attribute = Attribute.new nil, nil node = attribute.between(0...3) @@ -673,11 +674,11 @@ def quoted_range(begin_val, end_val, exclude) end end - describe '#in' do - it 'can be constructed with a subquery' do + describe "#in" do + it "can be constructed with a subquery" do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + mgr.where relation[:name].does_not_match_all(["%chunky%", "%bacon%"]) attribute = Attribute.new nil, nil node = attribute.in(mgr) @@ -685,7 +686,7 @@ def quoted_range(begin_val, end_val, exclude) node.must_equal Nodes::In.new(attribute, mgr.ast) end - it 'can be constructed with a list' do + it "can be constructed with a list" do attribute = Attribute.new nil, nil node = attribute.in([1, 2, 3]) @@ -699,7 +700,7 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'can be constructed with a random object' do + it "can be constructed with a random object" do attribute = Attribute.new nil, nil random_object = Object.new node = attribute.in(random_object) @@ -710,58 +711,58 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'should generate IN in sql' do + 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.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 + 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 + relation[:id].in_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].in_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.where relation[:id].in_all([[1, 2], [3, 4]]) mgr.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" WHERE ("users"."id" IN (1, 2) AND "users"."id" IN (3, 4)) } end end - describe 'with a range' do - it 'can be constructed with a standard range' do + describe "with a range" do + it "can be constructed with a standard range" do attribute = Attribute.new nil, nil node = attribute.not_between(1..3) node.must_equal Nodes::Grouping.new(Nodes::Or.new( - Nodes::LessThan.new( - attribute, - Nodes::Casted.new(1, attribute) - ), + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(1, attribute) + ), Nodes::GreaterThan.new( attribute, Nodes::Casted.new(3, attribute) @@ -769,7 +770,7 @@ def quoted_range(begin_val, end_val, exclude) )) end - it 'can be constructed with a range starting from -Infinity' do + it "can be constructed with a range starting from -Infinity" do attribute = Attribute.new nil, nil node = attribute.not_between(-::Float::INFINITY..3) @@ -779,7 +780,7 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'can be constructed with an exclusive range starting from -Infinity' do + it "can be constructed with an exclusive range starting from -Infinity" do attribute = Attribute.new nil, nil node = attribute.not_between(-::Float::INFINITY...3) @@ -789,14 +790,14 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'can be constructed with an infinite range' do + it "can be constructed with an infinite range" do attribute = Attribute.new nil, nil node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY) node.must_equal Nodes::In.new(attribute, []) end - it 'can be constructed with a range ending at Infinity' do + it "can be constructed with a range ending at Infinity" do attribute = Attribute.new nil, nil node = attribute.not_between(0..::Float::INFINITY) @@ -806,15 +807,15 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'can be constructed with an exclusive range' do + it "can be constructed with an exclusive range" do attribute = Attribute.new nil, nil node = attribute.not_between(0...3) node.must_equal Nodes::Grouping.new(Nodes::Or.new( - Nodes::LessThan.new( - attribute, - Nodes::Casted.new(0, attribute) - ), + Nodes::LessThan.new( + attribute, + Nodes::Casted.new(0, attribute) + ), Nodes::GreaterThanOrEqual.new( attribute, Nodes::Casted.new(3, attribute) @@ -823,11 +824,11 @@ def quoted_range(begin_val, end_val, exclude) end end - describe '#not_in' do - it 'can be constructed with a subquery' do + describe "#not_in" do + it "can be constructed with a subquery" do relation = Table.new(:users) mgr = relation.project relation[:id] - mgr.where relation[:name].does_not_match_all(['%chunky%','%bacon%']) + mgr.where relation[:name].does_not_match_all(["%chunky%", "%bacon%"]) attribute = Attribute.new nil, nil node = attribute.not_in(mgr) @@ -835,7 +836,7 @@ def quoted_range(begin_val, end_val, exclude) node.must_equal Nodes::NotIn.new(attribute, mgr.ast) end - it 'can be constructed with a Union' do + it "can be constructed with a Union" do relation = Table.new(:users) mgr1 = relation.project(relation[:id]) mgr2 = relation.project(relation[:id]) @@ -847,7 +848,7 @@ def quoted_range(begin_val, end_val, exclude) } end - it 'can be constructed with a list' do + it "can be constructed with a list" do attribute = Attribute.new nil, nil node = attribute.not_in([1, 2, 3]) @@ -861,7 +862,7 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'can be constructed with a random object' do + it "can be constructed with a random object" do attribute = Attribute.new nil, nil random_object = Object.new node = attribute.not_in(random_object) @@ -872,71 +873,71 @@ def quoted_range(begin_val, end_val, exclude) ) end - it 'should generate NOT IN in sql' do + 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.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 + 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 + relation[:id].not_in_any([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ORs in sql' do + 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.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 + 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 + relation[:id].not_in_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + relation[:id].eq_all([1, 2]).must_be_kind_of Nodes::Grouping end - it 'should generate ANDs in sql' do + 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.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 + 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 + it "should generate ASC in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.order relation[:id].asc @@ -946,13 +947,13 @@ def quoted_range(begin_val, end_val, exclude) end end - describe '#desc' do - it 'should create a Descending node' do + 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 + it "should generate DESC in sql" do relation = Table.new(:users) mgr = relation.project relation[:id] mgr.order relation[:id].desc @@ -962,18 +963,18 @@ def quoted_range(begin_val, end_val, exclude) end end - describe 'equality' do - describe '#to_sql' do - it 'should produce sql' do + describe "equality" do + describe "#to_sql" do + it "should produce sql" do table = Table.new :users - condition = table['id'].eq 1 + condition = table["id"].eq 1 condition.to_sql.must_equal '"users"."id" = 1' end end end - describe 'type casting' do - it 'does not type cast by default' do + describe "type casting" do + it "does not type cast by default" do table = Table.new(:foo) condition = table["id"].eq("1") @@ -981,7 +982,7 @@ def quoted_range(begin_val, end_val, exclude) condition.to_sql.must_equal %("foo"."id" = '1') end - it 'type casts when given an explicit caster' do + it "type casts when given an explicit caster" do fake_caster = Object.new def fake_caster.type_cast_for_database(attr_name, value) if attr_name == "id" @@ -997,7 +998,7 @@ def fake_caster.type_cast_for_database(attr_name, value) condition.to_sql.must_equal %("foo"."id" = 1 AND "foo"."other_id" = '2') end - it 'does not type cast SqlLiteral nodes' do + it "does not type cast SqlLiteral nodes" do fake_caster = Object.new def fake_caster.type_cast_for_database(attr_name, value) value.to_i diff --git a/activerecord/test/cases/arel/attributes_test.rb b/activerecord/test/cases/arel/attributes_test.rb index e17a6f5fd234c..b00af4bd2912e 100644 --- a/activerecord/test/cases/arel/attributes_test.rb +++ b/activerecord/test/cases/arel/attributes_test.rb @@ -1,62 +1,63 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel - describe 'Attributes' do - it 'responds to lower' do + 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 "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')] + 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')] + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 diff --git a/activerecord/test/cases/arel/collectors/bind_test.rb b/activerecord/test/cases/arel/collectors/bind_test.rb index febc7290a78af..9123a70c3e5ef 100644 --- a/activerecord/test/cases/arel/collectors/bind_test.rb +++ b/activerecord/test/cases/arel/collectors/bind_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Collectors @@ -10,15 +11,15 @@ def setup super end - def collect node + def collect(node) @visitor.accept(node, Collectors::Bind.new) end - def compile node + def compile(node) collect(node).value end - def ast_with_binds bvs + def ast_with_binds(bvs) table = Table.new(:users) manager = Arel::SelectManager.new table manager.where(table[:age].eq(Nodes::BindParam.new(bvs.shift))) diff --git a/activerecord/test/cases/arel/collectors/composite_test.rb b/activerecord/test/cases/arel/collectors/composite_test.rb index e330cae7a6718..545637496fa3c 100644 --- a/activerecord/test/cases/arel/collectors/composite_test.rb +++ b/activerecord/test/cases/arel/collectors/composite_test.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true -require_relative '../helper' -require 'arel/collectors/bind' -require 'arel/collectors/composite' +require_relative "../helper" + +require "arel/collectors/bind" +require "arel/collectors/composite" module Arel module Collectors @@ -13,18 +14,18 @@ def setup super end - def collect node + def collect(node) sql_collector = Collectors::SQLString.new bind_collector = Collectors::Bind.new collector = Collectors::Composite.new(sql_collector, bind_collector) @visitor.accept(node, collector) end - def compile node + def compile(node) collect(node).value end - def ast_with_binds bvs + def ast_with_binds(bvs) table = Table.new(:users) manager = Arel::SelectManager.new table manager.where(table[:age].eq(Nodes::BindParam.new(bvs.shift))) diff --git a/activerecord/test/cases/arel/collectors/sql_string_test.rb b/activerecord/test/cases/arel/collectors/sql_string_test.rb index a8ed3eb625449..380573494d5de 100644 --- a/activerecord/test/cases/arel/collectors/sql_string_test.rb +++ b/activerecord/test/cases/arel/collectors/sql_string_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Collectors @@ -10,15 +11,15 @@ def setup super end - def collect node + def collect(node) @visitor.accept(node, Collectors::SQLString.new) end - def compile node + def compile(node) collect(node).value end - def ast_with_binds bv + def ast_with_binds(bv) table = Table.new(:users) manager = Arel::SelectManager.new table manager.where(table[:age].eq(bv)) diff --git a/activerecord/test/cases/arel/collectors/substitute_bind_collector_test.rb b/activerecord/test/cases/arel/collectors/substitute_bind_collector_test.rb index 18f0ac14de679..255c8e79e9fa4 100644 --- a/activerecord/test/cases/arel/collectors/substitute_bind_collector_test.rb +++ b/activerecord/test/cases/arel/collectors/substitute_bind_collector_test.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true -require_relative '../helper' -require 'arel/collectors/substitute_binds' -require 'arel/collectors/sql_string' + +require_relative "../helper" +require "arel/collectors/substitute_binds" +require "arel/collectors/sql_string" module Arel module Collectors diff --git a/activerecord/test/cases/arel/crud_test.rb b/activerecord/test/cases/arel/crud_test.rb index 38a956b9dd369..f3cdd8927f1fd 100644 --- a/activerecord/test/cases/arel/crud_test.rb +++ b/activerecord/test/cases/arel/crud_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel class FakeCrudder < SelectManager @@ -10,12 +11,12 @@ def initialize @calls = [] @connection_pool = self @spec = self - @config = { :adapter => 'sqlite3' } + @config = { adapter: "sqlite3" } end def connection; self end - def method_missing name, *args + def method_missing(name, *args) @calls << [name, args] end end @@ -25,34 +26,34 @@ def method_missing name, *args attr_reader :engine attr_accessor :ctx - def initialize engine = FakeEngine.new + def initialize(engine = FakeEngine.new) super end end - describe 'crud' do - describe 'insert' do - it 'should call insert on the connection' do + 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']] + 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 + describe "update" do + it "should call update on the connection" do table = Table.new :users fc = FakeCrudder.new fc.from table - stmt = fc.compile_update [[table[:id], 'foo']], Arel::Attributes::Attribute.new(table, 'id') + stmt = fc.compile_update [[table[:id], "foo"]], Arel::Attributes::Attribute.new(table, "id") assert_instance_of Arel::UpdateManager, stmt end end - describe 'delete' do - it 'should call delete on the connection' do + describe "delete" do + it "should call delete on the connection" do table = Table.new :users fc = FakeCrudder.new fc.from table diff --git a/activerecord/test/cases/arel/delete_manager_test.rb b/activerecord/test/cases/arel/delete_manager_test.rb index 36d482f10bcdc..17a5271039654 100644 --- a/activerecord/test/cases/arel/delete_manager_test.rb +++ b/activerecord/test/cases/arel/delete_manager_test.rb @@ -1,15 +1,16 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel class DeleteManagerTest < Arel::Spec - describe 'new' do - it 'takes an engine' do + describe "new" do + it "takes an engine" do Arel::DeleteManager.new end end - it 'handles limit properly' do + it "handles limit properly" do table = Table.new(:users) dm = Arel::DeleteManager.new dm.take 10 @@ -17,23 +18,23 @@ class DeleteManagerTest < Arel::Spec assert_match(/LIMIT 10/, dm.to_sql) end - describe 'from' do - it 'uses from' do + describe "from" do + it "uses from" do table = Table.new(:users) dm = Arel::DeleteManager.new dm.from table dm.to_sql.must_be_like %{ DELETE FROM "users" } end - it 'chains' do + it "chains" do table = Table.new(:users) dm = Arel::DeleteManager.new dm.from(table).must_equal dm end end - describe 'where' do - it 'uses where values' do + describe "where" do + it "uses where values" do table = Table.new(:users) dm = Arel::DeleteManager.new dm.from table @@ -41,7 +42,7 @@ class DeleteManagerTest < Arel::Spec dm.to_sql.must_be_like %{ DELETE FROM "users" WHERE "users"."id" = 10} end - it 'chains' do + it "chains" do table = Table.new(:users) dm = Arel::DeleteManager.new dm.where(table[:id].eq(10)).must_equal dm diff --git a/activerecord/test/cases/arel/factory_methods_test.rb b/activerecord/test/cases/arel/factory_methods_test.rb index 2600b81e31e97..26d2cdd08dc5c 100644 --- a/activerecord/test/cases/arel/factory_methods_test.rb +++ b/activerecord/test/cases/arel/factory_methods_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel module FactoryMethods @@ -37,7 +38,7 @@ def test_create_false def test_lower lower = @factory.lower :one assert_instance_of Nodes::NamedFunction, lower - assert_equal 'LOWER', lower.name + assert_equal "LOWER", lower.name assert_equal [:one], lower.expressions.map(&:expr) end end diff --git a/activerecord/test/cases/arel/helper.rb b/activerecord/test/cases/arel/helper.rb index b716ee833f19d..1f8612f799ede 100644 --- a/activerecord/test/cases/arel/helper.rb +++ b/activerecord/test/cases/arel/helper.rb @@ -1,13 +1,14 @@ # frozen_string_literal: true -require 'rubygems' -require 'minitest/autorun' -require 'arel' -require_relative 'support/fake_record' +require "rubygems" +require "minitest/autorun" +require "arel" + +require_relative "support/fake_record" class Object - def must_be_like other - gsub(/\s+/, ' ').strip.must_equal other.gsub(/\s+/, ' ').strip + def must_be_like(other) + gsub(/\s+/, " ").strip.must_equal other.gsub(/\s+/, " ").strip end end @@ -24,9 +25,9 @@ def teardown super end - def assert_like expected, actual - assert_equal expected.gsub(/\s+/, ' ').strip, - actual.gsub(/\s+/, ' ').strip + def assert_like(expected, actual) + assert_equal expected.gsub(/\s+/, " ").strip, + actual.gsub(/\s+/, " ").strip end end diff --git a/activerecord/test/cases/arel/insert_manager_test.rb b/activerecord/test/cases/arel/insert_manager_test.rb index 33fab63fbc274..ae10ccf56cc37 100644 --- a/activerecord/test/cases/arel/insert_manager_test.rb +++ b/activerecord/test/cases/arel/insert_manager_test.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel class InsertManagerTest < Arel::Spec - describe 'new' do - it 'takes an engine' do + describe "new" do + it "takes an engine" do Arel::InsertManager.new end end - describe 'insert' do - it 'can create a Values node' do + describe "insert" do + it "can create a Values node" do manager = Arel::InsertManager.new values = manager.create_values %w{ a b }, %w{ c d } @@ -19,16 +20,16 @@ class InsertManagerTest < Arel::Spec assert_equal %w{ c d }, values.right end - it 'allows sql literals' do - manager = Arel::InsertManager.new + it "allows sql literals" do + manager = Arel::InsertManager.new manager.into Table.new(:users) - manager.values = manager.create_values [Arel.sql('*')], %w{ a } + manager.values = manager.create_values [Arel.sql("*")], %w{ a } manager.to_sql.must_be_like %{ INSERT INTO \"users\" VALUES (*) } end - it 'works with multiple values' do + it "works with multiple values" do table = Table.new(:users) manager = Arel::InsertManager.new manager.into table @@ -39,7 +40,7 @@ class InsertManagerTest < Arel::Spec manager.values = manager.create_values_list([ %w{1 david}, %w{2 kir}, - ["3", Arel.sql('DEFAULT')], + ["3", Arel.sql("DEFAULT")], ]) manager.to_sql.must_be_like %{ @@ -47,7 +48,7 @@ class InsertManagerTest < Arel::Spec } end - it 'literals in multiple values are not escaped' do + it "literals in multiple values are not escaped" do table = Table.new(:users) manager = Arel::InsertManager.new manager.into table @@ -55,8 +56,8 @@ class InsertManagerTest < Arel::Spec manager.columns << table[:name] manager.values = manager.create_values_list([ - [Arel.sql('*')], - [Arel.sql('DEFAULT')], + [Arel.sql("*")], + [Arel.sql("DEFAULT")], ]) manager.to_sql.must_be_like %{ @@ -64,7 +65,7 @@ class InsertManagerTest < Arel::Spec } end - it 'works with multiple single values' do + it "works with multiple single values" do table = Table.new(:users) manager = Arel::InsertManager.new manager.into table @@ -74,7 +75,7 @@ class InsertManagerTest < Arel::Spec manager.values = manager.create_values_list([ %w{david}, %w{kir}, - [Arel.sql('DEFAULT')], + [Arel.sql("DEFAULT")], ]) manager.to_sql.must_be_like %{ @@ -114,26 +115,26 @@ class InsertManagerTest < Arel::Spec } end - it 'takes a list of lists' do + it "takes a list of lists" do table = Table.new(:users) manager = Arel::InsertManager.new manager.into table - manager.insert [[table[:id], 1], [table[:name], 'aaron']] + 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 + it "defaults the table" do table = Table.new(:users) manager = Arel::InsertManager.new - manager.insert [[table[:id], 1], [table[:name], 'aaron']] + manager.insert [[table[:id], 1], [table[:name], "aaron"]] manager.to_sql.must_be_like %{ INSERT INTO "users" ("id", "name") VALUES (1, 'aaron') } end - it 'noop for empty list' do + it "noop for empty list" do table = Table.new(:users) manager = Arel::InsertManager.new manager.insert [[table[:id], 1]] @@ -143,21 +144,21 @@ class InsertManagerTest < Arel::Spec } end - it 'is chainable' do + it "is chainable" do table = Table.new(:users) manager = Arel::InsertManager.new - insert_result = manager.insert [[table[:id],1]] + insert_result = manager.insert [[table[:id], 1]] assert_equal manager, insert_result end end - describe 'into' do - it 'takes a Table and chains' do + describe "into" do + it "takes a Table and chains" do manager = Arel::InsertManager.new manager.into(Table.new(:users)).must_equal manager end - it 'converts to sql' do + it "converts to sql" do table = Table.new :users manager = Arel::InsertManager.new manager.into table @@ -167,7 +168,7 @@ class InsertManagerTest < Arel::Spec end end - describe 'columns' do + describe "columns" do it "converts to sql" do table = Table.new :users manager = Arel::InsertManager.new @@ -209,7 +210,7 @@ class InsertManagerTest < Arel::Spec manager = Arel::InsertManager.new manager.into table - manager.values = Nodes::Values.new [1, 'aaron'] + manager.values = Nodes::Values.new [1, "aaron"] manager.columns << table[:id] manager.columns << table[:name] manager.to_sql.must_be_like %{ @@ -227,7 +228,7 @@ class InsertManagerTest < Arel::Spec manager.into table select = Arel::SelectManager.new - select.project Arel.sql('1') + select.project Arel.sql("1") select.project Arel.sql('"aaron"') manager.select select @@ -239,6 +240,5 @@ class InsertManagerTest < Arel::Spec end end - end end diff --git a/activerecord/test/cases/arel/nodes/and_test.rb b/activerecord/test/cases/arel/nodes/and_test.rb index de63e0bb31880..eff54abd91e75 100644 --- a/activerecord/test/cases/arel/nodes/and_test.rb +++ b/activerecord/test/cases/arel/nodes/and_test.rb @@ -1,21 +1,21 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../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'])] + 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'])] + it "is not equal with different ivars" do + array = [And.new(["foo", "bar"]), And.new(["foo", "baz"])] assert_equal 2, array.uniq.size end end end end end - diff --git a/activerecord/test/cases/arel/nodes/as_test.rb b/activerecord/test/cases/arel/nodes/as_test.rb index 09c8aa8d62b65..1169ea11c9588 100644 --- a/activerecord/test/cases/arel/nodes/as_test.rb +++ b/activerecord/test/cases/arel/nodes/as_test.rb @@ -1,32 +1,33 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'As' do - describe '#as' do - it 'makes an AS node' do + describe "As" do + describe "#as" do + it "makes an AS node" do attr = Table.new(:users)[:id] - as = attr.as(Arel.sql('foo')) + as = attr.as(Arel.sql("foo")) assert_equal attr, as.left - assert_equal 'foo', as.right + assert_equal "foo", as.right end - it 'converts right to SqlLiteral if a string' do + it "converts right to SqlLiteral if a string" do attr = Table.new(:users)[:id] - as = attr.as('foo') + 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')] + 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')] + 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 diff --git a/activerecord/test/cases/arel/nodes/ascending_test.rb b/activerecord/test/cases/arel/nodes/ascending_test.rb index 5c73e69fa557c..1efb16222ae6f 100644 --- a/activerecord/test/cases/arel/nodes/ascending_test.rb +++ b/activerecord/test/cases/arel/nodes/ascending_test.rb @@ -1,43 +1,44 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes class TestAscending < Arel::Test def test_construct - ascending = Ascending.new 'zomg' - assert_equal 'zomg', ascending.expr + ascending = Ascending.new "zomg" + assert_equal "zomg", ascending.expr end def test_reverse - ascending = Ascending.new 'zomg' + 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' + ascending = Ascending.new "zomg" assert_equal :asc, ascending.direction end def test_ascending? - ascending = Ascending.new 'zomg' + ascending = Ascending.new "zomg" assert ascending.ascending? end def test_descending? - ascending = Ascending.new 'zomg' + ascending = Ascending.new "zomg" assert !ascending.descending? end def test_equality_with_same_ivars - array = [Ascending.new('zomg'), Ascending.new('zomg')] + 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!')] + array = [Ascending.new("zomg"), Ascending.new("zomg!")] assert_equal 2, array.uniq.size end end diff --git a/activerecord/test/cases/arel/nodes/bin_test.rb b/activerecord/test/cases/arel/nodes/bin_test.rb index 923a296adf2d7..ee2ec3cf2f641 100644 --- a/activerecord/test/cases/arel/nodes/bin_test.rb +++ b/activerecord/test/cases/arel/nodes/bin_test.rb @@ -1,32 +1,33 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes class TestBin < Arel::Test def test_new - assert Arel::Nodes::Bin.new('zomg') + assert Arel::Nodes::Bin.new("zomg") end def test_default_to_sql viz = Arel::Visitors::ToSql.new Table.engine.connection_pool - node = Arel::Nodes::Bin.new(Arel.sql('zomg')) - assert_equal 'zomg', viz.accept(node, Collectors::SQLString.new).value + node = Arel::Nodes::Bin.new(Arel.sql("zomg")) + assert_equal "zomg", viz.accept(node, Collectors::SQLString.new).value end def test_mysql_to_sql viz = Arel::Visitors::MySQL.new Table.engine.connection_pool - node = Arel::Nodes::Bin.new(Arel.sql('zomg')) - assert_equal 'BINARY zomg', viz.accept(node, Collectors::SQLString.new).value + node = Arel::Nodes::Bin.new(Arel.sql("zomg")) + assert_equal "BINARY zomg", viz.accept(node, Collectors::SQLString.new).value end def test_equality_with_same_ivars - array = [Bin.new('zomg'), Bin.new('zomg')] + 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!')] + array = [Bin.new("zomg"), Bin.new("zomg!")] assert_equal 2, array.uniq.size end end diff --git a/activerecord/test/cases/arel/nodes/binary_test.rb b/activerecord/test/cases/arel/nodes/binary_test.rb index 0bea35f7dd336..9bc55a155b1df 100644 --- a/activerecord/test/cases/arel/nodes/binary_test.rb +++ b/activerecord/test/cases/arel/nodes/binary_test.rb @@ -1,22 +1,23 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'Binary' do - describe '#hash' do - it 'generates a hash based on its value' do - eq = Equality.new('foo', 'bar') - eq2 = Equality.new('foo', 'bar') - eq3 = Equality.new('bar', 'baz') + describe "Binary" do + describe "#hash" do + it "generates a hash based on its value" do + eq = Equality.new("foo", "bar") + eq2 = Equality.new("foo", "bar") + eq3 = Equality.new("bar", "baz") assert_equal eq.hash, eq2.hash refute_equal eq.hash, eq3.hash end - it 'generates a hash specific to its class' do - eq = Equality.new('foo', 'bar') - neq = NotEqual.new('foo', 'bar') + it "generates a hash specific to its class" do + eq = Equality.new("foo", "bar") + neq = NotEqual.new("foo", "bar") refute_equal eq.hash, neq.hash end diff --git a/activerecord/test/cases/arel/nodes/bind_param_test.rb b/activerecord/test/cases/arel/nodes/bind_param_test.rb index 665581edcecbb..37a362ece4ebd 100644 --- a/activerecord/test/cases/arel/nodes/bind_param_test.rb +++ b/activerecord/test/cases/arel/nodes/bind_param_test.rb @@ -1,19 +1,20 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'BindParam' do - it 'is equal to other bind params with the same value' do + describe "BindParam" do + it "is equal to other bind params with the same value" do BindParam.new(1).must_equal(BindParam.new(1)) BindParam.new("foo").must_equal(BindParam.new("foo")) end - it 'is not equal to other nodes' do + it "is not equal to other nodes" do BindParam.new(nil).wont_equal(Node.new) end - it 'is not equal to bind params with different values' do + it "is not equal to bind params with different values" do BindParam.new(1).wont_equal(BindParam.new(2)) end end diff --git a/activerecord/test/cases/arel/nodes/case_test.rb b/activerecord/test/cases/arel/nodes/case_test.rb index 70364fe6ab4c0..2c087e624e3c4 100644 --- a/activerecord/test/cases/arel/nodes/case_test.rb +++ b/activerecord/test/cases/arel/nodes/case_test.rb @@ -1,26 +1,27 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'Case' do - describe '#initialize' do - it 'sets case expression from first argument' do - node = Case.new 'foo' + describe "Case" do + describe "#initialize" do + it "sets case expression from first argument" do + node = Case.new "foo" - assert_equal 'foo', node.case + assert_equal "foo", node.case end - it 'sets default case from second argument' do - node = Case.new nil, 'bar' + it "sets default case from second argument" do + node = Case.new nil, "bar" - assert_equal 'bar', node.default + assert_equal "bar", node.default end end - describe '#clone' do - it 'clones case, conditions and default' do - foo = Nodes.build_quoted 'foo' + describe "#clone" do + it "clones case, conditions and default" do + foo = Nodes.build_quoted "foo" node = Case.new node.case = foo @@ -40,9 +41,9 @@ module Nodes end end - describe 'equality' do - it 'is equal with equal ivars' do - foo = Nodes.build_quoted 'foo' + describe "equality" do + it "is equal with equal ivars" do + foo = Nodes.build_quoted "foo" one = Nodes.build_quoted 1 zero = Nodes.build_quoted 0 @@ -59,9 +60,9 @@ module Nodes assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do - foo = Nodes.build_quoted 'foo' - bar = Nodes.build_quoted 'bar' + it "is not equal with different ivars" do + foo = Nodes.build_quoted "foo" + bar = Nodes.build_quoted "bar" one = Nodes.build_quoted 1 zero = Nodes.build_quoted 0 diff --git a/activerecord/test/cases/arel/nodes/casted_test.rb b/activerecord/test/cases/arel/nodes/casted_test.rb index a6e2dd2294682..e27f58a4e2d1d 100644 --- a/activerecord/test/cases/arel/nodes/casted_test.rb +++ b/activerecord/test/cases/arel/nodes/casted_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes describe Casted do - describe '#hash' do - it 'is equal when eql? returns true' do + describe "#hash" do + it "is equal when eql? returns true" do one = Casted.new 1, 2 also_one = Casted.new 1, 2 diff --git a/activerecord/test/cases/arel/nodes/count_test.rb b/activerecord/test/cases/arel/nodes/count_test.rb index 28d8481993ea3..3107659e77ab0 100644 --- a/activerecord/test/cases/arel/nodes/count_test.rb +++ b/activerecord/test/cases/arel/nodes/count_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" class Arel::Nodes::CountTest < Arel::Spec describe "as" do - it 'should alias the count' do + it "should alias the count" do table = Arel::Table.new :users - table[:id].count.as('foo').to_sql.must_be_like %{ + table[:id].count.as("foo").to_sql.must_be_like %{ COUNT("users"."id") AS foo } end @@ -20,20 +21,20 @@ class Arel::Nodes::CountTest < Arel::Spec end end - describe 'equality' do - it 'is equal with equal ivars' do - array = [Arel::Nodes::Count.new('foo'), Arel::Nodes::Count.new('foo')] + 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!')] + 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 - describe 'math' do - it 'allows mathematical functions' do + describe "math" do + it "allows mathematical functions" do table = Arel::Table.new :users (table[:id].count + 1).to_sql.must_be_like %{ (COUNT("users"."id") + 1) diff --git a/activerecord/test/cases/arel/nodes/delete_statement_test.rb b/activerecord/test/cases/arel/nodes/delete_statement_test.rb index ada89646469eb..3f078063a46a4 100644 --- a/activerecord/test/cases/arel/nodes/delete_statement_test.rb +++ b/activerecord/test/cases/arel/nodes/delete_statement_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" describe Arel::Nodes::DeleteStatement do describe "#clone" do @@ -13,8 +14,8 @@ end end - describe 'equality' do - it 'is equal with equal ivars' do + 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 @@ -23,7 +24,7 @@ assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + it "is not equal with different ivars" do statement1 = Arel::Nodes::DeleteStatement.new statement1.wheres = %w[a b c] statement2 = Arel::Nodes::DeleteStatement.new diff --git a/activerecord/test/cases/arel/nodes/descending_test.rb b/activerecord/test/cases/arel/nodes/descending_test.rb index 5fe0ba62b0ddd..45e22de17b885 100644 --- a/activerecord/test/cases/arel/nodes/descending_test.rb +++ b/activerecord/test/cases/arel/nodes/descending_test.rb @@ -1,43 +1,44 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes class TestDescending < Arel::Test def test_construct - descending = Descending.new 'zomg' - assert_equal 'zomg', descending.expr + descending = Descending.new "zomg" + assert_equal "zomg", descending.expr end def test_reverse - descending = Descending.new 'zomg' + 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' + descending = Descending.new "zomg" assert_equal :desc, descending.direction end def test_ascending? - descending = Descending.new 'zomg' + descending = Descending.new "zomg" assert !descending.ascending? end def test_descending? - descending = Descending.new 'zomg' + descending = Descending.new "zomg" assert descending.descending? end def test_equality_with_same_ivars - array = [Descending.new('zomg'), Descending.new('zomg')] + 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!')] + array = [Descending.new("zomg"), Descending.new("zomg!")] assert_equal 2, array.uniq.size end end diff --git a/activerecord/test/cases/arel/nodes/distinct_test.rb b/activerecord/test/cases/arel/nodes/distinct_test.rb index 465700118ee18..de5f0ee588571 100644 --- a/activerecord/test/cases/arel/nodes/distinct_test.rb +++ b/activerecord/test/cases/arel/nodes/distinct_test.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'Distinct' do - describe 'equality' do - it 'is equal to other distinct nodes' do + 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 + it "is not equal with other nodes" do array = [Distinct.new, Node.new] assert_equal 2, array.uniq.size end @@ -18,4 +19,3 @@ module Nodes end end end - diff --git a/activerecord/test/cases/arel/nodes/equality_test.rb b/activerecord/test/cases/arel/nodes/equality_test.rb index 28a74de3211fb..e173720e86f19 100644 --- a/activerecord/test/cases/arel/nodes/equality_test.rb +++ b/activerecord/test/cases/arel/nodes/equality_test.rb @@ -1,37 +1,38 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'equality' do + describe "equality" do # FIXME: backwards compat - describe 'backwards compat' do - describe 'operator' do - it 'returns :==' do + describe "backwards compat" do + describe "operator" do + it "returns :==" do attr = Table.new(:users)[:id] - left = attr.eq(10) + left = attr.eq(10) left.operator.must_equal :== end end - describe 'operand1' do + describe "operand1" do it "should equal left" do attr = Table.new(:users)[:id] - left = attr.eq(10) + left = attr.eq(10) left.left.must_equal left.operand1 end end - describe 'operand2' do + describe "operand2" do it "should equal right" do attr = Table.new(:users)[:id] - left = attr.eq(10) + left = attr.eq(10) left.right.must_equal left.operand2 end end - describe 'to_sql' do - it 'takes an engine' do + describe "to_sql" do + it "takes an engine" do engine = FakeRecord::Base.new engine.connection.extend Module.new { attr_accessor :quote_count @@ -49,8 +50,8 @@ def quote_table_name(*args) @quote_count += 1; super; end end end - describe 'or' do - it 'makes an OR node' do + describe "or" do + it "makes an OR node" do attr = Table.new(:users)[:id] left = attr.eq(10) right = attr.eq(11) @@ -60,8 +61,8 @@ def quote_table_name(*args) @quote_count += 1; super; end end end - describe 'and' do - it 'makes and AND node' do + describe "and" do + it "makes and AND node" do attr = Table.new(:users)[:id] left = attr.eq(10) right = attr.eq(11) @@ -71,13 +72,13 @@ def quote_table_name(*args) @quote_count += 1; super; end end end - it 'is equal with equal ivars' do - array = [Equality.new('foo', 'bar'), Equality.new('foo', 'bar')] + 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')] + 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 diff --git a/activerecord/test/cases/arel/nodes/extract_test.rb b/activerecord/test/cases/arel/nodes/extract_test.rb index f6dc1626a4008..8fc1e04d670f6 100644 --- a/activerecord/test/cases/arel/nodes/extract_test.rb +++ b/activerecord/test/cases/arel/nodes/extract_test.rb @@ -1,41 +1,42 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" class Arel::Nodes::ExtractTest < Arel::Spec it "should extract field" do table = Arel::Table.new :users - table[:timestamp].extract('date').to_sql.must_be_like %{ + table[:timestamp].extract("date").to_sql.must_be_like %{ EXTRACT(DATE FROM "users"."timestamp") } end describe "as" do - it 'should alias the extract' do + it "should alias the extract" do table = Arel::Table.new :users - table[:timestamp].extract('date').as('foo').to_sql.must_be_like %{ + table[:timestamp].extract("date").as("foo").to_sql.must_be_like %{ EXTRACT(DATE FROM "users"."timestamp") AS foo } end - it 'should not mutate the extract' do + it "should not mutate the extract" do table = Arel::Table.new :users - extract = table[:timestamp].extract('date') + extract = table[:timestamp].extract("date") before = extract.dup - extract.as('foo') + extract.as("foo") assert_equal extract, before end end - describe 'equality' do - it 'is equal with equal ivars' do + describe "equality" do + it "is equal with equal ivars" do table = Arel::Table.new :users - array = [table[:attr].extract('foo'), table[:attr].extract('foo')] + array = [table[:attr].extract("foo"), table[:attr].extract("foo")] assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + it "is not equal with different ivars" do table = Arel::Table.new :users - array = [table[:attr].extract('foo'), table[:attr].extract('bar')] + array = [table[:attr].extract("foo"), table[:attr].extract("bar")] assert_equal 2, array.uniq.size end end diff --git a/activerecord/test/cases/arel/nodes/false_test.rb b/activerecord/test/cases/arel/nodes/false_test.rb index 8b91dc227c08e..4ecf8e332eb83 100644 --- a/activerecord/test/cases/arel/nodes/false_test.rb +++ b/activerecord/test/cases/arel/nodes/false_test.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'False' do - describe 'equality' do - it 'is equal to other false nodes' do + 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 + it "is not equal with other nodes" do array = [False.new, Node.new] assert_equal 2, array.uniq.size end @@ -18,4 +19,3 @@ module Nodes end end end - diff --git a/activerecord/test/cases/arel/nodes/grouping_test.rb b/activerecord/test/cases/arel/nodes/grouping_test.rb index 7ad1584f0f691..03d5c142d50e0 100644 --- a/activerecord/test/cases/arel/nodes/grouping_test.rb +++ b/activerecord/test/cases/arel/nodes/grouping_test.rb @@ -1,26 +1,26 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes class GroupingTest < Arel::Spec - it 'should create Equality nodes' do - grouping = Grouping.new(Nodes.build_quoted('foo')) - grouping.eq('foo').to_sql.must_be_like %q{('foo') = 'foo'} + it "should create Equality nodes" do + grouping = Grouping.new(Nodes.build_quoted("foo")) + grouping.eq("foo").to_sql.must_be_like "('foo') = 'foo'" end - describe 'equality' do - it 'is equal with equal ivars' do - array = [Grouping.new('foo'), Grouping.new('foo')] + 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')] + it "is not equal with different ivars" do + array = [Grouping.new("foo"), Grouping.new("bar")] assert_equal 2, array.uniq.size end end end end end - diff --git a/activerecord/test/cases/arel/nodes/infix_operation_test.rb b/activerecord/test/cases/arel/nodes/infix_operation_test.rb index 28a4710dc0756..dcf2200c127a1 100644 --- a/activerecord/test/cases/arel/nodes/infix_operation_test.rb +++ b/activerecord/test/cases/arel/nodes/infix_operation_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes @@ -13,10 +14,10 @@ def test_construct def test_operation_alias operation = InfixOperation.new :+, 1, 2 - aliaz = operation.as('zomg') + aliaz = operation.as("zomg") assert_kind_of As, aliaz assert_equal operation, aliaz.left - assert_equal 'zomg', aliaz.right + assert_equal "zomg", aliaz.right end def test_operation_ordering diff --git a/activerecord/test/cases/arel/nodes/insert_statement_test.rb b/activerecord/test/cases/arel/nodes/insert_statement_test.rb index 87f9d83a32adf..252a0d0d0b0fc 100644 --- a/activerecord/test/cases/arel/nodes/insert_statement_test.rb +++ b/activerecord/test/cases/arel/nodes/insert_statement_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" describe Arel::Nodes::InsertStatement do describe "#clone" do @@ -17,8 +18,8 @@ end end - describe 'equality' do - it 'is equal with equal ivars' do + 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] @@ -29,7 +30,7 @@ assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + 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] diff --git a/activerecord/test/cases/arel/nodes/named_function_test.rb b/activerecord/test/cases/arel/nodes/named_function_test.rb index 30f6dac595d96..dbd7ae43be503 100644 --- a/activerecord/test/cases/arel/nodes/named_function_test.rb +++ b/activerecord/test/cases/arel/nodes/named_function_test.rb @@ -1,44 +1,45 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes class TestNamedFunction < Arel::Test def test_construct - function = NamedFunction.new 'omg', 'zomg' - assert_equal 'omg', function.name - assert_equal 'zomg', function.expressions + 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 + 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 + 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 + 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 + assert_equal "wth", function.alias end def test_equality_with_same_ivars array = [ - NamedFunction.new('omg', 'zomg', 'wth'), - NamedFunction.new('omg', 'zomg', 'wth') + 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') + NamedFunction.new("omg", "zomg", "wth"), + NamedFunction.new("zomg", "zomg", "wth") ] assert_equal 2, array.uniq.size end diff --git a/activerecord/test/cases/arel/nodes/node_test.rb b/activerecord/test/cases/arel/nodes/node_test.rb index c1d3a01d1ce41..f4f07ef2c5f3f 100644 --- a/activerecord/test/cases/arel/nodes/node_test.rb +++ b/activerecord/test/cases/arel/nodes/node_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel class TestNode < Arel::Test diff --git a/activerecord/test/cases/arel/nodes/not_test.rb b/activerecord/test/cases/arel/nodes/not_test.rb index 15f94a6f10fab..481e6787008a2 100644 --- a/activerecord/test/cases/arel/nodes/not_test.rb +++ b/activerecord/test/cases/arel/nodes/not_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'not' do - describe '#not' do - it 'makes a NOT node' do + describe "not" do + describe "#not" do + it "makes a NOT node" do attr = Table.new(:users)[:id] expr = attr.eq(10) node = expr.not @@ -14,14 +15,14 @@ module Nodes end end - describe 'equality' do - it 'is equal with equal ivars' do - array = [Not.new('foo'), Not.new('foo')] + 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')] + it "is not equal with different ivars" do + array = [Not.new("foo"), Not.new("baz")] assert_equal 2, array.uniq.size end end diff --git a/activerecord/test/cases/arel/nodes/or_test.rb b/activerecord/test/cases/arel/nodes/or_test.rb index 4f8d56d1657b0..93f826740d1c7 100644 --- a/activerecord/test/cases/arel/nodes/or_test.rb +++ b/activerecord/test/cases/arel/nodes/or_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'or' do - describe '#or' do - it 'makes an OR node' do + 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) @@ -19,14 +20,14 @@ module Nodes end end - describe 'equality' do - it 'is equal with equal ivars' do - array = [Or.new('foo', 'bar'), Or.new('foo', 'bar')] + 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')] + 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 diff --git a/activerecord/test/cases/arel/nodes/over_test.rb b/activerecord/test/cases/arel/nodes/over_test.rb index c9804c395f542..981ec2e34bf5e 100644 --- a/activerecord/test/cases/arel/nodes/over_test.rb +++ b/activerecord/test/cases/arel/nodes/over_test.rb @@ -1,36 +1,37 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" class Arel::Nodes::OverTest < Arel::Spec - describe 'as' do - it 'should alias the expression' 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 %{ + 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 + 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 %{ + 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 + 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 %{ + 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 + 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 () @@ -38,29 +39,29 @@ class Arel::Nodes::OverTest < Arel::Spec end end - describe 'with expression' do - it 'should use definition in sub-expression' do + 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']) + 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 + describe "equality" do + it "is equal with equal ivars" do array = [ - Arel::Nodes::Over.new('foo', 'bar'), - Arel::Nodes::Over.new('foo', 'bar') + 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 + it "is not equal with different ivars" do array = [ - Arel::Nodes::Over.new('foo', 'bar'), - Arel::Nodes::Over.new('foo', 'baz') + Arel::Nodes::Over.new("foo", "bar"), + Arel::Nodes::Over.new("foo", "baz") ] assert_equal 2, array.uniq.size end diff --git a/activerecord/test/cases/arel/nodes/select_core_test.rb b/activerecord/test/cases/arel/nodes/select_core_test.rb index bbb06666b600c..1cdc7a2360d50 100644 --- a/activerecord/test/cases/arel/nodes/select_core_test.rb +++ b/activerecord/test/cases/arel/nodes/select_core_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes @@ -25,7 +26,7 @@ def test_set_quantifier core = Arel::Nodes::SelectCore.new core.set_quantifier = Arel::Nodes::Distinct.new viz = Arel::Visitors::ToSql.new Table.engine.connection_pool - assert_match 'DISTINCT', viz.accept(core, Collectors::SQLString.new).value + assert_match "DISTINCT", viz.accept(core, Collectors::SQLString.new).value end def test_equality_with_same_ivars diff --git a/activerecord/test/cases/arel/nodes/select_statement_test.rb b/activerecord/test/cases/arel/nodes/select_statement_test.rb index 5e313e03fa01d..a91605de3e270 100644 --- a/activerecord/test/cases/arel/nodes/select_statement_test.rb +++ b/activerecord/test/cases/arel/nodes/select_statement_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" describe Arel::Nodes::SelectStatement do describe "#clone" do @@ -12,37 +13,37 @@ end end - describe 'equality' do - it 'is equal with equal ivars' do + 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' + 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' + statement2.with = "zomg" array = [statement1, statement2] assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + 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' + 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' + statement2.with = "wth" array = [statement1, statement2] assert_equal 2, array.uniq.size end diff --git a/activerecord/test/cases/arel/nodes/sql_literal_test.rb b/activerecord/test/cases/arel/nodes/sql_literal_test.rb index 0c4f23be785c8..3b95fed1f4869 100644 --- a/activerecord/test/cases/arel/nodes/sql_literal_test.rb +++ b/activerecord/test/cases/arel/nodes/sql_literal_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -require_relative '../helper' -require 'yaml' + +require_relative "../helper" +require "yaml" module Arel module Nodes @@ -9,64 +10,64 @@ class SqlLiteralTest < Arel::Spec @visitor = Visitors::ToSql.new Table.engine.connection end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - describe 'sql' do - it 'makes a sql literal node' do - sql = Arel.sql 'foo' + 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 + describe "count" do + it "makes a count node" do + node = SqlLiteral.new("*").count compile(node).must_be_like %{ COUNT(*) } end - it 'makes a distinct node' do - node = SqlLiteral.new('*').count true + it "makes a distinct node" do + node = SqlLiteral.new("*").count true compile(node).must_be_like %{ COUNT(DISTINCT *) } end end - describe 'equality' do - it 'makes an equality node' do - node = SqlLiteral.new('foo').eq(1) + describe "equality" do + it "makes an equality node" do + node = SqlLiteral.new("foo").eq(1) compile(node).must_be_like %{ foo = 1 } end - it 'is equal with equal contents' do - array = [SqlLiteral.new('foo'), SqlLiteral.new('foo')] + 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')] + 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]) + it "makes a grouping node with an or node" do + node = SqlLiteral.new("foo").eq_any([1, 2]) compile(node).must_be_like %{ (foo = 1 OR foo = 2) } end end describe 'grouped "and" equality' do - it 'makes a grouping node with an and node' do - node = SqlLiteral.new('foo').eq_all([1,2]) + it "makes a grouping node with an and node" do + node = SqlLiteral.new("foo").eq_all([1, 2]) compile(node).must_be_like %{ (foo = 1 AND foo = 2) } end end - describe 'serialization' do - it 'serializes into YAML' do - yaml_literal = SqlLiteral.new('foo').to_yaml - assert_equal('foo', YAML.load(yaml_literal)) + describe "serialization" do + it "serializes into YAML" do + yaml_literal = SqlLiteral.new("foo").to_yaml + assert_equal("foo", YAML.load(yaml_literal)) end end end diff --git a/activerecord/test/cases/arel/nodes/sum_test.rb b/activerecord/test/cases/arel/nodes/sum_test.rb index 46c908d872e87..50159649518fa 100644 --- a/activerecord/test/cases/arel/nodes/sum_test.rb +++ b/activerecord/test/cases/arel/nodes/sum_test.rb @@ -1,30 +1,31 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" class Arel::Nodes::SumTest < Arel::Spec describe "as" do - it 'should alias the sum' do + it "should alias the sum" do table = Arel::Table.new :users - table[:id].sum.as('foo').to_sql.must_be_like %{ + 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')] + 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!')] + it "is not equal with different ivars" do + array = [Arel::Nodes::Sum.new("foo"), Arel::Nodes::Sum.new("foo!")] assert_equal 2, array.uniq.size end end - - describe 'order' do - it 'should order the sum' do + + describe "order" do + it "should order the sum" do table = Arel::Table.new :users table[:id].sum.desc.to_sql.must_be_like %{ SUM("users"."id") DESC diff --git a/activerecord/test/cases/arel/nodes/table_alias_test.rb b/activerecord/test/cases/arel/nodes/table_alias_test.rb index b1b49919d5f73..c661b6771eecf 100644 --- a/activerecord/test/cases/arel/nodes/table_alias_test.rb +++ b/activerecord/test/cases/arel/nodes/table_alias_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'table alias' do - describe 'equality' do - it 'is equal with equal ivars' do + describe "table alias" do + describe "equality" do + it "is equal with equal ivars" do relation1 = Table.new(:users) node1 = TableAlias.new relation1, :foo relation2 = Table.new(:users) @@ -14,7 +15,7 @@ module Nodes assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + it "is not equal with different ivars" do relation1 = Table.new(:users) node1 = TableAlias.new relation1, :foo relation2 = Table.new(:users) diff --git a/activerecord/test/cases/arel/nodes/true_test.rb b/activerecord/test/cases/arel/nodes/true_test.rb index 198e7b1aa4d09..1e85fe7d48c0e 100644 --- a/activerecord/test/cases/arel/nodes/true_test.rb +++ b/activerecord/test/cases/arel/nodes/true_test.rb @@ -1,16 +1,17 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'True' do - describe 'equality' do - it 'is equal to other true nodes' do + 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 + it "is not equal with other nodes" do array = [True.new, Node.new] assert_equal 2, array.uniq.size end @@ -18,5 +19,3 @@ module Nodes end end end - - diff --git a/activerecord/test/cases/arel/nodes/unary_operation_test.rb b/activerecord/test/cases/arel/nodes/unary_operation_test.rb index e76b59c8e14c0..f0dd0c625c680 100644 --- a/activerecord/test/cases/arel/nodes/unary_operation_test.rb +++ b/activerecord/test/cases/arel/nodes/unary_operation_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes @@ -12,10 +13,10 @@ def test_construct def test_operation_alias operation = UnaryOperation.new :-, 1 - aliaz = operation.as('zomg') + aliaz = operation.as("zomg") assert_kind_of As, aliaz assert_equal operation, aliaz.left - assert_equal 'zomg', aliaz.right + assert_equal "zomg", aliaz.right end def test_operation_ordering diff --git a/activerecord/test/cases/arel/nodes/update_statement_test.rb b/activerecord/test/cases/arel/nodes/update_statement_test.rb index 3a635f75d6359..a83ce32f682dd 100644 --- a/activerecord/test/cases/arel/nodes/update_statement_test.rb +++ b/activerecord/test/cases/arel/nodes/update_statement_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" describe Arel::Nodes::UpdateStatement do describe "#clone" do @@ -17,41 +18,41 @@ end end - describe 'equality' do - it 'is equal with equal ivars' do + describe "equality" do + it "is equal with equal ivars" do statement1 = Arel::Nodes::UpdateStatement.new - statement1.relation = 'zomg' + statement1.relation = "zomg" statement1.wheres = 2 statement1.values = false statement1.orders = %w[x y z] statement1.limit = 42 - statement1.key = 'zomg' + statement1.key = "zomg" statement2 = Arel::Nodes::UpdateStatement.new - statement2.relation = 'zomg' + statement2.relation = "zomg" statement2.wheres = 2 statement2.values = false statement2.orders = %w[x y z] statement2.limit = 42 - statement2.key = 'zomg' + statement2.key = "zomg" array = [statement1, statement2] assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + it "is not equal with different ivars" do statement1 = Arel::Nodes::UpdateStatement.new - statement1.relation = 'zomg' + statement1.relation = "zomg" statement1.wheres = 2 statement1.values = false statement1.orders = %w[x y z] statement1.limit = 42 - statement1.key = 'zomg' + statement1.key = "zomg" statement2 = Arel::Nodes::UpdateStatement.new - statement2.relation = 'zomg' + statement2.relation = "zomg" statement2.wheres = 2 statement2.values = false statement2.orders = %w[x y z] statement2.limit = 42 - statement2.key = 'wth' + statement2.key = "wth" array = [statement1, statement2] assert_equal 2, array.uniq.size end diff --git a/activerecord/test/cases/arel/nodes/window_test.rb b/activerecord/test/cases/arel/nodes/window_test.rb index 81ecd5ced8f6f..729b0556a4f7b 100644 --- a/activerecord/test/cases/arel/nodes/window_test.rb +++ b/activerecord/test/cases/arel/nodes/window_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Nodes - describe 'Window' do - describe 'equality' do - it 'is equal with equal ivars' do + describe "Window" do + describe "equality" do + it "is equal with equal ivars" do window1 = Window.new window1.orders = [1, 2] window1.partitions = [1] @@ -18,7 +19,7 @@ module Nodes assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + it "is not equal with different ivars" do window1 = Window.new window1.orders = [1, 2] window1.partitions = [1] @@ -33,14 +34,14 @@ module Nodes end end - describe 'NamedWindow' do - describe 'equality' do - it 'is equal with equal ivars' do - window1 = NamedWindow.new 'foo' + describe "NamedWindow" do + describe "equality" do + it "is equal with equal ivars" do + window1 = NamedWindow.new "foo" window1.orders = [1, 2] window1.partitions = [1] window1.frame 3 - window2 = NamedWindow.new 'foo' + window2 = NamedWindow.new "foo" window2.orders = [1, 2] window2.partitions = [1] window2.frame 3 @@ -48,12 +49,12 @@ module Nodes assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do - window1 = NamedWindow.new 'foo' + it "is not equal with different ivars" do + window1 = NamedWindow.new "foo" window1.orders = [1, 2] window1.partitions = [1] window1.frame 3 - window2 = NamedWindow.new 'bar' + window2 = NamedWindow.new "bar" window2.orders = [1, 2] window2.partitions = [1] window2.frame 3 @@ -63,14 +64,14 @@ module Nodes end end - describe 'CurrentRow' do - describe 'equality' do - it 'is equal to other current row nodes' do + 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 + it "is not equal with other nodes" do array = [CurrentRow.new, Node.new] assert_equal 2, array.uniq.size end diff --git a/activerecord/test/cases/arel/nodes_test.rb b/activerecord/test/cases/arel/nodes_test.rb index 1934ef4c3b955..9021de0d20b09 100644 --- a/activerecord/test/cases/arel/nodes_test.rb +++ b/activerecord/test/cases/arel/nodes_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel module Nodes @@ -24,12 +25,10 @@ def test_every_arel_nodes_have_hash_eql_eqeq_from_same_class eqeq_owner == hash_owner end - problem_msg = 'Some subclasses of Arel::Nodes::Node do not have a' \ - ' #== or #eql? or #hash defined from the same class as the others' + problem_msg = "Some subclasses of Arel::Nodes::Node do not have a" \ + " #== or #eql? or #hash defined from the same class as the others" assert_empty bad_node_descendants, problem_msg end - - end end end diff --git a/activerecord/test/cases/arel/select_manager_test.rb b/activerecord/test/cases/arel/select_manager_test.rb index e9056953d81d6..1bc9f6abf2cca 100644 --- a/activerecord/test/cases/arel/select_manager_test.rb +++ b/activerecord/test/cases/arel/select_manager_test.rb @@ -1,18 +1,18 @@ # frozen_string_literal: true -require_relative 'helper' -module Arel +require_relative "helper" +module Arel class SelectManagerTest < Arel::Spec def test_join_sources manager = Arel::SelectManager.new - manager.join_sources << Arel::Nodes::StringJoin.new(Nodes.build_quoted('foo')) + manager.join_sources << Arel::Nodes::StringJoin.new(Nodes.build_quoted("foo")) assert_equal "SELECT FROM 'foo'", manager.to_sql end - describe 'backwards compatibility' do - describe 'project' do - it 'accepts symbols as sql literals' do + describe "backwards compatibility" do + describe "project" do + it "accepts symbols as sql literals" do table = Table.new :users manager = Arel::SelectManager.new manager.project :id @@ -23,19 +23,19 @@ def test_join_sources end end - describe 'order' do - it 'accepts symbols' do + describe "order" do + it "accepts symbols" do table = Table.new :users manager = Arel::SelectManager.new - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" manager.from table manager.order :foo manager.to_sql.must_be_like %{ SELECT * FROM "users" ORDER BY foo } end end - describe 'group' do - it 'takes a symbol' do + describe "group" do + it "takes a symbol" do table = Table.new :users manager = Arel::SelectManager.new manager.from table @@ -44,55 +44,55 @@ def test_join_sources end end - describe 'as' do - it 'makes an AS node by grouping the AST' do + describe "as" do + it "makes an AS node by grouping the AST" do manager = Arel::SelectManager.new - as = manager.as(Arel.sql('foo')) + 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 + assert_equal "foo", as.right end - it 'converts right to SqlLiteral if a string' do + it "converts right to SqlLiteral if a string" do manager = Arel::SelectManager.new - as = manager.as('foo') + as = manager.as("foo") assert_kind_of Arel::Nodes::SqlLiteral, as.right end - it 'can make a subselect' do + it "can make a subselect" do manager = Arel::SelectManager.new manager.project Arel.star - manager.from Arel.sql('zomg') - as = manager.as(Arel.sql('foo')) + manager.from Arel.sql("zomg") + as = manager.as(Arel.sql("foo")) manager = Arel::SelectManager.new - manager.project Arel.sql('name') + 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 + describe "from" do + it "ignores strings when table of same name exists" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.from 'users' - manager.project table['id'] + 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 + it "should support any ast" do + table = Table.new :users manager1 = Arel::SelectManager.new manager2 = Arel::SelectManager.new - manager2.project(Arel.sql('*')) + manager2.project(Arel.sql("*")) manager2.from table - manager1.project Arel.sql('lol') - as = manager2.as Arel.sql('omg') + manager1.project Arel.sql("lol") + as = manager2.as Arel.sql("omg") manager1.from(as) manager1.to_sql.must_be_like %{ @@ -101,32 +101,32 @@ def test_join_sources end end - describe 'having' do - it 'converts strings to SQLLiterals' do - table = Table.new :users + describe "having" do + it "converts strings to SQLLiterals" do + table = Table.new :users mgr = table.from - mgr.having Arel.sql('foo') + mgr.having Arel.sql("foo") mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo } end - it 'can have multiple items specified separately' do + it "can have multiple items specified separately" do table = Table.new :users mgr = table.from - mgr.having Arel.sql('foo') - mgr.having Arel.sql('bar') + mgr.having Arel.sql("foo") + mgr.having Arel.sql("bar") mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } end - it 'can receive any node' do + it "can receive any node" do table = Table.new :users mgr = table.from - mgr.having Arel::Nodes::And.new([Arel.sql('foo'), Arel.sql('bar')]) + mgr.having Arel::Nodes::And.new([Arel.sql("foo"), Arel.sql("bar")]) mgr.to_sql.must_be_like %{ SELECT FROM "users" HAVING foo AND bar } end end - describe 'on' do - it 'converts to sqlliterals' do + describe "on" do + it "converts to sqlliterals" do table = Table.new :users right = table.alias mgr = table.from @@ -134,7 +134,7 @@ def test_join_sources mgr.to_sql.must_be_like %{ SELECT FROM "users" INNER JOIN "users" "users_2" ON omg } end - it 'converts to sqlliterals with multiple items' do + it "converts to sqlliterals with multiple items" do table = Table.new :users right = table.alias mgr = table.from @@ -144,17 +144,17 @@ def test_join_sources end end - describe 'clone' do - it 'creates new cores' do - table = Table.new :users, :as => 'foo' + describe "clone" do + it "creates new cores" do + table = Table.new :users, as: "foo" mgr = table.from m2 = mgr.clone m2.project "foo" mgr.to_sql.wont_equal m2.to_sql end - it 'makes updates to the correct copy' do - table = Table.new :users, :as => 'foo' + it "makes updates to the correct copy" do + table = Table.new :users, as: "foo" mgr = table.from m2 = mgr.clone m3 = m2.clone @@ -164,40 +164,40 @@ def test_join_sources end end - describe 'initialize' do - it 'uses alias in sql' do - table = Table.new :users, :as => 'foo' + describe "initialize" do + it "uses alias in sql" do + table = Table.new :users, as: "foo" mgr = table.from 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 + describe "skip" do + it "should add an offset" do + table = Table.new :users mgr = table.from mgr.skip 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } end - it 'should chain' do - table = Table.new :users + it "should chain" do + table = Table.new :users mgr = table.from 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 + describe "offset" do + it "should add an offset" do + table = Table.new :users mgr = table.from mgr.offset = 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } end - it 'should remove an offset' do - table = Table.new :users + it "should remove an offset" do + table = Table.new :users mgr = table.from mgr.offset = 10 mgr.to_sql.must_be_like %{ SELECT FROM "users" OFFSET 10 } @@ -206,35 +206,35 @@ def test_join_sources mgr.to_sql.must_be_like %{ SELECT FROM "users" } end - it 'should return the offset' do - table = Table.new :users + it "should return the offset" do + table = Table.new :users mgr = table.from mgr.offset = 10 assert_equal 10, mgr.offset end end - describe 'exists' do - it 'should create an exists clause' do + describe "exists" do + it "should create an exists clause" do table = Table.new(:users) manager = Arel::SelectManager.new table - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" m2 = Arel::SelectManager.new m2.project manager.exists m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) } end - it 'can be aliased' do + it "can be aliased" do table = Table.new(:users) manager = Arel::SelectManager.new table - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" m2 = Arel::SelectManager.new - m2.project manager.exists.as('foo') + m2.project manager.exists.as("foo") m2.to_sql.must_be_like %{ SELECT EXISTS (#{manager.to_sql}) AS foo } end end - describe 'union' do + describe "union" do before do table = Table.new :users @m1 = Arel::SelectManager.new table @@ -248,7 +248,7 @@ def test_join_sources end - it 'should union two managers' do + 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 @@ -259,7 +259,7 @@ def test_join_sources } end - it 'should union all' do + it "should union all" do node = @m1.union :all, @m2 node.to_sql.must_be_like %{ @@ -269,7 +269,7 @@ def test_join_sources end - describe 'intersect' do + describe "intersect" do before do table = Table.new :users @m1 = Arel::SelectManager.new table @@ -283,7 +283,7 @@ def test_join_sources end - it 'should interect two managers' do + 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 @@ -296,7 +296,7 @@ def test_join_sources end - describe 'except' do + describe "except" do before do table = Table.new :users @m1 = Arel::SelectManager.new table @@ -308,7 +308,7 @@ def test_join_sources @m2.where(table[:age].between(40..99)) end - it 'should except two managers' do + 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 @@ -321,8 +321,8 @@ def test_join_sources end - describe 'with' do - it 'should support basic WITH' do + describe "with" do + it "should support basic WITH" do users = Table.new(:users) users_top = Table.new(:users_top) comments = Table.new(:comments) @@ -370,43 +370,43 @@ def test_join_sources end end - describe 'ast' do - it 'should return the ast' do - table = Table.new :users + describe "ast" do + it "should return the ast" do + table = Table.new :users mgr = table.from assert mgr.ast end - it 'should allow orders to work when the ast is grepped' do - table = Table.new :users + it "should allow orders to work when the ast is grepped" do + table = Table.new :users mgr = table.from - mgr.project Arel.sql '*' + mgr.project Arel.sql "*" mgr.from table - mgr.orders << Arel::Nodes::Ascending.new(Arel.sql('foo')) + 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 + describe "taken" do + it "should return limit" do manager = Arel::SelectManager.new manager.take 10 manager.taken.must_equal 10 end end - describe 'lock' do + describe "lock" do # This should fail on other databases - it 'adds a lock node' do - table = Table.new :users + it "adds a lock node" do + table = Table.new :users mgr = table.from mgr.lock.to_sql.must_be_like %{ SELECT FROM "users" FOR UPDATE } end end - describe 'orders' do - it 'returns order clauses' do + describe "orders" do + it "returns order clauses" do table = Table.new :users manager = Arel::SelectManager.new order = table[:id] @@ -415,11 +415,11 @@ def test_join_sources end end - describe 'order' do - it 'generates order clauses' do + describe "order" do + it "generates order clauses" do table = Table.new :users manager = Arel::SelectManager.new - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" manager.from table manager.order table[:id] manager.to_sql.must_be_like %{ @@ -428,10 +428,10 @@ def test_join_sources end # FIXME: I would like to deprecate this - it 'takes *args' do + it "takes *args" do table = Table.new :users manager = Arel::SelectManager.new - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" manager.from table manager.order table[:id], table[:name] manager.to_sql.must_be_like %{ @@ -439,16 +439,16 @@ def test_join_sources } end - it 'chains' do + it "chains" do table = Table.new :users manager = Arel::SelectManager.new manager.order(table[:id]).must_equal manager end - it 'has order attributes' do + it "has order attributes" do table = Table.new :users manager = Arel::SelectManager.new - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" manager.from table manager.order table[:id].desc manager.to_sql.must_be_like %{ @@ -457,8 +457,8 @@ def test_join_sources end end - describe 'on' do - it 'takes two params' do + describe "on" do + it "takes two params" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -474,7 +474,7 @@ def test_join_sources } end - it 'takes three params' do + it "takes three params" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -496,59 +496,59 @@ def test_join_sources end end - it 'should hand back froms' do + it "should hand back froms" do relation = Arel::SelectManager.new assert_equal [], relation.froms end - it 'should create and nodes' do + it "should create and nodes" do relation = Arel::SelectManager.new - children = ['foo', 'bar', 'baz'] + 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 + it "should create insert managers" do relation = Arel::SelectManager.new insert = relation.create_insert assert_kind_of Arel::InsertManager, insert end - it 'should create join nodes' do + it "should create join nodes" do relation = Arel::SelectManager.new - join = relation.create_join 'foo', 'bar' + join = relation.create_join "foo", "bar" assert_kind_of Arel::Nodes::InnerJoin, join - assert_equal 'foo', join.left - assert_equal 'bar', join.right + assert_equal "foo", join.left + assert_equal "bar", join.right end - it 'should create join nodes with a full outer join klass' do + it "should create join nodes with a full outer join klass" do relation = Arel::SelectManager.new - join = relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + join = relation.create_join "foo", "bar", Arel::Nodes::FullOuterJoin assert_kind_of Arel::Nodes::FullOuterJoin, join - assert_equal 'foo', join.left - assert_equal 'bar', join.right + assert_equal "foo", join.left + assert_equal "bar", join.right end - it 'should create join nodes with a outer join klass' do + it "should create join nodes with a outer join klass" do relation = Arel::SelectManager.new - join = relation.create_join 'foo', 'bar', Arel::Nodes::OuterJoin + 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 + assert_equal "foo", join.left + assert_equal "bar", join.right end - it 'should create join nodes with a right outer join klass' do + it "should create join nodes with a right outer join klass" do relation = Arel::SelectManager.new - join = relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + join = relation.create_join "foo", "bar", Arel::Nodes::RightOuterJoin assert_kind_of Arel::Nodes::RightOuterJoin, join - assert_equal 'foo', join.left - assert_equal 'bar', join.right + assert_equal "foo", join.left + assert_equal "bar", join.right end - describe 'join' do - it 'responds to join' do + describe "join" do + it "responds to join" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -563,7 +563,7 @@ def test_join_sources } end - it 'takes a class' do + it "takes a class" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -578,7 +578,7 @@ def test_join_sources } end - it 'takes the full outer join class' do + it "takes the full outer join class" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -593,7 +593,7 @@ def test_join_sources } end - it 'takes the right outer join class' do + it "takes the right outer join class" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -608,12 +608,12 @@ def test_join_sources } end - it 'noops on nil' do - manager = Arel::SelectManager.new + it "noops on nil" do + manager = Arel::SelectManager.new manager.join(nil).must_equal manager end - it 'raises EmptyJoinError on empty' do + it "raises EmptyJoinError on empty" do left = Table.new :users manager = Arel::SelectManager.new @@ -624,8 +624,8 @@ def test_join_sources end end - describe 'outer join' do - it 'responds to join' do + describe "outer join" do + it "responds to join" do left = Table.new :users right = left.alias predicate = left[:id].eq(right[:id]) @@ -640,15 +640,15 @@ def test_join_sources } end - it 'noops on nil' do - manager = Arel::SelectManager.new + it "noops on nil" do + manager = Arel::SelectManager.new manager.outer_join(nil).must_equal manager end end - describe 'joins' do + describe "joins" do - it 'returns inner join sql' do + it "returns inner join sql" do table = Table.new :users aliaz = table.alias manager = Arel::SelectManager.new @@ -657,7 +657,7 @@ def test_join_sources manager.to_sql end - it 'returns outer join sql' do + it "returns outer join sql" do table = Table.new :users aliaz = table.alias manager = Arel::SelectManager.new @@ -666,7 +666,7 @@ def test_join_sources manager.to_sql end - it 'can have a non-table alias as relation name' do + it "can have a non-table alias as relation name" do users = Table.new :users comments = Table.new :comments @@ -678,7 +678,7 @@ def test_join_sources ).as("counts") joins = users.join(counts).on(counts[:user_id].eq(10)) - joins.to_sql.must_be_like %{ + 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 @@ -689,7 +689,7 @@ def test_join_sources predicate = left[:id].eq(right[:id]) mgr = left.join(right) - mgr.project Nodes::SqlLiteral.new('*') + mgr.project Nodes::SqlLiteral.new("*") mgr.on(predicate).must_equal mgr mgr.to_sql.must_be_like %{ @@ -699,15 +699,15 @@ def test_join_sources } end - it 'returns string join sql' do + it "returns string join sql" do manager = Arel::SelectManager.new - manager.from Nodes::StringJoin.new(Nodes.build_quoted('hello')) + manager.from Nodes::StringJoin.new(Nodes.build_quoted("hello")) assert_match "'hello'", manager.to_sql end end - describe 'group' do - it 'takes an attribute' do + describe "group" do + it "takes an attribute" do table = Table.new :users manager = Arel::SelectManager.new manager.from table @@ -717,13 +717,13 @@ def test_join_sources } end - it 'chains' do + it "chains" do table = Table.new :users manager = Arel::SelectManager.new manager.group(table[:id]).must_equal manager end - it 'takes multiple args' do + it "takes multiple args" do table = Table.new :users manager = Arel::SelectManager.new manager.from table @@ -734,132 +734,132 @@ def test_join_sources end # FIXME: backwards compat - it 'makes strings literals' do + it "makes strings literals" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.group 'foo' + 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 + describe "window definition" do + it "can be empty" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window') + manager.window("a_window") manager.to_sql.must_be_like %{ SELECT FROM "users" WINDOW "a_window" AS () } end - it 'takes an order' do + it "takes an order" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').order(table['foo'].asc) + manager.window("a_window").order(table["foo"].asc) manager.to_sql.must_be_like %{ SELECT FROM "users" WINDOW "a_window" AS (ORDER BY "users"."foo" ASC) } end - it 'takes an order with multiple columns' do + it "takes an order with multiple columns" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').order(table['foo'].asc, table['bar'].desc) + manager.window("a_window").order(table["foo"].asc, table["bar"].desc) manager.to_sql.must_be_like %{ SELECT FROM "users" WINDOW "a_window" AS (ORDER BY "users"."foo" ASC, "users"."bar" DESC) } end - it 'takes a partition' do + it "takes a partition" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').partition(table['bar']) + manager.window("a_window").partition(table["bar"]) manager.to_sql.must_be_like %{ SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."bar") } end - it 'takes a partition and an order' do + it "takes a partition and an order" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').partition(table['foo']).order(table['foo'].asc) + manager.window("a_window").partition(table["foo"]).order(table["foo"].asc) manager.to_sql.must_be_like %{ SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."foo" ORDER BY "users"."foo" ASC) } end - it 'takes a partition with multiple columns' do + it "takes a partition with multiple columns" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').partition(table['bar'], table['baz']) + manager.window("a_window").partition(table["bar"], table["baz"]) manager.to_sql.must_be_like %{ SELECT FROM "users" WINDOW "a_window" AS (PARTITION BY "users"."bar", "users"."baz") } end - it 'takes a rows frame, unbounded preceding' do + it "takes a rows frame, unbounded preceding" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').rows(Arel::Nodes::Preceding.new) + 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 + it "takes a rows frame, bounded preceding" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').rows(Arel::Nodes::Preceding.new(5)) + 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 + it "takes a rows frame, unbounded following" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').rows(Arel::Nodes::Following.new) + 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 + it "takes a rows frame, bounded following" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').rows(Arel::Nodes::Following.new(5)) + 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 + it "takes a rows frame, current row" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').rows(Arel::Nodes::CurrentRow.new) + 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 + it "takes a rows frame, between two delimiters" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - window = manager.window('a_window') + window = manager.window("a_window") window.frame( Arel::Nodes::Between.new( window.rows, @@ -872,61 +872,61 @@ def test_join_sources } end - it 'takes a range frame, unbounded preceding' do + it "takes a range frame, unbounded preceding" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').range(Arel::Nodes::Preceding.new) + 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 + it "takes a range frame, bounded preceding" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').range(Arel::Nodes::Preceding.new(5)) + 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 + it "takes a range frame, unbounded following" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').range(Arel::Nodes::Following.new) + 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 + it "takes a range frame, bounded following" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').range(Arel::Nodes::Following.new(5)) + 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 + it "takes a range frame, current row" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.window('a_window').range(Arel::Nodes::CurrentRow.new) + 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 + it "takes a range frame, between two delimiters" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - window = manager.window('a_window') + window = manager.window("a_window") window.frame( Arel::Nodes::Between.new( window.range, @@ -940,7 +940,7 @@ def test_join_sources end end - describe 'delete' do + describe "delete" do it "copies from" do table = Table.new :users manager = Arel::SelectManager.new @@ -963,8 +963,8 @@ def test_join_sources end end - describe 'where_sql' do - it 'gives me back the where sql' do + describe "where_sql" do + it "gives me back the where sql" do table = Table.new :users manager = Arel::SelectManager.new manager.from table @@ -972,7 +972,7 @@ def test_join_sources manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 } end - it 'joins wheres with AND' do + it "joins wheres with AND" do table = Table.new :users manager = Arel::SelectManager.new manager.from table @@ -981,19 +981,19 @@ def test_join_sources manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 AND "users"."id" = 11} end - it 'handles database specific statements' do + it "handles database specific statements" do old_visitor = Table.engine.connection.visitor Table.engine.connection.visitor = Visitors::PostgreSQL.new Table.engine.connection table = Table.new :users manager = Arel::SelectManager.new manager.from table manager.where table[:id].eq 10 - manager.where table[:name].matches 'foo%' + manager.where table[:name].matches "foo%" manager.where_sql.must_be_like %{ WHERE "users"."id" = 10 AND "users"."name" ILIKE 'foo%' } Table.engine.connection.visitor = old_visitor end - it 'returns nil when there are no wheres' do + it "returns nil when there are no wheres" do table = Table.new :users manager = Arel::SelectManager.new manager.from table @@ -1001,35 +1001,35 @@ def test_join_sources end end - describe 'update' do + describe "update" do - it 'creates an update statement' do + it "creates an update statement" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update({ table[:id] => 1 }, Arel::Attributes::Attribute.new(table, "id")) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 } end - it 'takes a string' do + it "takes a string" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update(Nodes::SqlLiteral.new("foo = bar"), Arel::Attributes::Attribute.new(table, "id")) stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end - it 'copies limits' do + it "copies limits" do table = Table.new :users manager = Arel::SelectManager.new manager.from table manager.take 1 - stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) - stmt.key = table['id'] + stmt = manager.compile_update(Nodes::SqlLiteral.new("foo = bar"), Arel::Attributes::Attribute.new(table, "id")) + stmt.key = table["id"] stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar @@ -1037,13 +1037,13 @@ def test_join_sources } end - it 'copies order' do + it "copies order" do table = Table.new :users manager = Arel::SelectManager.new manager.from table manager.order :foo - stmt = manager.compile_update(Nodes::SqlLiteral.new('foo = bar'), Arel::Attributes::Attribute.new(table, 'id')) - stmt.key = table['id'] + stmt = manager.compile_update(Nodes::SqlLiteral.new("foo = bar"), Arel::Attributes::Attribute.new(table, "id")) + stmt.key = table["id"] stmt.to_sql.must_be_like %{ UPDATE "users" SET foo = bar @@ -1051,25 +1051,25 @@ def test_join_sources } end - it 'copies where clauses' do + it "copies where clauses" do table = Table.new :users manager = Arel::SelectManager.new manager.where table[:id].eq 10 manager.from table - stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update({ table[:id] => 1 }, Arel::Attributes::Attribute.new(table, "id")) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" = 10 } end - it 'copies where clauses when nesting is triggered' do + it "copies where clauses when nesting is triggered" do table = Table.new :users manager = Arel::SelectManager.new manager.where table[:foo].eq 10 manager.take 42 manager.from table - stmt = manager.compile_update({table[:id] => 1}, Arel::Attributes::Attribute.new(table, 'id')) + stmt = manager.compile_update({ table[:id] => 1 }, Arel::Attributes::Attribute.new(table, "id")) stmt.to_sql.must_be_like %{ UPDATE "users" SET "id" = 1 WHERE "users"."id" IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42) @@ -1078,51 +1078,51 @@ def test_join_sources end - describe 'project' do + describe "project" do it "takes sql literals" do manager = Arel::SelectManager.new - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" manager.to_sql.must_be_like %{ SELECT * } end - it 'takes multiple args' do + it "takes multiple args" do manager = Arel::SelectManager.new - manager.project Nodes::SqlLiteral.new('foo'), - Nodes::SqlLiteral.new('bar') + manager.project Nodes::SqlLiteral.new("foo"), + Nodes::SqlLiteral.new("bar") manager.to_sql.must_be_like %{ SELECT foo, bar } end - it 'takes strings' do + it "takes strings" do manager = Arel::SelectManager.new - manager.project '*' + manager.project "*" manager.to_sql.must_be_like %{ SELECT * } end end - describe 'projections' do - it 'reads projections' do + describe "projections" do + it "reads projections" do manager = Arel::SelectManager.new - manager.project Arel.sql('foo'), Arel.sql('bar') - manager.projections.must_equal [Arel.sql('foo'), Arel.sql('bar')] + 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 + describe "projections=" do + it "overwrites projections" do manager = Arel::SelectManager.new - manager.project Arel.sql('foo') - manager.projections = [Arel.sql('bar')] + manager.project Arel.sql("foo") + manager.projections = [Arel.sql("bar")] manager.to_sql.must_be_like %{ SELECT bar } end end - describe 'take' do + describe "take" do it "knows take" do table = Table.new :users manager = Arel::SelectManager.new - manager.from(table).project(table['id']) - manager.where(table['id'].eq(1)) + manager.from(table).project(table["id"]) + manager.where(table["id"].eq(1)) manager.take 1 manager.to_sql.must_be_like %{ @@ -1138,22 +1138,22 @@ def test_join_sources manager.take(1).must_equal manager end - it 'removes LIMIT when nil is passed' do + it "removes LIMIT when nil is passed" do manager = Arel::SelectManager.new manager.limit = 10 - assert_match('LIMIT', manager.to_sql) + assert_match("LIMIT", manager.to_sql) manager.limit = nil - refute_match('LIMIT', manager.to_sql) + refute_match("LIMIT", manager.to_sql) end end - describe 'where' do + describe "where" do it "knows where" do table = Table.new :users manager = Arel::SelectManager.new - manager.from(table).project(table['id']) - manager.where(table['id'].eq(1)) + manager.from(table).project(table["id"]) + manager.where(table["id"].eq(1)) manager.to_sql.must_be_like %{ SELECT "users"."id" FROM "users" @@ -1165,37 +1165,37 @@ def test_join_sources table = Table.new :users manager = Arel::SelectManager.new manager.from(table) - manager.project(table['id']).where(table['id'].eq 1).must_equal manager + manager.project(table["id"]).where(table["id"].eq 1).must_equal manager end end - describe 'from' do + describe "from" do it "makes sql" do table = Table.new :users manager = Arel::SelectManager.new manager.from table - manager.project table['id'] + 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 - manager.from(table).project(table['id']).must_equal manager + 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 + describe "source" do + it "returns the join source of the select core" do manager = Arel::SelectManager.new manager.source.must_equal manager.ast.cores.last.source end end - describe 'distinct' do - it 'sets the quantifier' do + describe "distinct" do + it "sets the quantifier" do manager = Arel::SelectManager.new manager.distinct @@ -1212,13 +1212,13 @@ def test_join_sources end end - describe 'distinct_on' do - it 'sets the quantifier' do + describe "distinct_on" do + it "sets the quantifier" do manager = Arel::SelectManager.new table = Table.new :users - manager.distinct_on(table['id']) - manager.ast.cores.last.set_quantifier.must_equal Arel::Nodes::DistinctOn.new(table['id']) + manager.distinct_on(table["id"]) + manager.ast.cores.last.set_quantifier.must_equal Arel::Nodes::DistinctOn.new(table["id"]) manager.distinct_on(false) manager.ast.cores.last.set_quantifier.must_be_nil @@ -1228,7 +1228,7 @@ def test_join_sources manager = Arel::SelectManager.new table = Table.new :users - manager.distinct_on(table['id']).must_equal manager + manager.distinct_on(table["id"]).must_equal manager manager.distinct_on(false).must_equal manager end end diff --git a/activerecord/test/cases/arel/support/fake_record.rb b/activerecord/test/cases/arel/support/fake_record.rb index 75ac1e072fbd7..8620d6fd34267 100644 --- a/activerecord/test/cases/arel/support/fake_record.rb +++ b/activerecord/test/cases/arel/support/fake_record.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'date' +require "date" module FakeRecord class Column < Struct.new(:name, :type) end @@ -12,49 +12,49 @@ class Connection 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) + "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) + "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] }] + "users" => Hash[@columns["users"].map { |x| [x.name, x] }], + "products" => Hash[@columns["products"].map { |x| [x.name, x] }] } @primary_keys = { - 'users' => 'id', - 'products' => 'id' + "users" => "id", + "products" => "id" } @visitor = visitor end - def columns_hash table_name + def columns_hash(table_name) @columns_hash[table_name] end - def primary_key name + def primary_key(name) @primary_keys[name.to_s] end - def data_source_exists? name + def data_source_exists?(name) @tables.include? name.to_s end - def columns name, message = nil + def columns(name, message = nil) @columns[name.to_s] end - def quote_table_name name + def quote_table_name(name) "\"#{name.to_s}\"" end - def quote_column_name name + def quote_column_name(name) "\"#{name.to_s}\"" end @@ -62,7 +62,7 @@ def schema_cache self end - def quote thing + def quote(thing) case thing when DateTime "'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'" @@ -73,7 +73,7 @@ def quote thing when false "'f'" when nil - 'NULL' + "NULL" when Numeric thing else @@ -89,7 +89,7 @@ class Spec < Struct.new(:config) attr_reader :spec, :connection def initialize - @spec = Spec.new(:adapter => 'america') + @spec = Spec.new(adapter: "america") @connection = Connection.new @connection.visitor = Arel::Visitors::ToSql.new(connection) end @@ -98,7 +98,7 @@ def with_connection yield connection end - def table_exists? name + def table_exists?(name) connection.tables.include? name.to_s end @@ -110,7 +110,7 @@ def schema_cache connection end - def quote thing + def quote(thing) connection.quote thing end end diff --git a/activerecord/test/cases/arel/table_test.rb b/activerecord/test/cases/arel/table_test.rb index ccb3ab302f0d7..91b7a5a4808eb 100644 --- a/activerecord/test/cases/arel/table_test.rb +++ b/activerecord/test/cases/arel/table_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel class TableTest < Arel::Spec @@ -7,56 +8,56 @@ class TableTest < Arel::Spec @relation = Table.new(:users) end - it 'should create join nodes' do - join = @relation.create_string_join 'foo' + it "should create join nodes" do + join = @relation.create_string_join "foo" assert_kind_of Arel::Nodes::StringJoin, join - assert_equal 'foo', join.left + assert_equal "foo", join.left end - it 'should create join nodes' do - join = @relation.create_join 'foo', 'bar' + 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 + assert_equal "foo", join.left + assert_equal "bar", join.right end - it 'should create join nodes with a klass' do - join = @relation.create_join 'foo', 'bar', Arel::Nodes::FullOuterJoin + it "should create join nodes with a klass" do + join = @relation.create_join "foo", "bar", Arel::Nodes::FullOuterJoin assert_kind_of Arel::Nodes::FullOuterJoin, join - assert_equal 'foo', join.left - assert_equal 'bar', join.right + 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 + 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 + assert_equal "foo", join.left + assert_equal "bar", join.right end - it 'should create join nodes with a klass' do - join = @relation.create_join 'foo', 'bar', Arel::Nodes::RightOuterJoin + it "should create join nodes with a klass" do + join = @relation.create_join "foo", "bar", Arel::Nodes::RightOuterJoin assert_kind_of Arel::Nodes::RightOuterJoin, join - assert_equal 'foo', join.left - assert_equal 'bar', join.right + assert_equal "foo", join.left + assert_equal "bar", join.right end - it 'should return an insert manager' do - im = @relation.compile_insert 'VALUES(NULL)' + it "should return an insert manager" do + im = @relation.compile_insert "VALUES(NULL)" assert_kind_of Arel::InsertManager, im im.into Table.new(:users) assert_equal "INSERT INTO \"users\" VALUES(NULL)", im.to_sql end - describe 'skip' do - it 'should add an offset' do + 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 'having' do - it 'adds a having clause' do + 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 @@ -64,21 +65,21 @@ class TableTest < Arel::Spec end end - describe 'backwards compat' do - describe 'join' do - it 'noops on nil' do + 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 'raises EmptyJoinError on empty' do + it "raises EmptyJoinError on empty" do assert_raises(EmptyJoinError) do @relation.join "" end end - it 'takes a second argument for join type' do + 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) @@ -91,8 +92,8 @@ class TableTest < Arel::Spec end end - describe 'join' do - it 'creates an outer join' do + describe "join" do + it "creates an outer join" do right = @relation.alias predicate = @relation[:id].eq(right[:id]) mgr = @relation.outer_join(right).on(predicate) @@ -106,8 +107,8 @@ class TableTest < Arel::Spec end end - describe 'group' do - it 'should create a group' do + 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" @@ -115,54 +116,54 @@ class TableTest < Arel::Spec end end - describe 'alias' do - it 'should create a node that proxies to a table' do + describe "alias" do + it "should create a node that proxies to a table" do node = @relation.alias - node.name.must_equal 'users_2' + node.name.must_equal "users_2" node[:id].relation.must_equal node end end - describe 'new' do - it 'should accept a hash' do - rel = Table.new :users, :as => 'foo' - rel.table_alias.must_equal 'foo' + describe "new" do + it "should accept a hash" do + rel = Table.new :users, as: "foo" + rel.table_alias.must_equal "foo" end - it 'ignores as if it equals name' do - rel = Table.new :users, :as => 'users' + 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 + 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 + describe "take" do it "should add a limit" do manager = @relation.take 1 - manager.project Nodes::SqlLiteral.new '*' + manager.project Nodes::SqlLiteral.new "*" manager.to_sql.must_be_like %{ SELECT * FROM "users" LIMIT 1 } end end - describe 'project' do - it 'can project' do - manager = @relation.project Nodes::SqlLiteral.new '*' + describe "project" do + it "can project" do + manager = @relation.project Nodes::SqlLiteral.new "*" manager.to_sql.must_be_like %{ SELECT * FROM "users" } end - it 'takes multiple parameters' do - manager = @relation.project Nodes::SqlLiteral.new('*'), Nodes::SqlLiteral.new('*') + it "takes multiple parameters" do + manager = @relation.project Nodes::SqlLiteral.new("*"), Nodes::SqlLiteral.new("*") manager.to_sql.must_be_like %{ SELECT *, * FROM "users" } end end - describe 'where' do + describe "where" do it "returns a tree manager" do manager = @relation.where @relation[:id].eq 1 manager.project @relation[:id] @@ -176,15 +177,15 @@ class TableTest < Arel::Spec end it "should have a name" do - @relation.name.must_equal 'users' + @relation.name.must_equal "users" end it "should have a table name" do - @relation.table_name.must_equal 'users' + @relation.table_name.must_equal "users" end - describe '[]' do - describe 'when given a Symbol' do + 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 @@ -192,21 +193,21 @@ class TableTest < Arel::Spec end end - describe 'equality' do - it 'is equal with equal ivars' do + describe "equality" do + it "is equal with equal ivars" do relation1 = Table.new(:users) - relation1.table_alias = 'zomg' + relation1.table_alias = "zomg" relation2 = Table.new(:users) - relation2.table_alias = 'zomg' + relation2.table_alias = "zomg" array = [relation1, relation2] assert_equal 1, array.uniq.size end - it 'is not equal with different ivars' do + it "is not equal with different ivars" do relation1 = Table.new(:users) - relation1.table_alias = 'zomg' + relation1.table_alias = "zomg" relation2 = Table.new(:users) - relation2.table_alias = 'zomg2' + relation2.table_alias = "zomg2" array = [relation1, relation2] assert_equal 2, array.uniq.size end diff --git a/activerecord/test/cases/arel/update_manager_test.rb b/activerecord/test/cases/arel/update_manager_test.rb index 91118c5e9f4d6..cc1b9ac5b35f0 100644 --- a/activerecord/test/cases/arel/update_manager_test.rb +++ b/activerecord/test/cases/arel/update_manager_test.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true -require_relative 'helper' + +require_relative "helper" module Arel class UpdateManagerTest < Arel::Spec - describe 'new' do - it 'takes an engine' do + describe "new" do + it "takes an engine" do Arel::UpdateManager.new end end @@ -17,17 +18,17 @@ class UpdateManagerTest < Arel::Spec um.to_sql.must_be_like %{ UPDATE "users" SET "name" = ? } end - it 'handles limit properly' do + it "handles limit properly" do table = Table.new(:users) um = Arel::UpdateManager.new - um.key = 'id' + um.key = "id" um.take 10 um.table table um.set [[table[:name], nil]] assert_match(/LIMIT 10/, um.to_sql) end - describe 'set' do + describe "set" do it "updates with null" do table = Table.new(:users) um = Arel::UpdateManager.new @@ -36,7 +37,7 @@ class UpdateManagerTest < Arel::Spec um.to_sql.must_be_like %{ UPDATE "users" SET "name" = NULL } end - it 'takes a string' do + it "takes a string" do table = Table.new(:users) um = Arel::UpdateManager.new um.table table @@ -44,36 +45,36 @@ class UpdateManagerTest < Arel::Spec um.to_sql.must_be_like %{ UPDATE "users" SET foo = bar } end - it 'takes a list of lists' do + it "takes a list of lists" do table = Table.new(:users) um = Arel::UpdateManager.new um.table table - um.set [[table[:id], 1], [table[:name], 'hello']] + 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 + it "chains" do table = Table.new(:users) um = Arel::UpdateManager.new - um.set([[table[:id], 1], [table[:name], 'hello']]).must_equal um + um.set([[table[:id], 1], [table[:name], "hello"]]).must_equal um end end - describe 'table' do - it 'generates an update statement' do + describe "table" do + it "generates an update statement" do um = Arel::UpdateManager.new um.table Table.new(:users) um.to_sql.must_be_like %{ UPDATE "users" } end - it 'chains' do + it "chains" do um = Arel::UpdateManager.new um.table(Table.new(:users)).must_equal um end - it 'generates an update statement with joins' do + it "generates an update statement with joins" do um = Arel::UpdateManager.new table = Table.new(:users) @@ -87,8 +88,8 @@ class UpdateManagerTest < Arel::Spec end end - describe 'where' do - it 'generates a where clause' do + describe "where" do + it "generates a where clause" do table = Table.new :users um = Arel::UpdateManager.new um.table table @@ -98,7 +99,7 @@ class UpdateManagerTest < Arel::Spec } end - it 'chains' do + it "chains" do table = Table.new :users um = Arel::UpdateManager.new um.table table @@ -106,18 +107,18 @@ class UpdateManagerTest < Arel::Spec end end - describe 'key' do + describe "key" do before do @table = Table.new :users @um = Arel::UpdateManager.new @um.key = @table[:foo] end - it 'can be set' do + it "can be set" do @um.ast.key.must_equal @table[:foo] end - it 'can be accessed' do + it "can be accessed" do @um.key.must_equal @table[:foo] end end diff --git a/activerecord/test/cases/arel/visitors/depth_first_test.rb b/activerecord/test/cases/arel/visitors/depth_first_test.rb index b841d119d20b0..3baccc73161fd 100644 --- a/activerecord/test/cases/arel/visitors/depth_first_test.rb +++ b/activerecord/test/cases/arel/visitors/depth_first_test.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors class TestDepthFirst < Arel::Test Collector = Struct.new(:calls) do - def call object + def call(object) calls << object end end @@ -164,7 +165,7 @@ def test_Arel_Nodes_InfixOperation def test_table relation = Arel::Table.new(:users) @visitor.accept relation - assert_equal ['users', relation], @collector.calls + assert_equal ["users", relation], @collector.calls end def test_array diff --git a/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb b/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb index eb278cde4c1fc..a07a1a050a54f 100644 --- a/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb +++ b/activerecord/test/cases/arel/visitors/dispatch_contamination_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -require_relative '../helper' -require 'concurrent' + +require_relative "../helper" +require "concurrent" module Arel module Visitors @@ -10,14 +11,14 @@ def initialize @barrier = Concurrent::CyclicBarrier.new(2) end - def visit_Arel_Visitors_DummySuperNode node + def visit_Arel_Visitors_DummySuperNode(node) 42 end # This is terrible, but it's the only way to reliably reproduce # the possible race where two threads attempt to correct the # dispatch hash at the same time. - def send *args + def send(*args) super rescue # Both threads try (and fail) to dispatch to the subclass's name @@ -43,7 +44,7 @@ class DispatchContaminationTest < Arel::Spec @table = Table.new(:users) end - it 'dispatches properly after failing upwards' do + it "dispatches properly after failing upwards" do node = Nodes::Union.new(Nodes::True.new, Nodes::False.new) assert_equal "( TRUE UNION FALSE )", node.to_sql @@ -52,7 +53,7 @@ class DispatchContaminationTest < Arel::Spec assert_equal "( TRUE UNION FALSE )", node.to_sql end - it 'is threadsafe when implementing superclass fallback' do + it "is threadsafe when implementing superclass fallback" do visitor = DummyVisitor.new main_thread_finished = Concurrent::Event.new @@ -69,4 +70,3 @@ class DispatchContaminationTest < Arel::Spec end end end - diff --git a/activerecord/test/cases/arel/visitors/dot_test.rb b/activerecord/test/cases/arel/visitors/dot_test.rb index 048482c3ca82a..98f3bab6209e5 100644 --- a/activerecord/test/cases/arel/visitors/dot_test.rb +++ b/activerecord/test/cases/arel/visitors/dot_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -23,7 +24,7 @@ def setup end def test_named_function - func = Nodes::NamedFunction.new 'omg', 'omg' + func = Nodes::NamedFunction.new "omg", "omg" @visitor.accept func, Collectors::PlainString.new end diff --git a/activerecord/test/cases/arel/visitors/ibm_db_test.rb b/activerecord/test/cases/arel/visitors/ibm_db_test.rb index d7569eedc3d69..7163cb34d375c 100644 --- a/activerecord/test/cases/arel/visitors/ibm_db_test.rb +++ b/activerecord/test/cases/arel/visitors/ibm_db_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -8,18 +9,18 @@ class IbmDbTest < Arel::Spec @visitor = IBM_DB.new Table.engine.connection end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'uses FETCH FIRST n ROWS to limit results' do + it "uses FETCH FIRST n ROWS to limit results" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) sql = compile(stmt) sql.must_be_like "SELECT FETCH FIRST 1 ROWS ONLY" end - it 'uses FETCH FIRST n ROWS in updates with a limit' do + it "uses FETCH FIRST n ROWS in updates with a limit" do table = Table.new(:users) stmt = Nodes::UpdateStatement.new stmt.relation = table @@ -28,7 +29,6 @@ def compile node sql = compile(stmt) sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT \"users\".\"id\" FROM \"users\" FETCH FIRST 1 ROWS ONLY)" end - end end end diff --git a/activerecord/test/cases/arel/visitors/informix_test.rb b/activerecord/test/cases/arel/visitors/informix_test.rb index bb6ff42f05812..b0b031cca3bd9 100644 --- a/activerecord/test/cases/arel/visitors/informix_test.rb +++ b/activerecord/test/cases/arel/visitors/informix_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -8,18 +9,18 @@ class InformixTest < Arel::Spec @visitor = Informix.new Table.engine.connection end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'uses FIRST n to limit results' do + it "uses FIRST n to limit results" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) sql = compile(stmt) sql.must_be_like "SELECT FIRST 1" end - it 'uses FIRST n in updates with a limit' do + it "uses FIRST n in updates with a limit" do table = Table.new(:users) stmt = Nodes::UpdateStatement.new stmt.relation = table @@ -29,14 +30,14 @@ def compile node sql.must_be_like "UPDATE \"users\" WHERE \"users\".\"id\" IN (SELECT FIRST 1 \"users\".\"id\" FROM \"users\")" end - it 'uses SKIP n to jump results' do + it "uses SKIP n to jump results" do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(10) sql = compile(stmt) sql.must_be_like "SELECT SKIP 10" end - it 'uses SKIP before FIRST' do + it "uses SKIP before FIRST" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(1) stmt.offset = Nodes::Offset.new(1) @@ -44,7 +45,7 @@ def compile node sql.must_be_like "SELECT SKIP 1 FIRST 1" end - it 'uses INNER JOIN to perform joins' do + 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))]) @@ -53,7 +54,6 @@ def compile node sql = compile(stmt) sql.must_be_like 'SELECT FROM "posts" INNER JOIN "comments"' end - end end end diff --git a/activerecord/test/cases/arel/visitors/mssql_test.rb b/activerecord/test/cases/arel/visitors/mssql_test.rb index 4e81678813e50..340376c3d64a1 100644 --- a/activerecord/test/cases/arel/visitors/mssql_test.rb +++ b/activerecord/test/cases/arel/visitors/mssql_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -9,17 +10,17 @@ class MssqlTest < Arel::Spec @table = Arel::Table.new "users" end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'should not modify query if no offset or limit' do + it "should not modify query if no offset or limit" do stmt = Nodes::SelectStatement.new sql = compile(stmt) sql.must_be_like "SELECT" end - it 'should go over table PK if no .order() or .group()' do + 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) @@ -27,7 +28,7 @@ def compile node sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY \"users\".\"id\") as _row_num FROM \"users\") as _t WHERE _row_num BETWEEN 1 AND 10" end - it 'caches the PK lookup for order' do + it "caches the PK lookup for order" do connection = Minitest::Mock.new connection.expect(:primary_key, ["id"], ["users"]) @@ -46,7 +47,7 @@ def connection.quote_column_name(*); ""; end connection.verify end - it 'should use TOP for limited deletes' do + it "should use TOP for limited deletes" do stmt = Nodes::DeleteStatement.new stmt.relation = @table stmt.limit = Nodes::Limit.new(10) @@ -55,23 +56,23 @@ def connection.quote_column_name(*); ""; end sql.must_be_like "DELETE TOP (10) FROM \"users\"" end - it 'should go over query ORDER BY if .order()' do + 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') + stmt.orders << Nodes::SqlLiteral.new("order_by") sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY order_by) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10" end - it 'should go over query GROUP BY if no .order() and there is .group()' do + 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.cores.first.groups << Nodes::SqlLiteral.new("group_by") stmt.limit = Nodes::Limit.new(10) sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY group_by) as _row_num GROUP BY group_by) as _t WHERE _row_num BETWEEN 1 AND 10" end - it 'should use BETWEEN if both .limit() and .offset' do + 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) @@ -79,21 +80,20 @@ def connection.quote_column_name(*); ""; end 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 + it "should use >= if only .offset" do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(20) sql = compile(stmt) sql.must_be_like "SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num >= 21" end - it 'should generate subquery for .count' do + it "should generate subquery for .count" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) - stmt.cores.first.projections << Nodes::Count.new('*') + stmt.cores.first.projections << Nodes::Count.new("*") sql = compile(stmt) sql.must_be_like "SELECT COUNT(1) as count_id FROM (SELECT _t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY ) as _row_num) as _t WHERE _row_num BETWEEN 1 AND 10) AS subquery" end - end end end diff --git a/activerecord/test/cases/arel/visitors/mysql_test.rb b/activerecord/test/cases/arel/visitors/mysql_test.rb index f9b468b1d229d..9d3bad85165be 100644 --- a/activerecord/test/cases/arel/visitors/mysql_test.rb +++ b/activerecord/test/cases/arel/visitors/mysql_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -8,24 +9,24 @@ class MysqlTest < Arel::Spec @visitor = MySQL.new Table.engine.connection end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'squashes parenthesis on multiple unions' do - subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') - node = Nodes::Union.new subnode, Arel.sql('topright') - assert_equal 1, compile(node).scan('(').length + it "squashes parenthesis on multiple unions" do + subnode = Nodes::Union.new Arel.sql("left"), Arel.sql("right") + node = Nodes::Union.new subnode, Arel.sql("topright") + assert_equal 1, compile(node).scan("(").length - subnode = Nodes::Union.new Arel.sql('left'), Arel.sql('right') - node = Nodes::Union.new Arel.sql('topleft'), subnode - assert_equal 1, compile(node).scan('(').length + subnode = Nodes::Union.new Arel.sql("left"), Arel.sql("right") + node = Nodes::Union.new Arel.sql("topleft"), subnode + assert_equal 1, compile(node).scan("(").length end ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 - it 'defaults limit to 18446744073709551615' do + it "defaults limit to 18446744073709551615" do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) sql = compile(stmt) @@ -39,20 +40,20 @@ def compile node assert_equal("UPDATE \"users\" LIMIT 'omg'", compile(sc)) end - it 'uses DUAL for empty from' do + it "uses DUAL for empty from" do stmt = Nodes::SelectStatement.new sql = compile(stmt) sql.must_be_like "SELECT FROM DUAL" end - describe 'locking' do - it 'defaults to FOR UPDATE when locking' do - node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + describe "locking" do + it "defaults to FOR UPDATE when locking" do + node = Nodes::Lock.new(Arel.sql("FOR UPDATE")) compile(node).must_be_like "FOR UPDATE" end - it 'allows a custom string to be used as a lock' do - node = Nodes::Lock.new(Arel.sql('LOCK IN SHARE MODE')) + it "allows a custom string to be used as a lock" do + node = Nodes::Lock.new(Arel.sql("LOCK IN SHARE MODE")) compile(node).must_be_like "LOCK IN SHARE MODE" end end @@ -68,7 +69,7 @@ def compile node it "concats a string" do @table = Table.new(:users) - query = @table[:name].concat(Nodes.build_quoted('abc')) + query = @table[:name].concat(Nodes.build_quoted("abc")) compile(query).must_be_like %{ CONCAT("users"."name", 'abc') } diff --git a/activerecord/test/cases/arel/visitors/oracle12_test.rb b/activerecord/test/cases/arel/visitors/oracle12_test.rb index ef2050b7c91bb..83a2ee36cae68 100644 --- a/activerecord/test/cases/arel/visitors/oracle12_test.rb +++ b/activerecord/test/cases/arel/visitors/oracle12_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -9,11 +10,11 @@ class Oracle12Test < Arel::Spec @table = Table.new(:users) end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'modified except to be minus' do + it "modified except to be minus" do left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10") right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20") sql = compile Nodes::Except.new(left, right) @@ -22,7 +23,7 @@ def compile node } end - it 'generates select options offset then limit' do + it "generates select options offset then limit" do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) stmt.limit = Nodes::Limit.new(10) @@ -30,18 +31,18 @@ def compile node sql.must_be_like "SELECT OFFSET 1 ROWS FETCH FIRST 10 ROWS ONLY" end - describe 'locking' do - it 'generates ArgumentError if limit and lock are used' do + describe "locking" do + it "generates ArgumentError if limit and lock are used" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) - stmt.lock = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + stmt.lock = Nodes::Lock.new(Arel.sql("FOR UPDATE")) assert_raises ArgumentError do compile(stmt) end end - it 'defaults to FOR UPDATE when locking' do - node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + it "defaults to FOR UPDATE when locking" do + node = Nodes::Lock.new(Arel.sql("FOR UPDATE")) compile(node).must_be_like "FOR UPDATE" end end diff --git a/activerecord/test/cases/arel/visitors/oracle_test.rb b/activerecord/test/cases/arel/visitors/oracle_test.rb index 0737774fbf293..e1dfe40cf9afc 100644 --- a/activerecord/test/cases/arel/visitors/oracle_test.rb +++ b/activerecord/test/cases/arel/visitors/oracle_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -9,79 +10,79 @@ class OracleTest < Arel::Spec @table = Table.new(:users) end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'modifies order when there is distinct and first value' do + 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') + stmt.orders << Nodes::SqlLiteral.new("foo") sql = compile(stmt) sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__ } end - it 'is idempotent with crazy query' do + 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') + stmt.orders << Nodes::SqlLiteral.new("foo") sql = compile(stmt) sql2 = compile(stmt) sql.must_equal sql2 end - it 'splits orders with commas' do + 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') + stmt.orders << Nodes::SqlLiteral.new("foo, bar") sql = compile(stmt) sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__, alias_1__ } end - it 'splits orders with commas and function calls' do + 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)') + stmt.orders << Nodes::SqlLiteral.new("NVL(LOWER(bar, foo), foo) DESC, UPPER(baz)") sql = compile(stmt) sql.must_be_like %{ SELECT #{select} ORDER BY alias_0__ DESC, alias_1__ } end - describe 'Nodes::SelectStatement' do - describe 'limit' do - it 'adds a rownum clause' do + describe "Nodes::SelectStatement" do + describe "limit" do + it "adds a rownum clause" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) sql = compile stmt sql.must_be_like %{ SELECT WHERE ROWNUM <= 10 } end - it 'is idempotent' do + it "is idempotent" do stmt = Nodes::SelectStatement.new - stmt.orders << Nodes::SqlLiteral.new('foo') + stmt.orders << Nodes::SqlLiteral.new("foo") stmt.limit = Nodes::Limit.new(10) sql = compile stmt sql2 = compile stmt sql.must_equal sql2 end - it 'creates a subquery when there is order_by' do + it "creates a subquery when there is order_by" do stmt = Nodes::SelectStatement.new - stmt.orders << Nodes::SqlLiteral.new('foo') + stmt.orders << Nodes::SqlLiteral.new("foo") stmt.limit = Nodes::Limit.new(10) sql = compile stmt sql.must_be_like %{ @@ -89,9 +90,9 @@ def compile node } end - it 'creates a subquery when there is group by' do + it "creates a subquery when there is group by" do stmt = Nodes::SelectStatement.new - stmt.cores.first.groups << Nodes::SqlLiteral.new('foo') + stmt.cores.first.groups << Nodes::SqlLiteral.new("foo") stmt.limit = Nodes::Limit.new(10) sql = compile stmt sql.must_be_like %{ @@ -99,10 +100,10 @@ def compile node } end - it 'creates a subquery when there is DISTINCT' do + it "creates a subquery when there is DISTINCT" do stmt = Nodes::SelectStatement.new stmt.cores.first.set_quantifier = Arel::Nodes::Distinct.new - stmt.cores.first.projections << Nodes::SqlLiteral.new('id') + stmt.cores.first.projections << Nodes::SqlLiteral.new("id") stmt.limit = Arel::Nodes::Limit.new(10) sql = compile stmt sql.must_be_like %{ @@ -110,7 +111,7 @@ def compile node } end - it 'creates a different subquery when there is an offset' do + 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) @@ -125,7 +126,7 @@ def compile node } end - it 'creates a subquery when there is limit and offset with BindParams' do + it "creates a subquery when there is limit and offset with BindParams" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(Nodes::BindParam.new(1)) stmt.offset = Nodes::Offset.new(Nodes::BindParam.new(1)) @@ -140,7 +141,7 @@ def compile node } end - it 'is idempotent with different subquery' do + it "is idempotent with different subquery" do stmt = Nodes::SelectStatement.new stmt.limit = Nodes::Limit.new(10) stmt.offset = Nodes::Offset.new(10) @@ -150,8 +151,8 @@ def compile node end end - describe 'only offset' do - it 'creates a select from subquery with rownum condition' do + describe "only offset" do + it "creates a select from subquery with rownum condition" do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(10) sql = compile stmt @@ -166,7 +167,7 @@ def compile node end end - it 'modified except to be minus' do + it "modified except to be minus" do left = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 10") right = Nodes::SqlLiteral.new("SELECT * FROM users WHERE age > 20") sql = compile Nodes::Except.new(left, right) @@ -175,9 +176,9 @@ def compile node } end - describe 'locking' do - it 'defaults to FOR UPDATE when locking' do - node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) + describe "locking" do + it "defaults to FOR UPDATE when locking" do + node = Nodes::Lock.new(Arel.sql("FOR UPDATE")) compile(node).must_be_like "FOR UPDATE" end end diff --git a/activerecord/test/cases/arel/visitors/postgres_test.rb b/activerecord/test/cases/arel/visitors/postgres_test.rb index 6aa786b14f9f7..ba37afecfba61 100644 --- a/activerecord/test/cases/arel/visitors/postgres_test.rb +++ b/activerecord/test/cases/arel/visitors/postgres_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -10,19 +11,19 @@ class PostgresTest < Arel::Spec @attr = @table[:id] end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - describe 'locking' do - it 'defaults to FOR UPDATE' do - compile(Nodes::Lock.new(Arel.sql('FOR UPDATE'))).must_be_like %{ + describe "locking" do + it "defaults to FOR UPDATE" do + compile(Nodes::Lock.new(Arel.sql("FOR UPDATE"))).must_be_like %{ FOR UPDATE } end - it 'allows a custom string to be used as a lock' do - node = Nodes::Lock.new(Arel.sql('FOR SHARE')) + it "allows a custom string to be used as a lock" do + node = Nodes::Lock.new(Arel.sql("FOR SHARE")) compile(node).must_be_like %{ FOR SHARE } @@ -32,42 +33,42 @@ def compile node it "should escape LIMIT" do sc = Arel::Nodes::SelectStatement.new sc.limit = Nodes::Limit.new(Nodes.build_quoted("omg")) - sc.cores.first.projections << Arel.sql('DISTINCT ON') + sc.cores.first.projections << Arel.sql("DISTINCT ON") sc.orders << Arel.sql("xyz") - sql = compile(sc) + sql = compile(sc) assert_match(/LIMIT 'omg'/, sql) - assert_equal 1, sql.scan(/LIMIT/).length, 'should have one limit' + assert_equal 1, sql.scan(/LIMIT/).length, "should have one limit" end - it 'should support DISTINCT ON' do + it "should support DISTINCT ON" do core = Arel::Nodes::SelectCore.new - core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql('aaron')) - assert_match 'DISTINCT ON ( aaron )', compile(core) + core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql("aaron")) + assert_match "DISTINCT ON ( aaron )", compile(core) end - it 'should support DISTINCT' do + it "should support DISTINCT" do core = Arel::Nodes::SelectCore.new core.set_quantifier = Arel::Nodes::Distinct.new - assert_equal 'SELECT DISTINCT', compile(core) + assert_equal "SELECT DISTINCT", compile(core) end - it 'encloses LATERAL queries in parens' do - subquery = @table.project(:id).where(@table[:name].matches('foo%')) + it "encloses LATERAL queries in parens" do + subquery = @table.project(:id).where(@table[:name].matches("foo%")) compile(subquery.lateral).must_be_like %{ LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') } end - it 'produces LATERAL queries with alias' do - subquery = @table.project(:id).where(@table[:name].matches('foo%')) - compile(subquery.lateral('bar')).must_be_like %{ + it "produces LATERAL queries with alias" do + subquery = @table.project(:id).where(@table[:name].matches("foo%")) + compile(subquery.lateral("bar")).must_be_like %{ LATERAL (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') bar } end describe "Nodes::Matches" do it "should know how to visit" do - node = @table[:name].matches('foo%') + node = @table[:name].matches("foo%") node.must_be_kind_of Nodes::Matches node.case_sensitive.must_equal(false) compile(node).must_be_like %{ @@ -76,7 +77,7 @@ def compile node end it "should know how to visit case sensitive" do - node = @table[:name].matches('foo%', nil, true) + node = @table[:name].matches("foo%", nil, true) node.case_sensitive.must_equal(true) compile(node).must_be_like %{ "users"."name" LIKE 'foo%' @@ -84,14 +85,14 @@ def compile node end it "can handle ESCAPE" do - node = @table[:name].matches('foo!%', '!') + node = @table[:name].matches("foo!%", "!") compile(node).must_be_like %{ "users"."name" ILIKE 'foo!%' ESCAPE '!' } end - it 'can handle subqueries' do - subquery = @table.project(:id).where(@table[:name].matches('foo%')) + it "can handle subqueries" do + subquery = @table.project(:id).where(@table[:name].matches("foo%")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ILIKE 'foo%') @@ -101,7 +102,7 @@ def compile node describe "Nodes::DoesNotMatch" do it "should know how to visit" do - node = @table[:name].does_not_match('foo%') + node = @table[:name].does_not_match("foo%") node.must_be_kind_of Nodes::DoesNotMatch node.case_sensitive.must_equal(false) compile(node).must_be_like %{ @@ -110,7 +111,7 @@ def compile node end it "should know how to visit case sensitive" do - node = @table[:name].does_not_match('foo%', nil, true) + node = @table[:name].does_not_match("foo%", nil, true) node.case_sensitive.must_equal(true) compile(node).must_be_like %{ "users"."name" NOT LIKE 'foo%' @@ -118,14 +119,14 @@ def compile node end it "can handle ESCAPE" do - node = @table[:name].does_not_match('foo!%', '!') + node = @table[:name].does_not_match("foo!%", "!") compile(node).must_be_like %{ "users"."name" NOT ILIKE 'foo!%' ESCAPE '!' } end - it 'can handle subqueries' do - subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) + it "can handle subqueries" do + subquery = @table.project(:id).where(@table[:name].does_not_match("foo%")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT ILIKE 'foo%') @@ -135,7 +136,7 @@ def compile node describe "Nodes::Regexp" do it "should know how to visit" do - node = @table[:name].matches_regexp('foo.*') + node = @table[:name].matches_regexp("foo.*") node.must_be_kind_of Nodes::Regexp node.case_sensitive.must_equal(true) compile(node).must_be_like %{ @@ -144,7 +145,7 @@ def compile node end it "can handle case insensitive" do - node = @table[:name].matches_regexp('foo.*', false) + node = @table[:name].matches_regexp("foo.*", false) node.must_be_kind_of Nodes::Regexp node.case_sensitive.must_equal(false) compile(node).must_be_like %{ @@ -152,8 +153,8 @@ def compile node } end - it 'can handle subqueries' do - subquery = @table.project(:id).where(@table[:name].matches_regexp('foo.*')) + it "can handle subqueries" do + subquery = @table.project(:id).where(@table[:name].matches_regexp("foo.*")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" ~ 'foo.*') @@ -163,7 +164,7 @@ def compile node describe "Nodes::NotRegexp" do it "should know how to visit" do - node = @table[:name].does_not_match_regexp('foo.*') + node = @table[:name].does_not_match_regexp("foo.*") node.must_be_kind_of Nodes::NotRegexp node.case_sensitive.must_equal(true) compile(node).must_be_like %{ @@ -172,15 +173,15 @@ def compile node end it "can handle case insensitive" do - node = @table[:name].does_not_match_regexp('foo.*', false) + node = @table[:name].does_not_match_regexp("foo.*", false) node.case_sensitive.must_equal(false) compile(node).must_be_like %{ "users"."name" !~* 'foo.*' } end - it 'can handle subqueries' do - subquery = @table.project(:id).where(@table[:name].does_not_match_regexp('foo.*')) + it "can handle subqueries" do + subquery = @table.project(:id).where(@table[:name].does_not_match_regexp("foo.*")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" !~ 'foo.*') diff --git a/activerecord/test/cases/arel/visitors/sqlite_test.rb b/activerecord/test/cases/arel/visitors/sqlite_test.rb index 23f66ee096409..6650b6ff3aa31 100644 --- a/activerecord/test/cases/arel/visitors/sqlite_test.rb +++ b/activerecord/test/cases/arel/visitors/sqlite_test.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -require_relative '../helper' + +require_relative "../helper" module Arel module Visitors @@ -8,23 +9,23 @@ class SqliteTest < Arel::Spec @visitor = SQLite.new Table.engine.connection_pool end - it 'defaults limit to -1' do + it "defaults limit to -1" do stmt = Nodes::SelectStatement.new stmt.offset = Nodes::Offset.new(1) sql = @visitor.accept(stmt, Collectors::SQLString.new).value sql.must_be_like "SELECT LIMIT -1 OFFSET 1" end - it 'does not support locking' do - node = Nodes::Lock.new(Arel.sql('FOR UPDATE')) - assert_equal '', @visitor.accept(node, Collectors::SQLString.new).value + it "does not support locking" do + node = Nodes::Lock.new(Arel.sql("FOR UPDATE")) + assert_equal "", @visitor.accept(node, Collectors::SQLString.new).value end - it 'does not support boolean' do + it "does not support boolean" do node = Nodes::True.new() - assert_equal '1', @visitor.accept(node, Collectors::SQLString.new).value + assert_equal "1", @visitor.accept(node, Collectors::SQLString.new).value node = Nodes::False.new() - assert_equal '0', @visitor.accept(node, Collectors::SQLString.new).value + assert_equal "0", @visitor.accept(node, Collectors::SQLString.new).value end end end diff --git a/activerecord/test/cases/arel/visitors/to_sql_test.rb b/activerecord/test/cases/arel/visitors/to_sql_test.rb index 1503bcd578b0a..ce836eded749f 100644 --- a/activerecord/test/cases/arel/visitors/to_sql_test.rb +++ b/activerecord/test/cases/arel/visitors/to_sql_test.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true -require_relative '../helper' -require 'bigdecimal' + +require_relative "../helper" +require "bigdecimal" module Arel module Visitors - describe 'the to_sql visitor' do + describe "the to_sql visitor" do before do @conn = FakeRecord::Base.new @visitor = ToSql.new @conn.connection @@ -12,24 +13,24 @@ module Visitors @attr = @table[:id] end - def compile node + def compile(node) @visitor.accept(node, Collectors::SQLString.new).value end - it 'works with BindParams' do + it "works with BindParams" do node = Nodes::BindParam.new(1) sql = compile node - sql.must_be_like '?' + sql.must_be_like "?" end - it 'does not quote BindParams used as part of a Values' do + it "does not quote BindParams used as part of a Values" do bp = Nodes::BindParam.new(1) values = Nodes::Values.new([bp]) sql = compile values - sql.must_be_like 'VALUES (?)' + sql.must_be_like "VALUES (?)" end - it 'can define a dispatch method' do + it "can define a dispatch method" do visited = false viz = Class.new(Arel::Visitors::Visitor) { define_method(:hello) do |node, c| @@ -37,117 +38,117 @@ def compile node end def dispatch - { Arel::Table => 'hello' } + { Arel::Table => "hello" } end }.new viz.accept(@table, Collectors::SQLString.new) - assert visited, 'hello method was called' + assert visited, "hello method was called" end - it 'should not quote sql literals' do + it "should not quote sql literals" do node = @table[Arel.star] sql = compile node sql.must_be_like '"users".*' end - it 'should visit named functions' do - function = Nodes::NamedFunction.new('omg', [Arel.star]) - assert_equal 'omg(*)', compile(function) + it "should visit named functions" do + function = Nodes::NamedFunction.new("omg", [Arel.star]) + assert_equal "omg(*)", compile(function) end - it 'should chain predications on named functions' do - function = Nodes::NamedFunction.new('omg', [Arel.star]) + it "should chain predications on named functions" do + function = Nodes::NamedFunction.new("omg", [Arel.star]) sql = compile(function.eq(2)) sql.must_be_like %{ omg(*) = 2 } end - it 'should handle nil with named functions' do - function = Nodes::NamedFunction.new('omg', [Arel.star]) + it "should handle nil with named functions" do + function = Nodes::NamedFunction.new("omg", [Arel.star]) sql = compile(function.eq(nil)) sql.must_be_like %{ omg(*) IS NULL } end - it 'should visit built-in functions' do + it "should visit built-in functions" do function = Nodes::Count.new([Arel.star]) - assert_equal 'COUNT(*)', compile(function) + assert_equal "COUNT(*)", compile(function) function = Nodes::Sum.new([Arel.star]) - assert_equal 'SUM(*)', compile(function) + assert_equal "SUM(*)", compile(function) function = Nodes::Max.new([Arel.star]) - assert_equal 'MAX(*)', compile(function) + assert_equal "MAX(*)", compile(function) function = Nodes::Min.new([Arel.star]) - assert_equal 'MIN(*)', compile(function) + assert_equal "MIN(*)", compile(function) function = Nodes::Avg.new([Arel.star]) - assert_equal 'AVG(*)', compile(function) + assert_equal "AVG(*)", compile(function) end - it 'should visit built-in functions operating on distinct values' do + it "should visit built-in functions operating on distinct values" do function = Nodes::Count.new([Arel.star]) function.distinct = true - assert_equal 'COUNT(DISTINCT *)', compile(function) + assert_equal "COUNT(DISTINCT *)", compile(function) function = Nodes::Sum.new([Arel.star]) function.distinct = true - assert_equal 'SUM(DISTINCT *)', compile(function) + assert_equal "SUM(DISTINCT *)", compile(function) function = Nodes::Max.new([Arel.star]) function.distinct = true - assert_equal 'MAX(DISTINCT *)', compile(function) + assert_equal "MAX(DISTINCT *)", compile(function) function = Nodes::Min.new([Arel.star]) function.distinct = true - assert_equal 'MIN(DISTINCT *)', compile(function) + assert_equal "MIN(DISTINCT *)", compile(function) function = Nodes::Avg.new([Arel.star]) function.distinct = true - assert_equal 'AVG(DISTINCT *)', compile(function) + assert_equal "AVG(DISTINCT *)", compile(function) end - it 'works with lists' do - function = Nodes::NamedFunction.new('omg', [Arel.star, Arel.star]) - assert_equal 'omg(*, *)', compile(function) + it "works with lists" do + function = Nodes::NamedFunction.new("omg", [Arel.star, Arel.star]) + assert_equal "omg(*, *)", compile(function) end - describe 'Nodes::Equality' do + describe "Nodes::Equality" do it "should escape strings" do - test = Table.new(:users)[:name].eq 'Aaron Patterson' + test = Table.new(:users)[:name].eq "Aaron Patterson" compile(test).must_be_like %{ "users"."name" = 'Aaron Patterson' } end - it 'should handle false' do + it "should handle false" do table = Table.new(:users) val = Nodes.build_quoted(false, table[:active]) sql = compile Nodes::Equality.new(val, val) sql.must_be_like %{ 'f' = 'f' } end - it 'should handle nil' do + it "should handle nil" do sql = compile Nodes::Equality.new(@table[:name], nil) sql.must_be_like %{ "users"."name" IS NULL } end end - describe 'Nodes::Grouping' do - it 'wraps nested groupings in brackets only once' do - sql = compile Nodes::Grouping.new(Nodes::Grouping.new(Nodes.build_quoted('foo'))) + describe "Nodes::Grouping" do + it "wraps nested groupings in brackets only once" do + sql = compile Nodes::Grouping.new(Nodes::Grouping.new(Nodes.build_quoted("foo"))) sql.must_equal "('foo')" end end - describe 'Nodes::NotEqual' do - it 'should handle false' do + describe "Nodes::NotEqual" do + it "should handle false" do val = Nodes.build_quoted(false, @table[:active]) sql = compile Nodes::NotEqual.new(@table[:active], val) sql.must_be_like %{ "users"."active" != 'f' } end - it 'should handle nil' do + it "should handle nil" do val = Nodes.build_quoted(nil, @table[:active]) sql = compile Nodes::NotEqual.new(@table[:name], val) sql.must_be_like %{ "users"."name" IS NOT NULL } @@ -225,7 +226,7 @@ def dispatch end it "should visit_Hash" do - compile(Nodes.build_quoted({:a => 1})) + compile(Nodes.build_quoted(a: 1)) end it "should visit_Set" do @@ -233,7 +234,7 @@ def dispatch end it "should visit_BigDecimal" do - compile Nodes.build_quoted(BigDecimal('2.14')) + compile Nodes.build_quoted(BigDecimal("2.14")) end it "should visit_Date" do @@ -296,21 +297,21 @@ def dispatch describe "Nodes::Matches" do it "should know how to visit" do - node = @table[:name].matches('foo%') + node = @table[:name].matches("foo%") compile(node).must_be_like %{ "users"."name" LIKE 'foo%' } end it "can handle ESCAPE" do - node = @table[:name].matches('foo!%', '!') + node = @table[:name].matches("foo!%", "!") compile(node).must_be_like %{ "users"."name" LIKE 'foo!%' ESCAPE '!' } end - it 'can handle subqueries' do - subquery = @table.project(:id).where(@table[:name].matches('foo%')) + it "can handle subqueries" do + subquery = @table.project(:id).where(@table[:name].matches("foo%")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" LIKE 'foo%') @@ -320,21 +321,21 @@ def dispatch describe "Nodes::DoesNotMatch" do it "should know how to visit" do - node = @table[:name].does_not_match('foo%') + node = @table[:name].does_not_match("foo%") compile(node).must_be_like %{ "users"."name" NOT LIKE 'foo%' } end it "can handle ESCAPE" do - node = @table[:name].does_not_match('foo!%', '!') + node = @table[:name].does_not_match("foo!%", "!") compile(node).must_be_like %{ "users"."name" NOT LIKE 'foo!%' ESCAPE '!' } end - it 'can handle subqueries' do - subquery = @table.project(:id).where(@table[:name].does_not_match('foo%')) + it "can handle subqueries" do + subquery = @table.project(:id).where(@table[:name].does_not_match("foo%")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" NOT LIKE 'foo%') @@ -361,24 +362,24 @@ def dispatch it "should return 1=0 when empty right which is always false" do node = @attr.in [] - compile(node).must_equal '1=0' + compile(node).must_equal "1=0" end - it 'can handle two dot ranges' do + it "can handle two dot ranges" do node = @attr.between 1..3 compile(node).must_be_like %{ "users"."id" BETWEEN 1 AND 3 } end - it 'can handle three dot ranges' do + it "can handle three dot ranges" do node = @attr.between 1...3 compile(node).must_be_like %{ "users"."id" >= 1 AND "users"."id" < 3 } end - it 'can handle ranges bounded by infinity' do + it "can handle ranges bounded by infinity" do node = @attr.between 1..Float::INFINITY compile(node).must_be_like %{ "users"."id" >= 1 @@ -395,9 +396,9 @@ def dispatch compile(node).must_be_like %{1=1} end - it 'can handle subqueries' do + it "can handle subqueries" do table = Table.new(:users) - subquery = table.project(:id).where(table[:name].eq('Aaron')) + subquery = table.project(:id).where(table[:name].eq("Aaron")) node = @attr.in subquery compile(node).must_be_like %{ "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') @@ -459,7 +460,7 @@ def dispatch 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) ) @@ -474,7 +475,7 @@ def dispatch end it "should handle arbitrary operators" do - node = Arel::Nodes::UnaryOperation.new('!', Arel::Attributes::String.new(Table.new(:products), :active)) + node = Arel::Nodes::UnaryOperation.new("!", Arel::Attributes::String.new(Table.new(:products), :active)) compile(node).must_equal %( ! "products"."active") end end @@ -489,24 +490,24 @@ def dispatch it "should return 1=1 when empty right which is always true" do node = @attr.not_in [] - compile(node).must_equal '1=1' + compile(node).must_equal "1=1" end - it 'can handle two dot ranges' do + it "can handle two dot ranges" do node = @attr.not_between 1..3 compile(node).must_equal( %{("users"."id" < 1 OR "users"."id" > 3)} ) end - it 'can handle three dot ranges' do + it "can handle three dot ranges" do node = @attr.not_between 1...3 compile(node).must_equal( %{("users"."id" < 1 OR "users"."id" >= 3)} ) end - it 'can handle ranges bounded by infinity' do + it "can handle ranges bounded by infinity" do node = @attr.not_between 1..Float::INFINITY compile(node).must_be_like %{ "users"."id" < 1 @@ -523,9 +524,9 @@ def dispatch compile(node).must_be_like %{1=0} end - it 'can handle subqueries' do + it "can handle subqueries" do table = Table.new(:users) - subquery = table.project(:id).where(table[:name].eq('Aaron')) + subquery = table.project(:id).where(table[:name].eq("Aaron")) node = @attr.not_in subquery compile(node).must_be_like %{ "users"."id" NOT IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') @@ -533,7 +534,7 @@ def dispatch end end - describe 'Constants' do + describe "Constants" do it "should handle true" do test = Table.new(:users).create_true compile(test).must_be_like %{ @@ -549,19 +550,19 @@ def dispatch end end - describe 'TableAlias' do + describe "TableAlias" do it "should use the underlying table for checking columns" do - test = Table.new(:users).alias('zomgusers')[:id].eq '3' + test = Table.new(:users).alias("zomgusers")[:id].eq "3" compile(test).must_be_like %{ "zomgusers"."id" = '3' } end end - describe 'distinct on' do - it 'raises not implemented error' do + 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')) + core.set_quantifier = Arel::Nodes::DistinctOn.new(Arel.sql("aaron")) assert_raises(NotImplementedError) do compile(core) @@ -569,9 +570,9 @@ def dispatch end end - describe 'Nodes::Regexp' do - it 'raises not implemented error' do - node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted('foo%')) + describe "Nodes::Regexp" do + it "raises not implemented error" do + node = Arel::Nodes::Regexp.new(@table[:name], Nodes.build_quoted("foo%")) assert_raises(NotImplementedError) do compile(node) @@ -579,9 +580,9 @@ def dispatch end end - describe 'Nodes::NotRegexp' do - it 'raises not implemented error' do - node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted('foo%')) + describe "Nodes::NotRegexp" do + it "raises not implemented error" do + node = Arel::Nodes::NotRegexp.new(@table[:name], Nodes.build_quoted("foo%")) assert_raises(NotImplementedError) do compile(node) @@ -589,10 +590,10 @@ def dispatch end end - describe 'Nodes::Case' do - it 'supports simple case expressions' do + describe "Nodes::Case" do + it "supports simple case expressions" do node = Arel::Nodes::Case.new(@table[:name]) - .when('foo').then(1) + .when("foo").then(1) .else(0) compile(node).must_be_like %{ @@ -600,7 +601,7 @@ def dispatch } end - it 'supports extended case expressions' do + it "supports extended case expressions" do node = Arel::Nodes::Case.new .when(@table[:name].in(%w(foo bar))).then(1) .else(0) @@ -610,19 +611,19 @@ def dispatch } end - it 'works without default branch' do + it "works without default branch" do node = Arel::Nodes::Case.new(@table[:name]) - .when('foo').then(1) + .when("foo").then(1) compile(node).must_be_like %{ CASE "users"."name" WHEN 'foo' THEN 1 END } end - it 'allows chaining multiple conditions' do + it "allows chaining multiple conditions" do node = Arel::Nodes::Case.new(@table[:name]) - .when('foo').then(1) - .when('bar').then(2) + .when("foo").then(1) + .when("bar").then(2) .else(0) compile(node).must_be_like %{ @@ -630,7 +631,7 @@ def dispatch } end - it 'supports #when with two arguments and no #then' do + it "supports #when with two arguments and no #then" do node = Arel::Nodes::Case.new @table[:name] { foo: 1, bar: 0 }.reduce(node) { |_node, pair| _node.when(*pair) } @@ -640,8 +641,8 @@ def dispatch } end - it 'can be chained as a predicate' do - node = @table[:name].when('foo').then('bar').else('baz') + it "can be chained as a predicate" do + node = @table[:name].when("foo").then("bar").else("baz") compile(node).must_be_like %{ CASE "users"."name" WHEN 'foo' THEN 'bar' ELSE 'baz' END From 354f1c28e81d9846fb9e5346fcca50cf303c12c1 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Sat, 24 Feb 2018 18:11:47 +1030 Subject: [PATCH 1492/1492] Arel: :nodoc: all --- activerecord/lib/arel.rb | 2 +- activerecord/lib/arel/alias_predication.rb | 2 +- activerecord/lib/arel/attributes.rb | 2 +- activerecord/lib/arel/attributes/attribute.rb | 2 +- activerecord/lib/arel/collectors/bind.rb | 2 +- activerecord/lib/arel/collectors/composite.rb | 2 +- activerecord/lib/arel/collectors/plain_string.rb | 2 +- activerecord/lib/arel/collectors/sql_string.rb | 2 +- activerecord/lib/arel/collectors/substitute_binds.rb | 2 +- activerecord/lib/arel/compatibility/wheres.rb | 2 +- activerecord/lib/arel/crud.rb | 2 +- activerecord/lib/arel/delete_manager.rb | 2 +- activerecord/lib/arel/errors.rb | 2 +- activerecord/lib/arel/expressions.rb | 2 +- activerecord/lib/arel/factory_methods.rb | 2 +- activerecord/lib/arel/insert_manager.rb | 2 +- activerecord/lib/arel/math.rb | 2 +- activerecord/lib/arel/nodes/and.rb | 2 +- activerecord/lib/arel/nodes/ascending.rb | 2 +- activerecord/lib/arel/nodes/binary.rb | 2 +- activerecord/lib/arel/nodes/bind_param.rb | 2 +- activerecord/lib/arel/nodes/case.rb | 2 +- activerecord/lib/arel/nodes/casted.rb | 2 +- activerecord/lib/arel/nodes/count.rb | 2 +- activerecord/lib/arel/nodes/delete_statement.rb | 2 +- activerecord/lib/arel/nodes/descending.rb | 2 +- activerecord/lib/arel/nodes/equality.rb | 2 +- activerecord/lib/arel/nodes/extract.rb | 2 +- activerecord/lib/arel/nodes/false.rb | 2 +- activerecord/lib/arel/nodes/full_outer_join.rb | 2 +- activerecord/lib/arel/nodes/function.rb | 2 +- activerecord/lib/arel/nodes/grouping.rb | 2 +- activerecord/lib/arel/nodes/in.rb | 2 +- activerecord/lib/arel/nodes/infix_operation.rb | 2 +- activerecord/lib/arel/nodes/inner_join.rb | 2 +- activerecord/lib/arel/nodes/insert_statement.rb | 2 +- activerecord/lib/arel/nodes/join_source.rb | 2 +- activerecord/lib/arel/nodes/matches.rb | 2 +- activerecord/lib/arel/nodes/named_function.rb | 2 +- activerecord/lib/arel/nodes/node.rb | 2 +- activerecord/lib/arel/nodes/node_expression.rb | 2 +- activerecord/lib/arel/nodes/outer_join.rb | 2 +- activerecord/lib/arel/nodes/over.rb | 2 +- activerecord/lib/arel/nodes/regexp.rb | 2 +- activerecord/lib/arel/nodes/right_outer_join.rb | 2 +- activerecord/lib/arel/nodes/select_core.rb | 2 +- activerecord/lib/arel/nodes/select_statement.rb | 2 +- activerecord/lib/arel/nodes/sql_literal.rb | 2 +- activerecord/lib/arel/nodes/string_join.rb | 2 +- activerecord/lib/arel/nodes/table_alias.rb | 2 +- activerecord/lib/arel/nodes/terminal.rb | 2 +- activerecord/lib/arel/nodes/true.rb | 2 +- activerecord/lib/arel/nodes/unary.rb | 2 +- activerecord/lib/arel/nodes/unary_operation.rb | 2 +- activerecord/lib/arel/nodes/unqualified_column.rb | 2 +- activerecord/lib/arel/nodes/update_statement.rb | 2 +- activerecord/lib/arel/nodes/values.rb | 2 +- activerecord/lib/arel/nodes/values_list.rb | 2 +- activerecord/lib/arel/nodes/window.rb | 2 +- activerecord/lib/arel/nodes/with.rb | 2 +- activerecord/lib/arel/order_predications.rb | 2 +- activerecord/lib/arel/predications.rb | 2 +- activerecord/lib/arel/select_manager.rb | 2 +- activerecord/lib/arel/table.rb | 2 +- activerecord/lib/arel/tree_manager.rb | 2 +- activerecord/lib/arel/update_manager.rb | 2 +- activerecord/lib/arel/visitors.rb | 2 +- activerecord/lib/arel/visitors/depth_first.rb | 2 +- activerecord/lib/arel/visitors/dot.rb | 2 +- activerecord/lib/arel/visitors/ibm_db.rb | 2 +- activerecord/lib/arel/visitors/informix.rb | 2 +- activerecord/lib/arel/visitors/mssql.rb | 2 +- activerecord/lib/arel/visitors/mysql.rb | 2 +- activerecord/lib/arel/visitors/oracle.rb | 2 +- activerecord/lib/arel/visitors/oracle12.rb | 2 +- activerecord/lib/arel/visitors/postgresql.rb | 2 +- activerecord/lib/arel/visitors/sqlite.rb | 2 +- activerecord/lib/arel/visitors/to_sql.rb | 2 +- activerecord/lib/arel/visitors/visitor.rb | 2 +- activerecord/lib/arel/visitors/where_sql.rb | 2 +- activerecord/lib/arel/window_predications.rb | 2 +- 81 files changed, 81 insertions(+), 81 deletions(-) diff --git a/activerecord/lib/arel.rb b/activerecord/lib/arel.rb index 2d5cfa4d5c4e5..7d04e1cac693f 100644 --- a/activerecord/lib/arel.rb +++ b/activerecord/lib/arel.rb @@ -25,7 +25,7 @@ require "arel/delete_manager" require "arel/nodes" -module Arel +module Arel # :nodoc: all VERSION = "10.0.0" def self.sql(raw_sql) diff --git a/activerecord/lib/arel/alias_predication.rb b/activerecord/lib/arel/alias_predication.rb index ae44157b9a5b0..4abbbb7ef6def 100644 --- a/activerecord/lib/arel/alias_predication.rb +++ b/activerecord/lib/arel/alias_predication.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module AliasPredication def as(other) Nodes::As.new self, Nodes::SqlLiteral.new(other) diff --git a/activerecord/lib/arel/attributes.rb b/activerecord/lib/arel/attributes.rb index c81a7b941b5ab..35d586c948c2d 100644 --- a/activerecord/lib/arel/attributes.rb +++ b/activerecord/lib/arel/attributes.rb @@ -2,7 +2,7 @@ require "arel/attributes/attribute" -module Arel +module Arel # :nodoc: all module Attributes ### # Factory method to wrap a raw database +column+ to an Arel Attribute. diff --git a/activerecord/lib/arel/attributes/attribute.rb b/activerecord/lib/arel/attributes/attribute.rb index 71f839479ae2c..ecf499a23ef01 100644 --- a/activerecord/lib/arel/attributes/attribute.rb +++ b/activerecord/lib/arel/attributes/attribute.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Attributes class Attribute < Struct.new :relation, :name include Arel::Expressions diff --git a/activerecord/lib/arel/collectors/bind.rb b/activerecord/lib/arel/collectors/bind.rb index 8d19e7446d5c1..6f8912575dce8 100644 --- a/activerecord/lib/arel/collectors/bind.rb +++ b/activerecord/lib/arel/collectors/bind.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Collectors class Bind def initialize diff --git a/activerecord/lib/arel/collectors/composite.rb b/activerecord/lib/arel/collectors/composite.rb index 675a81959637c..d040d8598dc14 100644 --- a/activerecord/lib/arel/collectors/composite.rb +++ b/activerecord/lib/arel/collectors/composite.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Collectors class Composite def initialize(left, right) diff --git a/activerecord/lib/arel/collectors/plain_string.rb b/activerecord/lib/arel/collectors/plain_string.rb index b98802c44a9f4..687d7fbf2f729 100644 --- a/activerecord/lib/arel/collectors/plain_string.rb +++ b/activerecord/lib/arel/collectors/plain_string.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Collectors class PlainString def initialize diff --git a/activerecord/lib/arel/collectors/sql_string.rb b/activerecord/lib/arel/collectors/sql_string.rb index 78c9e48aab601..c293a89a74b5c 100644 --- a/activerecord/lib/arel/collectors/sql_string.rb +++ b/activerecord/lib/arel/collectors/sql_string.rb @@ -2,7 +2,7 @@ require "arel/collectors/plain_string" -module Arel +module Arel # :nodoc: all module Collectors class SQLString < PlainString def initialize(*) diff --git a/activerecord/lib/arel/collectors/substitute_binds.rb b/activerecord/lib/arel/collectors/substitute_binds.rb index ee6635f914f4c..3f40eec8a8abb 100644 --- a/activerecord/lib/arel/collectors/substitute_binds.rb +++ b/activerecord/lib/arel/collectors/substitute_binds.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Collectors class SubstituteBinds def initialize(quoter, delegate_collector) diff --git a/activerecord/lib/arel/compatibility/wheres.rb b/activerecord/lib/arel/compatibility/wheres.rb index 2ffb2e0ad8508..c8a73f0dae987 100644 --- a/activerecord/lib/arel/compatibility/wheres.rb +++ b/activerecord/lib/arel/compatibility/wheres.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Compatibility # :nodoc: class Wheres # :nodoc: include Enumerable diff --git a/activerecord/lib/arel/crud.rb b/activerecord/lib/arel/crud.rb index e2427b730c1bc..e8a563ca4ae7b 100644 --- a/activerecord/lib/arel/crud.rb +++ b/activerecord/lib/arel/crud.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all ### # FIXME hopefully we can remove this module Crud diff --git a/activerecord/lib/arel/delete_manager.rb b/activerecord/lib/arel/delete_manager.rb index df1f92bd23196..2def5810098d8 100644 --- a/activerecord/lib/arel/delete_manager.rb +++ b/activerecord/lib/arel/delete_manager.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class DeleteManager < Arel::TreeManager def initialize super diff --git a/activerecord/lib/arel/errors.rb b/activerecord/lib/arel/errors.rb index 8733b7ff5a7a7..2f8d5e3c02030 100644 --- a/activerecord/lib/arel/errors.rb +++ b/activerecord/lib/arel/errors.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class ArelError < StandardError end diff --git a/activerecord/lib/arel/expressions.rb b/activerecord/lib/arel/expressions.rb index 597b861b6c44a..da8afb338ca75 100644 --- a/activerecord/lib/arel/expressions.rb +++ b/activerecord/lib/arel/expressions.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Expressions def count(distinct = false) Nodes::Count.new [self], distinct diff --git a/activerecord/lib/arel/factory_methods.rb b/activerecord/lib/arel/factory_methods.rb index 55aea3ecd7259..b828bc274e690 100644 --- a/activerecord/lib/arel/factory_methods.rb +++ b/activerecord/lib/arel/factory_methods.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all ### # Methods for creating various nodes module FactoryMethods diff --git a/activerecord/lib/arel/insert_manager.rb b/activerecord/lib/arel/insert_manager.rb index 47b52d6515b4d..c90fc33a48052 100644 --- a/activerecord/lib/arel/insert_manager.rb +++ b/activerecord/lib/arel/insert_manager.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class InsertManager < Arel::TreeManager def initialize super diff --git a/activerecord/lib/arel/math.rb b/activerecord/lib/arel/math.rb index 671457efff3ad..2359f1314860b 100644 --- a/activerecord/lib/arel/math.rb +++ b/activerecord/lib/arel/math.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Math def *(other) Arel::Nodes::Multiplication.new(self, other) diff --git a/activerecord/lib/arel/nodes/and.rb b/activerecord/lib/arel/nodes/and.rb index e76d4f3933d45..c530a77bfbe42 100644 --- a/activerecord/lib/arel/nodes/and.rb +++ b/activerecord/lib/arel/nodes/and.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class And < Arel::Nodes::Node attr_reader :children diff --git a/activerecord/lib/arel/nodes/ascending.rb b/activerecord/lib/arel/nodes/ascending.rb index 7ee531734fd03..8b617f4df5723 100644 --- a/activerecord/lib/arel/nodes/ascending.rb +++ b/activerecord/lib/arel/nodes/ascending.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Ascending < Ordering def reverse diff --git a/activerecord/lib/arel/nodes/binary.rb b/activerecord/lib/arel/nodes/binary.rb index e6a5cb63dff22..e184e99c73a84 100644 --- a/activerecord/lib/arel/nodes/binary.rb +++ b/activerecord/lib/arel/nodes/binary.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Binary < Arel::Nodes::NodeExpression attr_accessor :left, :right diff --git a/activerecord/lib/arel/nodes/bind_param.rb b/activerecord/lib/arel/nodes/bind_param.rb index 1cc1886c2abb4..53c5563d938f6 100644 --- a/activerecord/lib/arel/nodes/bind_param.rb +++ b/activerecord/lib/arel/nodes/bind_param.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class BindParam < Node attr_accessor :value diff --git a/activerecord/lib/arel/nodes/case.rb b/activerecord/lib/arel/nodes/case.rb index 22c2da98ddddd..654a54825eb66 100644 --- a/activerecord/lib/arel/nodes/case.rb +++ b/activerecord/lib/arel/nodes/case.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Case < Arel::Nodes::Node attr_accessor :case, :conditions, :default diff --git a/activerecord/lib/arel/nodes/casted.rb b/activerecord/lib/arel/nodes/casted.rb index c701e7ff41f96..c1e6e97d6dc25 100644 --- a/activerecord/lib/arel/nodes/casted.rb +++ b/activerecord/lib/arel/nodes/casted.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Casted < Arel::Nodes::NodeExpression # :nodoc: attr_reader :val, :attribute diff --git a/activerecord/lib/arel/nodes/count.rb b/activerecord/lib/arel/nodes/count.rb index 3f138738efeef..c8e409ea8bf2f 100644 --- a/activerecord/lib/arel/nodes/count.rb +++ b/activerecord/lib/arel/nodes/count.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Count < Arel::Nodes::Function include Math diff --git a/activerecord/lib/arel/nodes/delete_statement.rb b/activerecord/lib/arel/nodes/delete_statement.rb index 1aad4199cd23b..eaac05e2f6cdc 100644 --- a/activerecord/lib/arel/nodes/delete_statement.rb +++ b/activerecord/lib/arel/nodes/delete_statement.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class DeleteStatement < Arel::Nodes::Node attr_accessor :left, :right diff --git a/activerecord/lib/arel/nodes/descending.rb b/activerecord/lib/arel/nodes/descending.rb index afcb6b1b71b44..f3f6992ca88b4 100644 --- a/activerecord/lib/arel/nodes/descending.rb +++ b/activerecord/lib/arel/nodes/descending.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Descending < Ordering def reverse diff --git a/activerecord/lib/arel/nodes/equality.rb b/activerecord/lib/arel/nodes/equality.rb index 4ed545ae172ac..2aa85a977e2d1 100644 --- a/activerecord/lib/arel/nodes/equality.rb +++ b/activerecord/lib/arel/nodes/equality.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Equality < Arel::Nodes::Binary def operator; :== end diff --git a/activerecord/lib/arel/nodes/extract.rb b/activerecord/lib/arel/nodes/extract.rb index 56069cd05a9b0..5799ee9b8ff66 100644 --- a/activerecord/lib/arel/nodes/extract.rb +++ b/activerecord/lib/arel/nodes/extract.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Extract < Arel::Nodes::Unary attr_accessor :field diff --git a/activerecord/lib/arel/nodes/false.rb b/activerecord/lib/arel/nodes/false.rb index 1759a323e381b..1e5bf04be5e54 100644 --- a/activerecord/lib/arel/nodes/false.rb +++ b/activerecord/lib/arel/nodes/false.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class False < Arel::Nodes::NodeExpression def hash diff --git a/activerecord/lib/arel/nodes/full_outer_join.rb b/activerecord/lib/arel/nodes/full_outer_join.rb index 3551855201f33..91bb81f2e343a 100644 --- a/activerecord/lib/arel/nodes/full_outer_join.rb +++ b/activerecord/lib/arel/nodes/full_outer_join.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class FullOuterJoin < Arel::Nodes::Join end diff --git a/activerecord/lib/arel/nodes/function.rb b/activerecord/lib/arel/nodes/function.rb index f3415da12b39d..0a439b39f5cb1 100644 --- a/activerecord/lib/arel/nodes/function.rb +++ b/activerecord/lib/arel/nodes/function.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Function < Arel::Nodes::NodeExpression include Arel::WindowPredications diff --git a/activerecord/lib/arel/nodes/grouping.rb b/activerecord/lib/arel/nodes/grouping.rb index b371b01612d87..4d0bd69d4d971 100644 --- a/activerecord/lib/arel/nodes/grouping.rb +++ b/activerecord/lib/arel/nodes/grouping.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Grouping < Unary end diff --git a/activerecord/lib/arel/nodes/in.rb b/activerecord/lib/arel/nodes/in.rb index 5d24d345288bd..2be45d6f99159 100644 --- a/activerecord/lib/arel/nodes/in.rb +++ b/activerecord/lib/arel/nodes/in.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class In < Equality end diff --git a/activerecord/lib/arel/nodes/infix_operation.rb b/activerecord/lib/arel/nodes/infix_operation.rb index 501da1173078a..bc7e20dcc6a50 100644 --- a/activerecord/lib/arel/nodes/infix_operation.rb +++ b/activerecord/lib/arel/nodes/infix_operation.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class InfixOperation < Binary include Arel::Expressions diff --git a/activerecord/lib/arel/nodes/inner_join.rb b/activerecord/lib/arel/nodes/inner_join.rb index 8af99c2daeab0..519fafad09cb4 100644 --- a/activerecord/lib/arel/nodes/inner_join.rb +++ b/activerecord/lib/arel/nodes/inner_join.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class InnerJoin < Arel::Nodes::Join end diff --git a/activerecord/lib/arel/nodes/insert_statement.rb b/activerecord/lib/arel/nodes/insert_statement.rb index 206d05e74fc0c..d28fd1f6c8d2f 100644 --- a/activerecord/lib/arel/nodes/insert_statement.rb +++ b/activerecord/lib/arel/nodes/insert_statement.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class InsertStatement < Arel::Nodes::Node attr_accessor :relation, :columns, :values, :select diff --git a/activerecord/lib/arel/nodes/join_source.rb b/activerecord/lib/arel/nodes/join_source.rb index 9d009e8081787..abf09446236f6 100644 --- a/activerecord/lib/arel/nodes/join_source.rb +++ b/activerecord/lib/arel/nodes/join_source.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes ### # Class that represents a join source diff --git a/activerecord/lib/arel/nodes/matches.rb b/activerecord/lib/arel/nodes/matches.rb index 607efe86dcdb3..fd5734f4bdbc5 100644 --- a/activerecord/lib/arel/nodes/matches.rb +++ b/activerecord/lib/arel/nodes/matches.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Matches < Binary attr_reader :escape diff --git a/activerecord/lib/arel/nodes/named_function.rb b/activerecord/lib/arel/nodes/named_function.rb index 1d0baf2885c4e..126462d6d68a9 100644 --- a/activerecord/lib/arel/nodes/named_function.rb +++ b/activerecord/lib/arel/nodes/named_function.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class NamedFunction < Arel::Nodes::Function attr_accessor :name diff --git a/activerecord/lib/arel/nodes/node.rb b/activerecord/lib/arel/nodes/node.rb index e2ce0a676d5cd..2b9b1e9828740 100644 --- a/activerecord/lib/arel/nodes/node.rb +++ b/activerecord/lib/arel/nodes/node.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes ### # Abstract base class for all AST nodes diff --git a/activerecord/lib/arel/nodes/node_expression.rb b/activerecord/lib/arel/nodes/node_expression.rb index e69e3262d59e7..cbcfaba37c96a 100644 --- a/activerecord/lib/arel/nodes/node_expression.rb +++ b/activerecord/lib/arel/nodes/node_expression.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class NodeExpression < Arel::Nodes::Node include Arel::Expressions diff --git a/activerecord/lib/arel/nodes/outer_join.rb b/activerecord/lib/arel/nodes/outer_join.rb index 2440be1f03519..0a3042be619fa 100644 --- a/activerecord/lib/arel/nodes/outer_join.rb +++ b/activerecord/lib/arel/nodes/outer_join.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class OuterJoin < Arel::Nodes::Join end diff --git a/activerecord/lib/arel/nodes/over.rb b/activerecord/lib/arel/nodes/over.rb index 57baebe9b3897..91176764a907e 100644 --- a/activerecord/lib/arel/nodes/over.rb +++ b/activerecord/lib/arel/nodes/over.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Over < Binary include Arel::AliasPredication diff --git a/activerecord/lib/arel/nodes/regexp.rb b/activerecord/lib/arel/nodes/regexp.rb index a2da51c135737..7c2509556932c 100644 --- a/activerecord/lib/arel/nodes/regexp.rb +++ b/activerecord/lib/arel/nodes/regexp.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Regexp < Binary attr_accessor :case_sensitive diff --git a/activerecord/lib/arel/nodes/right_outer_join.rb b/activerecord/lib/arel/nodes/right_outer_join.rb index 910eb0fa1fd8b..04ed4aaa7815a 100644 --- a/activerecord/lib/arel/nodes/right_outer_join.rb +++ b/activerecord/lib/arel/nodes/right_outer_join.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class RightOuterJoin < Arel::Nodes::Join end diff --git a/activerecord/lib/arel/nodes/select_core.rb b/activerecord/lib/arel/nodes/select_core.rb index 1686761bd5d3a..2defe6197478d 100644 --- a/activerecord/lib/arel/nodes/select_core.rb +++ b/activerecord/lib/arel/nodes/select_core.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class SelectCore < Arel::Nodes::Node attr_accessor :top, :projections, :wheres, :groups, :windows diff --git a/activerecord/lib/arel/nodes/select_statement.rb b/activerecord/lib/arel/nodes/select_statement.rb index d1c42dba3b826..eff5dad93948b 100644 --- a/activerecord/lib/arel/nodes/select_statement.rb +++ b/activerecord/lib/arel/nodes/select_statement.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class SelectStatement < Arel::Nodes::NodeExpression attr_reader :cores diff --git a/activerecord/lib/arel/nodes/sql_literal.rb b/activerecord/lib/arel/nodes/sql_literal.rb index 1ee496f285c38..d25a8521b7778 100644 --- a/activerecord/lib/arel/nodes/sql_literal.rb +++ b/activerecord/lib/arel/nodes/sql_literal.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class SqlLiteral < String include Arel::Expressions diff --git a/activerecord/lib/arel/nodes/string_join.rb b/activerecord/lib/arel/nodes/string_join.rb index ba3f5f9535451..86027fcab77ba 100644 --- a/activerecord/lib/arel/nodes/string_join.rb +++ b/activerecord/lib/arel/nodes/string_join.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class StringJoin < Arel::Nodes::Join def initialize(left, right = nil) diff --git a/activerecord/lib/arel/nodes/table_alias.rb b/activerecord/lib/arel/nodes/table_alias.rb index 37ad786d44851..f95ca16a3dc94 100644 --- a/activerecord/lib/arel/nodes/table_alias.rb +++ b/activerecord/lib/arel/nodes/table_alias.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class TableAlias < Arel::Nodes::Binary alias :name :right diff --git a/activerecord/lib/arel/nodes/terminal.rb b/activerecord/lib/arel/nodes/terminal.rb index 7cfd2eba4b4fe..d84c453f1afba 100644 --- a/activerecord/lib/arel/nodes/terminal.rb +++ b/activerecord/lib/arel/nodes/terminal.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Distinct < Arel::Nodes::NodeExpression def hash diff --git a/activerecord/lib/arel/nodes/true.rb b/activerecord/lib/arel/nodes/true.rb index 8de1f7522f7f2..c89101296985e 100644 --- a/activerecord/lib/arel/nodes/true.rb +++ b/activerecord/lib/arel/nodes/true.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class True < Arel::Nodes::NodeExpression def hash diff --git a/activerecord/lib/arel/nodes/unary.rb b/activerecord/lib/arel/nodes/unary.rb index 27dd2c1ddf4c0..a3c0045897411 100644 --- a/activerecord/lib/arel/nodes/unary.rb +++ b/activerecord/lib/arel/nodes/unary.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Unary < Arel::Nodes::NodeExpression attr_accessor :expr diff --git a/activerecord/lib/arel/nodes/unary_operation.rb b/activerecord/lib/arel/nodes/unary_operation.rb index a64346d278723..524282ac84af7 100644 --- a/activerecord/lib/arel/nodes/unary_operation.rb +++ b/activerecord/lib/arel/nodes/unary_operation.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class UnaryOperation < Unary attr_reader :operator diff --git a/activerecord/lib/arel/nodes/unqualified_column.rb b/activerecord/lib/arel/nodes/unqualified_column.rb index 216a35bc305d8..7c3e0720d7122 100644 --- a/activerecord/lib/arel/nodes/unqualified_column.rb +++ b/activerecord/lib/arel/nodes/unqualified_column.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class UnqualifiedColumn < Arel::Nodes::Unary alias :attribute :expr diff --git a/activerecord/lib/arel/nodes/update_statement.rb b/activerecord/lib/arel/nodes/update_statement.rb index 5cce1e3615470..5184b1180f96a 100644 --- a/activerecord/lib/arel/nodes/update_statement.rb +++ b/activerecord/lib/arel/nodes/update_statement.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class UpdateStatement < Arel::Nodes::Node attr_accessor :relation, :wheres, :values, :orders, :limit diff --git a/activerecord/lib/arel/nodes/values.rb b/activerecord/lib/arel/nodes/values.rb index 8554440be6bba..650248dc04cc6 100644 --- a/activerecord/lib/arel/nodes/values.rb +++ b/activerecord/lib/arel/nodes/values.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Values < Arel::Nodes::Binary alias :expressions :left diff --git a/activerecord/lib/arel/nodes/values_list.rb b/activerecord/lib/arel/nodes/values_list.rb index e68518d6841f3..27109848e4b1a 100644 --- a/activerecord/lib/arel/nodes/values_list.rb +++ b/activerecord/lib/arel/nodes/values_list.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class ValuesList < Node attr_reader :rows diff --git a/activerecord/lib/arel/nodes/window.rb b/activerecord/lib/arel/nodes/window.rb index 1f14630c81786..4916fc7fbe487 100644 --- a/activerecord/lib/arel/nodes/window.rb +++ b/activerecord/lib/arel/nodes/window.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class Window < Arel::Nodes::Node attr_accessor :orders, :framing, :partitions diff --git a/activerecord/lib/arel/nodes/with.rb b/activerecord/lib/arel/nodes/with.rb index a0fbf87e8e9c7..157bdcaa08bcd 100644 --- a/activerecord/lib/arel/nodes/with.rb +++ b/activerecord/lib/arel/nodes/with.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Nodes class With < Arel::Nodes::Unary alias children expr diff --git a/activerecord/lib/arel/order_predications.rb b/activerecord/lib/arel/order_predications.rb index a0f15cb4d6211..d785bbba92902 100644 --- a/activerecord/lib/arel/order_predications.rb +++ b/activerecord/lib/arel/order_predications.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module OrderPredications def asc Nodes::Ascending.new self diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 1e701586a4bda..e83a6f162f8b1 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Predications def not_eq(other) Nodes::NotEqual.new self, quoted_node(other) diff --git a/activerecord/lib/arel/select_manager.rb b/activerecord/lib/arel/select_manager.rb index dc61447d01c93..22a04b00c65bb 100644 --- a/activerecord/lib/arel/select_manager.rb +++ b/activerecord/lib/arel/select_manager.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class SelectManager < Arel::TreeManager include Arel::Crud diff --git a/activerecord/lib/arel/table.rb b/activerecord/lib/arel/table.rb index 2df2c4c514759..686fcdf962a4d 100644 --- a/activerecord/lib/arel/table.rb +++ b/activerecord/lib/arel/table.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class Table include Arel::Crud include Arel::FactoryMethods diff --git a/activerecord/lib/arel/tree_manager.rb b/activerecord/lib/arel/tree_manager.rb index f6ec1415fa08b..ed47b09a3792f 100644 --- a/activerecord/lib/arel/tree_manager.rb +++ b/activerecord/lib/arel/tree_manager.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class TreeManager include Arel::FactoryMethods diff --git a/activerecord/lib/arel/update_manager.rb b/activerecord/lib/arel/update_manager.rb index 6e36e82cf9a87..fe444343bae1d 100644 --- a/activerecord/lib/arel/update_manager.rb +++ b/activerecord/lib/arel/update_manager.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all class UpdateManager < Arel::TreeManager def initialize super diff --git a/activerecord/lib/arel/visitors.rb b/activerecord/lib/arel/visitors.rb index fb44721117485..e350f52e651c2 100644 --- a/activerecord/lib/arel/visitors.rb +++ b/activerecord/lib/arel/visitors.rb @@ -14,7 +14,7 @@ require "arel/visitors/ibm_db" require "arel/visitors/informix" -module Arel +module Arel # :nodoc: all module Visitors end end diff --git a/activerecord/lib/arel/visitors/depth_first.rb b/activerecord/lib/arel/visitors/depth_first.rb index fb32ef59ade62..bcf8f8f980bad 100644 --- a/activerecord/lib/arel/visitors/depth_first.rb +++ b/activerecord/lib/arel/visitors/depth_first.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class DepthFirst < Arel::Visitors::Visitor def initialize(block = nil) diff --git a/activerecord/lib/arel/visitors/dot.rb b/activerecord/lib/arel/visitors/dot.rb index 2b285ac775819..d352b81914c8a 100644 --- a/activerecord/lib/arel/visitors/dot.rb +++ b/activerecord/lib/arel/visitors/dot.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class Dot < Arel::Visitors::Visitor class Node # :nodoc: diff --git a/activerecord/lib/arel/visitors/ibm_db.rb b/activerecord/lib/arel/visitors/ibm_db.rb index 0291e434c90a8..0a06aef60bfa0 100644 --- a/activerecord/lib/arel/visitors/ibm_db.rb +++ b/activerecord/lib/arel/visitors/ibm_db.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class IBM_DB < Arel::Visitors::ToSql private diff --git a/activerecord/lib/arel/visitors/informix.rb b/activerecord/lib/arel/visitors/informix.rb index 9df5a60bc2c17..0a9713794efbd 100644 --- a/activerecord/lib/arel/visitors/informix.rb +++ b/activerecord/lib/arel/visitors/informix.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class Informix < Arel::Visitors::ToSql private diff --git a/activerecord/lib/arel/visitors/mssql.rb b/activerecord/lib/arel/visitors/mssql.rb index 4f2945e3a4ef9..9aedc51d15c69 100644 --- a/activerecord/lib/arel/visitors/mssql.rb +++ b/activerecord/lib/arel/visitors/mssql.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class MSSQL < Arel::Visitors::ToSql RowNumber = Struct.new :children diff --git a/activerecord/lib/arel/visitors/mysql.rb b/activerecord/lib/arel/visitors/mysql.rb index 7b32988be69d9..37bfb661f052a 100644 --- a/activerecord/lib/arel/visitors/mysql.rb +++ b/activerecord/lib/arel/visitors/mysql.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class MySQL < Arel::Visitors::ToSql private diff --git a/activerecord/lib/arel/visitors/oracle.rb b/activerecord/lib/arel/visitors/oracle.rb index 7811c18a8c8c3..30a1529d46f94 100644 --- a/activerecord/lib/arel/visitors/oracle.rb +++ b/activerecord/lib/arel/visitors/oracle.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class Oracle < Arel::Visitors::ToSql private diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb index e312ba96bb385..7061f0608749f 100644 --- a/activerecord/lib/arel/visitors/oracle12.rb +++ b/activerecord/lib/arel/visitors/oracle12.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class Oracle12 < Arel::Visitors::ToSql private diff --git a/activerecord/lib/arel/visitors/postgresql.rb b/activerecord/lib/arel/visitors/postgresql.rb index e7ed888ed8e4c..108ee431ee64a 100644 --- a/activerecord/lib/arel/visitors/postgresql.rb +++ b/activerecord/lib/arel/visitors/postgresql.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class PostgreSQL < Arel::Visitors::ToSql CUBE = "CUBE" diff --git a/activerecord/lib/arel/visitors/sqlite.rb b/activerecord/lib/arel/visitors/sqlite.rb index 8d4152c428fe3..cb1d2424ad325 100644 --- a/activerecord/lib/arel/visitors/sqlite.rb +++ b/activerecord/lib/arel/visitors/sqlite.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class SQLite < Arel::Visitors::ToSql private diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index 24db04200a9c6..5986fd5576de0 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class UnsupportedVisitError < StandardError def initialize(object) diff --git a/activerecord/lib/arel/visitors/visitor.rb b/activerecord/lib/arel/visitors/visitor.rb index 6cbe5caf8c51e..1c17184e869a6 100644 --- a/activerecord/lib/arel/visitors/visitor.rb +++ b/activerecord/lib/arel/visitors/visitor.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class Visitor def initialize diff --git a/activerecord/lib/arel/visitors/where_sql.rb b/activerecord/lib/arel/visitors/where_sql.rb index d9c87f0130417..c6caf5e7c95db 100644 --- a/activerecord/lib/arel/visitors/where_sql.rb +++ b/activerecord/lib/arel/visitors/where_sql.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module Visitors class WhereSql < Arel::Visitors::ToSql def initialize(inner_visitor, *args, &block) diff --git a/activerecord/lib/arel/window_predications.rb b/activerecord/lib/arel/window_predications.rb index 60d8f05b3cdc6..3a8ee41f8a474 100644 --- a/activerecord/lib/arel/window_predications.rb +++ b/activerecord/lib/arel/window_predications.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Arel +module Arel # :nodoc: all module WindowPredications def over(expr = nil) Nodes::Over.new(self, expr)