Skip to content

Instantly share code, notes, and snippets.

@Loupi
Created May 25, 2012 15:37
Show Gist options
  • Save Loupi/2788831 to your computer and use it in GitHub Desktop.
Save Loupi/2788831 to your computer and use it in GitHub Desktop.
Redis nested comments in C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using ServiceStack.Redis;
namespace RedisNestedComments
{
public class CommentsRepository
{
readonly IRedisClientsManager _RedisFactory;
public CommentsRepository(IRedisClientsManager redisFactory)
{
_RedisFactory = redisFactory;
}
public string Save(string itemId, string comment, string parentId = null)
{
CommentModel data;
using (var redis = _RedisFactory.GetClient())
{
var now = DateTime.UtcNow.ToFileTimeUtc();
var id = redis.Increment("1", 1);
data = new CommentModel(){Id = id, Comment = comment, Time = DateTime.UtcNow};
var k = parentId != null ? SubCommentsKey(parentId) : CommentsKey(itemId);
redis.Remove(JsonKey(itemId));
redis.AddItemToSortedSet(k, id.ToString(), now);
redis.StoreAsHash(data);
}
return data.Id.ToString();
}
public List<NestedComment> Get(string itemId)
{
List<NestedComment> result = null;
using (var redis = _RedisFactory.GetReadOnlyClient())
{
var jsonId = JsonKey(itemId);
var jsonComments = redis.Get<byte[]>(jsonId);
var xs = new XmlSerializer(typeof(List<NestedComment>));
if (jsonComments == null)
{
result = MultiFetch(CommentsKey(itemId), redis);
using (var ms = new MemoryStream())
{
xs.Serialize(ms, result);
redis.Set(jsonId, ms.ToArray());
}
}
else
{
using (var ms = new MemoryStream(jsonComments))
{
result = xs.Deserialize(ms) as List<NestedComment>;
}
}
}
return result;
}
public List<NestedComment> Leaf(string id)
{
List<NestedComment> result = null;
using (var redis = _RedisFactory.GetReadOnlyClient())
{
var nestedComment = new NestedComment(redis.GetFromHash<CommentModel>(CommentKey(id)));
nestedComment.SubComments = MultiFetch(SubCommentsKey(id), redis);
}
return result;
}
public void Delete(IList<NestedComment> comments, string parentId, string itemId, bool isMainThread = false)
{
using (var redis = _RedisFactory.GetClient())
{
InnerDelete(comments, parentId, isMainThread, redis);
redis.Remove(JsonKey(itemId));
}
}
List<NestedComment> MultiFetch(string keyName, IRedisClient redis)
{
var result = new List<CommentModel>();
var commentIds = redis.GetRangeFromSortedSet(keyName, 0, -1);
foreach (var commentId in commentIds)
{
result.Add(redis.GetFromHash<CommentModel>(commentId));
}
return ProcessComments(result, redis);
}
List<NestedComment> ProcessComments(IList<CommentModel> comments, IRedisClient redis)
{
var result = new List<NestedComment>();
foreach (var comment in comments)
{
var nestedComment = new NestedComment(comment);
var subCommentsId = SubCommentsKey(comment.Id.ToString());
if (redis.GetSortedSetCount(subCommentsId) > 0)
{
nestedComment.SubComments = MultiFetch(subCommentsId, redis);
}
result.Add(nestedComment);
}
return result;
}
void InnerDelete(IList<NestedComment> comments, string parentId, bool isMainThread, IRedisClient redis)
{
foreach (var comment in comments)
{
InnerDelete(comment, parentId, isMainThread, redis);
}
}
void InnerDelete(NestedComment comment, string parentId, bool isMainThread, IRedisClient redis)
{
var id = comment.Comment.Id.ToString();
var k = isMainThread ? CommentKey(parentId) : SubCommentsKey(parentId);
redis.Remove(CommentKey(id));
redis.RemoveItemFromSortedSet(k, id);
if (comment.SubComments != null)
InnerDelete(comment.SubComments, id, false, redis);
}
string JsonKey(string id)
{
return string.Format("comment:{0}:json", id);
}
string CommentKey(string id)
{
return string.Format("comment:{0}", id);
}
string CommentsKey(string id)
{
return string.Format("comments:{0}", id);
}
string SubCommentsKey(string id)
{
return string.Format("comment:{0}:sub", id);
}
}
public class CommentModel
{
public long Id {get; set;}
public DateTime Time {get; set;}
public string Comment {get; set;}
}
public class NestedComment
{
public NestedComment()
{
}
public NestedComment(CommentModel comment)
{
this.Comment = comment;
}
public CommentModel Comment { get; set; }
public List<NestedComment> SubComments { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment