1# Licensed under the Apache License, Version 2.0 (the "License"); you may not 2# use this file except in compliance with the License. You may obtain a copy of 3# the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations under 11# the License. 12 13import mango 14import unittest 15 16 17class OperatorTests: 18 def assertUserIds(self, user_ids, docs): 19 user_ids_returned = list(d["user_id"] for d in docs) 20 user_ids.sort() 21 user_ids_returned.sort() 22 self.assertEqual(user_ids, user_ids_returned) 23 24 def test_all(self): 25 docs = self.db.find( 26 {"manager": True, "favorites": {"$all": ["Lisp", "Python"]}} 27 ) 28 self.assertEqual(len(docs), 3) 29 user_ids = [2, 12, 9] 30 self.assertUserIds(user_ids, docs) 31 32 def test_all_non_array(self): 33 docs = self.db.find({"manager": True, "location": {"$all": ["Ohai"]}}) 34 self.assertEqual(len(docs), 0) 35 36 def test_elem_match(self): 37 emdocs = [ 38 {"user_id": "a", "bang": [{"foo": 1, "bar": 2}]}, 39 {"user_id": "b", "bang": [{"foo": 2, "bam": True}]}, 40 ] 41 self.db.save_docs(emdocs, w=3) 42 docs = self.db.find( 43 { 44 "_id": {"$gt": None}, 45 "bang": {"$elemMatch": {"foo": {"$gte": 1}, "bam": True}}, 46 } 47 ) 48 self.assertEqual(len(docs), 1) 49 self.assertEqual(docs[0]["user_id"], "b") 50 51 def test_all_match(self): 52 amdocs = [ 53 {"user_id": "a", "bang": [{"foo": 1, "bar": 2}, {"foo": 3, "bar": 4}]}, 54 {"user_id": "b", "bang": [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 4}]}, 55 ] 56 self.db.save_docs(amdocs, w=3) 57 docs = self.db.find( 58 {"bang": {"$allMatch": {"foo": {"$mod": [2, 1]}, "bar": {"$mod": [2, 0]}}}} 59 ) 60 self.assertEqual(len(docs), 1) 61 self.assertEqual(docs[0]["user_id"], "a") 62 63 def test_empty_all_match(self): 64 amdocs = [{"bad_doc": "a", "emptybang": []}] 65 self.db.save_docs(amdocs, w=3) 66 docs = self.db.find({"emptybang": {"$allMatch": {"foo": {"$eq": 2}}}}) 67 self.assertEqual(len(docs), 0) 68 69 def test_keymap_match(self): 70 amdocs = [ 71 {"foo": {"aa": "bar", "bb": "bang"}}, 72 {"foo": {"cc": "bar", "bb": "bang"}}, 73 ] 74 self.db.save_docs(amdocs, w=3) 75 docs = self.db.find({"foo": {"$keyMapMatch": {"$eq": "aa"}}}) 76 self.assertEqual(len(docs), 1) 77 78 def test_in_operator_array(self): 79 docs = self.db.find({"manager": True, "favorites": {"$in": ["Ruby", "Python"]}}) 80 self.assertUserIds([2, 6, 7, 9, 11, 12], docs) 81 82 def test_nin_operator_array(self): 83 docs = self.db.find( 84 {"manager": True, "favorites": {"$nin": ["Erlang", "Python"]}} 85 ) 86 self.assertEqual(len(docs), 4) 87 for doc in docs: 88 if isinstance(doc["favorites"], list): 89 self.assertNotIn("Erlang", doc["favorites"]) 90 self.assertNotIn("Python", doc["favorites"]) 91 92 def test_regex(self): 93 docs = self.db.find( 94 {"age": {"$gt": 40}, "location.state": {"$regex": "(?i)new.*"}} 95 ) 96 self.assertEqual(len(docs), 2) 97 self.assertUserIds([2, 10], docs) 98 99 def test_exists_false(self): 100 docs = self.db.find({"age": {"$gt": 0}, "twitter": {"$exists": False}}) 101 user_ids = [2, 3, 5, 6, 7, 8, 10, 11, 12, 14] 102 self.assertUserIds(user_ids, docs) 103 for d in docs: 104 self.assertNotIn("twitter", d) 105 106 def test_eq_null_does_not_include_missing(self): 107 docs = self.db.find({"age": {"$gt": 0}, "twitter": None}) 108 user_ids = [9] 109 self.assertUserIds(user_ids, docs) 110 for d in docs: 111 self.assertEqual(d["twitter"], None) 112 113 def test_ne_includes_null_but_not_missing(self): 114 docs = self.db.find({"twitter": {"$ne": "notamatch"}}) 115 user_ids = [0, 1, 4, 9, 13] 116 self.assertUserIds(user_ids, docs) 117 for d in docs: 118 self.assertIn("twitter", d) 119 120 # ideally this work be consistent across index types but, alas, it is not 121 @unittest.skipUnless( 122 not mango.has_text_service(), 123 "text indexes do not support range queries across type boundaries", 124 ) 125 def test_lt_includes_null_but_not_missing(self): 126 docs = self.db.find({"twitter": {"$lt": 1}}) 127 user_ids = [9] 128 self.assertUserIds(user_ids, docs) 129 for d in docs: 130 self.assertEqual(d["twitter"], None) 131 132 @unittest.skipUnless( 133 not mango.has_text_service(), 134 "text indexes do not support range queries across type boundaries", 135 ) 136 def test_lte_includes_null_but_not_missing(self): 137 docs = self.db.find({"twitter": {"$lt": 1}}) 138 user_ids = [9] 139 self.assertUserIds(user_ids, docs) 140 for d in docs: 141 self.assertEqual(d["twitter"], None) 142 143 def test_lte_null_includes_null_but_not_missing(self): 144 docs = self.db.find({"twitter": {"$lte": None}}) 145 user_ids = [9] 146 self.assertUserIds(user_ids, docs) 147 for d in docs: 148 self.assertEqual(d["twitter"], None) 149 150 def test_lte_at_z_except_null_excludes_null_and_missing(self): 151 docs = self.db.find({"twitter": {"$and": [{"$lte": "@z"}, {"$ne": None}]}}) 152 user_ids = [0, 1, 4, 13] 153 self.assertUserIds(user_ids, docs) 154 for d in docs: 155 self.assertNotEqual(d["twitter"], None) 156 157 def test_range_gte_null_includes_null_but_not_missing(self): 158 docs = self.db.find({"twitter": {"$gte": None}}) 159 self.assertGreater(len(docs), 0) 160 for d in docs: 161 self.assertIn("twitter", d) 162 163 def test_exists_false_returns_missing_but_not_null(self): 164 docs = self.db.find({"twitter": {"$exists": False}}) 165 self.assertGreater(len(docs), 0) 166 for d in docs: 167 self.assertNotIn("twitter", d) 168 169 @unittest.skipUnless( 170 not mango.has_text_service(), 171 "text indexes do not support range queries across type boundaries", 172 ) 173 def test_lte_respsects_unicode_collation(self): 174 docs = self.db.find({"ordered": {"$lte": "a"}}) 175 user_ids = [7, 8, 9, 10, 11, 12] 176 self.assertUserIds(user_ids, docs) 177 178 @unittest.skipUnless( 179 not mango.has_text_service(), 180 "text indexes do not support range queries across type boundaries", 181 ) 182 def test_gte_respsects_unicode_collation(self): 183 docs = self.db.find({"ordered": {"$gte": "a"}}) 184 user_ids = [12, 13, 14] 185 self.assertUserIds(user_ids, docs) 186 187 188class OperatorJSONTests(mango.UserDocsTests, OperatorTests): 189 pass 190 191 192@unittest.skipUnless(mango.has_text_service(), "requires text service") 193class OperatorTextTests(mango.UserDocsTextTests, OperatorTests): 194 pass 195 196 197class OperatorAllDocsTests(mango.UserDocsTestsNoIndexes, OperatorTests): 198 def test_range_id_eq(self): 199 doc_id = "8e1c90c0-ac18-4832-8081-40d14325bde0" 200 r = self.db.find({"_id": doc_id}, explain=True, return_raw=True) 201 202 self.assertEqual(r["mrargs"]["end_key"], doc_id) 203 self.assertEqual(r["mrargs"]["start_key"], doc_id) 204