diff --git a/src/mango/test/06-basic-text-test.py b/src/mango/test/06-basic-text-test.py deleted file mode 100644 index da3eb6ff58..0000000000 --- a/src/mango/test/06-basic-text-test.py +++ /dev/null @@ -1,602 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -import json -import mango -import unittest -import user_docs -import math -from hypothesis import given, assume, example, settings -import hypothesis.strategies as st - - -@unittest.skipIf(mango.has_text_service(), "text service exists") -class TextIndexCheckTests(mango.DbPerClass): - def test_create_text_index(self): - body = json.dumps({"index": {}, "type": "text"}) - resp = self.db.sess.post(self.db.path("_index"), data=body) - assert resp.status_code == 503, resp - - -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class BasicTextTests(mango.UserDocsTextTests): - def test_simple(self): - docs = self.db.find({"$text": "Stephanie"}) - assert len(docs) == 1 - assert docs[0]["name"]["first"] == "Stephanie" - - def test_with_integer(self): - docs = self.db.find({"name.first": "Stephanie", "age": 48}) - assert len(docs) == 1 - assert docs[0]["name"]["first"] == "Stephanie" - assert docs[0]["age"] == 48 - - def test_with_boolean(self): - docs = self.db.find({"name.first": "Stephanie", "manager": False}) - assert len(docs) == 1 - assert docs[0]["name"]["first"] == "Stephanie" - assert docs[0]["manager"] == False - - def test_with_array(self): - faves = ["Ruby", "C", "Python"] - docs = self.db.find({"name.first": "Stephanie", "favorites": faves}) - assert docs[0]["name"]["first"] == "Stephanie" - assert docs[0]["favorites"] == faves - - def test_array_ref(self): - docs = self.db.find({"favorites.1": "Python"}) - assert len(docs) == 4 - for d in docs: - assert "Python" in d["favorites"] - - # Nested Level - docs = self.db.find({"favorites.0.2": "Python"}) - assert len(docs) == 1 - for d in docs: - assert "Python" in d["favorites"][0][2] - - def test_number_ref(self): - docs = self.db.find({"11111": "number_field"}) - assert len(docs) == 1 - assert docs[0]["11111"] == "number_field" - - docs = self.db.find({"22222.33333": "nested_number_field"}) - assert len(docs) == 1 - assert docs[0]["22222"]["33333"] == "nested_number_field" - - def test_lt(self): - docs = self.db.find({"age": {"$lt": 22}}) - assert len(docs) == 0 - - docs = self.db.find({"age": {"$lt": 23}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"age": {"$lt": 33}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (1, 9) - - docs = self.db.find({"age": {"$lt": 34}}) - assert len(docs) == 3 - for d in docs: - assert d["user_id"] in (1, 7, 9) - - docs = self.db.find({"company": {"$lt": "Dreamia"}}) - assert len(docs) == 1 - assert docs[0]["company"] == "Affluex" - - docs = self.db.find({"foo": {"$lt": "bar car apple"}}) - assert len(docs) == 0 - - def test_lte(self): - docs = self.db.find({"age": {"$lte": 21}}) - assert len(docs) == 0 - - docs = self.db.find({"age": {"$lte": 22}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"age": {"$lte": 33}}) - assert len(docs) == 3 - for d in docs: - assert d["user_id"] in (1, 7, 9) - - docs = self.db.find({"company": {"$lte": "Dreamia"}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (0, 11) - - docs = self.db.find({"foo": {"$lte": "bar car apple"}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 14 - - def test_eq(self): - docs = self.db.find({"age": 21}) - assert len(docs) == 0 - - docs = self.db.find({"age": 22}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"age": {"$eq": 22}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"age": 33}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 7 - - def test_ne(self): - docs = self.db.find({"age": {"$ne": 22}}) - assert len(docs) == len(user_docs.DOCS) - 1 - for d in docs: - assert d["age"] != 22 - - docs = self.db.find({"$not": {"age": 22}}) - assert len(docs) == len(user_docs.DOCS) - 1 - for d in docs: - assert d["age"] != 22 - - def test_gt(self): - docs = self.db.find({"age": {"$gt": 77}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (3, 13) - - docs = self.db.find({"age": {"$gt": 78}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 3 - - docs = self.db.find({"age": {"$gt": 79}}) - assert len(docs) == 0 - - docs = self.db.find({"company": {"$gt": "Zialactic"}}) - assert len(docs) == 0 - - docs = self.db.find({"foo": {"$gt": "bar car apple"}}) - assert len(docs) == 0 - - docs = self.db.find({"foo": {"$gt": "bar car"}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 14 - - def test_gte(self): - docs = self.db.find({"age": {"$gte": 77}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (3, 13) - - docs = self.db.find({"age": {"$gte": 78}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (3, 13) - - docs = self.db.find({"age": {"$gte": 79}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 3 - - docs = self.db.find({"age": {"$gte": 80}}) - assert len(docs) == 0 - - docs = self.db.find({"company": {"$gte": "Zialactic"}}) - assert len(docs) == 1 - assert docs[0]["company"] == "Zialactic" - - docs = self.db.find({"foo": {"$gte": "bar car apple"}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 14 - - def test_and(self): - docs = self.db.find({"age": 22, "manager": True}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"age": 22, "manager": False}) - assert len(docs) == 0 - - docs = self.db.find({"$and": [{"age": 22}, {"manager": True}]}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"$and": [{"age": 22}, {"manager": False}]}) - assert len(docs) == 0 - - docs = self.db.find({"$text": "Ramona", "age": 22}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"$and": [{"$text": "Ramona"}, {"age": 22}]}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"$and": [{"$text": "Ramona"}, {"$text": "Floyd"}]}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - def test_or(self): - docs = self.db.find({"$or": [{"age": 22}, {"age": 33}]}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (7, 9) - - q = {"$or": [{"$text": "Ramona"}, {"$text": "Stephanie"}]} - docs = self.db.find(q) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (0, 9) - - q = {"$or": [{"$text": "Ramona"}, {"age": 22}]} - docs = self.db.find(q) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - def test_and_or(self): - q = {"age": 22, "$or": [{"manager": False}, {"location.state": "Missouri"}]} - docs = self.db.find(q) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - q = {"$or": [{"age": 22}, {"age": 43, "manager": True}]} - docs = self.db.find(q) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (9, 10) - - q = {"$or": [{"$text": "Ramona"}, {"age": 43, "manager": True}]} - docs = self.db.find(q) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (9, 10) - - def test_nor(self): - docs = self.db.find({"$nor": [{"age": 22}, {"age": 33}]}) - assert len(docs) == 13 - for d in docs: - assert d["user_id"] not in (7, 9) - - def test_in_with_value(self): - docs = self.db.find({"age": {"$in": [1, 5]}}) - assert len(docs) == 0 - - docs = self.db.find({"age": {"$in": [1, 5, 22]}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 9 - - docs = self.db.find({"age": {"$in": [1, 5, 22, 31]}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (1, 9) - - docs = self.db.find({"age": {"$in": [22, 31]}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (1, 9) - - # Limits on boolean clauses? - docs = self.db.find({"age": {"$in": list(range(1000))}}) - assert len(docs) == 15 - - def test_in_with_array(self): - vals = ["Random Garbage", 52, {"Versions": {"Alpha": "Beta"}}] - docs = self.db.find({"favorites": {"$in": vals}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 1 - - vals = ["Lisp", "Python"] - docs = self.db.find({"favorites": {"$in": vals}}) - assert len(docs) == 10 - - vals = [{"val1": 1, "val2": "val2"}] - docs = self.db.find({"test_in": {"$in": vals}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 2 - - def test_nin_with_value(self): - docs = self.db.find({"age": {"$nin": [1, 5]}}) - assert len(docs) == len(user_docs.DOCS) - - docs = self.db.find({"age": {"$nin": [1, 5, 22]}}) - assert len(docs) == len(user_docs.DOCS) - 1 - for d in docs: - assert d["user_id"] != 9 - - docs = self.db.find({"age": {"$nin": [1, 5, 22, 31]}}) - assert len(docs) == len(user_docs.DOCS) - 2 - for d in docs: - assert d["user_id"] not in (1, 9) - - docs = self.db.find({"age": {"$nin": [22, 31]}}) - assert len(docs) == len(user_docs.DOCS) - 2 - for d in docs: - assert d["user_id"] not in (1, 9) - - # Limits on boolean clauses? - docs = self.db.find({"age": {"$nin": list(range(1000))}}) - assert len(docs) == 0 - - def test_nin_with_array(self): - vals = ["Random Garbage", 52, {"Versions": {"Alpha": "Beta"}}] - docs = self.db.find({"favorites": {"$nin": vals}}) - assert len(docs) == len(user_docs.DOCS) - 1 - for d in docs: - assert d["user_id"] != 1 - - vals = ["Lisp", "Python"] - docs = self.db.find({"favorites": {"$nin": vals}}) - assert len(docs) == 5 - - vals = [{"val1": 1, "val2": "val2"}] - docs = self.db.find({"test_in": {"$nin": vals}}) - assert len(docs) == 0 - - def test_all(self): - vals = ["Ruby", "C", "Python", {"Versions": {"Alpha": "Beta"}}] - docs = self.db.find({"favorites": {"$all": vals}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 1 - - # This matches where favorites either contains - # the nested array, or is the nested array. This is - # notably different than the non-nested array in that - # it does not match a re-ordered version of the array. - # The fact that user_id 14 isn't included demonstrates - # this behavior. - vals = [["Lisp", "Erlang", "Python"]] - docs = self.db.find({"favorites": {"$all": vals}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (3, 9) - - def test_exists_field(self): - docs = self.db.find({"exists_field": {"$exists": True}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (7, 8) - - docs = self.db.find({"exists_field": {"$exists": False}}) - assert len(docs) == len(user_docs.DOCS) - 2 - for d in docs: - assert d["user_id"] not in (7, 8) - - def test_exists_array(self): - docs = self.db.find({"exists_array": {"$exists": True}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (9, 10) - - docs = self.db.find({"exists_array": {"$exists": False}}) - assert len(docs) == len(user_docs.DOCS) - 2 - for d in docs: - assert d["user_id"] not in (9, 10) - - def test_exists_object(self): - docs = self.db.find({"exists_object": {"$exists": True}}) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (11, 12) - - docs = self.db.find({"exists_object": {"$exists": False}}) - assert len(docs) == len(user_docs.DOCS) - 2 - for d in docs: - assert d["user_id"] not in (11, 12) - - def test_exists_object_member(self): - docs = self.db.find({"exists_object.should": {"$exists": True}}) - assert len(docs) == 1 - assert docs[0]["user_id"] == 11 - - docs = self.db.find({"exists_object.should": {"$exists": False}}) - assert len(docs) == len(user_docs.DOCS) - 1 - for d in docs: - assert d["user_id"] != 11 - - def test_exists_and(self): - q = { - "$and": [ - {"manager": {"$exists": True}}, - {"exists_object.should": {"$exists": True}}, - ] - } - docs = self.db.find(q) - assert len(docs) == 1 - assert docs[0]["user_id"] == 11 - - q = { - "$and": [ - {"manager": {"$exists": False}}, - {"exists_object.should": {"$exists": True}}, - ] - } - docs = self.db.find(q) - assert len(docs) == 0 - - # Translates to manager exists or exists_object.should doesn't - # exist, which will match all docs - q = {"$not": q} - docs = self.db.find(q) - assert len(docs) == len(user_docs.DOCS) - - def test_value_chars(self): - q = {"complex_field_value": '+-(){}[]^~&&*||"\\/?:!'} - docs = self.db.find(q) - assert len(docs) == 1 - - def test_regex(self): - docs = self.db.find( - {"age": {"$gt": 40}, "location.state": {"$regex": "(?i)new.*"}} - ) - assert len(docs) == 2 - assert docs[0]["user_id"] == 2 - assert docs[1]["user_id"] == 10 - - # test lucene syntax in $text - - -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class ElemMatchTests(mango.FriendDocsTextTests): - def test_elem_match_non_object(self): - q = {"bestfriends": {"$elemMatch": {"$eq": "Wolverine", "$eq": "Cyclops"}}} - docs = self.db.find(q) - self.assertEqual(len(docs), 1) - self.assertEqual(docs[0]["bestfriends"], ["Wolverine", "Cyclops"]) - - q = {"results": {"$elemMatch": {"$gte": 80, "$lt": 85}}} - - docs = self.db.find(q) - self.assertEqual(len(docs), 1) - self.assertEqual(docs[0]["results"], [82, 85, 88]) - - def test_elem_match(self): - q = {"friends": {"$elemMatch": {"name.first": "Vargas"}}} - docs = self.db.find(q) - self.assertEqual(len(docs), 2) - for d in docs: - self.assertIn(d["user_id"], (0, 1)) - - q = {"friends": {"$elemMatch": {"name.first": "Ochoa", "name.last": "Burch"}}} - docs = self.db.find(q) - self.assertEqual(len(docs), 1) - self.assertEqual(docs[0]["user_id"], 4) - - # Check that we can do logic in elemMatch - q = {"friends": {"$elemMatch": {"name.first": "Ochoa", "type": "work"}}} - docs = self.db.find(q) - self.assertEqual(len(docs), 2) - for d in docs: - self.assertIn(d["user_id"], (1, 15)) - - q = { - "friends": { - "$elemMatch": { - "name.first": "Ochoa", - "$or": [{"type": "work"}, {"type": "personal"}], - } - } - } - docs = self.db.find(q) - self.assertEqual(len(docs), 3) - for d in docs: - self.assertIn(d["user_id"], (1, 4, 15)) - - # Same as last, but using $in - q = { - "friends": { - "$elemMatch": { - "name.first": "Ochoa", - "type": {"$in": ["work", "personal"]}, - } - } - } - docs = self.db.find(q) - self.assertEqual(len(docs), 3) - for d in docs: - self.assertIn(d["user_id"], (1, 4, 15)) - - q = { - "$and": [ - {"friends": {"$elemMatch": {"id": 0, "name": {"$exists": True}}}}, - { - "friends": { - "$elemMatch": { - "$or": [ - {"name": {"first": "Campos", "last": "Freeman"}}, - { - "name": { - "$in": [ - {"first": "Gibbs", "last": "Mccarty"}, - {"first": "Wilkins", "last": "Chang"}, - ] - } - }, - ] - } - } - }, - ] - } - docs = self.db.find(q) - self.assertEqual(len(docs), 3) - for d in docs: - self.assertIn(d["user_id"], (10, 11, 12)) - - -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class AllMatchTests(mango.FriendDocsTextTests): - def test_all_match(self): - q = {"friends": {"$allMatch": {"type": "personal"}}} - docs = self.db.find(q) - assert len(docs) == 2 - for d in docs: - assert d["user_id"] in (8, 5) - - # Check that we can do logic in allMatch - q = { - "friends": { - "$allMatch": { - "name.first": "Ochoa", - "$or": [{"type": "work"}, {"type": "personal"}], - } - } - } - docs = self.db.find(q) - assert len(docs) == 1 - assert docs[0]["user_id"] == 15 - - # Same as last, but using $in - q = { - "friends": { - "$allMatch": { - "name.first": "Ochoa", - "type": {"$in": ["work", "personal"]}, - } - } - } - docs = self.db.find(q) - assert len(docs) == 1 - assert docs[0]["user_id"] == 15 - - -# Test numeric strings for $text -@unittest.skipUnless(mango.has_text_service(), "requires text service") -class NumStringTests(mango.DbPerClass): - @classmethod - def setUpClass(klass): - super(NumStringTests, klass).setUpClass() - klass.db.recreate() - klass.db.create_text_index() - - # not available for python 2.7.x - def isFinite(num): - not (math.isinf(num) or math.isnan(num)) - - @given(f=st.floats().filter(isFinite).map(str) | st.floats().map(lambda f: f.hex())) - @settings(deadline=1000) - @example("NaN") - @example("Infinity") - def test_floating_point_val(self, f): - doc = {"number_string": f} - self.db.save_doc(doc) - q = {"$text": f} - docs = self.db.find(q) - if len(docs) == 1: - assert docs[0]["number_string"] == f - if len(docs) == 2: - if docs[0]["number_string"] != f: - assert docs[1]["number_string"] == f - q = {"number_string": f} - docs = self.db.find(q) - if len(docs) == 1: - assert docs[0]["number_string"] == f - if len(docs) == 2: - if docs[0]["number_string"] != f: - assert docs[1]["number_string"] == f diff --git a/test/elixir/test/config/search.elixir b/test/elixir/test/config/search.elixir index 87715d4caf..ab30a7a9cf 100644 --- a/test/elixir/test/config/search.elixir +++ b/test/elixir/test/config/search.elixir @@ -34,9 +34,43 @@ "facet ranges, non-empty" ], "ElemMatchTests": [ - "elem match non object" + "elem match non object", + "elem match" + ], + "AllMatchTests": [ + "all match" ], "LimitTests": [ "limit field" + ], + "BasicTextTests": [ + "simple", + "with integer", + "with boolean", + "with array", + "array ref", + "number ref", + "lt", + "lte", + "eq", + "ne", + "gt", + "gte", + "and", + "or", + "and or", + "nor", + "in with value", + "in with array", + "nin with value", + "nin with array", + "all", + "exists field", + "exists array", + "exists object", + "exists object member", + "exists and", + "value chars", + "regex", ] } diff --git a/test/elixir/test/config/suite.elixir b/test/elixir/test/config/suite.elixir index b3fb950846..4d802ce46a 100644 --- a/test/elixir/test/config/suite.elixir +++ b/test/elixir/test/config/suite.elixir @@ -735,5 +735,8 @@ ], "IgnoreDesignDocsForAllDocsIndexTests": [ "should not return design docs" - ] + ], + "TextIndexCheckTests": [ + "create text index" + ], } diff --git a/test/elixir/test/mango/06_basic_text_test.exs b/test/elixir/test/mango/06_basic_text_test.exs index 310cd9cdbb..480692001f 100644 --- a/test/elixir/test/mango/06_basic_text_test.exs +++ b/test/elixir/test/mango/06_basic_text_test.exs @@ -10,6 +10,509 @@ # License for the specific language governing permissions and limitations under # the License. +defmodule TextIndexCheckTests do + use CouchTestCase + + @db_name "text-index-check" + @users_db "_users" + + @moduletag config: [ + { + "chttpd_auth", + "authentication_db", + @users_db + }, + { + "couch_httpd_auth", + "authentication_db", + @users_db + }, + { + "chttpd_auth", + "iterations", + "1" + }, + { + "admins", + "jan", + "apple" + } + ] + + setup do + MangoDatabase.recreate(@db_name) + MangoDatabase.recreate(@users_db) + :ok + end + + test "create text index" do + sess = Couch.login("jan", "apple") + + resp = Couch.Session.post( + sess, + "/#{@db_name}/_index", + body: %{"index" => %{}, "type" => "text"} + ) + + assert resp.status_code == 503 + assert resp + end +end + +defmodule BasicTextTests do + use CouchTestCase + + @db_name "basic-text-elem-match" + + setup do + UserDocs.setup(@db_name, "text") + end + + test "simple" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"$text" => "Stephanie"}) + + assert length(docs) == 1 + assert Enum.at(docs, 0)["name"]["first"] == "Stephanie" + end + + test "with integer" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"name.first" => "Stephanie", "age" => 48}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["name"]["first"] == "Stephanie" + assert Enum.at(docs, 0)["age"] == 48 + end + + test "with boolean" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"name.first" => "Stephanie", "manager" => false}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["name"]["first"] == "Stephanie" + assert Enum.at(docs, 0)["manager"] == false + end + + test "with array" do + faves = ["Ruby", "C", "Python"] + {:ok, docs} = MangoDatabase.find(@db_name, %{"name.first" => "Stephanie", "favorites" => faves}) + assert Enum.at(docs, 0)["name"]["first"] == "Stephanie" + assert Enum.at(docs, 0)["favorites"] == faves + end + + test "array ref" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites.1" => "Python"}) + assert length(docs) == 4 + assert Enum.all?(Enum.map(docs, & &1["favorites"]), fn fav -> Enum.member?(fav, "Python") end) + + # Nested Level + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites.0.2" => "Python"}) + assert length(docs) == 1 + nested_favorite = Enum.map(docs, fn d -> d["favorites"] |> Enum.at(0) |> Enum.at(2) end) + assert Enum.at(nested_favorite, 0) == "Python" + end + + test "number ref" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"11111" => "number_field"}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["11111"] == "number_field" + + {:ok, docs} = MangoDatabase.find(@db_name, %{"22222.33333" => "nested_number_field"}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["22222"]["33333"] == "nested_number_field" + end + + test "lt" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 22}}) + assert assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 23}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 33}}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 9] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 34}}) + assert length(docs) == 3 + + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 7, 9] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"company" => %{"$lt" => "Dreamia"}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["company"] == "Affluex" + + {:ok, docs} = MangoDatabase.find(@db_name, %{"foo" => %{"$lt" => "bar car apple"}}) + assert Enum.empty?(docs) + end + + test "lte" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lte" => 21}}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lte" => 22}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lte" => 33}}) + assert length(docs) == 3 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 7, 9] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"company" => %{"$lte" => "Dreamia"}}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert user_ids == [0, 11] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"foo" => %{"$lte" => "bar car apple"}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 14 + end + + test "eq" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => 21}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => 22}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$eq" => 22}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => 33}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 7 + end + + test "ne" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$ne" => 22}}) + assert length(docs) == UserDocs.len() - 1 + assert Enum.all?(docs, fn doc -> doc["age"] != 22 end) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"$not" => %{"age" => 22}}) + assert length(docs) == UserDocs.len() - 1 + assert Enum.all?(docs, fn doc -> doc["age"] != 22 end) + end + + test "gt" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gt" => 77}}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [3, 13] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gt" => 78}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 3 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gt" => 79}}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"company" => %{"$gt" => "Zialactic"}}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"foo" => %{"$gt" => "bar car apple"}}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"foo" => %{"$gt" => "bar car"}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 14 + end + + test "gte" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gte" => 77}}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [3, 13] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gte" => 78}}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [3, 13] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gte" => 79}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 3 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$gte" => 80}}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"company" => %{"$gte" => "Zialactic"}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["company"] == "Zialactic" + + {:ok, docs} = MangoDatabase.find(@db_name, %{"foo" => %{"$gte" => "bar car apple"}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 14 + end + + test "and" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => 22, "manager" => true}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => 22, "manager" => false}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"$and" => [%{"age" => 22}, %{"manager" => true}]}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"$and" => [%{"age" => 22}, %{"manager" => false}]}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"$text" => "Ramona", "age" => 22}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"$and" => [%{"$text" => "Ramona"}, %{"age" => 22}]}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"$and" => [%{"$text" => "Ramona"}, %{"$text" => "Floyd"}]}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + end + + test "or" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"$or" => [%{"age" => 22}, %{"age" => 33}]}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [7, 9] + + q = %{"$or" => [%{"$text" => "Ramona"}, %{"$text" => "Stephanie"}]} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [0, 9] + + q = %{"$or" => [%{"$text" => "Ramona"}, %{"age" => 22}]} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + end + + test "and or" do + q = %{"age" => 22, "$or" => [%{"manager" => false}, %{"location.state" => "Missouri"}]} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + q = %{"$or" => [%{"age" => 22}, %{"age" => 43, "manager" => true}]} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [9, 10] + + q = %{"$or" => [%{"$text" => "Ramona"}, %{"age" => 43, "manager" => true}]} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [9, 10] + end + + test "nor" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"$nor" => [%{"age" => 22}, %{"age" => 33}]}) + assert length(docs) == 13 + assert Enum.all?(docs, fn doc -> + not Enum.member?([7, 9], doc["user_id"]) + end) + end + + test "in with value" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$in" => [1, 5]}}) + assert Enum.empty?(docs) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$in" => [1, 5, 22]}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 9 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$in" => [1, 5, 22, 31]}}) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 9] + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$in" => [22, 31]}}) + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 9] + + # Limits on boolean clauses? + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$in" => Enum.to_list(0..999)}}) + assert length(docs) == 15 + end + + test "in with array" do + vals = ["Random Garbage", 52, %{"Versions" => %{"Alpha" => "Beta"}}] + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites" => %{"$in" => vals}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 1 + + vals = ["Lisp", "Python"] + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites" => %{"$in" => vals}}) + assert length(docs) == 10 + + vals = [%{"val1" => 1, "val2" => "val2"}] + {:ok, docs} = MangoDatabase.find(@db_name, %{"test_in" => %{"$in" => vals}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 2 + end + + test "nin with value" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$nin" => [1, 5]}}) + assert length(docs) == UserDocs.len() + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$nin" => [1, 5, 22]}}) + assert length(docs) == UserDocs.len() - 1 + assert Enum.all?(docs, fn doc -> doc["user_id"] != 9 end) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$nin" => [1, 5, 22, 31]}}) + assert length(docs) == UserDocs.len() - 2 + assert Enum.all?(docs, fn doc -> + not Enum.member?([1, 9], doc["user_id"]) + end) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$nin" => [22, 31]}}) + assert length(docs) == UserDocs.len() - 2 + assert Enum.all?(docs, fn doc -> + not Enum.member?([1, 9], doc["user_id"]) + end) + + # Limits on boolean clauses? + {:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$nin" => Enum.to_list(0..1000)}}) + assert Enum.empty?(docs) + end + + test "nin with array" do + vals = ["Random Garbage", 52, %{"Versions" => %{"Alpha" => "Beta"}}] + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites" => %{"$nin" => vals}}) + assert length(docs) == UserDocs.len() - 1 + assert Enum.all?(docs, fn doc -> doc["user_id"] != 1 end) + + vals = ["Lisp", "Python"] + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites" => %{"$nin" => vals}}) + assert length(docs) == 5 + + vals = [%{"val1" => 1, "val2" => "val2"}] + {:ok, docs} = MangoDatabase.find(@db_name, %{"test_in" => %{"$nin" => vals}}) + assert Enum.empty?(docs) + end + + test "all" do + vals = ["Ruby", "C", "Python", %{"Versions" => %{"Alpha" => "Beta"}}] + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites" => %{"$all" => vals}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 1 + + # This matches where favorites either contains + # the nested array, or is the nested array. This is + # notably different than the non-nested array in that + # it does not match a re-ordered version of the array. + # The fact that user_id 14 isn't included demonstrates + # this behavior. + vals = [["Lisp", "Erlang", "Python"]] + {:ok, docs} = MangoDatabase.find(@db_name, %{"favorites" => %{"$all" => vals}}) + assert length(docs) == 2 + assert Enum.all?(docs, fn doc -> + Enum.member?([3, 9], doc["user_id"]) + end) + end + + test "exists field" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_field" => %{"$exists" => true}}) + assert length(docs) == 2 + assert Enum.all?(docs, fn doc -> + Enum.member?([7, 8], doc["user_id"]) + end) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_field" => %{"$exists" => false}}) + assert length(docs) == UserDocs.len() - 2 + assert Enum.all?(docs, fn doc -> + not Enum.member?([7, 8], doc["user_id"]) + end) + end + + test "exists array" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_array" => %{"$exists" => true}}) + assert length(docs) == 2 + assert Enum.all?(docs, fn doc -> + Enum.member?([9, 10], doc["user_id"]) + end) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_array" => %{"$exists" => false}}) + assert length(docs) == UserDocs.len() - 2 + assert Enum.all?(docs, fn doc -> + not Enum.member?([9, 10], doc["user_id"]) + end) + end + + test "exists object" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_object" => %{"$exists" => true}}) + assert length(docs) == 2 + assert Enum.all?(docs, fn doc -> + Enum.member?([11, 12], doc["user_id"]) + end) + + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_object" => %{"$exists" => false}}) + assert length(docs) == UserDocs.len() - 2 + assert Enum.all?(docs, fn doc -> + not Enum.member?([11, 12], doc["user_id"]) + end) + end + + test "exists object member" do + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_object.should" => %{"$exists" => true}}) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 11 + + {:ok, docs} = MangoDatabase.find(@db_name, %{"exists_object.should" => %{"$exists" => false}}) + assert length(docs) == UserDocs.len() - 1 + assert Enum.all?(docs, fn doc -> doc["user_id"] != 11 end) + end + + test "exists and" do + q = %{ + "$and" => [ + %{"manager" => %{"$exists" => true}}, + %{"exists_object.should" => %{"$exists" => true}}, + ] + } + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 11 + + q = %{ + "$and" => [ + %{"manager" => %{"$exists" => false}}, + %{"exists_object.should" => %{"$exists" => true}}, + ] + } + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert Enum.empty?(docs) + + # Translates to manager exists or exists_object.should doesn't + # exist, which will match all docs + q = %{"$not" => q} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == UserDocs.len() + end + + # escape the " + test "value chars" do + q = %{"complex_field_value" => "+-(){}[]^~&&*||\"\\/?:!"} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + end + + test "regex" do + {:ok, docs} = MangoDatabase.find(@db_name, + %{"age" => %{"$gt" => 40}, "location.state" => %{"$regex" => "(?i)new.*"}} + ) + assert length(docs) == 2 + assert Enum.at(docs, 0)["user_id"] == 2 + assert Enum.at(docs, 1)["user_id"] == 10 + end +end + defmodule ElemMatchTests do use CouchTestCase @@ -30,4 +533,130 @@ defmodule ElemMatchTests do assert length(docs) == 1 assert Enum.at(docs, 0)["results"] == [82, 85, 88] end + + test "elem match" do + q = %{"friends" => %{"$elemMatch" => %{"name.first" => "Vargas"}}} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [0, 1] + + q = %{"friends" => %{"$elemMatch" => %{"name.first" => "Ochoa", "name.last" => "Burch"}}} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 4 + + # Check that we can do logic in elemMatch + q = %{"friends" => %{"$elemMatch" => %{"name.first" => "Ochoa", "type" => "work"}}} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 15] + + q = %{ + "friends" => %{ + "$elemMatch" => %{ + "name.first" => "Ochoa", + "$or" => [%{"type" => "work"}, %{"type" => "personal"}], + } + } + } + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 3 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 4, 15] + + # Same as last, but using $in + q = %{ + "friends" => %{ + "$elemMatch" => %{ + "name.first" => "Ochoa", + "type" => %{"$in" => ["work", "personal"]}, + } + } + } + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 3 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [1, 4, 15] + + q = %{ + "$and" => [ + %{ + "friends" => %{ + "$elemMatch" => %{ + "id" => 0, + "name" => %{"$exists" => true} + } + } + }, + %{ + "friends" => %{ + "$elemMatch" => %{ + "$or" => [ + %{"name" => %{"first" => "Campos", "last" => "Freeman"}}, + %{ + "name" => %{ + "$in" => [ + %{"first" => "Gibbs", "last" => "Mccarty"}, + %{"first" => "Wilkins", "last" => "Chang"} + ] + } + } + ] + } + } + } + ] + } + + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 3 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [10, 11, 12] + end +end + +defmodule AllMatchTests do + use CouchTestCase + + @db_name "basic-text-elem-match" + + setup do + FriendDocs.setup(@db_name, "text") + end + + test "all match" do + q = %{"friends" => %{"$allMatch" => %{"type" => "personal"}}} + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 2 + user_ids = Enum.map(docs, fn doc -> doc["user_id"] end) + assert Enum.sort(user_ids) == [5, 8] + + # Check that we can do logic in allMatch + q = %{ + "friends" => %{ + "$allMatch" => %{ + "name.first" => "Ochoa", + "$or" => [%{"type" => "work"}, %{"type" => "personal"}], + } + } + } + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 15 + + # Same as last, but using $in + q = %{ + "friends" => %{ + "$allMatch" => %{ + "name.first" => "Ochoa", + "type" => %{"$in" => ["work", "personal"]}, + } + } + } + {:ok, docs} = MangoDatabase.find(@db_name, q) + assert length(docs) == 1 + assert Enum.at(docs, 0)["user_id"] == 15 + end end diff --git a/test/elixir/test/support/user_docs.ex b/test/elixir/test/support/user_docs.ex index eb015cc64b..9b8f14b0c8 100644 --- a/test/elixir/test/support/user_docs.ex +++ b/test/elixir/test/support/user_docs.ex @@ -217,7 +217,7 @@ defmodule UserDocs do "twitter" => nil, "favorites" => ["Lisp", "Erlang", "Python"], "exists_array" => ["should", "exist", "array1"], - "complex_field_value" => '+-()%{}[]^~&&*||"\\/? =>!', + "complex_field_value" => "+-(){}[]^~&&*||\"\\/?:!", "ordered" => true, }, %{