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