Skip to content
This repository
Browse code

Issue 1275 - Allow overriding of formats in MongoCaseClassField

  • Loading branch information...
commit 8069db87b10e929e534006ded60d74e738d47a8b 1 parent e546a9f
Tim Nelson authored June 14, 2012
38  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoCaseClassField.scala
@@ -11,10 +11,10 @@
11 11
 * limitations under the License.
12 12
 */
13 13
 
14  
-package net.liftweb 
15  
-package mongodb 
16  
-package record 
17  
-package field 
  14
+package net.liftweb
  15
+package mongodb
  16
+package record
  17
+package field
18 18
 
19 19
 import net.liftweb.record._
20 20
 import net.liftweb.record.RecordHelpers.jvalueToJsExp
@@ -31,8 +31,10 @@ import net.liftweb.http.js.JsExp
31 31
 
32 32
 
33 33
 class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerType)( implicit mf: Manifest[CaseType]) extends Field[CaseType, OwnerType] with MandatoryTypedField[CaseType] with MongoFieldFlavor[CaseType] {
34  
-  
35  
-  implicit val formats = net.liftweb.json.DefaultFormats
  34
+
  35
+  // override this for custom formats
  36
+  def formats: Formats = DefaultFormats
  37
+  implicit lazy val _formats = formats
36 38
 
37 39
   override type MyType = CaseType
38 40
 
@@ -60,7 +62,7 @@ class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerTyp
60 62
     val jvalue = JObjectParser.serialize(dbo)
61 63
     setFromJValue(jvalue)
62 64
   }
63  
-  
  65
+
64 66
   override def setFromString(in: String): Box[CaseType] = {
65 67
     Helpers.tryo{ JsonParser.parse(in).extract[CaseType] }
66 68
   }
@@ -76,22 +78,24 @@ class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerTyp
76 78
 }
77 79
 
78 80
 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]] {
79  
-  
80  
-  implicit val formats = net.liftweb.json.DefaultFormats
81  
-  
  81
+
  82
+  // override this for custom formats
  83
+  def formats: Formats = DefaultFormats
  84
+  implicit lazy val _formats = formats
  85
+
82 86
   override type MyType = List[CaseType]
83  
-  
  87
+
84 88
   def owner = rec
85 89
 
86 90
   def asXHtml = Text(value.toString)
87  
-  
  91
+
88 92
   def toForm: Box[NodeSeq] = Empty
89 93
 
90 94
   override def defaultValue: MyType = Nil
91 95
   override def optional_? = true
92  
-  
  96
+
93 97
   def asJValue = JArray(value.map(v => Extraction.decompose(v)))
94  
-  
  98
+
95 99
   def setFromJValue(jvalue: JValue): Box[MyType] = jvalue match {
96 100
     case JArray(contents) => setBox(Full(contents.flatMap(s => Helpers.tryo[CaseType]{ s.extract[CaseType] })))
97 101
     case _ => setBox(Empty)
@@ -99,12 +103,12 @@ class MongoCaseClassListField[OwnerType <: Record[OwnerType],CaseType](rec: Owne
99 103
 
100 104
   def asDBObject: DBObject = {
101 105
     val dbl = new BasicDBList
102  
-    
  106
+
103 107
     asJValue match {
104  
-      case JArray(list) => 
  108
+      case JArray(list) =>
105 109
         list.foreach(v => dbl.add(JObjectParser.parse(v.asInstanceOf[JObject])))
106 110
     }
107  
-    
  111
+
108 112
     dbl
109 113
   }
110 114
 
23  persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
@@ -22,7 +22,8 @@ package fixtures
22 22
 import field._
23 23
 
24 24
 import common.{Box, Empty, Failure, Full}
25  
-import json.ext.JsonBoxSerializer
  25
+import json._
  26
+import json.ext.{EnumSerializer, JsonBoxSerializer}
26 27
 import http.SHtml
27 28
 import util.FieldError
28 29
 
@@ -243,6 +244,10 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
243 244
   object mandatoryUUIDField extends UUIDField(this)
244 245
   object legacyOptionalUUIDField extends UUIDField(this) { override def optional_? = true }
245 246
 
  247
+  object mandatoryMongoCaseClassField extends MongoCaseClassField[MongoFieldTypeTestRecord, MongoCaseClassTestObject](this) {
  248
+    override def formats = owner.meta.formats
  249
+  }
  250
+
246 251
   override def equals(other: Any): Boolean = other match {
247 252
     case that: MongoFieldTypeTestRecord =>
248 253
       this.id.value == that.id.value &&
@@ -251,7 +256,8 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
251 256
       this.mandatoryObjectIdField.value == that.mandatoryObjectIdField.value &&
252 257
       this.mandatoryPatternField.value.pattern == that.mandatoryPatternField.value.pattern &&
253 258
       this.mandatoryPatternField.value.flags == that.mandatoryPatternField.value.flags &&
254  
-      this.mandatoryUUIDField.value == that.mandatoryUUIDField.value
  259
+      this.mandatoryUUIDField.value == that.mandatoryUUIDField.value &&
  260
+      this.mandatoryMongoCaseClassField.value == that.mandatoryMongoCaseClassField.value
255 261
     case _ => false
256 262
   }
257 263
 
@@ -259,7 +265,7 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
259 265
 }
260 266
 
261 267
 object MongoFieldTypeTestRecord extends MongoFieldTypeTestRecord with MongoMetaRecord[MongoFieldTypeTestRecord] {
262  
-  override def formats = allFormats
  268
+  override def formats = allFormats + new EnumSerializer(MyTestEnum)
263 269
 }
264 270
 
265 271
 class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with ObjectIdPk[PasswordTestRecord] {
@@ -269,7 +275,7 @@ class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with
269 275
 }
270 276
 object PasswordTestRecord extends PasswordTestRecord with MongoMetaRecord[PasswordTestRecord]
271 277
 
272  
-case class MongoCaseClassTestObject(intField: Int, stringField: String)
  278
+case class MongoCaseClassTestObject(intField: Int, stringField: String, enum: MyTestEnum.Value)
273 279
 
274 280
 class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[ListTestRecord] {
275 281
   def meta = ListTestRecord
@@ -283,7 +289,9 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[
283 289
   object mandatoryMongoJsonObjectListField extends MongoJsonObjectListField(this, TypeTestJsonObject)
284 290
   object legacyOptionalMongoJsonObjectListField extends MongoJsonObjectListField(this, TypeTestJsonObject) { override def optional_? = true }
285 291
 
286  
-  object mongoCaseClassListField extends MongoCaseClassListField[ListTestRecord, MongoCaseClassTestObject](this)
  292
+  object mongoCaseClassListField extends MongoCaseClassListField[ListTestRecord, MongoCaseClassTestObject](this) {
  293
+    override def formats = owner.meta.formats
  294
+  }
287 295
 
288 296
   // TODO: More List types
289 297
 
@@ -292,14 +300,15 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[
292 300
       this.id.value == that.id.value &&
293 301
       this.mandatoryStringListField.value == that.mandatoryStringListField.value &&
294 302
       this.mandatoryIntListField.value == that.mandatoryIntListField.value &&
295  
-      this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value
  303
+      this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value &&
  304
+      this.mongoCaseClassListField.value == that.mongoCaseClassListField.value
296 305
     case _ => false
297 306
   }
298 307
 
299 308
   def dirtyFields = this.allFields.filter(_.dirty_?)
300 309
 }
301 310
 object ListTestRecord extends ListTestRecord with MongoMetaRecord[ListTestRecord] {
302  
-  override def formats = allFormats
  311
+  override def formats = allFormats + new EnumSerializer(MyTestEnum)
303 312
 }
304 313
 
305 314
 class MapTestRecord private () extends MongoRecord[MapTestRecord] with StringPk[MapTestRecord] {
2  persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
@@ -323,7 +323,7 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
323 323
   "MongoCaseClassListField" should {
324 324
     "setFromAny a List" in {
325 325
       val rec = ListTestRecord.createRecord
326  
-      val lst = List(MongoCaseClassTestObject(1,"str1"))
  326
+      val lst = List(MongoCaseClassTestObject(1,"str1", MyTestEnum.THREE))
327 327
       rec.mongoCaseClassListField.setFromAny(lst)
328 328
       rec.mongoCaseClassListField.value must_== lst
329 329
     }
22  persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
@@ -37,17 +37,17 @@ import com.mongodb._
37 37
  * Systems under specification for MongoRecord.
38 38
  */
39 39
 object MongoRecordSpec extends Specification("MongoRecord Specification") with MongoTestKit {
40  
-
41 40
   import fixtures._
42 41
 
43 42
   "MongoRecord field introspection" should {
44 43
     checkMongoIsRunning
45 44
 
46 45
     val rec = MongoFieldTypeTestRecord.createRecord
47  
-    val allExpectedFieldNames: List[String] = "_id" :: (for {
48  
-      typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
49  
-      flavor <- "mandatory legacyOptional".split(" ")
50  
-    } yield flavor + typeName + "Field").toList
  46
+    val allExpectedFieldNames: List[String] = "_id" :: "mandatoryMongoCaseClassField" ::
  47
+      (for {
  48
+        typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
  49
+        flavor <- "mandatory legacyOptional".split(" ")
  50
+      } yield flavor + typeName + "Field").toList
51 51
 
52 52
     "introspect only the expected fields" in {
53 53
       rec.fields().map(_.name).filterNot(allExpectedFieldNames.contains(_)) must_== Nil
@@ -194,6 +194,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
194 194
       .mandatoryObjectIdField(ObjectId.get)
195 195
       .mandatoryPatternField(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
196 196
       .mandatoryUUIDField(UUID.randomUUID)
  197
+      .mandatoryMongoCaseClassField(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO))
197 198
 
198 199
     val mfttrJson =
199 200
       ("_id" -> ("$oid" -> mfttr.id.toString)) ~
@@ -206,13 +207,14 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
206 207
       ("mandatoryPatternField" -> (("$regex" -> mfttr.mandatoryPatternField.value.pattern) ~ ("$flags" -> mfttr.mandatoryPatternField.value.flags))) ~
207 208
       ("legacyOptionalPatternField" -> (None: Option[JObject])) ~
208 209
       ("mandatoryUUIDField" -> ("$uuid" -> mfttr.mandatoryUUIDField.value.toString)) ~
209  
-      ("legacyOptionalUUIDField" -> (None: Option[JObject]))
  210
+      ("legacyOptionalUUIDField" -> (None: Option[JObject])) ~
  211
+      ("mandatoryMongoCaseClassField" -> ("intField" -> 1) ~ ("stringField" -> "str") ~ ("enum" -> 1))
210 212
 
211 213
     val ltr = ListTestRecord.createRecord
212 214
       .mandatoryStringListField(List("abc", "def", "ghi"))
213 215
       .mandatoryIntListField(List(4, 5, 6))
214 216
       .mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2"))))
215  
-      .mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str")))
  217
+      .mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO)))
216 218
 
217 219
     val ltrJson =
218 220
       ("_id" -> ("$uuid" -> ltr.id.toString)) ~
@@ -226,7 +228,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
226 228
       )) ~
227 229
       ("legacyOptionalMongoJsonObjectListField" -> List[JObject]()) ~
228 230
       ("mongoCaseClassListField" -> List(
229  
-        ("intField" -> 1) ~ ("stringField" -> "str")
  231
+        ("intField" -> 1) ~ ("stringField" -> "str") ~ ("enum" -> 1)
230 232
       ))
231 233
 
232 234
     val mtr = MapTestRecord.createRecord
@@ -685,7 +687,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
685 687
       fttr.legacyOptionalStringField(Empty)
686 688
       fttr.legacyOptionalStringField.dirty_? must_== true
687 689
 
688  
-      fttr.dirtyFields.length must_== 7
  690
+      fttr.dirtyFields.length must_== 9
689 691
       fttr.update
690 692
       fttr.dirtyFields.length must_== 0
691 693
 
@@ -792,7 +794,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
792 794
       ltr.mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2"))))
793 795
       ltr.mandatoryMongoJsonObjectListField.dirty_? must_== true
794 796
 
795  
-      ltr.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str")))
  797
+      ltr.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO)))
796 798
       ltr.mongoCaseClassListField.dirty_? must_== true
797 799
 
798 800
       ltr.dirtyFields.length must_== 4
6  persistence/mongodb/src/main/scala/net/liftweb/mongodb/JObjectParser.scala
@@ -36,10 +36,12 @@ object JObjectParser extends SimpleInjector {
36 36
     *
37 37
     * <code>JObjectParser.stringProcessor.default.set((s: String) => s)</code>
38 38
     */
39  
-  val stringProcessor = new Inject(() => (s: String) => {
  39
+  val stringProcessor = new Inject(() => defaultStringProcessor _) {}
  40
+
  41
+  def defaultStringProcessor(s: String): Object = {
40 42
     if (ObjectId.isValid(s)) new ObjectId(s)
41 43
     else s
42  
-  }) {}
  44
+  }
43 45
 
44 46
   /*
45 47
   * Parse a JObject into a DBObject
16  persistence/mongodb/src/test/scala/net/liftweb/mongodb/JObjectParserSpec.scala
@@ -45,14 +45,14 @@ object JObjectParserSpec extends Specification("JObjectParser Specification") {
45 45
       }
46 46
     }
47 47
     "not convert strings to ObjectId when configured not to" in {
48  
-      JObjectParser.stringProcessor.default.set((s: String) => s)
49  
-
50  
-      val (oid, dbo) = buildTestData
51  
-      val xval = tryo(dbo.get("x").asInstanceOf[String])
52  
-
53  
-      xval must notBeEmpty
54  
-      xval.foreach { x =>
55  
-        x must_== oid.toString
  48
+      JObjectParser.stringProcessor.doWith((s: String) => s) {
  49
+        val (oid, dbo) = buildTestData
  50
+        val xval = tryo(dbo.get("x").asInstanceOf[String])
  51
+
  52
+        xval must notBeEmpty
  53
+        xval.foreach { x =>
  54
+          x must_== oid.toString
  55
+        }
56 56
       }
57 57
     }
58 58
   }

0 notes on commit 8069db8

Please sign in to comment.
Something went wrong with that request. Please try again.