Augusto
Augusto

Reputation: 1336

Scala casbah DSL queries

I'm learning Scala and trying Mongo too. I'm creating a function that receives a Map[String, Any] as a parameter and I would like to return the proper MongoDBObject for it:

def parse(query: Map[String, Any]): MongoDBObject = {
  val result = query("operation") match {
    case "all" => query("field").toString $all query("value").asInstanceOf[List[String]]
    case "in" => query("field").toString $in query("value").asInstanceOf[List[String]]
    case "regex" => query("field").toString $regex query("value")
    case "eq" => query("field").toString $eq query("value")
    case "gt" => query("field").toString $gt query("value")
    case "gte" => query("field").toString $gte query("value")
    case "lt" => query("field").toString $lt query("value")
    case "lte" => query("field").toString $lte query("value")
    case "exists" => query("field").toString $exists query("value").asInstanceOf[Boolean]
    case "size" => query("field").toString $size query("value").asInstanceOf[Int]
    case "where" => $where(query("value").toString)
    case _ => throw new NotImplementedError("Unknown operation")
  }
}

I have some issues.

Upvotes: 0

Views: 735

Answers (1)

Kelsey Gilmore-Innis
Kelsey Gilmore-Innis

Reputation: 1010

It complains about $regex because it isn't finding a regex-able object on the right hand side to apply the conversion used to parse the $regex method--this is a problem you will run into with all of the following calls as well.

For the issue with Any (and also $mod), may I suggest a different approach? You have no type information with Any, so you can't really get around runtime casting (and I'm not sure how reflection would help you either.) You're not getting any of the benefits of a static type system that way. Here's a sketch of one way you could implement a method like this using a type hierarchy to enforce type safety:

sealed trait Query

case class All(field: String, value: List[String]) extends Query 
...
case class GreaterThan(field: String, value: Int) extends Query 
...
case class Mod(field: String, divisor: Int, remainder: Int) extends Query

def parse(q: Query): MongoDBObject = {
   q match {
      case All(f, v) => f $all v
      ...
      case GreaterThan(f, v) => f $gt v
      ...
      case Mod(f, d, r) => f $mod (d, r)
   }
}

Alternately, you could define an abstract execute method on Query and override it in each extending class instead of doing the match statement in parse. From there, you could abstract further using type parameters or generic types to allow, for example, GreaterThan to take any Numeric type.

Upvotes: 1

Related Questions