aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorNick Kallen <nkallen@nick-kallens-computer-2.local>2008-01-21 18:22:55 -0800
committerNick Kallen <nkallen@nick-kallens-computer-2.local>2008-01-21 18:22:55 -0800
commitd62ace142ce873c72eb916f5a14aa33a67ecfb86 (patch)
tree049a03b997366e770429c85ced3453bc92c2f3d5 /lib
parentb47ac80a17d7a74e1b5deac0e63a72960a4da453 (diff)
downloadrails-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.rb26
-rw-r--r--lib/active_relation/primitives/attribute.rb6
-rw-r--r--lib/active_relation/relations/alias.rb4
-rw-r--r--lib/active_relation/relations/compound.rb2
-rw-r--r--lib/active_relation/relations/join.rb14
-rw-r--r--lib/active_relation/relations/projection.rb12
-rw-r--r--lib/active_relation/relations/relation.rb10
-rw-r--r--lib/active_relation/relations/rename.rb28
-rw-r--r--lib/active_relation/relations/schmoin.rb12
-rw-r--r--lib/active_relation/relations/table.rb2
-rw-r--r--lib/active_relation/sql.rb14
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)