public async Task<BatchSet> GetChanges(string bucketName, Filter query, int limit, string anchor, string uploadAnchor)
        {
           
          
            var db = client.GetDatabase("local");

            var collection = db.GetCollection<BsonDocument>("oplog.rs");
            var filterBuilder = Builders<BsonDocument>.Filter;
            FilterDefinition<BsonDocument> filter = filterBuilder.Eq("ns", DbName + "." + bucketName);
            if (anchor != null)
            {
                filter = filter & filterBuilder.Gt("ts", new BsonTimestamp(Convert.ToInt64(anchor)));
            }
            var docs = await collection.Find(filter).Limit(limit).ToListAsync();
            BatchSet bs = new BatchSet();
            SyncLogItem logItem = null;
            if (docs != null && docs.Count > 0 && !string.IsNullOrEmpty(uploadAnchor))
            {
                logItem = await GetSyncLogItem(uploadAnchor);
            }

            int i = 0;
            foreach (var doc in docs)
            {

                if (i == docs.Count - 1)
                {
                    bs.Anchor = doc["ts"].AsBsonTimestamp.ToString();
                }
                i++;
                if (doc["op"] == "i" || doc["op"] == "u")
                {
                    this.AddChangedDoc(bs, doc, logItem, query);
                }
                else if (doc["op"] == "d")
                {
                    this.AddDeletedDoc(bs, doc, logItem);
                }


            }
            return bs;
        }
        private bool OutOfFilter(Filter query, BsonDocument nestedDoc)
        {
            if (query == null)
                return false;
            string tagName = query.TagName;
            if (query.TagName == "key")
            {
                tagName = "_id";
            }
            if (!nestedDoc.Names.Contains(tagName))
            {
                return true;
            }

            IComparable docValue = (IComparable)BsonTypeMapper.MapToDotNetValue(nestedDoc[tagName]);
            if (query.Value != null && docValue.CompareTo((IComparable)query.Value) != 0)
            {
                return true;
            }
            if (query.Start != null && docValue.CompareTo((IComparable)query.Start) < 0)
                return true;
            if (query.End != null && docValue.CompareTo((IComparable)query.End) > 0)
                return true;


            return false;
        }
        private void AddChangedDoc(BatchSet bs, BsonDocument doc, SyncLogItem logItem, Filter query)
        {

            if (bs.ChangedDocuments == null)
                bs.ChangedDocuments = new List<SiaqodbDocument>();

            var nestedDoc = doc["o"].AsBsonDocument;
            if (logItem != null && logItem.KeyVersion != null && logItem.KeyVersion.ContainsKey(nestedDoc["_id"].AsString) && logItem.KeyVersion[nestedDoc["_id"].AsString] == nestedDoc["_rev"].AsString)
                return;
            if (OutOfFilter(query, nestedDoc))
                return;
            SiaqodbDocument siaqodbDoc = Mapper.ToSiaqodbDocument(nestedDoc);
            bs.ChangedDocuments.Add(siaqodbDoc);

        }
        private bool OutOfFilter(Filter query, CouchDBDocument co)
        {
            if (query == null)
                return false;
            string tagName = query.TagName;
            if (query.TagName == "key")
            {
                tagName = "_id";
            }
            else if (!co.tags.Keys.Contains(tagName))
            {
                return true;
            }
            IComparable docValue = null;
            if (query.TagName == "key")
            {
                docValue = co._id;
            }
            else
            {
                docValue = co.tags[tagName] as IComparable;
            }
            
            if (query.Value != null && docValue.CompareTo((IComparable)query.Value) != 0)
            {
                return true;
            }
            if (query.Start != null && docValue.CompareTo((IComparable)query.Start) < 0)
                return true;
            if (query.End != null && docValue.CompareTo((IComparable)query.End) > 0)
                return true;


            return false;
        }
 private void AddChangedDoc(BatchSet changeSet, ChangesResponse<string>.Row row, SyncLogItem logItem, Filter query, MyCouch.Serialization.ISerializer serializer)
 {
     if (changeSet.ChangedDocuments == null)
         changeSet.ChangedDocuments = new List<SiaqodbDocument>();
     CouchDBDocument co = serializer.Deserialize<CouchDBDocument>(row.IncludedDoc);
     if (co._id.StartsWith("_design/"))
         return;
     //check uploaded anchor- means cliet just uploaded this record and we should not return back
     if (logItem != null && logItem.KeyVersion != null && logItem.KeyVersion.ContainsKey(co._id) && logItem.KeyVersion[co._id] == co._rev)
         return;
     if (OutOfFilter(query, co))
         return;
     changeSet.ChangedDocuments.Add(Mapper.ToSiaqodbDocument(co));
 }
        public async Task<BatchSet> GetChanges(string bucketName, Filter query, int limit, string anchor,string uploadAnchor)
        {
            using (var client = new MyCouchClient(DbServerUrl, bucketName))
            {
                
                GetChangesRequest changesReq = new GetChangesRequest();
                changesReq.Since = anchor;
                changesReq.Limit = limit;
                changesReq.IncludeDocs = true;
                var response = await client.Changes.GetAsync(changesReq);
                if (response.IsSuccess)
                {
                    BatchSet changeSet = new BatchSet();
                    if (response.Results != null)
                    {
                        SyncLogItem logItem = await this.GetSyncLogItem(uploadAnchor);

                        foreach (var row in response.Results)
                        {

                            if (row.Deleted)
                            {
                                this.AddDeletedDoc(changeSet, row, logItem);
                            }
                            else
                            {
                                this.AddChangedDoc(changeSet, row, logItem, query,client.Serializer );
                            }
                        }
                        changeSet.Anchor = response.LastSeq;
                    }

                    return changeSet;
                }
                else CheckBucketNotFound(bucketName, response);
                return null;

            }
        
        }