Created
May 22, 2012 01:54
-
-
Save Loupi/2766062 to your computer and use it in GitHub Desktop.
Redis Nested Comments in Ruby
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 'redis' | |
require 'json' | |
class CommentsRepository | |
def initialize | |
@redis = Redis.new | |
end | |
def save(itemId, comment, parentId = nil) | |
now = Time.now.utc.to_i | |
id = @redis.incr(1) | |
comment = {id: id, time: now}.merge(comment) | |
k = parentId ? sub_comments_key(parentId) : comments_key(itemId) | |
@redis.multi { |multi| | |
multi.del json_key(itemId) | |
multi.hmset comment_key(id), comment.map { |k,v| [k,v] }.flatten(1) | |
multi.zadd k, now, id | |
} | |
id | |
end | |
def get(id) | |
jsonId = json_key(id) | |
jsonComments = @redis.get(jsonId) | |
if jsonComments | |
comments = JSON.parse(jsonComments) | |
else | |
comments = multi_fetch(comments_key(id)) | |
@redis.set jsonId, comments.to_json | |
end | |
comments | |
end | |
def leaf(id) | |
comment = @redis.hgetall(comment_key(id)) | |
comment['comments'] = multi_fetch(sub_comments_key(id)) | |
comment | |
end | |
def delete(comment, parentId, itemId, isMainThread = true) | |
@redis.multi { |multi| | |
inner_delete comment, parentId, isMainThread, multi | |
multi.del json_key(itemId) | |
} | |
end | |
private | |
def multi_fetch(key) | |
commentIds = @redis.zrange(key, 0, -1) | |
comments = @redis.multi { |multi| | |
commentIds.map { |id| multi.hgetall(comment_key(id)) } | |
} | |
process_comments(comments) | |
end | |
def process_comments(comments) | |
comments.each { |comment| | |
subCommentsId = sub_comments_key(comment['id']) | |
if @redis.zcard(subCommentsId) > 0 | |
comment['comments'] = multi_fetch(subCommentsId) | |
end | |
} | |
end | |
def inner_delete(comment, parentId, isMainThread, multi) | |
if comment.kind_of?(Array) | |
comment.each {|c| inner_delete c, parentId, isMainThread, multi} | |
else | |
id = comment['id'] | |
comments = comment['comments'] | |
k = isMainThread ? comments_key(parentId) : sub_comments_key(parentId) | |
multi.del comment_key(id) | |
multi.zrem k, id | |
inner_delete comments, id, false, multi if comments | |
end | |
end | |
def json_key(id) | |
"comment:#{id}:json" | |
end | |
def comment_key(id) | |
"comment:#{id}" | |
end | |
def comments_key(id) | |
"comments:#{id}" | |
end | |
def sub_comments_key(id) | |
"comment:#{id}:sub" | |
end | |
end |
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 'optparse' | |
require './nested-redis' | |
options = {} | |
COMMANDS = {save: 1, delete: 2, print: 3, leaf: 4, remove: 5, dummy: 6} | |
FORMATS = {text: 1, json: 2, pretty_json:3} | |
optparse = OptionParser.new { |opts| | |
opts.banner = "Usage: redis-cmd.rb command [options]" | |
opts.on('-s', '--save item, parent, comment', Array, | |
'Save a comment on an item.') { |itemId, parentId, comment| | |
options[:command] = COMMANDS[:save] | |
options[:itemId] = itemId | |
options[:parentId] = parentId if parentId != '0' | |
options[:comment] = comment | |
} | |
opts.on('-p', '--print itemId', | |
'Print the comment hierarchy of an item.') { |itemId| | |
options[:command] = COMMANDS[:print] | |
options[:itemId] = itemId | |
options[:format] = FORMATS[:text] | |
} | |
opts.on('-l', '--leaf leafId', | |
'Print the hierarchy of a leaf.') { |leafId| | |
options[:command] = COMMANDS[:leaf] | |
options[:itemId] = leafId | |
options[:format] = FORMATS[:text] | |
} | |
opts.on('-d', '--delete itemId', | |
'Delete all the comments of an item.') { |itemId| | |
options[:command] = COMMANDS[:delete] | |
options[:itemId] = itemId | |
} | |
opts.on('-r', '--remove item, leaf, parent', Array, | |
'Delete a leaf and it\'s hierarchy from a comment.') { |itemId, leafId, parentId| | |
options[:command] = COMMANDS[:remove] | |
options[:itemId] = itemId | |
options[:leafId] = leafId | |
options[:parentId] = parentId | |
} | |
opts.on('-u', '--dummy itemId', | |
'Save a dummy comment hierarchy on an item.') { |itemId| | |
options[:command] = COMMANDS[:dummy] | |
options[:itemId] = itemId | |
} | |
opts.on('-j', '--json [pretty]', 'Set the output format to JSON.') { |pretty| | |
options[:format] = pretty ? FORMATS[:pretty_json] : FORMATS[:json] | |
} | |
opts.on( '-h', '--help', 'Display this screen' ) { | |
puts opts | |
exit | |
} | |
} | |
def print_comments(comments, tabs = 0) | |
comments.each { |comment| | |
tabs.times { putc "\t" } | |
puts "#{comment['comment']}" | |
if comment['comments'] | |
print_comments comment['comments'], tabs + 1 | |
end | |
} | |
end | |
def save_dummy(cr, id) | |
tree = cr.save(id, { comment:'Tree', test:1 }) | |
root = cr.save(id, { comment:'Root', kind:'ginger', age:50 }, tree) | |
trunk = cr.save(id, { comment:'Trunk', kmh_to_mph:0.621 }, tree) | |
branch = cr.save(id, { comment:'Branch' }, trunk) | |
leaf = cr.save(id, { comment:'Leaf' }, branch) | |
top = cr.save(id, { comment:'Top' }, tree) | |
end | |
def print_result comments, options | |
case options[:format] | |
when FORMATS[:text] | |
print_comments comments | |
when FORMATS[:json] | |
puts comments.to_json | |
when FORMATS[:pretty_json] | |
puts JSON.pretty_generate(comments) | |
end | |
end | |
optparse.parse! | |
id = options[:itemId] | |
cr = CommentsRepository.new | |
case options[:command] | |
when COMMANDS[:save] | |
comment = { comment: options[:comment] } | |
id = cr.save(id, comment, options[:parentId]) | |
puts "New comment saved with id #{id}." | |
when COMMANDS[:print] | |
print_result cr.get(id), options | |
when COMMANDS[:leaf] | |
print_result [cr.leaf(id)], options | |
when COMMANDS[:delete] | |
cr.delete cr.get(id), id, id | |
when COMMANDS[:remove] | |
cr.delete cr.leaf(options[:leafId]), options[:parentId], id, false | |
when COMMANDS[:dummy] | |
save_dummy cr, id | |
else | |
puts optparse | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage:
ruby redis-cmd.rb -u 2
ruby redis-cmd.rb -p 2 -j
ruby redis-cmd.rb -s 1,0,"Comment #1"
ruby redis-cmd.rb -s 1,0,"Comment #2"
ruby redis-cmd.rb -p 1
ruby redis-cmd.rb -s 1,1,"Sub comment #1"
ruby redis-cmd.rb -p 1 -j 1
ruby redis-cmd.rb -r 1,3,1
ruby redis-cmd.rb -p 1 -j 1
ruby redis-cmd.rb -d 1