如何使用Scala Slick表达Postgres数组

时间:2017-10-18 10:32:36

标签: scala slick

我在Postgres 9.5中有一个表格,结构如下:

my_table (id Integer, images_ranks image_rank[]);

其中image_rank是:

CREATE TYPE image_rank AS (image_url text, thumbnail_rank integer);

我正在努力在Slick(3.1)中表达类似的东西:

case class MyTable (id: Int, imagesRanks: Seq[Option[ImageRank]])

implicit val propertyMyTableResult = GetResult(r => MyTable(r.<<, r.<<)
implicit val propertyImageRankResult = GetResult[Option[ImageRank]] { r => ImageRank(r.<<, r.<<)) }

这样做的正确方法是什么?

更新

此包装(在n1r3的回答之后)暂时阻止了我:

implicit val ImageRankWrapper: JdbcType[List[ImageRank]] = new SimpleArrayJdbcType[ImageRank]("image_rank[]").to(_.toList)

更新2

仍然不确定是什么问题。我按照你的建议添加了代码,但它仍然抱怨:

could not find implicit value for parameter rconv: slick.jdbc.GetResult[database.rows.MyTable]

所以我补充说:

implicit val myTableResult = GetResult[MyTable](r => MyTable(r.<<, r.<<))

返回:

diverging implicit expansion for type slick.jdbc.GetResult[T1]
starting with object GetStringOption in object GetResult
         r.<<, r.<<))

这是我的配置:

import com.github.tminglei.slickpg._
import database.rows.ImageRank

trait CustomPostgresProfile extends ExPostgresProfile
  with PgArraySupport
  with PgPlayJsonSupport
  with PgPostGISSupport
  with PgEnumSupport
  with PgDate2Support {

  // Use PostgreSQL JSONB support
  def pgjson = "jsonb"

  override val api = MyAPI
  object MyAPI extends API
    with ArrayImplicits
    with JsonImplicits
    with PostGISImplicits
    with DateTimeImplicits {
    implicit val imageRankListTypeMapper =
      new AdvancedArrayJdbcType[ImageRank]("image_rank",
        str => utils.SimpleArrayUtils.fromString[ImageRank](s => {
          val ImageRankRegex = "ImageRank\\((.*),(\\d+)\\)".r
          s match {
            case ImageRankRegex(imageUrl, thumbnailRank) =>
              ImageRank(imageUrl, thumbnailRank.toInt)
            case _ =>
              println(s"$s is not ImageRank")
              ImageRank("", 0)
          }
        })(str).orNull,
        imageRanks => utils.SimpleArrayUtils.mkString[ImageRank](_.toString)(imageRanks)
      ).to(_.toList)
  }
}

object CustomPostgresProfile extends CustomPostgresProfile


abstract class DatabaseProfile(val provider: DatabaseConfigProvider) {
  val config = provider.get[CustomPostgresProfile]
  val profile = config.profile
  val db = config.db
}

trait PropertyDataDatabase {
    self: DatabaseProfile =>
    .....

2 个答案:

答案 0 :(得分:2)

最好的方法是使用这个优秀的图书馆:https://github.com/tminglei/slick-pg

如果您希望自己实现它,请查看源代码(https://github.com/tminglei/slick-pg/tree/master/core/src/main/scala/com/github/tminglei/slickpg/array)并从中获取您想要的内容。

答案 1 :(得分:1)

什么是protocol Language { var hello: String { get } } struct EN: Language {...} struct CN: Language {...} var stringObj: Language? ... ?写下它的定义。我认为这是一个案例类

ImageRank

我想除了case class ImageRank(imageUrl: String, thumbnailRank: Int) mapper之外的特定数组

slick-pg

您应该为implicit val imageRankListTypeMapper = new AdvancedArrayJdbcType[ImageRank]("image_rank", str => utils.SimpleArrayUtils.fromString[ImageRank](s => { val ImageRankRegex = "ImageRank\\((.*),(\\d+)\\)".r s match { case ImageRankRegex(imageUrl, thumbnailRank) => ImageRank(imageUrl, thumbnailRank.toInt) case _ => println(s"$s is not ImageRank") ImageRank("", 0) } })(str).orNull, imageRanks => utils.SimpleArrayUtils.mkString[ImageRank](_.toString)(imageRanks) ).to(_.toList)

定义slick映射器
ImageRank

文档是here

case class LiftedImageRank(imageUrl: Rep[String], thumbnailRank: Rep[Int]) implicit object ImageRankShape extends CaseClassShape(LiftedImageRank.tupled, ImageRank.tupled) SimpleArrayJdbcType参数含义为SQL base type,所以我猜String无效。

此外,"image_rank[]"适用于基类型为SimpleArrayJdbcType为标准且T定义为ElemWitness[T]的数组。由于没有slick-pg,您应该使用ElemWitness[ImageRank]