Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Issue 1343 - Ensure equals method works properly with all Fields #1351

Closed
wants to merge 1 commit into from

3 participants

@eltimn
Collaborator

Since Field.setBox now compares values before setting the dirty flag I wanted to make sure all of the fields' values have proper equals methods.

There were 2 that had problems; PatternField and BsonRecordField. I didn't figure out a solution for Pattern, but for BsonRecord I added an equals method to Record that compares each field.

There is also a problem with BsonRecord relating to it's mutablity. See this thread [1] for more info.

To help alleviate the problem I did 2 things:

  • Added a copy method to Record that creates a new Record instance with all fields set to the values in the original instance
  • Added forceDirty_? to Field. Setting this to true will force the dirty flag to always be set when calling setBox, the same as the previous behavior.

Note that this commit includes @davewhittaker 's fix for issue 1335

1 - https://groups.google.com/d/topic/liftweb/g8SwfKsLW_0/discussion

@lkuczera
Collaborator

+1 I like the copy function although sometimes you don't carbon copy all fields. I'd add a test function that takes field as argument and returns boolean. This way we could filter out which fields should be copied. Thoughts ?

@eltimn
Collaborator

Sounds like a good idea.

@fmpwizard
Owner

so, do we wait before rebasing this one into master?

@eltimn
Collaborator

Yes. I'll add that feature to it first.

@eltimn
Collaborator

On second thought, I created a new issue (#1354) for the filter function. I will work on it when I have more time.

This has been merged to master as is.

@eltimn eltimn closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 411 additions and 251 deletions.
  1. +23 −36 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/BsonRecord.scala
  2. +4 −2 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
  3. +2 −2 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JsonObjectField.scala
  4. +4 −4 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/PatternField.scala
  5. +46 −0 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/BsonRecordSpec.scala
  6. +33 −51 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
  7. +92 −70 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
  8. +62 −15 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
  9. +23 −13 persistence/record/src/main/scala/net/liftweb/record/Field.scala
  10. +21 −0 persistence/record/src/main/scala/net/liftweb/record/MetaRecord.scala
  11. +28 −4 persistence/record/src/main/scala/net/liftweb/record/Record.scala
  12. +61 −35 persistence/record/src/test/scala/net/liftweb/record/FieldSpec.scala
  13. +11 −17 persistence/record/src/test/scala/net/liftweb/record/Fixtures.scala
  14. +1 −2  persistence/record/src/test/scala/net/liftweb/record/RecordSpec.scala
View
59 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/BsonRecord.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 WorldWide Conferencing, LLC
+ * Copyright 2011-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,31 +36,18 @@ trait BsonRecord[MyType <: BsonRecord[MyType]] extends Record[MyType] {
def meta: BsonMetaRecord[MyType]
/**
- * Encode a record instance into a DBObject
- */
+ * Encode a record instance into a DBObject
+ */
def asDBObject: DBObject = meta.asDBObject(this)
/**
- * Set the fields of this record from the given DBObject
- */
+ * Set the fields of this record from the given DBObject
+ */
def setFieldsFromDBObject(dbo: DBObject): Unit = meta.setFieldsFromDBObject(this, dbo)
- override def toString = {
- val fieldList = this.fields.map(f => "%s=%s" format (f.name,
- f.valueBox match {
- case Full(c: java.util.Calendar) => c.getTime().toString()
- case Full(null) => ""
- case Full(v) => v.toString
- case _ => ""
- }))
-
- "%s={%s}" format (this.getClass.toString, fieldList.mkString(", "))
- }
-
-
/**
- * Save the instance and return the instance
- */
+ * Save the instance and return the instance
+ */
override def saveTheRecord(): Box[MyType] = throw new BackingStoreException("BSON Records don't save themselves")
}
@@ -69,10 +56,10 @@ trait BsonMetaRecord[BaseRecord <: BsonRecord[BaseRecord]] extends MetaRecord[Ba
self: BaseRecord =>
/**
- * Create a BasicDBObject from the field names and values.
- * - MongoFieldFlavor types (List) are converted to DBObjects
- * using asDBObject
- */
+ * Create a BasicDBObject from the field names and values.
+ * - MongoFieldFlavor types (List) are converted to DBObjects
+ * using asDBObject
+ */
def asDBObject(inst: BaseRecord): DBObject = {
val dbo = BasicDBObjectBuilder.start // use this so regex patterns can be stored.
@@ -116,11 +103,11 @@ trait BsonMetaRecord[BaseRecord <: BsonRecord[BaseRecord]] extends MetaRecord[Ba
}
/**
- * Creates a new record, then sets the fields with the given DBObject.
- *
- * @param dbo - the DBObject
- * @return Box[BaseRecord]
- */
+ * Creates a new record, then sets the fields with the given DBObject.
+ *
+ * @param dbo - the DBObject
+ * @return Box[BaseRecord]
+ */
def fromDBObject(dbo: DBObject): BaseRecord = {
val inst: BaseRecord = createRecord
setFieldsFromDBObject(inst, dbo)
@@ -128,13 +115,13 @@ trait BsonMetaRecord[BaseRecord <: BsonRecord[BaseRecord]] extends MetaRecord[Ba
}
/**
- * Populate the inst's fields with the values from a DBObject. Values are set
- * using setFromAny passing it the DBObject returned from Mongo.
- *
- * @param inst - the record that will be populated
- * @param dbo - The DBObject
- * @return Unit
- */
+ * Populate the inst's fields with the values from a DBObject. Values are set
+ * using setFromAny passing it the DBObject returned from Mongo.
+ *
+ * @param inst - the record that will be populated
+ * @param dbo - The DBObject
+ * @return Unit
+ */
def setFieldsFromDBObject(inst: BaseRecord, dbo: DBObject): Unit = {
for (k <- dbo.keySet; field <- inst.fieldByName(k.toString)) {
field.setFromAny(dbo.get(k.toString))
View
6 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 WorldWide Conferencing, LLC
+ * Copyright 2010-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -317,7 +317,9 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
}
/**
- * Update only the dirty fields
+ * Update only the dirty fields.
+ *
+ * Note: PatternField will always set the dirty flag when set.
*/
def update(inst: BaseRecord): Unit = {
val dirtyFields = fields(inst).filter(_.dirty_?)
View
4 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JsonObjectField.scala
@@ -1,5 +1,5 @@
/*
-* Copyright 2010-2011 WorldWide Conferencing, LLC
+* Copyright 2010-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ abstract class JsonObjectField[OwnerType <: BsonRecord[OwnerType], JObjectType <
override def toForm: Box[NodeSeq] = Empty // FIXME
/** Encode the field value into a JValue */
- def asJValue: JValue = value.asJObject
+ def asJValue: JValue = valueBox.map(_.asJObject) openOr (JNothing: JValue)
/*
* Decode the JValue and set the field to the decoded value.
View
8 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/PatternField.scala
@@ -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 java.util.regex.Pattern
import scala.xml.NodeSeq
View
46 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/BsonRecordSpec.scala
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2012 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package mongodb
+package record
+
+import org.specs2.mutable.Specification
+
+class BsonRecordSpec extends Specification with MongoTestKit {
+ "BsonRecordSpec Specification".title
+ import fixtures._
+
+ override def before = {
+ super.before
+ checkMongoIsRunning
+ }
+
+ "BsonRecord" should {
+ "compare properly" in {
+
+ val subRec = SubSubRecord.createRecord.name("subrecord")
+ val subRec2 = SubSubRecord.createRecord.name("subrecord")
+
+ (subRec == subRec2) must_== true
+
+ subRec2.name("subrecord2")
+
+ (subRec == subRec2) must_== false
+
+ }
+ }
+}
View
84 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 WorldWide Conferencing, LLC
+ * Copyright 2010-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -132,25 +132,6 @@ class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] wi
object legacyOptionalTimeZoneField extends TimeZoneField(this) { override def optional_? = true }
object optionalTimeZoneField extends OptionalTimeZoneField(this)
- override def equals(other: Any): Boolean = other match {
- case that: FieldTypeTestRecord =>
- this.id.value == that.id.value &&
- this.mandatoryBooleanField.value == that.mandatoryBooleanField.value &&
- this.mandatoryCountryField.value == that.mandatoryCountryField.value &&
- this.mandatoryDecimalField.value == that.mandatoryDecimalField.value &&
- this.mandatoryDoubleField.value == that.mandatoryDoubleField.value &&
- this.mandatoryEmailField.value == that.mandatoryEmailField.value &&
- this.mandatoryEnumField.value == that.mandatoryEnumField.value &&
- this.mandatoryIntField.value == that.mandatoryIntField.value &&
- this.mandatoryLocaleField.value == that.mandatoryLocaleField.value &&
- this.mandatoryLongField.value == that.mandatoryLongField.value &&
- this.mandatoryPostalCodeField.value == that.mandatoryPostalCodeField.value &&
- this.mandatoryStringField.value == that.mandatoryStringField.value &&
- this.mandatoryTextareaField.value == that.mandatoryTextareaField.value &&
- this.mandatoryTimeZoneField.value == that.mandatoryTimeZoneField.value
- case _ => false
- }
-
def dirtyFields = this.allFields.filter(_.dirty_?)
}
@@ -238,9 +219,6 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
object mandatoryObjectIdField extends ObjectIdField(this)
object legacyOptionalObjectIdField extends ObjectIdField(this) { override def optional_? = true }
- object mandatoryPatternField extends PatternField(this)
- object legacyOptionalPatternField extends PatternField(this) { override def optional_? = true }
-
object mandatoryUUIDField extends UUIDField(this)
object legacyOptionalUUIDField extends UUIDField(this) { override def optional_? = true }
@@ -248,19 +226,6 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
override def formats = owner.meta.formats
}
- override def equals(other: Any): Boolean = other match {
- case that: MongoFieldTypeTestRecord =>
- this.id.value == that.id.value &&
- this.mandatoryDateField.value == that.mandatoryDateField.value &&
- this.mandatoryJsonObjectField.value == that.mandatoryJsonObjectField.value &&
- 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.mandatoryMongoCaseClassField.value == that.mandatoryMongoCaseClassField.value
- case _ => false
- }
-
def dirtyFields = this.allFields.filter(_.dirty_?)
}
@@ -268,6 +233,38 @@ object MongoFieldTypeTestRecord extends MongoFieldTypeTestRecord with MongoMetaR
override def formats = allFormats + new EnumSerializer(MyTestEnum)
}
+class PatternFieldTestRecord private () extends MongoRecord[PatternFieldTestRecord] with ObjectIdPk[PatternFieldTestRecord] {
+ def meta = PatternFieldTestRecord
+
+ import java.util.regex.Pattern
+
+ object mandatoryPatternField extends PatternField(this)
+ object legacyOptionalPatternField extends PatternField(this) { override def optional_? = true }
+
+ /**
+ * Pattern.equals doesn't work properly, so a custom equals is required with PatternField
+ */
+ override def equals(other: Any): Boolean = {
+ other match {
+ case that: PatternFieldTestRecord =>
+ that.fields.corresponds(this.fields) { (a,b) =>
+ (a.name == b.name) && ((a.valueBox, b.valueBox) match {
+ case (Full(ap: Pattern), Full(bp: Pattern)) =>
+ ap.pattern == bp.pattern && ap.flags == bp.flags
+ case _ => a.valueBox == b.valueBox
+ })
+ }
+ case _ => false
+ }
+ }
+
+ def dirtyFields = this.allFields.filter(_.dirty_?)
+}
+
+object PatternFieldTestRecord extends PatternFieldTestRecord with MongoMetaRecord[PatternFieldTestRecord] {
+ override def formats = allFormats
+}
+
class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with ObjectIdPk[PasswordTestRecord] {
def meta = PasswordTestRecord
@@ -379,12 +376,6 @@ class SubSubRecord private () extends BsonRecord[SubSubRecord] {
def meta = SubSubRecord
object name extends StringField(this, 12)
-
- override def equals(other: Any): Boolean = other match {
- case that: SubSubRecord =>
- this.name.value == that.name.value
- case _ => false
- }
}
object SubSubRecord extends SubSubRecord with BsonMetaRecord[SubSubRecord] {
override def formats = allFormats
@@ -431,11 +422,6 @@ class NullTestRecord private () extends MongoRecord[NullTestRecord] with IntPk[N
def defaultValue = JsonObj("1", null)
}
object jsonobjlist extends MongoJsonObjectListField[NullTestRecord, JsonObj](this, JsonObj)
-
- override def equals(other: Any): Boolean = other match {
- case that: NullTestRecord => this.toString == that.toString
- case _ => false
- }
}
object NullTestRecord extends NullTestRecord with MongoMetaRecord[NullTestRecord]
@@ -454,10 +440,6 @@ class BoxTestRecord private () extends MongoRecord[BoxTestRecord] with LongPk[Bo
}
object jsonobjlist extends MongoJsonObjectListField[BoxTestRecord, BoxTestJsonObj](this, BoxTestJsonObj)
- override def equals(other: Any): Boolean = other match {
- case that: BoxTestRecord => this.toString == that.toString
- case _ => false
- }
}
object BoxTestRecord extends BoxTestRecord with MongoMetaRecord[BoxTestRecord] {
override def formats = super.formats + new JsonBoxSerializer
View
162 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2011 WorldWide Conferencing, LLC
+ * Copyright 2006-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@ package net.liftweb
package mongodb
package record
-import java.util.{Date, UUID}
+import java.util.{Calendar, Date, UUID}
import java.util.regex.Pattern
import org.bson.types.ObjectId
@@ -54,12 +54,13 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
def passBasicTests[A](
example: A,
+ example2: A,
mandatory: MandatoryTypedField[A],
legacyOptional: MandatoryTypedField[A],
canCheckDefaultValues: Boolean = true
)(implicit m: scala.reflect.Manifest[A]): Unit = {
- def commonBehaviorsForAllFlavors(field: MandatoryTypedField[A]) = {
+ def commonBehaviorsForAllFlavors(field: MandatoryTypedField[A]): Unit = {
"which have the correct initial value" in {
field.value must be_==(field.defaultValue).when(canCheckDefaultValues)
@@ -88,6 +89,30 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
// Failure("my failure") must_== Failure("my failure")
pending
}
+
+ "which are only flagged as dirty_? when setBox is called with a different value" in {
+ field.clear
+ field match {
+ case owned: OwnedField[_] => owned.owner.runSafe {
+ field.resetDirty
+ }
+ case _ => field.resetDirty
+ }
+ field.dirty_? must_== false
+ val valueBox = field.valueBox
+ field.setBox(valueBox)
+ field.dirty_? must_== false
+ val exampleBox = Full(example)
+ (valueBox === exampleBox) must_== false
+ field.setBox(exampleBox)
+ field.dirty_? must_== true
+ val exampleBox2 = Full(example2)
+ (exampleBox === exampleBox2) must_== false
+ field.setBox(exampleBox2)
+ field.dirty_? must_== true
+ field.setBox(valueBox)
+ success
+ }
}
"support mandatory fields" in {
@@ -191,7 +216,9 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
val rec = MongoFieldTypeTestRecord.createRecord
val now = new Date
val nowStr = rec.meta.formats.dateFormat.format(now)
- passBasicTests(now, rec.mandatoryDateField, rec.legacyOptionalDateField, false)
+ val now2 = Calendar.getInstance()
+ now2.add(Calendar.DATE, 1)
+ passBasicTests(now, now2.getTime, rec.mandatoryDateField, rec.legacyOptionalDateField, false)
passConversionTests(
now,
rec.mandatoryDateField,
@@ -204,8 +231,9 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"JsonObjectField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val ttjo = TypeTestJsonObject(1, "jsonobj1", Map("x" -> "a"))
+ val ttjo2 = TypeTestJsonObject(2, "jsonobj2", Map("x" -> "b"))
val json = ("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> (("x" -> "a")))
- passBasicTests(ttjo, rec.mandatoryJsonObjectField, rec.legacyOptionalJsonObjectField)
+ passBasicTests(ttjo, ttjo2, rec.mandatoryJsonObjectField, rec.legacyOptionalJsonObjectField)
passConversionTests(
ttjo,
rec.mandatoryJsonObjectField,
@@ -220,7 +248,8 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"ObjectIdField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val oid = ObjectId.get
- passBasicTests(oid, rec.mandatoryObjectIdField, rec.legacyOptionalObjectIdField, false)
+ val oid2 = ObjectId.get
+ passBasicTests(oid, oid2, rec.mandatoryObjectIdField, rec.legacyOptionalObjectIdField, false)
passConversionTests(
oid,
rec.mandatoryObjectIdField,
@@ -231,9 +260,10 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
}
"PatternField" should {
- val rec = MongoFieldTypeTestRecord.createRecord
+ val rec = PatternFieldTestRecord.createRecord
val ptrn = Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE)
- passBasicTests(ptrn, rec.mandatoryPatternField, rec.legacyOptionalPatternField, false)
+ val ptrn2 = Pattern.compile("^MON", Pattern.CASE_INSENSITIVE)
+ passBasicTests(ptrn, ptrn2, rec.mandatoryPatternField, rec.legacyOptionalPatternField, false)
passConversionTests(
ptrn,
rec.mandatoryPatternField,
@@ -246,7 +276,8 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"UUIDField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val uuid = UUID.randomUUID
- passBasicTests(uuid, rec.mandatoryUUIDField, rec.legacyOptionalUUIDField, false)
+ val uuid2 = UUID.randomUUID
+ passBasicTests(uuid, uuid2, rec.mandatoryUUIDField, rec.legacyOptionalUUIDField, false)
passConversionTests(
uuid,
rec.mandatoryUUIDField,
@@ -280,7 +311,8 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = ListTestRecord.createRecord
val lst = List("abc", "def", "ghi")
- passBasicTests(lst, rec.mandatoryStringListField, rec.legacyOptionalStringListField)
+ val lst2 = List("ab", "de", "gh")
+ passBasicTests(lst, lst2, rec.mandatoryStringListField, rec.legacyOptionalStringListField)
passConversionTests(
lst,
rec.mandatoryStringListField,
@@ -295,7 +327,8 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = ListTestRecord.createRecord
val lst = List(4, 5, 6)
- passBasicTests(lst, rec.mandatoryIntListField, rec.legacyOptionalIntListField)
+ val lst2 = List(1, 2, 3)
+ passBasicTests(lst, lst2, rec.mandatoryIntListField, rec.legacyOptionalIntListField)
passConversionTests(
lst,
rec.mandatoryIntListField,
@@ -310,11 +343,12 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = ListTestRecord.createRecord
val lst = List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2")))
+ val lst2 = List(TypeTestJsonObject(3, "jsonobj3", Map("x" -> "3")), TypeTestJsonObject(4, "jsonobj4", Map("x" -> "4")))
val json = List(
("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> (("x" -> "1"))),
("intField" -> 2) ~ ("stringField" -> "jsonobj2") ~ ("mapField" -> (("x" -> "2")))
)
- passBasicTests(lst, rec.mandatoryMongoJsonObjectListField, rec.legacyOptionalMongoJsonObjectListField)
+ passBasicTests(lst, lst2, rec.mandatoryMongoJsonObjectListField, rec.legacyOptionalMongoJsonObjectListField)
passConversionTests(
lst,
rec.mandatoryMongoJsonObjectListField,
@@ -340,7 +374,8 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = MapTestRecord.createRecord
val map = Map("a" -> "abc", "b" -> "def", "c" -> "ghi")
- passBasicTests(map, rec.mandatoryStringMapField, rec.legacyOptionalStringMapField)
+ val map2 = Map("a" -> "ab", "b" -> "de", "c" -> "gh")
+ passBasicTests(map, map2, rec.mandatoryStringMapField, rec.legacyOptionalStringMapField)
passConversionTests(
map,
rec.mandatoryStringMapField,
@@ -359,7 +394,8 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = MapTestRecord.createRecord
val map = Map("a" -> 4, "b" -> 5, "c" -> 6)
- passBasicTests(map, rec.mandatoryIntMapField, rec.legacyOptionalIntMapField)
+ val map2 = Map("a" -> 1, "b" -> 2, "c" -> 3)
+ passBasicTests(map, map2, rec.mandatoryIntMapField, rec.legacyOptionalIntMapField)
passConversionTests(
map,
rec.mandatoryIntMapField,
@@ -378,32 +414,27 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = SubRecordTestRecord.createRecord
val subRec = SubRecord.createRecord.name("subrecord")
+ val subRec2 = SubRecord.createRecord.name("subrecord2")
val srJson =
- JObject(List(
- JField("name", JString("subrecord")),
- JField("subsub", JObject(List(
- JField("name", JString(""))
- ))),
- JField("subsublist", JArray(List())),
- JField("when", JObject(List(
- JField("$dt", JString(rec.meta.formats.dateFormat.format(subRec.when.value)))
- ))),
- JField("slist", JArray(List())),
- JField("smap", JObject(List())),
- JField("oid", JObject(List(JField("$oid", JString(subRec.oid.value.toString))))),
- JField("pattern", JObject(List(
- JField("$regex", JString(subRec.pattern.value.pattern)),
- JField("$flags", JInt(subRec.pattern.value.flags))
- ))),
- JField("uuid", JObject(List(JField("$uuid", JString(subRec.uuid.value.toString)))))
- ))
+ ("name" -> "subrecord") ~
+ ("subsub" -> ("name" -> "")) ~
+ ("subsublist" -> JArray(Nil)) ~
+ ("when" -> ("$dt" -> rec.meta.formats.dateFormat.format(subRec.when.value))) ~
+ ("slist" -> JArray(Nil)) ~
+ ("smap" -> JObject(Nil)) ~
+ ("oid" -> ("$oid" -> subRec.oid.value.toString)) ~
+ ("pattern" ->
+ ("$regex" -> subRec.pattern.value.pattern) ~
+ ("$flags" -> subRec.pattern.value.flags)
+ ) ~
+ ("uuid" -> ("$uuid" -> subRec.uuid.value.toString))
val srJsExp = new JsExp {
def toJsCmd = Printer.compact(render(srJson))
}
- passBasicTests(subRec, rec.mandatoryBsonRecordField, rec.legacyOptionalBsonRecordField, false)
+ passBasicTests(subRec, subRec2, rec.mandatoryBsonRecordField, rec.legacyOptionalBsonRecordField, false)
passConversionTests(
subRec,
rec.mandatoryBsonRecordField,
@@ -418,44 +449,35 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
"function correctly" in {
val rec = SubRecordTestRecord.createRecord
val lst = List(SubRecord.createRecord.name("subrec1"), SubRecord.createRecord.name("subrec2"))
+ val lst2 = List(SubRecord.createRecord.name("subrec3"), SubRecord.createRecord.name("subrec4"))
val sr1Json =
- JObject(List(
- JField("name", JString("subrec1")),
- JField("subsub", JObject(List(
- JField("name", JString(""))
- ))),
- JField("subsublist", JArray(List())),
- JField("when", JObject(List(
- JField("$dt", JString(rec.meta.formats.dateFormat.format(lst(0).when.value)))
- ))),
- JField("slist", JArray(List())),
- JField("smap", JObject(List())),
- JField("oid", JObject(List(JField("$oid", JString(lst(0).oid.value.toString))))),
- JField("pattern", JObject(List(
- JField("$regex", JString(lst(0).pattern.value.pattern)),
- JField("$flags", JInt(lst(0).pattern.value.flags))
- ))),
- JField("uuid", JObject(List(JField("$uuid", JString(lst(0).uuid.value.toString)))))
- ))
+ ("name" -> "subrec1") ~
+ ("subsub" -> ("name" -> "")) ~
+ ("subsublist" -> JArray(Nil)) ~
+ ("when" -> ("$dt" -> rec.meta.formats.dateFormat.format(lst(0).when.value))) ~
+ ("slist" -> JArray(Nil)) ~
+ ("smap" -> JObject(Nil)) ~
+ ("oid" -> ("$oid" -> lst(0).oid.value.toString)) ~
+ ("pattern" ->
+ ("$regex" -> lst(0).pattern.value.pattern) ~
+ ("$flags" -> lst(0).pattern.value.flags)
+ ) ~
+ ("uuid" -> ("$uuid" -> lst(0).uuid.value.toString))
+
val sr2Json =
- JObject(List(
- JField("name", JString("subrec2")),
- JField("subsub", JObject(List(
- JField("name", JString(""))
- ))),
- JField("subsublist", JArray(List())),
- JField("when", JObject(List(
- JField("$dt", JString(rec.meta.formats.dateFormat.format(lst(1).when.value)))
- ))),
- JField("slist", JArray(List())),
- JField("smap", JObject(List())),
- JField("oid", JObject(List(JField("$oid", JString(lst(1).oid.value.toString))))),
- JField("pattern", JObject(List(
- JField("$regex", JString(lst(1).pattern.value.pattern)),
- JField("$flags", JInt(lst(1).pattern.value.flags))
- ))),
- JField("uuid", JObject(List(JField("$uuid", JString(lst(1).uuid.value.toString)))))
- ))
+ ("name" -> "subrec2") ~
+ ("subsub" -> ("name" -> "")) ~
+ ("subsublist" -> JArray(Nil)) ~
+ ("when" -> ("$dt" -> rec.meta.formats.dateFormat.format(lst(1).when.value))) ~
+ ("slist" -> JArray(Nil)) ~
+ ("smap" -> JObject(Nil)) ~
+ ("oid" -> ("$oid" -> lst(1).oid.value.toString)) ~
+ ("pattern" ->
+ ("$regex" -> lst(1).pattern.value.pattern) ~
+ ("$flags" -> lst(1).pattern.value.flags)
+ ) ~
+ ("uuid" -> ("$uuid" -> lst(1).uuid.value.toString))
+
val sr1JsExp = new JsExp {
def toJsCmd = compact(render(sr1Json))
}
@@ -463,7 +485,7 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
def toJsCmd = compact(render(sr2Json))
}
- passBasicTests(lst, rec.mandatoryBsonRecordListField, rec.legacyOptionalBsonRecordListField)
+ passBasicTests(lst, lst2, rec.mandatoryBsonRecordListField, rec.legacyOptionalBsonRecordListField)
passConversionTests(
lst,
rec.mandatoryBsonRecordListField,
View
77 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 WorldWide Conferencing, LLC
+ * Copyright 2010-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ class MongoRecordSpec extends Specification with MongoTestKit {
val rec = MongoFieldTypeTestRecord.createRecord
val allExpectedFieldNames: List[String] = "_id" :: "mandatoryMongoCaseClassField" ::
(for {
- typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
+ typeName <- "Date JsonObject ObjectId UUID".split(" ")
flavor <- "mandatory legacyOptional".split(" ")
} yield flavor + typeName + "Field").toList
@@ -196,7 +196,6 @@ class MongoRecordSpec extends Specification with MongoTestKit {
.mandatoryDateField(new Date)
.mandatoryJsonObjectField(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")))
.mandatoryObjectIdField(ObjectId.get)
- .mandatoryPatternField(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
.mandatoryUUIDField(UUID.randomUUID)
.mandatoryMongoCaseClassField(MongoCaseClassTestObject(1,"str",MyTestEnum.TWO))
@@ -205,15 +204,21 @@ class MongoRecordSpec extends Specification with MongoTestKit {
("mandatoryDateField" -> ("$dt" -> mfttr.meta.formats.dateFormat.format(mfttr.mandatoryDateField.value))) ~
("legacyOptionalDateField" -> (None: Option[JObject])) ~
("mandatoryJsonObjectField" -> (("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> ("x" -> "1")))) ~
- ("legacyOptionalJsonObjectField" -> (("intField" -> 0) ~ ("stringField" -> "") ~ ("mapField" -> JObject(Nil)))) ~
+ ("legacyOptionalJsonObjectField" -> (None: Option[JObject])) ~
("mandatoryObjectIdField", ("$oid" -> mfttr.mandatoryObjectIdField.value.toString)) ~
("legacyOptionalObjectIdField" -> (None: Option[JObject])) ~
- ("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])) ~
("mandatoryMongoCaseClassField" -> ("intField" -> 1) ~ ("stringField" -> "str") ~ ("enum" -> 1))
+ val pftr = PatternFieldTestRecord.createRecord
+ .mandatoryPatternField(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
+
+ val pftrJson =
+ ("_id" -> ("$oid" -> pftr.id.toString)) ~
+ ("mandatoryPatternField" -> (("$regex" -> pftr.mandatoryPatternField.value.pattern) ~ ("$flags" -> pftr.mandatoryPatternField.value.flags))) ~
+ ("legacyOptionalPatternField" -> (None: Option[JObject]))
+
val ltr = ListTestRecord.createRecord
.mandatoryStringListField(List("abc", "def", "ghi"))
.mandatoryIntListField(List(4, 5, 6))
@@ -371,6 +376,14 @@ class MongoRecordSpec extends Specification with MongoTestKit {
tr mustEqual mfttr
}
+ pftr.save
+
+ val pftrFromDb = PatternFieldTestRecord.find(pftr.id.value)
+ pftrFromDb.isDefined must_== true
+ pftrFromDb foreach { tr =>
+ tr mustEqual pftr
+ }
+
ltr.save
val ltrFromDb = ListTestRecord.find(ltr.id.value)
@@ -406,6 +419,15 @@ class MongoRecordSpec extends Specification with MongoTestKit {
tr mustEqual mfttrDef
}
+ val pftrDef = PatternFieldTestRecord.createRecord
+ pftrDef.save
+
+ val pftrFromDb = PatternFieldTestRecord.find(pftrDef.id.value)
+ pftrFromDb.isDefined must_== true
+ pftrFromDb foreach { tr =>
+ tr mustEqual pftrDef
+ }
+
val ltrDef = ListTestRecord.createRecord
ltrDef.save
@@ -437,6 +459,8 @@ class MongoRecordSpec extends Specification with MongoTestKit {
"convert Mongo type fields to JValue" in {
mfttr.asJValue mustEqual mfttrJson
+ pftr.asJValue mustEqual pftrJson
+
ltr.asJValue mustEqual ltrJson
mtr.asJValue mustEqual mtrJson
@@ -456,6 +480,12 @@ class MongoRecordSpec extends Specification with MongoTestKit {
tr mustEqual mfttr
}
+ val pftrFromJson = PatternFieldTestRecord.fromJsonString(compact(render(pftrJson)))
+ pftrFromJson.isDefined must_== true
+ pftrFromJson foreach { tr =>
+ tr mustEqual pftr
+ }
+
val ltrFromJson = ListTestRecord.fromJsonString(compact(render(ltrJson)))
ltrFromJson.isDefined must_== true
ltrFromJson foreach { tr =>
@@ -691,7 +721,6 @@ class MongoRecordSpec extends Specification with MongoTestKit {
rec.dirtyFields.length must_== 0
}
-
val fttr2 = FieldTypeTestRecord.createRecord.save
fttr2.legacyOptionalStringField("legacy optional string")
@@ -730,9 +759,6 @@ class MongoRecordSpec extends Specification with MongoTestKit {
mfttr.mandatoryObjectIdField(ObjectId.get)
mfttr.mandatoryObjectIdField.dirty_? must_== true
- mfttr.mandatoryPatternField(Pattern.compile("^Mon", Pattern.CASE_INSENSITIVE))
- mfttr.mandatoryPatternField.dirty_? must_== true
-
mfttr.mandatoryUUIDField(UUID.randomUUID)
mfttr.mandatoryUUIDField.dirty_? must_== true
@@ -742,7 +768,7 @@ class MongoRecordSpec extends Specification with MongoTestKit {
mfttr.legacyOptionalObjectIdField(Empty)
mfttr.legacyOptionalObjectIdField.dirty_? must_== true
- mfttr.dirtyFields.length must_== 7
+ mfttr.dirtyFields.length must_== 6
mfttr.update
mfttr.dirtyFields.length must_== 0
@@ -773,6 +799,25 @@ 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
+
+ pftrd.mandatoryPatternField(Pattern.compile("^Mon", Pattern.CASE_INSENSITIVE))
+ pftrd.mandatoryPatternField.dirty_? must_== true
+
+ pftrd.dirtyFields.length must_== 1
+ pftrd.update
+ pftrd.dirtyFields.length must_== 0
+
+ val fromDb = PatternFieldTestRecord.find(pftrd.id.is)
+ fromDb.isDefined must_== true
+ fromDb foreach { rec =>
+ rec must_== pftrd
+ rec.dirtyFields.length must_== 0
+ }
+ }*/
+
"update dirty fields for a ListTestRecord" in {
val ltr = ListTestRecord.createRecord.save
@@ -822,8 +867,6 @@ class MongoRecordSpec extends Specification with MongoTestKit {
}
"update dirty fields for a SubRecordTestRecord" in {
- val srtr = SubRecordTestRecord.createRecord.save
-
val ssr1 = SubSubRecord.createRecord.name("SubSubRecord1")
val ssr2 = SubSubRecord.createRecord.name("SubSubRecord2")
@@ -835,9 +878,13 @@ class MongoRecordSpec extends Specification with MongoTestKit {
.smap(Map("a" -> "s1", "b" -> "s2"))
.pattern(Pattern.compile("^Mon", Pattern.CASE_INSENSITIVE))
- val sr2 = SubRecord.createRecord.name("SubRecord2")
+ val srtr = SubRecordTestRecord.createRecord
+ .mandatoryBsonRecordField(sr1)
+ .save
+
+ val sr2 = sr1.copy.name("SubRecord2")
- srtr.mandatoryBsonRecordField(sr1)
+ srtr.mandatoryBsonRecordField(sr2)
srtr.mandatoryBsonRecordField.dirty_? must_== true
srtr.mandatoryBsonRecordListField(List(sr1,sr2))
View
36 persistence/record/src/main/scala/net/liftweb/record/Field.scala
@@ -39,6 +39,11 @@ trait BaseField extends FieldIdentifier with util.BaseField {
def dirty_? : Boolean = dirty
/**
+ * Should the dirty flag always be set when setBox is called
+ */
+ def forceDirty_? : Boolean = false
+
+ /**
* Should the field be ignored by the OR Mapper?
*/
def ignoreField_? = false
@@ -146,7 +151,7 @@ trait OwnedField[OwnerType <: Record[OwnerType]] extends BaseField {
/** Refined trait for fields holding a particular value type */
trait TypedField[ThisType] extends BaseField {
-
+
/*
* Unless overriden, MyType is equal to ThisType. Available for
* backwards compatibility
@@ -217,7 +222,7 @@ trait TypedField[ThisType] extends BaseField {
def setBox(in: Box[MyType]): Box[MyType] = synchronized {
needsDefault = false
- val oldValue = valueBox
+ val oldValue = data
data = in match {
case _ if !canWrite_? => Failure(noValueErrorMessage)
case Full(_) => set_!(in)
@@ -225,17 +230,22 @@ trait TypedField[ThisType] extends BaseField {
case (f: Failure) => set_!(f) // preserve failures set in
case _ => Failure(notOptionalErrorMessage)
}
- val same = (oldValue, valueBox) match {
- case (Full(ov), Full(nv)) => ov == nv
- case (a, b) => a == b
+ if (forceDirty_?) {
+ dirty_?(true)
+ }
+ else if (!dirty_?) {
+ val same = (oldValue, data) match {
+ case (Full(ov), Full(nv)) => ov == nv
+ case (a, b) => a == b
+ }
+ dirty_?(!same)
}
- dirty_?(!same)
data
}
// Helper methods for things to easily use mixins and so on that use ValueType instead of Box[MyType], regardless of the optional-ness of the field
protected def toValueType(in: Box[MyType]): ValueType
-
+
protected def toBoxMyType(in: ValueType): Box[MyType]
protected def set_!(in: Box[MyType]): Box[MyType] = runFilters(in, setFilterBox)
@@ -324,7 +334,7 @@ trait TypedField[ThisType] extends BaseField {
}
trait MandatoryTypedField[ThisType] extends TypedField[ThisType] with Product1[ThisType] {
-
+
/**
* ValueType represents the type that users will work with. For MandatoryTypeField, this is
* equal to ThisType.
@@ -351,7 +361,7 @@ trait MandatoryTypedField[ThisType] extends TypedField[ThisType] with Product1[T
def value: MyType = valueBox openOr defaultValue
def get: MyType = value
-
+
def is: MyType = value
protected def liftSetFilterToBox(in: Box[MyType]): Box[MyType] = in.map(v => setFilter.foldLeft(v)((prev, f) => f(prev)))
@@ -371,7 +381,7 @@ trait MandatoryTypedField[ThisType] extends TypedField[ThisType] with Product1[T
}
trait OptionalTypedField[ThisType] extends TypedField[ThisType] with Product1[Box[ThisType]] {
-
+
/**
* ValueType represents the type that users will work with. For OptionalTypedField, this is
* equal to Option[ThisType].
@@ -393,16 +403,16 @@ trait OptionalTypedField[ThisType] extends TypedField[ThisType] with Product1[Bo
def set(in: Option[MyType]): Option[MyType] = setBox(in) or defaultValueBox
def toValueType(in: Box[MyType]) = in
-
+
def toBoxMyType(in: ValueType) = in
def value: Option[MyType] = valueBox
def get: Option[MyType] = value
-
+
def is: Option[MyType] = value
- protected def liftSetFilterToBox(in: Box[MyType]): Box[MyType] = setFilter.foldLeft(in){ (prev, f) =>
+ protected def liftSetFilterToBox(in: Box[MyType]): Box[MyType] = setFilter.foldLeft(in){ (prev, f) =>
prev match {
case fail: Failure => fail //stop on failure, otherwise some filters will clober it to Empty
case other => f(other)
View
21 persistence/record/src/main/scala/net/liftweb/record/MetaRecord.scala
@@ -441,6 +441,27 @@ trait MetaRecord[BaseRecord <: Record[BaseRecord]] {
}
/**
+ * Populate the fields of the record with values from an existing record
+ *
+ * @param inst - The record to populate
+ * @param rec - The Record to read from
+ */
+ def setFieldsFromRecord(inst: BaseRecord, rec: BaseRecord) {
+ for {
+ fh <- fieldList
+ fld <- rec.fieldByName(fh.name)
+ } {
+ fh.field(inst).setFromAny(fld.valueBox)
+ }
+ }
+
+ def copy(rec: BaseRecord): BaseRecord = {
+ val inst = createRecord
+ setFieldsFromRecord(inst, rec)
+ inst
+ }
+
+ /**
* Defined the order of the fields in this record
*
* @return a List of Field
View
32 persistence/record/src/main/scala/net/liftweb/record/Record.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2011 WorldWide Conferencing, LLC
+ * Copyright 2007-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-package net.liftweb
-package record
+package net.liftweb
+package record
import common._
import http.js.{JsExp, JsObj}
@@ -82,7 +82,7 @@ trait Record[MyType <: Record[MyType]] extends FieldContainer {
* Save the instance and return the instance
*/
def saveTheRecord(): Box[MyType] = throw new BackingStoreException("Raw Records don't save themselves")
-
+
/**
* Retuns the JSON representation of this record, converts asJValue to JsObj
*
@@ -141,6 +141,30 @@ trait Record[MyType <: Record[MyType]] extends FieldContainer {
* @return Box[MappedField]
*/
def fieldByName(fieldName: String): Box[Field[_, MyType]] = meta.fieldByName(fieldName, this)
+
+ override def equals(other: Any): Boolean = {
+ other match {
+ case that: Record[MyType] =>
+ that.fields.corresponds(this.fields) { (a,b) =>
+ a.name == b.name && a.valueBox == b.valueBox
+ }
+ case _ => false
+ }
+ }
+
+ override def toString = {
+ val fieldList = this.fields.map(f => "%s=%s" format (f.name,
+ f.valueBox match {
+ case Full(c: java.util.Calendar) => c.getTime().toString()
+ case Full(null) => "null"
+ case Full(v) => v.toString
+ case _ => ""
+ }))
+
+ "%s={%s}" format (this.getClass.toString, fieldList.mkString(", "))
+ }
+
+ def copy: MyType = meta.copy(this)
}
trait ExpandoRecord[MyType <: Record[MyType] with ExpandoRecord[MyType]] {
View
96 persistence/record/src/test/scala/net/liftweb/record/FieldSpec.scala
@@ -44,7 +44,7 @@ object FieldSpec extends Specification {
lazy val session = new LiftSession("", randomString(20), Empty)
- def passBasicTests[A](example: A, mandatory: MandatoryTypedField[A], legacyOptional: MandatoryTypedField[A], optional: OptionalTypedField[A])(implicit m: scala.reflect.Manifest[A]): Fragment = {
+ def passBasicTests[A](example: A, example2: A, mandatory: MandatoryTypedField[A], legacyOptional: MandatoryTypedField[A], optional: OptionalTypedField[A])(implicit m: scala.reflect.Manifest[A]): Fragment = {
val canCheckDefaultValues =
!mandatory.defaultValue.isInstanceOf[Calendar] // don't try to use the default value of date/time typed fields, because it changes from moment to moment!
@@ -113,26 +113,31 @@ object FieldSpec extends Specification {
success
}
- if(canCheckDefaultValues) {
- "which are only flagged as dirty_? when setBox is called with a different value" in {
- in.clear
- in match {
- case owned: OwnedField[_] => owned.owner.runSafe {
- in.resetDirty
- }
- case _ => in.resetDirty
- }
- in.dirty_? must_== false
- val valueBox = in.valueBox
- in.setBox(valueBox)
- in.dirty_? must_== false
- val exampleBox = Full(example)
- (valueBox === exampleBox) must_== false
- in.setBox(exampleBox)
- in.dirty_? must_== true
- in.setBox(valueBox)
- success
- }
+ "which are only flagged as dirty_? when setBox is called with a different value" in {
+ in.clear
+ in match {
+ case owned: OwnedField[_] => owned.owner.runSafe {
+ in.resetDirty
+ }
+ case _ => in.resetDirty
+ }
+ in.dirty_? must_== false
+ val valueBox = in.valueBox
+ in.setBox(valueBox)
+ in.dirty_? must_== false
+ val exampleBox = Full(example)
+ (valueBox === exampleBox) must_== false
+ in.setBox(exampleBox)
+ in.dirty_? must_== true
+ val exampleBox2 = Full(example2)
+ (exampleBox === exampleBox2) must_== false
+ in.setBox(exampleBox2)
+ in.dirty_? must_== true
+ //dirty value should remain true, even if the same value is set twice before persisting
+ in.setBox(exampleBox)
+ in.dirty_? must_== true
+ in.setBox(valueBox)
+ success
}
}
@@ -271,7 +276,8 @@ object FieldSpec extends Specification {
"BooleanField" should {
val rec = FieldTypeTestRecord.createRecord
val bool = true
- passBasicTests(bool, rec.mandatoryBooleanField, rec.legacyOptionalBooleanField, rec.optionalBooleanField)
+ val bool2 = false
+ passBasicTests(bool, bool2, rec.mandatoryBooleanField, rec.legacyOptionalBooleanField, rec.optionalBooleanField)
passConversionTests(
bool,
rec.mandatoryBooleanField,
@@ -301,7 +307,8 @@ object FieldSpec extends Specification {
S.initIfUninitted(session){
val rec = FieldTypeTestRecord.createRecord
val country = Countries.Canada
- passBasicTests(country, rec.mandatoryCountryField, rec.legacyOptionalCountryField, rec.optionalCountryField)
+ val country2 = Countries.USA
+ passBasicTests(country, country2, rec.mandatoryCountryField, rec.legacyOptionalCountryField, rec.optionalCountryField)
passConversionTests(
country,
rec.mandatoryCountryField,
@@ -315,8 +322,10 @@ object FieldSpec extends Specification {
"DateTimeField" should {
val rec = FieldTypeTestRecord.createRecord
val dt = Calendar.getInstance
+ val dt2 = Calendar.getInstance
+ dt2.add(Calendar.DATE, 1)
val dtStr = toInternetDate(dt.getTime)
- passBasicTests(dt, rec.mandatoryDateTimeField, rec.legacyOptionalDateTimeField, rec.optionalDateTimeField)
+ passBasicTests(dt, dt2, rec.mandatoryDateTimeField, rec.legacyOptionalDateTimeField, rec.optionalDateTimeField)
passConversionTests(
dt,
rec.mandatoryDateTimeField,
@@ -342,7 +351,8 @@ object FieldSpec extends Specification {
"DecimalField" should {
val rec = FieldTypeTestRecord.createRecord
val bd = BigDecimal("12.34")
- passBasicTests(bd, rec.mandatoryDecimalField, rec.legacyOptionalDecimalField, rec.optionalDecimalField)
+ val bd2 = BigDecimal("1.22")
+ passBasicTests(bd, bd2, rec.mandatoryDecimalField, rec.legacyOptionalDecimalField, rec.optionalDecimalField)
passConversionTests(
bd,
rec.mandatoryDecimalField,
@@ -355,7 +365,8 @@ object FieldSpec extends Specification {
"DoubleField" should {
val rec = FieldTypeTestRecord.createRecord
val d = 12.34
- passBasicTests(d, rec.mandatoryDoubleField, rec.legacyOptionalDoubleField, rec.optionalDoubleField)
+ val d2 = 1.22
+ passBasicTests(d, d2, rec.mandatoryDoubleField, rec.legacyOptionalDoubleField, rec.optionalDoubleField)
passConversionTests(
d,
rec.mandatoryDoubleField,
@@ -369,7 +380,8 @@ object FieldSpec extends Specification {
val session = new LiftSession("", randomString(20), Empty)
val rec = FieldTypeTestRecord.createRecord
val email = "foo@bar.baz"
- passBasicTests(email, rec.mandatoryEmailField, rec.legacyOptionalEmailField, rec.optionalEmailField)
+ val email2 = "foo2@bar.baz"
+ passBasicTests(email, email2, rec.mandatoryEmailField, rec.legacyOptionalEmailField, rec.optionalEmailField)
passConversionTests(
email,
rec.mandatoryEmailField,
@@ -406,7 +418,8 @@ object FieldSpec extends Specification {
"EnumField" should {
val rec = FieldTypeTestRecord.createRecord
val ev = MyTestEnum.TWO
- passBasicTests(ev, rec.mandatoryEnumField, rec.legacyOptionalEnumField, rec.optionalEnumField)
+ val ev2 = MyTestEnum.ONE
+ passBasicTests(ev, ev2, rec.mandatoryEnumField, rec.legacyOptionalEnumField, rec.optionalEnumField)
passConversionTests(
ev,
rec.mandatoryEnumField,
@@ -419,7 +432,8 @@ object FieldSpec extends Specification {
"IntField" should {
val rec = FieldTypeTestRecord.createRecord
val num = 123
- passBasicTests(num, rec.mandatoryIntField, rec.legacyOptionalIntField, rec.optionalIntField)
+ val num2 = 456
+ passBasicTests(num, num2, rec.mandatoryIntField, rec.legacyOptionalIntField, rec.optionalIntField)
passConversionTests(
num,
rec.mandatoryIntField,
@@ -435,13 +449,18 @@ object FieldSpec extends Specification {
case "en_US" => "en_GB"
case _ => "en_US"
}
- passBasicTests(example, rec.mandatoryLocaleField, rec.legacyOptionalLocaleField, rec.optionalLocaleField)
+ val example2 = java.util.Locale.getDefault.toString match {
+ case "es_ES" => "en_NZ"
+ case _ => "es_ES"
+ }
+ passBasicTests(example, example2, rec.mandatoryLocaleField, rec.legacyOptionalLocaleField, rec.optionalLocaleField)
}
"LongField" should {
val rec = FieldTypeTestRecord.createRecord
val lng = 1234L
- passBasicTests(lng, rec.mandatoryLongField, rec.legacyOptionalLongField, rec.optionalLongField)
+ val lng2 = 5678L
+ passBasicTests(lng, lng2, rec.mandatoryLongField, rec.legacyOptionalLongField, rec.optionalLongField)
passConversionTests(
lng,
rec.mandatoryLongField,
@@ -485,8 +504,9 @@ object FieldSpec extends Specification {
val session = new LiftSession("", randomString(20), Empty)
val rec = FieldTypeTestRecord.createRecord
val zip = "02452"
+ val zip2 = "03344"
rec.mandatoryCountryField.set(Countries.USA)
- passBasicTests(zip, rec.mandatoryPostalCodeField, rec.legacyOptionalPostalCodeField, rec.optionalPostalCodeField)
+ passBasicTests(zip, zip2, rec.mandatoryPostalCodeField, rec.legacyOptionalPostalCodeField, rec.optionalPostalCodeField)
passConversionTests(
zip,
rec.mandatoryPostalCodeField,
@@ -524,7 +544,8 @@ object FieldSpec extends Specification {
{
val rec = FieldTypeTestRecord.createRecord
val str = "foobar"
- passBasicTests(str, rec.mandatoryStringField, rec.legacyOptionalStringField, rec.optionalStringField)
+ val str2 = "foobaz"
+ passBasicTests(str, str2, rec.mandatoryStringField, rec.legacyOptionalStringField, rec.optionalStringField)
passConversionTests(
str,
rec.mandatoryStringField,
@@ -610,7 +631,8 @@ object FieldSpec extends Specification {
"TextareaField" should {
val rec = FieldTypeTestRecord.createRecord
val txt = "foobar"
- passBasicTests(txt, rec.mandatoryTextareaField, rec.legacyOptionalTextareaField, rec.optionalTextareaField)
+ val txt2 = "foobaz"
+ passBasicTests(txt, txt2, rec.mandatoryTextareaField, rec.legacyOptionalTextareaField, rec.optionalTextareaField)
passConversionTests(
txt,
rec.mandatoryTextareaField,
@@ -626,7 +648,11 @@ object FieldSpec extends Specification {
case "America/New_York" => "Europe/London"
case _ => "America/New_York"
}
- passBasicTests(example, rec.mandatoryTimeZoneField, rec.legacyOptionalTimeZoneField, rec.optionalTimeZoneField)
+ val example2 = java.util.TimeZone.getDefault.getID match {
+ case "America/Chicago" => "Europe/Paris"
+ case _ => "America/Chicago"
+ }
+ passBasicTests(example, example2, rec.mandatoryTimeZoneField, rec.legacyOptionalTimeZoneField, rec.optionalTimeZoneField)
passConversionTests(
example,
rec.mandatoryTimeZoneField,
View
28 persistence/record/src/test/scala/net/liftweb/record/Fixtures.scala
@@ -212,24 +212,18 @@ class FieldTypeTestRecord private () extends Record[FieldTypeTestRecord] {
object legacyOptionalTimeZoneField extends TimeZoneField(this) { override def optional_? = true }
object optionalTimeZoneField extends OptionalTimeZoneField(this)
+
+ def fieldsToCompare = {
+ fields
+ .filterNot(_.name == "mandatoryBinaryField") // binarys don't compare
+ .filterNot(_.name == "mandatoryDateTimeField") // toInternetDate is lossy (doesn't retain time to ms precision)
+ }
+
override def equals(other: Any): Boolean = other match {
- case that:FieldTypeTestRecord =>
- //this.mandatoryBinaryField.value mustEqual that.mandatoryBinaryField.value
- this.mandatoryBooleanField.value == that.mandatoryBooleanField.value &&
- this.mandatoryCountryField.value == that.mandatoryCountryField.value &&
- Helpers.toInternetDate(this.mandatoryDateTimeField.value.getTime) ==
- Helpers.toInternetDate(that.mandatoryDateTimeField.value.getTime) &&
- //this.mandatoryDecimalField.value == that.mandatoryDecimalField.value &&
- this.mandatoryDoubleField.value == that.mandatoryDoubleField.value &&
- this.mandatoryEmailField.value == that.mandatoryEmailField.value &&
- this.mandatoryEnumField.value == that.mandatoryEnumField.value &&
- this.mandatoryIntField.value == that.mandatoryIntField.value &&
- this.mandatoryLocaleField.value == that.mandatoryLocaleField.value &&
- this.mandatoryLongField.value == that.mandatoryLongField.value &&
- this.mandatoryPostalCodeField.value == that.mandatoryPostalCodeField.value &&
- this.mandatoryStringField.value == that.mandatoryStringField.value &&
- this.mandatoryTextareaField.value == that.mandatoryTextareaField.value &&
- this.mandatoryTimeZoneField.value == that.mandatoryTimeZoneField.value
+ case that: FieldTypeTestRecord =>
+ that.fieldsToCompare.corresponds(this.fieldsToCompare) { (a,b) =>
+ a.name == b.name && a.valueBox == b.valueBox
+ }
case _ => false
}
}
View
3  persistence/record/src/test/scala/net/liftweb/record/RecordSpec.scala
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 WorldWide Conferencing, LLC
+ * Copyright 2010-2012 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -312,7 +312,6 @@ object RecordSpec extends Specification {
val fttrFromJson = FieldTypeTestRecord.fromJsonString(json)
fttrFromJson.isDefined must_== true
fttrFromJson.toList map { r =>
- r.mandatoryDecimalField.value mustEqual fttr.mandatoryDecimalField.value
r mustEqual fttr
}
}
Something went wrong with that request. Please try again.