Permalink
Browse files

Added BitSet support to DBO, JSON

  • Loading branch information...
1 parent 285b555 commit bbe30b888dda3c6921076b9634e1894a5124bb87 @rktoomey rktoomey committed Nov 2, 2012
View
@@ -4,5 +4,6 @@ Features new in Salat 1.9.2 include:
- switched from lift-json to [JSON4S][JSON4S]
- various fixes for JSON conversion, including an `Option` that contains a case object
- support for converting `Map[String, _]` to compact rendered JSON
+- BitSet support
[JSON4S]: http://json4s.org/
@@ -76,6 +76,7 @@ object ToJValue extends Logging {
case t: MongoDBList => 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 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: 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)
@@ -121,6 +122,21 @@ object FromJValue extends Logging {
def apply(j: Option[JValue], field: SField, childType: Option[TypeRefType] = None)(implicit ctx: Context): Option[Any] = {
val v = j.map {
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 notTraversable => sys.error("FromJValue: expected types for Traversable but instead got:\n%s".format(notTraversable))
}
@@ -136,6 +136,9 @@ package object out {
case TypeRefType(_, symbol, _) if isFloat(symbol.path) =>
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" => {
new Transformer(prefix.symbol.path, t)(ctx) with EnumStringifier
}
@@ -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 {
self: Transformer =>
override def transform(value: Any)(implicit ctx: Context): Any = value
@@ -208,6 +208,9 @@ package object in extends Logging {
case TypeRefType(_, symbol, _) if isJodaDateTime(symbol.path) =>
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" => {
new Transformer(prefix.symbol.path, t)(ctx) with EnumInflater
}
@@ -358,6 +361,25 @@ package in {
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 {
self: Transformer =>
override def transform(value: Any)(implicit ctx: Context): Any = value
@@ -24,12 +24,11 @@
*/
package com.novus.salat.test
-import com.novus.salat._
-import com.novus.salat.test.global._
import com.mongodb.casbah.Imports._
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.test.global._
import com.novus.salat.test.model._
class CollectionSupportSpec extends SalatSpec {
@@ -359,5 +358,23 @@ class CollectionSupportSpec extends SalatSpec {
}
// 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
+ }
+ }
}
}
@@ -63,6 +63,7 @@ case class Roger(@Key("_id") id: ObjectId = new ObjectId, coll: scala.collection
//Uncle
//Victor
//William
-//X-ray
-//Yoke
-//Zebra
+
+case class XRay(@Key("_id") id: ObjectId = new ObjectId, coll: scala.collection.BitSet)
+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)
@@ -36,21 +36,28 @@ protected[salat] object Types {
val Option = "scala.Option"
val Map = ".Map"
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 isMap(symbol: Symbol) = symbol.path.endsWith(Map)
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 isBigInt(symbol: Symbol) = symbol.path == BigInt
}
protected[salat] case class TypeFinder(t: TypeRefType) {
+
+ lazy val path = t.symbol.path
+
lazy val isMap = Types.isMap(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 isDateTime = TypeMatchers.matches(t, Types.DateTime)
@@ -90,6 +97,11 @@ protected[salat] object TypeMatchers {
case TypeRefType(_, symbol, List(arg)) if Types.isTraversable(symbol) => Some(arg)
case _ => None
}
+
+ def matchesBitSet(t: Type) = t match {
+ case TypeRefType(_, symbol, _) if Types.isBitSet(symbol) => Some(symbol)
+ case _ => None
+ }
}
protected[salat] object IsOption {

0 comments on commit bbe30b8

Please sign in to comment.