diff options
author | Nick Kallen <nkallen@nick-kallens-computer-2.local> | 2008-01-21 18:22:55 -0800 |
---|---|---|
committer | Nick Kallen <nkallen@nick-kallens-computer-2.local> | 2008-01-21 18:22:55 -0800 |
commit | d62ace142ce873c72eb916f5a14aa33a67ecfb86 (patch) | |
tree | 049a03b997366e770429c85ced3453bc92c2f3d5 /lib | |
parent | b47ac80a17d7a74e1b5deac0e63a72960a4da453 (diff) | |
download | rails-d62ace142ce873c72eb916f5a14aa33a67ecfb86.tar.gz rails-d62ace142ce873c72eb916f5a14aa33a67ecfb86.tar.bz2 rails-d62ace142ce873c72eb916f5a14aa33a67ecfb86.zip |
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)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/active_relation/primitives/aggregation.rb | 26 | ||||
-rw-r--r-- | lib/active_relation/primitives/attribute.rb | 6 | ||||
-rw-r--r-- | lib/active_relation/relations/alias.rb | 4 | ||||
-rw-r--r-- | lib/active_relation/relations/compound.rb | 2 | ||||
-rw-r--r-- | lib/active_relation/relations/join.rb | 14 | ||||
-rw-r--r-- | lib/active_relation/relations/projection.rb | 12 | ||||
-rw-r--r-- | lib/active_relation/relations/relation.rb | 10 | ||||
-rw-r--r-- | lib/active_relation/relations/rename.rb | 28 | ||||
-rw-r--r-- | lib/active_relation/relations/schmoin.rb | 12 | ||||
-rw-r--r-- | lib/active_relation/relations/table.rb | 2 | ||||
-rw-r--r-- | lib/active_relation/sql.rb | 14 |
11 files changed, 78 insertions, 52 deletions
diff --git a/lib/active_relation/primitives/aggregation.rb b/lib/active_relation/primitives/aggregation.rb index 26348fb35e..51ceee6e66 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 eb167b1a66..3b63bf985b 100644 --- a/lib/active_relation/primitives/attribute.rb +++ b/lib/active_relation/primitives/attribute.rb @@ -18,6 +18,10 @@ module ActiveRelation def qualify self.as(qualified_name) end + + def to_attribute + self + end end include Transformations @@ -26,7 +30,7 @@ module ActiveRelation 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 f40e51475e..701ab189d0 100644 --- a/lib/active_relation/relations/alias.rb +++ b/lib/active_relation/relations/alias.rb @@ -16,10 +16,6 @@ module ActiveRelation 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 bbc7ff1bae..e870f12aff 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 8ccd1e9c6c..b624df8d72 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 @@ module ActiveRelation 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 211e0607ac..9651acd021 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 18ba5491b1..f1febc497c 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -77,9 +77,13 @@ module ActiveRelation 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 @@ module ActiveRelation ("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 @@ module ActiveRelation 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 2977804db1..c9c47f95b8 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 398cfb7b28..6d0cb6f171 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 @@ module ActiveRelation 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 5220087318..637273f949 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -15,6 +15,8 @@ module ActiveRelation 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 89f6193cd8..bc658271c3 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -17,8 +17,8 @@ module ActiveRelation "#{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 @@ module ActiveRelation 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) |