public
Created

Convert play2.0 JsValue to mongodb DBObject provided by casbah

  • Download Gist
MongoJson.scala
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
package module.db;
 
import com.mongodb.casbah.Imports._
import java.text.DateFormat
import java.util.Date
import play.api.data.validation.ValidationError
import play.api.libs.json._
 
object MongoJson {
def fromJson(json: JsValue) : JsResult[DBObject] = readDBObject.reads(json)
 
implicit val readDBObject = new Reads[DBObject] {
def reads(js: JsValue): JsResult[DBObject] = {
parsePlainObject(js.asInstanceOf[JsObject], JsPath())
}
 
private def parsePlainObject(obj: JsObject, parent: JsPath): JsResult[DBObject] = {
parsePlainFields(obj.fields.toList, parent).map(DBObject(_))
}
 
private def parsePlainFields(l: List[(String, JsValue)], parent: JsPath): JsResult[List[(String, Any)]] = {
l match {
case Nil => JsSuccess(Nil, parent)
case head :: tail => cons(
parse(head._2, (parent \ head._1)).map(head._1 -> _),
parsePlainFields(tail, parent)
)
}
}
 
private def parse(obj: JsObject, parent: JsPath): JsResult[Any] = {
if(obj.fields.length > 0) {
obj.fields(0) match {
case ("$date", v: JsValue) =>
val path = parent \ "$date"
try {
v match {
case number: JsNumber => JsSuccess(new Date(number.value.toLong), path)
case _ => JsSuccess(DateFormat.getDateInstance().parse(v.toString))
}
} catch {
case ex: IllegalArgumentException => JsError(path, ValidationError("validation.invalid", "$date"))
}
case ("$oid", v :JsString) =>
val path = parent \ "$oid"
try {
JsSuccess(new ObjectId(v.value), path)
} catch {
case ex: IllegalArgumentException => JsError(path, ValidationError("validation.invalid", "$oid"))
}
case _ => parsePlainObject(obj, parent)
}
} else parsePlainObject(obj, parent)
}
 
private def parse(arr: JsArray, parent: JsPath): JsResult[List[Any]] = {
parse(arr.value.toList, parent, 0)
}
 
private def parse(l: List[JsValue], parent: JsPath, i: Int): JsResult[List[Any]] = {
l match {
case Nil => JsSuccess(Nil)
case head :: tail => cons(parse(head, parent(i)), parse(tail, parent, i + 1))
}
}
 
private def cons[T](head: JsResult[T], tail: JsResult[List[T]]): JsResult[List[T]] = {
(head, tail) match {
case (h: JsError, t: JsError) => h ++ t
case (JsSuccess(h, _), JsSuccess(t, _)) => JsSuccess(h :: t)
case (h: JsError, _) => h
case _ => tail
}
}
 
private def parse(js: JsValue, parent: JsPath): JsResult[Any] = {
js match {
case v: JsObject => parse(v, parent)
case v: JsArray => parse(v, parent)
case v: JsString => JsSuccess(v.value, parent)
case v: JsNumber => JsSuccess(v.value, parent)
case v: JsBoolean => JsSuccess(v.value, parent)
case JsNull => JsSuccess(null)
case _: JsUndefined => JsSuccess(null)
}
}
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.