Skip to content
Browse files

Issue 1125 - Add MongoRefListField

  • Loading branch information...
1 parent f4b8461 commit 7805a44cdd21e365f64f5c584cc24a65e81612f1 @eltimn eltimn committed
View
6 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
@@ -222,13 +222,15 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
/**
* Find all documents with the given ids
*/
- def findAll(ids: List[ObjectId]): List[BaseRecord] = if (ids.isEmpty) Nil else {
- val list = new java.util.ArrayList[ObjectId]()
+ def findAllByList[T](ids: List[T]): List[BaseRecord] = if (ids.isEmpty) Nil else {
+ val list = new java.util.ArrayList[T]()
for (id <- ids.distinct) list.add(id)
val query = QueryBuilder.start("_id").in(list).get()
findAll(query)
}
+ def findAll(ids: List[ObjectId]): List[BaseRecord] = findAllByList[ObjectId](ids)
+
protected def saveOp(inst: BaseRecord)(f: => Unit): Boolean = {
foreachCallback(inst, _.beforeSave)
f
View
2 ...ence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/BsonRecordField.scala
@@ -76,7 +76,7 @@ class BsonRecordField[OwnerType <: BsonRecord[OwnerType], SubRecordType <: BsonR
* List of BsonRecords
*/
class BsonRecordListField[OwnerType <: BsonRecord[OwnerType], SubRecordType <: BsonRecord[SubRecordType]]
- (rec: OwnerType, valueMeta: BsonMetaRecord[SubRecordType])
+ (rec: OwnerType, valueMeta: BsonMetaRecord[SubRecordType])(implicit mf: Manifest[SubRecordType])
extends MongoListField[OwnerType, SubRecordType](rec: OwnerType) {
import scala.collection.JavaConversions._
View
47 ...tence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoListField.scala
@@ -27,9 +27,10 @@ import scala.xml.NodeSeq
import common.{Box, Empty, Failure, Full}
import json.JsonAST._
import json.JsonParser
+import http.SHtml
import http.js.JE.{JsNull, JsRaw}
import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
-import util.Helpers.tryo
+import util.Helpers._
import com.mongodb._
import org.bson.types.ObjectId
@@ -38,24 +39,27 @@ import org.bson.types.ObjectId
* List field. Compatible with most object types,
* including Pattern, ObjectId, Date, and UUID.
*/
-class MongoListField[OwnerType <: BsonRecord[OwnerType], ListType](rec: OwnerType)
+class MongoListField[OwnerType <: BsonRecord[OwnerType], ListType: Manifest](rec: OwnerType)
extends Field[List[ListType], OwnerType]
with MandatoryTypedField[List[ListType]]
with MongoFieldFlavor[List[ListType]]
{
-
import Meta.Reflection._
+ lazy val mf = manifest[ListType]
+
+ override type MyType = List[ListType]
+
def owner = rec
def defaultValue = List[ListType]()
- def setFromAny(in: Any): Box[List[ListType]] = {
+ def setFromAny(in: Any): Box[MyType] = {
in match {
case dbo: DBObject => setFromDBObject(dbo)
- case list: List[ListType] => setBox(Full(list))
- case Some(list: List[ListType]) => setBox(Full(list))
- case Full(list: List[ListType]) => setBox(Full(list))
+ case list@c::xs if mf.erasure.isInstance(c) => setBox(Full(list.asInstanceOf[MyType]))
+ case Some(list@c::xs) if mf.erasure.isInstance(c) => setBox(Full(list.asInstanceOf[MyType]))
+ case Full(list@c::xs) if mf.erasure.isInstance(c) => setBox(Full(list.asInstanceOf[MyType]))
case s: String => setFromString(s)
case Some(s: String) => setFromString(s)
case Full(s: String) => setFromString(s)
@@ -78,7 +82,28 @@ class MongoListField[OwnerType <: BsonRecord[OwnerType], ListType](rec: OwnerTyp
case other => setBox(Failure("Error parsing String into a JValue: "+in))
}
- def toForm: Box[NodeSeq] = Empty
+ /*
+ * MongoListField is built on MandatoryField, so optional_? is always false. It would be nice to use optional to differentiate
+ * between a list that requires at least one item and a list that can be empty.
+ */
+
+ /** Options for select list **/
+ def options: List[(ListType, String)] = Nil
+
+ private def elem = SHtml.multiSelectObj[ListType](
+ options,
+ value,
+ set(_)
+ ) % ("tabindex" -> tabIndex.toString)
+
+ def toForm: Box[NodeSeq] =
+ if (options.length > 0)
+ uniqueFieldId match {
+ case Full(id) => Full(elem % ("id" -> id))
+ case _ => Full(elem)
+ }
+ else
+ Empty
def asJValue = JArray(value.map(li => li.asInstanceOf[AnyRef] match {
case x if primitive_?(x.getClass) => primitive2jvalue(x)
@@ -105,8 +130,8 @@ class MongoListField[OwnerType <: BsonRecord[OwnerType], ListType](rec: OwnerTyp
}
// 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]]))
+ def setFromDBObject(dbo: DBObject): Box[MyType] =
+ setBox(Full(dbo.asInstanceOf[BasicDBList].toList.asInstanceOf[MyType]))
}
/*
@@ -121,7 +146,7 @@ class MongoDateListField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
* List of JsonObject case classes
*/
class MongoJsonObjectListField[OwnerType <: BsonRecord[OwnerType], JObjectType <: JsonObject[JObjectType]]
- (rec: OwnerType, valueMeta: JsonObjectMeta[JObjectType])
+ (rec: OwnerType, valueMeta: JsonObjectMeta[JObjectType])(implicit mf: Manifest[JObjectType])
extends MongoListField[OwnerType, JObjectType](rec: OwnerType) {
override def asDBObject: DBObject = {
View
45 ...stence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoRefField.scala
@@ -90,46 +90,21 @@ trait MongoRefField[RefType <: MongoRecord[RefType], MyType] extends TypedField[
}
class ObjectIdRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
- rec: OwnerType, rm: MongoMetaRecord[RefType]
-)
- extends ObjectIdField[OwnerType](rec)
- with MongoRefField[RefType, ObjectId]
-{
- def refMeta = rm
-}
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends ObjectIdField[OwnerType](rec) with MongoRefField[RefType, ObjectId] {}
class UUIDRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
- rec: OwnerType, rm: MongoMetaRecord[RefType]
-)
- extends UUIDField[OwnerType](rec)
- with MongoRefField[RefType, UUID]
-{
- def refMeta = rm
-}
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends UUIDField[OwnerType](rec) with MongoRefField[RefType, UUID] {}
class StringRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
- rec: OwnerType, rm: MongoMetaRecord[RefType], maxLen: Int
-)
- extends StringField[OwnerType](rec, maxLen)
- with MongoRefField[RefType, String]
-{
- def refMeta = rm
-}
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType], maxLen: Int
+) extends StringField[OwnerType](rec, maxLen) with MongoRefField[RefType, String] {}
class IntRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
- rec: OwnerType, rm: MongoMetaRecord[RefType]
-)
- extends IntField[OwnerType](rec)
- with MongoRefField[RefType, Int]
-{
- def refMeta = rm
-}
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends IntField[OwnerType](rec) with MongoRefField[RefType, Int] {}
class LongRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
- rec: OwnerType, rm: MongoMetaRecord[RefType]
-)
- extends LongField[OwnerType](rec)
- with MongoRefField[RefType, Long]
-{
- def refMeta = rm
-}
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends LongField[OwnerType](rec) with MongoRefField[RefType, Long] {}
View
84 ...ce/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoRefListField.scala
@@ -0,0 +1,84 @@
+/*
+ * 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
+package field
+
+import common._
+import http.{S, SHtml}
+import net.liftweb.record.{Field, MandatoryTypedField, TypedField}
+
+import java.util.UUID
+
+import org.bson.types.ObjectId
+
+/*
+ * Trait for creating a Field for storing a list of "foreign keys". Caches the
+ * items after fetching. Implementations are available for ObjectId, UUID, String,
+ * Int, and Long, but you can extend this.
+ *
+ * toForm produces a multi-select form element. You just need to supply the
+ * options by overriding the options method.
+ */
+abstract class MongoRefListField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType], MyType]
+ (rec: OwnerType)(implicit mf: Manifest[MyType]) extends MongoListField[OwnerType, MyType](rec) {
+
+ /** The MongoMetaRecord of the referenced object **/
+ def refMeta: MongoMetaRecord[RefType]
+
+ /*
+ * get the referenced objects
+ */
+ def objs = synchronized {
+ if (!_calcedObjs) {
+ _calcedObjs = true
+ this._objs = refMeta.findAllByList(this.value)
+ }
+ _objs
+ }
+
+ def cached_? : Boolean = synchronized { _calcedObjs }
+
+ def primeObjs(objs: List[RefType]) = synchronized {
+ _objs = objs
+ _calcedObjs = true
+ }
+
+ private var _objs: List[RefType] = Nil
+ private var _calcedObjs = false
+}
+
+class ObjectIdRefListField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends MongoRefListField[OwnerType, RefType, ObjectId](rec) {}
+
+class UUIDRefListField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends MongoRefListField[OwnerType, RefType, UUID](rec) {}
+
+class StringRefListField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends MongoRefListField[OwnerType, RefType, String](rec) {}
+
+class IntRefListField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends MongoRefListField[OwnerType, RefType, Int](rec) {}
+
+class LongRefListField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, val refMeta: MongoMetaRecord[RefType]
+) extends MongoRefListField[OwnerType, RefType, Long](rec) {}
View
15 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
@@ -23,6 +23,7 @@ import field._
import common.{Box, Empty, Failure, Full}
import json.ext.JsonBoxSerializer
+import http.SHtml
import util.FieldError
import java.math.MathContext
@@ -31,6 +32,8 @@ import scala.xml.Text
import net.liftweb.record._
import net.liftweb.record.field._
+import org.bson.types.ObjectId
+
object MyTestEnum extends Enumeration {
val ONE = Value("ONE")
val TWO = Value("TWO")
@@ -156,7 +159,7 @@ class BinaryFieldTestRecord extends MongoRecord[BinaryFieldTestRecord] with IntP
object mandatoryBinaryField extends BinaryField(this) {
// compare the elements of the Array
override def equals(other: Any): Boolean = other match {
- case that: BinaryField[Any] =>
+ case that: BinaryField[_] =>
this.value.zip(that.value).filter(t => t._1 != t._2).length == 0
case _ => false
}
@@ -165,7 +168,7 @@ class BinaryFieldTestRecord extends MongoRecord[BinaryFieldTestRecord] with IntP
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 that: BinaryField[_] => (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
@@ -177,7 +180,7 @@ class BinaryFieldTestRecord extends MongoRecord[BinaryFieldTestRecord] with IntP
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 that: OptionalBinaryField[_] => (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
@@ -453,6 +456,12 @@ class RefFieldTestRecord private () extends MongoRecord[RefFieldTestRecord] with
object mandatoryStringRefField extends StringRefField(this, MapTestRecord, 100)
object mandatoryIntRefField extends IntRefField(this, NullTestRecord)
object mandatoryLongRefField extends LongRefField(this, BoxTestRecord)
+
+ object mandatoryObjectIdRefListField extends ObjectIdRefListField(this, FieldTypeTestRecord)
+ object mandatoryUUIDRefListField extends UUIDRefListField(this, ListTestRecord)
+ object mandatoryStringRefListField extends StringRefListField(this, MapTestRecord)
+ object mandatoryIntRefListField extends IntRefListField(this, NullTestRecord)
+ object mandatoryLongRefListField extends LongRefListField(this, BoxTestRecord)
}
object RefFieldTestRecord extends RefFieldTestRecord with MongoMetaRecord[RefFieldTestRecord] {
View
11 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
@@ -541,12 +541,23 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
.mandatoryStringRefField(mtr.id.is)
.mandatoryIntRefField(ntr.id.is)
.mandatoryLongRefField(btr.id.is)
+ .mandatoryObjectIdRefListField(List(fttr.id.is))
+ .mandatoryUUIDRefListField(List(ltr.id.is))
+ .mandatoryStringRefListField(List(mtr.id.is))
+ .mandatoryIntRefListField(List(ntr.id.is))
+ .mandatoryLongRefListField(List(btr.id.is))
rftr.mandatoryObjectIdRefField.obj mustEqual Full(fttr)
rftr.mandatoryUUIDRefField.obj mustEqual Full(ltr)
rftr.mandatoryStringRefField.obj mustEqual Full(mtr)
rftr.mandatoryIntRefField.obj mustEqual Full(ntr)
rftr.mandatoryLongRefField.obj mustEqual Full(btr)
+
+ rftr.mandatoryObjectIdRefListField.objs mustEqual List(fttr)
+ rftr.mandatoryUUIDRefListField.objs mustEqual List(ltr)
+ rftr.mandatoryStringRefListField.objs mustEqual List(mtr)
+ rftr.mandatoryIntRefListField.objs mustEqual List(ntr)
+ rftr.mandatoryLongRefListField.objs mustEqual List(btr)
}
}

0 comments on commit 7805a44

Please sign in to comment.
Something went wrong with that request. Please try again.