我正在 ReactiveMongo 之上开发一个 ORM 风格的库。目前我已经尝试实现嵌套文档表示 - 但是我一直坚持使用 Scala 对我的班级进行类型推断。我对 Scala 很陌生,所以欢迎大家提供帮助。
这是我的尝试:
trait MongoDocument[T <: MongoDocument[T]] {
self: T =>
val db: DefaultDB
val collection: String
var fields: List[MongoField[T,_]] = List.empty
def apply(doc: TraversableBSONDocument): T = { // loads the content of supplied document
fields.foreach { field =>
doc.get(field.field).foreach(field.load(_))
}
this
}
}
trait MongoMetaDocument[T <: MongoDocument[T]] extends MongoDocument[T] {
self: T =>
type DocType = T
protected val clazz = this.getClass.getSuperclass
def create: T = clazz.newInstance().asInstanceOf[T]
def find(id: String): Future[Option[T]] = {
db(collection).find(BSONDocument("_id" -> BSONObjectID(id)))
.headOption().map(a => a.map(create.apply(_)))
}
}
abstract class MongoField[Doc <: MongoDocument[Doc], T](doc: MongoDocument[Doc], val field: String) {
var value: Option[T] = None
def is: Option[T] = value
def apply(in: T) { value = Some(in) }
def unset() { value = None }
def load(bson: BSONValue)
doc.fields ::= this
}
class MongoInteger[Doc <: MongoDocument[Doc]](doc: Doc, field: String)
extends MongoField[Doc, Int](doc, field) {
def load(bson: BSONValue) { value = Try(bson.asInstanceOf[BSONNumberLike].toInt).toOption }
}
class MongoDoc[Doc <: MongoDocument[Doc], SubDocF <: MongoMetaDocument[SubDoc], SubDoc <: MongoDocument[SubDoc]](doc: Doc, field: String, meta: SubDocF)
extends MongoField[Doc, SubDocF#DocType](doc, field) {
def load(bson: BSONValue) {
value = Try(bson.asInstanceOf[TraversableBSONDocument]).toOption.map { doc =>
meta.create.apply(doc)
}
}
}
假设我有以下代码:
class SubEntity extends MongoDocument[SubEntity] {
val db = Db.get
val collection = ""
val field = new MongoInteger(this, "field")
}
object SubEntity extends SubEntity with MongoMetaDocument[SubEntity]
我想写另一个实体:
class Another extends MongoDocument[Another] {
val db = Db.get
val collection = "test"
val subEntity = new MongoDoc(this, "subEntity", SubEntity)
}
object Another extends Another with MongoMetaDocument[Another]
哪里Db.get
只返回一个DefaultDB
.
然而,Scala 无法推断MongoDoc
实例的类型,即使我认为它们可能是可推断的(Doc
很容易推断,SubDocF
可以推断SubEntity.type
为SubEntity
mixins,MongoMetaDocument[SubEntity]
然后SubDoc
类型必须是SubEntity
)。如果我使用以下代码,一切都会很好:
val subEntity = new MongoDoc[Another,SubEntity.type,SubEntity](this, "subEntity", SubEntity)
是否有一些不需要明确设置类型的解决方案?由于我需要构建一个从MongoDocument
trait 扩展的类的实例,我试图通过使用具有该create
方法的元对象来解决这个问题。
目前我想出的唯一解决方法是利用,implicitly
但这会使实体定义更加讨厌。
谢谢你帮我解决这个问题(或者给我一些提示如何安排我的类层次结构,这不会是一个问题)