Browse files

Added BsonDSL

  • Loading branch information...
1 parent 2694cf2 commit 0d59c9e1c478db966d227f98d3f6894d79943066 @eltimn eltimn committed Jun 20, 2011
View
2 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/DateField.scala
@@ -91,6 +91,6 @@ class DateField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
case jv => JsRaw(Printer.compact(render(jv)))
}
- def asJValue: JValue = valueBox.map(v => Meta.Reflection.dateAsJValue(v)(owner.meta.formats)) openOr (JNothing: JValue)
+ def asJValue: JValue = valueBox.map(v => Meta.dateAsJValue(v, owner.meta.formats)) openOr (JNothing: JValue)
}
View
10 ...stence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/ObjectIdField.scala
@@ -83,19 +83,11 @@ class ObjectIdField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
case _ => Full(elem)
}
- def asJs = valueBox.map { v =>
- if (Meta.Reflection.isObjectIdSerializerUsed(owner.meta.formats))
- JsObj(("$oid", Str(v.toString)))
- else
- Str(v.toString)
- } openOr JsNull
- /*
def asJs = asJValue match {
case JNothing => JsNull
case jv => JsRaw(Printer.compact(render(jv)))
}
- */
- def asJValue: JValue = valueBox.map(v => Meta.Reflection.objectIdAsJValue(v)(owner.meta.formats)) openOr (JNothing: JValue)
+ def asJValue: JValue = valueBox.map(v => Meta.objectIdAsJValue(v, owner.meta.formats)) openOr (JNothing: JValue)
}
View
2 ...istence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/PatternField.scala
@@ -70,6 +70,6 @@ class PatternField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
case jv => Str(Printer.compact(render(jv)))
}
- def asJValue: JValue = valueBox.map(v => Meta.Reflection.patternAsJValue(v)) openOr (JNothing: JValue)
+ def asJValue: JValue = valueBox.map(v => Meta.patternAsJValue(v)) openOr (JNothing: JValue)
}
View
2 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/UUIDField.scala
@@ -82,7 +82,7 @@ class UUIDField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
case jv => JsRaw(Printer.compact(render(jv)))
}
- def asJValue: JValue = valueBox.map(v => Meta.Reflection.uuidAsJValue(v)) openOr (JNothing: JValue)
+ def asJValue: JValue = valueBox.map(v => Meta.uuidAsJValue(v)) openOr (JNothing: JValue)
}
View
150 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/QueryExamplesSpec.scala
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2011 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package mongodb
+package record
+
+import BsonDSL._
+import json.JObject
+import field._
+import net.liftweb.record.field._
+
+import java.util.{Calendar, Date, UUID}
+import java.util.regex.Pattern
+
+import org.bson.types.ObjectId
+import org.specs.Specification
+
+package queryexamplesfixtures {
+ class Person private () extends MongoRecord[Person] with ObjectIdPk[Person] {
+ def meta = Person
+
+ object name extends StringField(this, 100)
+ object birthDate extends DateField(this)
+ object childId extends UUIDField(this)
+ object petId extends ObjectIdField(this) {
+ override def optional_? = true
+ }
+ }
+ object Person extends Person with MongoMetaRecord[Person] {
+ // index name
+ ensureIndex(("name" -> 1))
+
+ // implicit formats already exists
+ def findAllBornAfter(dt: Date) = findAll(("birthDate" -> ("$gt" -> dt)))
+ }
+}
+
+object QueryExamplesSpec extends Specification("QueryExamples Specification") with MongoTestKit {
+ import queryexamplesfixtures._
+
+ "Query examples" in {
+ checkMongoIsRunning
+
+ val fredsBirthDate = Calendar.getInstance
+ fredsBirthDate.set(1970, 1, 1, 19, 0)
+
+ val wilmasBirthDate = Calendar.getInstance
+ wilmasBirthDate.set(1971, 8, 30, 19, 0)
+
+ val barneysBirthDate = Calendar.getInstance
+ barneysBirthDate.set(1972, 8, 30, 19, 0)
+
+ val bettysBirthDate = Calendar.getInstance
+ bettysBirthDate.set(1973, 8, 30, 19, 0)
+
+ val dinoId = ObjectId.get
+ val pebblesId = UUID.randomUUID
+ val bammbammId = UUID.randomUUID
+
+ val fred = Person.createRecord
+ .name("Flinstone, Fred")
+ .birthDate(fredsBirthDate.getTime)
+ .childId(pebblesId)
+ .petId(dinoId)
+ .save
+ val wilma = Person.createRecord
+ .name("Flinstone, Wilma")
+ .birthDate(wilmasBirthDate.getTime)
+ .childId(pebblesId)
+ .petId(dinoId)
+ .save
+ val barney = Person.createRecord
+ .name("Rubble, Barney")
+ .birthDate(barneysBirthDate.getTime)
+ .childId(bammbammId)
+ .save
+ val betty = Person.createRecord
+ .name("Rubble, Betty")
+ .birthDate(bettysBirthDate.getTime)
+ .childId(bammbammId)
+ .save
+
+ val flinstonesIds = List(fred.id.is, wilma.id.is)
+ val rubblesIds = List(barney.id.is, betty.id.is)
+
+ // query for Bamm-Bamm's parents (UUID)
+ val pebblesParents = Person.findAll(("childId" -> bammbammId))
+
+ pebblesParents.length must_== 2
+ pebblesParents.map(_.id.is).filterNot(rubblesIds.contains(_)) must_== List()
+
+ // query for Dino's owners (ObjectId)
+ val dinosOwners = Person.findAll(("petId" -> dinoId))
+
+ dinosOwners.length must_== 2
+ dinosOwners.map(_.id.is).filterNot(flinstonesIds.contains(_)) must_== List()
+
+ // query for the Rubbles using a Regex
+ val rubbles = Person.findAll(("name" -> "^Rubble".r))
+
+ rubbles.length must_== 2
+ rubbles.map(_.id.is).filterNot(rubblesIds.contains(_)) must_== List()
+
+ // query for the Flinstones using a Pattern
+ val flinstones = Person.findAll(("name" -> Pattern.compile("^flinst", Pattern.CASE_INSENSITIVE)))
+
+ flinstones.length must_== 2
+ flinstones.map(_.id.is).filterNot(flinstonesIds.contains(_)) must_== List()
+
+ // query using Dates
+ implicit val formats = Person.formats // this is needed for Dates
+ val qryDate = Calendar.getInstance
+ qryDate.set(1971, 1, 1, 19, 0)
+ val people = Person.findAll(("birthDate" -> ("$gt" -> qryDate.getTime)))
+
+ people.length must_== 3
+ people.map(_.id.is).filterNot(List(wilma.id.is, barney.id.is, betty.id.is).contains(_)) must_== List()
+
+ // you do not need to define the implicit formats val if you write your query in the MongoMetaRecord object.
+ val people2 = Person.findAllBornAfter(qryDate.getTime)
+
+ people2.length must_== 3
+ people2.map(_.id.is).filterNot(List(wilma.id.is, barney.id.is, betty.id.is).contains(_)) must_== List()
+
+ // query with Sort
+ val people3 = Person.findAll(JObject(Nil), ("birthDate" -> -1))
+
+ people3.length must_== 4
+ people3.map(_.id.is) must_== List(betty.id.is, barney.id.is, wilma.id.is, fred.id.is)
+
+ val people4 = Person.findAll(JObject(Nil), ("birthDate" -> 1))
+
+ people4.length must_== 4
+ people4.map(_.id.is) must_== List(fred.id.is, wilma.id.is, barney.id.is, betty.id.is)
+ }
+}
View
34 persistence/mongodb/src/main/scala/net/liftweb/mongodb/BsonDSL.scala
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package mongodb
+
+import json._
+
+import scala.util.matching.Regex
+import java.util.{Date, UUID}
+import java.util.regex.Pattern
+
+import org.bson.types.ObjectId
+
+object BsonDSL extends JsonDSL {
+ implicit def objectid2jvalue(oid: ObjectId): JValue = Meta.objectIdAsJValue(oid)
+ implicit def pattern2jvalue(p: Pattern): JValue = Meta.patternAsJValue(p)
+ implicit def regex2jvalue(r: Regex): JValue = Meta.patternAsJValue(r.pattern)
+ implicit def uuid2jvalue(u: UUID): JValue = Meta.uuidAsJValue(u)
+ implicit def date2jvalue(d: Date)(implicit formats: Formats): JValue = Meta.dateAsJValue(d, formats)
+}
View
58 persistence/mongodb/src/main/scala/net/liftweb/mongodb/Meta.scala
@@ -14,8 +14,15 @@
* limitations under the License.
*/
-package net.liftweb
-package mongodb
+package net.liftweb
+package mongodb
+
+import json._
+
+import java.util.{Calendar, Date, GregorianCalendar, UUID}
+import java.util.regex.Pattern
+
+import org.bson.types.ObjectId
private[mongodb] object Meta {
@@ -24,14 +31,7 @@ private[mongodb] object Meta {
*/
object Reflection {
import java.lang.reflect._
- import java.util.{Calendar, Date, GregorianCalendar, UUID}
- import java.util.regex.Pattern
-
- import net.liftweb.json.Formats
- import net.liftweb.json.JsonAST._
-
import com.mongodb.{BasicDBObject, DBRef}
- import org.bson.types.ObjectId
/*
* These don't require a conversion and can be put directly into a DBObject
@@ -76,13 +76,10 @@ private[mongodb] object Meta {
def datetype_?(clazz: Class[_]) = datetypes contains clazz
def datetype2jvalue(a: Any)(implicit formats: Formats) = a match {
- case x: Calendar => dateAsJValue(x.getTime)
- case x: Date => dateAsJValue(x)
+ case x: Calendar => dateAsJValue(x.getTime, formats)
+ case x: Date => dateAsJValue(x, formats)
}
- def dateAsJValue(d: Date)(implicit formats: Formats) =
- JObject(JField("$dt", JString(formats.dateFormat.format(d))) :: Nil)
-
def datetype2dbovalue(a: Any) = a match {
case x: Calendar => x.getTime
case x: Date => x
@@ -100,28 +97,31 @@ private[mongodb] object Meta {
* Definitive place for JValue conversion of mongo types
*/
def mongotype2jvalue(a: Any)(implicit formats: Formats) = a match {
- case x: ObjectId => objectIdAsJValue(x)(formats)
+ case x: ObjectId => objectIdAsJValue(x, formats)
case x: Pattern => patternAsJValue(x)
case x: UUID => uuidAsJValue(x)
case x: DBRef => error("DBRefs are not supported.")
case _ => error("not a mongotype " + a.asInstanceOf[AnyRef].getClass)
}
+ }
- def objectIdAsJValue(oid: ObjectId)(formats: Formats): JValue =
- if (isObjectIdSerializerUsed(formats))
- JObject(JField("$oid", JString(oid.toString)) :: Nil)
- else
- JString(oid.toString)
- def patternAsJValue(p: Pattern): JValue = JObject(JField("$regex", JString(p.pattern)) :: JField("$flags", JInt(p.flags)) :: Nil)
- def uuidAsJValue(u: UUID): JValue = JObject(JField("$uuid", JString(u.toString)) :: Nil)
+ def dateAsJValue(d: Date, formats: Formats) = JObject(JField("$dt", JString(formats.dateFormat.format(d))) :: Nil)
+ def objectIdAsJValue(oid: ObjectId): JValue = JObject(JField("$oid", JString(oid.toString)) :: Nil)
+ def patternAsJValue(p: Pattern): JValue = JObject(JField("$regex", JString(p.pattern)) :: JField("$flags", JInt(p.flags)) :: Nil)
+ def uuidAsJValue(u: UUID): JValue = JObject(JField("$uuid", JString(u.toString)) :: Nil)
- /*
- * Check to see if the ObjectIdSerializer is being used.
- */
- def isObjectIdSerializerUsed(formats: Formats): Boolean =
- formats.customSerializers.exists(_.getClass == objectIdSerializerClass)
+ def objectIdAsJValue(oid: ObjectId, formats: Formats): JValue =
+ if (isObjectIdSerializerUsed(formats))
+ objectIdAsJValue(oid)
+ else
+ JString(oid.toString)
- private val objectIdSerializerClass = classOf[net.liftweb.mongodb.ObjectIdSerializer]
- }
+ /*
+ * Check to see if the ObjectIdSerializer is being used.
+ */
+ private def isObjectIdSerializerUsed(formats: Formats): Boolean =
+ formats.customSerializers.exists(_.getClass == objectIdSerializerClass)
+
+ private val objectIdSerializerClass = classOf[net.liftweb.mongodb.ObjectIdSerializer]
}
View
2 persistence/mongodb/src/main/scala/net/liftweb/mongodb/MongoMeta.scala
@@ -35,7 +35,7 @@ trait JsonFormats {
*/
trait MongoMeta[BaseDocument] extends JsonFormats {
- // class name has a $ at the end. because it's an object(?)
+ // class name has a $ at the end.
private lazy val _collectionName = {
getClass.getName.split("\\.").toList.last.replace("$", "")+"s"
}
View
8 persistence/mongodb/src/main/scala/net/liftweb/mongodb/Serializers.scala
@@ -41,7 +41,7 @@ class ObjectIdSerializer extends Serializer[ObjectId] {
}
def serialize(implicit formats: Formats): PartialFunction[Any, JValue] = {
- case x: ObjectId => Meta.Reflection.objectIdAsJValue(x)(formats)
+ case x: ObjectId => Meta.objectIdAsJValue(x)
}
}
@@ -64,7 +64,7 @@ class PatternSerializer extends Serializer[Pattern] {
}
def serialize(implicit formats: Formats): PartialFunction[Any, JValue] = {
- case x: Pattern => Meta.Reflection.patternAsJValue(x)
+ case x: Pattern => Meta.patternAsJValue(x)
}
}
@@ -86,7 +86,7 @@ class DateSerializer extends Serializer[Date] {
}
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
- case x: Date => Meta.Reflection.dateAsJValue(x)
+ case x: Date => Meta.dateAsJValue(x, format)
}
}
@@ -107,7 +107,7 @@ class UUIDSerializer extends Serializer[UUID] {
}
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
- case x: UUID => Meta.Reflection.uuidAsJValue(x)
+ case x: UUID => Meta.uuidAsJValue(x)
}
}
View
80 persistence/mongodb/src/test/scala/net/liftweb/mongodb/BsonDSLSpec.scala
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2011 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package mongodb
+
+import BsonDSL._
+import json._
+
+import scala.util.matching.Regex
+
+import java.util.{Date, UUID}
+import java.util.regex.Pattern
+
+import org.bson.types.ObjectId
+import org.specs.Specification
+
+import com.mongodb.{DBObject}
+
+object BsonDSLSpec extends Specification("BsonDSL Specification") {
+ "BsonDSL" should {
+ "Convert ObjectId properly" in {
+ val oid: ObjectId = ObjectId.get
+ val qry: JObject = ("id" -> oid)
+ val dbo: DBObject = JObjectParser.parse(qry)(DefaultFormats)
+
+ dbo.get("id") must_== oid
+ }
+
+ "Convert Pattern properly" in {
+ val ptrn: Pattern = Pattern.compile("^Mongo", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE)
+ val qry: JObject = ("ptrn" -> ptrn)
+ val dbo: DBObject = JObjectParser.parse(qry)(DefaultFormats)
+ val ptrn2: Pattern = dbo.get("ptrn").asInstanceOf[Pattern]
+
+ ptrn2.pattern must_== ptrn.pattern
+ ptrn2.flags must_== ptrn.flags
+ }
+
+ "Convert Regex properly" in {
+ val regex: Regex = "^Mongo".r
+ val qry: JObject = ("regex" -> regex)
+ val dbo: DBObject = JObjectParser.parse(qry)(DefaultFormats)
+ val ptrn: Pattern = dbo.get("regex").asInstanceOf[Pattern]
+
+ regex.pattern.pattern must_== ptrn.pattern
+ regex.pattern.flags must_== ptrn.flags
+ }
+
+ "Convert UUID properly" in {
+ val uuid: UUID = UUID.randomUUID
+ val qry: JObject = ("uuid" -> uuid)
+ val dbo: DBObject = JObjectParser.parse(qry)(DefaultFormats)
+
+ dbo.get("uuid") must_== uuid
+ }
+
+ "Convert Date properly" in {
+ implicit val formats = DefaultFormats.lossless
+ val dt: Date = new Date
+ val qry: JObject = ("now" -> dt)
+ val dbo: DBObject = JObjectParser.parse(qry)
+
+ dbo.get("now") must_== dt
+ }
+ }
+}
View
128 persistence/mongodb/src/test/scala/net/liftweb/mongodb/QueryExamplesSpec.scala
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2011 WorldWide Conferencing, LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.liftweb
+package mongodb
+
+import BsonDSL._
+import json.JObject
+
+import java.util.{Calendar, Date, UUID}
+import java.util.regex.Pattern
+
+import org.bson.types.ObjectId
+import org.specs.Specification
+
+package queryexamplesfixtures {
+ case class Person(_id: ObjectId, name: String, birthDate: Date, childId: UUID, petId: Option[ObjectId]) extends MongoDocument[Person] {
+ def meta = Person
+ }
+ object Person extends MongoDocumentMeta[Person] {
+ override def formats = allFormats
+ // index name
+ ensureIndex(("name" -> 1))
+
+ // implicit formats already exists
+ def findAllBornAfter(dt: Date) = findAll(("birthDate" -> ("$gt" -> dt)))
+ }
+}
+
+object QueryExamplesSpec extends Specification("QueryExamples Specification") with MongoTestKit {
+ import queryexamplesfixtures._
+
+ "Query examples" in {
+ checkMongoIsRunning
+
+ val fredsBirthDate = Calendar.getInstance
+ fredsBirthDate.set(1970, 1, 1, 19, 0)
+
+ val wilmasBirthDate = Calendar.getInstance
+ wilmasBirthDate.set(1971, 8, 30, 19, 0)
+
+ val barneysBirthDate = Calendar.getInstance
+ barneysBirthDate.set(1972, 8, 30, 19, 0)
+
+ val bettysBirthDate = Calendar.getInstance
+ bettysBirthDate.set(1973, 8, 30, 19, 0)
+
+ val dinoId = ObjectId.get
+ val pebblesId = UUID.randomUUID
+ val bammbammId = UUID.randomUUID
+
+ val fred = Person(ObjectId.get, "Flinstone, Fred", fredsBirthDate.getTime, pebblesId, Some(dinoId))
+ val wilma = Person(ObjectId.get, "Flinstone, Wilma", wilmasBirthDate.getTime, pebblesId, Some(dinoId))
+ val barney = Person(ObjectId.get, "Rubble, Barney", barneysBirthDate.getTime, bammbammId, None)
+ val betty = Person(ObjectId.get, "Rubble, Betty", bettysBirthDate.getTime, bammbammId, None)
+
+ fred.save
+ wilma.save
+ barney.save
+ betty.save
+
+ val flinstonesIds = List(fred._id, wilma._id)
+ val rubblesIds = List(barney._id, betty._id)
+
+ // query for Bamm-Bamm's parents (UUID)
+ val pebblesParents = Person.findAll(("childId" -> bammbammId))
+
+ pebblesParents.length must_== 2
+ pebblesParents.map(_._id).filterNot(rubblesIds.contains(_)) must_== List()
+
+ // query for Dino's owners (ObjectId)
+ val dinosOwners = Person.findAll(("petId" -> dinoId))
+
+ dinosOwners.length must_== 2
+ dinosOwners.map(_._id).filterNot(flinstonesIds.contains(_)) must_== List()
+
+ // query for the Rubbles using a Regex
+ val rubbles = Person.findAll(("name" -> "^Rubble".r))
+
+ rubbles.length must_== 2
+ rubbles.map(_._id).filterNot(rubblesIds.contains(_)) must_== List()
+
+ // query for the Flinstones using a Pattern
+ val flinstones = Person.findAll(("name" -> Pattern.compile("^flinst", Pattern.CASE_INSENSITIVE)))
+
+ flinstones.length must_== 2
+ flinstones.map(_._id).filterNot(flinstonesIds.contains(_)) must_== List()
+
+ // query using Dates
+ implicit val formats = Person.formats // this is needed for Dates
+ val qryDate = Calendar.getInstance
+ qryDate.set(1971, 1, 1, 19, 0)
+ val people = Person.findAll(("birthDate" -> ("$gt" -> qryDate.getTime)))
+
+ people.length must_== 3
+ people.map(_._id).filterNot(List(wilma._id, barney._id, betty._id).contains(_)) must_== List()
+
+ // you do not need to define the implicit formats val if you write your query in the DocumentMeta object.
+ val people2 = Person.findAllBornAfter(qryDate.getTime)
+
+ people2.length must_== 3
+ people2.map(_._id).filterNot(List(wilma._id, barney._id, betty._id).contains(_)) must_== List()
+
+ // query with Sort
+ val people3 = Person.findAll(JObject(Nil), ("birthDate" -> -1))
+
+ people3.length must_== 4
+ people3.map(_._id) must_== List(betty._id, barney._id, wilma._id, fred._id)
+
+ val people4 = Person.findAll(JObject(Nil), ("birthDate" -> 1))
+
+ people4.length must_== 4
+ people4.map(_._id) must_== List(fred._id, wilma._id, barney._id, betty._id)
+ }
+}

0 comments on commit 0d59c9e

Please sign in to comment.