lila/modules/game/src/main/CrosstableApi.scala

111 lines
3.2 KiB
Scala

package lila.game
import org.joda.time.DateTime
import scala.concurrent.ExecutionContext
import lila.db.AsyncCollFailingSilently
import lila.db.dsl._
import lila.user.User
final class CrosstableApi(
coll: AsyncCollFailingSilently,
matchupColl: AsyncCollFailingSilently,
enabled: () => Boolean
)(implicit ec: ExecutionContext) {
import Crosstable.{ Matchup, Result }
import Crosstable.{ BSONFields => F }
def apply(game: Game): Fu[Option[Crosstable]] =
game.twoUserIds ?? { case (u1, u2) =>
apply(u1, u2) dmap some
}
def withMatchup(game: Game): Fu[Option[Crosstable.WithMatchup]] =
game.twoUserIds ?? { case (u1, u2) =>
withMatchup(u1, u2) dmap some
}
def apply(u1: User.ID, u2: User.ID): Fu[Crosstable] =
justFetch(u1, u2) dmap { _ | Crosstable.empty(u1, u2) }
def justFetch(u1: User.ID, u2: User.ID): Fu[Option[Crosstable]] = enabled() ??
coll(_.one[Crosstable](select(u1, u2)))
def withMatchup(u1: User.ID, u2: User.ID): Fu[Crosstable.WithMatchup] =
apply(u1, u2) zip getMatchup(u1, u2) dmap { case (crosstable, matchup) =>
Crosstable.WithMatchup(crosstable, matchup)
}
def nbGames(u1: User.ID, u2: User.ID): Fu[Int] = enabled() ??
coll {
_.find(
select(u1, u2),
$doc("s1" -> true, "s2" -> true).some
)
.one[Bdoc] dmap { res =>
~(for {
o <- res
s1 <- o.int("s1")
s2 <- o.int("s2")
} yield (s1 + s2) / 10)
}
}
def add(game: Game): Funit =
game.userIds.distinct.sorted match {
case List(u1, u2) =>
val result = Result(game.id, game.winnerUserId)
val bsonResult = Crosstable.crosstableBSONHandler.writeResult(result, u1)
def incScore(userId: User.ID): Int =
game.winnerUserId match {
case Some(u) if u == userId => 10
case None => 5
case _ => 0
}
val inc1 = incScore(u1)
val inc2 = incScore(u2)
val updateCrosstable = enabled() ?? coll {
_.update
.one(
select(u1, u2),
$inc(
F.score1 -> inc1,
F.score2 -> inc2
) ++ $push(
Crosstable.BSONFields.results -> $doc(
"$each" -> List(bsonResult),
"$slice" -> -Crosstable.maxGames
)
),
upsert = true
)
.void
}
val updateMatchup = matchupColl {
_.update
.one(
select(u1, u2),
$inc(
F.score1 -> inc1,
F.score2 -> inc2
) ++ $set(
F.lastPlayed -> DateTime.now
),
upsert = true
)
.void
}
updateCrosstable zip updateMatchup void
case _ => funit
}
private val matchupProjection = $doc(F.lastPlayed -> false)
def getMatchup(u1: User.ID, u2: User.ID): Fu[Option[Matchup]] =
matchupColl(_.find(select(u1, u2), matchupProjection.some).one[Matchup])
private def select(u1: User.ID, u2: User.ID) =
$id(Crosstable.makeKey(u1, u2))
}