我正在为scala中的用户构建以下API:
case class User(_id: BSONObjectId, username: String)
问题在于,当客户端发送请求以存储/创建新用户时,_id不存在。
一个可行的解决方案似乎是:
case class User(_id: Option[BSONObjectId], username: String)
然而,检查选项字段似乎有点烦人,不仅是为了插入用户,还为了其他CRUD操作。
我得到的一个建议是有两种类型:
case class User(name: String) ; type UserWithId = (Id, User)
或
case class User[A](id: A, name: String); type UserWithId = User[BSONObjectId]
type UserWithoutId = User[Unit]
我选择了后一种实施方式,因为它看似合适。 我创建了适当的Json格式来处理插入案例和其他操作:
object User {
lazy val userWithIdFormat: OFormat[UserWithId] = Json.format[UserWithId]
lazy val userWithoutIdFormat: OFormat[UserWithoutId] = Json.format[UserWithoutId]
}
然而,现在我在插入时面临一个问题,如何从UserWithoutId =>优雅地转换;生成Id后的UserwithId
所以下一步是创建这个方法:
case class User[A](_id: A, username: String)
{
def map[B](f: A => B): User[B] = ???
}
这是我需要实施的某种Monad吗? (现在只是学习类别理论)
我想最简单的方法就是添加"初始化/清空"状态,其中案例类必须始终具有Id,并且只有在它持久化时才会有用户名。
像val initalizedUser = User(BSONObjectId.generate(), "")
这里最好的方法是什么? 使用类型会明智地提高性能并使域更丰富,或者只是添加一个州将使其对未来的同事更加平易近人
地图的实现是什么,这是我应该提取的内容,并将我自己的Monad实现应用于所有未来的集合?
是否更好地找到功能库来解决这个问题呢?
答案 0 :(得分:0)
在我看来,使用复杂类型似乎没有必要:它不会提高性能,可能会让一些不熟悉这些概念的同事感到困惑。
我最喜欢的方法是有两个案例类,一个用于创建用户,另一个用于表示创建的实体:
case class CreateUser(username: String)
case class User(id: BSONObjectId, username: String)
这有几个好处:
CreateUser
案例类缩小尺寸是需要再写一个案例类,但在scala中它很容易
答案 1 :(得分:0)
如果您希望坚持使用单个User
案例类,则可以在将传入的JSON字符串解析为_id
后将add JsValue
字段转换为JSON对象,但只是在反序列化到User
之前:
case class User(_id: BSONObjectId, username: String)
implicit val userReads: Reads[User] = (
(JsPath \ "_id").read[String].map(BSONObjectID) and
(JsPath \ "username").read[String]
)(User.apply _)
val incomingJsonStr = """{"username": "John"}"""
val json = Json.parse(incomingJsonStr)
val jsonWithId = json.as[JsObject] + ("_id" -> JsString("12345"))
val user = jsonWithId.as[User]