Permalink
Browse files

Fixed Collection to work with has() and belongs() associations

* Allows you to go: collection.parents or collection.children and it
  will return a Collection with the appropriate resources
  • Loading branch information...
1 parent 29054e7 commit da9f161d8c9174c8a1d10a6df302037b26705696 Dan Kubb committed Nov 27, 2008
@@ -71,6 +71,11 @@ def self.many_to_many; true end
Object.const_set(model_name, model)
end
+ # FIXME: temporary until the Relationship.new API is refactored to
+ # accept type as the first argument, and RelationshipChain has been
+ # removed
+ relationship.type = self
+
relationship
end
@@ -32,13 +32,20 @@ def #{name}_relationship
end
EOS
- model.relationships(repository_name)[name] = Relationship.new(
+ relationship = model.relationships(repository_name)[name] = Relationship.new(
name,
repository_name,
model,
options[:class_name] || Extlib::Inflection.classify(name),
options
)
+
+ # FIXME: temporary until the Relationship.new API is refactored to
+ # accept type as the first argument, and RelationshipChain has been
+ # removed
+ relationship.type = self
+
+ relationship
end
end # module ManyToOne
end # module Associations
@@ -34,7 +34,7 @@ def #{name}_association
end
EOS
- model.relationships(repository_name)[name] = if options.has_key?(:through)
+ relationship = model.relationships(repository_name)[name] = if options.has_key?(:through)
opts = options.dup
if opts.key?(:class_name) && !opts.key?(:child_key)
@@ -61,6 +61,13 @@ def #{name}_association
options
)
end
+
+ # FIXME: temporary until the Relationship.new API is refactored to
+ # accept type as the first argument, and RelationshipChain has been
+ # removed
+ relationship.type = self
+
+ relationship
end
# TODO: look at making this inherit from Collection. The API is
@@ -34,7 +34,7 @@ def #{name}_association
end
EOS
- model.relationships(repository_name)[name] = if options.has_key?(:through)
+ relationship = model.relationships(repository_name)[name] = if options.has_key?(:through)
RelationshipChain.new(
:child_model => options.fetch(:class_name, Extlib::Inflection.classify(name)),
:parent_model => model,
@@ -53,6 +53,13 @@ def #{name}_association
options
)
end
+
+ # FIXME: temporary until the Relationship.new API is refactored to
+ # accept type as the first argument, and RelationshipChain has been
+ # removed
+ relationship.type = self
+
+ relationship
end
end # module HasOne
end # module Associations
@@ -7,6 +7,7 @@ class Relationship
# @api private
attr_reader :name, :options, :query
+ attr_accessor :type
# @api private
def child_key
View
@@ -107,7 +107,7 @@ def get(*key)
if resource = @cache[key]
# find cached resource
resource
- elsif query.limit || query.offset > 0
+ elsif !loaded? && (query.limit || query.offset > 0)
# current query is exclusive, find resource within the set
# TODO: use a subquery to retrieve the Collection and then match
@@ -120,7 +120,7 @@ def get(*key)
# use the brute force approach until subquery lookups work
lazy_load
- get(*key)
+ @cache[key]
else
# current query is all inclusive, lookup using normal approach
first(model.key(repository.name).zip(key).to_hash)
@@ -1135,25 +1135,31 @@ def delegate_to_model(method, *args, &block)
# @return [DataMapper::Collection] the associated Resources
#
def delegate_to_relationship(relationship, *args)
- target_class = model == relationship.child_model ? relationship.parent_model : relationship.child_model
- target_key = model == relationship.child_model ? relationship.child_key : relationship.parent_key
+ target_class, target_key, source_key = nil, nil, nil
+
+ if relationship.type == Associations::ManyToOne
+ target_class = relationship.parent_model
+ target_key = relationship.parent_key
+ source_key = relationship.child_key
+ else
+ target_class = relationship.child_model
+ target_key = relationship.child_key
+ source_key = relationship.parent_key
+ end
# TODO: when self.query includes an offset/limit use it as a
# subquery to scope the results rather than a join
- keys = map { |r| r.key }
- query = Query.new(repository, target_class, target_key.zip(keys.transpose).to_hash)
+ values = map { |r| source_key.get(r) }
+ query = Query.new(repository, target_class, target_key.zip(values.transpose).to_hash)
query.update(relationship.query)
if args.last.kind_of?(Hash)
query.update(args.pop)
end
- query.update(
- :fields => target_class.properties(repository.name).defaults,
- :links => [ relationship ] + self.query.links
- )
+ query.update(:links => [ relationship ] + self.query.links)
target_class.all(query)
end
@@ -16,6 +16,11 @@ class Author
property :name, String
has n, :articles, :through => Resource
+
+ # TODO: move conditions down to before block once author.articles(query)
+ # returns a OneToMany::Proxy object (and not Collection as it does now)
+ has n, :sample_articles, :title.eql => 'Sample Article', :class_name => 'Article', :through => Resource
+ has n, :other_articles, :title => 'Other Article', :class_name => 'Article', :through => Resource
end
class Article
@@ -29,24 +34,27 @@ class Article
belongs_to :original, :class_name => 'Article'
has n, :revisions, :class_name => 'Article'
end
+
+ @model = Article
end
supported_by :all do
before do
- @article_repository = repository(:default)
- @model = Article
+ @author1 = Author.create(:name => 'Dan Kubb')
+ @author2 = Author.create(:name => 'Lawrence Pit')
- @article = @model.create(:title => 'Sample Article', :content => 'Sample')
- @other = @model.create(:title => 'Other Article', :content => 'Other')
-
- @author1 = Author.create(:name => 'Dan Kubb')
- @author2 = Author.create(:name => 'Lawrence Pit')
+ @original = @model.create(:title => 'Original Article')
+ @article = @model.create(:title => 'Sample Article', :content => 'Sample', :original => @original)
+ @other = @model.create(:title => 'Other Article', :content => 'Other')
#ArticleAuthor.create(:article_id => @article.id, :author_id => @author1.id)
- @author1.articles << @article
+ #ArticleAuthor.create(:article_id => @other.id, :author_id => @author1.id)
+
+ @author1.sample_articles << @article
+ @author1.other_articles << @other
- @articles = @author1.articles
- @other_articles = [@other]
+ @articles = @author1.sample_articles
+ @other_articles = @author1.other_articles
end
it_should_behave_like 'A public Collection'
@@ -52,16 +52,17 @@ class Article
belongs_to :original, :class_name => 'Article'
has n, :revisions, :class_name => 'Article'
end
+
+ @model = Article
end
supported_by :all do
before do
- @article_repository = repository(:default)
- @model = Article
-
@author = Author.create(:name => 'Dan Kubb')
- @article = @model.create(:title => 'Sample Article', :content => 'Sample', :author => @author)
- @other = @model.create(:title => 'Other Article', :content => 'Other', :author => @author)
+
+ @original = @model.create(:title => 'Original Article')
+ @article = @model.create(:title => 'Sample Article', :content => 'Sample', :author => @author, :original => @original)
+ @other = @model.create(:title => 'Other Article', :content => 'Other', :author => @author)
@articles = @author.sample_articles
@other_articles = @author.other_articles
@@ -18,18 +18,17 @@ class Article
belongs_to :original, :class_name => 'Article'
has n, :revisions, :class_name => 'Article'
end
+
+ @model = Article
end
supported_by :all do
before do
- @article_repository = repository(:default)
- @model = Article
- @articles_query = DataMapper::Query.new(@article_repository, @model, :title => 'Sample Article')
-
- @article = @model.create(:title => 'Sample Article', :content => 'Sample')
- @other = @model.create(:title => 'Other Article', :content => 'Other')
+ @original = @model.create(:title => 'Original Article')
+ @article = @model.create(:title => 'Sample Article', :content => 'Sample', :original => @original)
+ @other = @model.create(:title => 'Other Article', :content => 'Other')
- @articles = @model.all(@articles_query)
+ @articles = @model.all(:title => 'Sample Article')
@other_articles = @model.all(:title => 'Other Article')
@articles.entries if loaded
Oops, something went wrong.

0 comments on commit da9f161

Please sign in to comment.