Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
无法为用户类型构造读取实例。Scala中Doobie的类型错误_Scala_Scala Cats_Cats Effect_Doobie - Fatal编程技术网

无法为用户类型构造读取实例。Scala中Doobie的类型错误

无法为用户类型构造读取实例。Scala中Doobie的类型错误,scala,scala-cats,cats-effect,doobie,Scala,Scala Cats,Cats Effect,Doobie,我正在尝试使用doobie、http4s和CAT从数据库返回用户记录。我已被类型系统阻止,该系统根据以下代码提供以下错误: 路由器: val httpRoutes = HttpRoutes.of[IO] { case GET -> Root / "second" / id => val intId : Integer = Integer.parseInt(id) //if i make thie ConnectionIO[Option[Unit]] i

我正在尝试使用doobie、http4s和CAT从数据库返回用户记录。我已被类型系统阻止,该系统根据以下代码提供以下错误:

路由器:

val httpRoutes = HttpRoutes.of[IO] {
    case GET -> Root / "second" / id =>
      val intId : Integer = Integer.parseInt(id)
      //if i make thie ConnectionIO[Option[Unit]] it compiles, but returns a cats Free object
      val userOption: ConnectionIO[Option[User]] = UserModel.findById(intId, transactor.transactor)
      Ok(s"userOption is instance of: ${userOption.getClass} object: ${userOption.toString}")
  }.orNotFound
型号:

case class User(
                 id: Read[Integer],
                 username: Read[String],
                 email: Read[String],
                 passwordHash: Read[String], //PasswordHash[SCrypt],
                 isActive: Read[Boolean],
                 dob: Read[Date]
               ) {
//  def verifyPassword(password: String) : VerificationStatus = SCrypt.checkpw[cats.Id](password, passwordHash)
}

object UserModel {
  def findById[User: Read](id: Integer, transactor: Transactor[ConnectionIO]): ConnectionIO[Option[User]] = findBy(fr"id = ${id.toString}", transactor)

  private def findBy[User: Read](by: Fragment, transactor: Transactor[ConnectionIO]): ConnectionIO[Option[User]] = {
    (sql"SELECT id, username, email, password_hash, is_active, dob FROM public.user WHERE " ++ by)
      .query[User]
      .option
      .transact(transactor)
  }
}

错误:

Error:(35, 70) Cannot find or construct a Read instance for type:
  core.model.User
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.
      val userOption: ConnectionIO[Option[User]] = UserModel.findById(intId, transactor.transactor)
如果我将行更改为ConnectionIO[Option[User]到ConnectionIO[Option[Unit]],它会编译并运行,但会从cats库中返回一个免费的(…)对象,我不知道如何解析它,我不明白为什么我不能返回我的case类

另请参见findBy和findById方法上的类型声明。在添加这些类型声明之前,存在一个编译错误,表示它找到了一个用户,但需要一个Read[User]。我尝试将相同的类型声明应用于路由器中的findById调用,但它给出了上面提供的相同错误


提前感谢您的帮助,请耐心等待我的无知。我从未遇到过比我更聪明的打字系统!

这里有很多东西需要解开

  • 您不需要在
    Read
    中的
    User
    中包装字段
  • 使用
    User
    参数化函数是不必要的,因为您知道要返回的类型
  • 大多数情况下,如果手动处理
    Read
    实例,则说明您做错了什么。构建
    Read
    实例仅在您读取的数据没有直接映射到您的类型时才有用
  • 事务处理程序
    是指通过调用连接,在事务中执行操作,并处理所述操作,将
    连接(JDBC连接上的某些操作)转换为其他monad(例如
    IO
    这样做没有多大意义,可能会导致死锁(因为在保持连接的同时,您最终会尝试调用连接)。只需在
    ConnectionIO
    中编写数据库逻辑,然后
    处理整个事情
  • Integer
    除了用于与Java的互操作之外,在Scala代码中没有使用,Doobie也没有它的
    Get
    /
    Put
    实例
  • 在你的路线中,你使用
    ConnectionIO[Option[User]]
    ,然后使用
    .toString
    。这并不是你想要的-它只是将你构建的动作变成一个无用的字符串,而没有实际计算它。要真正获得
    Option[User]
    ,你需要计算你的动作
  • 将所有这些放在一起,我们最终得到一段代码,如下所示:

    import java.util.Date
    导入cats.effect.IO
    导入doobie.{connectiono,Fragment,transactior}
    导入doobie.its_
    导入org.http4s.HttpRoutes
    导入org.http4s.dsl.io_
    导入org.http4s.syntax.kleisli_
    def httpRoutes(transactior:transactior[IO])=httpRoutes.of[IO]{
    case GET->Root/“second”/IntVar(intId)=>
    UserModel.findById(intId)
    .transact(交易人)
    .flatMap{userOption=>
    确定(s“userOption是:${userOption.getClass}对象:${userOption.toString}的实例”)
    }
    }奥诺特先生
    最终案例类用户(
    id:Int,
    用户名:String,
    电子邮件:String,
    passwordHash:String,
    isActive:布尔值,
    dob:日期
    )
    对象用户模型{
    def findById(id:Int):ConnectionIO[Option[User]]=findBy(fr“id=${id.toString}”)
    private def findBy(by:Fragment):ConnectionIO[Option[User]]=
    (sql“选择id、用户名、电子邮件、密码\u散列,处于活动状态,dob FROM public.user,其中“++by”)
    .query[用户]
    选项
    }
    

    userOption
    这里是
    Option[User]

    非常感谢@DmitryPolienko花时间解决我的问题!非常感谢您的专业知识!