I'm using doobie to query some data and everything works fine, like this:
case class Usuario(var documento: String, var nombre: String, var contrasena: String)
def getUsuario(doc: String) =
sql"""SELECT documento, nombre, contrasena FROM "Usuario" WHERE "documento" = $doc"""
.query[Usuario]
.option
.transact(xa)
.unsafeRunSync()
But if I declare a function with type restriction like this:
def getOption[T](f: Fragment): Option[T] = {
f.query[T]
.option
.transact(xa)
.unsafeRunSync()
}
I got these errors:
Error:(42, 12) Cannot find or construct a Read instance for type:
T
This can happen for a few reasons, but the most common case is that a data
member somewhere within this type doesn't have a Get instance in scope. Here are
some debugging hints:
- For Option types, ensure that a Read instance is in scope for the non-Option
version.
- For types you expect to map to a single column ensure that a Get instance is
in scope.
- For case classes, HLists, and shapeless records ensure that each element
has a Read instance in scope.
- Lather, rinse, repeat, recursively until you find the problematic bit.
You can check that an instance exists for Read in the REPL or in your code:
scala> Read[Foo]
and similarly with Get:
scala> Get[Foo]
And find the missing instance and construct it as needed. Refer to Chapter 12
of the book of doobie for more information.
f.query[T].option.transact(xa).unsafeRunSync()
Error:(42, 12) not enough arguments for method query: (implicit evidence$1: doobie.util.Read[T], implicit h: doobie.LogHandler)doobie.Query0[T].
Unspecified value parameter evidence$1.
f.query[T].option.transact(xa).unsafeRunSync()
Does anyone know how to make what I want? I think it's something with implicits but I don't know how to fix it.
In order for doobie to be able to transform the result of SQL query to your case class, it needs an instance of Read
typeclass in scope.
For example for Usuario
it needs instance of Read[Usuario]
. Fortunately, doobie is able to derive typeclasses for types from typeclasses it already knows, like String
, so in most cases, we don't need to create these explicitly.
In your case, you want to create method getOption
which has type parameter T
, which means, that compiler doesn't know for which typeclass of which type to look for.
You can fix it very easily, by just adding context-bound for Read
to your type (like T: Read
or by adding implicit parameter). It means that your method will pass "request" to resolve typeclass later in compile-time when the concrete type of T would be already known.
So your fixed method will be:
def getOption[T: Read](f: Fragment): Option[T] = {
f.query[T]
.option
.transact(xa)
.unsafeRunSync()
or with implicit parameter:
def getOption[T](f: Fragment)(implicit read: Read[T]): Option[T] = {
f.query[T]
.option
.transact(xa)
.unsafeRunSync()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With