Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

MongoSubRecordField, MongoPk, MongoRef

  • Loading branch information...
commit 0d716b76ae44f1bd6644ff16796c9773254adc0c 1 parent daac188
@eltimn eltimn authored
Showing with 1,213 additions and 227 deletions.
  1. +57 −21 framework/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
  2. +114 −0 framework/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoPk.scala
  3. +10 −2 framework/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
  4. +15 −8 .../lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JsonObjectField.scala
  5. +12 −1 ...t-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoCaseClassField.scala
  6. +18 −18 ...odb-record/src/main/scala/net/liftweb/mongodb/record/field/{MongoFieldFlavor.scala → MongoField.scala}
  7. +42 −7 ...k/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoListField.scala
  8. +12 −7 ...rk/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoMapField.scala
  9. +235 −0 ...rk/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoRefField.scala
  10. +77 −0 ...t-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoSubRecordField.scala
  11. +10 −20 ...rk/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/ObjectIdField.scala
  12. +3 −12 framework/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/UUIDField.scala
  13. +204 −27 framework/lift-persistence/lift-mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
  14. +63 −20 framework/lift-persistence/lift-mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpecs.scala
  15. +276 −83 ...ework/lift-persistence/lift-mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpecs.scala
  16. +1 −1  framework/lift-persistence/lift-mongodb/src/main/scala/net/liftweb/mongodb/JsonObject.scala
  17. +64 −0 framework/lift-persistence/lift-record/src/main/scala/net/liftweb/record/field/ChoiceField.scala
View
78 ...ork/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
@@ -18,22 +18,23 @@ package net.liftweb {
package mongodb {
package record {
+import field._
+
+import common.{Box, Empty, Full}
+import json.{Formats, JsonParser}
+import json.JsonAST._
+import util.Helpers.tryo
+
import java.util.{Calendar, UUID}
import java.util.regex.Pattern
import scala.collection.JavaConversions._
-import net.liftweb.common.{Box, Empty, Full}
-import net.liftweb.json.{Formats, JsonParser}
-import net.liftweb.json.JsonAST._
-import net.liftweb.mongodb._
-import net.liftweb.mongodb.record.field._
-import net.liftweb.record.{MetaRecord, Record}
+import net.liftweb.record.{Field, MandatoryTypedField, MetaRecord, Record}
import net.liftweb.record.FieldHelpers.expectedA
import net.liftweb.record.field._
import com.mongodb._
-import com.mongodb.util.JSON
import org.bson.types.ObjectId
trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
@@ -41,12 +42,22 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
self: BaseRecord =>
+ /*
+ * Utility method for determining the value of _id.
+ *
+ * This is needed for backwards compatibility.
+ */
+ def idValue(inst: BaseRecord): Any = inst.id match {
+ case f: MandatoryTypedField[Any] => f.value
+ case x => x
+ }
+
/**
* Delete the instance from backing store
*/
def delete_!(inst: BaseRecord): Boolean = {
foreachCallback(inst, _.beforeDelete)
- delete("_id", inst.id)
+ delete("_id", idValue(inst))
foreachCallback(inst, _.afterDelete)
true
}
@@ -106,6 +117,11 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
def find(id: Int): Box[BaseRecord] = find(new BasicDBObject("_id", id))
/**
+ * Find a single row by a Long id
+ */
+ def find(id: Long): Box[BaseRecord] = find(new BasicDBObject("_id", id))
+
+ /**
* Find a single document by a qry using a json value
*/
def find(json: JObject): Box[BaseRecord] = find(JObjectParser.parse(json))
@@ -294,11 +310,21 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
*/
def update(obj: BaseRecord, update: DBObject): Unit = {
val query = (BasicDBObjectBuilder.start
- .add("_id", obj.id)
+ .add("_id", idValue(obj))
.get)
this.update(query, update)
}
+ /*
+ * Return the name of the field in the encoded DBbject. If the field
+ * implements MongoField and has overridden mongoName then
+ * that will be used, otherwise the record field name.
+ */
+ def mongoName(field: Field[_, BaseRecord]): String = field match {
+ case (mongoField: MongoField) => mongoField.mongoName openOr field.name
+ case _ => field.name
+ }
+
/**
* Create a BasicDBObject from the field names and values.
* - MongoFieldFlavor types (List) are converted to DBObjects
@@ -313,23 +339,31 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
for (f <- fields(inst)) {
f match {
- case field if (field.optional_? && field.valueBox.isEmpty) => // don't add to DBObject
+ case field if ((field.optional_? && field.valueBox.isEmpty) || field.ignoreField_?) => // don't add to DBObject
case field: EnumTypedField[Enumeration] =>
field.asInstanceOf[EnumTypedField[Enumeration]].valueBox foreach {
- v => dbo.add(f.name, v.id)
+ v => dbo.add(mongoName(f), v.id)
}
case field: EnumNameTypedField[Enumeration] =>
field.asInstanceOf[EnumNameTypedField[Enumeration]].valueBox foreach {
- v => dbo.add(f.name, v.toString)
+ v => dbo.add(mongoName(f), v.toString)
}
+ case field: MongoRefField[MongoRecord[Any], Any] => {
+ if (field.saveAsDbRef_?)
+ field.dbRef foreach { dbr => dbo.add(mongoName(f), dbr) }
+ else
+ field.valueBox foreach { v => dbo.add(mongoName(f), v) }
+ }
case field: MongoFieldFlavor[Any] =>
- dbo.add(f.name, field.asInstanceOf[MongoFieldFlavor[Any]].asDBObject)
+ dbo.add(mongoName(f), field.asInstanceOf[MongoFieldFlavor[Any]].asDBObject)
case field => field.valueBox foreach (_.asInstanceOf[AnyRef] match {
- case null => dbo.add(f.name, null)
- case x if primitive_?(x.getClass) => dbo.add(f.name, x)
- case x if mongotype_?(x.getClass) => dbo.add(f.name, x)
- case x if datetype_?(x.getClass) => dbo.add(f.name, datetype2dbovalue(x))
- case o => dbo.add(f.name, o.toString)
+ case null => dbo.add(mongoName(f), null)
+ case x if primitive_?(x.getClass) => dbo.add(mongoName(f), x)
+ case x if mongotype_?(x.getClass) => dbo.add(mongoName(f), x)
+ case x if datetype_?(x.getClass) => dbo.add(mongoName(f), datetype2dbovalue(x))
+ case x: Array[Byte] => dbo.add(mongoName(f), x)
+ case x: MongoRecord[Any] => dbo.add(mongoName(f), x.asDBObject)
+ case o => dbo.add(mongoName(f), o.toString)
})
}
}
@@ -357,9 +391,11 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
* @return Box[BaseRecord]
*/
def setFieldsFromDBObject(inst: BaseRecord, dbo: DBObject): Unit = {
- for (k <- dbo.keySet; field <- inst.fieldByName(k.toString)) {
- field.setFromAny(dbo.get(k.toString))
- }
+ inst.fields.foreach( f => {
+ val key = mongoName(f)
+ if (dbo.containsField(key))
+ f.setFromAny(dbo.get(key))
+ })
inst.runSafe {
inst.fields.foreach(_.resetDirty)
}
View
114 framework/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoPk.scala
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2010 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 field._
+import common.{Box, Empty, Full}
+import util.StringHelpers.randomString
+
+import scala.util.Random
+import java.util.UUID
+
+import org.bson.types.ObjectId
+import net.liftweb.record.field.{IntField, LongField, StringField}
+
+/*
+ * Trait for creating a "Primary Key" Field. All Mongo Records must have
+ * a _id defined. These all have an id field that is saved as _id in the
+ * database.
+ */
+trait MongoPk[PkType <: MongoField] {
+ def id: PkType
+ /** Override this to set default value of id field */
+ def defaultIdValue: Any
+}
+
+trait ObjectIdPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[ObjectIdField[OwnerType] with MongoField]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = ObjectId.get
+
+ object id extends ObjectIdField(this.asInstanceOf[OwnerType]) with MongoField {
+ override def mongoName = Full("_id") // store this as _id in the database
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait UUIDPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[UUIDField[OwnerType] with MongoField]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = UUID.randomUUID
+
+ object id extends UUIDField(this.asInstanceOf[OwnerType]) with MongoField {
+ override def mongoName = Full("_id") // store this as _id in the database
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait StringPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[StringField[OwnerType] with MongoField]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = randomString(32)
+
+ object id extends StringField(this.asInstanceOf[OwnerType], 12) with MongoField {
+ override def mongoName = Full("_id") // store this as _id in the database
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait IntPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[IntField[OwnerType] with MongoField]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = Random.nextInt
+
+ object id extends IntField(this.asInstanceOf[OwnerType]) with MongoField {
+ override def mongoName = Full("_id") // store this as _id in the database
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait LongPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[LongField[OwnerType] with MongoField]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = Random.nextLong
+
+ object id extends LongField(this.asInstanceOf[OwnerType]) with MongoField {
+ override def mongoName = Full("_id") // store this as _id in the database
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+}
+}
+}
View
12 framework/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
@@ -29,8 +29,12 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends Record[MyType] {
self: MyType =>
/*
- * every mongo record must have an _id field. Override this with the value of your _id object.
- */
+ * Mongo records that are to be saved in their own collection must
+ * have an _id field. This is defined for you if you mix in a MongoPk
+ * trait.
+ * For embedded objects, mix in the MongoEmbed trait or you must
+ * define this in your record.
+ */
def id: Any
/**
@@ -138,6 +142,10 @@ trait MongoId[OwnerType <: MongoRecord[OwnerType]] {
}
}
+trait MongoEmbed {
+ def id = ""
+}
+
}
}
}
View
23 ...ft-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JsonObjectField.scala
@@ -18,19 +18,22 @@ package field {
import scala.xml.{NodeSeq, Text}
-import _root_.net.liftweb.common.{Box, Empty, Failure, Full}
-
-import _root_.net.liftweb.http.js.JE.{JsNull, Str}
-import _root_.net.liftweb.json.JsonAST._
-import _root_.net.liftweb.json.{JsonParser, Printer}
-import _root_.net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
-import _root_.net.liftweb.util.Helpers.tryo
+import common.{Box, Empty, Failure, Full}
+import http.js.JsExp
+import http.js.JE.{JsNull, Str}
+import json.JsonAST._
+import json.{JsonParser, Printer}
+import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
+import util.Helpers.tryo
import com.mongodb.DBObject
abstract class JsonObjectField[OwnerType <: MongoRecord[OwnerType], JObjectType <: JsonObject[JObjectType]]
(rec: OwnerType, valueMeta: JsonObjectMeta[JObjectType])
- extends Field[JObjectType, OwnerType] with MandatoryTypedField[JObjectType] with MongoFieldFlavor[JObjectType] {
+ extends Field[JObjectType, OwnerType]
+ with MandatoryTypedField[JObjectType]
+ with MongoFieldFlavor[JObjectType]
+{
def owner = rec
@@ -44,6 +47,10 @@ abstract class JsonObjectField[OwnerType <: MongoRecord[OwnerType], JObjectType
/** Encode the field value into a JValue */
def asJValue: JValue = value.asJObject
+ def asJs = new JsExp {
+ lazy val toJsCmd = Printer.compact(render(asJValue))
+ }
+
/*
* Decode the JValue and set the field to the decoded value.
* Returns Empty or Failure if the value could not be set
View
13 ...ersistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoCaseClassField.scala
@@ -62,6 +62,13 @@ class MongoCaseClassField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerTyp
case (failure: Failure) => setBox(failure)
case _ => setBox(defaultValueBox)
}
+
+ def asJs = asJValue match {
+ case JNothing => JsNull
+ case jv => new JsExp {
+ lazy val toJsCmd = Printer.compact(render(jv))
+ }
+ }
}
class MongoCaseClassListField[OwnerType <: Record[OwnerType],CaseType](rec: OwnerType)( implicit mf: Manifest[CaseType]) extends Field[List[CaseType], OwnerType] with MandatoryTypedField[List[CaseType]] with MongoFieldFlavor[List[CaseType]] {
@@ -80,7 +87,7 @@ class MongoCaseClassListField[OwnerType <: Record[OwnerType],CaseType](rec: Owne
override def optional_? = true
def asJValue = JArray(value.map(v => Extraction.decompose(v)))
-
+
def setFromJValue(jvalue: JValue): Box[MyType] = jvalue match {
case JArray(contents) => setBox(Full(contents.flatMap(s => Helpers.tryo[CaseType]{ s.extract[CaseType] })))
case _ => setBox(Empty)
@@ -111,6 +118,10 @@ class MongoCaseClassListField[OwnerType <: Record[OwnerType],CaseType](rec: Owne
override def setFromString(in: String): Box[MyType] = {
setFromJValue(JsonParser.parse(in))
}
+
+ def asJs = new JsExp {
+ lazy val toJsCmd = Printer.compact(render(asJValue))
+ }
}
}
View
36 ...ftweb/mongodb/record/field/MongoFieldFlavor.scala → ...net/liftweb/mongodb/record/field/MongoField.scala
@@ -19,18 +19,30 @@ package mongodb {
package record {
package field {
-import net.liftweb.common.{Box, Empty, Failure, Full}
-import net.liftweb.http.js.JE.{JsNull, JsRaw}
-import net.liftweb.json.Printer
-import net.liftweb.json.JsonAST._
+import common.{Box, Empty}
+import http.js.JsExp
+import http.js.JE.JsNull
+import json.JsonAST._
+import json.Printer
import com.mongodb.DBObject
+/*
+ * Trait that allows for saving the field with a name that is
+ * different than the field name
+ */
+trait MongoField {
+ /**
+ * Return Full(name) to use that name in the encoded Mongo object, or
+ * Empty to use the same name as in Scala. Defaults to Empty.
+ */
+ def mongoName: Box[String] = Empty
+}
+
/**
-* Describes common aspects related to Mongo fields
+* Used by MongoMetaRecord to convert to/from DBObject.
*/
trait MongoFieldFlavor[MyType] {
-
/*
* convert this field's value into a DBObject so it can be stored in Mongo.
*/
@@ -38,18 +50,6 @@ trait MongoFieldFlavor[MyType] {
// set this field's value using a DBObject returned from Mongo.
def setFromDBObject(obj: DBObject): Box[MyType]
-
- /**
- * Returns the field's value as a valid JavaScript expression
- */
- def asJs = asJValue match {
- case JNothing => JsNull
- case jv => JsRaw(Printer.compact(render(jv)))
- }
-
- /** Encode the field value into a JValue */
- def asJValue: JValue
-
}
}
View
49 ...ift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoListField.scala
@@ -22,13 +22,14 @@ package field {
import java.util.Date
import scala.collection.JavaConversions._
+import scala.xml.NodeSeq
-import _root_.net.liftweb.common.{Box, Empty, Failure, Full}
-import _root_.net.liftweb.json.JsonAST._
-import _root_.net.liftweb.json.JsonParser
-import _root_.net.liftweb.http.js.JE.{JsNull, JsRaw}
-import _root_.net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
-import _root_.net.liftweb.util.Helpers.tryo
+import common.{Box, Empty, Failure, Full}
+import json.JsonAST._
+import json.{JsonParser, Printer}
+import http.js.JsExp
+import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record, TypedField}
+import util.Helpers.tryo
import com.mongodb._
import org.bson.types.ObjectId
@@ -77,7 +78,7 @@ class MongoListField[OwnerType <: MongoRecord[OwnerType], ListType](rec: OwnerTy
case other => setBox(Failure("Error parsing String into a JValue: "+in))
}
- def toForm = Empty // FIXME
+ def toForm: Box[NodeSeq] = Empty
def asJValue = JArray(value.map(li => li.asInstanceOf[AnyRef] match {
case x if primitive_?(x.getClass) => primitive2jvalue(x)
@@ -97,18 +98,52 @@ class MongoListField[OwnerType <: MongoRecord[OwnerType], ListType](rec: OwnerTy
case x if primitive_?(x.getClass) => dbl.add(x)
case x if mongotype_?(x.getClass) => dbl.add(x)
case x if datetype_?(x.getClass) => dbl.add(datetype2dbovalue(x))
+ //case x: TypedField => x.valueBox foreach { v => dbl.add(v) }
case o => dbl.add(o.toString)
}
}
dbl
}
+ def asJs = new JsExp {
+ lazy val toJsCmd = Printer.compact(render(asJValue))
+ }
+
// set this field's value using a DBObject returned from Mongo.
def setFromDBObject(dbo: DBObject): Box[List[ListType]] =
setBox(Full(dbo.asInstanceOf[BasicDBList].toList.asInstanceOf[List[ListType]]))
}
/*
+ * List of MongoSubRecords
+ */
+class MongoSubRecordListField[OwnerType <: MongoRecord[OwnerType], SubRecordType <: MongoRecord[SubRecordType]]
+ (rec: OwnerType, valueMeta: MongoMetaRecord[SubRecordType])
+ extends MongoListField[OwnerType, SubRecordType](rec: OwnerType) {
+
+ override def asDBObject: DBObject = {
+ val dbl = new BasicDBList
+ value.foreach { v => dbl.add(v.asDBObject) }
+ dbl
+ }
+
+ override def setFromDBObject(dbo: DBObject): Box[List[SubRecordType]] =
+ setBox(Full(dbo.keySet.toList.map(k => {
+ valueMeta.fromDBObject(dbo.get(k.toString).asInstanceOf[DBObject])
+ })))
+
+ override def asJValue = JArray(value.map(_.asJValue))
+
+ override def setFromJValue(jvalue: JValue) = jvalue match {
+ case JNothing|JNull if optional_? => setBox(Empty)
+ case JArray(arr) => setBox(Full(arr.map( jv => {
+ valueMeta.fromJValue(jv) openOr valueMeta.createRecord
+ })))
+ case other => setBox(FieldHelpers.expectedA("JArray", other))
+ }
+}
+
+/*
* List of Dates. Use MongListField(OwnerType, Date) instead.
*/
@Deprecated
View
19 ...lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoMapField.scala
@@ -21,12 +21,13 @@ package field {
import scala.xml.NodeSeq
-import _root_.net.liftweb.common.{Box, Empty, Failure, Full}
-import _root_.net.liftweb.http.js.JE.{JsNull, JsRaw}
-import _root_.net.liftweb.json.JsonAST._
-import _root_.net.liftweb.json.{JsonParser, Printer}
-import _root_.net.liftweb.record._
-import _root_.net.liftweb.util.Helpers.tryo
+import common.{Box, Empty, Failure, Full}
+import http.js.JsExp
+import http.js.JE.{JsNull, JsRaw}
+import json.JsonAST._
+import json.{JsonParser, Printer}
+import net.liftweb.record._
+import util.Helpers.tryo
import com.mongodb._
@@ -70,7 +71,7 @@ class MongoMapField[OwnerType <: MongoRecord[OwnerType], MapValueType](rec: Owne
case other => setBox(Failure("Error parsing String into a JValue: "+in))
}
- def toForm = Empty // FIXME
+ def toForm = Empty
def asJValue = JObject(value.keys.map {
k =>
@@ -82,6 +83,10 @@ class MongoMapField[OwnerType <: MongoRecord[OwnerType], MapValueType](rec: Owne
})
}.toList)
+ def asJs = new JsExp {
+ lazy val toJsCmd = Printer.compact(render(asJValue))
+ }
+
/*
* Convert this field's value into a DBObject so it can be stored in Mongo.
*/
View
235 ...lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoRefField.scala
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2010 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 {
+package field {
+
+import common.{Box, Empty, Full}
+import http.SHtml
+import util.Helpers._
+
+import java.util.UUID
+
+import org.bson.types.ObjectId
+import com.mongodb.DBRef
+import net.liftweb.record.TypedField
+import net.liftweb.record.field._
+
+/*
+ * T - ObjectId, UUID, String, Int, Long
+ */
+ /*
+class MongoRef[T, RefType <: MongoRecord[RefType]](
+ valueBox: Box[T],
+ refMeta: MongoMetaRecord[RefType],
+ saveAsDbRef_? : Boolean = false
+) {
+ /*
+ * get the referenced object
+ */
+ def obj = synchronized {
+ if (!_calcedObj) {
+ _calcedObj = true
+ this._obj = valueBox.flatMap(v => refMeta.findAny(v))
+ }
+ _obj
+ }
+
+ def cached_? : Boolean = synchronized { _calcedObj }
+
+ def primeObj(obj: Box[RefType]) = synchronized {
+ _obj = obj
+ _calcedObj = true
+ }
+
+ private var _obj: Box[RefType] = Empty
+ private var _calcedObj = false
+
+ /*
+ * Get the DBRef value that this Field represents.
+ */
+ def dbRef: Box[DBRef] = valueBox.map(v =>
+ MongoDB.use(refMeta.mongoIdentifier) ( db => {
+ new DBRef(db, refMeta.collectionName, v)
+ })
+ )
+}
+*/
+/*
+ * Trait for creating a Field for storing a "foreign key". Caches the
+ * item after fetching. Versions are available for ObjectId, UUID, String,
+ * Int, and Long. If saveAsDbRef_? is true a DBRef will be saved in the db.
+ *
+ * toForm produces a select form element. You just need to supply the
+ * options by overriding the options method.
+ */
+trait MongoRefField[RefType <: MongoRecord[RefType], MyType] extends TypedField[MyType] {
+
+ /** The MongoMetaRecord of the referenced object **/
+ def refMeta: MongoMetaRecord[RefType]
+
+ /*
+ * Set this to true to save this as a DBRef in Mongo.
+ */
+ def saveAsDbRef_? : Boolean = false
+
+ /*
+ * get the referenced object
+ */
+ def obj = synchronized {
+ if (!_calcedObj) {
+ _calcedObj = true
+ this._obj = valueBox.flatMap(v => refMeta.findAny(v))
+ }
+ _obj
+ }
+
+ def cached_? : Boolean = synchronized { _calcedObj }
+
+ def primeObj(obj: Box[RefType]) = synchronized {
+ _obj = obj
+ _calcedObj = true
+ }
+
+ private var _obj: Box[RefType] = Empty
+ private var _calcedObj = false
+
+ /*
+ * Get the DBRef value that this Field represents.
+ */
+ def dbRef: Box[DBRef] = valueBox.map(v =>
+ MongoDB.use(refMeta.mongoIdentifier) ( db => {
+ new DBRef(db, refMeta.collectionName, v)
+ })
+ )
+
+ /** Options for select list **/
+ def options: List[(Box[MyType], String)] = Nil
+
+ /** Label for the selection item representing Empty, show when this field is optional. Defaults to the empty string. */
+ def emptyOptionLabel: String = ""
+
+ def buildDisplayList: List[(Box[MyType], String)] = {
+ if (optional_?) (Empty, emptyOptionLabel)::options else options
+ }
+
+ private def elem = SHtml.selectObj[Box[MyType]](
+ buildDisplayList,
+ Full(valueBox),
+ setBox(_)
+ ) % ("tabindex" -> tabIndex.toString)
+
+ override def toForm =
+ if (options.length > 0)
+ uniqueFieldId match {
+ case Full(id) => Full(elem % ("id" -> (id + "_field")))
+ case _ => Full(elem)
+ }
+ else
+ Empty
+}
+
+class ObjectIdRefField[OwnerType <: MongoRecord[OwnerType],RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends ObjectIdField[OwnerType](rec)
+ with MongoRefField[RefType, ObjectId]
+{
+ def refMeta = rm
+
+ override def setFromAny(in: Any): Box[ObjectId] = in match {
+ case ref: DBRef => setBox(Full(ref.getId.asInstanceOf[ObjectId]))
+ case Some(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[ObjectId]))
+ case Full(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[ObjectId]))
+ case (ref: DBRef) :: _ => setBox(Full(ref.getId.asInstanceOf[ObjectId]))
+ case x => super.setFromAny(x)
+ }
+}
+
+class UUIDRefField[OwnerType <: MongoRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends UUIDField[OwnerType](rec)
+ with MongoRefField[RefType, UUID]
+{
+ def refMeta = rm
+
+ override def setFromAny(in: Any): Box[UUID] = in match {
+ case ref: DBRef => setBox(Full(ref.getId.asInstanceOf[UUID]))
+ case Some(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[UUID]))
+ case Full(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[UUID]))
+ case (ref: DBRef) :: _ => setBox(Full(ref.getId.asInstanceOf[UUID]))
+ case x => super.setFromAny(x)
+ }
+}
+
+class StringRefField[OwnerType <: MongoRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType], maxLen: Int
+)
+ extends StringField[OwnerType](rec, maxLen)
+ with MongoRefField[RefType, String]
+{
+ def refMeta = rm
+
+ override def setFromAny(in: Any): Box[String] = in match {
+ case ref: DBRef => setBox(Full(ref.getId.asInstanceOf[String]))
+ case Some(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[String]))
+ case Full(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[String]))
+ case (ref: DBRef) :: _ => setBox(Full(ref.getId.asInstanceOf[String]))
+ case x => super.setFromAny(x)
+ }
+}
+
+class IntRefField[OwnerType <: MongoRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends IntField[OwnerType](rec)
+ with MongoRefField[RefType, Int]
+{
+ def refMeta = rm
+
+ override def setFromAny(in: Any): Box[Int] = in match {
+ case ref: DBRef => setBox(Full(ref.getId.asInstanceOf[Int]))
+ case Some(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[Int]))
+ case Full(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[Int]))
+ case (ref: DBRef) :: _ => setBox(Full(ref.getId.asInstanceOf[Int]))
+ case x => super.setFromAny(x)
+ }
+}
+
+class LongRefField[OwnerType <: MongoRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends LongField[OwnerType](rec)
+ with MongoRefField[RefType, Long]
+{
+ def refMeta = rm
+
+ override def setFromAny(in: Any): Box[Long] = in match {
+ case ref: DBRef => setBox(Full(ref.getId.asInstanceOf[Long]))
+ case Some(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[Long]))
+ case Full(ref: DBRef) => setBox(Full(ref.getId.asInstanceOf[Long]))
+ case (ref: DBRef) :: _ => setBox(Full(ref.getId.asInstanceOf[Long]))
+ case x => super.setFromAny(x)
+ }
+}
+
+}
+}
+}
+}
View
77 ...ersistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoSubRecordField.scala
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 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 {
+package field {
+
+import common._
+import http.js.JsExp
+import http.js.JE.JsNull
+import json.JsonAST._
+import json.Printer
+
+import net.liftweb.record._
+import com.mongodb.DBObject
+
+import scala.xml._
+
+/** Field that contains an entire record represented as an inline object value. Inspired by JSONRecord */
+class MongoSubRecordField[OwnerType <: MongoRecord[OwnerType], SubRecordType <: MongoRecord[SubRecordType]]
+ (rec: OwnerType, valueMeta: MongoMetaRecord[SubRecordType])(implicit subRecordType: Manifest[SubRecordType])
+ extends Field[SubRecordType, OwnerType]
+ with MandatoryTypedField[SubRecordType]
+{
+ def this(rec: OwnerType, valueMeta: MongoMetaRecord[SubRecordType], value: SubRecordType)
+ (implicit subRecordType: Manifest[SubRecordType]) = {
+ this(rec, value.meta)
+ set(value)
+ }
+
+ def this(rec: OwnerType, valueMeta: MongoMetaRecord[SubRecordType], value: Box[SubRecordType])
+ (implicit subRecordType: Manifest[SubRecordType]) = {
+ this(rec, valueMeta)
+ setBox(value)
+ }
+
+ def owner = rec
+ def asJs = asJValue match {
+ case JNothing => JsNull
+ case jv => new JsExp {
+ lazy val toJsCmd = Printer.compact(render(jv))
+ }
+ }
+ def toForm: Box[NodeSeq] = Empty
+ def defaultValue = valueMeta.createRecord
+
+ def setFromString(s: String): Box[SubRecordType] = valueMeta.fromJsonString(s)
+
+ def setFromAny(in: Any): Box[SubRecordType] = in match {
+ case dbo: DBObject => setBox(Full(valueMeta.fromDBObject(dbo)))
+ case _ => genericSetFromAny(in)
+ }
+
+ def asJValue: JValue = valueBox.map(_.asJValue) openOr (JNothing: JValue)
+ def setFromJValue(jvalue: JValue): Box[SubRecordType] = jvalue match {
+ case JNothing|JNull if optional_? => setBox(Empty)
+ case _ => setBox(valueMeta.fromJValue(jvalue))
+ }
+}
+}
+}
+}
+}
View
30 ...lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/ObjectIdField.scala
@@ -21,15 +21,16 @@ package field {
import scala.xml.NodeSeq
-import _root_.net.liftweb.common.{Box, Empty, Failure, Full}
-import _root_.net.liftweb.http.js.JE.{JsNull, JsObj, JsRaw, Str}
-import _root_.net.liftweb.http.S
-import _root_.net.liftweb.json.JsonAST._
-import _root_.net.liftweb.json.Printer
-import _root_.net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
-import _root_.net.liftweb.util.Helpers._
+import common.{Box, Empty, Failure, Full}
+import http.js.JE.{JsNull, JsObj, JsRaw, Str}
+import http.S
+import json.JsonAST._
+import json.Printer
+import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
+import util.Helpers._
import org.bson.types.ObjectId
+import com.mongodb.DBRef
/*
* Field for storing an ObjectId
@@ -43,18 +44,7 @@ class ObjectIdField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
def defaultValue = ObjectId.get
- def setFromAny(in: Any): Box[ObjectId] = in match {
- case oid: ObjectId => setBox(Full(oid))
- case Some(oid: ObjectId) => setBox(Full(oid))
- case Full(oid: ObjectId) => setBox(Full(oid))
- case (oid: ObjectId) :: _ => setBox(Full(oid))
- case s: String => setFromString(s)
- case Some(s: String) => setFromString(s)
- case Full(s: String) => setFromString(s)
- case null|None|Empty => setBox(defaultValueBox)
- case f: Failure => setBox(f)
- case o => setFromString(o.toString)
- }
+ def setFromAny(in: Any): Box[ObjectId] = genericSetFromAny(in)
def setFromJValue(jvalue: JValue): Box[ObjectId] = jvalue match {
case JNothing|JNull if optional_? => setBox(Empty)
@@ -70,7 +60,7 @@ class ObjectIdField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
setBox(Failure("Invalid ObjectId string: "+in))
private def elem =
- S.fmapFunc(S.SFuncHolder(this.setFromAny(_))){funcName =>
+ S.fmapFunc(S.SFuncHolder(this.setFromString(_))){funcName =>
<input type="text"
name={funcName}
value={valueBox.map(s => s.toString) openOr ""}
View
15 ...ork/lift-persistence/lift-mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/UUIDField.scala
@@ -29,6 +29,8 @@ import net.liftweb.mongodb.record._
import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField}
import net.liftweb.util.Helpers._
+import com.mongodb.DBRef
+
class UUIDField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
extends Field[UUID, OwnerType]
with MandatoryTypedField[UUID]
@@ -38,18 +40,7 @@ class UUIDField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
def defaultValue = UUID.randomUUID
- def setFromAny(in: Any): Box[UUID] = in match {
- case uid: UUID => setBox(Full(uid))
- case Some(uid: UUID) => setBox(Full(uid))
- case Full(uid: UUID) => setBox(Full(uid))
- case (uid: UUID) :: _ => setBox(Full(uid))
- case s: String => setFromString(s)
- case Some(s: String) => setFromString(s)
- case Full(s: String) => setFromString(s)
- case null|None|Empty => setBox(defaultValueBox)
- case f: Failure => setBox(f)
- case o => setFromString(o.toString)
- }
+ def setFromAny(in: Any): Box[UUID] = genericSetFromAny(in)
def setFromJValue(jvalue: JValue): Box[UUID] = jvalue match {
case JNothing|JNull if optional_? => setBox(Empty)
View
231 framework/lift-persistence/lift-mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
@@ -22,8 +22,10 @@ package fixtures {
import field._
import common.{Box, Empty, Failure, Full}
+import json.JsonAST.JString
import json.ext.JsonBoxSerializer
import util.FieldError
+import util.StringHelpers.randomString
import java.math.MathContext
import scala.xml.Text
@@ -63,13 +65,9 @@ trait HarnessedLifecycleCallbacks extends LifecycleCallbacks {
override def afterDelete = afterDeleteHarness()
}
-class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] with MongoId[FieldTypeTestRecord] {
+class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] with ObjectIdPk[FieldTypeTestRecord] {
def meta = FieldTypeTestRecord
- object mandatoryBinaryField extends BinaryField(this)
- object legacyOptionalBinaryField extends BinaryField(this) { override def optional_? = true }
- object optionalBinaryField extends OptionalBinaryField(this)
-
object mandatoryBooleanField extends BooleanField(this)
object legacyOptionalBooleanField extends BooleanField(this) { override def optional_? = true }
object optionalBooleanField extends OptionalBooleanField(this)
@@ -84,6 +82,7 @@ class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] wi
object optionalDateTimeField extends OptionalDateTimeField(this)
*/
+ // Gets saved in MongoDB with toString
object mandatoryDecimalField extends DecimalField(this, MathContext.UNLIMITED, 2)
object legacyOptionalDecimalField extends DecimalField(this, MathContext.UNLIMITED, 2) { override def optional_? = true }
object optionalDecimalField extends OptionalDecimalField(this, MathContext.UNLIMITED, 2)
@@ -112,8 +111,6 @@ class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] wi
object legacyOptionalLongField extends LongField(this) { override def optional_? = true }
object optionalLongField extends OptionalLongField(this)
- // FIXME would be nice to have some of these PostalCode fields depend on an OptionalCountryField, but the type sig of
- // PostalCodeField does not yet allow it.
object mandatoryPostalCodeField extends PostalCodeField(this, mandatoryCountryField)
object legacyOptionalPostalCodeField extends PostalCodeField(this, mandatoryCountryField) { override def optional_? = true }
object optionalPostalCodeField extends OptionalPostalCodeField(this, mandatoryCountryField)
@@ -132,26 +129,101 @@ class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] wi
override def equals(other: Any): Boolean = other match {
case that:FieldTypeTestRecord =>
- //this.mandatoryBinaryField.value == that.mandatoryBinaryField.value &&
+ this.id.value == that.id.value &&
this.mandatoryBooleanField.value == that.mandatoryBooleanField.value &&
+ this.legacyOptionalBooleanField.valueBox == that.legacyOptionalBooleanField.valueBox &&
+ this.optionalBooleanField.value == that.optionalBooleanField.value &&
this.mandatoryCountryField.value == that.mandatoryCountryField.value &&
+ this.legacyOptionalCountryField.value == that.legacyOptionalCountryField.value &&
+ this.optionalCountryField.value == that.optionalCountryField.value &&
this.mandatoryDecimalField.value == that.mandatoryDecimalField.value &&
+ this.legacyOptionalDecimalField.value == that.legacyOptionalDecimalField.value &&
+ this.optionalDecimalField.value == that.optionalDecimalField.value &&
this.mandatoryDoubleField.value == that.mandatoryDoubleField.value &&
+ this.legacyOptionalDoubleField.value == that.legacyOptionalDoubleField.value &&
+ this.optionalDoubleField.value == that.optionalDoubleField.value &&
this.mandatoryEmailField.value == that.mandatoryEmailField.value &&
+ this.legacyOptionalEmailField.value == that.legacyOptionalEmailField.value &&
+ this.optionalEmailField.value == that.optionalEmailField.value &&
this.mandatoryEnumField.value == that.mandatoryEnumField.value &&
+ this.legacyOptionalEnumField.value == that.legacyOptionalEnumField.value &&
+ this.optionalEnumField.value == that.optionalEnumField.value &&
this.mandatoryIntField.value == that.mandatoryIntField.value &&
+ this.legacyOptionalIntField.value == that.legacyOptionalIntField.value &&
+ this.optionalIntField.value == that.optionalIntField.value &&
this.mandatoryLocaleField.value == that.mandatoryLocaleField.value &&
+ this.legacyOptionalLocaleField.value == that.legacyOptionalLocaleField.value &&
+ this.optionalLocaleField.value == that.optionalLocaleField.value &&
this.mandatoryLongField.value == that.mandatoryLongField.value &&
+ this.legacyOptionalLongField.value == that.legacyOptionalLongField.value &&
+ this.optionalLongField.value == that.optionalLongField.value &&
this.mandatoryPostalCodeField.value == that.mandatoryPostalCodeField.value &&
+ this.legacyOptionalPostalCodeField.value == that.legacyOptionalPostalCodeField.value &&
+ this.optionalPostalCodeField.value == that.optionalPostalCodeField.value &&
this.mandatoryStringField.value == that.mandatoryStringField.value &&
+ this.legacyOptionalStringField.value == that.legacyOptionalStringField.value &&
+ this.optionalStringField.value == that.optionalStringField.value &&
this.mandatoryTextareaField.value == that.mandatoryTextareaField.value &&
- this.mandatoryTimeZoneField.value == that.mandatoryTimeZoneField.value
+ this.legacyOptionalTextareaField.value == that.legacyOptionalTextareaField.value &&
+ this.optionalTextareaField.value == that.optionalTextareaField.value &&
+ this.mandatoryTimeZoneField.value == that.mandatoryTimeZoneField.value &&
+ this.legacyOptionalTimeZoneField.value == that.legacyOptionalTimeZoneField.value &&
+ this.optionalTimeZoneField.value == that.optionalTimeZoneField.value
case _ => false
}
}
-object FieldTypeTestRecord extends FieldTypeTestRecord with MongoMetaRecord[FieldTypeTestRecord]
+object FieldTypeTestRecord extends FieldTypeTestRecord with MongoMetaRecord[FieldTypeTestRecord] {
+ override def formats = allFormats
+}
+
+class BinaryFieldTestRecord extends MongoRecord[BinaryFieldTestRecord] with IntPk[BinaryFieldTestRecord] {
+ def meta = BinaryFieldTestRecord
+
+ object mandatoryBinaryField extends BinaryField(this) {
+ // compare the elements of the Array
+ override def equals(other: Any): Boolean = other match {
+ case that: BinaryField[Any] =>
+ this.value.zip(that.value).filter(t => t._1 != t._2).length == 0
+ case _ => false
+ }
+ }
+ object legacyOptionalBinaryField extends BinaryField(this) {
+ override def optional_? = true
+ // compare the elements of the Array
+ override def equals(other: Any): Boolean = other match {
+ case that: BinaryField[Any] => (this.valueBox, that.valueBox) match {
+ case (Empty, Empty) => true
+ case (Full(a), Full(b)) =>
+ a.zip(b).filter(t => t._1 != t._2).length == 0
+ case _ => false
+ }
+ case _ => false
+ }
+ }
+ object optionalBinaryField extends OptionalBinaryField(this) {
+ // compare the elements of the Array
+ override def equals(other: Any): Boolean = other match {
+ case that: OptionalBinaryField[Any] => (this.valueBox, that.valueBox) match {
+ case (Empty, Empty) => true
+ case (Full(a), Full(b)) =>
+ a.zip(b).filter(t => t._1 != t._2).length == 0
+ case _ => false
+ }
+ case _ => false
+ }
+ }
+ override def equals(other: Any): Boolean = other match {
+ case that:BinaryFieldTestRecord =>
+ this.id.value == that.id.value &&
+ this.mandatoryBinaryField == that.mandatoryBinaryField &&
+ this.legacyOptionalBinaryField == that.legacyOptionalBinaryField &&
+ this.optionalBinaryField == that.optionalBinaryField
+ case _ => false
+ }
+}
+object BinaryFieldTestRecord extends BinaryFieldTestRecord with MongoMetaRecord[BinaryFieldTestRecord]
case class TypeTestJsonObject(
intField: Int,
@@ -163,20 +235,12 @@ case class TypeTestJsonObject(
}
object TypeTestJsonObject extends JsonObjectMeta[TypeTestJsonObject]
-class DBRefTestRecord private () extends MongoRecord[DBRefTestRecord] with MongoId[DBRefTestRecord] {
- def meta = DBRefTestRecord
-}
-object DBRefTestRecord extends DBRefTestRecord with MongoMetaRecord[DBRefTestRecord]
-
-class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTestRecord] with MongoId[MongoFieldTypeTestRecord] {
+class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTestRecord] with ObjectIdPk[MongoFieldTypeTestRecord] {
def meta = MongoFieldTypeTestRecord
object mandatoryDateField extends DateField(this)
object legacyOptionalDateField extends DateField(this) { override def optional_? = true }
- object mandatoryDBRefField extends DBRefField[MongoFieldTypeTestRecord, DBRefTestRecord](this, DBRefTestRecord)
- object legacyOptionalDBRefField extends DBRefField[MongoFieldTypeTestRecord, DBRefTestRecord](this, DBRefTestRecord) { override def optional_? = true }
-
object mandatoryJsonObjectField extends JsonObjectField(this, TypeTestJsonObject) {
def defaultValue = TypeTestJsonObject(0, "")
}
@@ -196,9 +260,8 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
override def equals(other: Any): Boolean = other match {
case that:MongoFieldTypeTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryDateField.value == that.mandatoryDateField.value &&
- //this.mandatoryDBRefField.value.getId == that.mandatoryDBRefField.value.getId &&
- //this.mandatoryDBRefField.value.getRef == that.mandatoryDBRefField.value.getRef &&
this.mandatoryJsonObjectField.value == that.mandatoryJsonObjectField.value &&
this.mandatoryObjectIdField.value == that.mandatoryObjectIdField.value &&
this.mandatoryPatternField.value.pattern == that.mandatoryPatternField.value.pattern &&
@@ -212,14 +275,14 @@ object MongoFieldTypeTestRecord extends MongoFieldTypeTestRecord with MongoMetaR
override def formats = allFormats
}
-class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with MongoId[PasswordTestRecord] {
+class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with ObjectIdPk[PasswordTestRecord] {
def meta = PasswordTestRecord
object password extends MongoPasswordField(this, 3)
}
object PasswordTestRecord extends PasswordTestRecord with MongoMetaRecord[PasswordTestRecord]
-class ListTestRecord private () extends MongoRecord[ListTestRecord] with MongoId[ListTestRecord] {
+class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[ListTestRecord] {
def meta = ListTestRecord
object mandatoryStringListField extends MongoListField[ListTestRecord, String](this)
@@ -231,13 +294,27 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with MongoId
object mandatoryMongoJsonObjectListField extends MongoJsonObjectListField(this, TypeTestJsonObject)
object legacyOptionalMongoJsonObjectListField extends MongoJsonObjectListField(this, TypeTestJsonObject) { override def optional_? = true }
+ object mandatoryMongoSubRecordListField extends MongoSubRecordListField(this, SubRecord) {
+ // compare the elements of the List
+ override def equals(other: Any): Boolean = other match {
+ case that: MongoSubRecordListField[Any, Any] =>
+ this.value.zip(that.value).filter(t => t._1 != t._2).length == 0
+ case _ => false
+ }
+ }
+ object legacyOptionalMongoSubRecordListField extends MongoSubRecordListField(this, SubRecord) {
+ override def optional_? = true
+ }
+
// TODO: More List types
override def equals(other: Any): Boolean = other match {
case that:ListTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryStringListField.value == that.mandatoryStringListField.value &&
this.mandatoryIntListField.value == that.mandatoryIntListField.value &&
- this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value
+ this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value &&
+ this.mandatoryMongoSubRecordListField == that.mandatoryMongoSubRecordListField
case _ => false
}
}
@@ -245,9 +322,11 @@ object ListTestRecord extends ListTestRecord with MongoMetaRecord[ListTestRecord
override def formats = allFormats
}
-class MapTestRecord extends MongoRecord[MapTestRecord] with MongoId[MapTestRecord] {
+class MapTestRecord extends MongoRecord[MapTestRecord] with StringPk[MapTestRecord] {
def meta = MapTestRecord
+ override def defaultIdValue = randomString(12)
+
object mandatoryStringMapField extends MongoMapField[MapTestRecord, String](this)
object legacyOptionalStringMapField extends MongoMapField[MapTestRecord, String](this) { override def optional_? = true }
@@ -258,6 +337,7 @@ class MapTestRecord extends MongoRecord[MapTestRecord] with MongoId[MapTestRecor
override def equals(other: Any): Boolean = other match {
case that:MapTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryStringMapField.value == that.mandatoryStringMapField.value &&
this.mandatoryIntMapField.value == that.mandatoryIntMapField.value
case _ => false
@@ -267,6 +347,103 @@ object MapTestRecord extends MapTestRecord with MongoMetaRecord[MapTestRecord] {
override def formats = allFormats
}
+/*
+ * SubRecord fields
+ */
+class SubRecord extends MongoRecord[SubRecord] with MongoEmbed {
+ def meta = SubRecord
+
+ object name extends StringField(this, 12)
+
+ override def equals(other: Any): Boolean = other match {
+ case that:SubRecord =>
+ this.name.value == that.name.value
+ case _ => false
+ }
+}
+object SubRecord extends SubRecord with MongoMetaRecord[SubRecord] {
+ override def formats = allFormats
+}
+
+class SubRecordTestRecord extends MongoRecord[SubRecordTestRecord] with LongPk[SubRecordTestRecord] {
+ def meta = SubRecordTestRecord
+
+ object mandatoryMongoSubRecordField extends MongoSubRecordField(this, SubRecord)
+ object legacyOptionalMongoSubRecordField extends MongoSubRecordField(this, SubRecord) {
+ override def optional_? = true
+ }
+
+ object mandatoryFieldTypeMongoSubRecordField extends MongoSubRecordField(this, FieldTypeTestRecord)
+ object legacyOptionalFieldTypeMongoSubRecordField extends MongoSubRecordField(this, FieldTypeTestRecord) {
+ override def optional_? = true
+ }
+
+ object mandatoryMongoFieldTypeMongoSubRecordField extends MongoSubRecordField(this, MongoFieldTypeTestRecord)
+ object legacyMongoFieldTypeMongoSubRecordField extends MongoSubRecordField(this, MongoFieldTypeTestRecord) {
+ override def optional_? = true
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case that:SubRecordTestRecord =>
+ this.id.value == that.id.value &&
+ this.mandatoryMongoSubRecordField.value == that.mandatoryMongoSubRecordField.value &&
+ this.legacyOptionalMongoSubRecordField.valueBox == that.legacyOptionalMongoSubRecordField.valueBox &&
+ this.mandatoryFieldTypeMongoSubRecordField.value == that.mandatoryFieldTypeMongoSubRecordField.value &&
+ this.legacyOptionalFieldTypeMongoSubRecordField.valueBox == that.legacyOptionalFieldTypeMongoSubRecordField.valueBox &&
+ this.mandatoryMongoFieldTypeMongoSubRecordField.value == that.mandatoryMongoFieldTypeMongoSubRecordField.value &&
+ this.legacyMongoFieldTypeMongoSubRecordField.valueBox == that.legacyMongoFieldTypeMongoSubRecordField.valueBox
+ case _ => false
+ }
+
+}
+object SubRecordTestRecord extends SubRecordTestRecord with MongoMetaRecord[SubRecordTestRecord] {
+ override def formats = allFormats
+}
+
+/*
+ * MongoRefField
+ */
+class MongoRefTestRecord extends MongoRecord[MongoRefTestRecord] with ObjectIdPk[MongoRefTestRecord] {
+ def meta = MongoRefTestRecord
+
+ object mandatoryObjectIdRefField extends ObjectIdRefField(this, FieldTypeTestRecord)
+ object legacyOptionalObjectIdRefField extends ObjectIdRefField(this, FieldTypeTestRecord) {
+ override def optional_? = true
+ }
+
+ object mandatoryUUIDRefField extends UUIDRefField(this, ListTestRecord)
+ object legacyOptionalUUIDRefField extends UUIDRefField(this, ListTestRecord) {
+ override def optional_? = true
+ }
+}
+object MongoRefTestRecord extends MongoRefTestRecord with MongoMetaRecord[MongoRefTestRecord] {
+ override def formats = allFormats
+}
+
+/*
+ * Legacy DBRefField and MongoId test Record
+ */
+class RefRecord private () extends MongoRecord[RefRecord] with MongoId[RefRecord] {
+ def meta = RefRecord
+}
+object RefRecord extends RefRecord with MongoMetaRecord[RefRecord]
+
+class DBRefTestRecord extends MongoRecord[DBRefTestRecord] with MongoId[DBRefTestRecord] {
+ def meta = DBRefTestRecord
+
+ object mandatoryDBRefField extends DBRefField[DBRefTestRecord, RefRecord](this, RefRecord)
+ object legacyOptionalDBRefField extends DBRefField[DBRefTestRecord, RefRecord](this, RefRecord) { override def optional_? = true }
+
+ override def equals(other: Any): Boolean = other match {
+ case that:DBRefTestRecord =>
+ this._id.value == that._id.value &&
+ this.mandatoryDBRefField.value.getId == that.mandatoryDBRefField.value.getId &&
+ this.mandatoryDBRefField.value.getRef == that.mandatoryDBRefField.value.getRef
+ case _ => false
+ }
+}
+object DBRefTestRecord extends DBRefTestRecord with MongoMetaRecord[DBRefTestRecord]
+
class LifecycleTestRecord private ()
extends MongoRecord[LifecycleTestRecord]
with MongoId[LifecycleTestRecord]
@@ -292,7 +469,7 @@ case class JsonObj(id: String, name: String) extends JsonObject[JsonObj] {
}
object JsonObj extends JsonObjectMeta[JsonObj]
-class NullTestRecord extends MongoRecord[NullTestRecord] with MongoId[NullTestRecord] {
+class NullTestRecord extends MongoRecord[NullTestRecord] with IntPk[NullTestRecord] {
def meta = NullTestRecord
@@ -314,7 +491,7 @@ extends JsonObject[BoxTestJsonObj] {
}
object BoxTestJsonObj extends JsonObjectMeta[BoxTestJsonObj]
-class BoxTestRecord extends MongoRecord[BoxTestRecord] with MongoId[BoxTestRecord] {
+class BoxTestRecord extends MongoRecord[BoxTestRecord] with LongPk[BoxTestRecord] {
def meta = BoxTestRecord
object jsonobj extends JsonObjectField[BoxTestRecord, BoxTestJsonObj](this, BoxTestJsonObj) {
View
83 ...ork/lift-persistence/lift-mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpecs.scala
@@ -45,14 +45,12 @@ class MongoFieldSpecsTest extends JUnit4(MongoFieldSpecs)
object MongoFieldSpecs extends Specification with MongoTestKit {
import fixtures._
- def passBasicTests[A](example: A, mandatory: MandatoryTypedField[A], legacyOptional: MandatoryTypedField[A])(implicit m: scala.reflect.Manifest[A]): Unit = {
- val canCheckDefaultValues =
- !mandatory.defaultValue.isInstanceOf[Date] && // don't try to use the default value of date/time typed fields, because it changes from moment to moment!
- !mandatory.defaultValue.isInstanceOf[ObjectId] && // same with ObjectId
- !mandatory.defaultValue.isInstanceOf[Pattern] &&
- !mandatory.defaultValue.isInstanceOf[UUID] &&
- !mandatory.defaultValue.isInstanceOf[DBRef]
-
+ def passBasicTests[A](
+ example: A,
+ mandatory: MandatoryTypedField[A],
+ legacyOptional: MandatoryTypedField[A],
+ canCheckDefaultValues: Boolean = true
+ )(implicit m: scala.reflect.Manifest[A]): Unit = {
def commonBehaviorsForAllFlavors(in: TypedField[A]): Unit = {
if (canCheckDefaultValues) {
@@ -103,7 +101,9 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
"which correctly fail to be set to Empty" in {
mandatory.valueBox must verify(_.isDefined)
mandatory.setBox(Empty)
- mandatory.valueBox must beLike { case Failure(s, _, _) if s == mandatory.notOptionalErrorMessage => true }
+ mandatory.valueBox must beLike {
+ case Failure(s, _, _) if s == mandatory.notOptionalErrorMessage => true
+ }
}
}
@@ -139,18 +139,22 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
}
}
- def passConversionTests[A](example: A, mandatory: MandatoryTypedField[A], jsexp: JsExp, jvalue: JValue, formPattern: Box[String]): Unit = {
+ def passConversionTests[A](
+ example: A,
+ mandatory: MandatoryTypedField[A],
+ jsexp: JsExp,
+ jvalue: JValue,
+ formPattern: Box[String]
+ ): Unit = {
/*
"convert to JsExp" in {
mandatory.set(example)
- //println(mandatory.asJs)
mandatory.asJs mustEqual jsexp
}*/
"convert to JValue" in {
mandatory.set(example)
- //println(mandatory.asJValue)
mandatory.asJValue mustEqual jvalue
}
@@ -168,7 +172,6 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
val session = new LiftSession("", randomString(20), Empty)
S.initIfUninitted(session) {
val formXml = mandatory.toForm
- //println(formXml)
formXml must notBeEmpty
formXml foreach { f =>
f.toString must beMatching(fp)
@@ -182,7 +185,7 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
val rec = MongoFieldTypeTestRecord.createRecord
val now = new Date
val nowStr = rec.meta.formats.dateFormat.format(now)
- passBasicTests(now, rec.mandatoryDateField, rec.legacyOptionalDateField)
+ passBasicTests(now, rec.mandatoryDateField, rec.legacyOptionalDateField, false) // results in one test skipped
passConversionTests(
now,
rec.mandatoryDateField,
@@ -192,16 +195,18 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
)
}
+/*
"DBRefField" should {
checkMongoIsRunning
-
+
if (isMongoRunning) { // Even if this gets skipped, the vals still get set.
val rec = MongoFieldTypeTestRecord.createRecord
val dbref = DBRefTestRecord.createRecord.getRef // This makes a call to MongoDB.use and needs a MongoDB connection.
- passBasicTests(dbref, rec.mandatoryDBRefField, rec.legacyOptionalDBRefField)
+ passBasicTests(dbref, rec.mandatoryDBRefField, rec.legacyOptionalDBRefField, false)
+ // Does not convert to JValue or JsExp
}
}
-
+*/
"JsonObjectField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val ttjo = TypeTestJsonObject(1, "jsonobj1")
@@ -218,7 +223,7 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
"ObjectIdField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val oid = ObjectId.get
- passBasicTests(oid, rec.mandatoryObjectIdField, rec.legacyOptionalObjectIdField)
+ passBasicTests(oid, rec.mandatoryObjectIdField, rec.legacyOptionalObjectIdField, false)
passConversionTests(
oid,
rec.mandatoryObjectIdField,
@@ -231,7 +236,7 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
"PatternField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val ptrn = Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE)
- passBasicTests(ptrn, rec.mandatoryPatternField, rec.legacyOptionalPatternField)
+ passBasicTests(ptrn, rec.mandatoryPatternField, rec.legacyOptionalPatternField, false)
passConversionTests(
ptrn,
rec.mandatoryPatternField,
@@ -244,7 +249,7 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
"UUIDField" should {
val rec = MongoFieldTypeTestRecord.createRecord
val uuid = UUID.randomUUID
- passBasicTests(uuid, rec.mandatoryUUIDField, rec.legacyOptionalUUIDField)
+ passBasicTests(uuid, rec.mandatoryUUIDField, rec.legacyOptionalUUIDField, false)
passConversionTests(
uuid,
rec.mandatoryUUIDField,
@@ -325,6 +330,29 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
}
}
+ "MongoSubRecordListField" should {
+ val rec = ListTestRecord.createRecord
+ val lst = List(SubRecord.createRecord.name("subrec1"), SubRecord.createRecord.name("subrec2"))
+ passBasicTests(lst, rec.mandatoryMongoSubRecordListField, rec.legacyOptionalMongoSubRecordListField)
+ passConversionTests(
+ lst,
+ rec.mandatoryMongoSubRecordListField,
+ JsArray(
+ JsObj(("name", Str("subrec1"))),
+ JsObj(("name", Str("subrec2")))
+ ),
+ JArray(List(
+ JObject(List(
+ JField("name", JString("subrec1"))
+ )),
+ JObject(List(
+ JField("name", JString("subrec2"))
+ ))
+ )),
+ Empty
+ )
+ }
+
"MongoMapField (String)" should {
"function correctly" in {
val rec = MapTestRecord.createRecord
@@ -362,6 +390,21 @@ object MongoFieldSpecs extends Specification with MongoTestKit {
)
}
}
+
+ "MongoSubRecordField" should {
+ val rec = SubRecordTestRecord.createRecord
+ val subRec = SubRecord.createRecord.name("subrecord")
+ passBasicTests(subRec, rec.mandatoryMongoSubRecordField, rec.legacyOptionalMongoSubRecordField, false)
+ passConversionTests(
+ subRec,
+ rec.mandatoryMongoSubRecordField,
+ JsObj(("name", Str("subrecord"))),
+ JObject(List(
+ JField("name", JString("subrecord"))
+ )),
+ Empty
+ )
+ }
}
}
View
359 ...rk/lift-persistence/lift-mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpecs.scala
@@ -20,6 +20,7 @@ package record {
import common._
import http.js.JE._
+import http.js.JsExp
import json.JsonAST._
import json.Printer
@@ -44,8 +45,8 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
checkMongoIsRunning
val rec = MongoFieldTypeTestRecord.createRecord
- val allExpectedFieldNames: List[String] = "_id" :: (for {
- typeName <- "Date DBRef JsonObject ObjectId Pattern UUID".split(" ")
+ val allExpectedFieldNames: List[String] = "id" :: (for {
+ typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
flavor <- "mandatory legacyOptional".split(" ")
} yield flavor + typeName + "Field").toList
@@ -169,9 +170,14 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
"MongoRecord" should {
checkMongoIsRunning
-
+
+ val binData: Array[Byte] = Array(18, 19, 20)
+ val sr1 = SubRecord.createRecord
+ .name("SubRecord1")
+ val sr2 = SubRecord.createRecord
+ .name("SubRecord2")
+
val fttr = FieldTypeTestRecord.createRecord
- //.mandatoryBinaryField()
.mandatoryBooleanField(false)
.mandatoryCountryField(Countries.USA)
.mandatoryDecimalField(BigDecimal("3.14"))
@@ -186,59 +192,196 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
.mandatoryTextareaField("string")
.mandatoryTimeZoneField("America/Chicago")
+ val bftr = BinaryFieldTestRecord.createRecord
+ .mandatoryBinaryField(binData)
+
+ val ltr = ListTestRecord.createRecord
+ .mandatoryStringListField(List("abc", "def", "ghi"))
+ .mandatoryIntListField(List(4, 5, 6))
+ .mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1"), TypeTestJsonObject(2, "jsonobj2")))
+ .mandatoryMongoSubRecordListField(List(sr1, sr2))
+
val mfttr = MongoFieldTypeTestRecord.createRecord
.mandatoryDateField(new Date)
.mandatoryJsonObjectField(TypeTestJsonObject(1, "jsonobj1"))
- .mandatoryObjectIdField(ObjectId.get)
+ .mandatoryObjectIdField(fttr.id.value)
.mandatoryPatternField(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
- .mandatoryUUIDField(UUID.randomUUID)
-
- /* This causes problems if MongoDB is not running */
+ .mandatoryUUIDField(ltr.id.value)
+
+ /* This causes problems if MongoDB is not running
if (isMongoRunning) {
mfttr.mandatoryDBRefField(DBRefTestRecord.createRecord.getRef)
- }
-
- val ltr = ListTestRecord.createRecord
- .mandatoryStringListField(List("abc", "def", "ghi"))
- .mandatoryIntListField(List(4, 5, 6))
- .mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1"), TypeTestJsonObject(2, "jsonobj2")))
+ }*/
val mtr = MapTestRecord.createRecord
.mandatoryStringMapField(Map("a" -> "abc", "b" -> "def", "c" -> "ghi"))
.mandatoryIntMapField(Map("a" -> 4, "b" -> 5, "c" -> 6))
- val json = "{\"mandatoryDateField\":{\"$dt\":\""+mfttr.meta.formats.dateFormat.format(mfttr.mandatoryDateField.value)+"\"},\"mandatoryJsonObjectField\":{\"intField\":1,\"stringField\":\"jsonobj1\"},\"mandatoryObjectIdField\":{\"$oid\":\""+mfttr.mandatoryObjectIdField.value.toString+"\"},\"mandatoryPatternField\":{\"$regex\":\"^Mo\",\"$flags\":2},\"mandatoryUUIDField\":{\"$uuid\":\""+mfttr.mandatoryUUIDField.value.toString+"\"},\"_id\":{\"$oid\":\""+mfttr.id.toString+"\"}}"
- val ljson = "{\"mandatoryStringListField\":[\"abc\",\"def\",\"ghi\"],\"legacyOptionalStringListField\":[],\"mandatoryIntListField\":[4,5,6],\"legacyOptionalIntListField\":[],\"mandatoryMongoJsonObjectListField\":[{\"intField\":1,\"stringField\":\"jsonobj1\"},{\"intField\":2,\"stringField\":\"jsonobj2\"}],\"legacyOptionalMongoJsonObjectListField\":[],\"_id\":{\"$oid\":\""+ltr.id.toString+"\"}}"
- val mjson = "{\"mandatoryStringMapField\":{\"a\":\"abc\",\"b\":\"def\",\"c\":\"ghi\"},\"legacyOptionalStringMapField\":{},\"mandatoryIntMapField\":{\"a\":4,\"b\":5,\"c\":6},\"legacyOptionalIntMapField\":{},\"_id\":{\"$oid\":\""+mtr.id.toString+"\"}}"
+ val srtr = SubRecordTestRecord.createRecord
+ .mandatoryMongoSubRecordField(sr1)
+ .mandatoryFieldTypeMongoSubRecordField(fttr)
+ .mandatoryMongoFieldTypeMongoSubRecordField(mfttr)
+
+ val ref = RefRecord.createRecord.getRef
+ val dbrtr = DBRefTestRecord.createRecord
+ .mandatoryDBRefField(ref)
+
+ val fttrJson = JObject(List(
+ JField("id", JObject(List(JField("$oid", JString(fttr.id.toString))))),
+ JField("mandatoryBooleanField", JBool(fttr.mandatoryBooleanField.value)),
+ JField("legacyOptionalBooleanField", JNothing),
+ JField("optionalBooleanField", JNothing),
+ JField("mandatoryCountryField", JInt(fttr.mandatoryCountryField.value.id)),
+ JField("legacyOptionalCountryField", JNothing),
+ JField("optionalCountryField", JNothing),
+ JField("mandatoryDecimalField", JString(fttr.mandatoryDecimalField.value.toString)),
+ JField("legacyOptionalDecimalField", JNothing),
+ JField("optionalDecimalField", JNothing),
+ JField("mandatoryDoubleField", JDouble(fttr.mandatoryDoubleField.value)),
+ JField("legacyOptionalDoubleField", JNothing),
+ JField("optionalDoubleField", JNothing),
+ JField("mandatoryEmailField", JString(fttr.mandatoryEmailField.value)),
+ JField("legacyOptionalEmailField", JNothing),
+ JField("optionalEmailField", JNothing),
+ JField("mandatoryEnumField", JInt(fttr.mandatoryEnumField.value.id)),
+ JField("legacyOptionalEnumField", JNothing),
+ JField("optionalEnumField", JNothing),
+ JField("mandatoryIntField", JInt(fttr.mandatoryIntField.value)),
+ JField("legacyOptionalIntField", JNothing),
+ JField("optionalIntField", JNothing),
+ JField("mandatoryLocaleField", JString(fttr.mandatoryLocaleField.value)),
+ JField("legacyOptionalLocaleField", JNothing),
+ JField("optionalLocaleField", JNothing),
+ JField("mandatoryLongField", JInt(fttr.mandatoryLongField.value)),
+ JField("legacyOptionalLongField", JNothing),
+ JField("optionalLongField", JNothing),
+ JField("mandatoryPostalCodeField", JString(fttr.mandatoryPostalCodeField.value)),
+ JField("legacyOptionalPostalCodeField", JNothing),
+ JField("optionalPostalCodeField", JNothing),
+ JField("mandatoryStringField", JString(fttr.mandatoryStringField.value)),
+ JField("legacyOptionalStringField", JNothing),
+ JField("optionalStringField", JNothing),
+ JField("mandatoryTextareaField", JString(fttr.mandatoryTextareaField.value)),
+ JField("legacyOptionalTextareaField", JNothing),
+ JField("optionalTextareaField", JNothing),
+ JField("mandatoryTimeZoneField", JString(fttr.mandatoryTimeZoneField.value)),
+ JField("legacyOptionalTimeZoneField", JNothing),
+ JField("optionalTimeZoneField", JNothing)
+ ))
+
+ val mfttrJson = JObject(List(
+ JField("id", JObject(List(JField("$oid", JString(mfttr.id.toString))))),
+ JField("mandatoryDateField", JObject(List(JField("$dt", JString(mfttr.meta.formats.dateFormat.format(mfttr.mandatoryDateField.value)))))),
+ JField("legacyOptionalDateField", JNothing),
+ JField("mandatoryJsonObjectField", JObject(List(JField("intField", JInt(1)), JField("stringField", JString("jsonobj1"))))),
+ JField("legacyOptionalJsonObjectField", JObject(List(JField("intField", JInt(0)), JField("stringField", JString(""))))),
+ JField("mandatoryObjectIdField", JObject(List(JField("$oid", JString(mfttr.mandatoryObjectIdField.value.toString))))),
+ JField("legacyOptionalObjectIdField", JNothing),
+ JField("mandatoryPatternField", JObject(List(JField("$regex", JString(mfttr.mandatoryPatternField.value.pattern)), JField("$flags", JInt(mfttr.mandatoryPatternField.value.flags))))),
+ JField("legacyOptionalPatternField", JNothing),
+ JField("mandatoryUUIDField", JObject(List(JField("$uuid", JString(mfttr.mandatoryUUIDField.value.toString))))),
+ JField("legacyOptionalUUIDField", JNothing)
+ ))
+
+ val ltrJson = JObject(List(
+ JField("id", JObject(List(JField("$uuid", JString(ltr.id.toString))))),
+ JField("mandatoryStringListField", JArray(List(JString("abc"), JString("def"), JString("ghi")))),
+ JField("legacyOptionalStringListField", JArray(List())),
+ JField("mandatoryIntListField", JArray(List(JInt(4), JInt(5), JInt(6)))),
+ JField("legacyOptionalIntListField", JArray(List())),
+ JField("mandatoryMongoJsonObjectListField", JArray(List(
+ JObject(List(JField("intField", JInt(1)), JField("stringField", JString("jsonobj1")))),
+ JObject(List(JField("intField", JInt(2)), JField("stringField", JString("jsonobj2"))))
+ ))),
+ JField("legacyOptionalMongoJsonObjectListField", JArray(List())),
+ JField("mandatoryMongoSubRecordListField", JArray(List(
+ JObject(List(JField("name", JString("SubRecord1")))),
+ JObject(List(JField("name", JString("SubRecord2"))))
+ ))),
+ JField("legacyOptionalMongoSubRecordListField", JArray(List()))
+ ))
+
+ val mtrJson = JObject(List(
+ JField("id", JString(mtr.id.toString)),
+ JField("mandatoryStringMapField", JObject(List(
+ JField("a", JString("abc")),
+ JField("b", JString("def")),
+ JField("c", JString("ghi"))
+ ))),
+ JField("legacyOptionalStringMapField", JObject(List())),
+ JField("mandatoryIntMapField", JObject(List(
+ JField("a", JInt(4)),
+ JField("b", JInt(5)),
+ JField("c", JInt(6))
+ ))),
+ JField("legacyOptionalIntMapField", JObject(List()))
+ ))
+
+ val srtrJson = JObject(List(
+ JField("id", JInt(srtr.id.value)),
+ JField("mandatoryMongoSubRecordField", JObject(List(JField("name", JString("SubRecord1"))))),
+ JField("legacyOptionalMongoSubRecordField", JNothing),
+ JField("mandatoryFieldTypeMongoSubRecordField", fttrJson),
+ JField("legacyOptionalFieldTypeMongoSubRecordField", JNothing),
+ JField("mandatoryMongoFieldTypeMongoSubRecordField", mfttrJson),
+ JField("legacyMongoFieldTypeMongoSubRecordField", JNothing)
+ ))
+
+ "save and retrieve 'standard' type fields with Empty optional fields" in {
+ checkMongoIsRunning
+
+ fttr.save
+
+ val fttrFromDb = FieldTypeTestRecord.find(fttr.id.value)
+ fttrFromDb must notBeEmpty
+ fttrFromDb foreach { tr =>
+ tr mustEqual fttr
+ }
+ }
- "save and retrieve 'standard' type fields" in {
+ "save and retrieve 'standard' type fields with Full optional fields" in {
checkMongoIsRunning
fttr.save
- val fttrFromDb = FieldTypeTestRecord.find(fttr.id)
+ val fttrFromDb = FieldTypeTestRecord.find(fttr.id.value)
fttrFromDb must notBeEmpty
fttrFromDb foreach { tr =>
tr mustEqual fttr
}
}
+ "delete 'standard' type fields" in {
+ checkMongoIsRunning
+
+ fttr.save
+ FieldTypeTestRecord.find(fttr.id.value) must notBeEmpty
+ fttr.delete_!
+ FieldTypeTestRecord.find(fttr.id.value) must beEmpty
+ }
+
"save and retrieve Mongo type fields" in {
checkMongoIsRunning
mfttr.save
- val mfttrFromDb = MongoFieldTypeTestRecord.find(mfttr.id)
+ val mfttrFromDb = MongoFieldTypeTestRecord.find(mfttr.id.value)
mfttrFromDb must notBeEmpty
mfttrFromDb foreach { tr =>
- tr.mandatoryDBRefField.value.getId mustEqual mfttr.mandatoryDBRefField.value.getId
- tr.mandatoryDBRefField.value.getRef mustEqual mfttr.mandatoryDBRefField.value.getRef
tr mustEqual mfttr
}
+ bftr.save
+
+ val bftrFromDb = BinaryFieldTestRecord.find(bftr.id.value)
+ bftrFromDb must notBeEmpty
+ bftrFromDb foreach { tr =>
+ tr mustEqual bftr
+ }
+
ltr.save
- val ltrFromDb = ListTestRecord.find(ltr.id)
+ val ltrFromDb = ListTestRecord.find(ltr.id.value)
ltrFromDb must notBeEmpty
ltrFromDb foreach { tr =>
tr mustEqual ltr
@@ -246,73 +389,101 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
mtr.save
- val mtrFromDb = MapTestRecord.find(mtr.id)
+ val mtrFromDb = MapTestRecord.find(mtr.id.value)
mtrFromDb must notBeEmpty
mtrFromDb foreach { tr =>
tr mustEqual mtr
}
+
+ srtr.save
+
+ val srtrFromDb = SubRecordTestRecord.find(srtr.id.value)
+ srtrFromDb must notBeEmpty
+ srtrFromDb foreach { tr =>
+ tr mustEqual srtr
+ }
+
+ dbrtr.save
+
+ val dbrtrFromDb = DBRefTestRecord.find(dbrtr.id)
+ dbrtrFromDb must notBeEmpty
+ dbrtrFromDb foreach { tr =>
+ tr mustEqual dbrtr
+ }
+ }
+
+ "delete Mongo type fields" in {
+ checkMongoIsRunning
+
+ mfttr.save
+ MongoFieldTypeTestRecord.find(mfttr.id.value) must notBeEmpty
+ mfttr.delete_!
+ MongoFieldTypeTestRecord.find(mfttr.id.value) must beEmpty
+
+ bftr.save
+ BinaryFieldTestRecord.find(bftr.id.value) must notBeEmpty
+ bftr.delete_!
+ BinaryFieldTestRecord.find(bftr.id.value) must beEmpty
+
+ ltr.save
+ ListTestRecord.find(ltr.id.value) must notBeEmpty
+ ltr.delete_!
+ ListTestRecord.find(ltr.id.value) must beEmpty
+
+ mtr.save
+ MapTestRecord.find(mtr.id.value) must notBeEmpty
+ mtr.delete_!
+ MapTestRecord.find(mtr.id.value) must beEmpty
+
+ srtr.save
+ SubRecordTestRecord.find(srtr.id.value) must notBeEmpty
+ srtr.delete_!
+ SubRecordTestRecord.find(srtr.id.value) must beEmpty
+
+ dbrtr.save
+ DBRefTestRecord.find(dbrtr.id) must notBeEmpty
+ dbrtr.delete_!
+ DBRefTestRecord.find(dbrtr.id) must beEmpty
+ }
+
+ "convert 'standard' type fields to JValue" in {
+ fttr.asJValue mustEqual fttrJson
}
"convert Mongo type fields to JValue" in {
checkMongoIsRunning
- mfttr.asJValue mustEqual JObject(List(
- JField("_id", JObject(List(JField("$oid", JString(mfttr.id.toString))))),
- JField("mandatoryDateField", JObject(List(JField("$dt", JString(mfttr.meta.formats.dateFormat.format(mfttr.mandatoryDateField.value)))))),
- JField("legacyOptionalDateField", JNothing),
- JField("mandatoryDBRefField", JNothing),
- JField("legacyOptionalDBRefField", JNothing),
- JField("mandatoryJsonObjectField", JObject(List(JField("intField", JInt(1)), JField("stringField", JString("jsonobj1"))))),
- JField("legacyOptionalJsonObjectField", JObject(List(JField("intField", JInt(0)), JField("stringField", JString(""))))),
- JField("mandatoryObjectIdField", JObject(List(JField("$oid", JString(mfttr.mandatoryObjectIdField.value.toString))))),
- JField("legacyOptionalObjectIdField", JNothing),
- JField("mandatoryPatternField", JObject(List(JField("$regex", JString(mfttr.mandatoryPatternField.value.pattern)), JField("$flags", JInt(mfttr.mandatoryPatternField.value.flags))))),
- JField("legacyOptionalPatternField", JNothing),
- JField("mandatoryUUIDField", JObject(List(JField("$uuid", JString(mfttr.mandatoryUUIDField.value.toString))))),
- JField("legacyOptionalUUIDField", JNothing)
- ))
+ mfttr.asJValue mustEqual mfttrJson
- ltr.asJValue mustEqual JObject(List(
- JField("_id", JObject(List(JField("$oid", JString(ltr.id.toString))))),
- JField("mandatoryStringListField", JArray(List(JString("abc"), JString("def"), JString("ghi")))),
- JField("legacyOptionalStringListField", JArray(List())),
- JField("mandatoryIntListField", JArray(List(JInt(4), JInt(5), JInt(6)))),
- JField("legacyOptionalIntListField", JArray(List())),
- JField("mandatoryMongoJsonObjectListField", JArray(List(
- JObject(List(JField("intField", JInt(1)), JField("stringField", JString("jsonobj1")))),
- JObject(List(JField("intField", JInt(2)), JField("stringField", JString("jsonobj2"))))
- ))),
- JField("legacyOptionalMongoJsonObjectListField", JArray(List()))
- ))
+ ltr.asJValue mustEqual ltrJson
+
+ mtr.asJValue mustEqual mtrJson
- mtr.asJValue mustEqual JObject(List(
- JField("_id", JObject(List(JField("$oid", JString(mtr.id.toString))))),
- JField("_id", JObject(List(JField("$oid", JString(mtr.id.toString))))),
- JField("mandatoryStringMapField", JObject(List(
- JField("a", JString("abc")),
- JField("b", JString("def")),
- JField("c", JString("ghi"))
- ))),
- JField("legacyOptionalStringMapField", JObject(List())),
- JField("mandatoryIntMapField", JObject(List(
- JField("a", JInt(4)),
- JField("b", JInt(5)),
- JField("c", JInt(6))
- ))),
- JField("legacyOptionalIntMapField", JObject(List()))
+ val srtrAsJValue = srtr.asJValue
+ srtrAsJValue \\ "id" mustEqual srtrJson \\ "id"
+ srtrAsJValue \\ "mandatoryMongoSubRecordField" mustEqual srtrJson \\ "mandatoryMongoSubRecordField"
+ srtrAsJValue \\ "legacyOptionalMongoSubRecordField" mustEqual srtrJson \\ "legacyOptionalMongoSubRecordField"
+ srtrAsJValue \\ "mandatoryFieldTypeMongoSubRecordField" mustEqual srtrJson \\ "mandatoryFieldTypeMongoSubRecordField"
+ srtrAsJValue \\ "legacyOptionalFieldTypeMongoSubRecordField" mustEqual srtrJson \\ "legacyOptionalFieldTypeMongoSubRecordField"
+ srtrAsJValue \\ "mandatoryMongoFieldTypeMongoSubRecordField" mustEqual srtrJson \\ "mandatoryMongoFieldTypeMongoSubRecordField"
+ srtrAsJValue \\ "legacyMongoFieldTypeMongoSubRecordField" mustEqual srtrJson \\ "legacyMongoFieldTypeMongoSubRecordField"
+ //srtr.asJValue mustEqual srtrJson // The fields don't seem to be in the same order, but they are equal when compared individually.
+
+ dbrtr.asJValue mustEqual JObject(List(
+ JField("_id", JString(dbrtr.id.toString)),
+ JField("mandatoryDBRefField", JNothing),
+ JField("legacyOptionalDBRefField", JNothing)
))
}
-
+
"convert Mongo type fields to JsExp" in {
checkMongoIsRunning
/*
mfttr.asJsExp mustEqual JsObj(
- ("_id", JsObj(("$oid", Str(mfttr.id.toString)))),
+ ("id", JsObj(("$oid", Str(mfttr.id.toString)))),
("mandatoryDateField", JsObj(("$dt", Str(mfttr.meta.formats.dateFormat.format(mfttr.mandatoryDateField.value))))),
("legacyOptionalDateField", Str("null")),
- ("mandatoryDBRefField", Str("null")),
- ("legacyOptionalDBRefField", Str("null")),
("mandatoryJsonObjectField", JsObj(("intField", Num(1)), ("stringField", Str("jsonobj1")))),
("legacyOptionalJsonObjectField", JsObj(("intField", Num(0)), ("stringField", Str("")))),
("mandatoryObjectIdField", JsObj(("$oid", Str(mfttr.mandatoryObjectIdField.value.toString)))),
@@ -325,7 +496,7 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
/*
ltr.asJsExp mustEqual JsObj(
- ("_id", JsObj(("$oid", Str(ltr.id.toString)))),
+ ("id", JsObj(("$oid", Str(ltr.id.toString)))),
("mandatoryStringListField", JsArray(Str("abc"), Str("def"), Str("ghi"))),
("legacyOptionalStringListField", JsArray()),
("mandatoryIntListField", JsArray(Num(4), Num(5), Num(6))),
@@ -334,12 +505,15 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
JsObj(("intField", Num(1)), ("stringField", Str("jsonobj1"))),
JsObj(("intField", Num(2)), ("stringField", Str("jsonobj2")))
)),
- ("legacyOptionalMongoJsonObjectListField", JsArray())
+ ("legacyOptionalMongoJsonObjectListField", JsArray()),
+ ("mandatoryMongoSubRecordListField", JsArray(
+ JsObj(("name", Str("SubRecord1"))),
+ JsObj(("name", Str("SubRecord2")))
+ ))
)
mtr.asJsExp mustEqual JsObj(
- ("_id", JsObj(("$oid", Str(mtr.id.toString)))),
- ("_id", JsObj(("$oid", Str(mtr.id.toString)))),
+ ("id", JsObj(("$oid", Str(mtr.id.toString)))),
("mandatoryStringMapField", JsObj(
("a", Str("abc")),
("b", Str("def")),
@@ -352,33 +526,52 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
("c", Num(6))
)),
("legacyOptionalIntMapField", JsObj())
- )*/
+ )
+
+ srtr.asJsExp mustEqual new JsExp {
+ lazy val toJsCmd = Printer.compact(render(srtrJson))
+ }
+ dbrtr.asJsExp mustEqual JsObj(
+ ("_id", Str(dbrtr.id.toString)),
+ ("mandatoryDBRefField", Str("null")),
+ ("legacyOptionalDBRefField", Str("null"))
+ )*/
}
"get set from json string using lift-json parser" in {
checkMongoIsRunning
-
- val mfftrFromJson = MongoFieldTypeTestRecord.fromJsonString(json)
+ val mfftrFromJson = MongoFieldTypeTestRecord.fromJsonString(Printer.compact(render(mfttrJson)))
mfftrFromJson must notBeEmpty
mfftrFromJson foreach { tr =>
tr mustEqual mfttr
}
- val ltrFromJson = ListTestRecord.fromJsonString(ljson)
+ val ltrFromJson = ListTestRecord.fromJsonString(Printer.compact(render(ltrJson)))
ltrFromJson must notBeEmpty
ltrFromJson foreach { tr =>
tr mustEqual ltr
}
- val mtrFromJson = MapTestRecord.fromJsonString(mjson)
+ val mtrFromJson = MapTestRecord.fromJsonString(Printer.compact(render(mtrJson)))
mtrFromJson must notBeEmpty
mtrFromJson foreach { tr =>
tr mustEqual mtr
}
}
- "handle null" in {
+ /*
+ "retrieve MongoRef objects properly" in {
+ fttr.save
+ ltr.save
+ mfttr.save
+
+ mfttr.mandatoryObjectIdField.obj mustEqual Full(fttr)
+ mfttr.mandatoryUUIDField.obj mustEqual Full(ltr)
+ }
+ */
+
+ "handle null properly" in {
checkMongoIsRunning
val ntr = NullTestRecord.createRecord
@@ -387,7 +580,7 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
ntr.save must_== ntr
- val ntrFromDb = NullTestRecord.find(ntr.id)
+ val ntrFromDb = NullTestRecord.find(ntr.id.value)
ntrFromDb must notBeEmpty
@@ -409,7 +602,7 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
}
}
- "handle Box using JsonBoxSerializer" in {
+ "handle Box using JsonBoxSerializer properly" in {
checkMongoIsRunning
val btr = BoxTestRecord.createRecord
@@ -421,7 +614,7 @@ object MongoRecordSpecs extends Specification with MongoTestKit {
btr.save
- val btrFromDb = BoxTestRecord.find(btr.id)
+ val btrFromDb = BoxTestRecord.find(btr.id.value)
btrFromDb must notBeEmpty
View
2  framework/lift-persistence/lift-mongodb/src/main/scala/net/liftweb/mongodb/JsonObject.scala
@@ -58,4 +58,4 @@ case class MongoRef(ref: String, id: ObjectId)
}
-}
+}
View
64 framework/lift-persistence/lift-record/src/main/scala/net/liftweb/record/field/ChoiceField.scala
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2007-2010 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
+ *