/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewQuery() { PutDocs(database); View view = CreateView(database); view.UpdateIndex(); // Query all rows: QueryOptions options = new QueryOptions(); IList<QueryRow> rows = view.QueryWithOptions(options); IList<object> expectedRows = new AList<object>(); IDictionary<string, object> dict5 = new Dictionary<string, object>(); dict5.Put("id", "55555"); dict5.Put("key", "five"); expectedRows.AddItem(dict5); IDictionary<string, object> dict4 = new Dictionary<string, object>(); dict4.Put("id", "44444"); dict4.Put("key", "four"); expectedRows.AddItem(dict4); IDictionary<string, object> dict1 = new Dictionary<string, object>(); dict1.Put("id", "11111"); dict1.Put("key", "one"); expectedRows.AddItem(dict1); IDictionary<string, object> dict3 = new Dictionary<string, object>(); dict3.Put("id", "33333"); dict3.Put("key", "three"); expectedRows.AddItem(dict3); IDictionary<string, object> dict2 = new Dictionary<string, object>(); dict2.Put("id", "22222"); dict2.Put("key", "two"); expectedRows.AddItem(dict2); NUnit.Framework.Assert.AreEqual(5, rows.Count); NUnit.Framework.Assert.AreEqual(dict5.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(dict5.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(dict4.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(dict4.Get("value"), rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(dict1.Get("key"), rows[2].GetKey()); NUnit.Framework.Assert.AreEqual(dict1.Get("value"), rows[2].GetValue()); NUnit.Framework.Assert.AreEqual(dict3.Get("key"), rows[3].GetKey()); NUnit.Framework.Assert.AreEqual(dict3.Get("value"), rows[3].GetValue()); NUnit.Framework.Assert.AreEqual(dict2.Get("key"), rows[4].GetKey()); NUnit.Framework.Assert.AreEqual(dict2.Get("value"), rows[4].GetValue()); // Start/end key query: options = new QueryOptions(); options.SetStartKey("a"); options.SetEndKey("one"); rows = view.QueryWithOptions(options); expectedRows = new AList<object>(); expectedRows.AddItem(dict5); expectedRows.AddItem(dict4); expectedRows.AddItem(dict1); NUnit.Framework.Assert.AreEqual(3, rows.Count); NUnit.Framework.Assert.AreEqual(dict5.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(dict5.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(dict4.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(dict4.Get("value"), rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(dict1.Get("key"), rows[2].GetKey()); NUnit.Framework.Assert.AreEqual(dict1.Get("value"), rows[2].GetValue()); // Start/end query without inclusive end: options.SetInclusiveEnd(false); rows = view.QueryWithOptions(options); expectedRows = new AList<object>(); expectedRows.AddItem(dict5); expectedRows.AddItem(dict4); NUnit.Framework.Assert.AreEqual(2, rows.Count); NUnit.Framework.Assert.AreEqual(dict5.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(dict5.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(dict4.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(dict4.Get("value"), rows[1].GetValue()); // Reversed: options.SetDescending(true); options.SetStartKey("o"); options.SetEndKey("five"); options.SetInclusiveEnd(true); rows = view.QueryWithOptions(options); expectedRows = new AList<object>(); expectedRows.AddItem(dict4); expectedRows.AddItem(dict5); NUnit.Framework.Assert.AreEqual(2, rows.Count); NUnit.Framework.Assert.AreEqual(dict4.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(dict4.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(dict5.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(dict5.Get("value"), rows[1].GetValue()); // Reversed, no inclusive end: options.SetInclusiveEnd(false); rows = view.QueryWithOptions(options); expectedRows = new AList<object>(); expectedRows.AddItem(dict4); NUnit.Framework.Assert.AreEqual(1, rows.Count); NUnit.Framework.Assert.AreEqual(dict4.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(dict4.Get("value"), rows[0].GetValue()); // Specific keys: options = new QueryOptions(); IList<object> keys = new AList<object>(); keys.AddItem("two"); keys.AddItem("four"); options.SetKeys(keys); rows = view.QueryWithOptions(options); expectedRows = new AList<object>(); expectedRows.AddItem(dict4); expectedRows.AddItem(dict2); NUnit.Framework.Assert.AreEqual(2, rows.Count); NUnit.Framework.Assert.AreEqual(dict4.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(dict4.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(dict2.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(dict2.Get("value"), rows[1].GetValue()); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestLargerViewQuery() { PutNDocs(database, 4); View view = CreateView(database); view.UpdateIndex(); // Query all rows: QueryOptions options = new QueryOptions(); Status status = new Status(); IList<QueryRow> rows = view.QueryWithOptions(options); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewLinkedDocs() { PutLinkedDocs(database); View view = database.GetView("linked"); view.SetMapReduce(new _Mapper_1086(), null, "1"); view.UpdateIndex(); QueryOptions options = new QueryOptions(); options.SetIncludeDocs(true); // required for linked documents IList<QueryRow> rows = view.QueryWithOptions(options); NUnit.Framework.Assert.IsNotNull(rows); NUnit.Framework.Assert.AreEqual(5, rows.Count); object[][] expected = new object[][] { new object[] { "22222", "hello", 0, null, "22222" }, new object[] { "22222", "hello", 1, "11111", "11111" }, new object[] { "33333", "world", 0, null, "33333" }, new object[] { "33333", "world", 1, "22222" , "22222" }, new object[] { "33333", "world", 2, "11111", "11111" } }; for (int i = 0; i < rows.Count; i++) { QueryRow row = rows[i]; IDictionary<string, object> rowAsJson = row.AsJSONDictionary(); Log.D(Tag, string.Empty + rowAsJson); IList<object> key = (IList<object>)rowAsJson.Get("key"); IDictionary<string, object> doc = (IDictionary<string, object>)rowAsJson.Get("doc" ); string id = (string)rowAsJson.Get("id"); NUnit.Framework.Assert.AreEqual(expected[i][0], id); NUnit.Framework.Assert.AreEqual(2, key.Count); NUnit.Framework.Assert.AreEqual(expected[i][1], key[0]); NUnit.Framework.Assert.AreEqual(expected[i][2], key[1]); if (expected[i][3] == null) { NUnit.Framework.Assert.IsNull(row.GetValue()); } else { NUnit.Framework.Assert.AreEqual(expected[i][3], ((IDictionary<string, object>)row .GetValue()).Get("_id")); } NUnit.Framework.Assert.AreEqual(expected[i][4], doc.Get("_id")); } }
public int GetDeletedColumnIndex(QueryOptions options) { if (options.IsIncludeDocs()) { return 5; } else { return 4; } }
/// <summary>Queries the view.</summary> /// <remarks>Queries the view. Does NOT first update the index.</remarks> /// <param name="options">The options to use.</param> /// <returns>An array of QueryRow objects.</returns> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal IEnumerable <QueryRow> QueryWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } Cursor cursor = null; IList <QueryRow> rows = new List <QueryRow>(); try { cursor = ResultSetWithOptions(options); int groupLevel = options.GetGroupLevel(); var group = options.IsGroup() || (groupLevel > 0); var reduce = options.IsReduce() || group; var reduceBlock = Reduce; if (reduce && (reduceBlock == null) && !group) { var msg = "Cannot use reduce option in view " + Name + " which has no reduce block defined"; Log.W(Database.Tag, msg); throw new CouchbaseLiteException(StatusCode.BadRequest); } if (reduce || group) { // Reduced or grouped query: rows = ReducedQuery(cursor, group, groupLevel); } else { // regular query cursor.MoveToNext(); while (!cursor.IsAfterLast()) { var lazyKey = new Lazy <object>(() => FromJSON(cursor.GetBlob(0))); var lazyValue = new Lazy <object>(() => FromJSON(cursor.GetBlob(1))); // TODO: ditto var docId = cursor.GetString(2); var sequenceLong = cursor.GetLong(3); var sequence = Convert.ToInt32(sequenceLong); IDictionary <string, object> docContents = null; if (options.IsIncludeDocs()) { // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents if (lazyValue.Value is IDictionary <string, object> && ((IDictionary <string, object>)lazyValue.Value).ContainsKey("_id")) { var linkedDocId = (string)((IDictionary <string, object>)lazyValue.Value).Get("_id"); var linkedDoc = Database.GetDocumentWithIDAndRev(linkedDocId, null, DocumentContentOptions.None); docContents = linkedDoc.GetProperties(); } else { var revId = cursor.GetString(4); docContents = Database.DocumentPropertiesFromJSON(cursor.GetBlob(5), docId, revId, false, sequenceLong, options.GetContentOptions()); } } var row = new QueryRow(docId, sequence, lazyKey.Value, lazyValue.Value, docContents); row.Database = Database; rows.AddItem <QueryRow>(row); // NOTE.ZJG: Change to `yield return row` to convert to a generator. cursor.MoveToNext(); } } } catch (SQLException e) { var errMsg = string.Format("Error querying view: {0}", this); Log.E(Database.Tag, errMsg, e); throw new CouchbaseLiteException(errMsg, e, new Status(StatusCode.DbError)); } finally { if (cursor != null) { cursor.Close(); } } return(rows); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewGrouped() { IDictionary<string, object> docProperties1 = new Dictionary<string, object>(); docProperties1.Put("_id", "1"); docProperties1.Put("artist", "Gang Of Four"); docProperties1.Put("album", "Entertainment!"); docProperties1.Put("track", "Ether"); docProperties1.Put("time", 231); PutDoc(database, docProperties1); IDictionary<string, object> docProperties2 = new Dictionary<string, object>(); docProperties2.Put("_id", "2"); docProperties2.Put("artist", "Gang Of Four"); docProperties2.Put("album", "Songs Of The Free"); docProperties2.Put("track", "I Love A Man In Uniform"); docProperties2.Put("time", 248); PutDoc(database, docProperties2); IDictionary<string, object> docProperties3 = new Dictionary<string, object>(); docProperties3.Put("_id", "3"); docProperties3.Put("artist", "Gang Of Four"); docProperties3.Put("album", "Entertainment!"); docProperties3.Put("track", "Natural's Not In It"); docProperties3.Put("time", 187); PutDoc(database, docProperties3); IDictionary<string, object> docProperties4 = new Dictionary<string, object>(); docProperties4.Put("_id", "4"); docProperties4.Put("artist", "PiL"); docProperties4.Put("album", "Metal Box"); docProperties4.Put("track", "Memories"); docProperties4.Put("time", 309); PutDoc(database, docProperties4); IDictionary<string, object> docProperties5 = new Dictionary<string, object>(); docProperties5.Put("_id", "5"); docProperties5.Put("artist", "Gang Of Four"); docProperties5.Put("album", "Entertainment!"); docProperties5.Put("track", "Not Great Men"); docProperties5.Put("time", 187); PutDoc(database, docProperties5); View view = database.GetView("grouper"); view.SetMapReduce(new _Mapper_671(), new _Reducer_681(), "1"); Status status = new Status(); view.UpdateIndex(); QueryOptions options = new QueryOptions(); options.SetReduce(true); IList<QueryRow> rows = view.QueryWithOptions(options); IList<IDictionary<string, object>> expectedRows = new AList<IDictionary<string, object >>(); IDictionary<string, object> row1 = new Dictionary<string, object>(); row1.Put("key", null); row1.Put("value", 1162.0); expectedRows.AddItem(row1); NUnit.Framework.Assert.AreEqual(row1.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(row1.Get("value"), rows[0].GetValue()); //now group options.SetGroup(true); status = new Status(); rows = view.QueryWithOptions(options); expectedRows = new AList<IDictionary<string, object>>(); row1 = new Dictionary<string, object>(); IList<string> key1 = new AList<string>(); key1.AddItem("Gang Of Four"); key1.AddItem("Entertainment!"); key1.AddItem("Ether"); row1.Put("key", key1); row1.Put("value", 231.0); expectedRows.AddItem(row1); IDictionary<string, object> row2 = new Dictionary<string, object>(); IList<string> key2 = new AList<string>(); key2.AddItem("Gang Of Four"); key2.AddItem("Entertainment!"); key2.AddItem("Natural's Not In It"); row2.Put("key", key2); row2.Put("value", 187.0); expectedRows.AddItem(row2); IDictionary<string, object> row3 = new Dictionary<string, object>(); IList<string> key3 = new AList<string>(); key3.AddItem("Gang Of Four"); key3.AddItem("Entertainment!"); key3.AddItem("Not Great Men"); row3.Put("key", key3); row3.Put("value", 187.0); expectedRows.AddItem(row3); IDictionary<string, object> row4 = new Dictionary<string, object>(); IList<string> key4 = new AList<string>(); key4.AddItem("Gang Of Four"); key4.AddItem("Songs Of The Free"); key4.AddItem("I Love A Man In Uniform"); row4.Put("key", key4); row4.Put("value", 248.0); expectedRows.AddItem(row4); IDictionary<string, object> row5 = new Dictionary<string, object>(); IList<string> key5 = new AList<string>(); key5.AddItem("PiL"); key5.AddItem("Metal Box"); key5.AddItem("Memories"); row5.Put("key", key5); row5.Put("value", 309.0); expectedRows.AddItem(row5); NUnit.Framework.Assert.AreEqual(row1.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(row1.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(row2.Get("value"), rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(row3.Get("key"), rows[2].GetKey()); NUnit.Framework.Assert.AreEqual(row3.Get("value"), rows[2].GetValue()); NUnit.Framework.Assert.AreEqual(row4.Get("key"), rows[3].GetKey()); NUnit.Framework.Assert.AreEqual(row4.Get("value"), rows[3].GetValue()); NUnit.Framework.Assert.AreEqual(row5.Get("key"), rows[4].GetKey()); NUnit.Framework.Assert.AreEqual(row5.Get("value"), rows[4].GetValue()); //group level 1 options.SetGroupLevel(1); status = new Status(); rows = view.QueryWithOptions(options); expectedRows = new AList<IDictionary<string, object>>(); row1 = new Dictionary<string, object>(); key1 = new AList<string>(); key1.AddItem("Gang Of Four"); row1.Put("key", key1); row1.Put("value", 853.0); expectedRows.AddItem(row1); row2 = new Dictionary<string, object>(); key2 = new AList<string>(); key2.AddItem("PiL"); row2.Put("key", key2); row2.Put("value", 309.0); expectedRows.AddItem(row2); NUnit.Framework.Assert.AreEqual(row1.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(row1.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(row2.Get("value"), rows[1].GetValue()); //group level 2 options.SetGroupLevel(2); status = new Status(); rows = view.QueryWithOptions(options); expectedRows = new AList<IDictionary<string, object>>(); row1 = new Dictionary<string, object>(); key1 = new AList<string>(); key1.AddItem("Gang Of Four"); key1.AddItem("Entertainment!"); row1.Put("key", key1); row1.Put("value", 605.0); expectedRows.AddItem(row1); row2 = new Dictionary<string, object>(); key2 = new AList<string>(); key2.AddItem("Gang Of Four"); key2.AddItem("Songs Of The Free"); row2.Put("key", key2); row2.Put("value", 248.0); expectedRows.AddItem(row2); row3 = new Dictionary<string, object>(); key3 = new AList<string>(); key3.AddItem("PiL"); key3.AddItem("Metal Box"); row3.Put("key", key3); row3.Put("value", 309.0); expectedRows.AddItem(row3); NUnit.Framework.Assert.AreEqual(row1.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(row1.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(row2.Get("value"), rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(row3.Get("key"), rows[2].GetKey()); NUnit.Framework.Assert.AreEqual(row3.Get("value"), rows[2].GetValue()); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewCollationRaw() { IList<object> list1 = new AList<object>(); list1.AddItem("a"); IList<object> list2 = new AList<object>(); list2.AddItem("b"); IList<object> list3 = new AList<object>(); list3.AddItem("b"); list3.AddItem("c"); IList<object> list4 = new AList<object>(); list4.AddItem("b"); list4.AddItem("c"); list4.AddItem("a"); IList<object> list5 = new AList<object>(); list5.AddItem("b"); list5.AddItem("d"); IList<object> list6 = new AList<object>(); list6.AddItem("b"); list6.AddItem("d"); list6.AddItem("e"); // Based on CouchDB's "view_collation.js" test IList<object> testKeys = new AList<object>(); testKeys.AddItem(0); testKeys.AddItem(2.5); testKeys.AddItem(10); testKeys.AddItem(false); testKeys.AddItem(null); testKeys.AddItem(true); testKeys.AddItem(list1); testKeys.AddItem(list2); testKeys.AddItem(list3); testKeys.AddItem(list4); testKeys.AddItem(list5); testKeys.AddItem(list6); testKeys.AddItem(" "); testKeys.AddItem("A"); testKeys.AddItem("B"); testKeys.AddItem("_"); testKeys.AddItem("a"); testKeys.AddItem("aa"); testKeys.AddItem("b"); testKeys.AddItem("ba"); testKeys.AddItem("bb"); testKeys.AddItem("~"); int i = 0; foreach (object key in testKeys) { IDictionary<string, object> docProperties = new Dictionary<string, object>(); docProperties.Put("_id", Sharpen.Extensions.ToString(i++)); docProperties.Put("name", key); PutDoc(database, docProperties); } View view = database.GetView("default/names"); view.SetMapReduce(new _Mapper_1048(), null, "1.0"); view.SetCollation(View.TDViewCollation.TDViewCollationRaw); QueryOptions options = new QueryOptions(); IList<QueryRow> rows = view.QueryWithOptions(options); i = 0; foreach (QueryRow row in rows) { NUnit.Framework.Assert.AreEqual(testKeys[i++], row.GetKey()); } database.Close(); }
/// <summary>Queries the view.</summary> /// <remarks>Queries the view. Does NOT first update the index.</remarks> /// <param name="options">The options to use.</param> /// <returns>An array of QueryRow objects.</returns> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal IEnumerable<QueryRow> QueryWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } IEnumerable<QueryRow> iterator = null; if (false) { //TODO: Full text } else if (GroupOrReduce(options)) { iterator = Storage.ReducedQuery(options); } else { iterator = Storage.RegularQuery(options); } if (iterator != null) { Log.D(TAG, "Query {0}: Returning iterator", Name); } else { Log.D(TAG, "Query {0}: Failed", Name); } return iterator; }
private bool GroupOrReduce(QueryOptions options) { if (options.Group|| options.GroupLevel> 0) { return true; } if (options.ReduceSpecified) { return options.Reduce; } return Reduce != null; }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewGrouped() { IDictionary<string, object> docProperties1 = new Dictionary<string, object>(); docProperties1["_id"] = "1"; docProperties1["artist"] = "Gang Of Four"; docProperties1["album"] = "Entertainment!"; docProperties1["track"] = "Ether"; docProperties1["time"] = 231; PutDoc(database, docProperties1); IDictionary<string, object> docProperties2 = new Dictionary<string, object>(); docProperties2["_id"] = "2"; docProperties2["artist"] = "Gang Of Four"; docProperties2["album"] = "Songs Of The Free"; docProperties2["track"] = "I Love A Man In Uniform"; docProperties2["time"] = 248; PutDoc(database, docProperties2); IDictionary<string, object> docProperties3 = new Dictionary<string, object>(); docProperties3["_id"] = "3"; docProperties3["artist"] = "Gang Of Four"; docProperties3["album"] = "Entertainment!"; docProperties3["track"] = "Natural's Not In It"; docProperties3["time"] = 187; PutDoc(database, docProperties3); IDictionary<string, object> docProperties4 = new Dictionary<string, object>(); docProperties4["_id"] = "4"; docProperties4["artist"] = "PiL"; docProperties4["album"] = "Metal Box"; docProperties4["track"] = "Memories"; docProperties4["time"] = 309; PutDoc(database, docProperties4); IDictionary<string, object> docProperties5 = new Dictionary<string, object>(); docProperties5["_id"] = "5"; docProperties5["artist"] = "Gang Of Four"; docProperties5["album"] = "Entertainment!"; docProperties5["track"] = "Not Great Men"; docProperties5["time"] = 187; PutDoc(database, docProperties5); View view = database.GetView("grouper"); view.SetMapReduce((IDictionary<string, object> document, EmitDelegate emitter)=> { IList<object> key = new AList<object>(); key.AddItem(document["artist"]); key.AddItem(document["album"]); key.AddItem(document["track"]); emitter(key, document["time"]); }, (IList<object> keys, IList<object> values, bool rereduce)=> { return View.TotalValues(values); }, "1"); Status status = new Status(); view.UpdateIndex(); QueryOptions options = new QueryOptions(); options.SetReduce(true); IList<QueryRow> rows = view.QueryWithOptions(options); IList<IDictionary<string, object>> expectedRows = new AList<IDictionary<string, object >>(); IDictionary<string, object> row1 = new Dictionary<string, object>(); row1["key"] = null; row1["value"] = 1162.0; expectedRows.AddItem(row1); NUnit.Framework.Assert.AreEqual(row1["key"], rows[0].Key); NUnit.Framework.Assert.AreEqual(row1["value"], rows[0].GetValue()); //now group options.SetGroup(true); status = new Status(); rows = view.QueryWithOptions(options); expectedRows = new AList<IDictionary<string, object>>(); row1 = new Dictionary<string, object>(); IList<string> key1 = new AList<string>(); key1.AddItem("Gang Of Four"); key1.AddItem("Entertainment!"); key1.AddItem("Ether"); row1["key"] = key1; row1["value"] = 231.0; expectedRows.AddItem(row1); IDictionary<string, object> row2 = new Dictionary<string, object>(); IList<string> key2 = new AList<string>(); key2.AddItem("Gang Of Four"); key2.AddItem("Entertainment!"); key2.AddItem("Natural's Not In It"); row2["key"] = key2; row2["value"] = 187.0; expectedRows.AddItem(row2); IDictionary<string, object> row3 = new Dictionary<string, object>(); IList<string> key3 = new AList<string>(); key3.AddItem("Gang Of Four"); key3.AddItem("Entertainment!"); key3.AddItem("Not Great Men"); row3["key"] = key3; row3["value"] = 187.0; expectedRows.AddItem(row3); IDictionary<string, object> row4 = new Dictionary<string, object>(); IList<string> key4 = new AList<string>(); key4.AddItem("Gang Of Four"); key4.AddItem("Songs Of The Free"); key4.AddItem("I Love A Man In Uniform"); row4["key"] = key4; row4["value"] = 248.0; expectedRows.AddItem(row4); IDictionary<string, object> row5 = new Dictionary<string, object>(); IList<string> key5 = new AList<string>(); key5.AddItem("PiL"); key5.AddItem("Metal Box"); key5.AddItem("Memories"); row5["key"] = key5; row5["value"] = 309.0; expectedRows.AddItem(row5); NUnit.Framework.Assert.AreEqual(row1["key"], rows[0].Key); NUnit.Framework.Assert.AreEqual(row1["value"], rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2["key"], rows[1].Key); NUnit.Framework.Assert.AreEqual(row2["value"], rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(row3["key"], rows[2].Key); NUnit.Framework.Assert.AreEqual(row3["value"], rows[2].GetValue()); NUnit.Framework.Assert.AreEqual(row4["key"], rows[3].Key); NUnit.Framework.Assert.AreEqual(row4["value"], rows[3].GetValue()); NUnit.Framework.Assert.AreEqual(row5["key"], rows[4].Key); NUnit.Framework.Assert.AreEqual(row5["value"], rows[4].GetValue()); //group level 1 options.SetGroupLevel(1); status = new Status(); rows = view.QueryWithOptions(options); expectedRows = new AList<IDictionary<string, object>>(); row1 = new Dictionary<string, object>(); key1 = new AList<string>(); key1.AddItem("Gang Of Four"); row1["key"] = key1; row1["value"] = 853.0; expectedRows.AddItem(row1); row2 = new Dictionary<string, object>(); key2 = new AList<string>(); key2.AddItem("PiL"); row2["key"] = key2; row2["value"] = 309.0; expectedRows.AddItem(row2); NUnit.Framework.Assert.AreEqual(row1["key"], rows[0].Key); NUnit.Framework.Assert.AreEqual(row1["value"], rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2["key"], rows[1].Key); NUnit.Framework.Assert.AreEqual(row2["value"], rows[1].GetValue()); //group level 2 options.SetGroupLevel(2); status = new Status(); rows = view.QueryWithOptions(options); expectedRows = new AList<IDictionary<string, object>>(); row1 = new Dictionary<string, object>(); key1 = new AList<string>(); key1.AddItem("Gang Of Four"); key1.AddItem("Entertainment!"); row1["key"] = key1; row1["value"] = 605.0; expectedRows.AddItem(row1); row2 = new Dictionary<string, object>(); key2 = new AList<string>(); key2.AddItem("Gang Of Four"); key2.AddItem("Songs Of The Free"); row2["key"] = key2; row2["value"] = 248.0; expectedRows.AddItem(row2); row3 = new Dictionary<string, object>(); key3 = new AList<string>(); key3.AddItem("PiL"); key3.AddItem("Metal Box"); row3["key"] = key3; row3["value"] = 309.0; expectedRows.AddItem(row3); NUnit.Framework.Assert.AreEqual(row1["key"], rows[0].Key); NUnit.Framework.Assert.AreEqual(row1["value"], rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2["key"], rows[1].Key); NUnit.Framework.Assert.AreEqual(row2["value"], rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(row3["key"], rows[2].Key); NUnit.Framework.Assert.AreEqual(row3["value"], rows[2].GetValue()); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewGroupedStrings() { IDictionary<string, object> docProperties1 = new Dictionary<string, object>(); docProperties1["name"] = "Alice"; PutDoc(database, docProperties1); IDictionary<string, object> docProperties2 = new Dictionary<string, object>(); docProperties2["name"] = "Albert"; PutDoc(database, docProperties2); IDictionary<string, object> docProperties3 = new Dictionary<string, object>(); docProperties3["name"] = "Naomi"; PutDoc(database, docProperties3); IDictionary<string, object> docProperties4 = new Dictionary<string, object>(); docProperties4["name"] = "Jens"; PutDoc(database, docProperties4); IDictionary<string, object> docProperties5 = new Dictionary<string, object>(); docProperties5["name"] = "Jed"; PutDoc(database, docProperties5); View view = database.GetView("default/names"); view.SetMapReduce(new _Mapper_852(), new _Reducer_862(), "1.0"); view.UpdateIndex(); QueryOptions options = new QueryOptions(); options.SetGroupLevel(1); IList<QueryRow> rows = view.QueryWithOptions(options); IList<IDictionary<string, object>> expectedRows = new AList<IDictionary<string, object >>(); IDictionary<string, object> row1 = new Dictionary<string, object>(); row1["key"] = "A"; row1["value"] = 2; expectedRows.AddItem(row1); IDictionary<string, object> row2 = new Dictionary<string, object>(); row2["key"] = "J"; row2["value"] = 2; expectedRows.AddItem(row2); IDictionary<string, object> row3 = new Dictionary<string, object>(); row3["key"] = "N"; row3["value"] = 1; expectedRows.AddItem(row3); NUnit.Framework.Assert.AreEqual(row1["key"], rows[0].Key); NUnit.Framework.Assert.AreEqual(row1["value"], rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2["key"], rows[1].Key); NUnit.Framework.Assert.AreEqual(row2["value"], rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(row3["key"], rows[2].Key); NUnit.Framework.Assert.AreEqual(row3["value"], rows[2].GetValue()); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewReduce() { IDictionary<string, object> docProperties1 = new Dictionary<string, object>(); docProperties1["_id"] = "CD"; docProperties1["cost"] = 8.99; PutDoc(database, docProperties1); IDictionary<string, object> docProperties2 = new Dictionary<string, object>(); docProperties2["_id"] = "App"; docProperties2["cost"] = 1.95; PutDoc(database, docProperties2); IDictionary<string, object> docProperties3 = new Dictionary<string, object>(); docProperties3["_id"] = "Dessert"; docProperties3["cost"] = 6.50; PutDoc(database, docProperties3); View view = database.GetView("totaler"); view.SetMapReduce((document, emitter) => { NUnit.Framework.Assert.IsNotNull (document.Get ("_id")); NUnit.Framework.Assert.IsNotNull (document.Get ("_rev")); object cost = document.Get ("cost"); if (cost != null) { emitter (document.Get ("_id"), cost); } }, (IList<object> keys, IList<object> values, bool rereduce)=> { return View.TotalValues(values); }, "1"); view.UpdateIndex(); IList<IDictionary<string, object>> dumpResult = view.Dump(); Log.V(Tag, "View dump: " + dumpResult); NUnit.Framework.Assert.AreEqual(3, dumpResult.Count); NUnit.Framework.Assert.AreEqual("\"App\"", dumpResult[0]["key"]); NUnit.Framework.Assert.AreEqual("1.95", dumpResult[0]["value"]); NUnit.Framework.Assert.AreEqual(2, dumpResult[0]["seq"]); NUnit.Framework.Assert.AreEqual("\"CD\"", dumpResult[1]["key"]); NUnit.Framework.Assert.AreEqual("8.99", dumpResult[1]["value"]); NUnit.Framework.Assert.AreEqual(1, dumpResult[1]["seq"]); NUnit.Framework.Assert.AreEqual("\"Dessert\"", dumpResult[2]["key"]); NUnit.Framework.Assert.AreEqual("6.5", dumpResult[2]["value"]); NUnit.Framework.Assert.AreEqual(3, dumpResult[2]["seq"]); QueryOptions options = new QueryOptions(); options.SetReduce(true); IList<QueryRow> reduced = view.QueryWithOptions(options); NUnit.Framework.Assert.AreEqual(1, reduced.Count); object value = reduced[0].GetValue(); Number numberValue = (Number)value; NUnit.Framework.Assert.IsTrue(Math.Abs(numberValue - 17.44) < 0.001); }
/// <summary> /// https://github.com/couchbase/couchbase-lite-android/issues/139 /// test based on https://github.com/couchbase/couchbase-lite-ios/blob/master/Source/CBL_View_Tests.m#L358 /// </summary> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewQueryStartKeyDocID() { PutDocs(database); IList<RevisionInternal> result = new AList<RevisionInternal>(); IDictionary<string, object> dict = new Dictionary<string, object>(); dict.Put("_id", "11112"); dict.Put("key", "one"); result.AddItem(PutDoc(database, dict)); View view = CreateView(database); view.UpdateIndex(); QueryOptions options = new QueryOptions(); options.SetStartKey("one"); options.SetStartKeyDocId("11112"); options.SetEndKey("three"); IList<QueryRow> rows = view.QueryWithOptions(options); NUnit.Framework.Assert.AreEqual(2, rows.Count); NUnit.Framework.Assert.AreEqual("11112", rows[0].GetDocumentId()); NUnit.Framework.Assert.AreEqual("one", rows[0].GetKey()); NUnit.Framework.Assert.AreEqual("33333", rows[1].GetDocumentId()); NUnit.Framework.Assert.AreEqual("three", rows[1].GetKey()); options = new QueryOptions(); options.SetEndKey("one"); options.SetEndKeyDocId("11111"); rows = view.QueryWithOptions(options); Log.D(Tag, "rows: " + rows); NUnit.Framework.Assert.AreEqual(3, rows.Count); NUnit.Framework.Assert.AreEqual("55555", rows[0].GetDocumentId()); NUnit.Framework.Assert.AreEqual("five", rows[0].GetKey()); NUnit.Framework.Assert.AreEqual("44444", rows[1].GetDocumentId()); NUnit.Framework.Assert.AreEqual("four", rows[1].GetKey()); NUnit.Framework.Assert.AreEqual("11111", rows[2].GetDocumentId()); NUnit.Framework.Assert.AreEqual("one", rows[2].GetKey()); options.SetStartKey("one"); options.SetStartKeyDocId("11111"); rows = view.QueryWithOptions(options); NUnit.Framework.Assert.AreEqual(1, rows.Count); NUnit.Framework.Assert.AreEqual("11111", rows[0].GetDocumentId()); NUnit.Framework.Assert.AreEqual("one", rows[0].GetKey()); }
internal Cursor ResultSetWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } // OPT: It would be faster to use separate tables for raw-or ascii-collated views so that // they could be indexed with the right Collation, instead of having to specify it here. var collationStr = string.Empty; if (Collation == ViewCollation.ASCII) { collationStr += " COLLATE JSON_ASCII"; } else { if (Collation == ViewCollation.Raw) { collationStr += " COLLATE JSON_RAW"; } } var sql = "SELECT key, value, docid, revs.sequence"; if (options.IsIncludeDocs()) { sql = sql + ", revid, json"; } sql = sql + " FROM maps, revs, docs WHERE maps.view_id=?"; var argsList = new List <string>(); argsList.AddItem(Sharpen.Extensions.ToString(Id)); if (options.GetKeys() != null) { sql += " AND key in ("; var item = "?"; foreach (object key in options.GetKeys()) { sql += item; item = ", ?"; argsList.AddItem(ToJSONString(key)); } sql += ")"; } var startKey = ToJSONString(options.GetStartKey()); var endKey = ToJSONString(options.GetEndKey()); var minKey = startKey; var maxKey = endKey; var minKeyDocId = options.GetStartKeyDocId(); var maxKeyDocId = options.GetEndKeyDocId(); var inclusiveMin = true; var inclusiveMax = options.IsInclusiveEnd(); if (options.IsDescending()) { var min = minKey; minKey = maxKey; maxKey = min; inclusiveMin = inclusiveMax; inclusiveMax = true; minKeyDocId = options.GetEndKeyDocId(); maxKeyDocId = options.GetStartKeyDocId(); } if (minKey != null) { sql += inclusiveMin ? " AND key >= ?" : " AND key > ?"; sql += collationStr; argsList.AddItem(minKey); if (minKeyDocId != null && inclusiveMin) { //OPT: This calls the JSON collator a 2nd time unnecessarily. sql += " AND (key > ? {0} OR docid >= ?)".Fmt(collationStr); argsList.AddItem(minKey); argsList.AddItem(minKeyDocId); } } if (maxKey != null) { if (inclusiveMax) { sql += " AND key <= ?"; } else { sql += " AND key < ?"; } sql += collationStr; argsList.AddItem(maxKey); if (maxKeyDocId != null && inclusiveMax) { sql += string.Format(" AND (key < ? {0} OR docid <= ?)", collationStr); argsList.AddItem(maxKey); argsList.AddItem(maxKeyDocId); } } sql = sql + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; sql += collationStr; if (options.IsDescending()) { sql = sql + " DESC"; } sql = sql + " LIMIT ? OFFSET ?"; argsList.AddItem(options.GetLimit().ToString()); argsList.AddItem(options.GetSkip().ToString()); Log.V(Database.Tag, "Query {0}:{1}", Name, sql); var cursor = Database.StorageEngine.RawQuery(sql, CommandBehavior.SequentialAccess, argsList.ToArray()); return(cursor); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestAllDocsQuery() { IList<RevisionInternal> docs = PutDocs(database); IList<QueryRow> expectedRow = new AList<QueryRow>(); foreach (RevisionInternal rev in docs) { IDictionary<string, object> value = new Dictionary<string, object>(); value.Put("rev", rev.GetRevId()); value.Put("_conflicts", new AList<string>()); QueryRow queryRow = new QueryRow(rev.GetDocId(), 0, rev.GetDocId(), value, null); queryRow.SetDatabase(database); expectedRow.AddItem(queryRow); } QueryOptions options = new QueryOptions(); IDictionary<string, object> allDocs = database.GetAllDocs(options); IList<QueryRow> expectedRows = new AList<QueryRow>(); expectedRows.AddItem(expectedRow[2]); expectedRows.AddItem(expectedRow[0]); expectedRows.AddItem(expectedRow[3]); expectedRows.AddItem(expectedRow[1]); expectedRows.AddItem(expectedRow[4]); IDictionary<string, object> expectedQueryResult = CreateExpectedQueryResult(expectedRows , 0); NUnit.Framework.Assert.AreEqual(expectedQueryResult, allDocs); // Start/end key query: options = new QueryOptions(); options.SetStartKey("2"); options.SetEndKey("44444"); allDocs = database.GetAllDocs(options); expectedRows = new AList<QueryRow>(); expectedRows.AddItem(expectedRow[0]); expectedRows.AddItem(expectedRow[3]); expectedRows.AddItem(expectedRow[1]); expectedQueryResult = CreateExpectedQueryResult(expectedRows, 0); NUnit.Framework.Assert.AreEqual(expectedQueryResult, allDocs); // Start/end query without inclusive end: options.SetInclusiveEnd(false); allDocs = database.GetAllDocs(options); expectedRows = new AList<QueryRow>(); expectedRows.AddItem(expectedRow[0]); expectedRows.AddItem(expectedRow[3]); expectedQueryResult = CreateExpectedQueryResult(expectedRows, 0); NUnit.Framework.Assert.AreEqual(expectedQueryResult, allDocs); // Get all documents: with default QueryOptions options = new QueryOptions(); allDocs = database.GetAllDocs(options); expectedRows = new AList<QueryRow>(); expectedRows.AddItem(expectedRow[2]); expectedRows.AddItem(expectedRow[0]); expectedRows.AddItem(expectedRow[3]); expectedRows.AddItem(expectedRow[1]); expectedRows.AddItem(expectedRow[4]); expectedQueryResult = CreateExpectedQueryResult(expectedRows, 0); NUnit.Framework.Assert.AreEqual(expectedQueryResult, allDocs); // Get specific documents: options = new QueryOptions(); IList<object> docIds = new AList<object>(); QueryRow expected2 = expectedRow[2]; docIds.AddItem(expected2.GetDocument().GetId()); options.SetKeys(docIds); allDocs = database.GetAllDocs(options); expectedRows = new AList<QueryRow>(); expectedRows.AddItem(expected2); expectedQueryResult = CreateExpectedQueryResult(expectedRows, 0); NUnit.Framework.Assert.AreEqual(expectedQueryResult, allDocs); }
private QueryOptions GetQueryOptions() { QueryOptions queryOptions = new QueryOptions(); queryOptions.SetStartKey(GetStartKey()); queryOptions.SetEndKey(GetEndKey()); queryOptions.SetStartKey(GetStartKey()); queryOptions.SetKeys(GetKeys()); queryOptions.SetSkip(GetSkip()); queryOptions.SetLimit(GetLimit()); queryOptions.SetReduce(!IsMapOnly()); queryOptions.SetReduceSpecified(true); queryOptions.SetGroupLevel(GetGroupLevel()); queryOptions.SetDescending(IsDescending()); queryOptions.SetIncludeDocs(ShouldPrefetch()); queryOptions.SetUpdateSeq(true); queryOptions.SetInclusiveEnd(true); queryOptions.SetStale(GetIndexUpdateMode()); queryOptions.SetAllDocsMode(GetAllDocsMode()); return queryOptions; }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewReduce() { IDictionary<string, object> docProperties1 = new Dictionary<string, object>(); docProperties1.Put("_id", "CD"); docProperties1.Put("cost", 8.99); PutDoc(database, docProperties1); IDictionary<string, object> docProperties2 = new Dictionary<string, object>(); docProperties2.Put("_id", "App"); docProperties2.Put("cost", 1.95); PutDoc(database, docProperties2); IDictionary<string, object> docProperties3 = new Dictionary<string, object>(); docProperties3.Put("_id", "Dessert"); docProperties3.Put("cost", 6.50); PutDoc(database, docProperties3); View view = database.GetView("totaler"); view.SetMapReduce(new _Mapper_544(), new _Reducer_555(), "1"); view.UpdateIndex(); IList<IDictionary<string, object>> dumpResult = view.Dump(); Log.V(Tag, "View dump: " + dumpResult); NUnit.Framework.Assert.AreEqual(3, dumpResult.Count); NUnit.Framework.Assert.AreEqual("\"App\"", dumpResult[0].Get("key")); NUnit.Framework.Assert.AreEqual("1.95", dumpResult[0].Get("value")); NUnit.Framework.Assert.AreEqual(2, dumpResult[0].Get("seq")); NUnit.Framework.Assert.AreEqual("\"CD\"", dumpResult[1].Get("key")); NUnit.Framework.Assert.AreEqual("8.99", dumpResult[1].Get("value")); NUnit.Framework.Assert.AreEqual(1, dumpResult[1].Get("seq")); NUnit.Framework.Assert.AreEqual("\"Dessert\"", dumpResult[2].Get("key")); NUnit.Framework.Assert.AreEqual("6.5", dumpResult[2].Get("value")); NUnit.Framework.Assert.AreEqual(3, dumpResult[2].Get("seq")); QueryOptions options = new QueryOptions(); options.SetReduce(true); IList<QueryRow> reduced = view.QueryWithOptions(options); NUnit.Framework.Assert.AreEqual(1, reduced.Count); object value = reduced[0].GetValue(); Number numberValue = (Number)value; NUnit.Framework.Assert.IsTrue(Math.Abs(numberValue - 17.44) < 0.001); }
public Cursor ResultSetWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } // OPT: It would be faster to use separate tables for raw-or ascii-collated views so that // they could be indexed with the right collation, instead of having to specify it here. string collationStr = string.Empty; if (collation == View.TDViewCollation.TDViewCollationASCII) { collationStr += " COLLATE JSON_ASCII"; } else { if (collation == View.TDViewCollation.TDViewCollationRaw) { collationStr += " COLLATE JSON_RAW"; } } string sql = "SELECT key, value, docid, revs.sequence"; if (options.IsIncludeDocs()) { sql = sql + ", revid, json"; } sql = sql + " FROM maps, revs, docs WHERE maps.view_id=?"; IList<string> argsList = new AList<string>(); argsList.AddItem(Sharpen.Extensions.ToString(GetViewId())); if (options.GetKeys() != null) { sql += " AND key in ("; string item = "?"; foreach (object key in options.GetKeys()) { sql += item; item = ", ?"; argsList.AddItem(ToJSONString(key)); } sql += ")"; } object minKey = options.GetStartKey(); object maxKey = options.GetEndKey(); bool inclusiveMin = true; bool inclusiveMax = options.IsInclusiveEnd(); if (options.IsDescending()) { minKey = maxKey; maxKey = options.GetStartKey(); inclusiveMin = inclusiveMax; inclusiveMax = true; } if (minKey != null) { System.Diagnostics.Debug.Assert((minKey is string)); if (inclusiveMin) { sql += " AND key >= ?"; } else { sql += " AND key > ?"; } sql += collationStr; argsList.AddItem(ToJSONString(minKey)); } if (maxKey != null) { System.Diagnostics.Debug.Assert((maxKey is string)); if (inclusiveMax) { sql += " AND key <= ?"; } else { sql += " AND key < ?"; } sql += collationStr; argsList.AddItem(ToJSONString(maxKey)); } sql = sql + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; sql += collationStr; if (options.IsDescending()) { sql = sql + " DESC"; } sql = sql + " LIMIT ? OFFSET ?"; argsList.AddItem(Sharpen.Extensions.ToString(options.GetLimit())); argsList.AddItem(Sharpen.Extensions.ToString(options.GetSkip())); Log.V(Database.Tag, "Query " + name + ": " + sql); Cursor cursor = database.GetDatabase().RawQuery(sql, Sharpen.Collections.ToArray( argsList, new string[argsList.Count])); return cursor; }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewGroupedStrings() { IDictionary<string, object> docProperties1 = new Dictionary<string, object>(); docProperties1.Put("name", "Alice"); PutDoc(database, docProperties1); IDictionary<string, object> docProperties2 = new Dictionary<string, object>(); docProperties2.Put("name", "Albert"); PutDoc(database, docProperties2); IDictionary<string, object> docProperties3 = new Dictionary<string, object>(); docProperties3.Put("name", "Naomi"); PutDoc(database, docProperties3); IDictionary<string, object> docProperties4 = new Dictionary<string, object>(); docProperties4.Put("name", "Jens"); PutDoc(database, docProperties4); IDictionary<string, object> docProperties5 = new Dictionary<string, object>(); docProperties5.Put("name", "Jed"); PutDoc(database, docProperties5); View view = database.GetView("default/names"); view.SetMapReduce(new _Mapper_859(), new _Reducer_869(), "1.0"); view.UpdateIndex(); QueryOptions options = new QueryOptions(); options.SetGroupLevel(1); IList<QueryRow> rows = view.QueryWithOptions(options); IList<IDictionary<string, object>> expectedRows = new AList<IDictionary<string, object >>(); IDictionary<string, object> row1 = new Dictionary<string, object>(); row1.Put("key", "A"); row1.Put("value", 2); expectedRows.AddItem(row1); IDictionary<string, object> row2 = new Dictionary<string, object>(); row2.Put("key", "J"); row2.Put("value", 2); expectedRows.AddItem(row2); IDictionary<string, object> row3 = new Dictionary<string, object>(); row3.Put("key", "N"); row3.Put("value", 1); expectedRows.AddItem(row3); NUnit.Framework.Assert.AreEqual(row1.Get("key"), rows[0].GetKey()); NUnit.Framework.Assert.AreEqual(row1.Get("value"), rows[0].GetValue()); NUnit.Framework.Assert.AreEqual(row2.Get("key"), rows[1].GetKey()); NUnit.Framework.Assert.AreEqual(row2.Get("value"), rows[1].GetValue()); NUnit.Framework.Assert.AreEqual(row3.Get("key"), rows[2].GetKey()); NUnit.Framework.Assert.AreEqual(row3.Get("value"), rows[2].GetValue()); }
public Cursor ResultSetWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } // OPT: It would be faster to use separate tables for raw-or ascii-collated views so that // they could be indexed with the right collation, instead of having to specify it here. string collationStr = string.Empty; if (collation == View.TDViewCollation.TDViewCollationASCII) { collationStr += " COLLATE JSON_ASCII"; } else { if (collation == View.TDViewCollation.TDViewCollationRaw) { collationStr += " COLLATE JSON_RAW"; } } string sql = "SELECT key, value, docid, revs.sequence"; if (options.IsIncludeDocs()) { sql = sql + ", revid, json"; } sql = sql + " FROM maps, revs, docs WHERE maps.view_id=?"; IList<string> argsList = new AList<string>(); argsList.AddItem(Sharpen.Extensions.ToString(GetViewId())); if (options.GetKeys() != null) { sql += " AND key in ("; string item = "?"; foreach (object key in options.GetKeys()) { sql += item; item = ", ?"; argsList.AddItem(ToJSONString(key)); } sql += ")"; } string startKey = ToJSONString(options.GetStartKey()); string endKey = ToJSONString(options.GetEndKey()); string minKey = startKey; string maxKey = endKey; string minKeyDocId = options.GetStartKeyDocId(); string maxKeyDocId = options.GetEndKeyDocId(); bool inclusiveMin = true; bool inclusiveMax = options.IsInclusiveEnd(); if (options.IsDescending()) { string min = minKey; minKey = maxKey; maxKey = min; inclusiveMin = inclusiveMax; inclusiveMax = true; minKeyDocId = options.GetEndKeyDocId(); maxKeyDocId = options.GetStartKeyDocId(); } if (minKey != null) { if (inclusiveMin) { sql += " AND key >= ?"; } else { sql += " AND key > ?"; } sql += collationStr; argsList.AddItem(minKey); if (minKeyDocId != null && inclusiveMin) { //OPT: This calls the JSON collator a 2nd time unnecessarily. sql += string.Format(" AND (key > ? %s OR docid >= ?)", collationStr); argsList.AddItem(minKey); argsList.AddItem(minKeyDocId); } } if (maxKey != null) { if (inclusiveMax) { sql += " AND key <= ?"; } else { sql += " AND key < ?"; } sql += collationStr; argsList.AddItem(maxKey); if (maxKeyDocId != null && inclusiveMax) { sql += string.Format(" AND (key < ? %s OR docid <= ?)", collationStr); argsList.AddItem(maxKey); argsList.AddItem(maxKeyDocId); } } sql = sql + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; sql += collationStr; if (options.IsDescending()) { sql = sql + " DESC"; } sql = sql + " LIMIT ? OFFSET ?"; argsList.AddItem(Sharpen.Extensions.ToString(options.GetLimit())); argsList.AddItem(Sharpen.Extensions.ToString(options.GetSkip())); Log.V(Log.TagView, "Query %s: %s | args: %s", name, sql, argsList); Cursor cursor = database.GetDatabase().RawQuery(sql, Sharpen.Collections.ToArray( argsList, new string[argsList.Count])); return cursor; }
public IList<QueryRow> QueryViewNamed(string viewName, QueryOptions options, IList <long> outLastSequence) { long before = Runtime.CurrentTimeMillis(); long lastSequence = 0; IList<QueryRow> rows = null; if (viewName != null && viewName.Length > 0) { View view = GetView(viewName); if (view == null) { throw new CouchbaseLiteException(new Status(Status.NotFound)); } lastSequence = view.GetLastSequenceIndexed(); if (options.GetStale() == Query.IndexUpdateMode.Before || lastSequence <= 0) { view.UpdateIndex(); lastSequence = view.GetLastSequenceIndexed(); } else { if (options.GetStale() == Query.IndexUpdateMode.After && lastSequence < GetLastSequenceNumber ()) { new Sharpen.Thread(new _Runnable_1847(view)).Start(); } } rows = view.QueryWithOptions(options); } else { // nil view means query _all_docs // note: this is a little kludgy, but we have to pull out the "rows" field from the // result dictionary because that's what we want. should be refactored, but // it's a little tricky, so postponing. IDictionary<string, object> allDocsResult = GetAllDocs(options); rows = (IList<QueryRow>)allDocsResult.Get("rows"); lastSequence = GetLastSequenceNumber(); } outLastSequence.AddItem(lastSequence); long delta = Runtime.CurrentTimeMillis() - before; Log.D(Database.Tag, string.Format("Query view %s completed in %d milliseconds", viewName , delta)); return rows; }
public IList<QueryRow> QueryWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } Cursor cursor = null; IList<QueryRow> rows = new AList<QueryRow>(); try { cursor = ResultSetWithOptions(options); int groupLevel = options.GetGroupLevel(); bool group = options.IsGroup() || (groupLevel > 0); bool reduce = options.IsReduce() || group; if (reduce && (reduceBlock == null) && !group) { Log.W(Log.TagView, "Cannot use reduce option in view %s which has no reduce block defined" , name); throw new CouchbaseLiteException(new Status(Status.BadRequest)); } if (reduce || group) { // Reduced or grouped query: rows = ReducedQuery(cursor, group, groupLevel); } else { // regular query cursor.MoveToNext(); while (!cursor.IsAfterLast()) { JsonDocument keyDoc = new JsonDocument(cursor.GetBlob(0)); JsonDocument valueDoc = new JsonDocument(cursor.GetBlob(1)); string docId = cursor.GetString(2); int sequence = Sharpen.Extensions.ValueOf(cursor.GetString(3)); IDictionary<string, object> docContents = null; if (options.IsIncludeDocs()) { object valueObject = valueDoc.JsonObject(); // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents if (valueObject is IDictionary && ((IDictionary)valueObject).ContainsKey("_id")) { string linkedDocId = (string)((IDictionary)valueObject).Get("_id"); RevisionInternal linkedDoc = database.GetDocumentWithIDAndRev(linkedDocId, null, EnumSet.NoneOf<Database.TDContentOptions>()); docContents = linkedDoc.GetProperties(); } else { docContents = database.DocumentPropertiesFromJSON(cursor.GetBlob(5), docId, cursor .GetString(4), false, cursor.GetLong(3), options.GetContentOptions()); } } QueryRow row = new QueryRow(docId, sequence, keyDoc.JsonObject(), valueDoc.JsonObject (), docContents); row.SetDatabase(database); rows.AddItem(row); cursor.MoveToNext(); } } } catch (SQLException e) { string errMsg = string.Format("Error querying view: %s", this); Log.E(Log.TagView, errMsg, e); throw new CouchbaseLiteException(errMsg, e, new Status(Status.DbError)); } finally { if (cursor != null) { cursor.Close(); } } return rows; }
public IDictionary<string, object> GetAllDocs(QueryOptions options) { IDictionary<string, object> result = new Dictionary<string, object>(); IList<QueryRow> rows = new AList<QueryRow>(); if (options == null) { options = new QueryOptions(); } bool includeDeletedDocs = (options.GetAllDocsMode() == Query.AllDocsMode.IncludeDeleted ); long updateSeq = 0; if (options.IsUpdateSeq()) { updateSeq = GetLastSequenceNumber(); } // TODO: needs to be atomic with the following SELECT StringBuilder sql = new StringBuilder("SELECT revs.doc_id, docid, revid, sequence" ); if (options.IsIncludeDocs()) { sql.Append(", json"); } if (includeDeletedDocs) { sql.Append(", deleted"); } sql.Append(" FROM revs, docs WHERE"); if (options.GetKeys() != null) { if (options.GetKeys().Count == 0) { return result; } string commaSeperatedIds = JoinQuotedObjects(options.GetKeys()); sql.Append(string.Format(" revs.doc_id IN (SELECT doc_id FROM docs WHERE docid IN (%s)) AND" , commaSeperatedIds)); } sql.Append(" docs.doc_id = revs.doc_id AND current=1"); if (!includeDeletedDocs) { sql.Append(" AND deleted=0"); } IList<string> args = new AList<string>(); object minKey = options.GetStartKey(); object maxKey = options.GetEndKey(); bool inclusiveMin = true; bool inclusiveMax = options.IsInclusiveEnd(); if (options.IsDescending()) { minKey = maxKey; maxKey = options.GetStartKey(); inclusiveMin = inclusiveMax; inclusiveMax = true; } if (minKey != null) { System.Diagnostics.Debug.Assert((minKey is string)); sql.Append((inclusiveMin ? " AND docid >= ?" : " AND docid > ?")); args.AddItem((string)minKey); } if (maxKey != null) { System.Diagnostics.Debug.Assert((maxKey is string)); sql.Append((inclusiveMax ? " AND docid <= ?" : " AND docid < ?")); args.AddItem((string)maxKey); } sql.Append(string.Format(" ORDER BY docid %s, %s revid DESC LIMIT ? OFFSET ?", (options .IsDescending() ? "DESC" : "ASC"), (includeDeletedDocs ? "deleted ASC," : string.Empty ))); args.AddItem(Sharpen.Extensions.ToString(options.GetLimit())); args.AddItem(Sharpen.Extensions.ToString(options.GetSkip())); Cursor cursor = null; IDictionary<string, QueryRow> docs = new Dictionary<string, QueryRow>(); try { cursor = database.RawQuery(sql.ToString(), Sharpen.Collections.ToArray(args, new string[args.Count])); bool keepGoing = cursor.MoveToNext(); while (keepGoing) { long docNumericID = cursor.GetLong(0); string docId = cursor.GetString(1); string revId = cursor.GetString(2); long sequenceNumber = cursor.GetLong(3); bool deleted = includeDeletedDocs && cursor.GetInt(GetDeletedColumnIndex(options) ) > 0; IDictionary<string, object> docContents = null; if (options.IsIncludeDocs()) { byte[] json = cursor.GetBlob(4); docContents = DocumentPropertiesFromJSON(json, docId, revId, deleted, sequenceNumber , options.GetContentOptions()); } // Iterate over following rows with the same doc_id -- these are conflicts. // Skip them, but collect their revIDs if the 'conflicts' option is set: IList<string> conflicts = new AList<string>(); while (((keepGoing = cursor.MoveToNext()) == true) && cursor.GetLong(0) == docNumericID ) { if (options.GetAllDocsMode() == Query.AllDocsMode.ShowConflicts || options.GetAllDocsMode () == Query.AllDocsMode.OnlyConflicts) { if (conflicts.IsEmpty()) { conflicts.AddItem(revId); } conflicts.AddItem(cursor.GetString(2)); } } if (options.GetAllDocsMode() == Query.AllDocsMode.OnlyConflicts && conflicts.IsEmpty ()) { continue; } IDictionary<string, object> value = new Dictionary<string, object>(); value.Put("rev", revId); value.Put("_conflicts", conflicts); if (includeDeletedDocs) { value.Put("deleted", (deleted ? true : null)); } QueryRow change = new QueryRow(docId, sequenceNumber, docId, value, docContents); change.SetDatabase(this); if (options.GetKeys() != null) { docs.Put(docId, change); } else { rows.AddItem(change); } } if (options.GetKeys() != null) { foreach (object docIdObject in options.GetKeys()) { if (docIdObject is string) { string docId = (string)docIdObject; QueryRow change = docs.Get(docId); if (change == null) { IDictionary<string, object> value = new Dictionary<string, object>(); long docNumericID = GetDocNumericID(docId); if (docNumericID > 0) { bool deleted; IList<bool> outIsDeleted = new AList<bool>(); IList<bool> outIsConflict = new AList<bool>(); string revId = WinningRevIDOfDoc(docNumericID, outIsDeleted, outIsConflict); if (outIsDeleted.Count > 0) { deleted = true; } if (revId != null) { value.Put("rev", revId); value.Put("deleted", true); } } change = new QueryRow((value != null ? docId : null), 0, docId, value, null); change.SetDatabase(this); } rows.AddItem(change); } } } } catch (SQLException e) { Log.E(Database.Tag, "Error getting all docs", e); throw new CouchbaseLiteException("Error getting all docs", e, new Status(Status.InternalServerError )); } finally { if (cursor != null) { cursor.Close(); } } result.Put("rows", rows); result.Put("total_rows", rows.Count); result.Put("offset", options.GetSkip()); if (updateSeq != 0) { result.Put("update_seq", updateSeq); } return result; }
internal Cursor ResultSetWithOptions(QueryOptions options) { if (options == null) { options = new QueryOptions(); } // OPT: It would be faster to use separate tables for raw-or ascii-collated views so that // they could be indexed with the right Collation, instead of having to specify it here. var collationStr = string.Empty; if (Collation == ViewCollation.ASCII) { collationStr += " COLLATE JSON_ASCII"; } else { if (Collation == ViewCollation.Raw) { collationStr += " COLLATE JSON_RAW"; } } var sql = "SELECT key, value, docid, revs.sequence"; if (options.IsIncludeDocs()) { sql = sql + ", revid, json"; } sql = sql + " FROM maps, revs, docs WHERE maps.view_id=@"; var argsList = new AList <string>(); argsList.AddItem(Sharpen.Extensions.ToString(Id)); if (options.GetKeys() != null) { sql += " AND key in ("; var item = "@"; foreach (object key in options.GetKeys()) { sql += item; item = ", @"; argsList.AddItem(ToJSONString(key)); } sql += ")"; } var minKey = options.GetStartKey(); var maxKey = options.GetEndKey(); var inclusiveMin = true; var inclusiveMax = options.IsInclusiveEnd(); if (options.IsDescending()) { minKey = maxKey; maxKey = options.GetStartKey(); inclusiveMin = inclusiveMax; inclusiveMax = true; } if (minKey != null) { System.Diagnostics.Debug.Assert((minKey is string)); sql += inclusiveMin ? " AND key >= @" : " AND key > @"; sql += collationStr; argsList.AddItem(ToJSONString(minKey)); } if (maxKey != null) { System.Diagnostics.Debug.Assert((maxKey is string)); if (inclusiveMax) { sql += " AND key <= @"; } else { sql += " AND key < @"; } sql += collationStr; argsList.AddItem(ToJSONString(maxKey)); } sql = sql + " AND revs.sequence = maps.sequence AND docs.doc_id = revs.doc_id ORDER BY key"; sql += collationStr; if (options.IsDescending()) { sql = sql + " DESC"; } sql = sql + " LIMIT @ OFFSET @"; argsList.AddItem(options.GetLimit().ToString()); argsList.AddItem(options.GetSkip().ToString()); Log.V(Database.Tag, "Query " + Name + ": " + sql); var cursor = Database.StorageEngine.RawQuery(sql, CommandBehavior.SequentialAccess, argsList.ToArray()); return(cursor); }