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"); }); }
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); }
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)); }
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); }
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); }
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); } }
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);
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); }
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);