public void TestIndexVersion()
        {
            RunTestVariants(() => {
                CreateIndex();

                // Reopen view with same version string:
                LiteCoreBridge.Check(err => Native.c4view_close(_view, err));
                Native.c4view_free(_view);

                _view = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "myview", "1",
                                                                                 Native.c4db_getConfig(Db), err));
                Native.c4view_getTotalRows(_view).Should().Be(200, "because the view information should survive reopening");
                Native.c4view_getLastSequenceIndexed(_view).Should().Be(100, "because the view information should survive reopening");
                Native.c4view_getLastSequenceChangedAt(_view).Should().Be(100, "because the view information should survive reopening");

                // Reopen view with different version string:
                LiteCoreBridge.Check(err => Native.c4view_close(_view, err));
                Native.c4view_free(_view);

                _view = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "myview", "2",
                                                                                 Native.c4db_getConfig(Db), err));
                Native.c4view_getTotalRows(_view).Should().Be(0, "because the view information should be erased");
                Native.c4view_getLastSequenceIndexed(_view).Should().Be(0, "because the view information should be erased");
                Native.c4view_getLastSequenceChangedAt(_view).Should().Be(0, "because the view information should be erased");
            });
        }
Example #2
0
        private C4View *OpenIndexWithOptions(C4DatabaseFlags options, bool dryRun = false)
        {
            if (_indexDB == null)
            {
                _indexDB = (C4View *)ForestDBBridge.Check(err =>
                {
                    var encryptionKey = default(C4EncryptionKey);
                    if (_dbStorage.EncryptionKey != null)
                    {
                        encryptionKey = new C4EncryptionKey(_dbStorage.EncryptionKey.KeyData);
                    }

                    return(Native.c4view_open(_dbStorage.Forest, _path, Name, dryRun  ? "0" : Delegate.MapVersion, options,
                                              &encryptionKey, err));
                });

                if (dryRun)
                {
                    ForestDBBridge.Check(err => Native.c4view_close(_indexDB, err));
                    _indexDB = null;
                }
            }

            return(_indexDB);
        }
Example #3
0
        public override void SetUp()
        {
            base.SetUp();
            C4Error error;

            _view = Native.c4view_open(_db, VIEW_INDEX_PATH, "myview", "1", C4DatabaseFlags.Create, EncryptionKey, &error);
            Assert.IsTrue(_view != null);
        }
        private uint QueryGrouped(C4View *view, C4ReduceFunction reduce, bool verbose = false)
        {
            var options = C4QueryOptions.Default;

            options.reduce     = &reduce;
            options.groupLevel = 1;
            return(RunQuery(view, options, verbose));
        }
Example #5
0
        protected override void SetupVariant(int option)
        {
            base.SetupVariant(option);

            Native.c4view_deleteByName(Db, "geoview", null);
            _view = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "geoview", "1",
                                                                             Native.c4db_getConfig(Db), err));
        }
        private uint IndexLikesView()
        {
            var  likesKey   = Native.FLDictKey_Init("likes", true);
            var  keys       = new[] { Native.c4key_new(), Native.c4key_new(), Native.c4key_new() };
            var  values     = new C4Slice[3];
            uint totalLikes = 0;

            if (_likesView == null)
            {
                _likesView = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "likes",
                                                                                      "1", Native.c4db_getConfig(Db), err));
            }

            var     views   = new[] { _likesView };
            var     indexer = (C4Indexer *)LiteCoreBridge.Check(err => Native.c4indexer_begin(Db, views, err));
            var     e       = (C4DocEnumerator *)LiteCoreBridge.Check(err => Native.c4indexer_enumerateDocuments(indexer, err));
            C4Error error;

            while (Native.c4enum_next(e, &error))
            {
                var doc   = (C4Document *)LiteCoreBridge.Check(err => Native.c4enum_getDocument(e, err));
                var body  = Native.FLValue_AsDict(NativeRaw.FLValue_FromTrustedData((FLSlice)doc->selectedRev.body));
                var likes = Native.FLValue_AsArray(Native.FLDict_GetWithKey(body, &likesKey));

                FLArrayIterator iter;
                Native.FLArrayIterator_Begin(likes, &iter);
                uint nLikes;
                for (nLikes = 0; nLikes < 3; ++nLikes)
                {
                    var like = NativeRaw.FLValue_AsString(Native.FLArrayIterator_GetValue(&iter));
                    if (like.buf == null)
                    {
                        break;
                    }

                    Native.c4key_reset(keys[nLikes]);
                    NativeRaw.c4key_addString(keys[nLikes], (C4Slice)like);
                    Native.FLArrayIterator_Next(&iter);
                }

                totalLikes += nLikes;
                LiteCoreBridge.Check(err => Native.c4indexer_emit(indexer, doc, 0, nLikes, keys, values, err));
                Native.c4doc_free(doc);
            }

            Native.c4enum_free(e);
            error.Code.Should().Be(0, "because otherwise an error occurred somewhere");
            LiteCoreBridge.Check(err => Native.c4indexer_end(indexer, true, err));
            for (uint i = 0; i < 3; i++)
            {
                Native.c4key_free(keys[i]);
            }

            return(totalLikes);
        }
Example #7
0
        private void CloseIndex()
        {
            var indexDB = _indexDB;

            _indexDB = null;
            if (indexDB != null)
            {
                Log.D(TAG, "Closing index");
                ForestDBBridge.Check(err => Native.c4view_close(indexDB, err));
            }
        }
 public static string c4view_fullTextMatched(C4View *view,
                                             string docID,
                                             C4SequenceNumber seq,
                                             uint fullTextID,
                                             C4Error *outError)
 {
     using (var docID_ = new C4String(docID)) {
         using (var retVal = NativeRaw.c4view_fullTextMatched(view, docID_.AsC4Slice(), seq, fullTextID, outError)) {
             return(((C4Slice)retVal).CreateString());
         }
     }
 }
 public static C4QueryEnumerator *c4view_fullTextQuery(C4View *view,
                                                       string queryString,
                                                       string queryStringLanguage,
                                                       C4QueryOptions *c4Options,
                                                       C4Error *outError)
 {
     using (var queryString_ = new C4String(queryString))
         using (var queryStringLanguage_ = new C4String(queryStringLanguage)) {
             return(NativeRaw.c4view_fullTextQuery(view, queryString_.AsC4Slice(), queryStringLanguage_.AsC4Slice(),
                                                   c4Options, outError));
         }
 }
        protected override void TeardownVariant(int option)
        {
            Native.c4view_free(_artistsView);
            _artistsView = null;
            Native.c4view_free(_albumsView);
            _albumsView = null;
            Native.c4view_free(_tracksView);
            _tracksView = null;
            Native.c4view_free(_likesView);
            _likesView = null;
            Native.c4view_free(_statesView);
            _statesView = null;

            base.TeardownVariant(option);
        }
        private void CloseIndex()
        {
#if CONNECTION_PER_THREAD
            var connections = _fdbConnections.Values.ToArray();
            _fdbConnections.Clear();
            foreach (var connection in connections)
            {
                ForestDBBridge.Check(err => Native.c4view_close((C4View *)connection.ToPointer(), err));
            }
#else
            var indexDb = _indexDB;
            _indexDB = null;
            ForestDBBridge.Check(err => Native.c4view_close(indexDb, err));
#endif
        }
        private uint IndexStatesView()
        {
            var  contactKey  = Native.FLDictKey_Init("contact", true);
            var  addressKey  = Native.FLDictKey_Init("address", true);
            var  stateKey    = Native.FLDictKey_Init("state", true);
            var  key         = Native.c4key_new();
            uint totalStates = 0;

            if (_statesView == null)
            {
                _statesView = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "states",
                                                                                       "1", Native.c4db_getConfig(Db), err));
            }

            var     views   = new[] { _statesView };
            var     indexer = (C4Indexer *)LiteCoreBridge.Check(err => Native.c4indexer_begin(Db, views, err));
            var     e       = (C4DocEnumerator *)LiteCoreBridge.Check(err => Native.c4indexer_enumerateDocuments(indexer, err));
            C4Error error;

            while (Native.c4enum_next(e, &error))
            {
                var doc     = (C4Document *)LiteCoreBridge.Check(err => Native.c4enum_getDocument(e, err));
                var body    = Native.FLValue_AsDict(NativeRaw.FLValue_FromTrustedData((FLSlice)doc->selectedRev.body));
                var contact = Native.FLValue_AsDict(Native.FLDict_GetWithKey(body, &contactKey));
                var address = Native.FLValue_AsDict(Native.FLDict_GetWithKey(contact, &addressKey));
                var state   = NativeRaw.FLValue_AsString(Native.FLDict_GetWithKey(address, &stateKey));

                uint nStates = 0;
                if (state.buf != null)
                {
                    Native.c4key_reset(key);
                    NativeRaw.c4key_addString(key, (C4Slice)state);
                    nStates = 1;
                    totalStates++;
                }

                var value = C4Slice.Null;
                LiteCoreBridge.Check(err => Native.c4indexer_emit(indexer, doc, 0, nStates, new[] { key },
                                                                  new[] { value }, err));
                Native.c4doc_free(doc);
            }

            Native.c4enum_free(e);
            error.Code.Should().Be(0, "because otherwise an error occurred somewhere");
            LiteCoreBridge.Check(err => Native.c4indexer_end(indexer, true, err));
            Native.c4key_free(key);
            return(totalStates);
        }
        private uint RunQuery(C4View *view, C4QueryOptions options, bool verbose = false)
        {
            var     allKeys = new List <string>(1200);
            C4Error error;
            var     query = (C4QueryEnumerator *)LiteCoreBridge.Check(err => {
                var localOpts = options;
                return(Native.c4view_query(view, &localOpts, err));
            });

            C4SliceResult keySlice;

            while (Native.c4queryenum_next(query, &error))
            {
                var key = query->key;
                if (Native.c4key_peek(&key) == C4KeyToken.Array)
                {
                    Native.c4key_skipToken(&key);
                    keySlice = NativeRaw.c4key_readString(&key);
                }
                else
                {
                    Native.c4key_peek(&key).Should().Be(C4KeyToken.String, "because otherwise an invalid entry is present");
                    keySlice = NativeRaw.c4key_readString(&key);
                }

                ((long)keySlice.buf).Should().NotBe(0, "because the entry should not be null");
                var keyStr = ((C4Slice)keySlice).CreateString();
                if (verbose)
                {
                    var valStr = query->value.CreateString();
                    Console.Write($"{keyStr} ({valStr}) ");
                }

                allKeys.Add(keyStr);
                Native.c4slice_free(keySlice);
            }

            Native.c4queryenum_free(query);
            if (verbose)
            {
                Console.WriteLine();
            }

            return((uint)allKeys.Count);
        }
Example #14
0
        private bool QueryIndex(C4View *view)
        {
            var e = (C4QueryEnumerator *)LiteCoreBridge.Check(err => Native.c4view_query(view, null, err));

            if (Log)
            {
                Console.Write("{ ");
            }

            ulong   i = 0;
            C4Error error;

            while (Native.c4queryenum_next(e, &error))
            {
                ++i;
                var buf = $"\"doc-{i:D5}\"";
                if (e->docSequence != i)
                {
                    if (Log)
                    {
                        var gotID = e->docID.CreateString();
                        Console.WriteLine();
                        Console.WriteLine($"*** Expected {buf}, got {gotID} ***");
                    }

                    i = e->docSequence;
                    continue;
                }

                Native.c4key_toJSON(&e->key).Should().Be(buf, "because the docID should be correct");
                e->value.Equals(C4Slice.Constant("1234")).Should().BeTrue("because the value should be accurate");
            }

            if (Log)
            {
                Console.Write($"}}queried_to:{i}");
            }

            Native.c4queryenum_free(e);
            error.Code.Should().Be(0, "because otherwise an error occurred somewhere");
            return(i < NumDocs);
        }
        private void IndexTracksView()
        {
            var nameKey = NativeRaw.FLDictKey_Init(FLSlice.Constant("Name"), true);
            var key     = Native.c4key_new();

            C4Error error;

            if (_tracksView == null)
            {
                _tracksView = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "Tracks", "1",
                                                                                       Native.c4db_getConfig(Db), err));
            }

            var views   = new[] { _tracksView };
            var indexer = (C4Indexer *)LiteCoreBridge.Check(err => Native.c4indexer_begin(Db, views, err));

            try {
                var e = (C4DocEnumerator *)LiteCoreBridge.Check(err => Native.c4indexer_enumerateDocuments(indexer, err));
                while (Native.c4enum_next(e, &error))
                {
                    var doc  = Native.c4enum_getDocument(e, &error);
                    var body = Native.FLValue_AsDict(NativeRaw.FLValue_FromTrustedData((FLSlice)doc->selectedRev.body));
                    ((long)body).Should().NotBe(0, "because otherwise the data got corrupted somehow");
                    var name = Native.FLValue_AsString(Native.FLDict_GetWithKey(body, &nameKey));

                    Native.c4key_reset(key);
                    Native.c4key_addString(key, name);

                    var value = C4Slice.Null;
                    LiteCoreBridge.Check(err => Native.c4indexer_emit(indexer, doc, 0, new[] { key }, new[] { value }, err));
                    Native.c4key_reset(key);
                    Native.c4doc_free(doc);
                }

                Native.c4enum_free(e);
                error.Code.Should().Be(0, "because otherwise an error occurred somewhere");
            } finally {
                LiteCoreBridge.Check(err => Native.c4indexer_end(indexer, true, err));
                Native.c4key_free(key);
            }
        }
Example #16
0
        public void TestIndexVersion()
        {
            CreateIndex();

            // Reopen view with same version string:
            var error = default(C4Error);

            Assert.IsTrue(Native.c4view_close(_view, &error));
            _view = Native.c4view_open(_db, VIEW_INDEX_PATH, "myview", "1", C4DatabaseFlags.Create, EncryptionKey, &error);
            Assert.IsTrue(_view != null);

            Assert.AreEqual(200UL, Native.c4view_getTotalRows(_view));
            Assert.AreEqual(100UL, Native.c4view_getLastSequenceIndexed(_view));
            Assert.AreEqual(100UL, Native.c4view_getLastSequenceChangedAt(_view));

            // Reopen view with different version string:
            Assert.IsTrue(Native.c4view_close(_view, &error));
            _view = Native.c4view_open(_db, VIEW_INDEX_PATH, "myview", "2", C4DatabaseFlags.Create, EncryptionKey, &error);
            Assert.IsTrue(_view != null);

            Assert.AreEqual(0UL, Native.c4view_getTotalRows(_view));
            Assert.AreEqual(0UL, Native.c4view_getLastSequenceIndexed(_view));
            Assert.AreEqual(0UL, Native.c4view_getLastSequenceChangedAt(_view));
        }
 public static extern C4SliceResult c4view_fullTextMatched(C4View *view,
                                                           C4Slice docID,
                                                           C4SequenceNumber seq,
                                                           uint fullTextID,
                                                           C4Error *outError);
 public static extern C4SequenceNumber c4view_getLastSequenceIndexed(C4View *view);
 public static extern C4SequenceNumber c4view_getLastSequenceChangedAt(C4View *view);
 public static void c4view_setDocumentType(C4View *view, string docType)
 {
     using (var docType_ = new C4String(docType)) {
         NativeRaw.c4view_setDocumentType(view, docType_.AsC4Slice());
     }
 }
        private void IndexViews()
        {
            var nameKey    = Native.FLDictKey_Init("Name", true);
            var albumKey   = Native.FLDictKey_Init("Album", true);
            var artistKey  = Native.FLDictKey_Init("Artist", true);
            var timeKey    = Native.FLDictKey_Init("Total Time", true);
            var trackNoKey = Native.FLDictKey_Init("Track Number", true);
            var compKey    = Native.FLDictKey_Init("Compilation", true);

            var enc = Native.FLEncoder_New();
            var key = Native.c4key_new();

            C4Error error;

            if (_artistsView == null)
            {
                var config = Native.c4db_getConfig(Db);
                _artistsView = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "Artists", "1",
                                                                                        Native.c4db_getConfig(Db), err));
            }

            if (_albumsView == null)
            {
                _albumsView = (C4View *)LiteCoreBridge.Check(err => Native.c4view_open(Db, null, "Albums", "1",
                                                                                       Native.c4db_getConfig(Db), err));
            }

            var views   = new[] { _artistsView, _albumsView };
            var indexer = (C4Indexer *)LiteCoreBridge.Check(err => Native.c4indexer_begin(Db, views, err));
            var e       = (C4DocEnumerator *)LiteCoreBridge.Check(err => Native.c4indexer_enumerateDocuments(indexer, err));

            while (Native.c4enum_next(e, &error))
            {
                var doc  = Native.c4enum_getDocument(e, &error);
                var body = Native.FLValue_AsDict(NativeRaw.FLValue_FromTrustedData((FLSlice)doc->selectedRev.body));
                ((long)body).Should().NotBe(0, "because otherwise the data got corrupted somehow");

                FLSlice artist;
                if (Native.FLValue_AsBool(Native.FLDict_GetWithKey(body, &compKey)))
                {
                    artist = FLSlice.Constant("-Compilations-");
                }
                else
                {
                    artist = NativeRaw.FLValue_AsString(Native.FLDict_GetWithKey(body, &artistKey));
                }

                var name    = NativeRaw.FLValue_AsString(Native.FLDict_GetWithKey(body, &nameKey));
                var album   = Native.FLValue_AsString(Native.FLDict_GetWithKey(body, &albumKey));
                var trackNo = Native.FLValue_AsInt(Native.FLDict_GetWithKey(body, &trackNoKey));
                var time    = Native.FLDict_GetWithKey(body, &timeKey);

                // Generate Value:
                Native.FLEncoder_WriteValue(enc, time);
                FLError flError;
                var     fval = NativeRaw.FLEncoder_Finish(enc, &flError);
                Native.FLEncoder_Reset(enc);
                ((long)fval.buf).Should().NotBe(0, "because otherwise the encoding failed");
                var value = (C4Slice)fval;

                // Emit to artists view:
                uint nKeys = 0;
                if (!artist.Equals(FLSlice.Null) && !name.Equals(FLSlice.Null))
                {
                    nKeys = 1;
                    // Generate key:
                    Native.c4key_beginArray(key);
                    NativeRaw.c4key_addString(key, (C4Slice)artist);
                    if (album != null)
                    {
                        Native.c4key_addString(key, album);
                    }
                    else
                    {
                        Native.c4key_addNull(key);
                    }

                    Native.c4key_addNumber(key, trackNo);
                    NativeRaw.c4key_addString(key, (C4Slice)name);
                    Native.c4key_addNumber(key, 1.0);
                    Native.c4key_endArray(key);
                }

                Native.c4indexer_emit(indexer, doc, 0, nKeys, new[] { key }, new[] { value }, &error).Should()
                .BeTrue("because otherwise the emit to the artists view failed");
                Native.c4key_reset(key);

                // Emit to albums view:
                nKeys = 0;
                if (album != null)
                {
                    nKeys = 1;
                    Native.c4key_beginArray(key);
                    Native.c4key_addString(key, album);
                    if (!artist.Equals(FLSlice.Null))
                    {
                        NativeRaw.c4key_addString(key, (C4Slice)artist);
                    }
                    else
                    {
                        Native.c4key_addNull(key);
                    }

                    Native.c4key_addNumber(key, trackNo);
                    if (name.buf == null)
                    {
                        name = FLSlice.Constant("");
                    }

                    NativeRaw.c4key_addString(key, (C4Slice)name);
                    Native.c4key_addNumber(key, 1.0);
                    Native.c4key_endArray(key);
                }

                Native.c4indexer_emit(indexer, doc, 1, nKeys, new[] { key }, new[] { value }, &error).Should()
                .BeTrue("because otherwise the emit to the artists view failed");
                Native.c4key_reset(key);

                Native.FLSliceResult_Free(fval);
                Native.c4doc_free(doc);
            }

            Native.c4enum_free(e);
            error.Code.Should().Be(0, "because otherwise an error occurred");
            Native.c4indexer_end(indexer, true, &error).Should().BeTrue("because otherwise the indexer failed to end");
            Native.FLEncoder_Free(enc);
            Native.c4key_free(key);
        }
 public static extern void c4view_setOnCompactCallback(C4View *view, C4OnCompactCallback cb, void *context);
 public static extern void c4view_triggerOnView(C4Indexer *indexer, C4View *view);
Example #24
0
        public bool UpdateIndexes(IEnumerable <IViewStore> views)
        {
            Log.To.Query.V(Tag, "Checking indexes of ({0}) for {1}", ViewNames(views), Name);

            // Creates an array of tuples -> [[view1, view1 last sequence, view1 native handle],
            // [view2, view2 last sequence, view2 native handle], ...]
            var viewsArray = views.Where(x => {
                var viewDelegate = x.Delegate;
                if (viewDelegate == null || viewDelegate.Map == null)
                {
                    Log.To.Query.V(Tag, "    {0} has no map block; skipping it", x.Name);
                    return(false);
                }

                return(true);
            }).Cast <ForestDBViewStore> ().ToArray();

            var nativeViews = new C4View *[viewsArray.Length];

            for (int i = 0; i < viewsArray.Length; i++)
            {
                nativeViews[i] = viewsArray[i].IndexDB;
            }

            var indexer = (C4Indexer *)ForestDBBridge.Check(err => Native.c4indexer_begin(_dbStorage.Forest, nativeViews, err));

            var enumerator = new CBForestDocEnumerator(indexer);

            var commit = false;

            try {
                foreach (var next in enumerator)
                {
                    var seq = next.Sequence;

                    for (int i = 0; i < viewsArray.Length; i++)
                    {
                        var info = viewsArray [i];
                        if (seq <= info.LastSequenceIndexed)
                        {
                            continue; // This view has already indexed this sequence
                        }

                        var rev    = new ForestRevisionInternal(next, true);
                        var keys   = new List <object>();
                        var values = new List <string>();

                        var conflicts = default(List <string>);
                        foreach (var leaf in new CBForestHistoryEnumerator(_dbStorage.Forest, next.Sequence, true))
                        {
                            if (leaf.SelectedRev.revID.Equals(leaf.CurrentRevID))
                            {
                                continue;
                            }

                            if (leaf.IsDeleted)
                            {
                                break;
                            }

                            if (conflicts == null)
                            {
                                conflicts = new List <string>();
                            }

                            conflicts.Add((string)leaf.SelectedRev.revID);
                        }

                        if (conflicts != null)
                        {
                            rev.SetPropertyForKey("_conflicts", conflicts);
                        }

                        try {
                            var props = rev.GetProperties();
                            info.Delegate.Map(props, (key, value) =>
                            {
                                if (key == null)
                                {
                                    Log.To.Query.W(Tag, "Emit function called with a null key; ignoring");
                                    return;
                                }

                                keys.Add(key);
                                if (props == value)
                                {
                                    values.Add("*");
                                }
                                else
                                {
                                    values.Add(Manager.GetObjectMapper().WriteValueAsString(value));
                                }
                            });
                        } catch (Exception e) {
                            Log.To.Query.W(Tag, String.Format("Exception thrown in map function of {0}, continuing", info.Name), e);
                            continue;
                        }

                        WithC4Keys(keys.ToArray(), true, c4keys =>
                                   ForestDBBridge.Check(err => Native.c4indexer_emit(indexer, next.GetDocument(), (uint)i, c4keys, values.ToArray(), err))
                                   );
                    }
                }

                commit = true;
            } catch (Exception e) {
                Log.To.Query.W(Tag, "Error updates indexes, returning false", e);
                return(false);
            } finally {
                ForestDBBridge.Check(err => Native.c4indexer_end(indexer, commit, err));
            }

            return(true);
        }
Example #25
0
        public bool UpdateIndexes(IEnumerable <IViewStore> views)
        {
            Log.D(TAG, "Checking indexes of ({0}) for {1}", ViewNames(views), Name);

            // Creates an array of tuples -> [[view1, view1 last sequence, view1 native handle],
            // [view2, view2 last sequence, view2 native handle], ...]
            var viewsArray  = views.Cast <ForestDBViewStore>().ToArray();
            var viewInfo    = viewsArray.Select(x => Tuple.Create(x, x.LastSequenceIndexed)).ToArray();
            var nativeViews = new C4View *[viewsArray.Length];

            for (int i = 0; i < viewsArray.Length; i++)
            {
                nativeViews[i] = viewsArray[i]._indexDB;
            }

            var indexer = (C4Indexer *)ForestDBBridge.Check(err => Native.c4indexer_begin(_dbStorage.Forest, nativeViews, err));

            var enumerator = new CBForestDocEnumerator(indexer);

            var commit = false;

            try {
                foreach (var next in enumerator)
                {
                    var seq = next.SelectedRev.sequence;

                    for (int i = 0; i < viewInfo.Length; i++)
                    {
                        var info = viewInfo[i];
                        if (seq <= (ulong)info.Item2)
                        {
                            continue; // This view has already indexed this sequence
                        }

                        var viewDelegate = info.Item1.Delegate;
                        if (viewDelegate == null || viewDelegate.Map == null)
                        {
                            Log.V(TAG, "    {0} has no map block; skipping it", info.Item1.Name);
                            continue;
                        }

                        var rev    = new RevisionInternal(next, true);
                        var keys   = new List <object>();
                        var values = new List <string>();
                        try {
                            viewDelegate.Map(rev.GetProperties(), (key, value) =>
                            {
                                keys.Add(key);
                                values.Add(Manager.GetObjectMapper().WriteValueAsString(value));
                            });
                        } catch (Exception e) {
                            Log.W(TAG, String.Format("Exception thrown in map function of {0}", info.Item1.Name), e);
                            continue;
                        }

                        WithC4Keys(keys.ToArray(), true, c4keys =>
                                   ForestDBBridge.Check(err => Native.c4indexer_emit(indexer, next.Document, (uint)i, c4keys, values.ToArray(), err))
                                   );
                    }
                }

                commit = true;
            } catch (Exception e) {
                Log.W(TAG, "Error updates indexes", e);
            } finally {
                ForestDBBridge.Check(err => Native.c4indexer_end(indexer, commit, err));
            }

            return(true);
        }
 public static extern C4QueryEnumerator *c4view_query(C4View *view, C4QueryOptions *options, C4Error *outError);
 public static extern C4QueryEnumerator *c4view_geoQuery(C4View *view, C4GeoArea area, C4Error *outError);
 public static extern void c4view_setMapVersion(C4View *view, C4Slice version);
 public static extern void c4view_setDocumentType(C4View *view, C4Slice docType);
 public static extern C4QueryEnumerator *c4view_fullTextQuery(C4View *view,
                                                              C4Slice queryString,
                                                              C4Slice queryStringLanguage,
                                                              C4QueryOptions *c4Options,
                                                              C4Error *outError);