PageRenderTime 46ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/datastore/src/main/scala/org/sgine/datastore/mongodb/MongoDBDatastore.scala

https://code.google.com/p/sgine/
Scala | 85 lines | 66 code | 13 blank | 6 comment | 11 complexity | 1785bbc53817efa53b316d6c11da9935 MD5 | raw file
  1. package org.sgine.datastore.mongodb
  2. import org.sgine.datastore.{Datastore, Identifiable}
  3. import com.mongodb.casbah.MongoDB
  4. import java.util.UUID
  5. import org.sgine.datastore.mongodb.converter._
  6. import com.mongodb.casbah.commons.Implicits._
  7. import org.sgine.reflect.EnhancedClass
  8. import com.mongodb.casbah.commons.{MongoDBObjectBuilder, MongoDBObject}
  9. import com.mongodb.DBObject
  10. import org.bson.types.ObjectId
  11. /**
  12. * MongoDB implementation of Datastore
  13. *
  14. * @author Matt Hicks <mhicks@sgine.org>
  15. */
  16. class MongoDBDatastore[T <: Identifiable](db: MongoDB, collectionName: String, val layers: Datastore[_]*)(implicit val manifest: Manifest[T]) extends Datastore[T] {
  17. private lazy val collection = db(collectionName)
  18. protected def persistInternal(obj: T) = {
  19. val dbObj = DataObjectConverter.toDBObject(obj)
  20. collection += dbObj
  21. }
  22. protected def deleteInternal(id: UUID) = collection.findAndRemove(MongoDBObject("_id" -> id)) != None
  23. override def clear() = collection.dropCollection()
  24. def commit() {} // TODO: support
  25. def rollback() {} // TODO: support
  26. def byExample(example: T) = {
  27. val ec = EnhancedClass(example.getClass)
  28. val method = ec.createMethod.getOrElse(throw new NullPointerException("%s is not a case class".format(example)))
  29. val companion = ec.companion.getOrElse(throw new NullPointerException("No companion found for %s".format(example)))
  30. val companionInstance = companion.instance.getOrElse(throw new NullPointerException("No companion instance found for %s".format(companion)))
  31. val defaults = method.args.collect {
  32. // Generate defaults excluding "id"
  33. case arg if (arg.name != "id") => arg.default(companionInstance) match {
  34. case None => arg.name -> arg.`type`.defaultForType // Default by the class type
  35. case Some(value) => arg.name -> value // Default argument for this case class
  36. }
  37. }.toMap
  38. val builder = MongoDBObject.newBuilder
  39. ec.caseValues.foreach(cv => if (cv.name != "id" && defaults(cv.name) != cv[Any](example)) {
  40. val value = cv[Any](example)
  41. builder += cv.name -> DataObjectConverter.toDBValue(value)
  42. })
  43. val query = toDotNotation("", wrapDBObj(builder.result()))
  44. collection.find(query).map(entry => {
  45. DataObjectConverter.fromDBValue(entry)
  46. }).asInstanceOf[Iterator[T]]
  47. }
  48. override def byId(id: UUID) = {
  49. val criteria = MongoDBObject("_id" -> id)
  50. collection.findOne(criteria).map(entry => {
  51. DataObjectConverter.fromDBValue(entry).asInstanceOf[T]
  52. })
  53. }
  54. def all = collection.find().map(entry => DataObjectConverter.fromDBValue(entry)).asInstanceOf[Iterator[T]]
  55. private def toDotNotation(pre: String, values: MongoDBObject, builder: MongoDBObjectBuilder = MongoDBObject.newBuilder): DBObject = {
  56. if (values.isEmpty) {
  57. builder.result()
  58. } else {
  59. values.head match {
  60. case (s, id: ObjectId) => // Ignore for queries
  61. case (s, obj: DBObject) => toDotNotation(dotSeparate(pre, s), obj, builder)
  62. case (s, value) => builder += dotSeparate(pre, s) -> value
  63. }
  64. toDotNotation(pre, map2MongoDBObject(values.tail), builder)
  65. }
  66. }
  67. private def dotSeparate(pre: String, actual: String) = if (pre.nonEmpty) {
  68. "%s.%s".format(pre, actual)
  69. } else {
  70. actual
  71. }
  72. }