Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

JObjectField doesn't serialize to BSON #1346

Closed
wants to merge 1 commit into from

2 participants

@ultramiraculous

JObjectField isn't fully working following issue 1314 being fixed. In the current builds, JObjectField will serialize to something like "JObject(List(JField(minutes,Jint(59))))", rather than the intended BSON data structure.

The issue is that -fieldDbValue in BsonRecord falls through to the o.toString option when it asDBObject tried to create the DBObject.

I was able to shim in something that uses the mongo driver's JSON parser to deserialize a serialized JObject into a DBObject in the case that fieldDbValue gets a JObject, but it feels kinda hacky.

The current "get set from JValue" test only covers the fact that the JObject can in-fact be set on a given record, but it doesn't cover a round trip to BSON and back.

@eltimn
Collaborator

Next time, please discuss this in the list before opening a ticket. That's standard Lift policy.

I will get this fixed soon.

@eltimn eltimn was assigned
@eltimn eltimn closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 30, 2012
  1. @eltimn
This page is out of date. Refresh to see the latest.
View
32 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JObjectField.scala
@@ -23,16 +23,18 @@ import common._
import http.js.JE._
import json._
import util.Helpers.tryo
-import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
+import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField}
import scala.xml.NodeSeq
-class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field[JObject, OwnerType] with MandatoryTypedField[JObject] {
+import com.mongodb._
- def asJs = asJValue match {
- case JNothing => JsNull
- case jv => JsRaw(compact(render(jv)))
- }
+abstract class JObjectField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
+extends Field[JObject, OwnerType]
+with MandatoryTypedField[JObject]
+with MongoFieldFlavor[JObject] {
+
+ def owner = rec
def asJValue = valueBox openOr (JNothing: JValue)
@@ -45,14 +47,15 @@ class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field
def defaultValue = JObject(List())
def setFromAny(in: Any): Box[JObject] = in match {
- case jv: JObject => Full(set(jv))
- case Some(jv: JObject) => Full(set(jv))
- case Full(jv: JObject) => Full(set(jv))
+ case dbo: DBObject => setBox(setFromDBObject(dbo))
+ case jv: JObject => setBox(Full(jv))
+ case Some(jv: JObject) => setBox(Full(jv))
+ case Full(jv: JObject) => setBox(Full(jv))
case seq: Seq[_] if !seq.isEmpty => seq.map(setFromAny).apply(0)
case (s: String) :: _ => setFromString(s)
- case null => Full(set(null))
+ case null => setBox(Full(null))
case s: String => setFromString(s)
- case None | Empty | Failure(_, _, _) => Full(set(null))
+ case None | Empty | Failure(_, _, _) => setBox(Full(null))
case o => setFromString(o.toString)
}
@@ -64,5 +67,10 @@ class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field
def toForm: Box[NodeSeq] = Empty
- def owner = rec
+ def asDBObject: DBObject = valueBox
+ .map { v => JObjectParser.parse(v)(owner.meta.formats) }
+ .openOr(new BasicDBObject)
+
+ def setFromDBObject(obj: DBObject): Box[JObject] =
+ Full(JObjectParser.serialize(obj)(owner.meta.formats).asInstanceOf[JObject])
}
View
6 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
@@ -469,10 +469,12 @@ object RefFieldTestRecord extends RefFieldTestRecord with MongoMetaRecord[RefFie
}
-class JObjectFieldTestRecord private () extends Record[JObjectFieldTestRecord] {
+class JObjectFieldTestRecord private () extends MongoRecord[JObjectFieldTestRecord] with ObjectIdPk[JObjectFieldTestRecord] {
def meta = JObjectFieldTestRecord
object mandatoryJObjectField extends JObjectField(this)
}
-object JObjectFieldTestRecord extends JObjectFieldTestRecord with MetaRecord[JObjectFieldTestRecord]
+object JObjectFieldTestRecord extends JObjectFieldTestRecord with MongoMetaRecord[JObjectFieldTestRecord] {
+ override def formats = allFormats
+}
View
24 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
@@ -39,6 +39,8 @@ import xml.{Elem, NodeSeq, Text}
import util.{Helpers, FieldError}
import Helpers._
+import org.bson.types.ObjectId
+
/**
* Systems under specification for MongoField.
*/
@@ -508,11 +510,25 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
}
"get set from JValue" in {
- val fromJson = JObjectFieldTestRecord.fromJValue(json)
+ val rec = JObjectFieldTestRecord.createRecord
+ val recFromJson = rec.mandatoryJObjectField.setFromJValue(json)
+
+ recFromJson.isDefined must_== true
+ recFromJson foreach { r =>
+ r must_== json
+ }
+ success
+ }
+ "get set from JValue after BSON roundtrip" in {
+ val joftrJson: JObject = ("_id" -> ("$oid" -> ObjectId.get.toString)) ~ ("mandatoryJObjectField" -> ("minutes" -> 59))
+ val fromJsonBox = JObjectFieldTestRecord.fromJValue(joftrJson)
+
+ fromJsonBox.isDefined must_== true
- fromJson.isDefined must_== true
- fromJson foreach { r =>
- r.asJValue must_== json
+ fromJsonBox foreach { fromJson =>
+ //Convert the test record, make a DBObject out of it, and make a record from that DBObject
+ val fromBson = JObjectFieldTestRecord.fromDBObject(fromJson.asDBObject)
+ fromBson.asJValue must_== fromJson.asJValue
}
success
}
View
36 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
@@ -334,6 +334,11 @@ class MongoRecordSpec extends Specification with MongoTestKit {
JField("legacyOptionalBsonRecordListField", JArray(List()))
))
+ // JObjectField
+ val joftrFieldJObject: JObject = ("minutes" -> 59)
+ val joftr = JObjectFieldTestRecord.createRecord.mandatoryJObjectField(joftrFieldJObject)
+ val joftrJson: JValue = ("_id" -> ("$oid" -> joftr.id.toString)) ~ ("mandatoryJObjectField" -> ("minutes" -> 59))
+
"save and retrieve 'standard' type fields" in {
checkMongoIsRunning
@@ -407,6 +412,15 @@ class MongoRecordSpec extends Specification with MongoTestKit {
srtrFromDb.toList map { tr =>
tr mustEqual srtr
}
+
+ joftr.save
+
+ val joftrFromDb = JObjectFieldTestRecord.find(joftr.id.is)
+ joftrFromDb.isDefined must_== true
+ joftrFromDb foreach { tr =>
+ tr must_== joftr
+ }
+ success
}
"save and retrieve Mongo type fields with default values" in {
@@ -454,6 +468,16 @@ class MongoRecordSpec extends Specification with MongoTestKit {
srtrFromDb.toList map { tr =>
tr mustEqual srtrDef
}
+
+ val joftrDef = JObjectFieldTestRecord.createRecord
+ joftrDef.save
+
+ val joftrFromDb = JObjectFieldTestRecord.find(joftrDef.id.value)
+ joftrFromDb.isDefined must_== true
+ joftrFromDb foreach { tr =>
+ tr mustEqual joftrDef
+ }
+ success
}
"convert Mongo type fields to JValue" in {
@@ -471,6 +495,8 @@ class MongoRecordSpec extends Specification with MongoTestKit {
srtrAsJValue \\ "legacyOptionalBsonRecordField" mustEqual srtrJson \\ "legacyOptionalBsonRecordField"
srtrAsJValue \\ "mandatoryBsonRecordListField" mustEqual srtrJson \\ "mandatoryBsonRecordListField"
srtrAsJValue \\ "legacyOptionalBsonRecordListField" mustEqual srtrJson \\ "legacyOptionalBsonRecordListField"
+
+ joftr.asJValue mustEqual joftrJson
}
"get set from json string using lift-json parser" in {
@@ -497,6 +523,12 @@ class MongoRecordSpec extends Specification with MongoTestKit {
mtrFromJson.toList map { tr =>
tr mustEqual mtr
}
+
+ val joftrFromJson = JObjectFieldTestRecord.fromJsonString(compact(render(joftrJson)))
+ joftrFromJson.isDefined must_== true
+ joftrFromJson.toList map { tr =>
+ tr mustEqual joftr
+ }
}
"handle null" in {
@@ -799,7 +831,6 @@ class MongoRecordSpec extends Specification with MongoTestKit {
}
}
- /* save throws an exception here but not above ???
"update dirty fields for a PatternFieldTestRecord" in {
val pftrd = PatternFieldTestRecord.createRecord.save
@@ -816,7 +847,8 @@ class MongoRecordSpec extends Specification with MongoTestKit {
rec must_== pftrd
rec.dirtyFields.length must_== 0
}
- }*/
+ success
+ }
"update dirty fields for a ListTestRecord" in {
val ltr = ListTestRecord.createRecord.save
Something went wrong with that request. Please try again.