study flat chapters WIP
parent
570c6b4857
commit
29f506a41e
|
@ -9,6 +9,7 @@ import reactivemongo.api.bson._
|
|||
import scala.util.Success
|
||||
import scala.util.Try
|
||||
|
||||
import lila.common.Iso
|
||||
import lila.db.BSON
|
||||
import lila.db.BSON.{ Reader, Writer }
|
||||
import lila.db.dsl._
|
||||
|
@ -16,8 +17,6 @@ import lila.tree.Eval
|
|||
import lila.tree.Eval.Score
|
||||
import lila.tree.Node.{ Comment, Comments, Gamebook, Shape, Shapes }
|
||||
|
||||
import lila.common.Iso
|
||||
|
||||
object BSONHandlers {
|
||||
|
||||
import Chapter._
|
||||
|
@ -159,65 +158,50 @@ object BSONHandlers {
|
|||
)
|
||||
}
|
||||
|
||||
implicit val ChildrenBSONHandler: BSONHandler[Node.Children] = tryHandler[Node.Children](
|
||||
{ case arr: BSONArray =>
|
||||
Try {
|
||||
Node.Children(arr.values.view.flatMap(NodeBSONHandler.readOpt).toVector)
|
||||
}
|
||||
},
|
||||
children =>
|
||||
BSONArray(children.nodes map { n =>
|
||||
NodeBSONHandler.writeTry(n).get
|
||||
})
|
||||
)
|
||||
|
||||
implicit lazy val NodeBSONHandler: BSON[Node] = new BSON[Node] {
|
||||
def reads(r: Reader) =
|
||||
Node(
|
||||
id = r.get[UciCharPair]("i"),
|
||||
ply = r int "p",
|
||||
move = WithSan(r.get[Uci]("u"), r.str("s")),
|
||||
fen = r.get[FEN]("f"),
|
||||
check = r boolD "c",
|
||||
shapes = r.getO[Shapes]("h") | Shapes.empty,
|
||||
comments = r.getO[Comments]("co") | Comments.empty,
|
||||
gamebook = r.getO[Gamebook]("ga"),
|
||||
glyphs = r.getO[Glyphs]("g") | Glyphs.empty,
|
||||
score = r.getO[Score]("e"),
|
||||
crazyData = r.getO[Crazyhouse.Data]("z"),
|
||||
clock = r.getO[Centis]("l"),
|
||||
children =
|
||||
try {
|
||||
r.get[Node.Children]("n")
|
||||
} catch {
|
||||
case _: StackOverflowError =>
|
||||
logger.warn(s"study ChildrenBSONHandler StackOverflowError")
|
||||
Node.emptyChildren
|
||||
},
|
||||
forceVariation = r boolD "fv"
|
||||
)
|
||||
def writes(w: Writer, s: Node) =
|
||||
$doc(
|
||||
"i" -> s.id,
|
||||
"p" -> s.ply,
|
||||
"u" -> s.move.uci,
|
||||
"s" -> s.move.san,
|
||||
"f" -> s.fen,
|
||||
"c" -> w.boolO(s.check),
|
||||
"h" -> s.shapes.value.nonEmpty.option(s.shapes),
|
||||
"co" -> s.comments.value.nonEmpty.option(s.comments),
|
||||
"ga" -> s.gamebook,
|
||||
"g" -> s.glyphs.nonEmpty,
|
||||
"e" -> s.score,
|
||||
"l" -> s.clock,
|
||||
"z" -> s.crazyData,
|
||||
"n" -> (if (s.ply < Node.MAX_PLIES) s.children else Node.emptyChildren),
|
||||
"fv" -> w.boolO(s.forceVariation)
|
||||
)
|
||||
def readNode(doc: Bdoc, id: UciCharPair): Node = {
|
||||
val r = new Reader(doc)
|
||||
Node(
|
||||
id = id,
|
||||
ply = r int "p",
|
||||
move = WithSan(r.get[Uci]("u"), r.str("s")),
|
||||
fen = r.get[FEN]("f"),
|
||||
check = r boolD "c",
|
||||
shapes = r.getO[Shapes]("h") | Shapes.empty,
|
||||
comments = r.getO[Comments]("co") | Comments.empty,
|
||||
gamebook = r.getO[Gamebook]("ga"),
|
||||
glyphs = r.getO[Glyphs]("g") | Glyphs.empty,
|
||||
score = r.getO[Score]("e"),
|
||||
crazyData = r.getO[Crazyhouse.Data]("z"),
|
||||
clock = r.getO[Centis]("l"),
|
||||
children = Node.emptyChildren,
|
||||
forceVariation = r boolD "fv"
|
||||
)
|
||||
}
|
||||
|
||||
def writeNode(s: Node) = {
|
||||
val w = new Writer
|
||||
$doc(
|
||||
"p" -> s.ply,
|
||||
"u" -> s.move.uci,
|
||||
"s" -> s.move.san,
|
||||
"f" -> s.fen,
|
||||
"c" -> w.boolO(s.check),
|
||||
"h" -> s.shapes.value.nonEmpty.option(s.shapes),
|
||||
"co" -> s.comments.value.nonEmpty.option(s.comments),
|
||||
"ga" -> s.gamebook,
|
||||
"g" -> s.glyphs.nonEmpty,
|
||||
"e" -> s.score,
|
||||
"l" -> s.clock,
|
||||
"z" -> s.crazyData,
|
||||
"fv" -> w.boolO(s.forceVariation)
|
||||
)
|
||||
}
|
||||
|
||||
import Node.Root
|
||||
implicit private[study] lazy val NodeRootBSONHandler: BSON[Root] = new BSON[Root] {
|
||||
def reads(r: Reader) =
|
||||
def reads(fullReader: Reader) = {
|
||||
val rootNode = fullReader.doc.getAsOpt[Bdoc]("") err "Missing root"
|
||||
val r = new Reader(rootNode)
|
||||
Root(
|
||||
ply = r int "p",
|
||||
fen = r.get[FEN]("f"),
|
||||
|
@ -229,22 +213,22 @@ object BSONHandlers {
|
|||
score = r.getO[Score]("e"),
|
||||
clock = r.getO[Centis]("l"),
|
||||
crazyData = r.getO[Crazyhouse.Data]("z"),
|
||||
children = r.get[Node.Children]("n")
|
||||
)
|
||||
def writes(w: Writer, s: Root) =
|
||||
$doc(
|
||||
"p" -> s.ply,
|
||||
"f" -> s.fen,
|
||||
"c" -> w.boolO(s.check),
|
||||
"h" -> s.shapes.value.nonEmpty.option(s.shapes),
|
||||
"co" -> s.comments.value.nonEmpty.option(s.comments),
|
||||
"ga" -> s.gamebook,
|
||||
"g" -> s.glyphs.nonEmpty,
|
||||
"e" -> s.score,
|
||||
"l" -> s.clock,
|
||||
"z" -> s.crazyData,
|
||||
"n" -> s.children
|
||||
children = StudyFlatTree.rootChildren(fullReader.doc)
|
||||
)
|
||||
}
|
||||
def writes(w: Writer, s: Root) = ???
|
||||
// $doc(
|
||||
// "p" -> s.ply,
|
||||
// "f" -> s.fen,
|
||||
// "c" -> w.boolO(s.check),
|
||||
// "h" -> s.shapes.value.nonEmpty.option(s.shapes),
|
||||
// "co" -> s.comments.value.nonEmpty.option(s.comments),
|
||||
// "ga" -> s.gamebook,
|
||||
// "g" -> s.glyphs.nonEmpty,
|
||||
// "e" -> s.score,
|
||||
// "l" -> s.clock,
|
||||
// "z" -> s.crazyData
|
||||
// )
|
||||
}
|
||||
|
||||
implicit val PathBSONHandler = BSONStringHandler.as[Path](Path.apply, _.toString)
|
||||
|
|
|
@ -126,7 +126,9 @@ final class ChapterRepo(val coll: Coll)(implicit
|
|||
|
||||
def setScore(score: Option[lila.tree.Eval.Score]) = setNodeValue("e", score) _
|
||||
|
||||
def setChildren(children: Node.Children) = setNodeValue("n", children.some) _
|
||||
def setChildren(children: Node.Children)(chapter: Chapter, path: Path): Funit =
|
||||
??? // TODO
|
||||
// setNodeValue("n", children.some) _
|
||||
|
||||
private def setNodeValue[A: BSONWriter](
|
||||
field: String,
|
||||
|
@ -152,14 +154,15 @@ final class ChapterRepo(val coll: Coll)(implicit
|
|||
}
|
||||
|
||||
private[study] def setChild(chapter: Chapter, path: Path, child: Node): Funit =
|
||||
pathToField(chapter, path, "n") ?? { parentChildrenPath =>
|
||||
coll.update.one(
|
||||
$id(chapter.id) ++ $doc(s"$parentChildrenPath.i" -> child.id),
|
||||
$set(s"$parentChildrenPath.$$" -> child)
|
||||
) flatMap { res =>
|
||||
(res.n == 0) ?? coll.update.one($id(chapter.id), $push(parentChildrenPath -> child)).void
|
||||
}
|
||||
}
|
||||
??? // TODO
|
||||
// pathToField(chapter, path, "n") ?? { parentChildrenPath =>
|
||||
// coll.update.one(
|
||||
// $id(chapter.id) ++ $doc(s"$parentChildrenPath.i" -> child.id),
|
||||
// $set(s"$parentChildrenPath.$$" -> child)
|
||||
// ) flatMap { res =>
|
||||
// (res.n == 0) ?? coll.update.one($id(chapter.id), $push(parentChildrenPath -> child)).void
|
||||
// }
|
||||
// }
|
||||
|
||||
private[study] def idNamesByStudyIds(
|
||||
studyIds: Seq[Study.Id],
|
||||
|
|
|
@ -46,7 +46,7 @@ final class Env(
|
|||
private val socket = wire[StudySocket]
|
||||
|
||||
lazy val studyRepo = new StudyRepo(db(CollName("study")))
|
||||
lazy val chapterRepo = new ChapterRepo(db(CollName("study_chapter")))
|
||||
lazy val chapterRepo = new ChapterRepo(db(CollName("study_chapter_flat")))
|
||||
private lazy val topicRepo = new StudyTopicRepo(db(CollName("study_topic")))
|
||||
private lazy val userTopicRepo = new StudyUserTopicRepo(db(CollName("study_user_topic")))
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package lila.study
|
||||
|
||||
import BSONHandlers._
|
||||
import Node.Children
|
||||
|
||||
import lila.db.dsl._
|
||||
import lila.tree.Eval
|
||||
import lila.tree.Eval.Score
|
||||
|
||||
private object StudyFlatTree {
|
||||
|
||||
private case class FlatNode(path: Path, data: Bdoc) {
|
||||
val depth = path.ids.size
|
||||
|
||||
def toNodeWithChildren(children: Option[Children]): Node = {
|
||||
readNode(data, path.ids.last)
|
||||
}.copy(children = children | Node.emptyChildren)
|
||||
}
|
||||
|
||||
def rootChildren(flatTree: Bdoc): Children = traverse {
|
||||
flatTree.elements.toList
|
||||
.collect {
|
||||
case el if el.name.nonEmpty => FlatNode(Path(el.name), el.value.asOpt[Bdoc].get)
|
||||
}
|
||||
.sortBy(-_.depth)
|
||||
}
|
||||
|
||||
private def traverse(children: List[FlatNode]): Children =
|
||||
children
|
||||
.foldLeft(Map.empty[Path, Children]) { case (allChildren, flat) =>
|
||||
update(allChildren, flat)
|
||||
}
|
||||
.get(Path.root) | Node.emptyChildren
|
||||
|
||||
// assumes that node has a greater depth than roots (sort beforehand)
|
||||
private def update(roots: Map[Path, Children], flat: FlatNode): Map[Path, Children] = {
|
||||
val node = flat.toNodeWithChildren(roots get flat.path)
|
||||
roots.removed(flat.path).updatedWith(flat.path.init) {
|
||||
case None => Children(Vector(node)).some
|
||||
case Some(siblings) => siblings.addNode(node).some
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue