Skip to content

Commit

Permalink
Issue 1275 - Allow overriding of formats in MongoCaseClassField
Browse files Browse the repository at this point in the history
  • Loading branch information
eltimn committed Jun 20, 2012
1 parent e546a9f commit 8069db8
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 45 deletions.
Expand Up @@ -11,10 +11,10 @@
* limitations under the License.
*/

package net.liftweb
package mongodb
package record
package field
package net.liftweb
package mongodb
package record
package field

import net.liftweb.record._
import net.liftweb.record.RecordHelpers.jvalueToJsExp
Expand All @@ -31,8 +31,10 @@ import net.liftweb.http.js.JsExp


class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerType)( implicit mf: Manifest[CaseType]) extends Field[CaseType, OwnerType] with MandatoryTypedField[CaseType] with MongoFieldFlavor[CaseType] {

implicit val formats = net.liftweb.json.DefaultFormats

// override this for custom formats
def formats: Formats = DefaultFormats
implicit lazy val _formats = formats

override type MyType = CaseType

Expand Down Expand Up @@ -60,7 +62,7 @@ class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerTyp
val jvalue = JObjectParser.serialize(dbo)
setFromJValue(jvalue)
}

override def setFromString(in: String): Box[CaseType] = {
Helpers.tryo{ JsonParser.parse(in).extract[CaseType] }
}
Expand All @@ -76,35 +78,37 @@ class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerTyp
}

class MongoCaseClassListField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerType)( implicit mf: Manifest[CaseType]) extends Field[List[CaseType], OwnerType] with MandatoryTypedField[List[CaseType]] with MongoFieldFlavor[List[CaseType]] {

implicit val formats = net.liftweb.json.DefaultFormats


// override this for custom formats
def formats: Formats = DefaultFormats
implicit lazy val _formats = formats

override type MyType = List[CaseType]

def owner = rec

def asXHtml = Text(value.toString)

def toForm: Box[NodeSeq] = Empty

override def defaultValue: MyType = Nil
override def optional_? = true

def asJValue = JArray(value.map(v => Extraction.decompose(v)))

def setFromJValue(jvalue: JValue): Box[MyType] = jvalue match {
case JArray(contents) => setBox(Full(contents.flatMap(s => Helpers.tryo[CaseType]{ s.extract[CaseType] })))
case _ => setBox(Empty)
}

def asDBObject: DBObject = {
val dbl = new BasicDBList

asJValue match {
case JArray(list) =>
case JArray(list) =>
list.foreach(v => dbl.add(JObjectParser.parse(v.asInstanceOf[JObject])))
}

dbl
}

Expand Down
Expand Up @@ -22,7 +22,8 @@ package fixtures
import field._

import common.{Box, Empty, Failure, Full}
import json.ext.JsonBoxSerializer
import json._
import json.ext.{EnumSerializer, JsonBoxSerializer}
import http.SHtml
import util.FieldError

Expand Down Expand Up @@ -243,6 +244,10 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
object mandatoryUUIDField extends UUIDField(this)
object legacyOptionalUUIDField extends UUIDField(this) { override def optional_? = true }

object mandatoryMongoCaseClassField extends MongoCaseClassField[MongoFieldTypeTestRecord, MongoCaseClassTestObject](this) {
override def formats = owner.meta.formats
}

override def equals(other: Any): Boolean = other match {
case that: MongoFieldTypeTestRecord =>
this.id.value == that.id.value &&
Expand All @@ -251,15 +256,16 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
this.mandatoryObjectIdField.value == that.mandatoryObjectIdField.value &&
this.mandatoryPatternField.value.pattern == that.mandatoryPatternField.value.pattern &&
this.mandatoryPatternField.value.flags == that.mandatoryPatternField.value.flags &&
this.mandatoryUUIDField.value == that.mandatoryUUIDField.value
this.mandatoryUUIDField.value == that.mandatoryUUIDField.value &&
this.mandatoryMongoCaseClassField.value == that.mandatoryMongoCaseClassField.value
case _ => false
}

def dirtyFields = this.allFields.filter(_.dirty_?)
}

object MongoFieldTypeTestRecord extends MongoFieldTypeTestRecord with MongoMetaRecord[MongoFieldTypeTestRecord] {
override def formats = allFormats
override def formats = allFormats + new EnumSerializer(MyTestEnum)
}

class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with ObjectIdPk[PasswordTestRecord] {
Expand All @@ -269,7 +275,7 @@ class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with
}
object PasswordTestRecord extends PasswordTestRecord with MongoMetaRecord[PasswordTestRecord]

case class MongoCaseClassTestObject(intField: Int, stringField: String)
case class MongoCaseClassTestObject(intField: Int, stringField: String, enum: MyTestEnum.Value)

class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[ListTestRecord] {
def meta = ListTestRecord
Expand All @@ -283,7 +289,9 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[
object mandatoryMongoJsonObjectListField extends MongoJsonObjectListField(this, TypeTestJsonObject)
object legacyOptionalMongoJsonObjectListField extends MongoJsonObjectListField(this, TypeTestJsonObject) { override def optional_? = true }

object mongoCaseClassListField extends MongoCaseClassListField[ListTestRecord, MongoCaseClassTestObject](this)
object mongoCaseClassListField extends MongoCaseClassListField[ListTestRecord, MongoCaseClassTestObject](this) {
override def formats = owner.meta.formats
}

// TODO: More List types

Expand All @@ -292,14 +300,15 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[
this.id.value == that.id.value &&
this.mandatoryStringListField.value == that.mandatoryStringListField.value &&
this.mandatoryIntListField.value == that.mandatoryIntListField.value &&
this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value
this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value &&
this.mongoCaseClassListField.value == that.mongoCaseClassListField.value
case _ => false
}

def dirtyFields = this.allFields.filter(_.dirty_?)
}
object ListTestRecord extends ListTestRecord with MongoMetaRecord[ListTestRecord] {
override def formats = allFormats
override def formats = allFormats + new EnumSerializer(MyTestEnum)
}

class MapTestRecord private () extends MongoRecord[MapTestRecord] with StringPk[MapTestRecord] {
Expand Down
Expand Up @@ -323,7 +323,7 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
"MongoCaseClassListField" should {
"setFromAny a List" in {
val rec = ListTestRecord.createRecord
val lst = List(MongoCaseClassTestObject(1,"str1"))
val lst = List(MongoCaseClassTestObject(1,"str1", MyTestEnum.THREE))
rec.mongoCaseClassListField.setFromAny(lst)
rec.mongoCaseClassListField.value must_== lst
}
Expand Down
Expand Up @@ -37,17 +37,17 @@ import com.mongodb._
* Systems under specification for MongoRecord.
*/
object MongoRecordSpec extends Specification("MongoRecord Specification") with MongoTestKit {

import fixtures._

"MongoRecord field introspection" should {
checkMongoIsRunning

val rec = MongoFieldTypeTestRecord.createRecord
val allExpectedFieldNames: List[String] = "_id" :: (for {
typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
flavor <- "mandatory legacyOptional".split(" ")
} yield flavor + typeName + "Field").toList
val allExpectedFieldNames: List[String] = "_id" :: "mandatoryMongoCaseClassField" ::
(for {
typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
flavor <- "mandatory legacyOptional".split(" ")
} yield flavor + typeName + "Field").toList

"introspect only the expected fields" in {
rec.fields().map(_.name).filterNot(allExpectedFieldNames.contains(_)) must_== Nil
Expand Down Expand Up @@ -194,6 +194,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
.mandatoryObjectIdField(ObjectId.get)
.mandatoryPatternField(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
.mandatoryUUIDField(UUID.randomUUID)
.mandatoryMongoCaseClassField(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO))

val mfttrJson =
("_id" -> ("$oid" -> mfttr.id.toString)) ~
Expand All @@ -206,13 +207,14 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
("mandatoryPatternField" -> (("$regex" -> mfttr.mandatoryPatternField.value.pattern) ~ ("$flags" -> mfttr.mandatoryPatternField.value.flags))) ~
("legacyOptionalPatternField" -> (None: Option[JObject])) ~
("mandatoryUUIDField" -> ("$uuid" -> mfttr.mandatoryUUIDField.value.toString)) ~
("legacyOptionalUUIDField" -> (None: Option[JObject]))
("legacyOptionalUUIDField" -> (None: Option[JObject])) ~
("mandatoryMongoCaseClassField" -> ("intField" -> 1) ~ ("stringField" -> "str") ~ ("enum" -> 1))

val ltr = ListTestRecord.createRecord
.mandatoryStringListField(List("abc", "def", "ghi"))
.mandatoryIntListField(List(4, 5, 6))
.mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2"))))
.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str")))
.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO)))

val ltrJson =
("_id" -> ("$uuid" -> ltr.id.toString)) ~
Expand All @@ -226,7 +228,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
)) ~
("legacyOptionalMongoJsonObjectListField" -> List[JObject]()) ~
("mongoCaseClassListField" -> List(
("intField" -> 1) ~ ("stringField" -> "str")
("intField" -> 1) ~ ("stringField" -> "str") ~ ("enum" -> 1)
))

val mtr = MapTestRecord.createRecord
Expand Down Expand Up @@ -685,7 +687,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
fttr.legacyOptionalStringField(Empty)
fttr.legacyOptionalStringField.dirty_? must_== true

fttr.dirtyFields.length must_== 7
fttr.dirtyFields.length must_== 9
fttr.update
fttr.dirtyFields.length must_== 0

Expand Down Expand Up @@ -792,7 +794,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
ltr.mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2"))))
ltr.mandatoryMongoJsonObjectListField.dirty_? must_== true

ltr.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str")))
ltr.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO)))
ltr.mongoCaseClassListField.dirty_? must_== true

ltr.dirtyFields.length must_== 4
Expand Down
Expand Up @@ -36,10 +36,12 @@ object JObjectParser extends SimpleInjector {
*
* <code>JObjectParser.stringProcessor.default.set((s: String) => s)</code>
*/
val stringProcessor = new Inject(() => (s: String) => {
val stringProcessor = new Inject(() => defaultStringProcessor _) {}

def defaultStringProcessor(s: String): Object = {
if (ObjectId.isValid(s)) new ObjectId(s)
else s
}) {}
}

/*
* Parse a JObject into a DBObject
Expand Down
Expand Up @@ -45,14 +45,14 @@ object JObjectParserSpec extends Specification("JObjectParser Specification") {
}
}
"not convert strings to ObjectId when configured not to" in {
JObjectParser.stringProcessor.default.set((s: String) => s)

val (oid, dbo) = buildTestData
val xval = tryo(dbo.get("x").asInstanceOf[String])

xval must notBeEmpty
xval.foreach { x =>
x must_== oid.toString
JObjectParser.stringProcessor.doWith((s: String) => s) {
val (oid, dbo) = buildTestData
val xval = tryo(dbo.get("x").asInstanceOf[String])

xval must notBeEmpty
xval.foreach { x =>
x must_== oid.toString
}
}
}
}
Expand Down

0 comments on commit 8069db8

Please sign in to comment.