我尝试使用Scalaz(7.2.18)来验证数据。我试过以下代码:
def hasDob: ValidationNel[AdtError, String] =
enc.dob.map(_.success).getOrElse(MissingAdmitDate(enc).failureNel)
def hasAdmitDt: ValidationNel[AdtError, Timestamp] =
enc.admitDT.map(_.success).getOrElse( MissingAdmitDate(enc).failureNel )
def hasTimezone: Validation[AdtError, DateTimeZone] =
fac.timezone.map(_.success).getOrElse( UndefinedTimezone(fac).failureNel )
(hasDob |@| hasAdmitDt |@| hasTimezone) { (dob, admitTime, facilityTz) => ... }
case class MissingDateOfBirth(enc: EncAdt)
extends AdtError { def logString = s"Txn ID: ${enc.transactionID} Missing DOB: ${enc.accountNumber}" }
case class MissingAdmitDate(enc: EncAdt)
extends AdtError { def logString = s"Txn ID: ${enc.transactionID} Missing Admit Date: ${enc.accountNumber}" }
更新开始
//enc
case class EncAdt(transactionID: Long,
dob: Option[String],
admitDT: Option[Timestamp],
...
)
//fac
case class Hl7Facility(
timezone: Option[DateTimeZone],
...
)
更新结束
但上面的代码抛出了编译时错误:
Type mismatch: Validation[Nothing, String], actual: scalaz.ValidationNel[MissingDateOfBirth, Nothing]
Type mismatch: Validation[Nothing, String], actual: scalaz.ValidationNel[MissingAdmitDate, Nothing]
Type mismatch: Validation[Nothing, String], actual: scalaz.ValidationNel[UndefinedTimezone, Nothing]
我在这做错了什么?针对上述问题的任何解决方案都非常值得注意
不幸的是NonEmptyList[A]
是不变的,所以你不能将NonEmptyList[MissingAdmitDate]
升级为NonEmptyList[AdtError]
。所以直接编译的代码应该如下所示:
def hasAdmitDt: ValidationNel[AdtError, Timestamp] = {
enc.admitDT.map(_.successNel[AdtError])
.getOrElse(MissingAdmitDate(enc).asInstanceOf[AdtError].failureNel)
}
这看起来不太好但是我没有看到让Scala编译器以这种形式在你需要它的方式推断泛型的方法。但是,您可以创建自己的自定义方法,而不是successNel
和failureNel
。
我的意思是这样的:
object AdtValidation {
type AdtValidation[A] = ValidationNel[AdtError, A]
implicit class AdtValidationSuccess[A](val value: A) extends AnyVal {
def successAdt: AdtValidation[A] = Validation.success[NonEmptyList[AdtError], A](value)
}
implicit class AdtValidationFailure(val value: AdtError) extends AnyVal {
def failureAdt[A]: AdtValidation[A] = Validation.failureNel[AdtError, A](value)
}
}
然后你可以做这样的事情:
import AdtValidation._
def hasAdmitDt: AdtValidation[Timestamp] = {
enc.admitDT.map(_.successAdt).getOrElse(MissingAdmitDate(enc).failureAdt)
}
但是,如果你还是这样,你也可以添加这样的东西
object AdtValidation {
type AdtValidation[A] = ValidationNel[AdtError, A]
implicit class AdtValidationOptionOps[A](val value: Option[A]) extends AnyVal {
def validateNonEmpty(emptyError: => AdtError): AdtValidation[A] = value.map(_.success[NonEmptyList[AdtError]]).getOrElse(Validation.failureNel[AdtError, A](emptyError))
}
}
这样你就可以做到
def hasAdmitDt: AdtValidation[Timestamp] = {
enc.admitDT.validateNonEmpty(MissingAdmitDate(enc))
}
附:看起来很可疑在hasDob
里面的代码示例中你用MissingAdmitDate
而不是像MissingDob
那样失败