philosophy.rb |
|
|---|---|
Internals: Nest and the Ohm Philosophy |
|
Ohm does not want to hide Redis from you |
|
|
In contrast to the usual philosophy of ORMs in the wild, Ohm actually just provides a basic object mapping where you can safely tuck away attributes and declare grouping of data. Beyond that, Ohm doesn’t try to hide Redis, but rather exposes it in a simple way, through key hierarchies provided by the library Nest. |
|
|
Let’s require |
require "ohm"
require "ohm/contrib" |
|
Let’s quickly declare our In addition we specify our |
class Post < Ohm::Model
include Ohm::Callbacks
attribute :title
index :title
list :comments, Comment |
|
This is one example of using the underlying library Note: Since |
def self.latest
key[:latest].zrevrange(0, -1).map(&Post)
end |
|
Here we just quickly push this instance of |
protected
def after_save
self.class.key[:latest].zadd(Time.now.to_i, id)
end |
|
Since we add every In this case we use the raw Redis command ZREM. |
def after_delete
self.class.key[:latest].zrem(id)
end
end |
|
Now let’s quickly define our |
class Comment < Ohm::Model
end |
Test it out |
|
|
For this example, we’ll use Cutest for our testing framework. |
require "cutest" |
|
To make it simple, we also ensure that every test run has a clean Redis instance. |
prepare { Ohm.flush } |
|
Now let’s create Post. |
setup { Post.create } |
|
We then verify the behavior for our |
test "created post is inserted into latest" do |p|
assert [p.id] == Post.key[:latest].zrange(0, -1)
end |
|
And it should automatically be removed from it as soon as we delete our
|
test "deleting the created post removes it from latest" do |p|
p.delete
assert Post.key[:latest].zrange(0, -1).empty?
end |
|
You might be curious what happens when we do |
test "querying Post:all using raw Redis commands" do |p|
assert [p.id] == Post.key[:all].smembers
assert [p] == Post.key[:all].smembers.map(&Post)
end |
Understanding
|
|
|
Let’s pop the hood and see how we can do LIST operations on our
|
|
|
Getting the current size of our comments is just a wrapper for LLEN. |
test "checking the number of comments for a given post" do |p|
assert 0 == p.comments.key.llen
assert 0 == p.comments.size
end |
|
Also, pushing a comment to our |
test "pushing a Comment manually and checking for its presence" do |p|
comment = Comment.create
p.comments.key.rpush(comment.id)
assert [comment.id] == p.comments.key.lrange(0, -1)
end |
|
Now for some interesting judo |
test "now what if we want to find all Ohm or Redis posts" do
ohm = Post.create(:title => "Ohm")
redis = Post.create(:title => "Redis") |
|
Let’s first choose an arbitrary key name to hold our |
ohm_redis = Post.key.volatile["ohm-redis"] |
|
A volatile key just simply means it will be prefixed with a |
assert "~:Post:ohm-redis" == ohm_redis |
|
Finding all Ohm or Redis posts now will just be a call to
SUNIONSTORE
on our volatile |
ohm_redis.sunionstore(
Post.index_key_for(:title, "Ohm"),
Post.index_key_for(:title, "Redis")
) |
|
And voila, they have been found! |
assert [ohm.id, redis.id] == ohm_redis.smembers.sort
end |
The command reference is your friend |
|
|
If you invest a little time reading through all the different Redis commands, I’m pretty sure you will enjoy your experience hacking with Ohm, Nest and Redis a lot more. |
|