Skip to content

Commit

Permalink
Collection can now delegate to the model method, with scope
Browse files Browse the repository at this point in the history
* This allows a Collection to delegate to a model's method with the
  proper level of scope.  This should also allow chaining of model
  methods that return Collection objects, as well as using model
  methods that return a Resource with the correct scope.
  • Loading branch information
Dan Kubb committed Jul 11, 2008
1 parent af5c773 commit 618bfd3
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 46 deletions.
30 changes: 24 additions & 6 deletions lib/dm-core/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,26 @@ def default_attributes
default_attributes
end

##
# check to see if collection can respond to the method
#
# @param method [Symbol] method to check in the object
# @param include_private [FalseClass, TrueClass] if set to true,
# collection will check private methods
#
# @return [TrueClass, FalseClass]
# TrueClass indicates the method can be responded to by the collection
# FalseClass indicates the method can not be responded to by the collection
#
# @api public
def respond_to?(method, include_private = false)
super || model.respond_to?(method, include_private) || relationships.has_key?(method)
end

protected

##
# @api private
#
# @api public
def model
query.model
end
Expand Down Expand Up @@ -594,7 +608,11 @@ def set_relative_position(query)
##
# @api private
def method_missing(method, *args, &block)
if relationship = relationships[method]
if model.respond_to?(method)
model.send(:with_scope, query) do
model.send(method, *args, &block)
end
elsif relationship = relationships[method]
klass = model == relationship.child_model ? relationship.parent_model : relationship.child_model

# TODO: when self.query includes an offset/limit use it as a
Expand All @@ -610,10 +628,10 @@ def method_missing(method, *args, &block)
:links => self.query.links + [ relationship ]
)

return klass.all(query, &block)
klass.all(query, &block)
else
super
end

super
end
end # class Collection
end # module DataMapper
87 changes: 47 additions & 40 deletions spec/integration/collection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def self.default_repository_name
property :zebra_id, Integer

belongs_to :zebra

def self.sort_by_name
all(:order => [ :name ])
end
end

class CollectionSpecParty
Expand Down Expand Up @@ -71,46 +75,6 @@ def setup
end
end

describe 'association proxying' do
include CollectionSpecHelper

before do
setup
end

it "should provide a Query" do
repository(ADAPTER) do
zebras = Zebra.all(:order => [ :name ])
zebras.query.order.should == [DataMapper::Query::Direction.new(Zebra.properties(ADAPTER)[:name])]
end
end

it "should proxy the relationships of the model" do
repository(ADAPTER) do
zebras = Zebra.all
zebras.should have(3).entries
zebras.find { |zebra| zebra.name == 'Nancy' }.stripes.should have(2).entries
zebras.stripes.should == [@babe, @snowball]
end
end

it "should preserve it's order on reload" do
repository(ADAPTER) do |r|
zebras = Zebra.all(:order => [ :name ])

order = %w{ Bessie Nancy Steve }

zebras.map { |z| z.name }.should == order

# Force a lazy-load call:
zebras.first.notes

# The order should be unaffected.
zebras.map { |z| z.name }.should == order
end
end
end

describe DataMapper::Collection do
include CollectionSpecHelper

Expand Down Expand Up @@ -163,6 +127,49 @@ def setup
results.first.should == bob
end

describe 'model proxying' do
it 'should delegate to a model method' do
stripes = @model.first.stripes
stripes.should respond_to(:sort_by_name)
stripes.sort_by_name.should == [ @babe, @snowball ]
end
end

describe 'association proxying' do
it "should provide a Query" do
repository(ADAPTER) do
zebras = Zebra.all(:order => [ :name ])
zebras.query.order.should == [DataMapper::Query::Direction.new(Zebra.properties(ADAPTER)[:name])]
end
end

it "should proxy the relationships of the model" do
repository(ADAPTER) do
zebras = Zebra.all
zebras.should have(3).entries
zebras.find { |zebra| zebra.name == 'Nancy' }.stripes.should have(2).entries
zebras.should respond_to(:stripes)
zebras.stripes.should == [@babe, @snowball]
end
end

it "should preserve it's order on reload" do
repository(ADAPTER) do |r|
zebras = Zebra.all(:order => [ :name ])

order = %w{ Bessie Nancy Steve }

zebras.map { |z| z.name }.should == order

# Force a lazy-load call:
zebras.first.notes

# The order should be unaffected.
zebras.map { |z| z.name }.should == order
end
end
end

describe '.new' do
describe 'with non-index keys' do
it 'should instantiate read-only resources' do
Expand Down

0 comments on commit 618bfd3

Please sign in to comment.