private string SerializeContinuationQuery(LeaderboardContinuationQuery query)
        {
            var json = Newtonsoft.Json.JsonConvert.SerializeObject(query);

            return(System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(json)));
        }
        public async Task <LeaderboardResult <ScoreRecord> > Query(LeaderboardQuery rq)
        {
            var isContinuation = rq is LeaderboardContinuationQuery;
            var client         = await CreateClient(rq);

            ScoreRecord start = null;

            if (!string.IsNullOrEmpty(rq.StartId))
            {
                start = await GetScore(rq.StartId, rq.Name);

                if (start == null)
                {
                    throw new ClientException("Admiral not found in leadeboard.");
                }
            }

            var result = await client.SearchAsync <ScoreRecord>(s =>
            {
                s = s.AllowNoIndices();
                s = s.Query(query => CreateQuery(query, rq, q =>
                {
                    if (start != null)//If we have a pivot we must add constraint to start the result around it.
                    {
                        //Create next/previous additional constraints
                        if ((rq as LeaderboardContinuationQuery)?.IsPrevious == true)
                        {
                            return(CreatePreviousPaginationFilter(q, start));
                        }
                        else
                        {
                            return(CreateNextPaginationFilter(q, start));
                        }
                    }
                    else
                    {
                        return(q);
                    }
                })).AllowNoIndices();

                if ((rq as LeaderboardContinuationQuery)?.IsPrevious == true)
                {
                    s = s.Sort(sort => sort.Ascending(record => record.Score).Descending(record => record.CreatedOn));
                }
                else
                {
                    s = s.Sort(sort => sort.Descending(record => record.Score).Ascending(record => record.CreatedOn));
                }
                if ((isContinuation && (rq as LeaderboardContinuationQuery)?.IsPrevious == false) || start == null)
                {
                    s = s.Size(rq.Count + 1).From(rq.Skip);// We get one more document  than necessary to be able to determine if we can build a "next" continuation
                }
                else// The pivot is not included in the result set, if we are not running a continuation query, we must prefix the results with the pivot.
                {
                    s = s.Size(rq.Count).From(rq.Skip);
                }


                return(s);
            });

            if (!result.IsValid)
            {
                if (result.ServerError.Status == 404)
                {
                    return(new LeaderboardResult <ScoreRecord> {
                        Results = new List <LeaderboardRanking <ScoreRecord> >()
                    });
                }
                _logger.Log(LogLevel.Error, "leaderboard", "failed to process query request.", result.ServerError);
                throw new InvalidOperationException($"Failed to query leaderboard : {result.ServerError.Error.Reason}");
            }
            var documents = result.Documents.ToList();

            if (!isContinuation && start != null)
            {
                documents.Insert(0, start);
            }
            else if ((rq as LeaderboardContinuationQuery)?.IsPrevious == true)
            {
                documents.Reverse();
            }

            //Compute rankings
            if (documents.Any())
            {
                int firstRank = 0;
                try
                {
                    firstRank = (int) await GetRanking(documents.First(), rq, rq.Name);
                }
                catch (InvalidOperationException ex)
                {
                    _logger.Log(LogLevel.Error, "leaderboard", ex.Message, ex);
                    throw new InvalidOperationException($"Failed to query leaderboard : {ex.Message}");
                }
                var rank      = firstRank;
                var lastScore = int.MaxValue;
                var lastRank  = firstRank;
                var results   = new List <LeaderboardRanking <ScoreRecord> >();


                foreach (var doc in documents.Take(rq.Count))
                {
                    if (EnableExequo)
                    {
                        int currentRank;
                        if (doc.Score == lastScore)
                        {
                            currentRank = lastRank;
                        }
                        else
                        {
                            currentRank = rank;
                        }

                        results.Add(new LeaderboardRanking <ScoreRecord> {
                            Document = doc, Ranking = currentRank
                        });
                        lastRank = currentRank;
                    }
                    else
                    {
                        results.Add(new LeaderboardRanking <ScoreRecord> {
                            Document = doc, Ranking = rank
                        });
                    }
                    rank++;
                }


                var leaderboardResult = new LeaderboardResult <ScoreRecord> {
                    Results = results
                };

                if (firstRank > 1)//There are scores before the first in the list
                {
                    var previousQuery = new LeaderboardContinuationQuery(rq);
                    previousQuery.Skip         = 0;
                    previousQuery.Count        = rq.Count;
                    previousQuery.IsPrevious   = true;
                    previousQuery.StartId      = results.First().Document.Id;
                    leaderboardResult.Previous = SerializeContinuationQuery(previousQuery);
                }

                if (documents.Count > rq.Count || (rq as LeaderboardContinuationQuery)?.IsPrevious == true)//there are scores after the last in the list.
                {
                    var nextQuery = new LeaderboardContinuationQuery(rq);
                    nextQuery.Skip         = 0;
                    nextQuery.Count        = rq.Count;
                    nextQuery.IsPrevious   = false;
                    nextQuery.StartId      = results.Last().Document.Id;
                    leaderboardResult.Next = SerializeContinuationQuery(nextQuery);
                }

                return(leaderboardResult);
            }
            else
            {
                return(new LeaderboardResult <ScoreRecord>());
            }
        }