Doobie更新和插入案例类语法

时间:2019-09-09 18:14:21

标签: scala doobie

Doobie可以使用案例类select *来方便且正确地传递参数,但是我看不出如何使用updateinsert以类似的方式工作。

例如,给定这样的案例类:

case class Course(
  sku: String,
  title: String,
  id: Id,
  price: Int,
  instructorid: Id,
  groupid: Id,
  shortdescription: String = "",
  transcript: String = "",
  project_home: String = "",
  repository: String = "",
  category: String = "",
  image: String = "",
  privacy: String = "",
  language: String = "",
  keywords: String = "",
  goals: String = "",
  instructionallevel: String = "",
  audience: String = "",
  studenttasks: String =  "",
  sections: String = "",
  active: Boolean = true,
  video: String = "",
  paypal_button_id: String = "",
  prerequisite_ids: String = ""
)

我可以select条记录。之所以可以使用这种漂亮的语法,是因为Doobie遍历Course case类属性,并通过将它们的名称与courses数据库记录字段进行匹配来为它们分配值:

    def find(id: Id): Option[Course] =
      sql"select * from courses where id = $id"
        .query[Course]
        .option
        .transact(SQLSupport.xa)
        .unsafeRunSync

然而,insert要求手动列出所有案例类属性,并与值匹配,这很可怕且容易出错:

    /** @return saved Course with new Id */
    def save(course: Course): Course = {
      val insert: doobie.ConnectionIO[Course] = sql"""insert into courses (
          sku,
          title,
          price,
          instructorid,
          groupid,
          shortdescription,
          transcript,
          project_home,
          repository,
          category,
          image,
          privacy,
          language,
          keywords,
          goals,
          instructionallevel,
          audience,
          studenttasks,
          sections,
          active,
          video,
          paypal_button_id,
          prerequisite_ids
        ) values (
          ${ course.sku },
          ${ course.title },
          ${ course.price },
          ${ course.instructorid },
          ${ course.groupid },
          ${ course.shortdescription },
          ${ course.transcript },
          ${ course.project_home },
          ${ course.repository },
          ${ course.category },
          ${ course.image },
          ${ course.privacy },
          ${ course.language },
          ${ course.keywords },
          ${ course.goals },
          ${ course.instructionallevel },
          ${ course.audience },
          ${ course.studenttasks },
          ${ course.sections },
          ${ course.active },
          ${ course.video },
          ${ course.paypal_button_id },
          ${ course.prerequisite_ids }
        )"""
        .update
        .withUniqueGeneratedKeys("id")
      val newCourse: Course = insert.transact(SQLSupport.xa).unsafeRunSync
      newCourse
    }

update同样令人恐惧:

    /** @return updated Course, which should be identical to the given course */
    def update(course: Course): Course = {
      val update: doobie.ConnectionIO[Course] = sql"""update courses set
          sku = ${ course.sku },
          title = ${ course.title },
          id = ${ course.id },
          price = ${ course.price },
          instructorid = ${ course.instructorid },
          groupid = ${ course.groupid },
          shortdescription = ${ course.shortdescription },
          transcript = ${ course.transcript },
          project_home = ${ course.project_home },
          repository = ${ course.repository },
          category = ${ course.category },
          image = ${ course.image },
          privacy = ${ course.privacy },
          language = ${ course.language },
          keywords = ${ course.keywords },
          goals = ${ course.goals },
          instructionallevel = ${ course.instructionallevel },
          audience = ${ course.audience },
          studenttasks = ${ course.studenttasks },
          sections = ${ course.sections },
          active = ${ course.active },
          video = ${ course.video },
          paypal_button_id = ${ course.paypal_button_id },
          prerequisite_ids = ${ course.prerequisite_ids }
        where id = ${ course.id }"""
        .update
        .withUniqueGeneratedKeys("id")
      val modifiedCourse: Course = update.transact(SQLSupport.xa).unsafeRunSync
      modifiedCourse
    }

有更好的方法吗?

3 个答案:

答案 0 :(得分:0)

给出一些模型

Foo(id: Int, b: String, c: String)
val foo = Foo(1, "bar", "qux")

我们可以像这样使用Update[Foo]插入其实例

Update[Foo]("INSERT INTO suppliers VALUES (?, ?, ?)", None)
  .withUniqueGeneratedKeys("id")(foo)

在插入时,我们不再必须显式引用字段名称,从而减少了混淆列名称的可能性。

这是受官方仓库中example的启发

val insertSupplier: Update[Supplier] =
  Update[Supplier]("INSERT INTO suppliers VALUES (?, ?, ?, ?, ?, ?)", None)

答案 1 :(得分:0)

如果您使用的是Postgres,则可以看看Rob Norris的另一个库-skunk

它允许您编写自定义编解码器:

  case class City(id: Int, name: String, code: String, district: String, pop: Int)

  val city: Codec[City] =
    (int4 ~ varchar ~ bpchar(3) ~ varchar ~ int4).gimap[City]

  val insertCity: Command[City] =
    sql"""
         INSERT INTO city
         VALUES ($city)
       """.command

Check examples

答案 2 :(得分:0)

Doobie 与 getquill.io 的 Quill 集成,允许您使用案例类对 sql DML 进行建模 https://tpolecat.github.io/doobie/docs/17-Quill.html