module Dynamoid::Persistence

Persistence is responsible for dumping objects to and marshalling objects from the datastore. It tries to reserialize values to be of the same type as when they were passed in, based on the fields in the class.

Attributes

new_record[RW]
new_record?[RW]

Public Instance Methods

delete() click to toggle source

Delete this object from the datastore and all indexes.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 211
def delete
  delete_indexes
  options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
  Dynamoid::Adapter.delete(self.class.table_name, self.hash_key, options)
end
destroy() click to toggle source

Delete this object, but only after running callbacks for it.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 201
def destroy
  run_callbacks(:destroy) do
    self.delete
  end
  self
end
dump() click to toggle source

Dump this object’s attributes into hash form, fit to be persisted into the datastore.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 220
def dump
  Hash.new.tap do |hash|
    self.class.attributes.each do |attribute, options|
      hash[attribute] = dump_field(self.read_attribute(attribute), options)
    end
  end
end
persisted?() click to toggle source

Is this object persisted in the datastore? Required for some ActiveModel integration stuff.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 149
def persisted?
  !new_record?
end
save(options = {}) click to toggle source

Run the callbacks and then persist this object in the datastore.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 156
def save(options = {})
  self.class.create_table
  
  if new_record?
    conditions = { :unless_exists => [self.class.hash_key]}
    conditions[:unless_exists] << range_key if(range_key)

    run_callbacks(:create) { persist(conditions) }
  else
    persist
  end

  self
end
touch(name = nil) click to toggle source

Set updated_at and any passed in field to current DateTime. Useful for things like last_login_at, etc.

# File lib/dynamoid/persistence.rb, line 139
def touch(name = nil)
  now = DateTime.now
  self.updated_at = now
  attributes[name] = now if name
  save
end
update(conditions = {}, &block) click to toggle source
# File lib/dynamoid/persistence.rb, line 191
def update(conditions = {}, &block)
  update!(conditions, &block)
  true
rescue Dynamoid::Errors::ConditionalCheckFailedException
  false
end
update!(conditions = {}) { |t| ... } click to toggle source

update!() will increment the lock_version if the table has the column, but will not check it. Thus, a concurrent save will never cause an update! to fail, but an update! may cause a concurrent save to fail.

# File lib/dynamoid/persistence.rb, line 176
def update!(conditions = {}, &block)
  run_callbacks(:update) do
    options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
    new_attrs = Dynamoid::Adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions)) do |t|
      if(self.class.attributes[:lock_version])
        raise "Optimistic locking cannot be used with Partitioning" if(Dynamoid::Config.partitioning)
        t.add(lock_version: 1)
      end

      yield t
    end
    load(new_attrs)
  end
end

Private Instance Methods

dump_field(value, options) click to toggle source

Determine how to dump this field. Given a value, it’ll determine how to turn it into a value that can be persisted into the datastore.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 234
def dump_field(value, options)
  return if value.nil? || (value.respond_to?(:empty?) && value.empty?)

  case options[:type]
  when :string
    value.to_s
  when :integer
    value.to_i
  when :float
    value.to_f
  when :set, :array
    if value.is_a?(Set) || value.is_a?(Array)
      value
    else
      Set[value]
    end
  when :datetime
    value.to_time.to_f
  when :serialized
    options[:serializer] ? options[:serializer].dump(value) : value.to_yaml
  when :boolean
    value.to_s[0]
  else
    raise ArgumentError, "Unknown type #{options[:type]}"
  end
end
persist(conditions = nil) click to toggle source

Persist the object into the datastore. Assign it an id first if it doesn’t have one; then afterwards, save its indexes.

@since 0.2.0

# File lib/dynamoid/persistence.rb, line 265
def persist(conditions = nil)
  run_callbacks(:save) do
    self.hash_key = SecureRandom.uuid if self.hash_key.nil? || self.hash_key.blank?
    
    # Add an exists check to prevent overwriting existing records with new ones
    if(new_record?)
      conditions ||= {}
      (conditions[:unless_exists] ||= []) << self.class.hash_key
    end

    # Add an optimistic locking check if the lock_version column exists
    if(self.class.attributes[:lock_version])
      conditions ||= {}
      raise "Optimistic locking cannot be used with Partitioning" if(Dynamoid::Config.partitioning)
      self.lock_version = (lock_version || 0) + 1 
      #Uses the original lock_version value from ActiveModel::Dirty in case user changed lock_version manually
      (conditions[:if] ||= {})[:lock_version] = changes[:lock_version][0] if(changes[:lock_version][0])
    end

    Dynamoid::Adapter.write(self.class.table_name, self.dump, conditions)
    save_indexes
    @new_record = false
    true
  end
end