14

While using circe in slick to get data in json,I could fetch data having no date(Timestamp/DateTime) fields in Entities. But when I use Timestamp fields in Entities, the error is thrown:

[error] /var/www/html/scala-api/src/main/scala/oc/api/http/routes/TestApi.scala:40: could not find implicit value for parameter encoder: io.circe.Encoder[Seq[oc.api.models.UserEntity]]
[error]             auth => complete(userDao.getAll().map(_.asJson))

Here is the code, I used for Slick Entities and using CIRCE for json encoding.

BaseTable:

abstract class BaseTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def createdAt = column[Timestamp]("created_at")
  def updatedAt = column[Timestamp]("updated_at")
  def deletedAt = column[Timestamp]("deleted_at")
}

BaseEntity:

trait BaseEntity {
  val id : Long
  def isValid : Boolean = true
}

UserEntity: createdAt generates encoder error

case class UserEntity(id: Long, email: String, password: String, createdAt: Timestamp) extends BaseEntity

UserEntity: This works perfectly

case class UserEntity(id: Long, email: String, password: String) extends BaseEntity

UserTable(Slick):

object UserTables {

  class UserTable(tag : Tag) extends BaseTable[UserEntity](tag, "users") {
    def name = column[String]("name")
    def password = column[String]("password")
    def * = (id, name, password) <> (UserEntity.tupled, UserEntity.unapply)
  }

  implicit val accountsTableQ : TableQuery[UserTable] = TableQuery[UserTable]
}

Am I missing something in the code? Any help would be highly appreciated.

Sujit Baniya
  • 775
  • 5
  • 22

1 Answers1

13

You should use a custom encoder and decoder to your code, something like that :

  implicit val TimestampFormat : Encoder[Timestamp] with Decoder[Timestamp] = new Encoder[Timestamp] with Decoder[Timestamp] {
    override def apply(a: Timestamp): Json = Encoder.encodeLong.apply(a.getTime)

    override def apply(c: HCursor): Result[Timestamp] = Decoder.decodeLong.map(s => new Timestamp(s)).apply(c)
  }

Put this val in whatever code needs to encode/decode timestamps. For example, you can put it in an object, and import the object where needed.

C4stor
  • 7,629
  • 4
  • 25
  • 43
  • I tried to add n Table as object UserTables { class UserTable(tag : Tag) extends BaseTable[UserEntity](tag, "users") { def updated_at = column[Option[String]]("updated_at") def * = (..., updated_at) <> (...) } implicit val TimestampFormat : Encoder[Timestamp] with Decoder[Timestamp] = new Encoder[Timestamp] with Decoder[Timestamp] { override def apply(a: Timestamp): Json = Encoder.encodeLong.apply(a.getTime) override def apply(c: HCursor): Result[Timestamp] = Decoder.decodeLong.map(s => new Timestamp(s)).apply(c) } } But got encoder error as before – Sujit Baniya Jan 05 '17 at 18:34
  • You have to put the val in scope of where the encoding/decoding is actually done (so, probably somewhere near http related code ?), not in the sql classes ! – C4stor Jan 06 '17 at 09:21
  • While decoding, how can I use DateTimeFormat i.e. Y-m-d H:i:s to decode instead of decodeLong – Sujit Baniya Jan 06 '17 at 10:09
  • 1
    You can use decodeString.map(s => function(s)) where function should be a function to transform the String you have in Timestamp (using DateTimeFormat in the process I suppose). – C4stor Jan 06 '17 at 10:16
  • Cheers! decodeString.map( s => new Timestamp(timestampFormatter.parse(s).getTime)).apply(c) worked – Sujit Baniya Jan 06 '17 at 11:10