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