tminglei / slick-pg

Slick extensions for PostgreSQL
BSD 2-Clause "Simplified" License
838 stars 180 forks source link

How do I support serializing of Seq[T] via SimpleArrayJdbcType? #246

Open unoexperto opened 8 years ago

unoexperto commented 8 years ago

How do I support serializing of Seq[T] via SimpleArrayJdbcType? For some reason I get compilation error when I have projection to type Seq[T]. Strangely I don't see any references to List[T] in PgArraySupport.

How can I fix it ?

Compilation error I get when switching from List[T] to Seq[T] is something line this

Error:(93, 119) 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. Or you use an unsupported type in a Query (e.g. scala List).
  Required level: slick.lifted.FlatShapeLevel
     Source type: (slick.lifted.Rep[org.bson.types.ObjectId], slick.lifted.Rep[String], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[String]], slick.lifted.Rep[Option[org.bson.types.ObjectId]], slick.lifted.Rep[Option[Seq[co.zzzz.medstream.server.models.db.ElectronicAddress]]], slick.lifted.Rep[Option[Seq[co.zzzz.medstream.server.models.db.ElectronicAddress]]], slick.lifted.Rep[Option[scala.collection.immutable.Map[String,Seq[String]]]], slick.lifted.Rep[Option[Seq[String]]], slick.lifted.Rep[Option[Seq[String]]])
   Unpacked type: (org.bson.types.ObjectId, String, Option[String], Option[String], Option[org.bson.types.ObjectId], Option[Seq[co.zzzz.medstream.server.models.db.ElectronicAddress]], Option[Seq[co.zzzz.medstream.server.models.db.ElectronicAddress]], Option[scala.collection.immutable.Map[String,Seq[String]]], Option[Seq[String]], Option[List[String]])
     Packed type: Any
  def * = ProvenShape.proveShapeOf((id, name, email, pwdHash, token, emails, phones, deviceIds, awsSNSEnpoints, test) <> (fromTuple, toTuple))(MappedProjection.mappedProjectionShape)
                                                                                                                      ^
tminglei commented 8 years ago

If T is a complex type, you should turn to use AdvancedArrayJdbcType. To support other seq type, you should code it like new SimpleArrayJdbcType[Long]("int8").to(_.toBuffer).

Array support related test cases are here, pls check it.

unoexperto commented 8 years ago

The problem in my case is that I can't use Seq[String] but List[String] works. Could you please show example of implicit that would support Seq[String] ?

I mean nothing in AdvancedArrayJdbcType indicates type of container class. Generic type only specifies type of values in the container.

tminglei commented 8 years ago

Ok, here's built-in supported arrays:

  implicit val simpleUUIDListTypeMapper = new SimpleArrayJdbcType[UUID]("uuid").to(_.toList)
  implicit val simpleStrListTypeMapper = new SimpleArrayJdbcType[String]("text").to(_.toList)
  implicit val simpleLongListTypeMapper = new SimpleArrayJdbcType[Long]("int8").to(_.toList)
  implicit val simpleIntListTypeMapper = new SimpleArrayJdbcType[Int]("int4").to(_.toList)
  implicit val simpleShortListTypeMapper = new SimpleArrayJdbcType[Short]("int2").to(_.toList)
  implicit val simpleFloatListTypeMapper = new SimpleArrayJdbcType[Float]("float4").to(_.toList)
  implicit val simpleDoubleListTypeMapper = new SimpleArrayJdbcType[Double]("float8").to(_.toList)
  implicit val simpleBoolListTypeMapper = new SimpleArrayJdbcType[Boolean]("bool").to(_.toList)
  implicit val simpleDateListTypeMapper = new SimpleArrayJdbcType[Date]("date").to(_.toList)
  implicit val simpleTimeListTypeMapper = new SimpleArrayJdbcType[Time]("time").to(_.toList)
  implicit val simpleTsListTypeMapper = new SimpleArrayJdbcType[Timestamp]("timestamp").to(_.toList)

To support Seq[String], you can use codes in your customized postgres driver as follow:

  implicit val simpleStrSeqTypeMapper = new SimpleArrayJdbcType[String]("text")
unoexperto commented 8 years ago

Thank you for helping me out. Unfortunately this implicit is not being selected. I'm using JSONB type actively because I'm moving away from Mongo. More details here: http://stackoverflow.com/q/34366478/226895

Thus I use your spray-json support. In order to automagically convert my case classes to JSONB fields I added following implicit to my MyPostgresDriver

implicit def JsonColumnType[T: ClassTag](implicit reader: RootJsonReader[T], writer: RootJsonWriter[T]) =
  MappedColumnType.base[T, JsValue]({ obj => writer.write(obj) }, { json => reader.read(json) })

it works nicely but now it creates JSONB for Seq[String] instead of creating TEXT[] column :) But for some reason List[String] is created as TEXT[].

tminglei commented 8 years ago

Well, I don't very clear your problem now.