Вы можете вкладывать сопоставления при построении проекции с помощью Slick. То есть вы можете определить *
для включения других вызовов mapTo
(для класса case) или <>
(для настраиваемого сопоставления).
Используя пример с Int
вместо LocalDate
, мы можем начать с класса case, с которым хотим работать:
case class Row(
name : String,
range : Option[(Int, Int)],
id : Long = 0L
)
Обратите внимание, что поле range
имеет одно значение (кортеж), но в базе данных мы можем представить это как два столбца называемые start
и end
:
class RowTable(tag: Tag) extends Table[Row](tag, "row") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def start = column[Option[Int]]("start")
def end = column[Option[Int]]("end")
def range = (start, end) <> (into_range, from_range)
def * = (name, range, id).mapTo[Row]
}
Проекция *
в Row
построена из другого сопоставления, которое я назвал range
.
Отображение range
находится в двух столбцах start
и end
. Для <>
мы предоставляем две функции: одна функция преобразует пару параметров в нужный нам тип (вариант кортежа); другая функция идет другим путем. Функции отражают стандартные библиотечные функции tupled
и unappy
(unapply
- это экстрактор ).
Мы можем писать эти функции, как хотим, и я написал их вне с сопоставлением с образцом:
def into_range(pair: (Option[Int], Option[Int])): Option[(Int, Int)] =
pair match {
case (Some(x), Some(y)) => Some((x, y))
case _ => None
}
def from_range(r: Option[(Int, Int)]): Option[(Option[Int], Option[Int])] =
r match {
case Some((x, y)) => Some((Some(x), Some(y)))
case _ => Some((None, None))
}
Таким образом, ваш dateRange
эквивалентен сопоставлению range
в этом примере, но вместо того, чтобы вызывать его напрямую, мы включаем его в нашу проекцию по умолчанию, *
.