diff options
author | Nick Kallen <nkallen@nick-kallens-computer-2.local> | 2008-02-24 22:19:32 -0800 |
---|---|---|
committer | Nick Kallen <nkallen@nick-kallens-computer-2.local> | 2008-02-24 22:19:32 -0800 |
commit | 92db013ba3ee4d0a9d92281e614d05f064c22e15 (patch) | |
tree | 23585e771ee1a2b1682f66a67d6b6891fab49f24 | |
parent | ecd072d21951573f59e9515b868224d3732dbdfa (diff) | |
download | rails-92db013ba3ee4d0a9d92281e614d05f064c22e15.tar.gz rails-92db013ba3ee4d0a9d92281e614d05f064c22e15.tar.bz2 rails-92db013ba3ee4d0a9d92281e614d05f064c22e15.zip |
quoting issues
-rw-r--r-- | lib/active_relation/extensions.rb | 1 | ||||
-rw-r--r-- | lib/active_relation/extensions/base.rb | 48 | ||||
-rw-r--r-- | lib/active_relation/extensions/object.rb | 6 | ||||
-rw-r--r-- | lib/active_relation/predicates.rb | 5 | ||||
-rw-r--r-- | lib/active_relation/primitives/attribute.rb | 18 | ||||
-rw-r--r-- | lib/active_relation/primitives/expression.rb | 2 | ||||
-rw-r--r-- | lib/active_relation/relations/compound.rb | 2 | ||||
-rw-r--r-- | lib/active_relation/relations/join.rb | 2 | ||||
-rw-r--r-- | lib/active_relation/relations/relation.rb | 4 | ||||
-rw-r--r-- | lib/active_relation/relations/table.rb | 17 | ||||
-rw-r--r-- | lib/active_relation/sql.rb | 23 | ||||
-rw-r--r-- | spec/active_relation/integration/scratch_spec.rb | 252 | ||||
-rw-r--r-- | spec/active_relation/unit/predicates/binary_spec.rb | 3 | ||||
-rw-r--r-- | spec/active_relation/unit/predicates/equality_spec.rb | 8 | ||||
-rw-r--r-- | spec/active_relation/unit/primitives/attribute_spec.rb | 41 | ||||
-rw-r--r-- | spec/active_relation/unit/primitives/expression_spec.rb | 2 | ||||
-rw-r--r-- | spec/active_relation/unit/relations/table_spec.rb | 8 |
17 files changed, 93 insertions, 349 deletions
diff --git a/lib/active_relation/extensions.rb b/lib/active_relation/extensions.rb index 3751088483..8a024947ed 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 c1b823f9a7..0000000000 --- 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 35ffa9c661..0cc87bf262 100644 --- a/lib/active_relation/extensions/object.rb +++ b/lib/active_relation/extensions/object.rb @@ -7,7 +7,11 @@ class Object 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 7d0618f42e..2a36e65042 100644 --- a/lib/active_relation/predicates.rb +++ b/lib/active_relation/predicates.rb @@ -6,7 +6,6 @@ module ActiveRelation end class Binary < Predicate - # rename "operand21", "operand22" attr_reader :operand1, :operand2 def initialize(operand1, operand2) @@ -25,8 +24,8 @@ module ActiveRelation 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 e55dd0bdc4..75f19605c7 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 @@ module ActiveRelation 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 @@ module ActiveRelation def qualified_name "#{prefix}.#{name}" end + + def column + relation.column_for(self) + end def ==(other) self.class == other.class and @@ -112,10 +116,14 @@ module ActiveRelation 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 35c1b5ff65..11aa558977 100644 --- a/lib/active_relation/primitives/expression.rb +++ b/lib/active_relation/primitives/expression.rb @@ -20,7 +20,7 @@ module ActiveRelation 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 094c6e29dd..115315a76a 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 70c85bb1e0..8e0dcb2a4b 100644 --- a/lib/active_relation/relations/join.rb +++ b/lib/active_relation/relations/join.rb @@ -38,7 +38,7 @@ module ActiveRelation 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 1d5e194923..7536390aca 100644 --- a/lib/active_relation/relations/relation.rb +++ b/lib/active_relation/relations/relation.rb @@ -104,12 +104,12 @@ module ActiveRelation 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 d0fc2b2475..5720be30e3 100644 --- a/lib/active_relation/relations/table.rb +++ b/lib/active_relation/relations/table.rb @@ -3,11 +3,11 @@ module ActiveRelation 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 @@ module ActiveRelation 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 85bcb4107b..49ced3cbaa 100644 --- a/lib/active_relation/sql.rb +++ b/lib/active_relation/sql.rb @@ -27,8 +27,8 @@ module ActiveRelation "#{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 @@ module ActiveRelation 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 @@ module ActiveRelation 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 d6ec030518..0000000000 --- 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 44c1a1a7a0..1f6656b9d1 100644 --- a/spec/active_relation/unit/predicates/binary_spec.rb +++ b/spec/active_relation/unit/predicates/binary_spec.rb @@ -53,6 +53,9 @@ module ActiveRelation `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 fd30846c70..499b13383d 100644 --- a/spec/active_relation/unit/predicates/equality_spec.rb +++ b/spec/active_relation/unit/predicates/equality_spec.rb @@ -3,10 +3,10 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') 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 e5a3792d85..8b4f52c432 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 5506f52b86..dda35157b0 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 3b02f80701..f8d4431aa7 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 |