2013-05-16 1 views
0

subset2을 사용하여 DBObject와 case 클래스 객체를 구문 분석하는 방법을 아는 사람이 있습니까? 슈퍼 간결 문서는어떻게 DBObject를 case2 클래스를 사용하여 case 클래스 객체로 파싱합니까?

이 경우 클래스를

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() 
    } 
) 
} 

을 다음 고려 :(나에게 도움이되지 않으며 나는 내가 마지막 필드 subitems를 제거하면 작동

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) 
    } 
} 

이 파서를 썼다. 그러나 버전은 위 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 { 
                                       ^

마지막으로 get이 암시 적으로 Field[MenuItem]을 원하기 때문에 분명히 컴파일되지 않습니다. 하지만 내가 MenuItem에 대해 정의한다면 꽤 많은 복사 - 붙여 넣기 DocParser[MenuItem] 않을까요?

어떻게 우아하게 할 수 있습니까?

+0

은 당신의 컴파일 오류를 생성하는 코드 또는 기대하는 동작을 얻지 못하고 있습니까? – cmbaxter

+0

컴파일 오류 – expert

답변

2

저는 Subset (모두 1.x와 2)의 저자입니다. 당신이 읽고 싶은 모든 T

그냥 보조 노트 (는 "직렬화"섹션의) 당 Field[T]이 필요

README 상태. 솔직히 MenuItem에 대한 디시리얼라이저의 이름을 jodaDateTime으로 지정하는 것은 매우 논리적이지 않습니다.

어쨌든 Field[T]은 바닐라 BSON 유형을 T으로 변환해야합니다. BSON는 기본적으로 MenuItem를 저장하는 기본 BSON 유형

here를 참조하지만 확실히 큰 문제는 그래서 당신의 "시리얼"(BsonWritable)와 "디시리얼라이저"(Field가) 순환뿐만 아니라해야합니다, 당신은 재귀 데이터 구조를 가지고있다 할 수 없다. 서브 세트에는 List[T]에 대한 내재적 직렬화/비 직렬 화가가 있지만 MenuItem : 재귀 용으로 제공해야합니다.

간단하게하기 위해, 더 간단한 "사례 클래스"에 대해 이와 비슷한 것을 어떻게 쓸 것인지 보여 드리겠습니다. Field[Rec]

우리가

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

는 그런 작가는 "DBOBJECT"로 rec.children를 작성하고 여기에

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

처럼 보일 수 있다고 가정 BsonWriteable[Rec]을 사용하는 경우와이 필요 "암시" 차례로. 따라서이 시리얼 라이저 입니다.(! lazy val를 사용하는 기억)

디시리얼라이저로, 다음은 이러한 상호 재귀

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) 
    } 
} 

않는 것

을 당신과 같이 사용할 것이다 :

val dbo = DBO("y" -> Rec(123, Some(Rec(234, None) :: Nil)))() 
val Y = DocParser.get[Rec]("y") 
dbo match { 
    case Y(doc) => doc 
} 
+0

이것은 최고입니다! 고마워요! – expert

+0

Alexander, 그냥 궁금해서. 라이브러리에'List [T]'에'BsonWritable '이없는 이유는 무엇입니까? – expert

+0

'Seq [T]'는 좀 더 일반적이고'List'를 위해 선택 될 것입니다. (더 자세한 정보가 필요하면 스칼라에서 공분산에 대해 읽으십시오. 또 다른 좋은 읽을 거리는 "타입 클래스"에 관한 것입니다) –