require 'massive_record/orm/persistence/operations' module MassiveRecord module ORM module Persistence extend ActiveSupport::Concern module ClassMethods def create(*args) new(*args).tap do |record| record.save end end def destroy_all all.each { |record| record.destroy } end end def new_record? @new_record end def persisted? !(new_record? || destroyed?) end def destroyed? @destroyed end def reload Operations.reload(self).execute self end def save(*) create_or_update end def save!(*) create_or_update or raise RecordNotSaved end def update_attribute(attr_name, value) self[attr_name] = value save(:validate => false) end def update_attributes(attributes) self.attributes = attributes save end def update_attributes!(attributes) self.attributes = attributes save! end # TODO This actually does nothing atm, but it's here and callbacks on it # is working. def touch true end def destroy @destroyed = (persisted? ? do_destroy : true) and freeze end alias_method :delete, :destroy def change_id!(new_id) old_id, self.id = id, new_id @new_record = true unless save raise <<-TXT Unable to save #{self.class} with updated id '#{new_id}'. Old id '#{old_id}' was not deleted so in theory nothing should be changed in the database. TXT end unless self.class.find(old_id).destroy raise <<-TXT Unable to destroy #{self.class} with id '#{old_id}'. You now how duplicate records in the database. New id is: '#{new_id}.' TXT end reload end def increment(attr_name, by = 1) raise NotNumericalFieldError unless attributes_schema[attr_name.to_s].type == :integer self[attr_name] ||= 0 self[attr_name] += by self end def increment!(attr_name, by = 1) increment(attr_name, by).update_attribute(attr_name, self[attr_name]) end def atomic_increment!(attr_name, by = 1) atomic_operation(:increment, attr_name, by) end def decrement(attr_name, by = 1) raise NotNumericalFieldError unless attributes_schema[attr_name.to_s].type == :integer self[attr_name] ||= 0 self[attr_name] -= by self end def decrement!(attr_name, by = 1) decrement(attr_name, by).update_attribute(attr_name, self[attr_name]) end def atomic_decrement!(attr_name, by = 1) atomic_operation(:decrement, attr_name, by) end private def create_or_update raise ReadOnlyRecord if readonly? !!(new_record? ? create : update) end def create Operations.insert(self).execute.tap do |saved| @new_record = false if saved end end def update(attribute_names_to_update = attributes_with_embedded) Operations.update(self, :attribute_names_to_update => attribute_names_to_update).execute end def do_destroy Operations.destroy(self).execute end # # Atomic decrement of an attribute. Please note that it's the # adapter (or the wrapper) which needs to guarantee that the update # is atomic. Thrift adapter is working with atomic decrementation. # def atomic_operation(operation, attr_name, by) Operations.atomic_operation(self, :operation => operation, :attr_name => attr_name, :by => by).execute end # # Gives you all attribute names pluss all known embedded # attributes names. Is used if dirty is active. # def attributes_with_embedded attributes.keys | relation_proxies_for_embedded.collect { |proxy| proxy.metadata.name } end end end end