private List <QuestionResult> ToQuestionResults(IEnumerable <Question> questions)
        {
            var uniqueUserIds = questions.Map(x => x.UserId).ToHashSet();
            var usersMap      = GetUsersByIds(uniqueUserIds).ToDictionary(x => x.Id);

            var results = questions.Map(x => new QuestionResult {
                Question = x
            });
            var resultsMap = results.ToDictionary(q => q.Question.Id);

            results.ForEach(x => x.User = usersMap[x.Question.UserId]);

            //Batch multiple operations in a single pipelined transaction (i.e. for a single network request/response)
            RedisManager.ExecTrans(trans =>
            {
                foreach (var question in questions)
                {
                    var q = question;

                    trans.QueueCommand(r => r.GetSetCount(QuestionUserIndex.UpVotes(q.Id)),
                                       voteUpCount => resultsMap[q.Id].VotesUpCount = voteUpCount);

                    trans.QueueCommand(r => r.GetSetCount(QuestionUserIndex.DownVotes(q.Id)),
                                       voteDownCount => resultsMap[q.Id].VotesDownCount = voteDownCount);

                    trans.QueueCommand(r => r.As <Question>().GetRelatedEntitiesCount <Answer>(q.Id),
                                       answersCount => resultsMap[q.Id].AnswersCount = answersCount);
                }
            });

            return(results);
        }
        public QuestionStat GetQuestionStats(long questionId)
        {
            using var redis = RedisManager.GetReadOnlyClient();
            var result = new QuestionStat
            {
                VotesUpCount   = redis.GetSetCount(QuestionUserIndex.UpVotes(questionId)),
                VotesDownCount = redis.GetSetCount(QuestionUserIndex.DownVotes(questionId))
            };

            result.VotesTotal = result.VotesUpCount - result.VotesDownCount;
            return(result);
        }
        public void VoteQuestionDown(long userId, long questionId)
        {
            //Populate Question => User and User => Question set indexes in a single transaction
            RedisManager.ExecTrans(trans =>
            {
                //Register downvote against question and remove any upvotes if any
                trans.QueueCommand(redis => redis.AddItemToSet(QuestionUserIndex.DownVotes(questionId), userId.ToString()));
                trans.QueueCommand(redis => redis.RemoveItemFromSet(QuestionUserIndex.UpVotes(questionId), userId.ToString()));

                //Register downvote against user and remove any upvotes if any
                trans.QueueCommand(redis => redis.AddItemToSet(UserQuestionIndex.DownVotes(userId), questionId.ToString()));
                trans.QueueCommand(redis => redis.RemoveItemFromSet(UserQuestionIndex.UpVotes(userId), questionId.ToString()));
            });
        }