diff options
author | Nick Kallen <nkallen@nick-kallens-computer-2.local> | 2008-03-02 21:10:35 -0800 |
---|---|---|
committer | Nick Kallen <nkallen@nick-kallens-computer-2.local> | 2008-03-02 21:10:35 -0800 |
commit | 6647a1e08eb9dc3512628882bcf60d421df74228 (patch) | |
tree | 204eebc8e9c6e6711331706dbd14815164db2eda | |
parent | c54392872f024d55e8a23ead3065e6119a52b234 (diff) | |
download | rails-6647a1e08eb9dc3512628882bcf60d421df74228.tar.gz rails-6647a1e08eb9dc3512628882bcf60d421df74228.tar.bz2 rails-6647a1e08eb9dc3512628882bcf60d421df74228.zip |
scalars are now lifted; the heavy lifting is done by the operations on relation (select, join, etc.)
21 files changed, 100 insertions, 75 deletions
diff --git a/lib/active_relation/extensions/array.rb b/lib/active_relation/extensions/array.rb index 5b6d6d6abd..aa4354a78a 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 72b3bf0c15..0000000000 --- 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 50864912bf..a33ace5738 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 b0c7ada999..d13cf9aabb 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 ddc6eab02b..ba926a86e5 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -84,7 +84,7 @@ module ActiveRelation 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 2ac157297e..7629256034 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 0000000000..fa88404ee3 --- /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 dd5b8ec530..16fe3d5f46 100644 --- a/lib/active_relation/relations/insertion.rb +++ b/lib/active_relation/relations/insertion.rb @@ -11,7 +11,7 @@ module ActiveRelation "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 e6395aecd7..6949b3acf7 100644 --- a/lib/active_relation/relations/order.rb +++ b/lib/active_relation/relations/order.rb @@ -7,8 +7,9 @@ module ActiveRelation 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 3d4ff6613c..1c97cc7035 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -42,11 +42,11 @@ module ActiveRelation 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 @@ module ActiveRelation 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 @@ module ActiveRelation 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 @@ module ActiveRelation 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 @@ module ActiveRelation 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 9a0e5552c7..ac5484bfff 100644 --- a/lib/active_relation/relations/rename.rb +++ b/lib/active_relation/relations/rename.rb @@ -15,7 +15,7 @@ module ActiveRelation end def attributes - relation.attributes.collect(&method(:baptize)) + relation.attributes.collect(&method(:christen)) end def descend(&block) @@ -23,7 +23,7 @@ module ActiveRelation 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 8909ee80a0..c50919af3e 100644 --- a/lib/active_relation/relations/update.rb +++ b/lib/active_relation/relations/update.rb @@ -9,7 +9,9 @@ module ActiveRelation 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 a5701ca8cd..99cfc66383 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -20,7 +20,7 @@ module ActiveRelation 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 f6466d9105..677d8f3ab4 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -55,7 +55,7 @@ module ActiveRelation 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 0ac7ccb6e2..af5846b747 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 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') 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 b2b239097a..91bf7773c1 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 64d41effc5..a424239c4b 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 3af3b8aa9c..8f35760801 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 3a18d4ae6e..d5e0c6a9f6 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 2cd3eb9d11..cad14fd5ec 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 1ac69976b5..89d96ef323 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 |