lib/ohm.rb in ohm-1.0.0 vs lib/ohm.rb in ohm-1.0.1
- old
+ new
@@ -127,12 +127,33 @@
# Wrapper for Ohm.redis.flushdb.
def self.flush
redis.flushdb
end
+ # Wraps the whole pipelining functionality.
+ module PipelinedFetch
+ private
+ def fetch(ids)
+ arr = db.pipelined do
+ ids.each { |id| db.hgetall(namespace[id]) }
+ end
+
+ res = []
+
+ return res if arr.nil?
+
+ arr.each_with_index do |atts, idx|
+ res << model.new(Hash[*atts].update(:id => ids[idx]))
+ end
+
+ res
+ end
+ end
+
# Defines most of the methods used by `Set` and `MultiSet`.
module Collection
+ include PipelinedFetch
include Enumerable
# Fetch the data from Redis in one go.
def to_a
fetch(ids)
@@ -190,14 +211,14 @@
# # => true
#
def sort(options = {})
if options.has_key?(:get)
options[:get] = namespace["*->%s" % options[:get]]
- return execute { |key| key.sort(options) }
+ return execute { |key| db.sort(key, options) }
end
- fetch(execute { |key| key.sort(options) })
+ fetch(execute { |key| db.sort(key, options) })
end
# Check if a model is included in this set.
#
# Example:
@@ -214,11 +235,11 @@
exists?(model.id)
end
# Returns the total size of the set using SCARD.
def size
- execute { |key| key.scard }
+ execute { |key| db.scard(key) }
end
# Syntactic sugar for `sort_by` or `sort` when you only need the
# first element.
#
@@ -241,11 +262,11 @@
end
end
# Grab all the elements of this set using SMEMBERS.
def ids
- execute { |key| key.smembers }
+ execute { |key| db.smembers(key) }
end
# Retrieve a specific element using an ID from this set.
#
# Example:
@@ -260,46 +281,31 @@
model[id] if exists?(id)
end
private
def exists?(id)
- execute { |key| key.sismember(id) }
+ execute { |key| db.sismember(key, id) }
end
-
- def fetch(ids)
- arr = model.db.pipelined do
- ids.each { |id| model.db.hgetall(namespace[id]) }
- end
-
- res = []
-
- return res if arr.nil?
-
- arr.each_with_index do |atts, idx|
- res << model.new(Hash[*atts].update(:id => ids[idx]))
- end
-
- res
- end
end
class List < Struct.new(:key, :namespace, :model)
+ include PipelinedFetch
include Enumerable
# Returns the total size of the list using LLEN.
def size
- key.llen
+ db.llen(key)
end
# Returns the first element of the list using LINDEX.
def first
- model[key.lindex(0)]
+ model[db.lindex(key, 0)]
end
# Returns the last element of the list using LINDEX.
def last
- model[key.lindex(-1)]
+ model[db.lindex(key, -1)]
end
# Checks if the model is part of this List.
#
# An important thing to note is that this method loads all of the
@@ -329,12 +335,12 @@
#
def replace(models)
ids = models.map { |model| model.id }
model.db.multi do
- key.del
- ids.each { |id| key.rpush(id) }
+ db.del(key)
+ ids.each { |id| db.rpush(key, id) }
end
end
# Fetch the data from Redis in one go.
def to_a
@@ -349,16 +355,16 @@
size == 0
end
# Pushes the model to the _end_ of the list using RPUSH.
def push(model)
- key.rpush(model.id)
+ db.rpush(key, model.id)
end
# Pushes the model to the _beginning_ of the list using LPUSH.
def unshift(model)
- key.lpush(model.id)
+ db.lpush(key, model.id)
end
# Delete a model from the list.
#
# Note: If your list contains the model multiple times, this method
@@ -385,32 +391,20 @@
# # => true
#
def delete(model)
# LREM key 0 <id> means remove all elements matching <id>
# @see http://redis.io/commands/lrem
- key.lrem(0, model.id)
+ db.lrem(key, 0, model.id)
end
private
def ids
- key.lrange(0, -1)
+ db.lrange(key, 0, -1)
end
- def fetch(ids)
- arr = model.db.pipelined do
- ids.each { |id| model.db.hgetall(namespace[id]) }
- end
-
- res = []
-
- return res if arr.nil?
-
- arr.each_with_index do |atts, idx|
- res << model.new(Hash[*atts].update(:id => ids[idx]))
- end
-
- res
+ def db
+ model.db
end
end
class Set < Struct.new(:key, :namespace, :model)
include Collection
@@ -458,10 +452,14 @@
private
def execute
yield key
end
+
+ def db
+ model.db
+ end
end
class MutableSet < Set
# Add a model directly to the set.
#
@@ -471,11 +469,11 @@
# post = Post.create
#
# user.posts.add(post)
#
def add(model)
- key.sadd(model.id)
+ db.sadd(key, model.id)
end
# Remove a model directly from the set.
#
# Example:
@@ -484,11 +482,11 @@
# post = Post.create
#
# user.posts.delete(post)
#
def delete(model)
- key.srem(model.id)
+ db.srem(key, model.id)
end
# Replace all the existing elements of a set with a different
# collection of models. This happens atomically in a MULTI-EXEC
# block.
@@ -507,12 +505,12 @@
#
def replace(models)
ids = models.map { |model| model.id }
key.redis.multi do
- key.del
- ids.each { |id| key.sadd(id) }
+ db.del(key)
+ ids.each { |id| db.sadd(key, id) }
end
end
end
# Anytime you filter a set with more than one requirement, you
@@ -584,20 +582,24 @@
return self
end
private
+ def db
+ model.db
+ end
+
def filters
@filters ||= []
end
def temp_keys
@temp_keys ||= []
end
def clean_temp_keys
- model.db.del(*temp_keys)
+ db.del(*temp_keys)
temp_keys.clear
end
def generate_temp_key
key = namespace[:temp][SecureRandom.hex(32)]
@@ -615,11 +617,11 @@
# Operation can be sinterstore, sdiffstore, or sunionstore.
# each operation we do, i.e. `.union(...)`, will be considered
# one intersected set, hence we need to `sinterstore` all
# the filters in a temporary set.
temp = generate_temp_key
- temp.sinterstore(*list)
+ db.sinterstore(temp, *list)
# If this is the first set, we simply assign the generated
# set to main, which could possibly be the return value
# for simple filters like one `.find(...)`.
if main.nil?
@@ -627,11 +629,16 @@
else
# Append the generated temporary set using the operation.
# i.e. if we have (mood=happy & book=1) and we have an
# `sunionstore`, we do (mood=happy & book=1) | (mood=sad & book=1)
- main.send(operation, main, temp)
+ #
+ # Here we dynamically call the stored command, e.g.
+ #
+ # SUNIONSTORE main main temp
+ #
+ db.send(operation, main, main, temp)
end
end
begin
@@ -767,11 +774,11 @@
lambda { |id| self[id] }
end
# Check if the ID exists within <Model>:all.
def self.exists?(id)
- key[:all].sismember(id)
+ db.sismember(key[:all], id)
end
# Find values in `unique` indices.
#
# Example:
@@ -783,11 +790,11 @@
# u = User.create(:email => "foo@bar.com")
# u == User.with(:email, "foo@bar.com")
# # => true
#
def self.with(att, val)
- id = key[:uniques][att].hget(val)
+ id = db.hget(key[:uniques][att], val)
id && self[id]
end
# Find values in indexed fields.
#
@@ -812,12 +819,12 @@
# def tag
# ["ruby", "python"]
# end
# end
#
- # u = User.create(:name => "John", :status => "pending", :email => "foo@me.com")
- # User.find(:provider => "me", :name => "John", :status => "pending").include?(u)
+ # u = User.create(name: "John", status: "pending", email: "foo@me.com")
+ # User.find(provider: "me", name: "John", status: "pending").include?(u)
# # => true
#
# User.find(:tag => "ruby").include?(u)
# # => true
#
@@ -1052,11 +1059,11 @@
#
def self.counter(name)
define_method(name) do
return 0 if new?
- key[:counters].hget(name).to_i
+ db.hget(key[:counters], name).to_i
end
end
# An Ohm::Set wrapper for Model.key[:all].
def self.all
@@ -1130,11 +1137,11 @@
end
# Preload all the attributes of this model from Redis. Used
# internally by `Model::[]`.
def load!
- update_attributes(key.hgetall) unless new?
+ update_attributes(db.hgetall(key)) unless new?
return self
end
# Read an attribute remotly from Redis. Useful if you want to get
# the most recent value of the attribute and not rely on locally
@@ -1151,31 +1158,31 @@
# u.save |
# | u.name == "A"
# | u.get(:name) == "B"
#
def get(att)
- @attributes[att] = key.hget(att)
+ @attributes[att] = db.hget(key, att)
end
# Update an attribute value atomically. The best usecase for this
# is when you simply want to update one value.
#
# Note: This method is dangerous because it doesn't update indices
# and uniques. Use it wisely. The safe equivalent is `update`.
#
def set(att, val)
- val.to_s.empty? ? key.hdel(att) : key.hset(att, val)
+ val.to_s.empty? ? db.hdel(key, att) : db.hset(key, att, val)
@attributes[att] = val
end
def new?
!defined?(@id)
end
# Increment a counter atomically. Internally uses HINCRBY.
def incr(att, count = 1)
- key[:counters].hincrby(att, count)
+ db.hincrby(key[:counters], att, count)
end
# Decrement a counter atomically. Internally uses HINCRBY.
def decr(att, count = 1)
incr(att, -count)
@@ -1289,17 +1296,17 @@
uniques = nil
indices = nil
t.read do
_verify_uniques
- existing = key.hgetall
+ existing = db.hgetall(key)
uniques = _read_index_type(:uniques)
indices = _read_index_type(:indices)
end
t.write do
- model.key[:all].sadd(id)
+ db.sadd(model.key[:all], id)
_delete_uniques(existing)
_delete_indices(existing)
_save
_save_indices(indices)
_save_uniques(uniques)
@@ -1316,20 +1323,20 @@
# If the model has uniques or indices, they're also cleaned up.
#
def delete
transaction do |t|
t.read do |store|
- store[:existing] = key.hgetall
+ store[:existing] = db.hgetall(key)
end
t.write do |store|
_delete_uniques(store[:existing])
_delete_indices(store[:existing])
- model.collections.each { |e| key[e].del }
- model.key[:all].srem(id)
- key[:counters].del
- key.del
+ model.collections.each { |e| db.del(key[e]) }
+ db.srem(model.key[:all], id)
+ db.del(key[:counters])
+ db.del(key)
end
yield t if block_given?
end
end
@@ -1395,11 +1402,11 @@
[key[:indices][att][val]]
end
end
def self.new_id
- key[:id].incr
+ db.incr(key[:id])
end
attr_writer :id
def transaction
@@ -1433,12 +1440,12 @@
model.uniques.map { |att| model.key[:uniques][att] }
end
def _save
catch :empty do
- key.del
- key.hmset(*_skip_empty(attributes).to_a.flatten)
+ db.del(key)
+ db.hmset(key, *_skip_empty(attributes).to_a.flatten)
end
end
def _verify_uniques
if att = _detect_duplicate
@@ -1446,11 +1453,11 @@
end
end
def _detect_duplicate
model.uniques.detect do |att|
- id = model.key[:uniques][att].hget(send(att))
+ id = db.hget(model.key[:uniques][att], send(att))
id && id != self.id.to_s
end
end
def _read_index_type(type)
@@ -1461,31 +1468,31 @@
end
end
def _save_uniques(uniques)
uniques.each do |att, val|
- model.key[:uniques][att].hset(val, id)
+ db.hset(model.key[:uniques][att], val, id)
end
end
def _delete_uniques(atts)
model.uniques.each do |att|
- model.key[:uniques][att].hdel(atts[att.to_s])
+ db.hdel(model.key[:uniques][att], atts[att.to_s])
end
end
def _delete_indices(atts)
model.indices.each do |att|
val = atts[att.to_s]
- model.key[:indices][att][val].srem(id)
+ db.srem(model.key[:indices][att][val], id)
end
end
def _save_indices(indices)
indices.each do |att, val|
model.toindices(att, val).each do |index|
- index.sadd(id)
+ db.sadd(index, id)
end
end
end
end