Created
April 17, 2011 18:09
-
-
Save antirez/924301 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'json' | |
require 'redis' | |
class RedisComments | |
def initialize(redis,namespace,sort_proc=nil) | |
@r = redis | |
@namespace = namespace | |
@sort_proc = sort_proc | |
end | |
def thread_key(thread_id) | |
"thread:#{@namespace}:#{thread_id}" | |
end | |
def insert(thread_id,comment) | |
raise "no parent_id field" if !comment.has_key?('parent_id') | |
key = thread_key(thread_id) | |
id = @r.hincrby(key,:nextid,1) | |
@r.hset(key,id,comment.to_json) | |
return id.to_i | |
end | |
def edit(thread_id,comment_id,comment) | |
key = thread_key(thread_id) | |
old = @r.hget(key,id) | |
return false if !old | |
comment['parent_id'] = JSON.parse(old)['parent_id'] | |
@r.hset(key,id,comment.to_json) | |
return true | |
end | |
def remove_thread(thread_id) | |
@r.del(thread_key(thread_id)) | |
end | |
def comments_in_thread(thread_id) | |
@r.hlen(thread_key(thread_id)).to_i-1 | |
end | |
def del_comment(thread_id,comment_id) | |
# TODO? You may want to make sure there are no parents. | |
# If there are parents we can call edit() with "comment removed" | |
# or something like that. | |
# | |
# A probably wiser implementation is to *never* use this method | |
# and instead flag the comment as deleted. Then when rendering we | |
# can display it in a special way if there ara replies, otherwise | |
# we can avoid displaying deleted comments that are leafs. | |
@r.hdel(thread_key(thread_id),comment_id) | |
end | |
def render_comments(thread_id,&block) | |
byparent = {} | |
@r.hgetall(thread_key(thread_id)).each{|id,comment| | |
next if id == "nextid" | |
c = JSON.parse(comment) | |
c['id'] = id.to_i | |
parent_id = c['parent_id'].to_i | |
byparent[parent_id] = [] if !byparent.has_key?(parent_id) | |
byparent[parent_id] << c | |
} | |
render_comments_rec(byparent,-1,0,block) | |
end | |
def render_comments_rec(byparent,parent_id,level,block) | |
thislevel = byparent[parent_id] | |
thislevel = @sort_proc.call(thislevel,level) if @sort_proc | |
thislevel.each{|c| | |
c['level'] = level | |
block.call(c) | |
if byparent[c['id']] | |
render_comments_rec(byparent,c['id'],level+1,block) | |
end | |
} | |
end | |
end | |
# In this example we want comments at top level sorted in reversed chronological | |
# order, but all the sub trees sorted in plain chronological order. | |
comments = RedisComments.new(Redis.new,"mycomments",proc{|c,level| | |
if level == 0 | |
c.sort {|a,b| b['ctime'] <=> a['ctime']} | |
else | |
c.sort {|a,b| a['ctime'] <=> b['ctime']} | |
end | |
}) | |
comments.remove_thread(50) | |
first_id = comments.insert(50, | |
{'body' => 'First comment at top level','parent_id'=>-1,'ctime'=>1000} | |
) | |
second_id = comments.insert(50, | |
{'body' => 'Second comment at top level','parent_id'=>-1,'ctime'=>1001} | |
) | |
id = comments.insert(50, | |
{'body' => 'reply number one','parent_id'=>second_id,'ctime'=>1002} | |
) | |
id = comments.insert(50, | |
{'body' => 'reply to reply','parent_id'=>id,'ctime'=>1003} | |
) | |
id = comments.insert(50, | |
{'body' => 'reply number two','parent_id'=>second_id,'ctime'=>1002} | |
) | |
rendered_comments = comments.render_comments(50) {|c| | |
puts (" "*c['level']) + c['body'] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment