Class: EasyRedis::Model

Inherits:
Object
  • Object
show all
Defined in:
lib/easyredis.rb

Overview

class representing a data model you want to store in redis

Constant Summary collapse

@@sorts =
[]
@@searches =
[]
@@types =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id = nil, check = true) ⇒ Model

create a new instance of this model

Parameters:

  • id (String) (defaults to: nil)

    optional id to use for the entry if you leave this parameter out an id will be generated for you

  • check (Boolean) (defaults to: true)

    this flag is used for internal purposes. LEAVE IT AS TRUE



445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/easyredis.rb', line 445

def initialize(id=nil,check=true)
  if id
    @id = id.to_s
    if check
      raise "id #{id} is already in use" if EasyRedis.redis.zscore(prefix,id)
      EasyRedis.redis.zadd(prefix,Time.now.to_i,@id)
    end
  else
    @id = EasyRedis.redis.incr(prefix + ':next_id').to_s
    EasyRedis.redis.zadd(prefix,Time.now.to_i,@id)
  end
end

Instance Attribute Details

#idObject (readonly)

the id of this entry



437
438
439
# File 'lib/easyredis.rb', line 437

def id
  @id
end

Class Method Details

.[](index, amt = nil) ⇒ Object

access entries of this model based on time

same as calling self.all.[]



329
330
331
# File 'lib/easyredis.rb', line 329

def self.[](index,amt=nil)
  self.all[index,amt]
end

.all(options = {:order => :asc}) ⇒ Object

get all instances of this model ordered by creation time



291
292
293
# File 'lib/easyredis.rb', line 291

def self.all(options = {:order => :asc})
  self.sort_by :created_at, options
end

.countObject

returns number of instances of this model



285
286
287
# File 'lib/easyredis.rb', line 285

def self.count
  EasyRedis.redis.zcard(prefix)
end

.destroy_allObject

destroy all instances of this model



427
428
429
430
431
432
433
# File 'lib/easyredis.rb', line 427

def self.destroy_all
  all.each {|x| x.destroy}
  @@sorts.each {|field| EasyRedis.redis.del(sort_key(field)) }
  # @@text_searches.each {|field| EasyRedis.redis.del(terms_key(field)) }
  EasyRedis.redis.del(prefix)
  EasyRedis.redis.del(prefix + ":next_id")
end

.field(name) ⇒ Object

add a field to the model

Parameters:

  • name (Symbol)

    a symbol representing the name of the field



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/easyredis.rb', line 200

def self.field(name)
  @@fields ||= []
  @@fields << name.to_sym
  name = name.to_s
  getter = name
  setter = name + "="
  instance_var = '@' + name

  define_method getter.to_sym do
    prev = instance_variable_get(instance_var)
    if prev
      prev
    else
      data = EasyRedis.redis.hget(key_name,name)
      type = get_type(name)
      if type == 'int'
        data = data.to_i
      elsif type == 'flt'
        data = data.to_f
      elsif type == 'str'
        data = data.to_s
      elsif type.match /^model:/
        klass = eval(type[6..-1])
        data = klass.find(data)
      end
      instance_variable_set(instance_var,data)
    end
  end

  define_method setter.to_sym do |val|
    instance_variable_set(instance_var,val)
    if val.is_a? Fixnum
      set_type(name,'int')
    elsif val.is_a? Float
      set_type(name,'flt')
    elsif val.is_a? String
      set_type(name,'str')
    elsif val.is_a? EasyRedis::Model
      set_type(name,"model:#{val.class.name}")
      val = val.id
    end # TODO: else.... marshall it
    EasyRedis.redis.hset(key_name,name,val)

    if self.class.sortable? name.to_sym
      EasyRedis.redis.zadd(sort_key(name),EasyRedis.score(val),@id)
    end

    if self.class.searchable? name
      EasyRedis.redis.sadd(search_key(name,val),@id)
    end

    #if self.class.text_search? name.to_sym
    #  val.split.each do |term|
    #    EasyRedis.redis.zadd term_key(name,term), created_at.to_i, id
    #    EasyRedis.redis.zadd terms_key(name), EasyRedis.score(term), term
    #  end
    #end
  end
end

.find(id) ⇒ Object

find an entry of this model based on its id OR, find an entry based on field/value pairs in a hash (current only works with one pair)

Parameters:

  • id (Integer, Hash)

    the id of the entry to retrive, or a hash of field/value pairs



315
316
317
318
319
320
321
322
323
324
# File 'lib/easyredis.rb', line 315

def self.find(id)
  if id.is_a? Hash
    pair = id.to_a.first
    self.find_by(pair[0],pair[1]) # TODO: add support for multiple field/value pairs
  elsif EasyRedis.redis.zscore(prefix,id)
    build(id)
  else
    nil
  end
end

.find_by(field, val) ⇒ Object

get the first entry where field matches val



348
349
350
351
# File 'lib/easyredis.rb', line 348

def self.find_by(field,val)
  i = EasyRedis.redis.srandmember(search_key(field,val))
  build(i) if i
end

.first(n = nil) ⇒ Object

same as calling self.all.first



296
297
298
# File 'lib/easyredis.rb', line 296

def self.first(n = nil)
  self.all.first(n)
end

.last(n = nil) ⇒ Object

same as calling self.all.last



301
302
303
# File 'lib/easyredis.rb', line 301

def self.last(n = nil)
  self.all.last(n)
end

.randObject

returns a random entry of this model



306
307
308
# File 'lib/easyredis.rb', line 306

def self.rand
  self[Kernel.rand(self.count)]
end

.search(params) ⇒ Object

search the model based on multiple parameters

Parameters:

  • params (Hash)

    a hash of field => value pairs



356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/easyredis.rb', line 356

def self.search(params)
  return search_by(*params.first) if params.size == 1
  if params.all? {|f,v| searchable? f }
    ids = EasyRedis.redis.sinter(*params.map{|k,v|search_key(k,v)})
    ids.map{|i|build(i)}
  elsif params.all? {|f,v| sortable? f}
    result_set = nil
    params.each do |field,value|
      scr = EasyRedis.score(value)
      ids = EasyRedis.redis.zrangebyscore(sort_key(field),scr,scr)
      result_set = result_set ? (result_set & Set.new(ids)) : Set.new(ids)
    end
    result_set.map{|i|build(i)}
  else
    raise "fields must all be searchable or all be sortable"
  end
end

.search_by(field, val, options = {}) ⇒ Object

get all entries where field matches val

Parameters:

  • field (Symbol)

    a symbol representing the field to search on

  • val

    the value of field to search for



337
338
339
340
341
342
343
# File 'lib/easyredis.rb', line 337

def self.search_by(field, val, options = {})
  # scr = EasyRedis.score(val)
  # options[:limit] = [0,options[:limit]] if options[:limit]
  # ids = EasyRedis.redis.zrangebyscore(sort_key(field),scr,scr,proc_options(options))
  ids = EasyRedis.redis.smembers(search_key(field,val))
  ids.map{|i| build(i) }
end

.search_on(field) ⇒ Object

index a field to be searched (with exact matches)



271
272
273
274
# File 'lib/easyredis.rb', line 271

def self.search_on(field)
  @@searches << field.to_sym
  nil
end

.searchable?(field) ⇒ Boolean

indicates whether field has been indexed with sort_on

Returns:

  • (Boolean)


417
418
419
# File 'lib/easyredis.rb', line 417

def self.searchable?(field)
  @@searches and @@searches.member? field.to_sym
end

.sort_by(field, options = {:order => :asc}) ⇒ Object

get all entries, sorted by the given field



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/easyredis.rb', line 375

def self.sort_by(field,options = {:order => :asc})
  raise EasyRedis::FieldNotSortable unless self.sortable? field
  EasyRedis::Collection.new do |range|
    a = range.begin
    b = range.end
    b -= 1 if range.exclude_end?
    ids = []
    if options[:order] == :asc
      ids = EasyRedis.redis.zrange(sort_key(field),a,b)
    elsif options[:order] == :desc
      ids = EasyRedis.redis.zrevrange(sort_key(field),a,b)
    end
    ids.map{|i| build(i)}
  end
end

.sort_on(field) ⇒ Object

index a field to be sorted



263
264
265
266
# File 'lib/easyredis.rb', line 263

def self.sort_on(field)
  @@sorts << field.to_sym
  nil
end

.sortable?(field) ⇒ Boolean

indicates whether field has been indexed with sort_on

Returns:

  • (Boolean)


412
413
414
# File 'lib/easyredis.rb', line 412

def self.sortable?(field)
  @@sorts and (@@sorts.member? field or field.to_sym == :created_at)
end

Instance Method Details

#[](field) ⇒ Object

directly access a field of this entry’s redis hash

note that you cannot access created_at or id with these methods



466
467
468
# File 'lib/easyredis.rb', line 466

def [](field)
  EasyRedis.redis.hget(key_name,field)
end

#[]=(field, val) ⇒ Object

directly change a field of this entry’s redis hash

note that you cannot access created_at or id with these methods



473
474
475
476
477
478
479
# File 'lib/easyredis.rb', line 473

def []=(field,val)
  if val
    EasyRedis.redis.hset(key_name,field,val)
  else
    EasyRedis.redis.hdel(key_name,field)
  end
end

#clearObject

clears all fields, causing future gets to reretrive them from redis



497
498
499
500
501
# File 'lib/easyredis.rb', line 497

def clear
  @@fields.each do |field|
    self.instance_variable_set("@"+field.to_s,nil)
  end
end

#created_atObject

get the creation time of an entry



459
460
461
# File 'lib/easyredis.rb', line 459

def created_at
  Time.at(EasyRedis.redis.zscore(prefix,@id).to_i)
end

#destroyObject

remove the entry



482
483
484
485
# File 'lib/easyredis.rb', line 482

def destroy
  EasyRedis.redis.zrem(prefix,@id)
  EasyRedis.redis.del(key_name)
end

#inspectObject



492
493
494
# File 'lib/easyredis.rb', line 492

def inspect
  "#<#{self.class.name}:#{@id}>"
end

#key_nameObject

returns the key name of this entry’s redis hash



488
489
490
# File 'lib/easyredis.rb', line 488

def key_name
  "#{prefix}:#{@id}"
end