class Record
Attributes
attributes[R]
dirty[R]
errors[R]
id[R]
Public Class Methods
all(options={})
click to toggle source
# File lib/redisant/records.rb, line 58 def self.all options={} sort = options.delete :sort if sort index = self.find_index sort.to_s raise Redisant::InvalidArgument.new("Cannot order by #{sort}") unless index index.objects options else ids.map { |id| self.find id } end end
any?()
click to toggle source
# File lib/redisant/records.rb, line 69 def self.any? $redis.scard( id_key ) > 0 end
build(attributes=nil)
click to toggle source
crud
# File lib/redisant/records.rb, line 115 def self.build attributes=nil object = self.new attributes object.save object end
class_key(str)
click to toggle source
# File lib/redisant/records.rb, line 183 def self.class_key str "#{self.name.downcase}:#{str}" end
count()
click to toggle source
# File lib/redisant/records.rb, line 89 def self.count Criteria.new(self).count end
destroy_all()
click to toggle source
# File lib/redisant/records.rb, line 170 def self.destroy_all keys = ids.map {|id| "#{self.name.downcase}:#{id}:attributes" } keys << id_key keys << class_key('ids:counter') $redis.del keys if keys.any? end
exists?(id)
click to toggle source
# File lib/redisant/records.rb, line 54 def self.exists? id $redis.sismember( id_key, id ) end
find(id)
click to toggle source
query
# File lib/redisant/records.rb, line 38 def self.find id raise Redisant::InvalidArgument.new("Invalid argument") unless id return nil unless exists? id t = self.new id:id t.load t end
find!(id)
click to toggle source
# File lib/redisant/records.rb, line 47 def self.find! id raise Redisant::InvalidArgument.new("Not found") unless exists? id t = self.new id:id t.load t end
first(attributes={})
click to toggle source
# File lib/redisant/records.rb, line 73 def self.first attributes={} Criteria.new(self).first attributes end
id_key()
click to toggle source
ids
# File lib/redisant/records.rb, line 261 def self.id_key class_key 'id' end
ids()
click to toggle source
# File lib/redisant/records.rb, line 278 def self.ids Criteria.new(self).ids end
last(attributes={})
click to toggle source
# File lib/redisant/records.rb, line 77 def self.last attributes={} Criteria.new(self).last attributes end
load(id)
click to toggle source
# File lib/redisant/records.rb, line 31 def self.load id t = self.new id:id t.load t end
new(attributes=nil)
click to toggle source
# File lib/redisant/records.rb, line 16 def initialize attributes=nil raise Redisant::InvalidArgument.new('Wrong arguments') unless attributes==nil or attributes.is_a? Hash @id = attributes.delete(:id) if attributes @attributes = stringify_attributes(attributes) || {} @prev_attributes = {} @dirty = @attributes.keys setup_relations if respond_to? :setup_relations @id_saved = false @errors = nil end
order(options)
click to toggle source
# File lib/redisant/records.rb, line 97 def self.order options Criteria.new(self).order options end
random()
click to toggle source
# File lib/redisant/records.rb, line 81 def self.random Criteria.new(self).random end
sort(options)
click to toggle source
# File lib/redisant/records.rb, line 93 def self.sort options Criteria.new(self).sort options end
where(attributes)
click to toggle source
# File lib/redisant/records.rb, line 85 def self.where attributes Criteria.new(self).where attributes end
Public Instance Methods
add_id()
click to toggle source
# File lib/redisant/records.rb, line 282 def add_id raise Redisant::InvalidArgument.new('Cannot add empty id') unless @id return if @id_saved $redis.sadd self.class.id_key, @id.to_i @id_saved = true end
attribute(key)
click to toggle source
single attribute
# File lib/redisant/records.rb, line 188 def attribute key @attributes[key.to_s] end
attributes=(attributes)
click to toggle source
multiple attributes
# File lib/redisant/records.rb, line 208 def attributes= attributes raise Redisant::InvalidArgument.new("Invalid arguments") unless attributes.is_a? Hash attributes.each_pair do |key,value| if value != @attributes[key.to_s] @attributes[key.to_s] = value dirty key end end end
class_name()
click to toggle source
# File lib/redisant/records.rb, line 27 def class_name self.class.name.downcase end
clean()
click to toggle source
# File lib/redisant/records.rb, line 110 def clean @dirty = [] end
cleanup_attributes()
click to toggle source
# File lib/redisant/records.rb, line 253 def cleanup_attributes # delete attribues in the hash that's not in our local attributes keys = $redis.hkeys member_key('attributes') delete = keys - @attributes.keys $redis.hdel member_key('attributes'), delete end
destroy()
click to toggle source
# File lib/redisant/records.rb, line 121 def destroy destroy_relations destroy_attributes remove_id end
destroy_attributes()
click to toggle source
# File lib/redisant/records.rb, line 247 def destroy_attributes $redis.del member_key('attributes') @attributes = nil update_search end
dirty?()
click to toggle source
dirty
# File lib/redisant/records.rb, line 102 def dirty? @dirty.any? end
load()
click to toggle source
# File lib/redisant/records.rb, line 131 def load load_attributes @id_saved = true end
load_attributes(keys=nil)
click to toggle source
# File lib/redisant/records.rb, line 218 def load_attributes keys=nil if keys keys = keys.map { |key| key.to_s } values = $redis.hmget(member_key('attributes'), keys) raw = keys.zip(values).to_h else raw = $redis.hgetall(member_key('attributes')) end decoded = decode_attributes(raw) @attributes = restore_attribute_types decoded keep_attributes end
make_unique_id()
click to toggle source
# File lib/redisant/records.rb, line 265 def make_unique_id return if @id #use optimistic concurrency control: #if id is taken, try again until we succeed while true id = $redis.incr(self.class.class_key('ids:counter')).to_i unless self.class.exists? id @id = id return end end end
member_key(str)
click to toggle source
keys
# File lib/redisant/records.rb, line 178 def member_key str raise Redisant::InvalidArgument.new('Cannot make key without id') unless @id "#{class_name}:#{@id}:#{str}" end
new?()
click to toggle source
# File lib/redisant/records.rb, line 127 def new? id == nil end
remove_id()
click to toggle source
# File lib/redisant/records.rb, line 289 def remove_id raise Redisant::InvalidArgument.new('Cannot remove empty id') unless @id $redis.srem self.class.id_key, @id @id = nil @id_saved = false end
save()
click to toggle source
# File lib/redisant/records.rb, line 136 def save return false unless validate make_unique_id add_id save_attributes true end
save!()
click to toggle source
# File lib/redisant/records.rb, line 144 def save! raise Redisant::ValidationFailed.new('Validation failed') unless save end
save_attributes()
click to toggle source
# File lib/redisant/records.rb, line 231 def save_attributes if dirty? synthesize_attributes $redis.hmset member_key('attributes'), encode_attributes clean end update_search end
set_attribute(key, value)
click to toggle source
# File lib/redisant/records.rb, line 192 def set_attribute key, value if value != @attributes[key.to_s] @attributes[key.to_s] = value dirty [key] end end
update_attribute(key, value)
click to toggle source
# File lib/redisant/records.rb, line 199 def update_attribute key, value if value != @attributes[key.to_s] @attributes[key.to_s] = value $redis.hset member_key('attributes'), key, value update_search end end
update_attributes(attributes)
click to toggle source
# File lib/redisant/records.rb, line 240 def update_attributes attributes raise Redisant::InvalidArgument.new("Invalid arguments") unless attributes.is_a? Hash @attributes.merge! stringify_attributes(attributes) dirty attributes.keys save_attributes end
validate()
click to toggle source
# File lib/redisant/records.rb, line 148 def validate @errors = nil self.class.attributes.each_pair do |key,options| v = attribute(key) if options[:required] if v==nil @errors ||= {} @errors[key] = "is required" end end if v && options[:unique] conditions = {} conditions[key] = v if self.class.where(conditions).count > 0 @errors ||= {} @errors[key] = "must be unique" end end end @errors == nil end
Private Instance Methods
decode_attributes(attributes)
click to toggle source
# File lib/redisant/records.rb, line 325 def decode_attributes attributes decoded = {} attributes.each do |pair| if pair[1]==nil decoded[pair[0]] = nil else decoded[pair[0]] = JSON.parse pair[1], quirks_mode: true end end @attributes = decoded end
destroy_relations()
click to toggle source
# File lib/redisant/records.rb, line 348 def destroy_relations relations.values.each {|relation| relation.destroy } @relations = nil end
encode_attributes()
click to toggle source
# File lib/redisant/records.rb, line 316 def encode_attributes encoded = {} @dirty.each do |key| k = key.to_s encoded[k] = @attributes[k].to_json end encoded.flatten end
keep_attributes()
click to toggle source
# File lib/redisant/records.rb, line 357 def keep_attributes if @attributes @prev_attributes = @attributes.dup else @prev_attributes = nil end end
restore_attribute_types(attributes)
click to toggle source
# File lib/redisant/records.rb, line 337 def restore_attribute_types attributes restored = {} attributes.each_pair do |k,v| time_match = /(.+)_at$/.match k if time_match restored[k] = Time.parse v end end attributes.merge! restored end
stringify_attributes(attributes)
click to toggle source
# File lib/redisant/records.rb, line 353 def stringify_attributes attributes attributes.collect {|k,v| [k.to_s,v] }.to_h if attributes end
synthesize_attributes()
click to toggle source
redis can only sort by string or float to sort by eg. Time we store float version of required attributes
# File lib/redisant/records.rb, line 301 def synthesize_attributes synthesized = {} self.class.indexes.each_pair do |name,index| if @dirty.include? name if index.type=='float' # for Time objects to_f return number of seconds since epoch key = "#{name}:float" value = @attributes[name].to_f @attributes[key] = value dirty key end end end end
update_search()
click to toggle source
search
# File lib/redisant/records.rb, line 366 def update_search prev_keys = @prev_attributes ? @prev_attributes.keys : [] cur_keys = @attributes? @attributes.keys : [] keys = prev_keys | cur_keys keys = keys & self.class.searches.keys # only attributes with search activated keys.each do |k| prev = @prev_attributes? @prev_attributes[k] : nil cur = @attributes ? @attributes[k] : nil if prev != cur search = self.class.find_search k.to_s if search if prev && cur search.update self, prev, cur elsif cur search.add self, cur elsif prev search.remove self, prev end end end end keep_attributes end