Created
May 24, 2009 05:00
-
-
Save snusnu/116962 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "rubygems" | |
require "spec" | |
require "dm-core" | |
require "dm-validations" | |
require "dm-constraints" | |
DataMapper::Logger.new(STDOUT, :debug) | |
ENV["SQLITE3_SPEC_URI"] ||= 'sqlite3::memory:' | |
ENV["MYSQL_SPEC_URI"] ||= 'mysql://localhost/dm-association_validation_test' | |
ENV["POSTGRES_SPEC_URI"] ||= 'postgres://postgres@localhost/dm-association_validation_test' | |
def setup_adapter(name, default_uri = nil) | |
begin | |
DataMapper.setup(name, ENV["#{ENV['ADAPTER'].to_s.upcase}_SPEC_URI"] || default_uri) | |
Object.const_set('ADAPTER', ENV['ADAPTER'].to_sym) if name.to_s == ENV['ADAPTER'] | |
true | |
rescue Exception => e | |
if name.to_s == ENV['ADAPTER'] | |
Object.const_set('ADAPTER', nil) | |
warn "Could not load do_#{name}: #{e}" | |
end | |
false | |
end | |
end | |
ENV['ADAPTER'] ||= 'mysql' | |
setup_adapter(:default) | |
module DataMapper | |
module NestedAttributes | |
module AssociationPersistence | |
extend Chainable | |
# chainable do | |
# | |
# def save(*args) | |
# if (roots = initialize_paths_to_self).any? | |
# roots.all? { |r| r.save(*args) } | |
# else | |
# super | |
# end | |
# end | |
# | |
# end | |
# private | |
# # walks the parent relationships up to their root and initializes | |
# # the inverse relationship to the correct resource on its way up | |
# # returns an array of all root resources | |
# def initialize_paths_to_self | |
# parent_relationships.map { |r| initialize_path_to_self(r) } | |
# end | |
# | |
# # initialize the inverse in order to have it loaded as child association. | |
# # necessary for the target resource to save it as a loaded child association. | |
# # returns the root of this path (the topmost resource from which self is accessible) | |
# def initialize_path_to_self(relationship, resource = self) | |
# relationship.inverse.set(resource.send(relationship.name), resource) | |
# target = relationship.get!(resource) | |
# target.parent_relationships.each do |r| | |
# target = initialize_path_to_self(r, target) | |
# end | |
# target | |
# end | |
chainable do | |
def save(*args) | |
unless parent_associations.all? { |a| a.save(*args) } | |
return false | |
end | |
super(nil) | |
end | |
end | |
def parent_relationships | |
parent_relationships = [] | |
relationships.each_value do |r| | |
if r.kind_of?(Associations::ManyToOne::Relationship) && r.loaded?(self) | |
parent_relationships << r | |
end | |
end | |
parent_relationships | |
end | |
def parent_associations | |
parent_relationships.map do |r| | |
parent = r.get!(self) | |
r.inverse.send(:lazy_load, parent) | |
r.inverse.get!(parent).replace([ self ]) | |
parent | |
end | |
end | |
end | |
end | |
end | |
DataMapper::Model.append_inclusions(DataMapper::NestedAttributes::AssociationPersistence) | |
class Person | |
include DataMapper::Resource | |
property :id, Serial | |
property :name, String, :nullable => false | |
has 1, :profile | |
end | |
class Profile | |
include DataMapper::Resource | |
property :id, Serial | |
property :person_id, Integer, :nullable => false | |
property :nickname, String, :nullable => false | |
belongs_to :person | |
end | |
# describe "Resource#initialize_path_to_self" do | |
# | |
# before :each do | |
# [ Person, Profile ].each { |model| model.auto_migrate! } | |
# end | |
# | |
# it "should return the root resource" do | |
# p = Profile.new(:nickname => 'snusnu') | |
# p.person = Person.new(:name => 'Martin') | |
# r = p.class.relationships[:person] | |
# p.initialize_path_to_self(r, p).should == p.person | |
# end | |
# | |
# it "should initialize the inverse relationship" do | |
# Profile.all.size.should == 0 | |
# Person.all.size.should == 0 | |
# | |
# p = Profile.new(:nickname => 'snusnu') | |
# p.person = Person.new(:name => 'Martin') | |
# r = p.class.relationships[:person] | |
# p.person.profile.should be_nil | |
# p.initialize_path_to_self(r, p) | |
# p.person.profile.should == p | |
# | |
# p.person.save.should be_true | |
# | |
# Person.all.size.should == 1 | |
# Profile.all.size.should == 1 | |
# end | |
# | |
# end | |
# | |
# describe "Resource#initialize_paths_to_self" do | |
# | |
# before :each do | |
# [ Person, Profile ].each { |model| model.auto_migrate! } | |
# end | |
# | |
# it "should return all roots for a resource" do | |
# p = Profile.new(:nickname => 'snusnu') | |
# p.person = Person.new(:name => 'Martin') | |
# p.initialize_paths_to_self.should == [ p.person ] | |
# end | |
# | |
# end | |
describe "DataMapper::NestedAttributes::AssociationPersistence#save" do | |
before :each do | |
[ Person, Profile ].each { |model| model.auto_migrate! } | |
end | |
it "should save a many_to_one target resource before saving self" do | |
Profile.all.size.should == 0 | |
Person.all.size.should == 0 | |
p = Profile.new(:nickname => 'snusnu') | |
p.person = Person.new(:name => 'Martin') | |
Profile.all.size.should == 0 | |
Person.all.size.should == 0 | |
p.save.should be_true | |
Person.all.size.should == 1 | |
Profile.all.size.should == 1 | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment