1

This question is maybe more about Scala than Play, but here it is: I am trying to achieve an abstraction of a repository for common DB operations.

trait Entity {
  def id: UUID
}

trait Repository[T <: Entity] {

  val JSON_KEY_ID = "_id"

  def collection: JSONCollection

  def insert(t: T): Future[Either[String, T]] = {
    collection.insert(t).map(wr => if (wr.ok) Right(t) else Left(wr.getMessage()))
      .recover { case t => Left(t.getMessage) }
  }

   def update(t: T): Future[Either[String, T]] = {
    val selector = Json.obj(JSON_KEY_ID -> t.id.toString)
    collection.update(selector, t).map(wr => if (wr.ok) Right(t) else Left(wr.getMessage()))
      .recover { case t => Left(t.getMessage) }
  }
}

Then I have the objects I would like to use this with:

case class UserDAO(id: UUID) extends Entity[UserDAO]

object UserDAO {
  val JSON_KEY_ID = "_id"

  implicit val userDaoWrites: OWrites[UserDAO] = new OWrites[UserDAO] {
    def writes(user: UserDAO): JsObject = Json.obj(
      JSON_KEY_ID -> JsString(user.id.toString)
    )
  }

  implicit val userDaoReads: Reads[UserDAO] = (
    (__ \ JSON_KEY_ID).read[UUID]
    )(UserDAO.apply _)
}

and then I define its repository like this:

class UserRepository @Inject()(val reactiveMongoApi: ReactiveMongoApi) extends Repository[UserDAO] {
  val db = reactiveMongoApi.db
  override def collection: JSONCollection = db.collection[JSONCollection]("users")
}

The error I get is

No Json serializer as JsObject found for type T. Try to implement an implicit OWrites or OFormat for this type.
collection.insert(t).map(wr => if (wr.ok) Right(t) else Left(wr.getMessage()))
                 ^

I tried to provide implicit OWrites[T], or even implicit OWrites[_] to no avail. Maybe what I am trying to achieve is impossible. If not, how could I solve this? Thank you very much.

ticofab
  • 7,551
  • 13
  • 49
  • 90

1 Answers1

1

You should be able to just use a context bound.

trait Entity {
  def id: UUID
}

class Repository[T <: Entity : Writes] {
  ...
}

That will ensure that if there exists an implicit Writes[T] in scope, it will be available for your insert and update functions.

Ryan
  • 7,227
  • 5
  • 29
  • 40
  • Thanks it was all I needed, plus I had to make `Repository` a class because traits cannot have type parameters with context bounds. – ticofab Jul 23 '15 at 10:18