Skip to content

Commit

Permalink
- Backport of MongoDBObject related changes related to typing from 1.…
Browse files Browse the repository at this point in the history
…1 development

- Inclusion of Specs, with backport of MongoDBObjectSpec from 1.1 branch
- Improvement of type returns from MongoDBObject
    * Builder and Factory now ALWAYS return a DBObject which makes more sense
  • Loading branch information
bwmcadams committed Aug 29, 2010
1 parent 8305d63 commit b69511c
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 10 deletions.
2 changes: 2 additions & 0 deletions project/build/CasbahProject.scala
Expand Up @@ -6,6 +6,8 @@ class CasbahProject(info: ProjectInfo) extends DefaultProject(info) with rsync.R
val scalaTime = "org.scala-tools" % "time" % "2.8.0-0.2-SNAPSHOT"

val configgy = "net.lag" % "configgy_2.8.0" % "1.5.2"

val specs = "org.scala-tools.testing" %% "specs" % "1.6.5" % "test->default"
val scalatest = "org.scalatest" % "scalatest" % "1.2-for-scala-2.8.0.final-SNAPSHOT" % "test"

val scalajCollection = "org.scalaj" % "scalaj-collection_2.8.0" % "1.0"
Expand Down
18 changes: 9 additions & 9 deletions src/main/scala/mongodb/MongoDBObject.scala
Expand Up @@ -41,7 +41,7 @@ import scala.reflect._
* due to conflicts between the java methods and scala methods.
* Implicits and explicit methods allow you to convert to java though.
*
* This is a very crappy, thin interface and likely to go away. Use it at your own risk.
* We will likely reimplement DBObject itself longterm as a pure base. on the wire format
* @author Brendan W. McAdams <bmcadams@novus.com>
* @version 1.0, 06/02/10
* @since 1.0
Expand All @@ -63,7 +63,7 @@ trait MongoDBObject extends Map[String, AnyRef] with Logging {


/** Lazy utility method to allow typing without conflicting with Map's required get() method and causing ambiguity */
def getAs[A <% AnyRef : Manifest](key: String): Option[A] = {
def getAs[A <: Any : Manifest](key: String): Option[A] = {
require(manifest[A] != manifest[scala.Nothing], "Type inference failed; getAs[A]() requires an explicit type argument (e.g. dbObject[<ReturnType](\"someKey\") ) to function correctly.")
underlying.get(key) match {
case null => None
Expand All @@ -78,12 +78,12 @@ trait MongoDBObject extends Map[String, AnyRef] with Logging {
* Your type parameter must be that of the item at the bottom of the tree you specify...
* If cast fails - it's your own fault.
*/
def expand[A <% AnyRef : Manifest](key: String): Option[A] = {
def expand[A <: Any : Manifest](key: String): Option[A] = {
require(manifest[A] != manifest[scala.Nothing], "Type inference failed; expand[A]() requires an explicit type argument (e.g. dbObject[<ReturnType](\"someKey\") ) to function correctly.")
@tailrec def _dot(dbObj: DBObject, key: String): Option[DBObject] =
@tailrec def _dot(dbObj: MongoDBObject, key: String): Option[_] =
if (key.indexOf('.') < 0) {
log.trace("_dot returning on key '%s'", key)
dbObj.getAs[DBObject](key)
dbObj.getAs[AnyRef](key)
}
else {
val (pfx, sfx) = key.splitAt(key.indexOf('.'))
Expand Down Expand Up @@ -139,15 +139,15 @@ trait MongoDBObject extends Map[String, AnyRef] with Logging {

object MongoDBObject {

def empty = new MongoDBObject { val underlying = new BasicDBObject }
def empty: DBObject = new MongoDBObject { val underlying = new BasicDBObject }

def apply[A <: String, B <: Any](elems: (A, B)*) = (newBuilder[A, B] ++= elems).result
def apply[A <: String, B <: Any](elems: (A, B)*): DBObject = (newBuilder[A, B] ++= elems).result

def newBuilder[A <: String, B <: Any]: MongoDBObjectBuilder = new MongoDBObjectBuilder

}

protected[mongodb] class MongoDBObjectBuilder extends scala.collection.mutable.Builder[(String, Any), MongoDBObject] {
sealed class MongoDBObjectBuilder extends scala.collection.mutable.Builder[(String, Any), DBObject] {
protected val empty = BasicDBObjectBuilder.start
protected var elems = empty
override def +=(x: (String, Any)) = {
Expand All @@ -156,7 +156,7 @@ protected[mongodb] class MongoDBObjectBuilder extends scala.collection.mutable.B
}

def clear() { elems = empty }
def result = new MongoDBObject { val underlying = elems.get }
def result: DBObject = new MongoDBObject { val underlying = elems.get }
}

// vim: set ts=2 sw=2 sts=2 et:
2 changes: 1 addition & 1 deletion src/main/scala/mongodb/query/BarewordOperators.scala
Expand Up @@ -53,7 +53,7 @@ trait BarewordQueryOperator extends Logging {
log.trace("Apply - %s", fields)
val bldr = MongoDBObject.newBuilder
for ((k, v) <- fields) bldr += k -> v
MongoDBObject(oper -> bldr.result.asDBObject).asDBObject
MongoDBObject(oper -> bldr.result)
}

}
Expand Down
86 changes: 86 additions & 0 deletions src/test/scala/mongodb/MongoDBObjectSpec.scala
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2009, 2010 Novus Partners, Inc. <http://novus.com>
*
* 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.
*
* For questions and comments about this product, please see the project page at:
*
* http://github.com/novus/casbah
*
*/

package com.novus.casbah
package mongodb
package test

import com.novus.casbah.mongodb.Imports._


import org.specs._
import org.specs.specification.PendingUntilFixed

class MongoDBObjectSpec extends Specification with PendingUntilFixed {
"MongoDBObject expand operations" should {
shareVariables()

val x: DBObject = MongoDBObject("A" -> MongoDBObject("B" -> "C"))
val y: DBObject = MongoDBObject("A" -> MongoDBObject("B" -> MongoDBObject("C" -> 5)))
val z: DBObject = MongoDBObject("A" -> MongoDBObject("B" -> MongoDBObject("C" -> List(5, 4, 3, 2, 1))))

"Expanding a simple layering should work" in {
val b = x.expand[String]("A.B")
b must beSome("C")

"While overexpanding should probably fail" in {
lazy val bFail = x.expand[String]("A.B.C")
bFail must throwA[ClassCastException]
}
}

"Expanding a further layering should work" in {
// TODO - This is way broken as far as casting to int
val c = y.expand[Int]("A.B.C")
c must beSome(5)
"While overexpanding should probably fail" in {
lazy val cFail = y.expand[String]("A.B.C.D")
cFail must throwA[ClassCastException]
}
}

"And you can go further and even get a list" in {
// TODO - This is way broken as far as casting to int
val c = z.expand[List[_]]("A.B.C")
c must beSome(List(5, 4, 3, 2, 1))
}
}

"MongoDBObject issues reported by users" should {
"Not break like tommy chheng reported" in {
lazy val universityDB = MongoConnection()("test")("universities")

val q = MongoDBObject.empty

val fields = MongoDBObject("name" -> 1)
for(university <- universityDB.find(q, fields)) {
println(university)
}

// Simple test of Is it a DBObject?
q must haveSuperClass[DBObject]
fields must haveSuperClass[DBObject]
}
}
}


// vim: set ts=2 sw=2 sts=2 et:

0 comments on commit b69511c

Please sign in to comment.