diff --git a/doc/TODO b/doc/TODO index f959964652..752579d229 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 f4d6b199b5..735f586114 100644 --- a/lib/arel/relations/compound.rb +++ b/lib/arel/relations/compound.rb @@ -6,7 +6,7 @@ module Arel 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 1fb0055caa..cb24ab7717 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 @@ module Arel 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 @@ module Arel 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 @@ module Arel @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 @@ module Arel 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 @@ module Arel 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 02fc1c6284..7b414b9768 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -115,10 +115,11 @@ module Arel 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 34a730c5f3..7a620009db 100644 --- a/lib/arel/sql.rb +++ b/lib/arel/sql.rb @@ -68,6 +68,7 @@ module Arel 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 c08ff68f36..0c2d1d771d 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` ")