optimise study comment updates

pull/2881/head
Thibault Duplessis 2017-03-31 13:37:08 +02:00
parent 28f619c815
commit 8b4797797d
4 changed files with 46 additions and 26 deletions

View File

@ -80,7 +80,7 @@ object BSONHandlers {
implicit val ShapesBSONHandler: BSONHandler[BSONArray, Shapes] =
isoHandler[Shapes, List[Shape], BSONArray](
(s: Shapes) => s.value.distinct,
(s: Shapes) => s.value,
Shapes(_)
)
@ -108,8 +108,11 @@ object BSONHandlers {
}
private implicit val CommentBSONHandler = Macros.handler[Comment]
private def readComments(r: Reader) =
Comments(r.getsD[Comment]("co").filter(_.text.value.nonEmpty))
implicit val CommentsBSONHandler: BSONHandler[BSONArray, Comments] =
isoHandler[Comments, List[Comment], BSONArray](
(s: Comments) => s.value,
Comments(_)
)
private implicit def CrazyDataBSONHandler: BSON[Crazyhouse.Data] = new BSON[Crazyhouse.Data] {
private def writePocket(p: Crazyhouse.Pocket) = p.roles.map(_.forsyth).mkString
@ -143,7 +146,7 @@ object BSONHandlers {
fen = r.get[FEN]("f"),
check = r boolD "c",
shapes = r.getO[Shapes]("h") | Shapes.empty,
comments = readComments(r),
comments = r.getO[Comments]("co") | Comments.empty,
glyphs = r.getO[Glyphs]("g") | Glyphs.empty,
crazyData = r.getO[Crazyhouse.Data]("z"),
clock = r.getO[Centis]("l"),
@ -156,8 +159,8 @@ object BSONHandlers {
"s" -> s.move.san,
"f" -> s.fen,
"c" -> w.boolO(s.check),
"h" -> w.listO(s.shapes.list.distinct),
"co" -> w.listO(s.comments.list),
"h" -> s.shapes.value.nonEmpty.option(s.shapes),
"co" -> s.comments.value.nonEmpty.option(s.comments),
"g" -> s.glyphs.nonEmpty,
"l" -> s.clock,
"z" -> s.crazyData,
@ -171,7 +174,7 @@ object BSONHandlers {
fen = r.get[FEN]("f"),
check = r boolD "c",
shapes = r.getO[Shapes]("h") | Shapes.empty,
comments = readComments(r),
comments = r.getO[Comments]("co") | Comments.empty,
glyphs = r.getO[Glyphs]("g") | Glyphs.empty,
clock = r.getO[Centis]("l"),
crazyData = r.getO[Crazyhouse.Data]("z"),
@ -181,8 +184,8 @@ object BSONHandlers {
"p" -> s.ply,
"f" -> s.fen,
"c" -> w.boolO(s.check),
"h" -> w.listO(s.shapes.list.distinct),
"co" -> w.listO(s.comments.list),
"h" -> s.shapes.value.nonEmpty.option(s.shapes),
"co" -> s.comments.value.nonEmpty.option(s.comments),
"g" -> s.glyphs.nonEmpty,
"l" -> s.clock,
"z" -> s.crazyData,

View File

@ -59,17 +59,28 @@ final class ChapterRepo(coll: Coll) {
def setTagsFor(chapter: Chapter) =
coll.updateField($id(chapter.id), "tags", chapter.tags).void
def setShapes(chapter: Chapter, path: Path, shapes: lila.tree.Node.Shapes): Option[Funit] =
pathToField(chapter, path) map { field =>
val shapesField = s"$field.h"
if (shapes.value.isEmpty) coll.unsetField($id(chapter.id), shapesField).void
else coll.updateField($id(chapter.id), shapesField, shapes).void
def setShapes(chapter: Chapter, path: Path, shapes: lila.tree.Node.Shapes): Funit =
setNodeValue(chapter, path, "h", shapes.value.nonEmpty option shapes)
def setComments(chapter: Chapter, path: Path, comments: lila.tree.Node.Comments): Funit =
setNodeValue(chapter, path, "co", comments.value.nonEmpty option comments)
private def setNodeValue[A: BSONValueWriter](chapter: Chapter, path: Path, field: String, value: Option[A]): Funit =
pathToField(chapter, path, field) match {
case None =>
logger.warn(s"Can't setNodeValue ${chapter.id} $path $field")
funit
case Some(field) =>
(value match {
case None => coll.unsetField($id(chapter.id), field)
case Some(v) => coll.updateField($id(chapter.id), field, v)
}) void
}
// root.n[0].n[0].n[1].n[0].n[2]
private def pathToField(chapter: Chapter, path: Path): Option[String] =
private def pathToField(chapter: Chapter, path: Path, subField: String): Option[String] =
chapter.root.children.pathToIndexes(path) map { indexes =>
s"root.n.${indexes.mkString(".n.")}"
s"root.n.${indexes.mkString(".n.")}.$subField"
}
private[study] def idNamesByStudyIds(studyIds: Seq[Study.Id]): Fu[Map[Study.Id, Vector[Chapter.IdName]]] =

View File

@ -251,10 +251,7 @@ final class StudyApi(
chapter.setShapes(shapes, position.path) match {
case Some(newChapter) =>
studyRepo.updateNow(study)
chapterRepo.setShapes(newChapter, position.path, shapes) | {
logger.warn(s"Failed to setShapes $studyId $position")
chapterRepo update newChapter
} >>-
chapterRepo.setShapes(newChapter, position.path, shapes) >>-
sendTo(study, Socket.SetShapes(position, shapes, uid))
case None => fufail(s"Invalid setShapes $position $shapes") >>- reloadUid(study, uid)
}
@ -287,11 +284,13 @@ final class StudyApi(
chapter.setComment(comment, position.path) match {
case Some(newChapter) =>
studyRepo.updateNow(study)
newChapter.root.nodeAt(position.path).flatMap(_.comments findBy comment.by) ?? { c =>
chapterRepo.update(newChapter) >>-
sendTo(study, Socket.SetComment(position, c, uid)) >>-
indexStudy(study) >>-
sendStudyEnters(study, userId)
newChapter.root.nodeAt(position.path) ?? { node =>
node.comments.findBy(comment.by) ?? { c =>
chapterRepo.setComments(newChapter, position.path, node.comments.filterEmpty) >>-
sendTo(study, Socket.SetComment(position, c, uid)) >>-
indexStudy(study) >>-
sendStudyEnters(study, userId)
}
}
case None => fufail(s"Invalid setComment $studyId $position") >>- reloadUid(study, uid)
}

View File

@ -107,7 +107,9 @@ object Node {
}
case class Shapes(value: List[Shape]) extends AnyVal {
def list = value
def ++(shapes: Shapes) = Shapes(value ::: shapes.value)
def ++(shapes: Shapes) = Shapes {
(value ::: shapes.value).distinct
}
}
object Shapes {
val empty = Shapes(Nil)
@ -159,6 +161,11 @@ object Node {
value.filterNot(_.id == commentId)
}
def +(comment: Comment) = Comments(comment :: value)
def filterEmpty = Comments(value.filter(_.text.value.nonEmpty))
}
object Comments {
val empty = Comments(Nil)
}
// TODO copied from lila.game