Skip to content
This repository has been archived by the owner on Jan 15, 2022. It is now read-only.

Commit

Permalink
Added BitSet support to DBO, JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
rktoomey committed Nov 2, 2012
1 parent 285b555 commit bbe30b8
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 6 deletions.
1 change: 1 addition & 0 deletions notes/1.9.2.markdown
Expand Up @@ -4,5 +4,6 @@ Features new in Salat 1.9.2 include:
- switched from lift-json to [JSON4S][JSON4S] - switched from lift-json to [JSON4S][JSON4S]
- various fixes for JSON conversion, including an `Option` that contains a case object - various fixes for JSON conversion, including an `Option` that contains a case object
- support for converting `Map[String, _]` to compact rendered JSON - support for converting `Map[String, _]` to compact rendered JSON
- BitSet support


[JSON4S]: http://json4s.org/ [JSON4S]: http://json4s.org/
16 changes: 16 additions & 0 deletions salat-core/src/main/scala/com/novus/salat/json/ToJValue.scala
Expand Up @@ -76,6 +76,7 @@ object ToJValue extends Logging {
case t: MongoDBList => JArray(t.map(apply(_)).toList) case t: MongoDBList => JArray(t.map(apply(_)).toList)
case t: BasicDBList => JArray(t.map(apply(_)).toList) case t: BasicDBList => JArray(t.map(apply(_)).toList)
case dbo: DBObject => JObject(wrapDBObj(dbo).toList.map(v => JField(v._1, apply(v._2)))) case dbo: DBObject => JObject(wrapDBObj(dbo).toList.map(v => JField(v._1, apply(v._2))))
case ba: Array[Byte] => JArray(ba.toList.map(JInt(_)))
case m: Map[_, _] => JObject(m.toList.map(v => JField(v._1.toString, apply(v._2)))) case m: Map[_, _] => JObject(m.toList.map(v => JField(v._1.toString, apply(v._2))))
case m: java.util.Map[_, _] => JObject(scala.collection.JavaConversions.mapAsScalaMap(m).toList.map(v => JField(v._1.toString, apply(v._2)))) case m: java.util.Map[_, _] => JObject(scala.collection.JavaConversions.mapAsScalaMap(m).toList.map(v => JField(v._1.toString, apply(v._2))))
case iter: Iterable[_] => JArray(iter.map(apply(_)).toList) case iter: Iterable[_] => JArray(iter.map(apply(_)).toList)
Expand Down Expand Up @@ -121,6 +122,21 @@ object FromJValue extends Logging {
def apply(j: Option[JValue], field: SField, childType: Option[TypeRefType] = None)(implicit ctx: Context): Option[Any] = { def apply(j: Option[JValue], field: SField, childType: Option[TypeRefType] = None)(implicit ctx: Context): Option[Any] = {
val v = j.map { val v = j.map {
case j: JArray => field.typeRefType match { case j: JArray => field.typeRefType match {
case t if Types.isBitSet(t.symbol) => {
val bs = scala.collection.mutable.BitSet.empty
j.arr.foreach {
case JInt(bi) => bs.add(bi.toInt)
case x => sys.error("expected JInt got %s\n%s".format(x.getClass.getName, x))
}
val v = field.tf.path match {
case "scala.collection.BitSet" => scala.collection.BitSet.empty ++ bs
case "scala.collection.immutable.BitSet" => scala.collection.immutable.BitSet.empty ++ bs
case "scala.collection.mutable.BitSet" => bs
case x => sys.error("unexpected TypeRefType %s".format(field.tf.t))
}
log.debug("RETURNING: v=%s", v)
v
}
case IsTraversable(childType: TypeRefType) => j.arr.flatMap(v => apply(Some(v), field, Some(childType))) case IsTraversable(childType: TypeRefType) => j.arr.flatMap(v => apply(Some(v), field, Some(childType)))
case notTraversable => sys.error("FromJValue: expected types for Traversable but instead got:\n%s".format(notTraversable)) case notTraversable => sys.error("FromJValue: expected types for Traversable but instead got:\n%s".format(notTraversable))
} }
Expand Down
Expand Up @@ -136,6 +136,9 @@ package object out {
case TypeRefType(_, symbol, _) if isFloat(symbol.path) => case TypeRefType(_, symbol, _) if isFloat(symbol.path) =>
new Transformer(symbol.path, t)(ctx) with FloatToDouble new Transformer(symbol.path, t)(ctx) with FloatToDouble


case TypeRefType(_, symbol, _) if Types.isBitSet(symbol) =>
new Transformer(symbol.path, t)(ctx) with BitSetExtractor

case t @ TypeRefType(prefix @ SingleType(_, esym), sym, _) if sym.path == "scala.Enumeration.Value" => { case t @ TypeRefType(prefix @ SingleType(_, esym), sym, _) if sym.path == "scala.Enumeration.Value" => {
new Transformer(prefix.symbol.path, t)(ctx) with EnumStringifier new Transformer(prefix.symbol.path, t)(ctx) with EnumStringifier
} }
Expand Down Expand Up @@ -225,6 +228,16 @@ package out {
} }
} }


trait BitSetExtractor extends Transformer with Logging {

override def transform(value: Any)(implicit ctx: Context): Any = value

override def after(value: Any)(implicit ctx: Context): Option[Any] = value match {
case bs: scala.collection.BitSet => Some(bs.toArray.map(_.toByte))
case _ => None
}
}

trait MapExtractor extends Transformer { trait MapExtractor extends Transformer {
self: Transformer => self: Transformer =>
override def transform(value: Any)(implicit ctx: Context): Any = value override def transform(value: Any)(implicit ctx: Context): Any = value
Expand Down
Expand Up @@ -208,6 +208,9 @@ package object in extends Logging {
case TypeRefType(_, symbol, _) if isJodaDateTime(symbol.path) => case TypeRefType(_, symbol, _) if isJodaDateTime(symbol.path) =>
new Transformer(symbol.path, pt)(ctx) with DateToJodaDateTime new Transformer(symbol.path, pt)(ctx) with DateToJodaDateTime


case TypeRefType(_, symbol, _) if Types.isBitSet(symbol) =>
new Transformer(symbol.path, pt)(ctx) with BitSetInjector

case t @ TypeRefType(prefix @ SingleType(_, esym), sym, _) if sym.path == "scala.Enumeration.Value" => { case t @ TypeRefType(prefix @ SingleType(_, esym), sym, _) if sym.path == "scala.Enumeration.Value" => {
new Transformer(prefix.symbol.path, t)(ctx) with EnumInflater new Transformer(prefix.symbol.path, t)(ctx) with EnumInflater
} }
Expand Down Expand Up @@ -358,6 +361,25 @@ package in {
val parentType: TypeRefType val parentType: TypeRefType
} }


trait BitSetInjector extends Transformer with Logging {
override def transform(value: Any)(implicit ctx: Context): Any = value

override def after(value: Any)(implicit ctx: Context): Option[Any] = value match {
case ba: Array[Byte] => {
val bs = scala.collection.mutable.BitSet.empty
ba.foreach(b => bs.add(b))
Option(path match {
case "scala.collection.BitSet" => scala.collection.BitSet.empty ++ bs
case "scala.collection.immutable.BitSet" => scala.collection.immutable.BitSet.empty ++ bs
case "scala.collection.mutable.BitSet" => bs
case x => sys.error("unexpected TypeRefType %s".format(t))
})
}
case bs: scala.collection.BitSet => Some(bs)
case _ => None
}
}

trait MapInjector extends Transformer { trait MapInjector extends Transformer {
self: Transformer => self: Transformer =>
override def transform(value: Any)(implicit ctx: Context): Any = value override def transform(value: Any)(implicit ctx: Context): Any = value
Expand Down
Expand Up @@ -24,12 +24,11 @@
*/ */
package com.novus.salat.test package com.novus.salat.test


import com.novus.salat._
import com.novus.salat.test.global._
import com.mongodb.casbah.Imports._ import com.mongodb.casbah.Imports._
import com.mongodb.casbah.commons.MongoDBObject import com.mongodb.casbah.commons.MongoDBObject
import com.novus.salat.util.MapPrettyPrinter import com.novus.salat._
import com.novus.salat.dao.SalatDAO import com.novus.salat.dao.SalatDAO
import com.novus.salat.test.global._
import com.novus.salat.test.model._ import com.novus.salat.test.model._


class CollectionSupportSpec extends SalatSpec { class CollectionSupportSpec extends SalatSpec {
Expand Down Expand Up @@ -359,5 +358,23 @@ class CollectionSupportSpec extends SalatSpec {
} }


// TODO: moar collection types // TODO: moar collection types

"support BitSet" in {
"scala.collection.BitSet" in {
val coll = scala.collection.BitSet(0, 5, 10, 15)
val x = XRay(coll = coll)
grater[XRay].asObject(grater[XRay].asDBObject(x)) must_== x
}
"scala.collection.immutable.BitSet" in {
val coll = scala.collection.immutable.BitSet(0, 5, 10, 15)
val y = Yoke(coll = coll)
grater[Yoke].asObject(grater[Yoke].asDBObject(y)) must_== y
}
"scala.collection.mutable.BitSet" in {
val coll = scala.collection.mutable.BitSet(0, 5, 10, 15)
val y = Zebra(coll = coll)
grater[Zebra].asObject(grater[Zebra].asDBObject(y)) must_== y
}
}
} }
} }
Expand Up @@ -63,6 +63,7 @@ case class Roger(@Key("_id") id: ObjectId = new ObjectId, coll: scala.collection
//Uncle //Uncle
//Victor //Victor
//William //William
//X-ray
//Yoke case class XRay(@Key("_id") id: ObjectId = new ObjectId, coll: scala.collection.BitSet)
//Zebra case class Yoke(@Key("_id") id: ObjectId = new ObjectId, coll: scala.collection.immutable.BitSet)
case class Zebra(@Key("_id") id: ObjectId = new ObjectId, coll: scala.collection.mutable.BitSet)
12 changes: 12 additions & 0 deletions salat-util/src/main/scala/com/novus/salat/TypeMatchers.scala
Expand Up @@ -36,21 +36,28 @@ protected[salat] object Types {
val Option = "scala.Option" val Option = "scala.Option"
val Map = ".Map" val Map = ".Map"
val Traversables = Set(".Seq", ".List", ".Vector", ".Set", ".Buffer", ".ArrayBuffer", ".IndexedSeq", ".LinkedList", ".DoubleLinkedList") val Traversables = Set(".Seq", ".List", ".Vector", ".Set", ".Buffer", ".ArrayBuffer", ".IndexedSeq", ".LinkedList", ".DoubleLinkedList")
val BitSets = Set("scala.collection.BitSet", "scala.collection.immutable.BitSet", "scala.collection.mutable.BitSet")


def isOption(sym: Symbol) = sym.path == Option def isOption(sym: Symbol) = sym.path == Option


def isMap(symbol: Symbol) = symbol.path.endsWith(Map) def isMap(symbol: Symbol) = symbol.path.endsWith(Map)


def isTraversable(symbol: Symbol) = Traversables.exists(symbol.path.endsWith(_)) def isTraversable(symbol: Symbol) = Traversables.exists(symbol.path.endsWith(_))


def isBitSet(symbol: Symbol) = BitSets.contains(symbol.path)

def isBigDecimal(symbol: Symbol) = symbol.path == SBigDecimal def isBigDecimal(symbol: Symbol) = symbol.path == SBigDecimal


def isBigInt(symbol: Symbol) = symbol.path == BigInt def isBigInt(symbol: Symbol) = symbol.path == BigInt
} }


protected[salat] case class TypeFinder(t: TypeRefType) { protected[salat] case class TypeFinder(t: TypeRefType) {

lazy val path = t.symbol.path

lazy val isMap = Types.isMap(t.symbol) lazy val isMap = Types.isMap(t.symbol)
lazy val isTraversable = Types.isTraversable(t.symbol) lazy val isTraversable = Types.isTraversable(t.symbol)
lazy val isBitSet = Types.isBitSet(t.symbol)


lazy val isDate = TypeMatchers.matches(t, Types.Date) lazy val isDate = TypeMatchers.matches(t, Types.Date)
lazy val isDateTime = TypeMatchers.matches(t, Types.DateTime) lazy val isDateTime = TypeMatchers.matches(t, Types.DateTime)
Expand Down Expand Up @@ -90,6 +97,11 @@ protected[salat] object TypeMatchers {
case TypeRefType(_, symbol, List(arg)) if Types.isTraversable(symbol) => Some(arg) case TypeRefType(_, symbol, List(arg)) if Types.isTraversable(symbol) => Some(arg)
case _ => None case _ => None
} }

def matchesBitSet(t: Type) = t match {
case TypeRefType(_, symbol, _) if Types.isBitSet(symbol) => Some(symbol)
case _ => None
}
} }


protected[salat] object IsOption { protected[salat] object IsOption {
Expand Down

0 comments on commit bbe30b8

Please sign in to comment.