Quill Cassandra, кодек не найден, ошибка для определенного пользователем типа данных

Я использую гусиное перо в своем проекте "play-scala" в качестве драйвера кассандры. У меня есть таблица со следующей структурой -

CREATE TABLE user_data (
    id int,
    name string,
    addresses list<frozen<dwelltimebd>>
    PRIMARY KEY ((id, name))
)

где ADDRESS является определяемым пользователем типом данных, как упомянуто здесь -

CREATE TYPE ADDRESS (
    city string,
    country string
);

Код, написанный для доступа к данным из этой таблицы, выглядит примерно так:

object UserTable {
  case class addresses(city: String, country: String)
  case class userData ( id :Int, name :String, addresses : Seq[addresses])

    lazy val ctx = new CassandraAsyncContext[SnakeCase]("user")

    import ctx._

implicit val seqAddressDecoder: Decoder[Seq[addresses]] =
    decoder[Seq[addresses]] { (row: Row) =>
      (index) =>
      row.getList(index, classOf[addresses]).asScala
    }

  implicit val seqAddressesEncoder: Encoder[Seq[addresses]] =
    encoder[Seq[addresses]] { (row: BoundStatement) =>(idx, lista) =>
      row.setList(idx, lista.toList.asJava, classOf[addresses])
    }


    def getUserData(id: Int, name: String) =  {
        val getAllDetail = quote {
          query[userData].filter(p => p.id == lift(id) && p.name == lift(name))
        }
        val result: List[userData] = Await.result(ctx.run(
          getAllDetail
        ), Duration.Inf)
        result
    }
}

При запуске вышеуказанного кода получена следующая ошибка:

play.api.UnexpectedException: Unexpected exception[CodecNotFoundException: Codec not found for requested operation: [frozen<user.addresses> <-> models.databaseModels.UserTable$addresses]]
        at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:289)
        at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
        at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
        at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
        at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
        at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:100)
        at play.core.server.netty.PlayRequestHandler$$anonfun$2$$anonfun$apply$1.applyOrElse(PlayRequestHandler.scala:99)
        at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:346)
        at scala.concurrent.Future$$anonfun$recoverWith$1.apply(Future.scala:345)
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: com.datastax.driver.core.exceptions.CodecNotFoundException: Codec not found for requested operation: [frozen<user.addresses> <-> models.databaseModels.UserTable$addresses]
        at com.datastax.driver.core.CodecRegistry.notFound(CodecRegistry.java:679)
        at com.datastax.driver.core.CodecRegistry.createCodec(CodecRegistry.java:526)
        at com.datastax.driver.core.CodecRegistry.findCodec(CodecRegistry.java:506)
        at com.datastax.driver.core.CodecRegistry.maybeCreateCodec(CodecRegistry.java:558)
        at com.datastax.driver.core.CodecRegistry.createCodec(CodecRegistry.java:524)
        at com.datastax.driver.core.CodecRegistry.findCodec(CodecRegistry.java:506)
        at com.datastax.driver.core.CodecRegistry.access$200(CodecRegistry.java:140)
        at com.datastax.driver.core.CodecRegistry$TypeCodecCacheLoader.load(CodecRegistry.java:211)
        at com.datastax.driver.core.CodecRegistry$TypeCodecCacheLoader.load(CodecRegistry.java:208)
        at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3542)

Не удалось решить проблему. Несколько советов, которые я получил,

I need to first create Java TypeCodec and register it with the cluster. Then also need to implement row-codec for quill just to make it compile. 

из этого поста

Не могу понять, как это сделать, любая помощь в этом плане будет полезна.

1 ответ

Решение

Это сработало для меня:

Из Datastax Docs:

По умолчанию драйвер сопоставляет значения пользовательских типов с экземплярами UDTValue.

Для декодера попробуйте что-то вроде:

  import scala.collection.JavaConverters._

  implicit val addressListDecoder: Decoder[List[Address]] = decoder(
    (index, row) =>
      row.getList(index, classOf[UDTValue]).asScala.toList.map { a =>
        Address(a.getString("city"), a.getString("country"))
      }
   )

Это не сработало: (но, может быть, я не очень старался)

Теоретически вы также можете определить собственный кодек, расширить Quill's CassandraAsyncContext (или любой из доступных контекстов), чтобы иметь возможность получить Cluster объект, а затем зарегистрировать пользовательский кодек это:

def registerCodecs(cluster: Cluster): Unit = {
    val codecRegistry = cluster.getConfiguration.getCodecRegistry
    codecRegistry.register(new LocalDateTimeCodec) //just for example
}

Вы можете составить кодек из существующих "базовых" кодеков.

Datastax Docs на пользовательских кодеках

Другие вопросы по тегам