Это дано:
case class Money(value: BigDecimal, currency: Currency)
trait Currency
case class EUR ( ... ) extends Currency
... and so on
Я хочу смоделировать необязательный тип Money
, который содержит value
часть (BigDecimal) и Currency
часть (Enum через Enumeratum).
Чтобы отобразить это в БД, у меня есть два необязательных столбца:
private def moneyOptionalValue: Rep[Option[BigDecimal]] = column[Option[BigDecimal]]("money_value")
private def moneyOptionalCurrency: Rep[Option[Currency]] = column[Option[Currency]]("money_currency")
Желаемое состояние будет иметь это:
def money: Rep[Option[Money]] = ...
Я пробовал с этим подходом, как описано в
http://slick.lightbend.com/doc/3.1.0/userdefined.html#using-custom-record-types-in-queries
private implicit def myCurrencyType: BaseColumnType[Currency] = MappedColumnType.base[Currency, String](
c => c.shortName,
s => Currency.withNameUppercaseOnly(s.toUpperCase)
)
case class LiftedMoney(value: Rep[BigDecimal], currency: Rep[Currency])
case class LiftedMoneyOptional(a: Rep[Option[BigDecimal]], b: Rep[Option[Currency]])
case class MoneyOptional(a: Option[BigDecimal], b: Option[Currency])
// custom case class mapping
implicit object MoneyOptionalShape extends CaseClassShape(LiftedMoneyOptional.tupled, MoneyOptional.tupled)
implicit object MoneyShape extends CaseClassShape(LiftedMoney.tupled, Money.tupled)
implicit object MoneyToOptional
extends Isomorphism[Option[Money], MoneyOptional](
{
case Some(m) => MoneyOptional(Some(m.value), Some(m.currency))
case None => MoneyOptional(None, None)
}, {
case MoneyOptional(Some(v), Some(c)) => Some(Money(v, c))
case MoneyOptional(_, _) => None
}
)
private def moneyOptionalValue: Rep[Option[BigDecimal]] = column[Option[BigDecimal]]("money_value")
private def moneyOptionalCurrency: Rep[Option[Currency]] = column[Option[Currency]]("money_currency")
def moneyOptional: Rep[MoneyOptional] =
moneyOptionalValue.zip(moneyOptionalCurrency).mapTo[MoneyOptional]
def moneyOptional1: MappedProjection[MoneyOptional, (Option[BigDecimal], Option[Currency])] =
moneyOptionalValue.zip(moneyOptionalCurrency).mapTo[MoneyOptional]
// this compiles, if its not optional, but would break at runtime, when null values are in the columns:
private def moneyValue: Rep[BigDecimal] = column[BigDecimal]("money_value") // this column can be nullable!
private def moneyCurrency: Rep[Currency] = column[Currency]("money_currency") // // this column can be nullable!
def money: Rep[Money] = moneyValue.zip(moneyCurrency).value.mapTo[Money]
// I also tried this, but cannot compile my code with that for some reason
def optionMoney: Rep[Option[Money]] = RepOption[Money](money, money.toNode)
Любая помощь будет принята с благодарностью!