summaryrefslogtreecommitdiff
path: root/src/mango/test/12-use-correct-index-test.py
blob: c21ad6c5e10aa3e1430a091e431520558943bde4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# 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 mango
import copy

DOCS = [
    {"_id": "_design/my-design-doc"},
    {
        "_id": "54af50626de419f5109c962f",
        "user_id": 0,
        "age": 10,
        "name": "Jimi",
        "location": "UK",
        "number": 4,
    },
    {
        "_id": "54af50622071121b25402dc3",
        "user_id": 1,
        "age": 12,
        "name": "Eddie",
        "location": "ZAR",
        "number": 2,
    },
    {
        "_id": "54af50622071121b25402dc6",
        "user_id": 1,
        "age": 6,
        "name": "Harry",
        "location": "US",
        "number": 8,
    },
    {
        "_id": "54af50622071121b25402dc9",
        "name": "Eddie",
        "occupation": "engineer",
        "number": 7,
    },
]


class ChooseCorrectIndexForDocs(mango.DbPerClass):
    def setUp(self):
        self.db.recreate()
        self.db.save_docs(copy.deepcopy(DOCS))

    def test_choose_index_with_one_field_in_index(self):
        self.db.create_index(["name", "age", "user_id"], ddoc="aaa")
        self.db.create_index(["name"], ddoc="zzz")
        explain = self.db.find({"name": "Eddie"}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/zzz")

    def test_choose_index_with_two(self):
        self.db.create_index(["name", "age", "user_id"], ddoc="aaa")
        self.db.create_index(["name", "age"], ddoc="bbb")
        self.db.create_index(["name"], ddoc="zzz")
        explain = self.db.find({"name": "Eddie", "age": {"$gte": 12}}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/bbb")

    def test_choose_index_alphabetically(self):
        self.db.create_index(["name"], ddoc="aaa")
        self.db.create_index(["name"], ddoc="bbb")
        self.db.create_index(["name"], ddoc="zzz")
        explain = self.db.find({"name": "Eddie", "age": {"$gte": 12}}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/aaa")

    def test_choose_index_most_accurate(self):
        self.db.create_index(["name", "age", "user_id"], ddoc="aaa")
        self.db.create_index(["name", "age"], ddoc="bbb")
        self.db.create_index(["name"], ddoc="zzz")
        explain = self.db.find({"name": "Eddie", "age": {"$gte": 12}}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/bbb")

    def test_choose_index_most_accurate_in_memory_selector(self):
        self.db.create_index(["name", "location", "user_id"], ddoc="aaa")
        self.db.create_index(["name", "age", "user_id"], ddoc="bbb")
        self.db.create_index(["name"], ddoc="zzz")
        explain = self.db.find({"name": "Eddie", "number": {"$lte": 12}}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/zzz")

    def test_warn_on_full_db_scan(self):
        selector = {"not_indexed": "foo"}
        explain_resp = self.db.find(selector, explain=True, return_raw=True)
        self.assertEqual(explain_resp["index"]["type"], "special")
        resp = self.db.find(selector, return_raw=True)
        self.assertEqual(
            resp["warning"].split("\n")[0].lower(),
            "no matching index found, create an index to optimize query time.",
        )

    def test_chooses_idxA(self):
        DOCS2 = [{"a": 1, "b": 1, "c": 1}, {"a": 1000, "d": 1000, "e": 1000}]
        self.db.save_docs(copy.deepcopy(DOCS2))
        self.db.create_index(["a", "b", "c"])
        self.db.create_index(["a", "d", "e"])
        explain = self.db.find(
            {"a": {"$gt": 0}, "b": {"$gt": 0}, "c": {"$gt": 0}}, explain=True
        )
        self.assertEqual(
            explain["index"]["def"]["fields"],
            [{"a": "asc"}, {"b": "asc"}, {"c": "asc"}],
        )

    def test_can_query_with_range_on_secondary_column(self):
        self.db.create_index(["age", "name"], ddoc="bbb")
        selector = {"age": 10, "name": {"$gte": 0}}
        docs = self.db.find(selector)
        self.assertEqual(len(docs), 1)
        explain = self.db.find(selector, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/bbb")
        self.assertEqual(explain["mrargs"]["end_key"], [10, "<MAX>"])

    # all documents contain an _id and _rev field they
    # should not be used to restrict indexes based on the
    # fields required by the selector
    def test_choose_index_with_id(self):
        self.db.create_index(["name", "_id"], ddoc="aaa")
        explain = self.db.find({"name": "Eddie"}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/aaa")

    def test_choose_index_with_rev(self):
        self.db.create_index(["name", "_rev"], ddoc="aaa")
        explain = self.db.find({"name": "Eddie"}, explain=True)
        self.assertEqual(explain["index"]["ddoc"], "_design/aaa")