Skip to content

Instantly share code, notes, and snippets.

@snusnu
Created May 24, 2009 05:00
Show Gist options
  • Save snusnu/116962 to your computer and use it in GitHub Desktop.
Save snusnu/116962 to your computer and use it in GitHub Desktop.
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