-
Notifications
You must be signed in to change notification settings - Fork 77
/
IndexCheckerTest.scala
192 lines (158 loc) · 7.66 KB
/
IndexCheckerTest.scala
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright 2011 Foursquare Labs Inc. All Rights Reserved.
package com.foursquare.rogue
import com.foursquare.rogue.LiftRogue._
import net.liftweb.mongodb.record._
import net.liftweb.mongodb.record.field._
import net.liftweb.record._
import net.liftweb.record.field.{BooleanField, IntField}
import scala.collection.immutable.ListMap
import org.bson.types.ObjectId
import org.joda.time.DateTime
import org.junit._
import org.specs.SpecsMatchers
class TestModel extends MongoRecord[TestModel] with MongoId[TestModel] {
def meta = TestModel
object a extends IntField(this)
object b extends IntField(this)
object c extends IntField(this)
object d extends IntField(this)
object m extends MongoMapField[TestModel, Int](this)
object n extends MongoMapField[TestModel, Int](this)
object ll extends MongoCaseClassField[TestModel, LatLong](this)
}
object TestModel extends TestModel with MongoMetaRecord[TestModel] with IndexedRecord[TestModel] {
override def collectionName = "model"
override val mongoIndexList = List(
TestModel.index(_._id, Asc),
TestModel.index(_.a, Asc, _.b, Asc, _.c, Asc),
TestModel.index(_.m, Asc, _.a, Asc),
TestModel.index(_.ll, TwoD, _.b, Asc))
}
class MongoIndexCheckerTest extends SpecsMatchers {
@Test
def testIndexExpectations {
def test(query: GenericQuery[_, _]) = {
val q = query.asInstanceOf[GenericBaseQuery[_, _]]
MongoIndexChecker.validateIndexExpectations(q)
}
def yes(query: GenericQuery[_, _]) =
test(query) must beTrue
def no(query: GenericQuery[_, _]) =
test(query) must beFalse
yes(TestModel where (_.a eqs 1))
yes(TestModel iscan (_.a eqs 1))
yes(TestModel scan (_.a eqs 1))
no(TestModel where (_.a > 1))
yes(TestModel iscan (_.a > 1))
yes(TestModel scan (_.a > 1))
no(TestModel where (_.a neqs 1))
yes(TestModel iscan (_.a neqs 1))
yes(TestModel scan (_.a neqs 1))
no(TestModel where (_.a exists true))
no(TestModel iscan (_.a exists true))
yes(TestModel scan (_.a exists true))
no(TestModel where (_.ll near (1.0, 2.0, Degrees(1.0))))
yes(TestModel iscan (_.ll near (1.0, 2.0, Degrees(1.0))))
yes(TestModel scan (_.ll near (1.0, 2.0, Degrees(1.0))))
// $or queries
yes(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.where(_.b eqs 2)))
no(TestModel where (_.a eqs 1) or (_.where(_.b > 2), _.where(_.b < 2)))
yes(TestModel where (_.a eqs 1) or (_.iscan(_.b > 2), _.iscan(_.b < 2)))
yes(TestModel where (_.a eqs 1) or (_.scan(_.b > 2), _.scan(_.b < 2)))
no(TestModel where (_.a eqs 1) or (_.where(_.b exists true), _.where(_.b eqs 0)))
no(TestModel where (_.a eqs 1) or (_.iscan(_.b exists true), _.where(_.b eqs 0)))
yes(TestModel where (_.a eqs 1) or (_.scan(_.b exists true), _.where(_.b eqs 0)))
}
@Test
def testMatchesIndex {
def test(query: GenericQuery[_, _]) = {
val q = query.asInstanceOf[GenericBaseQuery[_, _]]
MongoIndexChecker.validateIndexExpectations(q) &&
MongoIndexChecker.validateQueryMatchesSomeIndex(q)
}
def yes(query: GenericQuery[_, _]) =
test(query) must beTrue
def no(query: GenericQuery[_, _]) =
test(query) must beFalse
yes(TestModel where (_.a eqs 1))
yes(TestModel where (_.a eqs 1) and (_.b eqs 2))
yes(TestModel where (_.a eqs 1) and (_.b eqs 2) and (_.c eqs 3))
yes(TestModel where (_.a eqs 1) and (_.c eqs 3) and (_.b eqs 2))
// Skip level
yes(TestModel where (_.a eqs 1) iscan (_.c eqs 3))
yes(TestModel where (_.a eqs 1) scan (_.c eqs 3))
no(TestModel where (_.a eqs 1) and (_.c eqs 3))
// Missing initial
yes(TestModel scan (_.b eqs 2))
no(TestModel where (_.b eqs 2))
no(TestModel iscan (_.b eqs 2))
// Range
yes(TestModel iscan (_.a > 1) iscan (_.b eqs 2))
yes(TestModel scan (_.a > 1) scan (_.b eqs 2))
no(TestModel where (_.a > 1) and (_.b eqs 2))
no(TestModel where (_.a > 1) iscan (_.b eqs 2))
yes(TestModel where (_.a eqs 1) and (_.b eqs 2) iscan (_.c > 3))
// Range placement
yes(TestModel where (_.a eqs 1) iscan (_.b eqs 2) iscan (_.c > 3))
yes(TestModel where (_.a eqs 1) iscan (_.b > 2) iscan (_.c eqs 3))
yes(TestModel iscan (_.a > 1) iscan (_.b eqs 2) iscan (_.c eqs 3))
// Double range
yes(TestModel iscan (_.a > 1) iscan (_.b > 2) iscan (_.c eqs 3))
no(TestModel where (_.a > 1) and (_.b > 2) and (_.c eqs 3))
no(TestModel where (_.a > 1) and (_.b > 2) iscan (_.c eqs 3))
no(TestModel where (_.a > 1) iscan (_.b > 2) iscan (_.c eqs 3))
no(TestModel where (_.a > 1) iscan (_.b > 2) and (_.c eqs 3))
yes(TestModel iscan (_.a > 1) scan (_.b > 2) scan (_.c eqs 3))
yes(TestModel iscan (_.a > 1) scan (_.b > 2) iscan (_.c eqs 3))
yes(TestModel where (_.a eqs 1) iscan (_.b > 2) iscan (_.c > 3))
no(TestModel where (_.a eqs 1) and (_.b > 2) iscan (_.c > 3))
// Unindexable
yes(TestModel scan (_.a exists true))
no(TestModel where (_.a exists true))
no(TestModel iscan (_.a exists true))
yes(TestModel scan (_.a exists true) scan (_.b eqs 3))
no(TestModel scan (_.a exists true) iscan (_.b eqs 3))
// Not in index
yes(TestModel where (_.a eqs 1) scan (_.d eqs 4))
no(TestModel where (_.a eqs 1) and (_.d eqs 4))
no(TestModel where (_.a eqs 1) iscan (_.d eqs 4))
// 2d indexes
yes(TestModel iscan (_.ll near (1.0, 2.0, Degrees(1.0))) iscan (_.b eqs 2))
no(TestModel where (_.ll near (1.0, 2.0, Degrees(1.0))) and (_.b eqs 2))
no(TestModel where (_.ll near (1.0, 2.0, Degrees(1.0))) iscan (_.b eqs 2))
no(TestModel iscan (_.ll near (1.0, 2.0, Degrees(1.0))) and (_.b eqs 2))
yes(TestModel iscan (_.ll near (1.0, 2.0, Degrees(1.0))) scan (_.c eqs 2))
no(TestModel iscan (_.ll near (1.0, 2.0, Degrees(1.0))) iscan (_.c eqs 2))
// Overspecifed queries
val id = new ObjectId
val d = new DateTime
yes(TestModel where (_._id eqs id) and (_.d eqs 4))
yes(TestModel where (_._id in List(id)) and (_.d eqs 4))
no(TestModel where (_._id after d) scan (_.d eqs 4))
no(TestModel iscan (_._id after d) iscan (_.d eqs 4))
yes(TestModel iscan (_._id after d) scan (_.d eqs 4))
// Multikeys
yes(TestModel scan (_.m at "foo" eqs 2))
no(TestModel where (_.m at "foo" eqs 2))
no(TestModel iscan (_.m at "foo" eqs 2))
//TODO(markcc) yes(TestModel where (_.n at "foo" eqs 2))
no(TestModel where (_.n at "fo" eqs 2))
no(TestModel where (_.n at "foot" eqs 2))
no(TestModel where (_.n at "bar" eqs 2))
// $or queries
yes(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.where(_.b eqs 2)))
no(TestModel where (_.a eqs 1) or (_.where(_.d eqs 4), _.where(_.d eqs 4)))
no(TestModel where (_.a eqs 1) or (_.iscan(_.d eqs 4), _.iscan(_.d eqs 4)))
yes(TestModel where (_.a eqs 1) or (_.scan(_.d eqs 4), _.scan(_.d eqs 4)))
no(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.where(_.d eqs 4)))
yes(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.scan(_.d eqs 4)))
no(TestModel where (_.a eqs 1) or (_.where(_.c eqs 3), _.where(_.c eqs 3)))
yes(TestModel where (_.a eqs 1) or (_.iscan(_.c eqs 3), _.iscan(_.c eqs 3)))
no(TestModel where (_.a eqs 1) and (_.b between (2, 2)) or (_.where(_.c eqs 3), _.where(_.c eqs 3)))
yes(TestModel where (_.a eqs 1) iscan (_.b between (2, 2)) or (_.iscan(_.c eqs 3), _.iscan(_.c eqs 3)))
yes(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.where(_.b eqs 2)) and (_.c eqs 3))
no(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.where(_.b > 2)) and (_.c eqs 3))
no(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.iscan(_.b > 2)) and (_.c eqs 3))
yes(TestModel where (_.a eqs 1) or (_.where(_.b eqs 2), _.iscan(_.b > 2)) iscan (_.c eqs 3))
}
}