Skip to content

Instantly share code, notes, and snippets.

@gciampa
Forked from antirez/gist:924301
Created April 17, 2011 19:39
Show Gist options
  • Select an option

  • Save gciampa/924408 to your computer and use it in GitHub Desktop.

Select an option

Save gciampa/924408 to your computer and use it in GitHub Desktop.

Revisions

  1. @antirez antirez renamed this gist Apr 17, 2011. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. @antirez antirez created this gist Apr 17, 2011.
    110 changes: 110 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,110 @@
    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']
    }