lib/ohm.rb in ohm-1.1.2 vs lib/ohm.rb in ohm-1.2.0
- old
+ new
@@ -138,12 +138,31 @@
# Wrapper for Ohm.redis.flushdb.
def self.flush
redis.flushdb
end
- # Wraps the whole pipelining functionality.
- module PipelinedFetch
+ module Collection
+ include Enumerable
+
+ def each
+ if block_given?
+ to_a.each { |element| yield element }
+ else
+ Enumerator.new(self, :each)
+ end
+ end
+
+ # Fetch the data from Redis in one go.
+ def to_a
+ fetch(ids)
+ end
+
+ def empty?
+ size == 0
+ end
+
+ # Wraps the whole pipelining functionality.
def fetch(ids)
arr = db.pipelined do
ids.each { |id| db.hgetall(namespace[id]) }
end
@@ -157,28 +176,130 @@
res
end
end
- # Defines most of the methods used by `Set` and `MultiSet`.
- module Collection
- include PipelinedFetch
- include Enumerable
+ class List
+ include Collection
- # Fetch the data from Redis in one go.
- def to_a
- fetch(ids)
+ attr :key
+ attr :namespace
+ attr :model
+
+ def initialize(key, namespace, model)
+ @key = key
+ @namespace = namespace
+ @model = model
end
- def each
- to_a.each { |e| yield e }
+ # Returns the total size of the list using LLEN.
+ def size
+ db.llen(key)
end
+ alias :count :size
- def empty?
- size == 0
+ # Returns the first element of the list using LINDEX.
+ def first
+ model[db.lindex(key, 0)]
end
+ # Returns the last element of the list using LINDEX.
+ def last
+ 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
+ # elements of the List since there is no command in Redis that
+ # allows you to actually check the list contents efficiently.
+ #
+ # You may want to avoid doing this if your list has say, 10K entries.
+ def include?(model)
+ ids.include?(model.id.to_s)
+ end
+
+ # Replace all the existing elements of a list with a different
+ # collection of models. This happens atomically in a MULTI-EXEC
+ # block.
+ #
+ # Example:
+ #
+ # user = User.create
+ # p1 = Post.create
+ # user.posts.push(p1)
+ #
+ # p2, p3 = Post.create, Post.create
+ # user.posts.replace([p2, p3])
+ #
+ # user.posts.include?(p1)
+ # # => false
+ #
+ def replace(models)
+ ids = models.map { |model| model.id }
+
+ model.db.multi do
+ db.del(key)
+ ids.each { |id| db.rpush(key, id) }
+ end
+ end
+
+ # Pushes the model to the _end_ of the list using RPUSH.
+ def push(model)
+ db.rpush(key, model.id)
+ end
+
+ # Pushes the model to the _beginning_ of the list using LPUSH.
+ def unshift(model)
+ db.lpush(key, model.id)
+ end
+
+ # Delete a model from the list.
+ #
+ # Note: If your list contains the model multiple times, this method
+ # will delete all instances of that model in one go.
+ #
+ # Example:
+ #
+ # class Comment < Ohm::Model
+ # end
+ #
+ # class Post < Ohm::Model
+ # list :comments, Comment
+ # end
+ #
+ # p = Post.create
+ # c = Comment.create
+ #
+ # p.comments.push(c)
+ # p.comments.push(c)
+ #
+ # p.comments.delete(c)
+ #
+ # p.comments.size == 0
+ # # => true
+ #
+ def delete(model)
+ # LREM key 0 <id> means remove all elements matching <id>
+ # @see http://redis.io/commands/lrem
+ db.lrem(key, 0, model.id)
+ end
+
+ private
+ def ids
+ db.lrange(key, 0, -1)
+ end
+
+ def db
+ model.db
+ end
+ end
+
+ # Defines most of the methods used by `Set` and `MultiSet`.
+ class BasicSet
+ include Collection
+
# Allows you to sort by any field in your model.
#
# Example:
#
# class User < Ohm::Model
@@ -247,10 +368,11 @@
# Returns the total size of the set using SCARD.
def size
execute { |key| db.scard(key) }
end
+ alias :count :size
# Syntactic sugar for `sort_by` or `sort` when you only need the
# first element.
#
# Example:
@@ -303,132 +425,21 @@
namespace["*->%s" % att]
end
end
end
- class List < Struct.new(:key, :namespace, :model)
- include PipelinedFetch
- include Enumerable
+ class Set < BasicSet
+ attr :key
+ attr :namespace
+ attr :model
- # Returns the total size of the list using LLEN.
- def size
- db.llen(key)
+ def initialize(key, namespace, model)
+ @key = key
+ @namespace = namespace
+ @model = model
end
- # Returns the first element of the list using LINDEX.
- def first
- model[db.lindex(key, 0)]
- end
-
- # Returns the last element of the list using LINDEX.
- def last
- 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
- # elements of the List since there is no command in Redis that
- # allows you to actually check the list contents efficiently.
- #
- # You may want to avoid doing this if your list has say, 10K entries.
- def include?(model)
- ids.include?(model.id.to_s)
- end
-
- # Replace all the existing elements of a list with a different
- # collection of models. This happens atomically in a MULTI-EXEC
- # block.
- #
- # Example:
- #
- # user = User.create
- # p1 = Post.create
- # user.posts.push(p1)
- #
- # p2, p3 = Post.create, Post.create
- # user.posts.replace([p2, p3])
- #
- # user.posts.include?(p1)
- # # => false
- #
- def replace(models)
- ids = models.map { |model| model.id }
-
- model.db.multi do
- db.del(key)
- ids.each { |id| db.rpush(key, id) }
- end
- end
-
- # Fetch the data from Redis in one go.
- def to_a
- fetch(ids)
- end
-
- def each
- to_a.each { |element| yield element }
- end
-
- def empty?
- size == 0
- end
-
- # Pushes the model to the _end_ of the list using RPUSH.
- def push(model)
- db.rpush(key, model.id)
- end
-
- # Pushes the model to the _beginning_ of the list using LPUSH.
- def unshift(model)
- db.lpush(key, model.id)
- end
-
- # Delete a model from the list.
- #
- # Note: If your list contains the model multiple times, this method
- # will delete all instances of that model in one go.
- #
- # Example:
- #
- # class Comment < Ohm::Model
- # end
- #
- # class Post < Ohm::Model
- # list :comments, Comment
- # end
- #
- # p = Post.create
- # c = Comment.create
- #
- # p.comments.push(c)
- # p.comments.push(c)
- #
- # p.comments.delete(c)
- #
- # p.comments.size == 0
- # # => true
- #
- def delete(model)
- # LREM key 0 <id> means remove all elements matching <id>
- # @see http://redis.io/commands/lrem
- db.lrem(key, 0, model.id)
- end
-
- private
- def ids
- db.lrange(key, 0, -1)
- end
-
- def db
- model.db
- end
- end
-
- class Set < Struct.new(:key, :namespace, :model)
- include Collection
-
# Chain new fiters on an existing set.
#
# Example:
#
# set = User.find(:name => "John")
@@ -545,11 +556,19 @@
# # => true
#
# User.find(:name => "John", :age => 30).kind_of?(Ohm::MultiSet)
# # => true
#
- class MultiSet < Struct.new(:namespace, :model, :command)
- include Collection
+ class MultiSet < BasicSet
+ attr :namespace
+ attr :model
+ attr :command
+
+ def initialize(namespace, model, command)
+ @namespace = namespace
+ @model = model
+ @command = command
+ end
# Chain new fiters on an existing set.
#
# Example:
#