module Cassie::Model
This module provides a simple interface for models backed by Cassandra tables.
Cassandra is very limited in how data can be accessed efficiently so this code is intentionally not designed as a full fledged DSL with all the nifty features of ActiveRecord. Doing so will only get you into trouble when you run into the limits of Cassandra data structures.
It implements ActiveModel::Model and supports ActiveModel callbacks on :create, :update, :save, and :destroy as well as ActiveModel validations.
Example:
class Thing include Cassie::Model self.table_name = "things" self.keyspace = "test" self.primary_key = [:owner, :id] column :owner, :int column :id, :int, :as => :identifier column :val, :varchar, :as => :value ordering_key :id, :desc validates_presence_of :id, :value before_save do ... end end
Public Class Methods
# File lib/cassie/model.rb, line 65 def find_subscribers @@find_subscribers end
# File lib/cassie/model.rb, line 474 def initialize(attributes = {}) super @persisted = false end
Public Instance Methods
# File lib/cassie/model.rb, line 552 def ==(other) eql?(other) end
Returns a hash of column to values. Column names will be symbols.
# File lib/cassie/model.rb, line 535 def attributes hash = {} self.class.column_names.each do |name| hash[name] = send(name) end hash end
Return true if the table is used for a counter.
# File lib/cassie/model.rb, line 485 def counter_table? !!self.class._counter_table end
Delete a record and call the destroy callbacks.
# File lib/cassie/model.rb, line 526 def destroy run_callbacks(:destroy) do self.class.connection.delete(self.class.full_table_name, key_hash, consistency: write_consistency) @persisted = false true end end
# File lib/cassie/model.rb, line 548 def eql?(other) other.is_a?(self.class) && other.key_hash == key_hash end
Returns the primary key as a hash
# File lib/cassie/model.rb, line 557 def key_hash hash = {} self.class.primary_key.each do |key| hash[key] = send(key) end hash end
Return true if the record has been persisted to Cassandra.
# File lib/cassie/model.rb, line 480 def persisted? @persisted end
Subclasses can override this method to provide a TTL on the persisted record.
# File lib/cassie/model.rb, line 544 def persistence_ttl nil end
Save a record. Returns true if the record was persisted and false if it was invalid. This method will run the save callbacks as well as either the update or create callbacks as necessary.
# File lib/cassie/model.rb, line 492 def save(validate: true, ttl: nil) raise ArgumentError.new("Cannot call save on a counter table") if counter_table? valid_record = (validate ? valid? : true) if valid_record run_callbacks(:save) do options = {consistency: write_consistency, ttl: (ttl || persistence_ttl)} if persisted? run_callbacks(:update) do self.class.connection.update(self.class.full_table_name, values_hash, key_hash, options) end else run_callbacks(:create) do self.class.connection.insert(self.class.full_table_name, attributes, options) @persisted = true end end end true else false end end
Save a record. Returns true if the record was saved and raises an ActiveRecord::RecordInvalid error if the record is invalid.
# File lib/cassie/model.rb, line 517 def save!(ttl: nil) if save(ttl: ttl) true else raise Cassie::RecordInvalid.new(self) end end
Private Instance Methods
Used for updating counter columns.
# File lib/cassie/model.rb, line 568 def adjust_counter!(name, amount, ttl: nil) amount = amount.to_i if amount != 0 run_callbacks(:update) do adjustment = (amount < 0 ? "#{name} = #{name} - #{amount.abs}" : "#{name} = #{name} + #{amount}") options = {consistency: write_consistency, ttl: (ttl || persistence_ttl)} self.class.connection.update(self.class.full_table_name, adjustment, key_hash, options) end end record = self.class.find(key_hash) value = (record ? record.send(name) : send(name) + amount) send("#{name}=", value) end
Returns a hash of value except for the ones that constitute the primary key
# File lib/cassie/model.rb, line 583 def values_hash pk = self.class.primary_key hash = {} self.class.column_names.each do |name| hash[name] = send(name) unless pk.include?(name) end hash end