Mahesh Chand
Mahesh Chand

Reputation: 3250

How to map Map[String, String] to (String, String) in slick 3.2.0

I am trying to update the hstore field in my Postgres table. It throws an error

Error:(468, 13) No matching Shape found.
Slick does not know how to map the given types.
Possible causes: T in Table[T] does not match your * projection,
 you use an unsupported type in a Query (e.g. scala List),
 or you forgot to import a driver api into scope.
  Required level: slick.lifted.FlatShapeLevel
     Source type: slick.lifted.Rep[Option[scala.collection.immutable.Map[String,String]]]
   Unpacked type: T
     Packed type: G
        .map(_.additionalInfo).update(Some(info.additionalInfo))

I have added hstore implicit as well

trait MyPostgresDriver extends ExPostgresProfile with PgHStoreSupport {

  override val api = MyAPI

  // Add back `capabilities.insertOrUpdate` to enable native `upsert` support; for postgres 9.5+
  override protected def computeCapabilities: Set[Capability] =
    super.computeCapabilities + JdbcProfile.capabilities.insertOrUpdate


  object MyAPI extends API with HStoreImplicits

}

After browsing I found to create a custom mapping for such scenarios.

implicit val stringMapper = MappedColumnType.base[Map[String, String], (String, String)](
    list => (list.keys.toString(), list.values.toString()),
    string => Map(string._1 -> string._2)
  )

But above custom mapping is not correct. I found this blog But it Implicits is not there in version 3.x

Any help will be appreciated.

Upvotes: 1

Views: 687

Answers (2)

Harmeet Singh Taara
Harmeet Singh Taara

Reputation: 6611

As per the error, slick implicit is missing which help you to use Map[String, String] as PgHStore. You need to add (implicit a: JdbcType[Map[String, String]]) in the scope of your code block. which is I guess provided by HStoreImplicits Or PgHStoreSupport.

Upvotes: 1

Dmytro Mitin
Dmytro Mitin

Reputation: 51658

Try

import com.github.tminglei.slickpg._

trait MyPostgresProfile extends ExPostgresProfile
  with PgArraySupport
  with PgHStoreSupport {

  override val api = MyAPI

  object MyAPI extends API 
    with ArrayImplicits
    with HStoreImplicits {
    implicit val strListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList)
  }
}

object MyPostgresProfile extends MyPostgresProfile

import MyPostgresProfile.api._

case class Student(
                    id: Int,
                    name: String,
                    hobbies: List[String],
                    marks: Map[String, String])

class StudentTable(tag: Tag) extends Table[Student](tag, "student") {
  def id = column[Int]("id", O.PrimaryKey)
  def name = column[String]("name")
  def hobbies = column[List[String]]("hobbies", O.Default(Nil))
  def marks = column[Map[String, String]]("marks")

  def * = (id, name, hobbies, marks) <> (Student.tupled, Student.unapply)
}

lazy val studentQuery: TableQuery[StudentTable] = TableQuery[StudentTable]
val db = Database.forURL("jdbc:postgresql://localhost:5432/student", "root", "root",
  null, "org.postgresql.Driver")
val student = Student(1, "Ayush", List("Study", "Coding"), Map("Scala" -> "90", "Java" -> "80", "PHP" -> "0"))
db.run {
  studentQuery += student
}

build.sbt

lazy val slickV = "3.3.2"
//lazy val slickV = "3.2.0"
libraryDependencies ++= Seq(
  "com.typesafe.slick" %% "slick" % slickV,
  "org.slf4j" % "slf4j-nop" % "1.7.28",
  "com.typesafe.slick" %% "slick-hikaricp" % slickV,
  "com.github.tminglei" %% "slick-pg" % "0.18.0"
)

https://github.com/tminglei/slick-pg

Upvotes: 0

Related Questions