PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/casbah-core/src/test/scala/QueryIntegrationSpec.scala

http://github.com/mongodb/casbah
Scala | 519 lines | 444 code | 54 blank | 21 comment | 6 complexity | 868af7f3d3cff3441d818de8c3820a66 MD5 | raw file
Possible License(s): Apache-2.0
  1. /**
  2. * Copyright (c) 2010 MongoDB, Inc. <http://mongodb.com>
  3. * Copyright (c) 2009, 2010 Novus Partners, Inc. <http://novus.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * For questions and comments about this product, please see the project page at:
  18. *
  19. * http://github.com/mongodb/casbah
  20. *
  21. */
  22. package com.mongodb.casbah.test.core
  23. import scala.collection.JavaConverters._
  24. import scala.language.reflectiveCalls
  25. import com.mongodb.WriteConcernException
  26. import com.mongodb.casbah.Imports._
  27. @SuppressWarnings(Array("deprecation"))
  28. class QueryIntegrationSpec extends CasbahDBTestSpecification {
  29. "Casbah's collection string representation" should {
  30. "not read the collection" in {
  31. collection.toString must beEqualTo(collection.name)
  32. }
  33. }
  34. "$set" should {
  35. "Work with a single pair" in {
  36. collection.drop()
  37. collection += MongoDBObject("foo" -> "baz")
  38. collection.update(MongoDBObject("foo" -> "baz"), $set("foo" -> "bar"))
  39. collection.find(MongoDBObject("foo" -> "bar")).count must beEqualTo(1)
  40. }
  41. "Work with multiple pairs" in {
  42. val set = $set("foo" -> "baz", "x" -> 5.2,
  43. "y" -> 9, "a" -> ("b", "c", "d", "e"))
  44. collection.drop()
  45. collection += MongoDBObject("foo" -> "bar")
  46. collection.update(MongoDBObject("foo" -> "baz"), set)
  47. collection.find(MongoDBObject("foo" -> "bar")).count must beEqualTo(1)
  48. }
  49. }
  50. "$setOnInsert" should {
  51. "Work with a single pair" in {
  52. serverIsAtLeastVersion(2, 4) must beTrue.orSkip("Needs server >= 2.4")
  53. collection.drop()
  54. try {
  55. collection.update(MongoDBObject(), $setOnInsert("foo" -> "baz"), upsert = true)
  56. collection.find(MongoDBObject("foo" -> "baz")).count must beEqualTo(1)
  57. } catch {
  58. case ex: WriteConcernException if ex.getErrorMessage != "Invalid modifier specified $setOnInsert" =>
  59. throw ex
  60. }
  61. success
  62. }
  63. "Work with multiple pairs" in {
  64. serverIsAtLeastVersion(2, 4) must beTrue.orSkip("Needs server >= 2.4")
  65. val set = $setOnInsert("foo" -> "baz", "x" -> 5.2,
  66. "y" -> 9, "a" -> ("b", "c", "d", "e"))
  67. collection.drop()
  68. try {
  69. collection.update(MongoDBObject(), set, upsert = true)
  70. collection.find(MongoDBObject("foo" -> "baz")).count must beEqualTo(1)
  71. } catch {
  72. case ex: WriteConcernException =>
  73. if (ex.getErrorMessage != "Invalid modifier specified $setOnInsert")
  74. throw ex
  75. }
  76. success
  77. }
  78. "work combined with $set" in {
  79. serverIsAtLeastVersion(2, 4) must beTrue.orSkip("Needs server >= 2.4")
  80. collection.drop()
  81. try {
  82. collection.update(MongoDBObject(), $setOnInsert("x" -> 1) ++ $set("a" -> "b"), true)
  83. collection.find(MongoDBObject("x" -> 1)).count must beEqualTo(1)
  84. collection.find(MongoDBObject("a" -> "b")).count must beEqualTo(1)
  85. } catch {
  86. case ex: WriteConcernException =>
  87. if (ex.getErrorMessage != "Invalid modifier specified $setOnInsert")
  88. throw ex
  89. }
  90. success
  91. }
  92. }
  93. "$unset" should {
  94. "work as a single item" in {
  95. collection.drop()
  96. collection += MongoDBObject("foo" -> "baz", "hello" -> "world")
  97. collection.update(MongoDBObject("foo" -> "baz"), $unset("foo"))
  98. collection.findOne().get.keySet.asScala must beEqualTo(Set("_id", "hello"))
  99. }
  100. "work with multiple items" in {
  101. collection.drop()
  102. collection += MongoDBObject(
  103. "foo" -> "One",
  104. "bar" -> 1,
  105. "x" -> "X",
  106. "y" -> "Y",
  107. "hello" -> "world"
  108. )
  109. val unset = $unset("foo", "bar", "x", "y")
  110. collection.update(MongoDBObject("hello" -> "world"), unset)
  111. collection.findOne().get.keySet.asScala must beEqualTo(Set("_id", "hello"))
  112. }
  113. }
  114. "$where" should {
  115. "work as expected" in {
  116. collection.drop()
  117. collection += MongoDBObject("foo" -> "baz")
  118. collection.find($where("this.foo == 'baz'")).count must beEqualTo(1)
  119. }
  120. }
  121. "$inc" should {
  122. "Work with a single pair" in {
  123. collection.drop()
  124. collection += MongoDBObject("hello" -> "world")
  125. collection.update(MongoDBObject("hello" -> "world"), $inc("foo" -> 5.0))
  126. collection.findOne().get("foo") must beEqualTo(5)
  127. }
  128. "Work with multiple pairs" in {
  129. collection.drop()
  130. collection += MongoDBObject("hello" -> "world")
  131. val inc = $inc("foo" -> 5.0, "bar" -> -1.2)
  132. collection.update(MongoDBObject("hello" -> "world"), inc)
  133. val doc = collection.findOne()
  134. doc.get("foo") must beEqualTo(5)
  135. doc.get("bar") must beEqualTo(-1.2)
  136. }
  137. }
  138. "$max" should {
  139. "Work with a single pair" in {
  140. serverIsAtLeastVersion(2, 6) must beTrue.orSkip("Needs server >= 2.6")
  141. collection.drop()
  142. collection += MongoDBObject("hello" -> "world", "foo" -> 5.0)
  143. collection.update(MongoDBObject("hello" -> "world"), $max("foo" -> 6.0))
  144. collection.findOne().get("foo") must beEqualTo(6)
  145. }
  146. "Work with multiple pairs" in {
  147. serverIsAtLeastVersion(2, 6) must beTrue.orSkip("Needs server >= 2.6")
  148. collection.drop()
  149. collection += MongoDBObject("hello" -> "world", "foo" -> 5.0, "bar" -> 5.0)
  150. val max = $max("foo" -> 3.0, "bar" -> 10.0)
  151. collection.update(MongoDBObject("hello" -> "world"), max)
  152. val doc = collection.findOne()
  153. doc.get("foo") must beEqualTo(5)
  154. doc.get("bar") must beEqualTo(10)
  155. }
  156. }
  157. "$or" should {
  158. "load some test data first" in {
  159. collection.drop()
  160. collection += MongoDBObject("foo" -> "bar")
  161. collection += MongoDBObject("foo" -> 6)
  162. collection += MongoDBObject("foo" -> 5)
  163. collection += MongoDBObject("x" -> 11)
  164. success
  165. }
  166. "Accept multiple values" in {
  167. val or = $or("foo" -> "bar", "foo" -> 6)
  168. collection.find(or).count must beEqualTo(2)
  169. }
  170. "Accept a mix" in {
  171. val or = $or {
  172. "foo" -> "bar" :: ("foo" $gt 5 $lt 10)
  173. }
  174. collection.find(or).count must beEqualTo(2)
  175. }
  176. "Work with nested operators" in {
  177. "As a simple list (comma separated)" in {
  178. val or = $or("foo" $lt 6 $gt 1, "x" $gte 10 $lte 152)
  179. collection.find(or).count must beEqualTo(2)
  180. }
  181. "As a cons (:: constructed) cell" in {
  182. val or = $or(("foo" $lt 6 $gt 1) :: ("x" $gte 10 $lte 152))
  183. collection.find(or).count must beEqualTo(2)
  184. }
  185. }
  186. }
  187. "$nor" should {
  188. "load some test data first" in {
  189. collection.drop()
  190. collection += MongoDBObject("foo" -> "bar", "x" -> "y")
  191. collection += MongoDBObject("foo" -> "baz", "x" -> "y")
  192. collection += MongoDBObject("foo" -> 6, "x" -> 5)
  193. collection += MongoDBObject("foo" -> 5, "x" -> 6)
  194. success
  195. }
  196. "Accept multiple values" in {
  197. val nor = $nor("foo" -> "bar", "x" -> "y")
  198. collection.find(nor).count must beEqualTo(2)
  199. }
  200. "Accept a mix" in {
  201. val nor = $nor("foo" -> 5 :: ("foo" $gt 5 $lt 10))
  202. collection.find(nor).count must beEqualTo(2)
  203. }
  204. "Work with nested operators" in {
  205. "As a simple list (comma separated)" in {
  206. val nor = $nor("foo" $lt 6 $gt 1, "x" $gte 6 $lte 10)
  207. collection.find(nor).count must beEqualTo(3)
  208. }
  209. "As a cons (:: constructed) cell" in {
  210. val nor = $nor(("foo" $lt 6 $gt 1) :: ("x" $gte 6 $lte 10))
  211. collection.find(nor).count must beEqualTo(3)
  212. }
  213. }
  214. }
  215. "$and" should {
  216. "load some test data first" in {
  217. collection.drop()
  218. collection += MongoDBObject("foo" -> "bar", "x" -> "y")
  219. collection += MongoDBObject("foo" -> "bar", "x" -> 5)
  220. collection += MongoDBObject("foo" -> "bar", "x" -> 11)
  221. collection += MongoDBObject("foo" -> 4, "x" -> 11)
  222. success
  223. }
  224. "Accept multiple values" in {
  225. val and = $and("foo" -> "bar", "x" -> "y")
  226. collection.find(and).count must beEqualTo(1)
  227. }
  228. "Accept a mix" in {
  229. val and = $and {
  230. "foo" -> "bar" :: ("x" $gte 5 $lt 10)
  231. }
  232. collection.find(and).count must beEqualTo(1)
  233. }
  234. "Work with nested operators" in {
  235. "As a simple list (comma separated)" in {
  236. val and = $and("foo" $lt 5 $gt 1, "x" $gte 10 $lte 152)
  237. collection.find(and).count must beEqualTo(1)
  238. }
  239. "As a cons (:: constructed) cell" in {
  240. val and = $and(("foo" $lt 5 $gt 1) :: ("x" $gte 10 $lte 152))
  241. collection.find(and).count must beEqualTo(1)
  242. }
  243. }
  244. }
  245. "$rename" should {
  246. "Accept one or many sets of renames" in {
  247. "A single set" in {
  248. collection.drop()
  249. collection += MongoDBObject("foo" -> "bar", "x" -> "y")
  250. val rename = $rename("foo" -> "bar")
  251. collection.update(MongoDBObject("foo" -> "bar"), rename)
  252. collection.findOne().get.keySet.asScala must containAllOf(Seq("_id", "bar", "x"))
  253. }
  254. "Multiple sets" in {
  255. collection.drop()
  256. collection += MongoDBObject("foo" -> "bar", "x" -> "y")
  257. val rename = $rename("foo" -> "bar", "x" -> "y")
  258. collection.update(MongoDBObject("foo" -> "bar"), rename)
  259. collection.findOne().get.keySet.asScala must containAllOf(Seq("_id", "bar", "y"))
  260. }
  261. }
  262. }
  263. "Casbah's DSL Array operators" should {
  264. "$push" in {
  265. "Accept a single value" in {
  266. collection.drop()
  267. collection += MongoDBObject("foo" -> "bar")
  268. val push = $push("x" -> "y")
  269. collection.update(MongoDBObject("foo" -> "bar"), push)
  270. val doc = collection.findOne().get
  271. doc.keySet.asScala must beEqualTo(Set("_id", "foo", "x"))
  272. doc.as[MongoDBList]("x") must beEqualTo(MongoDBList("y"))
  273. }
  274. "Accept multiple values" in {
  275. collection.drop()
  276. collection += MongoDBObject("a" -> "b")
  277. val push = $push("foo" -> "bar", "x" -> 5.2)
  278. collection.update(MongoDBObject("a" -> "b"), push)
  279. val doc = collection.findOne().get
  280. doc.keySet.asScala must beEqualTo(Set("_id", "a", "foo", "x"))
  281. doc.as[MongoDBList]("foo") must beEqualTo(MongoDBList("bar"))
  282. doc.as[MongoDBList]("x") must beEqualTo(MongoDBList(5.2))
  283. }
  284. }
  285. "$pushAll" in {
  286. "Accept a single value list" in {
  287. collection.drop()
  288. collection += MongoDBObject("foo" -> "bar")
  289. val push = $pushAll("baz" -> ("bar", "baz", "x", "y"))
  290. collection.update(MongoDBObject("foo" -> "bar"), push)
  291. val doc = collection.findOne().get
  292. doc.keySet.asScala must containAllOf(Seq("_id", "baz", "foo"))
  293. doc.as[MongoDBList]("baz") must beEqualTo(MongoDBList("bar", "baz", "x", "y"))
  294. }
  295. "Accept multiple value lists" in {
  296. collection.drop()
  297. collection += MongoDBObject("a" -> "b")
  298. val push = $pushAll("foo" -> ("bar", "baz", "x", "y"), "x" -> (5, 10, 12, 238))
  299. collection.update(MongoDBObject("a" -> "b"), push)
  300. val doc = collection.findOne().get
  301. doc.keySet.asScala must containAllOf(Seq("_id", "a", "foo", "x"))
  302. doc.as[MongoDBList]("foo") must beEqualTo(MongoDBList("bar", "baz", "x", "y"))
  303. doc.as[MongoDBList]("x") must beEqualTo(MongoDBList(5, 10, 12, 238))
  304. }
  305. }
  306. "$pull" in {
  307. "Accept a single value" in {
  308. collection.drop()
  309. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(3, 2, 1))
  310. val pull = $pull("foo" -> 2)
  311. collection.update(MongoDBObject("a" -> "b"), pull)
  312. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(3, 1))
  313. }
  314. "Allow Value Test Operators" in {
  315. "A simple $gt test" in {
  316. collection.drop()
  317. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(3, 2, 1))
  318. val pull = $pull("foo" $gt 2)
  319. collection.update(MongoDBObject("a" -> "b"), pull)
  320. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(2, 1))
  321. }
  322. "A deeper chain test" in {
  323. collection.drop()
  324. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(30, 20, 10, 3, 2, 1))
  325. val pull = $pull("foo" $gt 5 $lte 52)
  326. collection.update(MongoDBObject("a" -> "b"), pull)
  327. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(3, 2, 1))
  328. }
  329. "a sub document from a list" in {
  330. collection.drop()
  331. collection += MongoDBObject("_id" -> "xyz", "answers" -> MongoDBList(
  332. MongoDBObject("name" -> "Yes"),
  333. MongoDBObject("name" -> "No")
  334. ))
  335. val pull = $pull("answers" -> MongoDBObject("name" -> "Yes"))
  336. collection.update(MongoDBObject("_id" -> "xyz"), pull)
  337. collection.findOne().get.as[MongoDBList]("answers") must beEqualTo(MongoDBList(MongoDBObject("name" -> "No")))
  338. }
  339. }
  340. "Accept multiple values" in {
  341. collection.drop()
  342. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(3, 2, 1), "x" -> MongoDBList(5.1, 5.2, 5.3))
  343. val pull = $pull("foo" -> 2, "x" -> 5.2)
  344. collection.update(MongoDBObject("a" -> "b"), pull)
  345. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(3, 1))
  346. collection.findOne().get.as[MongoDBList]("x") must beEqualTo(MongoDBList(5.1, 5.3))
  347. }
  348. }
  349. "$pullAll" in {
  350. "Accept a single value list" in {
  351. collection.drop()
  352. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(30, 20, 10, 3, 2, 1))
  353. val pull = $pullAll("foo" -> (30, 20, 10))
  354. collection.update(MongoDBObject("a" -> "b"), pull)
  355. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(3, 2, 1))
  356. }
  357. "Accept multiple value lists" in {
  358. collection.drop()
  359. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(3, 2, 1), "x" -> MongoDBList(5.1, 5.2, 5.3))
  360. val pull = $pullAll("foo" -> (3, 2), "x" -> (5.1, 5.2))
  361. collection.update(MongoDBObject("a" -> "b"), pull)
  362. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(1))
  363. collection.findOne().get.as[MongoDBList]("x") must beEqualTo(MongoDBList(5.3))
  364. }
  365. }
  366. }
  367. "$addToSet" in {
  368. "Accept a single value" in {
  369. collection.drop()
  370. collection += MongoDBObject("a" -> "b")
  371. val addToSet = $addToSet("foo" -> "bar")
  372. collection.update(MongoDBObject("a" -> "b"), addToSet)
  373. val doc = collection.findOne().get
  374. doc.as[MongoDBList]("foo") must beEqualTo(MongoDBList("bar"))
  375. }
  376. "Accept multiple values" in {
  377. collection.drop()
  378. collection += MongoDBObject("a" -> "b")
  379. val addToSet = $addToSet("foo" -> "bar", "x" -> 5.2)
  380. collection.update(MongoDBObject("a" -> "b"), addToSet)
  381. val doc = collection.findOne().get
  382. doc.keySet.asScala must beEqualTo(Set("_id", "a", "foo", "x"))
  383. doc.as[MongoDBList]("foo") must beEqualTo(MongoDBList("bar"))
  384. doc.as[MongoDBList]("x") must beEqualTo(MongoDBList(5.2))
  385. }
  386. "Function with the $each operator for multi-value updates" in {
  387. collection.drop()
  388. collection += MongoDBObject("a" -> "b")
  389. val addToSet = $addToSet("foo") $each ("x", "y", "foo", "bar", "baz")
  390. collection.update(MongoDBObject("a" -> "b"), addToSet)
  391. val doc = collection.findOne().get
  392. doc.as[MongoDBList]("foo") must beEqualTo(MongoDBList("x", "y", "foo", "bar", "baz"))
  393. }
  394. }
  395. "$pop" in {
  396. "Accept a single value" in {
  397. collection.drop()
  398. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(3, 2, 1))
  399. val pop = $pop("foo" -> 1)
  400. collection.update(MongoDBObject("a" -> "b"), pop)
  401. collection.findOne().get.as[MongoDBList]("foo") must beEqualTo(MongoDBList(3, 2))
  402. }
  403. "Accept multiple values" in {
  404. collection.drop()
  405. collection += MongoDBObject("a" -> "b", "foo" -> MongoDBList(3, 2, 1), "x" -> MongoDBList(1, 2, 3))
  406. val pop = $pop("foo" -> 1, "x" -> -1)
  407. collection.update(MongoDBObject("a" -> "b"), pop)
  408. val doc = collection.findOne().get
  409. doc.as[MongoDBList]("foo") must beEqualTo(MongoDBList(3, 2))
  410. doc.as[MongoDBList]("x") must beEqualTo(MongoDBList(2, 3))
  411. }
  412. }
  413. "$bit" in {
  414. "Accept a single value For 'and'" in {
  415. collection.drop()
  416. collection += MongoDBObject("foo" -> 5)
  417. val bit = $bit("foo") and 1
  418. collection.update(MongoDBObject("foo" -> 5), bit)
  419. collection.findOne().get("foo") must beEqualTo(1)
  420. }
  421. "Accept a single value For 'or'" in {
  422. collection.drop()
  423. collection += MongoDBObject("foo" -> 5)
  424. val bit = $bit("foo") or 1
  425. collection.update(MongoDBObject("foo" -> 5), bit)
  426. collection.findOne().get("foo") must beEqualTo(5)
  427. }
  428. }
  429. "$text operator" should {
  430. "Setup and load some test data first" in {
  431. serverIsAtLeastVersion(2, 5) must beTrue.orSkip("Needs server >= 2.5")
  432. val enableTextCommand = MongoDBObject("setParameter" -> 1, "textSearchEnabled" -> true)
  433. collection.getDB.getSisterDB("admin").command(enableTextCommand)
  434. val textIndex = MongoDBObject("a" -> "text")
  435. collection.drop()
  436. collection.createIndex(textIndex)
  437. collection += MongoDBObject("_id" -> 0, "unindexedField" -> 0, "a" -> "textual content")
  438. collection += MongoDBObject("_id" -> 1, "unindexedField" -> 1, "a" -> "additional content")
  439. collection += MongoDBObject("_id" -> 2, "unindexedField" -> 2, "a" -> "irrelevant content")
  440. success
  441. }
  442. "Accept just $text" in {
  443. serverIsAtLeastVersion(2, 5) must beTrue.orSkip("Needs server >= 2.5")
  444. collection.find($text("textual content -irrelevant")).count should beEqualTo(2)
  445. }
  446. "Accept $text and other operators" in {
  447. serverIsAtLeastVersion(2, 5) must beTrue.orSkip("Needs server >= 2.5")
  448. collection.find(("unindexedField" $eq 0) ++ $text("textual content -irrelevant")).count should beEqualTo(1)
  449. }
  450. "Accept $text and $language" in {
  451. serverIsAtLeastVersion(2, 5) must beTrue.orSkip("Needs server >= 2.5")
  452. collection.find($text("textual content -irrelevant") $language "english").count should beEqualTo(2)
  453. }
  454. "Work with $meta projection" in {
  455. serverIsAtLeastVersion(2, 5) must beTrue.orSkip("Needs server >= 2.5")
  456. collection.find($text("textual content -irrelevant"), "score" $meta).count should beEqualTo(2)
  457. val result = collection.findOne($text("textual content -irrelevant"), "score" $meta)
  458. result must haveSomeField("score")
  459. }
  460. "Work with $meta in projection and sort" in {
  461. serverIsAtLeastVersion(2, 5) must beTrue.orSkip("Needs server >= 2.5")
  462. collection.find($text("textual content -irrelevant"), "score" $meta).sort("score" $meta).count should beEqualTo(2)
  463. }
  464. }
  465. }