class CassandraStore::Base
Public Class Methods
cast_value(value, type)
click to toggle source
# File lib/cassandra_store/base.rb, line 228 def self.cast_value(value, type) return nil if value.nil? case type when :text value.to_s when :int, :bigint Integer(value) when :boolean return true if [1, "1", "true", true].include?(value) return false if [0, "0", "false", false].include?(value) raise ArgumentError, "Can't cast '#{value}' to #{type}" when :date if value.is_a?(String) then Date.parse(value) elsif value.respond_to?(:to_date) then value.to_date else raise(ArgumentError, "Can't cast '#{value}' to #{type}") end when :timestamp if value.is_a?(String) then Time.parse(value) elsif value.respond_to?(:to_time) then value.to_time elsif value.is_a?(Numeric) then Time.at(value) else raise(ArgumentError, "Can't cast '#{value}' to #{type}") end.utc.round(3) when :timeuuid return value if value.is_a?(Cassandra::TimeUuid) return Cassandra::TimeUuid.new(value) if value.is_a?(String) || value.is_a?(Integer) raise ArgumentError, "Can't cast '#{value}' to #{type}" when :uuid return value if value.is_a?(Cassandra::Uuid) return Cassandra::Uuid.new(value) if value.is_a?(String) || value.is_a?(Integer) raise ArgumentError, "Can't cast '#{value}' to #{type}" else raise CassandraStore::UnknownType, "Unknown type #{type}" end end
cluster_execute(statement, options = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 304 def self.cluster_execute(statement, options = {}) logger.debug(statement) cluster_pool.with do |connection| connection.execute(statement, options) end end
clustering_key_columns()
click to toggle source
# File lib/cassandra_store/base.rb, line 198 def self.clustering_key_columns columns.select { |_, options| options[:clustering_key] } end
column(name, type, partition_key: false, clustering_key: false)
click to toggle source
# File lib/cassandra_store/base.rb, line 202 def self.column(name, type, partition_key: false, clustering_key: false) self.columns = columns.merge(name => { type: type, partition_key: partition_key, clustering_key: clustering_key }) define_attribute_methods name define_method name do read_raw_attribute(name) end define_method :"#{name}=" do |value| raise(ArgumentError, "Can't update key '#{name}' for persisted records") if persisted? && (self.class.columns[name][:partition_key] || self.class.columns[name][:clustering_key]) send :"#{name}_will_change!" unless read_raw_attribute(name) == value write_raw_attribute(name, self.class.cast_value(value, type)) end end
configure(hosts: ["127.0.0.1"], keyspace:, cluster_settings: {}, replication: {}, durable_writes: true, pool: { size: 5, timeout: 5 })
click to toggle source
# File lib/cassandra_store/base.rb, line 23 def self.configure(hosts: ["127.0.0.1"], keyspace:, cluster_settings: {}, replication: {}, durable_writes: true, pool: { size: 5, timeout: 5 }) self.keyspace_settings = { name: keyspace, replication: replication, durable_writes: durable_writes } self.cluster_pool = ConnectionPool.new(pool) do Cassandra.cluster(cluster_settings.merge(hosts: hosts)).connect end self.connection_pool = ConnectionPool.new(pool) do Cassandra.cluster(cluster_settings.merge(hosts: hosts)).connect(keyspace) end end
create(attributes = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 100 def self.create(attributes = {}) new(attributes).tap(&:save) end
create!(attributes = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 96 def self.create!(attributes = {}) new(attributes).tap(&:save!) end
create_keyspace(name: keyspace_settings[:name], replication: keyspace_settings[:replication], durable_writes: keyspace_settings[:durable_writes], if_not_exists: false)
click to toggle source
# File lib/cassandra_store/base.rb, line 39 def self.create_keyspace(name: keyspace_settings[:name], replication: keyspace_settings[:replication], durable_writes: keyspace_settings[:durable_writes], if_not_exists: false) cql = <<~CQL CREATE KEYSPACE #{if_not_exists ? "IF NOT EXISTS" : ""} #{quote_keyspace_name(name)} WITH REPLICATION = { #{replication.map { |key, value| "#{quote_value(key)}: #{quote_value(value)}" }.join(", ")} } AND DURABLE_WRITES = #{quote_value(durable_writes)} CQL cluster_execute(cql) end
drop_keyspace(name: keyspace_settings[:name], if_exists: false)
click to toggle source
# File lib/cassandra_store/base.rb, line 35 def self.drop_keyspace(name: keyspace_settings[:name], if_exists: false) cluster_execute("DROP KEYSPACE #{if_exists ? "IF EXISTS" : ""} #{quote_keyspace_name(name)}") end
execute(statement, options = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 312 def self.execute(statement, options = {}) logger.debug(statement) connection_pool.with do |connection| connection.execute(statement, options) end end
execute_batch(statements, options = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 320 def self.execute_batch(statements, options = {}) statements.each do |statement| logger.debug(statement) end connection_pool.with do |connection| batch = connection.send(:"#{options[:batch_type] || "logged"}_batch") statements.each do |statement| batch.add(statement) end connection.execute(batch, options.except(:batch_type)) end end
key_columns()
click to toggle source
# File lib/cassandra_store/base.rb, line 190 def self.key_columns partition_key_columns.merge(clustering_key_columns) end
new(attributes = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 51 def initialize(attributes = {}) @persisted = false @destroyed = false assign(attributes) end
partition_key_columns()
click to toggle source
# File lib/cassandra_store/base.rb, line 194 def self.partition_key_columns columns.select { |_, options| options[:partition_key] } end
quote_column_name(column_name)
click to toggle source
# File lib/cassandra_store/base.rb, line 275 def self.quote_column_name(column_name) raise(ArgumentError, "Invalid column name #{column_name}") if column_name.to_s.include?("\"") "\"#{column_name}\"" end
quote_keyspace_name(keyspace_name)
click to toggle source
# File lib/cassandra_store/base.rb, line 267 def self.quote_keyspace_name(keyspace_name) quote_column_name(keyspace_name) end
quote_string(string)
click to toggle source
# File lib/cassandra_store/base.rb, line 296 def self.quote_string(string) "'#{string.gsub("'", "''")}'" end
quote_table_name(table_name)
click to toggle source
# File lib/cassandra_store/base.rb, line 271 def self.quote_table_name(table_name) quote_column_name(table_name) end
quote_value(value)
click to toggle source
# File lib/cassandra_store/base.rb, line 281 def self.quote_value(value) case value when Time, ActiveSupport::TimeWithZone (value.to_r * 1000).round.to_s when DateTime quote_value(value.utc.to_time) when Date quote_value(value.strftime("%Y-%m-%d")) when Numeric, true, false, Cassandra::Uuid value.to_s else quote_string(value.to_s) end end
relation()
click to toggle source
# File lib/cassandra_store/base.rb, line 220 def self.relation CassandraStore::Relation.new(target: self) end
statement(template, args = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 336 def self.statement(template, args = {}) res = template.dup args.each do |key, value| res.gsub!(":#{key}", quote_value(value)) end res end
table_name()
click to toggle source
# File lib/cassandra_store/base.rb, line 186 def self.table_name name.tableize end
truncate_table()
click to toggle source
# File lib/cassandra_store/base.rb, line 300 def self.truncate_table execute "TRUNCATE TABLE #{quote_table_name table_name}" end
Public Instance Methods
==(other)
click to toggle source
# File lib/cassandra_store/base.rb, line 58 def ==(other) other.instance_of?(self.class) && key_values == other.key_values end
assign(attributes = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 74 def assign(attributes = {}) attributes.each do |column, value| send(:"#{column}=", value) end end
attributes()
click to toggle source
# File lib/cassandra_store/base.rb, line 80 def attributes columns.each_with_object({}) do |(name, _), hash| hash[name] = read_raw_attribute(name) end end
delete()
click to toggle source
# File lib/cassandra_store/base.rb, line 178 def delete raise CassandraStore::RecordNotPersisted unless persisted? self.class.execute(delete_record_statement) true end
destroy()
click to toggle source
# File lib/cassandra_store/base.rb, line 164 def destroy raise CassandraStore::RecordNotPersisted unless persisted? run_hook :before_destroy delete destroyed! run_hook :after_destroy true end
destroyed!()
click to toggle source
# File lib/cassandra_store/base.rb, line 148 def destroyed! @destroyed = true end
destroyed?()
click to toggle source
# File lib/cassandra_store/base.rb, line 144 def destroyed? !!@destroyed end
eql?(other)
click to toggle source
# File lib/cassandra_store/base.rb, line 62 def eql?(other) self == other end
hash()
click to toggle source
# File lib/cassandra_store/base.rb, line 66 def hash key_values.hash end
key_values()
click to toggle source
# File lib/cassandra_store/base.rb, line 70 def key_values self.class.key_columns.map { |column, _| read_raw_attribute(column) } end
new_record?()
click to toggle source
# File lib/cassandra_store/base.rb, line 140 def new_record? !persisted? end
persisted!()
click to toggle source
# File lib/cassandra_store/base.rb, line 136 def persisted! @persisted = true end
persisted?()
click to toggle source
# File lib/cassandra_store/base.rb, line 132 def persisted? !!@persisted end
read_raw_attribute(attribute)
click to toggle source
# File lib/cassandra_store/base.rb, line 86 def read_raw_attribute(attribute) return nil unless instance_variable_defined?(:"@#{attribute}") instance_variable_get(:"@#{attribute}") end
save()
click to toggle source
# File lib/cassandra_store/base.rb, line 110 def save return false unless valid? _save end
save!()
click to toggle source
# File lib/cassandra_store/base.rb, line 104 def save! validate! _save end
update(attributes = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 152 def update(attributes = {}) assign(attributes) save end
update!(attributes = {})
click to toggle source
# File lib/cassandra_store/base.rb, line 158 def update!(attributes = {}) assign(attributes) save! end
valid?(context = nil)
click to toggle source
Calls superclass method
# File lib/cassandra_store/base.rb, line 116 def valid?(context = nil) context ||= new_record? ? :create : :update run_hook :before_validation retval = super(context) run_hook :after_validation retval end
validate!(context = nil)
click to toggle source
# File lib/cassandra_store/base.rb, line 128 def validate!(context = nil) valid?(context) || raise(CassandraStore::RecordInvalid, errors.to_a.join(", ")) end
write_raw_attribute(attribute, value)
click to toggle source
# File lib/cassandra_store/base.rb, line 92 def write_raw_attribute(attribute, value) instance_variable_set(:"@#{attribute}", value) end
Protected Instance Methods
generate_timeuuid(time = Time.now)
click to toggle source
# File lib/cassandra_store/base.rb, line 422 def generate_timeuuid(time = Time.now) @timeuuid_generator ||= Cassandra::TimeUuid::Generator.new @timeuuid_generator.at(time) end
generate_uuid()
click to toggle source
# File lib/cassandra_store/base.rb, line 417 def generate_uuid @uuid_generator ||= Cassandra::Uuid::Generator.new @uuid_generator.uuid end
Private Instance Methods
_save()
click to toggle source
# File lib/cassandra_store/base.rb, line 348 def _save run_hook :before_save if persisted? update_record else create_record persisted! end run_hook :after_save changes_applied true end
create_record()
click to toggle source
# File lib/cassandra_store/base.rb, line 365 def create_record run_hook :before_create self.class.execute(create_record_statement) run_hook :after_create end
create_record_statement()
click to toggle source
# File lib/cassandra_store/base.rb, line 373 def create_record_statement columns_clause = changes.keys.map { |column_name| self.class.quote_column_name column_name }.join(", ") values_clause = changes.values.map(&:last).map { |value| self.class.quote_value value }.join(", ") "INSERT INTO #{self.class.quote_table_name self.class.table_name}(#{columns_clause}) VALUES(#{values_clause})" end
delete_record_statement()
click to toggle source
# File lib/cassandra_store/base.rb, line 407 def delete_record_statement "DELETE FROM #{self.class.quote_table_name self.class.table_name} #{where_key_clause}" end
update_record()
click to toggle source
# File lib/cassandra_store/base.rb, line 380 def update_record run_hook :before_update self.class.execute_batch(update_record_statements) unless changes.empty? run_hook :after_update end
update_record_statements()
click to toggle source
# File lib/cassandra_store/base.rb, line 388 def update_record_statements nils = changes.select { |_, (__, new_value)| new_value.nil? } objs = changes.reject { |_, (__, new_value)| new_value.nil? } statements = [] if nils.present? statements << "DELETE #{nils.keys.join(", ")} FROM #{self.class.quote_table_name self.class.table_name} #{where_key_clause}" end if objs.present? update_clause = objs.map { |column, (_, new_value)| "#{self.class.quote_column_name column} = #{self.class.quote_value new_value}" }.join(", ") statements << "UPDATE #{self.class.quote_table_name self.class.table_name} SET #{update_clause} #{where_key_clause}" end statements end
where_key_clause()
click to toggle source
# File lib/cassandra_store/base.rb, line 411 def where_key_clause "WHERE #{self.class.key_columns.map { |column, _| "#{self.class.quote_column_name column} = #{self.class.quote_value read_raw_attribute(column)}" }.join(" AND ")}" end