Scala Doobie фрагмент с параметром универсального типа
Я пытаюсь абстрагироваться от вставки объектов разных типов в таблицы SQL аналогичной структуры. Вот что я пытаюсь сделать:
class TableAccess[A : Meta](table: String) {
def insert(key: String, a: A): ConnectionIO[Unit] = {
(fr"insert into " ++ Fragment.const(table) ++ fr" values ($key, $a);").update.run.map(_ => ())
}
}
Но я получаю эту ошибку компиляции:
[error] diverging implicit expansion for type doobie.util.param.Param[A]
[error] starting with method fromMeta in object Param
[error] (fr"insert into " ++ Fragment.const(table) ++ fr" values ($key, $a);").update.run.map(_ => ())
Все, что я могу найти в документации:
Doobie позволяет интерполировать значения любого типа (и их параметры) с экземпляром Meta, который включает в себя...
Но, похоже, этого недостаточно; какой тип / класс импорта / преобразования мне нужен?
2 ответа
Я отвечу на свой вопрос почти год спустя. Я никогда полностью не понимал, что происходит, и с тех пор обновился до более новой версии doobie, поэтому я не уверен, насколько это актуально. Но теперь в документации есть подсказка:
Примечание: важно понимать, что Meta существует только для того, чтобы вводить пары Get/Put в неявную область видимости. Вы никогда не должны требовать Meta как свидетельство в коде пользователя: вместо этого требуйте Get, Put или и то, и другое.
def foo[A: Meta](...) // don't do this def foo[A: Get: Put](...) // ok
И действительно, между этим изменением и новой версией теперь это прекрасно для меня компилируется:
class TableAccess[A: Get: Put](table: String) {
Один из способов, который я решил, это локализовать параметры типа (и их доказательства) в методе (на статическом / сопутствующем объекте), а затем он скомпилирован.
Что-то вроде
object MinimalGood {
def good[A: Meta, B: Meta](a: A, b: B): Update0 =
sql"""$a $b""".update
}
Когда компилятор разрешает неявно, он ищет один из определенного типа в текущей области видимости. Здесь кажется, что он нашел больше, чем один в своем поиске дерева.
Дело не в отсутствующем классе типов или импорте, скорее, их слишком много, и компилятор не может подобрать правильный. Попробуйте удалить некоторые неявные и посмотреть, как это работает или передать их явно.