0

Subset2 を使用してDBObjectをケース クラス オブジェクトに解析する方法を知っている人はいますか? 非常に簡潔なドキュメントは役に立ちません:(

次のケースクラスを検討してください

case class MenuItem(id : Int, name: String, desc: Option[String], prices: Option[Array[String]], subitems: Option[Array[MenuItem]])

object MenuItem {
  implicit val asBson = BsonWritable[MenuItem](item =>
    {
      val buf: DBObjectBuffer = DBO("id" -> item.id, "name" -> item.name)
      item.desc match { case Some(value) => buf.append("desc" -> value) case None => }
      item.prices match { case Some(value) => buf.append("prices" -> value) case None => }
      item.subitems match { case Some(value) => buf.append("subitems" -> value) case None => }
      buf()
    }
  )
}

そして私はこのパーサーを書きました

val menuItemParser: DocParser[MenuItem] = int("id") ~ str("name") ~ str("desc").opt ~ get[Array[String]]("prices").opt ~ get[Array[MenuItem]]("subitems").opt map {
  case id ~ name ~ desc_opt ~ prices_opt ~ subitems => {
    MenuItem(id, name, desc_opt, prices_opt, subitems)
  }
}

last field を削除すると機能しますsubitems。ただし、上記のバージョンはMenuItem、それ自体を参照するフィールドがあるため、コンパイルされません。次のエラーが表示されます

Cannot find Field for Array[com.borsch.model.MenuItem]
    val menuItemParser: DocParser[MenuItem] = int("id") ~ str("name") ~ str("desc").opt ~ get[Array[String]]("prices").opt ~ get[Array[MenuItem]]("subitems").opt map {
                                                                                                                                                 ^

last は暗黙的をget望んでいるため、明らかにコンパイルされません。Field[MenuItem]しかし、私がそれを定義した場合、それはMenuItemほとんどのコピーアンドペーストではDocParser[MenuItem]ないでしょうか?

どのようにエレガントにしますか?

4

1 に答える 1

2

私はサブセット (1.x と 2 の両方) の作成者です。

READMEには、読みたいものごとに必要であると記載されています( Field[T]Tデシリアライゼーション」セクションの下にあります)。

補足です。率直に言って、デシリアライザーの名前を にするのはあまり論理的ではありませMenuItemjodaDateTime

とにかくField[T]、バニラの BSON タイプからあなたのT. BSON はネイティブに保存できません。ここでMenuItemネイティブ BSON タイプを参照してください

しかし、確かに主な問題は、再帰的なデータ構造を持っていることです。そのため、BsonWritable「シリアライザー」( ) と「デシリアライザー」 ( Field) も再帰的でなければなりません。サブセットには の暗黙的なシリアライザー/デシリアライザーがありますが、再帰List[T]のためにそれらを提供する必要があります。MenuItem

簡単にするために、より単純な「ケースクラス」に対してそのようなものをどのように書くかを示します。

私たちが持っているとしましょう

case class Rec(id: Int, children: Option[List[Rec]])

それから作家は次のように見えるかもしれません

object Rec {
  implicit object asBson extends BsonWritable[Rec] {
    override def apply(rec: Rec) =
      Some( DBO("id" -> rec.id, "children" -> rec.children)() )
  }

ここで、rec.children「DBObject」に書き込む場合、BsonWriteable[Rec]が使用されており、「暗黙的」が必要Field[Rec]です。したがって、このシリアライザー再帰的です。

デシリアライザーの時点で、次のようになります

  import DocParser._

  implicit lazy val recField = Field({ case Doc(rec) => rec })
  lazy val Doc: DocParser[Rec] =
    get[Int]("id") ~ get[List[Rec]]("children").opt map {
      case id ~ children => new Rec(id, children)
    }
}

これらは相互に再帰的です (使用することを忘れないでlazy valください!)

次のように使用します。

val dbo = DBO("y" -> Rec(123, Some(Rec(234, None) :: Nil))) ()
val Y = DocParser.get[Rec]("y")
dbo match {
  case Y(doc) => doc
}
于 2013-05-17T07:10:06.337 に答える