lib/dm-core/resource/persistence_state/dirty.rb
module DataMapper
module Resource
class PersistenceState
# a persisted/dirty resource
class Dirty < Persisted
def set(subject, value)
track(subject, value)
super
original_attributes.empty? ? Clean.new(resource) : self
end
def delete
reset_resource
Deleted.new(resource)
end
def commit
remove_from_identity_map
set_child_keys
assert_valid_attributes
update_resource
reset_original_attributes
reset_resource_key
Clean.new(resource)
ensure
add_to_identity_map
end
def rollback
reset_resource
Clean.new(resource)
end
def original_attributes
@original_attributes ||= {}
end
private
def track(subject, value)
if original_attributes.key?(subject)
# stop tracking if the new value is the same as the original
if original_attributes[subject].eql?(value)
original_attributes.delete(subject)
end
elsif !value.eql?(original = get(subject))
# track the original value
original_attributes[subject] = original
end
end
def update_resource
repository.update(resource.dirty_attributes, collection_for_self)
end
def reset_resource
reset_resource_properties
reset_resource_relationships
end
def reset_resource_key
resource.instance_eval { remove_instance_variable(:@_key) }
end
def reset_resource_properties
# delete every original attribute after resetting the resource
original_attributes.delete_if do |property, value|
property.set!(resource, value)
true
end
end
def reset_resource_relationships
relationships.each do |relationship|
next unless relationship.loaded?(resource)
# TODO: consider a method in Relationship that can reset the relationship
resource.instance_eval { remove_instance_variable(relationship.instance_variable_name) }
end
end
def reset_original_attributes
original_attributes.clear
end
def assert_valid_attributes
properties.each do |property|
value = property.get! resource
property.assert_valid_value(value)
end
end
end # class Dirty
end # class PersistenceState
end # module Resource
end # module DataMapper