module Cequel::Record::Persistence

This module provides functionality for loading and saving records to the Cassandra database.

@see ClassMethods

@since 0.1.0

Public Instance Methods

deleter() click to toggle source
# File lib/cequel/record/persistence.rb, line 267
def deleter
  raise ArgumentError, "Can't get deleter for new record" if new_record?
  @deleter ||= Metal::Deleter.new(metal_scope)
end
destroy(options = {}) click to toggle source

Remove this record from the database

@param options [Options] options for deletion @option options [Symbol] :consistency what consistency with

which to persist the deletion

@option options [Time] :timestamp the writetime to use for the deletion

@return [Record] self

# File lib/cequel/record/persistence.rb, line 219
def destroy(options = {})
  options.assert_valid_keys(:consistency, :timestamp)
  assert_keys_present!
  metal_scope.delete(options)
  transient!
  self
end
exist?()
Alias for: exists?
exists?() click to toggle source

Check if an unloaded record exists in the database

@return `true` if the record has a corresponding row in the

database

@since 1.0.0

# File lib/cequel/record/persistence.rb, line 106
def exists?
  load!
  true
rescue RecordNotFound
  false
end
Also aliased as: exist?
hydrate(row) click to toggle source

@private

# File lib/cequel/record/persistence.rb, line 256
def hydrate(row)
  init_attributes(row)
  hydrated!
  self
end
key_attributes() click to toggle source

@return [Hash] the attributes of this record that make up the primary

key

@example

post = Post.new
post.blog_subdomain = 'cassandra'
post.permalink = 'cequel'
post.title = 'Cequel: The Next Generation'
post.key_attributes
  #=> {:blog_subdomain=>'cassandra', :permalink=>'cequel'}

@since 1.0.0

# File lib/cequel/record/persistence.rb, line 83
def key_attributes
  @cequel_attributes.slice(*self.class.key_column_names)
end
key_values() click to toggle source

@return [Array] the values of the primary key columns for this record

@see key_attributes @since 1.0.0

# File lib/cequel/record/persistence.rb, line 93
def key_values
  key_attributes.values
end
Also aliased as: to_key
load() click to toggle source

Load an unloaded record's row from the database and hydrate the record's attributes

@return [Record] self

@since 1.0.0

# File lib/cequel/record/persistence.rb, line 122
def load
  assert_keys_present!
  record_collection.load! unless loaded?
  self
end
load!() click to toggle source

Attempt to load an unloaded record and raise an error if the record does not correspond to a row in the database

@return [Record] self @raise [RecordNotFound] if row does not exist in the database

@see load @since 1.0.0

# File lib/cequel/record/persistence.rb, line 138
def load!
  load.tap do
    if transient?
      fail RecordNotFound,
           "Couldn't find #{self.class.name} with " \
           "#{key_attributes.inspect}"
    end
  end
end
loaded?(column = nil) click to toggle source

@overload loaded?

@return [Boolean] true if this record's attributes have been loaded
  from the database

@overload loaded?(column)

@param [Symbol] column name of column to check if loaded
@return [Boolean] true if the named column is loaded in memory

@return [Boolean]

@since 1.0.0

# File lib/cequel/record/persistence.rb, line 161
def loaded?(column = nil)
  !!@loaded && (column.nil? || @cequel_attributes.key?(column.to_sym))
end
new_record?() click to toggle source

@return true if this is a new, unsaved record

@since 1.0.0

# File lib/cequel/record/persistence.rb, line 233
def new_record?
  !!@new_record
end
persisted?() click to toggle source

@return true if this record is persisted in the database

@see transient?

# File lib/cequel/record/persistence.rb, line 242
def persisted?
  !!@persisted
end
save(options = {}) click to toggle source

Persist the record to the database. If this is a new record, it will be saved using an INSERT statement. If it is an existing record, it will be persisted using a series of `UPDATE` and `DELETE` statements which will persist all changes to the database, including atomic collection modifications.

@param options [Options] options for save @option options [Boolean] :validate (true) whether to run validations

before saving

@option options [Symbol] :consistency what consistency with

which to persist the changes

@option options [Integer] :ttl time-to-live of the updated rows in

seconds

@option options [Time] :timestamp the writetime to use for the column

updates

@return [Boolean] true if record saved successfully, false if invalid

@see Validations#save!

# File lib/cequel/record/persistence.rb, line 185
def save(options = {})
  options.assert_valid_keys(:consistency, :ttl, :timestamp)
  if new_record? then create(options)
  else update(options)
  end
  @new_record = false
  true
end
to_key()
Alias for: key_values
transient?() click to toggle source

@return true if this record is not persisted in the database

@see persisted?

# File lib/cequel/record/persistence.rb, line 251
def transient?
  !persisted?
end
update_attributes(attributes) click to toggle source

Set attributes and save the record

@param attributes [Hash] hash of attributes to update @return [Boolean] true if saved successfully

@see save @see Properties#attributes= @see Validations#update_attributes!

# File lib/cequel/record/persistence.rb, line 204
def update_attributes(attributes)
  self.attributes = attributes
  save
end
updater() click to toggle source
# File lib/cequel/record/persistence.rb, line 262
def updater
  raise ArgumentError, "Can't get updater for new record" if new_record?
  @updater ||= Metal::Updater.new(metal_scope)
end

Protected Instance Methods

create(options = {}) click to toggle source
# File lib/cequel/record/persistence.rb, line 284
def create(options = {})
  assert_keys_present!
  attributes_for_write = attributes.reject { |attr, value| value.nil? }
  metal_scope.insert(attributes_for_write, options)
  loaded!
  persisted!
end
persisted!() click to toggle source
# File lib/cequel/record/persistence.rb, line 274
def persisted!
  @persisted = true
  self
end
transient!() click to toggle source
# File lib/cequel/record/persistence.rb, line 279
def transient!
  @persisted = false
  self
end
update(options = {}) click to toggle source
# File lib/cequel/record/persistence.rb, line 293
def update(options = {})
  assert_keys_present!
  connection.batch do |batch|
    batch.on_complete { @updater, @deleter = nil }
    updater.execute(options)
    deleter.execute(options.except(:ttl))
  end
end

Private Instance Methods

assert_keys_present!() click to toggle source
# File lib/cequel/record/persistence.rb, line 376
def assert_keys_present!
  missing_keys = key_attributes.select { |k, v| v.nil? }
  if missing_keys.any?
    fail MissingKeyError,
         "Missing required key values: #{missing_keys.keys.join(', ')}"
  end
end
attributes_for_create() click to toggle source
# File lib/cequel/record/persistence.rb, line 362
def attributes_for_create
  @cequel_attributes.each_with_object({}) do |(column, value), attributes|
    attributes[column] = value unless value.nil?
  end
end
attributes_for_deletion() click to toggle source
# File lib/cequel/record/persistence.rb, line 372
def attributes_for_deletion
  @cequel_attributes_for_deletion ||= []
end
attributes_for_update() click to toggle source
# File lib/cequel/record/persistence.rb, line 368
def attributes_for_update
  @cequel_attributes_for_update ||= {}
end
hydrated!() click to toggle source
# File lib/cequel/record/persistence.rb, line 346
def hydrated!
  loaded!
  persisted!
  self
end
loaded!() click to toggle source
# File lib/cequel/record/persistence.rb, line 352
def loaded!
  @loaded = true
  collection_proxies.each_value { |collection| collection.loaded! }
  self
end
metal_scope() click to toggle source
# File lib/cequel/record/persistence.rb, line 358
def metal_scope
  table.where(key_attributes)
end
read_attribute(attribute) click to toggle source
Calls superclass method
# File lib/cequel/record/persistence.rb, line 308
def read_attribute(attribute)
  super
rescue MissingAttributeError
  load
  super
end
record_collection() click to toggle source
# File lib/cequel/record/persistence.rb, line 340
def record_collection
  @record_collection ||=
    LazyRecordCollection.new(self.class.at(*key_values))
    .tap { |set| set.__setobj__([self]) }
end
stage_attribute_update(name, value) click to toggle source
# File lib/cequel/record/persistence.rb, line 330
def stage_attribute_update(name, value)
  unless new_record?
    if value.nil?
      deleter.delete_columns(name)
    else
      updater.set(name => value)
    end
  end
end
write_attribute(name, value) click to toggle source
Calls superclass method
# File lib/cequel/record/persistence.rb, line 315
def write_attribute(name, value)
  column = self.class.reflect_on_column(name)
  fail UnknownAttributeError, "unknown attribute: #{name}" unless column
  value = column.cast(value) unless value.nil?

  if !new_record? && key_attributes.keys.include?(name)
    if read_attribute(name) != value
      fail ArgumentError,
           "Can't update key #{name} on persisted record"
    end
  else
    super.tap { stage_attribute_update(name, value) }
  end
end