Сопоставление запроса Slick с проекцией по умолчанию после изменения значения столбца

При создании табличного запроса я хотел бы изменить свой оператор выбора, сопоставив табличный запрос по умолчанию. Однако я не могу найти способ сопоставить значение столбца и по-прежнему сопоставлять с моим классом case

case class MyRecord(id: Int, name: String, value: Int)

class MyTable(tag: Tag) extends Table[MyRecord](tag, "MYTABLE") {
    def id = column[Int]("id")
    def name = column[String]("name")
    def value = column[Int]("value")

    def * = (id, name, value) <> (MyRecord.tupled, MyRecord.unapply)
  }

lazy val tableQuery = TableQuery[MyTable]

Я хотел бы обрезать значение name с помощью этой функции:

def trimLeading0: (Rep[String]) => Rep[String] = SimpleExpression.unary[String, String] {
    (str, queryBuilder) =>
      import slick.util.MacroSupport._
      import queryBuilder._
      b"TRIM(LEADING 0 FROM $str)"
  }

Теперь я в недоумении, что делать здесь:

val trimmedTableQuery: Query[MyTable, MyRecord, Seq] = tableQuery.map(s => ???)

Я попытался сопоставить Rep, как я сделал бы с классом case:

val trimmedTableQuery = tableQuery.map(s => s.copy(name = trimLeading0(s.name)))

Это отказывается компилироваться с value copy is not a member of MyTable

Мой текущий обходной путь — использовать пользовательскую функцию вместо MyRecord.tupled для проекции по умолчанию:

def trimming(t: (Int, String, Int)) = MyRecord(t._1, t._2.dropWhile(_ == "0"), t._3)
def * = (id, name, value) <> (trimming, MyRecord.unapply)

В качестве альтернативы я мог бы сопоставить возвращаемый результат DBIOAction, возвращающего кортеж, с классом case, что гораздо менее элегантно:

val action = tableQuery.map{ s => (s.id, trimLeading0(s.name), s.value)}.result
val futureTuples: Future[Seq[(Int, String, Int)]] = db.run(action)
val records = futureTuples map (s => s.map(MyRecord.tupled))

Но как я могу сделать это внутри метода map при построении запроса? ИЛИ было бы лучше изменить описание столбца def name?


person kostja    schedule 07.02.2016    source источник


Ответы (1)


Вы не можете возиться с проекцией по умолчанию (например, def *) в MyTable, поскольку она должна быть симметричной. Он используется для запроса и вставки. Но вы можете создать trimmedTableQuery на основе специализации MyTable с переопределенной проекцией по умолчанию. Затем вы также можете иметь tableQuery на основе симметричной проекции по умолчанию. Вы получите сообщение об ошибке, если попытаетесь выполнить вставку на основе trimmedTableQuery (но вам не нужно этого делать, просто используйте tableQuery для вставки).

lazy val tableQuery = TableQuery[MyTable]
lazy val trimmedTableQuery = new TableQuery(new MyTable(_) {
  override def * = (id, trimLeading0(name), value) <> (MyRecord.tupled, MyRecord.unapply)
}) 
person Sue C    schedule 07.02.2016
comment
Еще один отличный ответ. И здесь я узнал две вещи :) Большое спасибо, Сью С. - person kostja; 08.02.2016