Skip to content
This repository has been archived by the owner on Apr 12, 2018. It is now read-only.

Commit

Permalink
issue650 (partially), issue652 - add pile of unit tests to Record whi…
Browse files Browse the repository at this point in the history
…ch reveal the broken corner cases with "legacy optional" fields, the fact that errors are being swallowed by default values on non-optional fields, and that life cycle callbacks were broken at the record level (ended up trying to call them on the Meta object, because of def meta <: LifecycleCallbacks)
  • Loading branch information
Ross Mellgren committed Sep 21, 2010
1 parent e9ad228 commit 39d1df8
Show file tree
Hide file tree
Showing 6 changed files with 650 additions and 32 deletions.
Expand Up @@ -145,7 +145,7 @@ trait TypedField[ThisType] extends BaseField {
type ValidationFunction = ValueType => List[FieldError]

private[record] var data: Box[MyType] = Empty
private[record] var needsDefault = true
private[record] var needsDefault: Boolean = true

/**
* Helper for implementing asJValue for a conversion to an encoded JString
Expand Down Expand Up @@ -210,6 +210,7 @@ trait TypedField[ThisType] extends BaseField {
case _ if !checkCanWrite_? => Failure(noValueErrorMessage)
case Full(_) => set_!(in)
case _ if optional_? => set_!(in)
case (f: Failure) => set_!(f) // preserve failures set in
case _ => Failure(notOptionalErrorMessage)
}
dirty_?(true)
Expand All @@ -224,12 +225,15 @@ trait TypedField[ThisType] extends BaseField {

protected def setFilter: List[ValueType => ValueType] = Nil

/** OptionalTypedField and MandatoryTypedField implement this to do the appropriate lifting of Box[MyType] to ValueType */
protected def liftSetFilterToBox(in: Box[MyType]): Box[MyType]

/**
* A list of functions that transform the value before it is set. The transformations
* are also applied before the value is used in a query. Typical applications
* of this are trimming and/or toLowerCase-ing strings
*/
protected def setFilterBox: List[Box[MyType] => Box[MyType]] = ((in: Box[MyType]) => toBoxMyType(setFilter.foldLeft(toValueType(in))((prev, f) => f(prev)))) :: Nil
protected def setFilterBox: List[Box[MyType] => Box[MyType]] = liftSetFilterToBox _ :: Nil

def runFilters(in: Box[MyType], filter: List[Box[MyType] => Box[MyType]]): Box[MyType] = filter match {
case Nil => in
Expand Down Expand Up @@ -285,8 +289,8 @@ trait TypedField[ThisType] extends BaseField {

def valueBox: Box[MyType] = synchronized {
if (needsDefault) {
data = defaultValueBox
needsDefault = false
data = defaultValueBox
}

if (canRead_?) data
Expand All @@ -296,7 +300,7 @@ trait TypedField[ThisType] extends BaseField {
/** Clear the value of this field */
def clear: Unit = optional_? match {
case true => setBox(Empty)
case false => needsDefault = true
case false => setBox(defaultValueBox)
}
}

Expand Down Expand Up @@ -325,6 +329,7 @@ trait MandatoryTypedField[ThisType] extends TypedField[ThisType] with Product1[T
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)))

/**
* The default value of the field when a field has no value set and is optional, or a method that must return a value (e.g. value) is used
Expand Down Expand Up @@ -365,6 +370,8 @@ trait OptionalTypedField[ThisType] extends TypedField[ThisType] with Product1[Bo
def get: Option[MyType] = value
def is: Option[MyType] = value

protected def liftSetFilterToBox(in: Box[MyType]): Box[MyType] = setFilter.foldLeft(in)((prev, f) => f(prev))


def defaultValueBox: Box[MyType] = Empty

Expand Down
Expand Up @@ -112,7 +112,7 @@ trait MetaRecord[BaseRecord <: Record[BaseRecord]] {
val tArray = new ListBuffer[FieldHolder]

lifecycleCallbacks = for (v <- rootClass.getMethods.toList
if isLifecycle(v)) yield (v.getName, v)
if v.getName != "meta" && isLifecycle(v)) yield (v.getName, v)

introspect(this, rootClass.getMethods) {
case (v, mf) => tArray += FieldHolder(mf.name, v, mf)
Expand Down Expand Up @@ -246,6 +246,10 @@ trait MetaRecord[BaseRecord <: Record[BaseRecord]] {
}

protected def foreachCallback(inst: BaseRecord, f: LifecycleCallbacks => Any) {
inst match {
case (lc: LifecycleCallbacks) => f(lc)
case _ => {}
}
lifecycleCallbacks.foreach(m => f(m._2.invoke(inst).asInstanceOf[LifecycleCallbacks]))
}

Expand Down
Expand Up @@ -32,7 +32,7 @@ import S._
trait PostalCodeTypedField extends StringTypedField {
protected val country: CountryField[_]

override def setFilter = notNull _ :: toUpper _ :: trim _ :: super.setFilter
override def setFilter = toUpper _ :: trim _ :: super.setFilter

override def validations = validatePostalCode _ :: Nil

Expand Down

0 comments on commit 39d1df8

Please sign in to comment.