How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration

MongodbClassScalaRecordLift

Mongodb Problem Overview


I am upgrading existing code from Rogue 1.1.8 to 2.0.0 and lift-mongodb-record from 2.4-M5 to 2.5.

I'm having difficulty writing MongoCaseClassField that contains a scala enum, that I really could use some help with.

For example,

object MyEnum extends Enumeration {
  type MyEnum = Value
  val A = Value(0)
  val B = Value(1)
}

case class MyCaseClass(name: String, value: MyEnum.MyEnum)

class MyMongo extends MongoRecord[MyMongo] with StringPk[MyMongo] {
  def meta = MyMongo

  class MongoCaseClassFieldWithMyEnum[OwnerType <: net.liftweb.record.Record[OwnerType], CaseType](rec : OwnerType)(implicit mf : Manifest[CaseType]) extends MongoCaseClassField[OwnerType, CaseType](rec)(mf) {
    override def formats = super.formats + new EnumSerializer(MyEnum)
  }

  object myCaseClass extends MongoCaseClassFieldWithMyEnum[MyMongo, MyCaseClass](this)
  /// ...
}

When we try to write to this field, we get the following error:

> could not find implicit value for evidence parameter of type > com.foursquare.rogue.BSONType[MyCaseClass] > .and(_.myCaseClass setTo myCaseClass)

We used to have this working in Rogue 1.1.8, by using our own version of the MongoCaseClassField, which made the #formats method overridable. But that feature was included into lift-mongodb-record in 2.5-RC6, so we thought this should just work now?

Mongodb Solutions


Solution 1 - Mongodb

Answer coming from : http://grokbase.com/t/gg/rogue-users/1367nscf80/how-to-update-a-record-with-mongocaseclassfield-when-case-class-contains-a-scala-enumeration#20130612woc3x7utvaoacu7tv7lzn4sr2q

But more convenient directly here on StackOverFlow:


Sorry, I should have chimed in here sooner.

One of the long-standing problems with Rogue was that it was too easy to accidentally make a field that was not serializable as BSON, and have it fail at runtime (when you try to add that value to a DBObject) rather than at compile time.

I introduced the BSONType type class to try to address this. The upside is it catches BSON errors at compile time. The downside is you need to make a choice when it comes to case classes.

If you want to do this the "correct" way, define your case class plus a BSONType "witness" for that case class. To define a BSONType witness, you need to provide serialization from that type to a BSON type. Example:

 case class TestCC(v: Int)

 implicit object TestCCIsBSONType extends BSONType[TestCC] {
   override def asBSONObject(v: TestCC): AnyRef = {
     // Create a BSON object
     val ret = new BasicBSONObject
     // Serialize all the fields of the case class
     ret.put("v", v.v)
     ret
   }
 }

That said, this can be quite burdensome if you're doing it for each case class. Your second option is to define a generic witness that works for any case class, if you have a generic serialization scheme:

 implicit def CaseClassesAreBSONTypes[CC <: CaseClass]: BSONType[CC] =
new BSONType[CC] {
   override def asBSONObject(v: CC): AnyRef = {
     // your generic serialization code here, maybe involving formats
   }
 }

Hope this helps,

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJuneyt DonmezView Question on Stackoverflow
Solution 1 - MongodbValentin MontmirailView Answer on Stackoverflow