Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'irc_wip_290' of github.com:lift/framework into irc_wip_290

  • Loading branch information...
commit 77ce071b9a1d750e9cb39cbe614b84595a6e4778 2 parents b9cfc4c + 0bdae65
Naftoli authored
Showing with 1,183 additions and 510 deletions.
  1. +9 −0 core/common/src/main/scala/net/liftweb/common/Box.scala
  2. +9 −1 core/json-ext/src/main/scala/net/liftweb/json/ext/JodaTimeSerializer.scala
  3. +3 −3 core/json-ext/src/test/scala/net/liftweb/json/ext/JodaTimeSerializerSpec.scala
  4. +1 −1  core/json/README.md
  5. +2 −1  core/json/src/main/scala/net/liftweb/json/Extraction.scala
  6. +31 −13 core/json/src/main/scala/net/liftweb/json/Meta.scala
  7. +3 −2 core/json/src/test/scala/net/liftweb/json/FieldSerializerBugs.scala
  8. +24 −0 core/json/src/test/scala/net/liftweb/json/SerializationBugs.scala
  9. +8 −0 core/json/src/test/scala/net/liftweb/json/SerializationExamples.scala
  10. +4 −0 core/util/src/main/scala/net/liftweb/util/BindHelpers.scala
  11. +21 −12 core/util/src/main/scala/net/liftweb/util/Mailer.scala
  12. +1 −2  ...tence/mapper/src/main/scala/net/liftweb/mapper → core/util/src/main/scala/net/liftweb/util}/Safe.scala
  13. +1 −1  core/util/src/test/scala/net/liftweb/util/BindHelpersSpec.scala
  14. +6 −3 persistence/db/src/main/scala/net/liftweb/db/DB.scala
  15. +0 −1  persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPassword.scala
  16. +4 −1 persistence/mapper/src/main/scala/net/liftweb/mapper/package.scala
  17. +20 −3 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
  18. +7 −3 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
  19. +2 −2 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/BsonRecordField.scala
  20. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/DBRefField.scala
  21. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/DateField.scala
  22. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JsonObjectField.scala
  23. +5 −4 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoListField.scala
  24. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoMapField.scala
  25. +2 −3 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoPasswordField.scala
  26. +110 −0 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoPk.scala
  27. +135 −0 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoRefField.scala
  28. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/ObjectIdField.scala
  29. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/PatternField.scala
  30. +1 −1  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/UUIDField.scala
  31. +2 −2 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/CustomSerializersSpec.scala
  32. +80 −41 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
  33. +127 −35 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
  34. +202 −136 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
  35. +2 −5 persistence/mongodb/src/main/scala/net/liftweb/mongodb/JObjectParser.scala
  36. +48 −42 persistence/mongodb/src/test/scala/net/liftweb/mongodb/MongoDocumentSpec.scala
  37. +7 −7 persistence/mongodb/src/test/scala/net/liftweb/mongodb/MongoSpec.scala
  38. +34 −13 persistence/proto/src/main/scala/net/liftweb/proto/ProtoUser.scala
  39. +2 −2 persistence/record/src/main/scala/net/liftweb/record/DBMetaRecord.scala
  40. +2 −3 persistence/record/src/main/scala/net/liftweb/record/DBRecord.scala
  41. +22 −3 persistence/record/src/main/scala/net/liftweb/record/Field.scala
  42. +5 −22 persistence/record/src/main/scala/net/liftweb/record/MetaRecord.scala
  43. +0 −1  persistence/record/src/main/scala/net/liftweb/record/Record.scala
  44. +1 −1  persistence/record/src/main/scala/net/liftweb/record/field/EnumField.scala
  45. +0 −2  persistence/record/src/main/scala/net/liftweb/record/field/PasswordField.scala
  46. +0 −1  persistence/record/src/main/scala/net/liftweb/record/field/PostalCodeField.scala
  47. +21 −8 persistence/record/src/test/scala/net/liftweb/record/Fixtures.scala
  48. +5 −2 persistence/record/src/test/scala/net/liftweb/record/RecordSpec.scala
  49. +4 −4 persistence/squeryl-record/src/main/scala/net/liftweb/squerylrecord/SquerylRecord.scala
  50. +1 −1  project/build.properties
  51. +12 −7 project/build/LiftFrameworkProject.scala
  52. +1 −0  project/plugins/Plugins.scala
  53. +6 −8 web/webkit/src/main/scala/net/liftweb/http/Bindings.scala
  54. +6 −6 web/webkit/src/main/scala/net/liftweb/http/DefaultRoutines.scala
  55. +8 −2 web/webkit/src/main/scala/net/liftweb/http/LiftRules.scala
  56. +1 −2  web/webkit/src/main/scala/net/liftweb/http/LiftScreen.scala
  57. +7 −1 web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
  58. +14 −54 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
  59. +1 −1  web/webkit/src/main/scala/net/liftweb/http/MVCHelper.scala
  60. +1 −1  web/webkit/src/main/scala/net/liftweb/http/Req.scala
  61. +6 −6 web/webkit/src/main/scala/net/liftweb/http/ResponseShortcutException.scala
  62. +8 −8 web/webkit/src/main/scala/net/liftweb/http/S.scala
  63. +36 −10 web/webkit/src/main/scala/net/liftweb/http/SHtml.scala
  64. +92 −7 web/webkit/src/main/scala/net/liftweb/http/{TemplateFinder.scala → Templates.scala}
  65. +2 −1  web/webkit/src/main/scala/net/liftweb/http/package.scala
  66. +1 −1  web/webkit/src/main/scala/net/liftweb/sitemap/Loc.scala
  67. +1 −1  web/webkit/src/main/scala/net/liftweb/sitemap/SiteMap.scala
9 core/common/src/main/scala/net/liftweb/common/Box.scala
View
@@ -279,6 +279,15 @@ sealed abstract class Box[+A] extends Product {
def exists(func: A => Boolean): Boolean = false
/**
+ * Creates a Box if the current Box is Full and the value does not satisfy the predicate, f.
+ *
+ * @param f the predicate used to test value.
+ *
+ * @returns a Box
+ */
+ def filterNot(f: A => Boolean): Box[A] = filter(a => !f(a))
+
+ /**
* Perform a side effect by calling the specified function
* with the value contained in this box.
*/
10 core/json-ext/src/main/scala/net/liftweb/json/ext/JodaTimeSerializer.scala
View
@@ -24,7 +24,15 @@ import JsonDSL._
object JodaTimeSerializers {
def all = List(DurationSerializer(), InstantSerializer(), DateTimeSerializer(),
DateMidnightSerializer(), IntervalSerializer(), LocalDateSerializer(),
- LocalTimeSerializer())
+ LocalTimeSerializer(), PeriodSerializer())
+}
+
+object PeriodSerializer {
+ def apply() = new SimpleTypeSerializer(new JStringType[Period]() {
+ def targetClass = classOf[Period]
+ def unwrap(json: JString)(implicit format: Formats) = new Period(json.s)
+ def wrap(a: Period)(implicit format: Formats) = JString(a.toString)
+ })
}
object DurationSerializer {
6 core/json-ext/src/test/scala/net/liftweb/json/ext/JodaTimeSerializerSpec.scala
View
@@ -36,7 +36,7 @@ object JodaTimeSerializerSpec extends Specification("JodaTimeSerializer Specific
"Serialize joda time types" in {
val x = JodaTypes(new Duration(10*1000), new Instant(System.currentTimeMillis),
new DateTime, new DateMidnight, new Interval(1000, 50000),
- new LocalDate(2011, 1, 16), new LocalTime(16, 52, 10))
+ new LocalDate(2011, 1, 16), new LocalTime(16, 52, 10), Period.weeks(3))
val ser = swrite(x)
read[JodaTypes](ser) mustEqual x
}
@@ -52,7 +52,7 @@ object JodaTimeSerializerSpec extends Specification("JodaTimeSerializer Specific
}
"null is serialized as JSON null" in {
- val x = JodaTypes(null, null, null, null, null, null, null)
+ val x = JodaTypes(null, null, null, null, null, null, null, null)
val ser = swrite(x)
read[JodaTypes](ser) mustEqual x
}
@@ -60,6 +60,6 @@ object JodaTimeSerializerSpec extends Specification("JodaTimeSerializer Specific
case class JodaTypes(duration: Duration, instant: Instant, dateTime: DateTime,
dateMidnight: DateMidnight, interval: Interval, localDate: LocalDate,
- localTime: LocalTime)
+ localTime: LocalTime, period: Period)
case class Dates(dt: DateTime, dm: DateMidnight)
2  core/json/README.md
View
@@ -508,7 +508,7 @@ Serialization supports:
* Arbitrarily deep case class graphs
* All primitive types, including BigInt and Symbol
-* List, Array, Set and Map (note, keys of the Map must be strings: Map[String, _])
+* List, Seq, Array, Set and Map (note, keys of the Map must be strings: Map[String, _])
* scala.Option
* java.util.Date
* Polymorphic Lists (see below)
3  core/json/src/main/scala/net/liftweb/json/Extraction.scala
View
@@ -184,7 +184,7 @@ object Extraction {
Col(clazz, mappingOf(typeArgs(0)))
else if (clazz == classOf[Map[_, _]])
Dict(mappingOf(typeArgs(1)))
- else mappingOf(clazz)
+ else mappingOf(clazz, typeArgs)
extract0(json, mapping)
}
@@ -202,6 +202,7 @@ object Extraction {
case x => Nil
}
constructor.bestMatching(argNames)
+ .getOrElse(fail("No constructor for type " + constructor.targetType.clazz + ", " + json))
}
}
44 core/json/src/main/scala/net/liftweb/json/Meta.scala
View
@@ -53,21 +53,24 @@ private[json] object Meta {
case class Dict(mapping: Mapping) extends Mapping
case class Col(targetType: Class[_], mapping: Mapping) extends Mapping
case class Constructor(targetType: TypeInfo, choices: List[DeclaredConstructor]) extends Mapping {
- def bestMatching(argNames: List[String]): DeclaredConstructor = {
+ def bestMatching(argNames: List[String]): Option[DeclaredConstructor] = {
val names = Set(argNames: _*)
def countOptionals(args: List[Arg]) =
args.foldLeft(0)((n, x) => if (x.optional) n+1 else n)
def score(args: List[Arg]) =
args.foldLeft(0)((s, arg) => if (names.contains(arg.path)) s+1 else -100)
- val best = choices.tail.foldLeft((choices.head, score(choices.head.args))) { (best, c) =>
- val newScore = score(c.args)
- if (newScore == best._2) {
- if (countOptionals(c.args) < countOptionals(best._1.args))
- (c, newScore) else best
- } else if (newScore > best._2) (c, newScore) else best
+ if (choices.isEmpty) None
+ else {
+ val best = choices.tail.foldLeft((choices.head, score(choices.head.args))) { (best, c) =>
+ val newScore = score(c.args)
+ if (newScore == best._2) {
+ if (countOptionals(c.args) < countOptionals(best._1.args))
+ (c, newScore) else best
+ } else if (newScore > best._2) (c, newScore) else best
+ }
+ Some(best._1)
}
- best._1
}
}
@@ -82,7 +85,8 @@ private[json] object Meta {
paranamer.lookupParameterNames(constructor)
}
- private[json] def mappingOf(clazz: Class[_])(implicit formats: Formats): Mapping = {
+ private[json] def mappingOf(clazz: Class[_], typeArgs: Seq[Class[_]] = Seq())
+ (implicit formats: Formats): Mapping = {
import Reflection._
def constructors(clazz: Class[_], visited: Set[Class[_]]) =
@@ -105,8 +109,6 @@ private[json] object Meta {
def fieldMapping(fType: Class[_], genType: Type): (Mapping, Boolean) = {
if (primitive_?(fType)) (Value(fType), false)
- else if (classOf[List[_]].isAssignableFrom(fType))
- (mkContainer(genType, `* -> *`, 0, Col.apply(classOf[List[_]], _)), false)
else if (classOf[Set[_]].isAssignableFrom(fType))
(mkContainer(genType, `* -> *`, 0, Col.apply(classOf[Set[_]], _)), false)
else if (fType.isArray)
@@ -115,6 +117,8 @@ private[json] object Meta {
(mkContainer(genType, `* -> *`, 0, identity _), true)
else if (classOf[Map[_, _]].isAssignableFrom(fType))
(mkContainer(genType, `(*,*) -> *`, 1, Dict.apply _), false)
+ else if (classOf[Seq[_]].isAssignableFrom(fType))
+ (mkContainer(genType, `* -> *`, 0, Col.apply(classOf[List[_]], _)), false)
else {
if (visited.contains(fType)) (Cycle(fType), false)
else (Constructor(TypeInfo(fType, parameterizedTypeOpt(genType)),
@@ -127,9 +131,23 @@ private[json] object Meta {
}
if (primitive_?(clazz)) Value(clazz)
- else mappings.memoize(clazz, c => Constructor(TypeInfo(c, None), constructors(c, Set())))
+ else {
+ mappings.memoize(clazz, c => {
+ val typeInfo =
+ if (typeArgs.isEmpty) TypeInfo(c, None)
+ else TypeInfo(c, Some(mkParameterizedType(c, typeArgs)))
+ Constructor(typeInfo, constructors(c, Set()))
+ })
+ }
}
+ private[json] def mkParameterizedType(owner: Class[_], typeArgs: Seq[Class[_]]) =
+ new ParameterizedType {
+ def getActualTypeArguments = typeArgs.toArray
+ def getOwnerType = owner
+ def getRawType = owner
+ }
+
private[json] def unmangleName(name: String) =
unmangledNames.memoize(name, operators.foldLeft(_)((n, o) => n.replace(o._1, o._2)))
@@ -253,7 +271,7 @@ private[json] object Meta {
def fields(clazz: Class[_]): List[(String, TypeInfo)] = {
val fs = clazz.getDeclaredFields.toList
- .filterNot(f => Modifier.isStatic(f.getModifiers))
+ .filterNot(f => Modifier.isStatic(f.getModifiers) || Modifier.isTransient(f.getModifiers))
.map(f => (f.getName, TypeInfo(f.getType, f.getGenericType match {
case p: ParameterizedType => Some(p)
case _ => None
5 core/json/src/test/scala/net/liftweb/json/FieldSerializerBugs.scala
View
@@ -23,7 +23,8 @@ object FieldSerializerBugs extends Specification {
import Serialization.{read, write => swrite}
implicit val formats = DefaultFormats + FieldSerializer[AnyRef]()
-/*
+
+/* FIXME: For some reason this fails on CI
"AtomicInteger should not cause stack overflow" in {
import java.util.concurrent.atomic.AtomicInteger
@@ -31,6 +32,6 @@ object FieldSerializerBugs extends Specification {
val atomic = read[AtomicInteger](ser)
atomic.get mustEqual 1
}
-*/
+ */
}
24 core/json/src/test/scala/net/liftweb/json/SerializationBugs.scala
View
@@ -87,6 +87,30 @@ object SerializationBugs extends Specification {
read[OptionalUUID](swrite(o1)) mustEqual o1
read[OptionalUUID](swrite(o2)) mustEqual o2
}
+
+ "TypeInfo is not correctly constructed for customer serializer -- 970" in {
+ class SeqFormat extends Serializer[Seq[_]] {
+ val SeqClass = classOf[Seq[_]]
+
+ def serialize(implicit format: Formats) = {
+ case seq: Seq[_] => JArray(seq.toList.map(Extraction.decompose))
+ }
+
+ def deserialize(implicit format: Formats) = {
+ case (TypeInfo(SeqClass, parameterizedType), JArray(xs)) =>
+ val typeInfo = TypeInfo(parameterizedType
+ .map(_.getActualTypeArguments()(0))
+ .getOrElse(fail("No type parameter info for type Seq")).asInstanceOf[Class[_]], None)
+ xs.map(x => Extraction.extract(x, typeInfo))
+ }
+ }
+
+ implicit val formats = DefaultFormats + new SeqFormat
+
+ val seq = Seq(1, 2, 3)
+ val ser = Extraction.decompose(seq)
+ Extraction.extract[Seq[Int]](ser) mustEqual seq
+ }
}
case class LongList(xs: List[Num])
8 core/json/src/test/scala/net/liftweb/json/SerializationExamples.scala
View
@@ -95,6 +95,12 @@ object SerializationExamples extends Specification {
s.array.toList mustEqual unser.array.toList
}
+ "Seq serialization example" in {
+ val s = SeqContainer(List("foo", "bar"))
+ val ser = swrite(s)
+ read[SeqContainer](ser) mustEqual s
+ }
+
"None Option of tuple serialization example" in {
// This is a regression test case, failed in lift json
val s = OptionOfTupleOfDouble(None)
@@ -343,4 +349,6 @@ case class SetContainer(set: Set[String])
case class ArrayContainer(array: Array[String])
+case class SeqContainer(seq: Seq[String])
+
case class OptionOfTupleOfDouble(position: Option[Tuple2[Double, Double]])
4 core/util/src/main/scala/net/liftweb/util/BindHelpers.scala
View
@@ -688,6 +688,7 @@ trait BindHelpers {
* Remove all the <head> tags, just leaving the child tags
*/
def stripHead(in: NodeSeq): NodeSeq = {
+ ("head" #> ((ns: NodeSeq) => ns.asInstanceOf[Elem].child))(in)
import scala.xml.transform._
val rewrite = new RewriteRule {
@@ -705,6 +706,8 @@ trait BindHelpers {
* nodeseq.
*/
def replaceIdNode(in: NodeSeq, id: String, replacement: NodeSeq): NodeSeq = {
+ (("#"+id) #> replacement)(in)
+ /*
import scala.xml.transform._
val cmp = Some(Text(id))
@@ -718,6 +721,7 @@ trait BindHelpers {
}
(new RuleTransformer(rewrite)).transform(in)
+ */
}
/**
33 core/util/src/main/scala/net/liftweb/util/Mailer.scala
View
@@ -37,36 +37,40 @@ protected trait MailerImpl extends SimpleInjector {
private val logger = Logger(classOf[MailerImpl])
sealed abstract class MailTypes
+ /**
+ * Add message headers to outgoing messages
+ */
+ final case class MessageHeader(name: String, value: String) extends MailTypes
sealed abstract class MailBodyType extends MailTypes
- case class PlusImageHolder(name: String, mimeType: String, bytes: Array[Byte])
+ final case class PlusImageHolder(name: String, mimeType: String, bytes: Array[Byte])
/**
* Represents a text/plain mail body. The given text will
* be encoded as UTF-8 when sent.
*/
- case class PlainMailBodyType(text: String) extends MailBodyType
+ final case class PlainMailBodyType(text: String) extends MailBodyType
/**
* Represents a text/plain mail body that is encoded with the
* specified charset
*/
- case class PlainPlusBodyType(text: String, charset: String) extends MailBodyType
+ final case class PlainPlusBodyType(text: String, charset: String) extends MailBodyType
- case class XHTMLMailBodyType(text: NodeSeq) extends MailBodyType
- case class XHTMLPlusImages(text: NodeSeq, items: PlusImageHolder*) extends MailBodyType
+ final case class XHTMLMailBodyType(text: NodeSeq) extends MailBodyType
+ final case class XHTMLPlusImages(text: NodeSeq, items: PlusImageHolder*) extends MailBodyType
sealed abstract class RoutingType extends MailTypes
sealed abstract class AddressType(val adr: String) extends RoutingType
- case class From(address: String) extends AddressType(address)
- case class To(address: String) extends AddressType(address)
- case class CC(address: String) extends AddressType(address)
- case class Subject(subject: String) extends RoutingType
- case class BCC(address: String) extends AddressType(address)
- case class ReplyTo(address: String) extends AddressType(address)
+ final case class From(address: String) extends AddressType(address)
+ final case class To(address: String) extends AddressType(address)
+ final case class CC(address: String) extends AddressType(address)
+ final case class Subject(subject: String) extends RoutingType
+ final case class BCC(address: String) extends AddressType(address)
+ final case class ReplyTo(address: String) extends AddressType(address)
implicit def xmlToMailBodyType(html: NodeSeq): MailBodyType = XHTMLMailBodyType(html)
- case class MessageInfo(from: From, subject: Subject, info: List[MailTypes])
+ final case class MessageInfo(from: From, subject: Subject, info: List[MailTypes])
implicit def addressToAddress(in: AddressType): Address = new InternetAddress(in.adr)
@@ -221,6 +225,11 @@ protected trait MailerImpl extends SimpleInjector {
// message.setReplyTo(filter[MailTypes, ReplyTo](info, {case x @ ReplyTo(_) => Some(x); case _ => None}))
message.setReplyTo(info.flatMap {case x: ReplyTo => Some[ReplyTo](x) case _ => None})
message.setSubject(subject.subject)
+ info.foreach {
+ case MessageHeader(name, value) => message.addHeader(name, value)
+ case _ =>
+ }
+
val bodyTypes = info.flatMap {case x: MailBodyType => Some[MailBodyType](x); case _ => None}
bodyTypes match {
case PlainMailBodyType(txt) :: Nil =>
3  ...pper/src/main/scala/net/liftweb/mapper/Safe.scala → core/util/src/main/scala/net/liftweb/util/Safe.scala
View
@@ -15,11 +15,10 @@
*/
package net.liftweb
-package mapper
+package util
import java.security.{SecureRandom, MessageDigest}
import org.apache.commons.codec.binary.Base64
-import net.liftweb.util.{StringHelpers, Helpers, ThreadGlobal}
/**
* Manage the current "safety" state of the stack
2  core/util/src/test/scala/net/liftweb/util/BindHelpersSpec.scala
View
@@ -216,7 +216,7 @@ object BindHelpersSpec extends Specification("BindHelpers Specification") {
"replace a node" in {
Helpers.replaceIdNode(<foo><bar id="dog"/></foo>,
"dog",
- <baz/>) must ==/ (<foo><baz/></foo>)
+ <baz/>) must ==/ (<foo><baz id="dog"></baz></foo>)
}
"Ignore if no id match" in {
9 persistence/db/src/main/scala/net/liftweb/db/DB.scala
View
@@ -1166,16 +1166,19 @@ trait ProtoDBVendor extends ConnectionManager {
notifyAll
}
- def closeAllConnections_!(): Unit = synchronized {
+ def closeAllConnections_!(): Unit = _closeAllConnections_!(0)
+
+
+ private def _closeAllConnections_!(cnt: Int): Unit = synchronized {
logger.info("Closing all connections")
- if (poolSize == 0) ()
+ if (poolSize <= 0 || cnt > 10) ()
else {
pool.foreach {c => tryo(c.close); poolSize -= 1}
pool = Nil
if (poolSize > 0) wait(250)
- closeAllConnections_!()
+ _closeAllConnections_!(cnt + 1)
}
}
}
1  persistence/mapper/src/main/scala/net/liftweb/mapper/MappedPassword.scala
View
@@ -17,7 +17,6 @@
package net.liftweb
package mapper
-import net.liftweb.mapper._
import net.liftweb.util.Helpers._
import net.liftweb.util.FatLazy
import java.sql.{ResultSet, Types}
5 persistence/mapper/src/main/scala/net/liftweb/mapper/package.scala
View
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package net.liftweb
+package net.liftweb
package object mapper {
type SuperConnection = db.SuperConnection
type ConnectionIdentifier = db.ConnectionIdentifier
@@ -26,4 +26,7 @@ package object mapper {
def DBLogEntry = db.DBLogEntry
def DefaultConnectionIdentifier = db.DefaultConnectionIdentifier
def DriverType = db.DriverType
+
+ @deprecated("Use util.Safe instead.")
+ def Safe = util.Safe
}
23 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoMetaRecord.scala
View
@@ -28,7 +28,7 @@ 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.{MandatoryTypedField, MetaRecord, Record}
import net.liftweb.record.FieldHelpers.expectedA
import net.liftweb.record.field._
@@ -41,12 +41,24 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
self: BaseRecord =>
+ /*
+ * Utility method for determining the value of _id.
+ * This is needed for backwards compatibility with MongoId. This is
+ * due to the fact that MongoRecord.id is of type Any. That will
+ * be changed to type MandatoryTypedField in a future version. When
+ * that happens this will no longer be necessary.
+ */
+ private def idValue(inst: BaseRecord): Any = inst.id match {
+ case f: MandatoryTypedField[_] => 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 +118,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,7 +311,7 @@ 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)
}
10 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
View
@@ -29,7 +29,11 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
self: MyType =>
/*
- * every mongo record must have an _id field. Override this with the value of your _id object.
+ * Every MongoRecord must have an _id field. Use a MongoPkField to
+ * satisfy this.
+
+ * This may change to type MandatoryTypedField in the
+ * future (once MongoId is removed.)
*/
def id: Any
@@ -47,7 +51,7 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
}
this
}
-
+
/**
* Save the instance and return the instance
* @param safe - if true will use WriteConcern SAFE else NORMAL
@@ -58,7 +62,7 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
/**
* Save the instance and return the instance
- * WILL NOT RAISE MONGO SERVER ERRORS.
+ * WILL NOT RAISE MONGO SERVER ERRORS.
* Use save(Boolean) or save(WriteConcern) to control error behavior
*/
def save: MyType = save(false)
4 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/BsonRecordField.scala
View
@@ -31,7 +31,7 @@ import com.mongodb._
import scala.xml._
/** Field that contains an entire record represented as an inline object value. Inspired by JSONSubRecordField */
-class BsonRecordField[OwnerType <: MongoRecord[OwnerType], SubRecordType <: BsonRecord[SubRecordType]]
+class BsonRecordField[OwnerType <: BsonRecord[OwnerType], SubRecordType <: BsonRecord[SubRecordType]]
(rec: OwnerType, valueMeta: BsonMetaRecord[SubRecordType])(implicit subRecordType: Manifest[SubRecordType])
extends Field[SubRecordType, OwnerType]
with MandatoryTypedField[SubRecordType]
@@ -75,7 +75,7 @@ class BsonRecordField[OwnerType <: MongoRecord[OwnerType], SubRecordType <: Bson
/*
* List of BsonRecords
*/
-class BsonRecordListField[OwnerType <: MongoRecord[OwnerType], SubRecordType <: BsonRecord[SubRecordType]]
+class BsonRecordListField[OwnerType <: BsonRecord[OwnerType], SubRecordType <: BsonRecord[SubRecordType]]
(rec: OwnerType, valueMeta: BsonMetaRecord[SubRecordType])
extends MongoListField[OwnerType, SubRecordType](rec: OwnerType) {
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/DBRefField.scala
View
@@ -32,7 +32,7 @@ import org.bson.types.ObjectId
/*
* Field for storing a DBRef
*/
-class DBRefField[OwnerType <: MongoRecord[OwnerType], RefType <: MongoRecord[RefType]](rec: OwnerType, ref: RefType)
+class DBRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](rec: OwnerType, ref: RefType)
extends Field[DBRef, OwnerType] with MandatoryTypedField[DBRef] {
/*
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/DateField.scala
View
@@ -32,7 +32,7 @@ import net.liftweb.util.Helpers._
/*
* Since MongoDB only stores UTC dates, Calendar data is not necessary.
*/
-class DateField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
+class DateField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
extends Field[Date, OwnerType]
with MandatoryTypedField[Date]
{
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JsonObjectField.scala
View
@@ -28,7 +28,7 @@ import net.liftweb.util.Helpers.tryo
import com.mongodb.DBObject
-abstract class JsonObjectField[OwnerType <: MongoRecord[OwnerType], JObjectType <: JsonObject[JObjectType]]
+abstract class JsonObjectField[OwnerType <: BsonRecord[OwnerType], JObjectType <: JsonObject[JObjectType]]
(rec: OwnerType, valueMeta: JsonObjectMeta[JObjectType])
extends Field[JObjectType, OwnerType] with MandatoryTypedField[JObjectType] with MongoFieldFlavor[JObjectType] {
9 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoListField.scala
View
@@ -22,6 +22,7 @@ package field
import java.util.Date
import scala.collection.JavaConversions._
+import scala.xml.NodeSeq
import common.{Box, Empty, Failure, Full}
import json.JsonAST._
@@ -37,7 +38,7 @@ import org.bson.types.ObjectId
* List field. Compatible with most object types,
* including Pattern, ObjectId, Date, and UUID.
*/
-class MongoListField[OwnerType <: MongoRecord[OwnerType], ListType](rec: OwnerType)
+class MongoListField[OwnerType <: BsonRecord[OwnerType], ListType](rec: OwnerType)
extends Field[List[ListType], OwnerType]
with MandatoryTypedField[List[ListType]]
with MongoFieldFlavor[List[ListType]]
@@ -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)
@@ -112,14 +113,14 @@ class MongoListField[OwnerType <: MongoRecord[OwnerType], ListType](rec: OwnerTy
* List of Dates. Use MongListField[OwnerType, Date] instead.
*/
@deprecated("Use MongListField[OwnerType, Date] instead")
-class MongoDateListField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
+class MongoDateListField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
extends MongoListField[OwnerType, Date](rec: OwnerType) {
}
/*
* List of JsonObject case classes
*/
-class MongoJsonObjectListField[OwnerType <: MongoRecord[OwnerType], JObjectType <: JsonObject[JObjectType]]
+class MongoJsonObjectListField[OwnerType <: BsonRecord[OwnerType], JObjectType <: JsonObject[JObjectType]]
(rec: OwnerType, valueMeta: JsonObjectMeta[JObjectType])
extends MongoListField[OwnerType, JObjectType](rec: OwnerType) {
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoMapField.scala
View
@@ -30,7 +30,7 @@ import net.liftweb.util.Helpers.tryo
import com.mongodb._
-class MongoMapField[OwnerType <: MongoRecord[OwnerType], MapValueType](rec: OwnerType)
+class MongoMapField[OwnerType <: BsonRecord[OwnerType], MapValueType](rec: OwnerType)
extends Field[Map[String, MapValueType], OwnerType] with MandatoryTypedField[Map[String, MapValueType]]
with MongoFieldFlavor[Map[String, MapValueType]] {
5 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoPasswordField.scala
View
@@ -24,8 +24,7 @@ import scala.xml.{Node, NodeSeq, Text}
import net.liftweb.common.{Box, Empty, Failure, Full}
import net.liftweb.http.S
import net.liftweb.http.js.JE._
-import net.liftweb.mapper.Safe
-import net.liftweb.util.{FatLazy, FieldError, Helpers}
+import net.liftweb.util.{FatLazy, FieldError, Helpers, Safe}
import Helpers._
@@ -43,7 +42,7 @@ object MongoPasswordField {
def encrypt(s: String, salt: String) = hash("{"+s+"} salt={" + salt + "}")
}
-class MongoPasswordField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType, minLen: Int) extends JsonObjectField[OwnerType, Password](rec, Password) {
+class MongoPasswordField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType, minLen: Int) extends JsonObjectField[OwnerType, Password](rec, Password) {
def this(rec: OwnerType) = {
this(rec, 3)
110 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoPk.scala
View
@@ -0,0 +1,110 @@
+/*
+ * 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 util.StringHelpers
+
+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. These are all an id field
+ * that is saved as _id in the database. Mix one of these into your
+ * MongoRecord.
+ */
+trait MongoPk[PkType] {
+ def id: PkType
+ /** Override this to set default value of id field */
+ def defaultIdValue: Any
+}
+
+trait ObjectIdPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[ObjectIdField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = ObjectId.get
+
+ object id extends ObjectIdField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait UUIDPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[UUIDField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = UUID.randomUUID
+
+ object id extends UUIDField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait StringPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[StringField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = StringHelpers.randomString(32)
+
+ object id extends StringField(this.asInstanceOf[OwnerType], 12) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait IntPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[IntField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = Random.nextInt
+
+ object id extends IntField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait LongPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[LongField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = Random.nextLong
+
+ object id extends LongField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
135 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/MongoRefField.scala
View
@@ -0,0 +1,135 @@
+/*
+ * 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.{Box, Empty, Full}
+import http.SHtml
+import util.Helpers._
+
+import java.util.UUID
+
+import org.bson.types.ObjectId
+import net.liftweb.record.TypedField
+import net.liftweb.record.field._
+
+/*
+ * Trait for creating a Field for storing a "foreign key". Caches the
+ * item after fetching. Implementations are available for ObjectId, UUID, String,
+ * Int, and Long, but you can mix this into any Field.
+ *
+ * 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]
+
+ /*
+ * 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
+
+ /** 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))
+ case _ => Full(elem)
+ }
+ else
+ Empty
+}
+
+class ObjectIdRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends ObjectIdField[OwnerType](rec)
+ with MongoRefField[RefType, ObjectId]
+{
+ def refMeta = rm
+}
+
+class UUIDRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends UUIDField[OwnerType](rec)
+ with MongoRefField[RefType, UUID]
+{
+ def refMeta = rm
+}
+
+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
+}
+
+class IntRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends IntField[OwnerType](rec)
+ with MongoRefField[RefType, Int]
+{
+ def refMeta = rm
+}
+
+class LongRefField[OwnerType <: BsonRecord[OwnerType], RefType <: MongoRecord[RefType]](
+ rec: OwnerType, rm: MongoMetaRecord[RefType]
+)
+ extends LongField[OwnerType](rec)
+ with MongoRefField[RefType, Long]
+{
+ def refMeta = rm
+}
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/ObjectIdField.scala
View
@@ -34,7 +34,7 @@ import org.bson.types.ObjectId
/*
* Field for storing an ObjectId
*/
-class ObjectIdField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
+class ObjectIdField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
extends Field[ObjectId, OwnerType]
with MandatoryTypedField[ObjectId]
{
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/PatternField.scala
View
@@ -26,7 +26,7 @@ import net.liftweb.mongodb.record._
import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField}
import net.liftweb.util.Helpers.tryo
-class PatternField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
+class PatternField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
extends Field[Pattern, OwnerType]
with MandatoryTypedField[Pattern]
{
2  persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/UUIDField.scala
View
@@ -29,7 +29,7 @@ import net.liftweb.mongodb.record._
import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField}
import net.liftweb.util.Helpers._
-class UUIDField[OwnerType <: MongoRecord[OwnerType]](rec: OwnerType)
+class UUIDField[OwnerType <: BsonRecord[OwnerType]](rec: OwnerType)
extends Field[UUID, OwnerType]
with MandatoryTypedField[UUID]
{
4 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/CustomSerializersSpec.scala
View
@@ -284,7 +284,7 @@ object CustomSerializersSpec extends Specification("CustomSerializers Specificat
// nfl._id.asJs mustEqual Str(nfl._id.value.toString)
nfl._id.asJValue mustEqual JString(nfl._id.value.toString)
val session = new LiftSession("", randomString(20), Empty)
- val formPattern = "<input name=\".*\" type=\"text\" tabindex=\"1\" value=\""+nfl._id.value.toString+"\" id=\"_id_id_field\"></input>"
+ val formPattern = "<input name=\".*\" type=\"text\" tabindex=\"1\" value=\""+nfl._id.value.toString+"\" id=\"_id_id\"></input>"
S.initIfUninitted(session) {
val form = nfl._id.toForm
form must notBeEmpty
@@ -347,7 +347,7 @@ object CustomSerializersSpec extends Specification("CustomSerializers Specificat
// nfl._id.asJs mustEqual JsObj(("$oid", Str(nfl._id.value.toString)))
nfl._id.asJValue mustEqual JObject(List(JField("$oid", JString(nfl._id.value.toString))))
val session = new LiftSession("", randomString(20), Empty)
- val formPattern = "<input name=\".*\" type=\"text\" tabindex=\"1\" value=\""+nfl._id.value.toString+"\" id=\"_id_id_field\"></input>"
+ val formPattern = "<input name=\".*\" type=\"text\" tabindex=\"1\" value=\""+nfl._id.value.toString+"\" id=\"_id_id\"></input>"
S.initIfUninitted(session) {
val form = nfl._id.toForm
form must notBeEmpty
121 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
View
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package net.liftweb
-package mongodb
-package record
-package fixtures
+package net.liftweb
+package mongodb
+package record
+package fixtures
import field._
@@ -38,6 +38,8 @@ object MyTestEnum extends Enumeration {
}
trait HarnessedLifecycleCallbacks extends LifecycleCallbacks {
+ this: BaseField =>
+
var beforeValidationHarness: () => Unit = () => ()
override def beforeValidation = beforeValidationHarness()
var afterValidationHarness: () => Unit = () => ()
@@ -63,7 +65,7 @@ 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)
@@ -131,7 +133,8 @@ class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] wi
object optionalTimeZoneField extends OptionalTimeZoneField(this)
override def equals(other: Any): Boolean = other match {
- case that:FieldTypeTestRecord =>
+ case that: FieldTypeTestRecord =>
+ this.id.value == that.id.value &&
//this.mandatoryBinaryField.value == that.mandatoryBinaryField.value &&
this.mandatoryBooleanField.value == that.mandatoryBooleanField.value &&
this.mandatoryCountryField.value == that.mandatoryCountryField.value &&
@@ -157,7 +160,8 @@ object FieldTypeTestRecord extends FieldTypeTestRecord with MongoMetaRecord[Fiel
case class TypeTestJsonObject(
intField: Int,
- stringField: String
+ stringField: String,
+ mapField: Map[String, String]
) extends JsonObject[TypeTestJsonObject]
{
// TODO: Add more types
@@ -170,21 +174,18 @@ class DBRefTestRecord private () extends MongoRecord[DBRefTestRecord] with Mongo
}
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, "")
+ def defaultValue = TypeTestJsonObject(0, "", Map[String, String]())
}
object legacyOptionalJsonObjectField extends JsonObjectField(this, TypeTestJsonObject) {
override def optional_? = true
- def defaultValue = TypeTestJsonObject(0, "")
+ def defaultValue = TypeTestJsonObject(0, "", Map[String, String]())
}
object mandatoryObjectIdField extends ObjectIdField(this)
@@ -197,10 +198,9 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
object legacyOptionalUUIDField extends UUIDField(this) { override def optional_? = true }
override def equals(other: Any): Boolean = other match {
- case that:MongoFieldTypeTestRecord =>
+ 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 &&
@@ -214,14 +214,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)
@@ -238,7 +238,8 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with MongoId
// TODO: More List types
override def equals(other: Any): Boolean = other match {
- case that:ListTestRecord =>
+ 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
@@ -249,7 +250,7 @@ object ListTestRecord extends ListTestRecord with MongoMetaRecord[ListTestRecord
override def formats = allFormats
}
-class MapTestRecord extends MongoRecord[MapTestRecord] with MongoId[MapTestRecord] {
+class MapTestRecord private () extends MongoRecord[MapTestRecord] with StringPk[MapTestRecord] {
def meta = MapTestRecord
object mandatoryStringMapField extends MongoMapField[MapTestRecord, String](this)
@@ -261,7 +262,8 @@ class MapTestRecord extends MongoRecord[MapTestRecord] with MongoId[MapTestRecor
// TODO: More Map types, including JsonObject (will require a new Field type)
override def equals(other: Any): Boolean = other match {
- case that:MapTestRecord =>
+ case that: MapTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryStringMapField.value == that.mandatoryStringMapField.value &&
this.mandatoryIntMapField.value == that.mandatoryIntMapField.value
case _ => false
@@ -274,34 +276,35 @@ object MapTestRecord extends MapTestRecord with MongoMetaRecord[MapTestRecord] {
class LifecycleTestRecord private ()
extends MongoRecord[LifecycleTestRecord]
with MongoId[LifecycleTestRecord]
- with HarnessedLifecycleCallbacks
{
def meta = LifecycleTestRecord
def foreachCallback(f: LifecycleCallbacks => Any): Unit =
meta.foreachCallback(this, f)
- object innerObjectWithCallbacks extends LifecycleCallbacks with HarnessedLifecycleCallbacks
-
- object stringFieldWithCallbacks extends StringField(this, 100) with LifecycleCallbacks with HarnessedLifecycleCallbacks
+ object stringFieldWithCallbacks extends StringField(this, 100) with HarnessedLifecycleCallbacks
}
-object LifecycleTestRecord extends LifecycleTestRecord with MongoMetaRecord[LifecycleTestRecord] {
- // without this, the Scala 2.7 compiler panics, so don't blame me if you remove it and it's confusing!
- override def foreachCallback(inst: LifecycleTestRecord, f: LifecycleCallbacks => Any) = super.foreachCallback(inst, f)
-}
+object LifecycleTestRecord extends LifecycleTestRecord with MongoMetaRecord[LifecycleTestRecord]
/*
* SubRecord fields
*/
-class SubRecord extends BsonRecord[SubRecord] {
+class SubRecord private () extends BsonRecord[SubRecord] {
def meta = SubRecord
object name extends StringField(this, 12)
+ object subsub extends BsonRecordField(this, SubSubRecord)
+ object subsublist extends BsonRecordListField(this, SubSubRecord)
+ object when extends DateField(this)
+ object slist extends MongoListField[SubRecord, String](this)
+ object smap extends MongoMapField[SubRecord, String](this)
+ object oid extends ObjectIdField(this)
+ object pattern extends PatternField(this)
+ object uuid extends UUIDField(this)
override def equals(other: Any): Boolean = other match {
- case that:SubRecord =>
- this.name.value == that.name.value
+ case that: SubRecord => this.toString == that.toString
case _ => false
}
}
@@ -309,7 +312,22 @@ object SubRecord extends SubRecord with BsonMetaRecord[SubRecord] {
override def formats = allFormats
}
-class SubRecordTestRecord extends MongoRecord[SubRecordTestRecord] with MongoId[SubRecordTestRecord] {
+class SubSubRecord private () extends BsonRecord[SubSubRecord] {
+ def meta = SubSubRecord
+
+ object name extends StringField(this, 12)
+
+ override def equals(other: Any): Boolean = other match {
+ case that: SubSubRecord =>
+ this.name.value == that.name.value
+ case _ => false
+ }
+}
+object SubSubRecord extends SubSubRecord with BsonMetaRecord[SubSubRecord] {
+ override def formats = allFormats
+}
+
+class SubRecordTestRecord private () extends MongoRecord[SubRecordTestRecord] with ObjectIdPk[SubRecordTestRecord] {
def meta = SubRecordTestRecord
object mandatoryBsonRecordField extends BsonRecordField(this, SubRecord)
@@ -323,12 +341,7 @@ class SubRecordTestRecord extends MongoRecord[SubRecordTestRecord] with MongoId[
}
override def equals(other: Any): Boolean = other match {
- case that:SubRecordTestRecord =>
- this.id == that.id &&
- this.mandatoryBsonRecordField.value == that.mandatoryBsonRecordField.value &&
- this.legacyOptionalBsonRecordField.valueBox == that.legacyOptionalBsonRecordField.valueBox &&
- this.mandatoryBsonRecordListField.value == that.mandatoryBsonRecordListField.value &&
- this.legacyOptionalBsonRecordListField.valueBox == that.legacyOptionalBsonRecordListField.valueBox
+ case that: SubRecordTestRecord => this.toString == that.toString
case _ => false
}
@@ -342,7 +355,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 private () extends MongoRecord[NullTestRecord] with IntPk[NullTestRecord] {
def meta = NullTestRecord
@@ -354,6 +367,11 @@ class NullTestRecord extends MongoRecord[NullTestRecord] with MongoId[NullTestRe
def defaultValue = JsonObj("1", null)
}
object jsonobjlist extends MongoJsonObjectListField[NullTestRecord, JsonObj](this, JsonObj)
+
+ override def equals(other: Any): Boolean = other match {
+ case that: NullTestRecord => this.toString == that.toString
+ case _ => false
+ }
}
object NullTestRecord extends NullTestRecord with MongoMetaRecord[NullTestRecord]
@@ -364,15 +382,36 @@ extends JsonObject[BoxTestJsonObj] {
}
object BoxTestJsonObj extends JsonObjectMeta[BoxTestJsonObj]
-class BoxTestRecord extends MongoRecord[BoxTestRecord] with MongoId[BoxTestRecord] {
+class BoxTestRecord private () extends MongoRecord[BoxTestRecord] with LongPk[BoxTestRecord] {
def meta = BoxTestRecord
object jsonobj extends JsonObjectField[BoxTestRecord, BoxTestJsonObj](this, BoxTestJsonObj) {
def defaultValue = BoxTestJsonObj("0", Empty, Full("Full String"), Failure("Failure"))
}
object jsonobjlist extends MongoJsonObjectListField[BoxTestRecord, BoxTestJsonObj](this, BoxTestJsonObj)
+
+ override def equals(other: Any): Boolean = other match {
+ case that: BoxTestRecord => this.toString == that.toString
+ case _ => false
+ }
}
object BoxTestRecord extends BoxTestRecord with MongoMetaRecord[BoxTestRecord] {
override def formats = super.formats + new JsonBoxSerializer
}
+/*
+ * MongoRefFields
+ */
+class RefFieldTestRecord private () extends MongoRecord[RefFieldTestRecord] with ObjectIdPk[RefFieldTestRecord] {
+ def meta = RefFieldTestRecord
+
+ object mandatoryObjectIdRefField extends ObjectIdRefField(this, FieldTypeTestRecord)
+ object mandatoryUUIDRefField extends UUIDRefField(this, ListTestRecord)
+ object mandatoryStringRefField extends StringRefField(this, MapTestRecord, 100)
+ object mandatoryIntRefField extends IntRefField(this, NullTestRecord)
+ object mandatoryLongRefField extends LongRefField(this, BoxTestRecord)
+}
+
+object RefFieldTestRecord extends RefFieldTestRecord with MongoMetaRecord[RefFieldTestRecord] {
+ override def formats = allFormats
+}
162 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
View
@@ -28,7 +28,8 @@ import org.bson.types.ObjectId
import org.specs.Specification
import common._
-import json.JsonAST._
+import json.{Num => JsonNum, _}
+import JsonDSL._
import util.FieldError
import util.Helpers.randomString
import http.{LiftSession, S}
@@ -43,14 +44,12 @@ import net.liftweb.record._
object MongoFieldSpec extends Specification("MongoField 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(field: MandatoryTypedField[A]) = {
@@ -180,7 +179,7 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
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)
passConversionTests(
now,
rec.mandatoryDateField,
@@ -190,25 +189,18 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
)
}
- "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)
- }
- }
-
"JsonObjectField" should {
val rec = MongoFieldTypeTestRecord.createRecord
- val ttjo = TypeTestJsonObject(1, "jsonobj1")
+ val ttjo = TypeTestJsonObject(1, "jsonobj1", Map("x" -> "a"))
+ val json = ("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> (("x" -> "a")))
passBasicTests(ttjo, rec.mandatoryJsonObjectField, rec.legacyOptionalJsonObjectField)
passConversionTests(
ttjo,
rec.mandatoryJsonObjectField,
- JsObj(("intField", Num(1)), ("stringField", Str("jsonobj1"))),
- JObject(List(JField("intField", JInt(1)), JField("stringField", JString("jsonobj1")))),
+ new JsExp {
+ def toJsCmd = Printer.compact(render(json))
+ },
+ json,
Empty
)
}
@@ -216,7 +208,7 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
"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,
@@ -229,7 +221,7 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
"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,
@@ -242,7 +234,7 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
"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,
@@ -305,19 +297,19 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
"MongoJsonObjectListField" should {
"function correctly" in {
val rec = ListTestRecord.createRecord
- val lst = List(TypeTestJsonObject(1, "jsonobj1"), TypeTestJsonObject(2, "jsonobj2"))
+ val lst = List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2")))
+ val json = List(
+ ("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> (("x" -> "1"))),
+ ("intField" -> 2) ~ ("stringField" -> "jsonobj2") ~ ("mapField" -> (("x" -> "2")))
+ )
passBasicTests(lst, rec.mandatoryMongoJsonObjectListField, rec.legacyOptionalMongoJsonObjectListField)
passConversionTests(
lst,
rec.mandatoryMongoJsonObjectListField,
- JsArray(
- JsObj(("intField", Num(1)), ("stringField", Str("jsonobj1"))),
- JsObj(("intField", Num(2)), ("stringField", Str("jsonobj2")))
- ),
- JArray(List(
- JObject(List(JField("intField", JInt(1)), JField("stringField", JString("jsonobj1")))),
- JObject(List(JField("intField", JInt(2)), JField("stringField", JString("jsonobj2"))))
- )),
+ new JsExp {
+ def toJsCmd = Printer.compact(render(json))
+ },
+ json,
Empty
)
}
@@ -369,5 +361,105 @@ object MongoFieldSpec extends Specification("MongoField Specification") with Mon
)
}
}
+
+ "BsonRecordField" should {
+ "function correctly" in {
+ val rec = SubRecordTestRecord.createRecord
+ val subRec = SubRecord.createRecord.name("subrecord")
+
+ val srJson =
+ JObject(List(
+ JField("name", JString("subrecord")),
+ JField("subsub", JObject(List(
+ JField("name", JString(""))
+ ))),
+ JField("subsublist", JArray(List())),
+ JField("when", JObject(List(
+ JField("$dt", JString(rec.meta.formats.dateFormat.format(subRec.when.value)))
+ ))),
+ JField("slist", JArray(List())),
+ JField("smap", JObject(List())),
+ JField("oid", JObject(List(JField("$oid", JString(subRec.oid.value.toString))))),
+ JField("pattern", JObject(List(
+ JField("$regex", JString(subRec.pattern.value.pattern)),
+ JField("$flags", JInt(subRec.pattern.value.flags))
+ ))),
+ JField("uuid", JObject(List(JField("$uuid", JString(subRec.uuid.value.toString)))))
+ ))
+
+ val srJsExp = new JsExp {
+ def toJsCmd = Printer.compact(render(srJson))
+ }
+
+ passBasicTests(subRec, rec.mandatoryBsonRecordField, rec.legacyOptionalBsonRecordField, false)
+ passConversionTests(
+ subRec,
+ rec.mandatoryBsonRecordField,
+ srJsExp,
+ srJson,
+ Empty
+ )
+ }
+ }
+
+ "BsonRecordListField" should {
+ "function correctly" in {
+ val rec = SubRecordTestRecord.createRecord
+ val lst = List(SubRecord.createRecord.name("subrec1"), SubRecord.createRecord.name("subrec2"))
+ val sr1Json =
+ JObject(List(
+ JField("name", JString("subrec1")),
+ JField("subsub", JObject(List(
+ JField("name", JString(""))
+ ))),
+ JField("subsublist", JArray(List())),
+ JField("when", JObject(List(
+ JField("$dt", JString(rec.meta.formats.dateFormat.format(lst(0).when.value)))
+ ))),
+ JField("slist", JArray(List())),
+ JField("smap", JObject(List())),
+ JField("oid", JObject(List(JField("$oid", JString(lst(0).oid.value.toString))))),
+ JField("pattern", JObject(List(
+ JField("$regex", JString(lst(0).pattern.value.pattern)),
+ JField("$flags", JInt(lst(0).pattern.value.flags))
+ ))),
+ JField("uuid", JObject(List(JField("$uuid", JString(lst(0).uuid.value.toString)))))
+ ))
+ val sr2Json =
+ JObject(List(
+ JField("name", JString("subrec2")),
+ JField("subsub", JObject(List(
+ JField("name", JString(""))
+ ))),
+ JField("subsublist", JArray(List())),
+ JField("when", JObject(List(
+ JField("$dt", JString(rec.meta.formats.dateFormat.format(lst(1).when.value)))
+ ))),
+ JField("slist", JArray(List())),
+ JField("smap", JObject(List())),
+ JField("oid", JObject(List(JField("$oid", JString(lst(1).oid.value.toString))))),
+ JField("pattern", JObject(List(
+ JField("$regex", JString(lst(1).pattern.value.pattern)),
+ JField("$flags", JInt(lst(1).pattern.value.flags))
+ ))),
+ JField("uuid", JObject(List(JField("$uuid", JString(lst(1).uuid.value.toString)))))
+ ))
+ val sr1JsExp = new JsExp {
+ def toJsCmd = compact(render(sr1Json))
+ }
+ val sr2JsExp = new JsExp {
+ def toJsCmd = compact(render(sr2Json))
+ }
+
+ passBasicTests(lst, rec.mandatoryBsonRecordListField, rec.legacyOptionalBsonRecordListField)
+ passConversionTests(
+ lst,
+ rec.mandatoryBsonRecordListField,
+ JsArray(sr1JsExp, sr2JsExp),
+ JArray(List(sr1Json, sr2Json)),
+ Empty
+ )
+ }
+ }
}
338 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoRecordSpec.scala
View
@@ -25,7 +25,9 @@ import org.bson.types.ObjectId
import org.specs.Specification
import common._
+import http.js.JsExp
import json._
+import JsonDSL._
import net.liftweb.record.field.Countries
@@ -42,12 +44,12 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
val rec = MongoFieldTypeTestRecord.createRecord
val allExpectedFieldNames: List[String] = "_id" :: (for {
- typeName <- "Date DBRef JsonObject ObjectId Pattern UUID".split(" ")
+ typeName <- "Date JsonObject ObjectId Pattern UUID".split(" ")
flavor <- "mandatory legacyOptional".split(" ")
} yield flavor + typeName + "Field").toList
"introspect only the expected fields" in {
- rec.fields().map(_.name).sortWith(_ < _) must_== allExpectedFieldNames.sortWith(_ < _)
+ rec.fields().map(_.name).filterNot(allExpectedFieldNames.contains(_)) must_== Nil
}
"correctly look up fields by name" in {
@@ -159,19 +161,12 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
}
}
- testOneHarness("the record level", rec => rec)
- testOneHarness("the inner object level", rec => rec.innerObjectWithCallbacks: HarnessedLifecycleCallbacks)
testOneHarness("the field level", rec => rec.stringFieldWithCallbacks: HarnessedLifecycleCallbacks)
}
"MongoRecord" should {
checkMongoIsRunning
- val sr1 = SubRecord.createRecord
- .name("SubRecord1")
- val sr2 = SubRecord.createRecord
- .name("SubRecord2")
-
val fttr = FieldTypeTestRecord.createRecord
//.mandatoryBinaryField()
.mandatoryBooleanField(false)
@@ -190,41 +185,135 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
val mfttr = MongoFieldTypeTestRecord.createRecord
.mandatoryDateField(new Date)
- .mandatoryJsonObjectField(TypeTestJsonObject(1, "jsonobj1"))
+ .mandatoryJsonObjectField(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")))
.mandatoryObjectIdField(ObjectId.get)
.mandatoryPatternField(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
.mandatoryUUIDField(UUID.randomUUID)
-
- /* This causes problems if MongoDB is not running */
- if (isMongoRunning) {
- mfttr.mandatoryDBRefField(DBRefTestRecord.createRecord.getRef)
- }
+
+ val mfttrJson =
+ ("_id" -> ("$oid" -> mfttr.id.toString)) ~
+ ("mandatoryDateField" -> ("$dt" -> mfttr.meta.formats.dateFormat.format(mfttr.mandatoryDateField.value))) ~
+ ("legacyOptionalDateField" -> (None: Option[JObject])) ~
+ ("mandatoryJsonObjectField" -> (("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> ("x" -> "1")))) ~
+ ("legacyOptionalJsonObjectField" -> (("intField" -> 0) ~ ("stringField" -> "") ~ ("mapField" -> JObject(Nil)))) ~
+ ("mandatoryObjectIdField", ("$oid" -> mfttr.mandatoryObjectIdField.value.toString)) ~
+ ("legacyOptionalObjectIdField" -> (None: Option[JObject])) ~
+ ("mandatoryPatternField" -> (("$regex" -> mfttr.mandatoryPatternField.value.pattern) ~ ("$flags" -> mfttr.mandatoryPatternField.value.flags))) ~
+ ("legacyOptionalPatternField" -> (None: Option[JObject])) ~
+ ("mandatoryUUIDField" -> ("$uuid" -> mfttr.mandatoryUUIDField.value.toString)) ~
+ ("legacyOptionalUUIDField" -> (None: Option[JObject]))
val ltr = ListTestRecord.createRecord
.mandatoryStringListField(List("abc", "def", "ghi"))
.mandatoryIntListField(List(4, 5, 6))
- .mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1"), TypeTestJsonObject(2, "jsonobj2")))
+ .mandatoryMongoJsonObjectListField(List(TypeTestJsonObject(1, "jsonobj1", Map("x" -> "1")), TypeTestJsonObject(2, "jsonobj2", Map("x" -> "2"))))
.mongoCaseClassListField(List(MongoCaseClassTestObject(1,"str")))
-
+
+ val ltrJson =
+ ("_id" -> ("$uuid" -> ltr.id.toString)) ~
+ ("mandatoryStringListField" -> List("abc", "def", "ghi")) ~
+ ("legacyOptionalStringListField" -> List[String]()) ~
+ ("mandatoryIntListField" -> List(4, 5, 6)) ~
+ ("legacyOptionalIntListField" -> List[Int]()) ~
+ ("mandatoryMongoJsonObjectListField" -> List(
+ (("intField" -> 1) ~ ("stringField" -> "jsonobj1") ~ ("mapField" -> ("x" -> "1"))),
+ (("intField" -> 2) ~ ("stringField" -> "jsonobj2") ~ ("mapField" -> ("x" -> "2")))
+ )) ~
+ ("legacyOptionalMongoJsonObjectListField" -> List[JObject]()) ~
+ ("mongoCaseClassListField" -> List(
+ ("intField" -> 1) ~ ("stringField" -> "str")
+ ))
+
val mtr = MapTestRecord.createRecord
.mandatoryStringMapField(Map("a" -> "abc", "b" -> "def", "c" -> "ghi"))
.mandatoryIntMapField(Map("a" -> 4, "b" -> 5, "c" -> 6))
+ val mtrJson =
+ ("_id" -> mtr.id.toString) ~
+ ("mandatoryStringMapField" -> (
+ ("a" -> "abc") ~
+ ("b" -> "def") ~
+ ("c" -> "ghi")
+ )) ~
+ ("legacyOptionalStringMapField" -> JObject(Nil)) ~
+ ("mandatoryIntMapField" -> (
+ ("a" -> 4) ~
+ ("b" -> 5) ~
+ ("c" -> 6)
+ )) ~
+ ("legacyOptionalIntMapField" -> JObject(Nil))
+
+ // SubRecord
+ val ssr1 = SubSubRecord.createRecord.name("SubSubRecord1")
+ val ssr2 = SubSubRecord.createRecord.name("SubSubRecord2")
+
+ val sr1 = SubRecord.createRecord
+ .name("SubRecord1")
+ .subsub(ssr1)
+ .subsublist(ssr1 :: ssr2 :: Nil)
+ .slist("s1" :: "s2" :: Nil)
+ .smap(Map("a" -> "s1", "b" -> "s2"))
+ .pattern(Pattern.compile("^Mo", Pattern.CASE_INSENSITIVE))
+
+ val sr2 = SubRecord.createRecord.name("SubRecord2")
+
val srtr = SubRecordTestRecord.createRecord
.mandatoryBsonRecordField(sr1)
.mandatoryBsonRecordListField(List(sr1,sr2))
- val json = Printer.compact(render(mfttr.asJValue))
- val ljson = Printer.compact(render(ltr.asJValue))
- val mjson = Printer.compact(render(mtr.asJValue))
+ val sr1Json =
+ JObject(List(
+ JField("name", JString("SubRecord1")),
+ JField("subsub", JObject(List(
+ JField("name", JString("SubSubRecord1"))
+ ))),
+ JField("subsublist", JArray(List(
+ JObject(List(JField("name", JString("SubSubRecord1")))),
+ JObject(List(JField("name", JString("SubSubRecord2"))))
+ ))),
+ JField("when", JObject(List(
+ JField("$dt", JString(srtr.meta.formats.dateFormat.format(sr1.when.value)))
+ ))),
+ JField("slist", JArray(List(JString("s1"), JString("s2")))),
+ JField("smap", JObject(List(
+ JField("a", JString("s1")),
+ JField("b", JString("s2"))
+ ))),
+ JField("oid", JObject(List(JField("$oid", JString(sr1.oid.value.toString))))),
+ JField("pattern", JObject(List(
+ JField("$regex", JString(sr1.pattern.value.pattern)),
+ JField("$flags", JInt(sr1.pattern.value.flags))
+ ))),
+ JField("uuid", JObject(List(JField("$uuid", JString(sr1.uuid.value.toString)))))
+ ))
+
+ val sr2Json =
+ JObject(List(
+ JField("name", JString("SubRecord2")),
+ JField("subsub", JObject(List(
+ JField("name", JString(""))
+ ))),
+ JField("subsublist", JArray(List())),
+ JField("when", JObject(List(
+ JField("$dt", JString(srtr.meta.formats.dateFormat.format(sr2.when.value)))
+ ))),
+ JField("slist", JArray(List())),
+ JField("smap", JObject(List())),
+ JField("oid", JObject(List(JField("$oid", JString(sr2.oid.value.toString))))),
+ JField("pattern", JObject(List(
+ JField("$regex", JString(sr2.pattern.value.pattern)),
+ JField("$flags", JInt(sr2.pattern.value.flags))
+ ))),
+ JField("uuid", JObject(List(JField("$uuid", JString(sr2.uuid.value.toString)))))
+ ))
val srtrJson = JObject(List(
JField("_id", JObject(List(JField("$oid", JString(srtr.id.toString))))),
- JField("mandatoryBsonRecordField", JObject(List(JField("name", JString("SubRecord1"))))),
+ JField("mandatoryBsonRecordField", sr1Json),
JField("legacyOptionalBsonRecordField", JNothing),
JField("mandatoryBsonRecordListField", JArray(List(
- JObject(List(JField("name", JString("SubRecord1")))),
- JObject(List(JField("name", JString("SubRecord2"))))
+ sr1Json,
+ sr2Json
))),
JField("legacyOptionalBsonRecordListField", JArray(List()))
))
@@ -234,29 +323,36 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
fttr.save
- val fttrFromDb = FieldTypeTestRecord.find(fttr.id)
+ val fttrFromDb = FieldTypeTestRecord.find(fttr.id.value)
fttrFromDb must notBeEmpty
fttrFromDb foreach { tr =>
tr mustEqual fttr
}
}
- "save and retrieve Mongo type fields" in {
+ "delete record properly" 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 with set values" 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
}
ltr.save
- val ltrFromDb = ListTestRecord.find(ltr.id)
+ val ltrFromDb = ListTestRecord.find(ltr.id.value)
ltrFromDb must notBeEmpty
ltrFromDb foreach { tr =>
tr mustEqual ltr
@@ -264,7 +360,7 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
mtr.save
- val mtrFromDb = MapTestRecord.find(mtr.id)
+ val mtrFromDb = MapTestRecord.find(mtr.id.value)
mtrFromDb must notBeEmpty
mtrFromDb foreach { tr =>
tr mustEqual mtr
@@ -272,64 +368,61 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
srtr.save
- val srtrFromDb = SubRecordTestRecord.find(srtr.id)
+ val srtrFromDb = SubRecordTestRecord.find(srtr.id.value)
srtrFromDb must notBeEmpty
srtrFromDb foreach { tr =>
tr mustEqual srtr
}
}
+ "save and retrieve Mongo type fields with default values" in {
+ checkMongoIsRunning
+
+ val mfttrDef = MongoFieldTypeTestRecord.createRecord
+ mfttrDef.save
+
+ val mfttrFromDb = MongoFieldTypeTestRecord.find(mfttrDef.id.value)
+ mfttrFromDb must notBeEmpty
+ mfttrFromDb foreach { tr =>
+ tr mustEqual mfttrDef
+ }
+
+ val ltrDef = ListTestRecord.createRecord
+ ltrDef.save
+
+ val ltrFromDb = ListTestRecord.find(ltrDef.id.value)
+ ltrFromDb must notBeEmpty
+ ltrFromDb foreach { tr =>
+ tr mustEqual ltrDef
+ }
+
+ val mtrDef = MapTestRecord.createRecord
+ mtrDef.save
+
+ val mtrFromDb = MapTestRecord.find(mtrDef.id.value)
+ mtrFromDb must notBeEmpty
+ mtrFromDb foreach { tr =>
+ tr mustEqual mtrDef
+ }
+
+ val srtrDef = SubRecordTestRecord.createRecord
+ srtrDef.save
+
+ val srtrFromDb = SubRecordTestRecord.find(srtrDef.id.value)
+ srtrFromDb must notBeEmpty
+ srtrFromDb foreach { tr =>
+ tr mustEqual srtrDef
+ }
+ }
+
"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())),
- JField("mongoCaseClassListField",JArray(List(
- JObject(List(JField("intField", JInt(1)), JField("stringField", JString("str"))))
- )))
- ))
+ ltr.asJValue mustEqual ltrJson
- 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()))
- ))
+ mtr.asJValue mustEqual mtrJson
val srtrAsJValue = srtr.asJValue
srtrAsJValue \\ "_id" mustEqual srtrJson \\ "_id"
@@ -338,76 +431,23 @@ object MongoRecordSpec extends Specification("MongoRecord Specification") with M
srtrAsJValue \\ "mandatoryBsonRecordListField" mustEqual srtrJson \\ "mandatoryBsonRecordListField"
srtrAsJValue \\ "legacyOptionalBsonRecordListField" mustEqual srtrJson \\ "legacyOptionalBsonRecordListField"
}
-
- "convert Mongo type fields to JsExp" in {
- checkMongoIsRunning
-
- /*
- mfttr.asJsExp mustEqual JsObj(
- ("_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)))),
- ("legacyOptionalObjectIdField", Str("null")),
- ("mandatoryPatternField", JsObj(("$regex", Str(mfttr.mandatoryPatternField.value.pattern)), ("$flags", Num(mfttr.mandatoryPatternField.value.flags)))),
- ("legacyOptionalPatternField", Str("null")),
- ("mandatoryUUIDField", JsObj(("$uuid", Str(mfttr.mandatoryUUIDField.value.toString)))),
- ("legacyOptionalUUIDField", Str("null"))
- )*/
-
- /*
- ltr.asJsExp mustEqual JsObj(
- ("_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))),
- ("legacyOptionalIntListField", JsArray()),
- ("mandatoryMongoJsonObjectListField", JsArray(
- JsObj(("intField", Num(1)), ("stringField", Str("jsonobj1"))),
- JsObj(("intField", Num(2)), ("stringField", Str("jsonobj2")))
- )),
- ("legacyOptionalMongoJsonObjectListField", JsArray())
- )
-
- mtr.asJsExp mustEqual JsObj(
- ("_id", JsObj(("$oid", Str(mtr.id.toString)))),
- ("_id", JsObj(("$oid", Str(mtr.id.toString)))),
- ("mandatoryStringMapField", JsObj(
- ("a", Str("abc")),
- ("b", Str("def")),
- ("c", Str("ghi"))
- )),
- ("legacyOptionalStringMapField", JsObj()),
- ("mandatoryIntMapField", JsObj(
- ("a", Num(4)),
- ("b", Num(5)),
- ("c", Num(6))
- )),
- ("legacyOptionalIntMapField", JsObj())
- )*/
-
- }
"get set from json string using lift-json parser" in {
checkMongoIsRunning