Finally I was able to manage things correctly. Here below is how to insert an user and handle possible exceptions with ReactiveMongo:
val idPath = __ \ 'id
val oidPath = __ \ '_id
/**
* Generates a BSON object id.
*/
protected val generateId = __.json.update(
(oidPath \ '$oid).json.put(JsString(BSONObjectID.generate.stringify))
)
/**
* Converts the current JSON into an internal representation to be used
* to interact with Mongo.
*/
protected val toInternal = (__.json.update((oidPath \ '$oid).json.copyFrom(idPath.json.pick))
andThen idPath.json.prune
)
/**
* Converts the current JSON into an external representation to be used
* to interact with the rest of the world.
*/
protected val toExternal = (__.json.update(idPath.json.copyFrom((oidPath \ '$oid).json.pick))
andThen oidPath.json.prune
)
...
def insert(user: User): Future[User] = {
val json = user.asJson.transform(idPath.json.prune andThen generateId).get
collection.insert(json).transform(
success => User(json.transform(toExternal).get).get,
failure => DaoServiceException(failure.getMessage)
)
}
The user
parameter is a POJO-like instance with an internal representation in JSON – User
instances always contain valid JSON since it is generated and validated in the constructor and I no longer need to check whether user.asJson.transform
fails.
The first transform
ensures there is no id
already in the user
and then generates a brand new Mongo ObjectID. Then, the new object is inserted in the database, and finally the result converted back to the external representation (i.e. _id
=> id
). In case of failure, I just create a custom exception with the current error message. I hope that helps.