more DB code rewrite

killPRM
Thibault Duplessis 2016-04-02 13:11:09 +07:00
parent a6ee522bfe
commit b141f54761
32 changed files with 258 additions and 339 deletions

View File

@ -5,9 +5,8 @@ import reactivemongo.bson._
import chess.Mode
import chess.variant.Variant
import lila.db.BSON
import lila.db.BSON._
import lila.db.BSON.BSONJodaDateTimeHandler
import lila.db.Implicits._
import lila.db.BSON.{ Reader, Writer }
import lila.db.dsl._
import lila.rating.PerfType
private object BSONHandlers {
@ -37,9 +36,9 @@ private object BSONHandlers {
r intO "d" map TimeControl.Correspondence.apply
} getOrElse TimeControl.Unlimited
def writes(w: Writer, t: TimeControl) = t match {
case TimeControl.Clock(l, i) => BSONDocument("l" -> l, "i" -> i)
case TimeControl.Correspondence(d) => BSONDocument("d" -> d)
case TimeControl.Unlimited => BSONDocument()
case TimeControl.Clock(l, i) => $doc("l" -> l, "i" -> i)
case TimeControl.Correspondence(d) => $doc("d" -> d)
case TimeControl.Unlimited => $empty
}
}
implicit val VariantBSONHandler = new BSONHandler[BSONInteger, Variant] {
@ -56,19 +55,19 @@ private object BSONHandlers {
}
implicit val RatingBSONHandler = new BSON[Rating] {
def reads(r: Reader) = Rating(r.int("i"), r.boolD("p"))
def writes(w: Writer, r: Rating) = BSONDocument(
def writes(w: Writer, r: Rating) = $doc(
"i" -> r.int,
"p" -> w.boolO(r.provisional))
}
implicit val RegisteredBSONHandler = new BSON[Registered] {
def reads(r: Reader) = Registered(r.str("id"), r.get[Rating]("r"))
def writes(w: Writer, r: Registered) = BSONDocument(
def writes(w: Writer, r: Registered) = $doc(
"id" -> r.id,
"r" -> r.rating)
}
implicit val AnonymousBSONHandler = new BSON[Anonymous] {
def reads(r: Reader) = Anonymous(r.str("s"))
def writes(w: Writer, a: Anonymous) = BSONDocument(
def writes(w: Writer, a: Anonymous) = $doc(
"s" -> a.secret)
}
implicit val EitherChallengerBSONHandler = new BSON[EitherChallenger] {

View File

@ -1,12 +1,9 @@
package lila.challenge
import org.joda.time.DateTime
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONRegex, BSONArray, BSONBoolean }
import scala.concurrent.duration._
import lila.db.BSON.BSONJodaDateTimeHandler
import lila.db.Implicits.LilaBSONDocumentZero
import lila.db.Types.Coll
import lila.db.dsl._
import lila.user.{ User, UserRepo }
private final class ChallengeRepo(coll: Coll, maxPerUser: Int) {
@ -14,9 +11,9 @@ private final class ChallengeRepo(coll: Coll, maxPerUser: Int) {
import BSONHandlers._
import Challenge._
def byId(id: Challenge.ID) = coll.find(selectId(id)).one[Challenge]
def byId(id: Challenge.ID) = coll.find($id(id)).one[Challenge]
def exists(id: Challenge.ID) = coll.count(selectId(id).some).map(0<)
def exists(id: Challenge.ID) = coll.count($id(id).some).map(0<)
def insert(c: Challenge): Funit =
coll.insert(c) >> c.challenger.right.toOption.?? { challenger =>
@ -27,55 +24,55 @@ private final class ChallengeRepo(coll: Coll, maxPerUser: Int) {
}
def createdByChallengerId(userId: String): Fu[List[Challenge]] =
coll.find(selectCreated ++ BSONDocument("challenger.id" -> userId))
.sort(BSONDocument("createdAt" -> 1))
coll.find(selectCreated ++ $doc("challenger.id" -> userId))
.sort($doc("createdAt" -> 1))
.cursor[Challenge]().collect[List]()
def createdByDestId(userId: String): Fu[List[Challenge]] =
coll.find(selectCreated ++ BSONDocument("destUser.id" -> userId))
.sort(BSONDocument("createdAt" -> 1))
coll.find(selectCreated ++ $doc("destUser.id" -> userId))
.sort($doc("createdAt" -> 1))
.cursor[Challenge]().collect[List]()
def removeByUserId(userId: String): Funit =
coll.remove(BSONDocument("$or" -> BSONArray(
BSONDocument("challenger.id" -> userId),
BSONDocument("destUser.id" -> userId)
coll.remove($doc("$or" -> $arr(
$doc("challenger.id" -> userId),
$doc("destUser.id" -> userId)
))).void
def like(c: Challenge) = ~(for {
challengerId <- c.challengerUserId
destUserId <- c.destUserId
if c.active
} yield coll.find(selectCreated ++ BSONDocument(
} yield coll.find(selectCreated ++ $doc(
"challenger.id" -> challengerId,
"destUser.id" -> destUserId)).one[Challenge])
private[challenge] def countCreatedByDestId(userId: String): Fu[Int] =
coll.count(Some(selectCreated ++ BSONDocument("destUser.id" -> userId)))
coll.count(Some(selectCreated ++ $doc("destUser.id" -> userId)))
private[challenge] def realTimeUnseenSince(date: DateTime, max: Int): Fu[List[Challenge]] =
coll.find(selectCreated ++ selectClock ++ BSONDocument(
"seenAt" -> BSONDocument("$lt" -> date)
coll.find(selectCreated ++ selectClock ++ $doc(
"seenAt" -> $doc("$lt" -> date)
)).cursor[Challenge]().collect[List](max)
private[challenge] def expiredIds(max: Int): Fu[List[Challenge.ID]] =
coll.distinct(
"_id",
BSONDocument("expiresAt" -> BSONDocument("$lt" -> DateTime.now)).some
$doc("expiresAt" -> $doc("$lt" -> DateTime.now)).some
) map lila.db.BSON.asStrings
def setSeenAgain(id: Challenge.ID) = coll.update(
selectId(id),
BSONDocument(
"$set" -> BSONDocument(
$id(id),
$doc(
"$set" -> $doc(
"status" -> Status.Created.id,
"seenAt" -> DateTime.now,
"expiresAt" -> inTwoWeeks))
).void
def setSeen(id: Challenge.ID) = coll.update(
selectId(id),
BSONDocument("$set" -> BSONDocument("seenAt" -> DateTime.now))
$id(id),
$doc("$set" -> $doc("seenAt" -> DateTime.now))
).void
def offline(challenge: Challenge) = setStatus(challenge, Status.Offline, Some(_ plusHours 3))
@ -84,25 +81,24 @@ private final class ChallengeRepo(coll: Coll, maxPerUser: Int) {
def accept(challenge: Challenge) = setStatus(challenge, Status.Accepted, Some(_ plusHours 3))
def statusById(id: Challenge.ID) = coll.find(
selectId(id),
BSONDocument("status" -> true, "_id" -> false)
).one[BSONDocument].map { _.flatMap(_.getAs[Status]("status")) }
$id(id),
$doc("status" -> true, "_id" -> false)
).one[Bdoc].map { _.flatMap(_.getAs[Status]("status")) }
private def setStatus(
challenge: Challenge,
status: Status,
expiresAt: Option[DateTime => DateTime] = None) = coll.update(
selectCreated ++ selectId(challenge.id),
BSONDocument("$set" -> BSONDocument(
selectCreated ++ $id(challenge.id),
$doc("$set" -> $doc(
"status" -> status.id,
"expiresAt" -> expiresAt.fold(inTwoWeeks) { _(DateTime.now) }
))
).void
private[challenge] def remove(id: Challenge.ID) = coll.remove(selectId(id)).void
private[challenge] def remove(id: Challenge.ID) = coll.remove($id(id)).void
private def selectId(id: Challenge.ID) = BSONDocument("_id" -> id)
private val selectCreated = BSONDocument("status" -> Status.Created.id)
private val selectClock = BSONDocument("timeControl.l" -> BSONDocument("$exists" -> true))
private val selectCreated = $doc("status" -> Status.Created.id)
private val selectClock = $doc("timeControl.l" $exists true)
}

View File

@ -21,8 +21,9 @@ trait CollExt {
def byId[D: BSONDocumentReader, I: BSONValueWriter](id: I): Fu[Option[D]] =
one[D]($id(id))
def byId[D: BSONDocumentReader](id: String): Fu[Option[D]] =
one[D]($id(id))
def byId[D: BSONDocumentReader](id: String): Fu[Option[D]] = one[D]($id(id))
def byId[D: BSONDocumentReader](id: Int): Fu[Option[D]] = one[D]($id(id))
def byIds[D: BSONDocumentReader, I: BSONValueWriter](ids: Iterable[I]): Fu[List[D]] =
list[D]($inIds(ids))

View File

@ -25,6 +25,7 @@ trait dsl {
type Coll = reactivemongo.api.collections.bson.BSONCollection
type Bdoc = BSONDocument
type Barr = BSONArray
type QueryBuilder = GenericQueryBuilder[BSONSerializationPack.type]

View File

@ -16,7 +16,7 @@ import lila.user.{ User, UidNb }
object GameRepo {
// dirty
private val coll = Env.current.gameColl
val coll = Env.current.gameColl
type ID = String

View File

@ -4,7 +4,7 @@ import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework
import reactivemongo.bson._
import scalaz.NonEmptyList
import lila.db.Implicits._
import lila.db.dsl._
private final class AggregationPipeline {
@ -14,20 +14,20 @@ private final class AggregationPipeline {
private lazy val movetimeIdDispatcher =
MovetimeRange.reversedNoInf.foldLeft[BSONValue](BSONInteger(MovetimeRange.MTRInf.id)) {
case (acc, mtr) => BSONDocument(
"$cond" -> BSONArray(
BSONDocument("$lte" -> BSONArray("$" + F.moves("t"), mtr.tenths.last)),
case (acc, mtr) => $doc(
"$cond" -> $arr(
$doc("$lte" -> $arr("$" + F.moves("t"), mtr.tenths.last)),
mtr.id,
acc))
}
private lazy val materialIdDispatcher = BSONDocument(
"$cond" -> BSONArray(
BSONDocument("$eq" -> BSONArray("$" + F.moves("i"), 0)),
private lazy val materialIdDispatcher = $doc(
"$cond" -> $arr(
$doc("$eq" -> $arr("$" + F.moves("i"), 0)),
MaterialRange.Equal.id,
MaterialRange.reversedButEqualAndLast.foldLeft[BSONValue](BSONInteger(MaterialRange.Up4.id)) {
case (acc, mat) => BSONDocument(
"$cond" -> BSONArray(
BSONDocument(mat.negative.fold("$lt", "$lte") -> BSONArray("$" + F.moves("i"), mat.imbalance)),
case (acc, mat) => $doc(
"$cond" -> $arr(
$doc(mat.negative.fold("$lt", "$lte") -> $arr("$" + F.moves("i"), mat.imbalance)),
mat.id,
acc))
}))
@ -48,7 +48,7 @@ private final class AggregationPipeline {
"nb" -> SumValue(1),
"ids" -> AddToSet("_id")
).some
private def groupMulti(d: Dimension[_], metricDbKey: String) = Group(BSONDocument(
private def groupMulti(d: Dimension[_], metricDbKey: String) = Group($doc(
"dimension" -> dimensionGroupId(d),
"metric" -> ("$" + metricDbKey)))(
"v" -> SumValue(1),
@ -60,17 +60,17 @@ private final class AggregationPipeline {
"stack" -> PushMulti(
"metric" -> "_id.metric",
"v" -> "v")).some
private val sliceIds = Project(BSONDocument(
private val sliceIds = Project($doc(
"_id" -> true,
"v" -> true,
"nb" -> true,
"ids" -> BSONDocument("$slice" -> BSONArray("$ids", 4))
"ids" -> $doc("$slice" -> $arr("$ids", 4))
)).some
private val sliceStackedIds = Project(BSONDocument(
private val sliceStackedIds = Project($doc(
"_id" -> true,
"nb" -> true,
"stack" -> true,
"ids" -> BSONDocument("$slice" -> BSONArray("$ids", 4))
"ids" -> $doc("$slice" -> $arr("$ids", 4))
)).some
def apply(question: Question[_], userId: String): NonEmptyList[PipelineOperator] = {
@ -78,11 +78,11 @@ private final class AggregationPipeline {
val gameMatcher = combineDocs(question.filters.collect {
case f if f.dimension.isInGame => f.matcher
})
def matchMoves(extraMatcher: BSONDocument = BSONDocument()) =
def matchMoves(extraMatcher: Bdoc = $empty) =
combineDocs(extraMatcher :: question.filters.collect {
case f if f.dimension.isInMove => f.matcher
}).some.filterNot(_.isEmpty) map Match
def projectForMove = Project(BSONDocument({
def projectForMove = Project($doc({
metric.dbKey :: dimension.dbKey :: filters.collect {
case Filter(d, _) if d.isInMove => d.dbKey
}
@ -92,10 +92,10 @@ private final class AggregationPipeline {
Match(
selectUserId(userId) ++
gameMatcher ++
(dimension == Dimension.Opening).??(BSONDocument(F.eco -> BSONDocument("$exists" -> true))) ++
Metric.requiresAnalysis(metric).??(BSONDocument(F.analysed -> true)) ++
(dimension == Dimension.Opening).??($doc(F.eco -> $doc("$exists" -> true))) ++
Metric.requiresAnalysis(metric).??($doc(F.analysed -> true)) ++
(Metric.requiresStableRating(metric) || Dimension.requiresStableRating(dimension)).?? {
BSONDocument(F.provisional -> BSONDocument("$ne" -> true))
$doc(F.provisional -> $doc("$ne" -> true))
}
),
/* sortDate :: */ sampleGames :: ((metric match {
@ -118,15 +118,15 @@ private final class AggregationPipeline {
case M.Opportunism => List(
projectForMove,
unwindMoves,
matchMoves(BSONDocument(F.moves("o") -> BSONDocument("$exists" -> true))),
matchMoves($doc(F.moves("o") -> $doc("$exists" -> true))),
sampleMoves,
group(dimension, GroupFunction("$push", BSONDocument(
"$cond" -> BSONArray("$" + F.moves("o"), 1, 0)
group(dimension, GroupFunction("$push", $doc(
"$cond" -> $arr("$" + F.moves("o"), 1, 0)
))),
sliceIds,
Project(BSONDocument(
Project($doc(
"_id" -> true,
"v" -> BSONDocument("$multiply" -> BSONArray(100, BSONDocument("$avg" -> "$v"))),
"v" -> $doc("$multiply" -> $arr(100, $doc("$avg" -> "$v"))),
"nb" -> true,
"ids" -> true
)).some
@ -134,15 +134,15 @@ private final class AggregationPipeline {
case M.Luck => List(
projectForMove,
unwindMoves,
matchMoves(BSONDocument(F.moves("l") -> BSONDocument("$exists" -> true))),
matchMoves($doc(F.moves("l") -> $doc("$exists" -> true))),
sampleMoves,
group(dimension, GroupFunction("$push", BSONDocument(
"$cond" -> BSONArray("$" + F.moves("l"), 1, 0)
group(dimension, GroupFunction("$push", $doc(
"$cond" -> $arr("$" + F.moves("l"), 1, 0)
))),
sliceIds,
Project(BSONDocument(
Project($doc(
"_id" -> true,
"v" -> BSONDocument("$multiply" -> BSONArray(100, BSONDocument("$avg" -> "$v"))),
"v" -> $doc("$multiply" -> $arr(100, $doc("$avg" -> "$v"))),
"nb" -> true,
"ids" -> true
)).some
@ -153,17 +153,17 @@ private final class AggregationPipeline {
matchMoves(),
sampleMoves,
group(dimension, SumValue(1)),
Project(BSONDocument(
Project($doc(
"v" -> true,
"ids" -> true,
"nb" -> BSONDocument("$size" -> "$ids")
"nb" -> $doc("$size" -> "$ids")
)).some,
Project(BSONDocument(
"v" -> BSONDocument(
"$divide" -> BSONArray("$v", "$nb")
Project($doc(
"v" -> $doc(
"$divide" -> $arr("$v", "$nb")
),
"nb" -> true,
"ids" -> BSONDocument("$slice" -> BSONArray("$ids", 4))
"ids" -> $doc("$slice" -> $arr("$ids", 4))
)).some
)
case M.Movetime => List(
@ -172,7 +172,7 @@ private final class AggregationPipeline {
matchMoves(),
sampleMoves,
group(dimension, GroupFunction("$avg",
BSONDocument("$divide" -> BSONArray("$" + F.moves("t"), 10))
$doc("$divide" -> $arr("$" + F.moves("t"), 10))
)),
sliceIds
)

View File

@ -5,8 +5,7 @@ import reactivemongo.bson.Macros
import chess.{ Role, Color }
import lila.db.BSON
import lila.db.BSON._
import lila.db.Implicits._
import lila.db.dsl._
import lila.game.BSONHandlers.StatusBSONHandler
import lila.rating.PerfType
@ -61,7 +60,7 @@ private object BSONHandlers {
def write(e: MaterialRange) = BSONInteger(e.id)
}
implicit def MoveBSONHandler = new BSON[Move] {
def reads(r: Reader) = Move(
def reads(r: BSON.Reader) = Move(
phase = r.get[Phase]("p"),
tenths = r.get[Int]("t"),
role = r.get[Role]("r"),
@ -71,7 +70,7 @@ private object BSONHandlers {
material = r.int("i"),
opportunism = r.boolO("o"),
luck = r.boolO("l"))
def writes(w: Writer, b: Move) = BSONDocument(
def writes(w: BSON.Writer, b: Move) = BSONDocument(
"p" -> b.phase,
"t" -> b.tenths,
"r" -> b.role,
@ -85,7 +84,7 @@ private object BSONHandlers {
implicit def EntryBSONHandler = new BSON[Entry] {
import Entry.BSONFields._
def reads(r: Reader) = Entry(
def reads(r: BSON.Reader) = Entry(
id = r.str(id),
number = r.int(number),
userId = r.str(userId),
@ -104,7 +103,7 @@ private object BSONHandlers {
analysed = r.boolD(analysed),
provisional = r.boolD(provisional),
date = r.date(date))
def writes(w: Writer, e: Entry) = BSONDocument(
def writes(w: BSON.Writer, e: Entry) = BSONDocument(
id -> e.id,
number -> e.number,
userId -> e.userId,

View File

@ -4,7 +4,7 @@ import play.twirl.api.Html
import reactivemongo.bson._
import chess.{ Color, Role }
import lila.db.Types._
import lila.db.dsl._
import lila.rating.PerfType
sealed abstract class Dimension[A: BSONValueHandler](

View File

@ -3,15 +3,12 @@ package lila.insight
import akka.actor.ActorRef
import org.joda.time.DateTime
import play.api.libs.iteratee._
import play.api.libs.json.Json
import reactivemongo.bson._
import lila.db.dsl._
import lila.db.BSON._
import lila.db.Implicits._
import lila.db.dsl._
import lila.game.BSONHandlers.gameBSONHandler
import lila.game.tube.gameTube
import lila.game.{ Game, Query }
import lila.game.{ Game, GameRepo, Query }
import lila.hub.Sequencer
import lila.rating.PerfType
import lila.user.User
@ -55,10 +52,15 @@ private final class Indexer(storage: Storage, sequencer: ActorRef) {
private def fetchFirstGame(user: User): Fu[Option[Game]] =
if (user.count.rated == 0) fuccess(none)
else {
(user.count.rated >= maxGames) ??
pimpQB($query(gameQuery(user))).sort(Query.sortCreated).skip(maxGames - 1).one[Game]
} orElse
pimpQB($query(gameQuery(user))).sort(Query.sortChronological).one[Game]
(user.count.rated >= maxGames) ?? GameRepo.coll
.find(gameQuery(user))
.sort(Query.sortCreated)
.skip(maxGames - 1)
.one[Game]
} orElse GameRepo.coll
.find(gameQuery(user))
.sort(Query.sortCreated)
.one[Game]
private def computeFrom(user: User, from: DateTime, fromNumber: Int): Funit = {
storage nbByPerf user.id flatMap { nbs =>
@ -71,10 +73,8 @@ private final class Indexer(storage: Storage, sequencer: ActorRef) {
e.printStackTrace
} map (_.toOption)
}
val query = $query(gameQuery(user) ++ Json.obj(Game.BSONFields.createdAt -> $gte($date(from))))
pimpQB(query)
.sort(Query.sortChronological)
.cursor[Game]()
val query = gameQuery(user) ++ $doc(Game.BSONFields.createdAt $gte from)
GameRepo.sortedCursor(query, Query.sortChronological)
.enumerate(maxGames, stopOnError = true) &>
Enumeratee.grouped(Iteratee takeUpTo 4) &>
Enumeratee.mapM[Seq[Game]].apply[Seq[Entry]] { games =>

View File

@ -4,7 +4,7 @@ import org.joda.time.DateTime
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
import reactivemongo.bson._
import lila.db.Implicits._
import lila.db.dsl._
import lila.game.{ Game, GameRepo, Pov }
import lila.user.User
@ -39,7 +39,7 @@ final class InsightApi(
def userStatus(user: User): Fu[UserStatus] =
GameRepo lastFinishedRatedNotFromPosition user flatMap {
case None => fuccess(UserStatus.NoGame)
case Some(game) => storage fetchLast user map {
case Some(game) => storage fetchLast user.id map {
case None => UserStatus.Empty
case Some(entry) if entry.date isBefore game.createdAt => UserStatus.Stale
case _ => UserStatus.Fresh

View File

@ -7,8 +7,7 @@ import reactivemongo.bson._
import scala.concurrent.duration._
import scalaz.NonEmptyList
import lila.db.BSON._
import lila.db.Implicits._
import lila.db.dsl._
import lila.user.UserRepo
import lila.rating.PerfType

View File

@ -1,13 +1,10 @@
package lila.insight
import org.joda.time.DateTime
import play.api.libs.iteratee._
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
import reactivemongo.bson._
import reactivemongo.bson.Macros
import lila.db.BSON._
import lila.db.Implicits._
import lila.db.dsl._
case class UserCache(
_id: String, // user id
@ -22,11 +19,9 @@ private final class UserCacheApi(coll: Coll) {
private implicit val userCacheBSONHandler = Macros.handler[UserCache]
def find(id: String) = coll.find(selectId(id)).one[UserCache]
def find(id: String) = coll.one[UserCache]($id(id))
def save(u: UserCache) = coll.update(selectId(u.id), u, upsert = true).void
def save(u: UserCache) = coll.update($id(u.id), u, upsert = true).void
def remove(id: String) = coll.remove(selectId(id)).void
private def selectId(id: String) = BSONDocument("_id" -> id)
def remove(id: String) = coll.remove($id(id)).void
}

View File

@ -1,13 +1,11 @@
package lila.lobby
import org.joda.time.DateTime
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONRegex, BSONArray, BSONBoolean }
import reactivemongo.core.commands._
import scala.concurrent.duration._
import actorApi.LobbyUser
import lila.db.BSON.BSONJodaDateTimeHandler
import lila.db.Types.Coll
import lila.db.dsl._
import lila.memo.AsyncCache
import lila.user.{ User, UserRepo }
@ -23,8 +21,8 @@ final class SeekApi(
private object ForUser extends CacheKey
private def allCursor =
coll.find(BSONDocument())
.sort(BSONDocument("createdAt" -> -1))
coll.find($empty)
.sort($doc("createdAt" -> -1))
.cursor[Seek]()
private val cache = AsyncCache[CacheKey, List[Seek]](
@ -58,7 +56,7 @@ final class SeekApi(
}._1.reverse
def find(id: String): Fu[Option[Seek]] =
coll.find(BSONDocument("_id" -> id)).one[Seek]
coll.find($doc("_id" -> id)).one[Seek]
def insert(seek: Seek) = coll.insert(seek) >> findByUser(seek.user.id).flatMap {
case seeks if seeks.size <= maxPerUser => funit
@ -67,27 +65,27 @@ final class SeekApi(
} >> cache.clear
def findByUser(userId: String): Fu[List[Seek]] =
coll.find(BSONDocument("user.id" -> userId))
.sort(BSONDocument("createdAt" -> -1))
coll.find($doc("user.id" -> userId))
.sort($doc("createdAt" -> -1))
.cursor[Seek]().collect[List]()
def remove(seek: Seek) =
coll.remove(BSONDocument("_id" -> seek.id)).void >> cache.clear
coll.remove($doc("_id" -> seek.id)).void >> cache.clear
def archive(seek: Seek, gameId: String) = {
val archiveDoc = Seek.seekBSONHandler.write(seek) ++ BSONDocument(
val archiveDoc = Seek.seekBSONHandler.write(seek) ++ $doc(
"gameId" -> gameId,
"archivedAt" -> DateTime.now)
coll.remove(BSONDocument("_id" -> seek.id)).void >>
coll.remove($doc("_id" -> seek.id)).void >>
cache.clear >>
archiveColl.insert(archiveDoc)
}
def findArchived(gameId: String): Fu[Option[Seek]] =
archiveColl.find(BSONDocument("gameId" -> gameId)).one[Seek]
archiveColl.find($doc("gameId" -> gameId)).one[Seek]
def removeBy(seekId: String, userId: String) =
coll.remove(BSONDocument(
coll.remove($doc(
"_id" -> seekId,
"user.id" -> userId
)).void >> cache.clear

View File

@ -2,9 +2,8 @@ package lila.opening
import org.goochjs.glicko2._
import org.joda.time.DateTime
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONDouble }
import lila.db.Types.Coll
import lila.db.dsl._
import lila.rating.{ Glicko, Perf }
import lila.user.{ User, UserRepo }
@ -34,13 +33,13 @@ private[opening] final class Finisher(
userRatingDiff = userPerf.intRating - user.perfs.opening.intRating)
((api.attempt add a) >> {
openingColl.update(
BSONDocument("_id" -> opening.id),
BSONDocument("$inc" -> BSONDocument(
Opening.BSONFields.attempts -> BSONInteger(1),
Opening.BSONFields.wins -> BSONInteger(win ? 1 | 0)
)) ++ BSONDocument("$set" -> BSONDocument(
Opening.BSONFields.perf -> Perf.perfBSONHandler.write(openingPerf)
))) zip UserRepo.setPerf(user.id, "opening", userPerf)
$id(opening.id),
$inc(
Opening.BSONFields.attempts -> $int(1),
Opening.BSONFields.wins -> $int(win ? 1 | 0)
) ++ $set(
Opening.BSONFields.perf -> Perf.perfBSONHandler.write(openingPerf)
)) zip UserRepo.setPerf(user.id, "opening", userPerf)
}) recover lila.db.recoverDuplicateKey(_ => ()) inject (a -> none)
}
}

View File

@ -3,11 +3,10 @@ package lila.opening
import scala.util.{ Try, Success, Failure }
import org.joda.time.DateTime
import play.api.libs.json.JsValue
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONRegex, BSONArray, BSONBoolean }
import reactivemongo.bson.BSONArray
import reactivemongo.core.commands._
import lila.db.Types.Coll
import lila.db.dsl._
import lila.user.{ User, UserRepo }
private[opening] final class OpeningApi(
@ -21,39 +20,20 @@ private[opening] final class OpeningApi(
object opening {
def find(id: Opening.ID): Fu[Option[Opening]] =
openingColl.find(BSONDocument("_id" -> id)).one[Opening]
def importOne(json: JsValue, token: String): Fu[Opening.ID] =
if (token != apiToken) fufail("Invalid API token")
else {
import Generated.generatedJSONRead
Try(json.as[Generated]) match {
case Failure(err) => fufail(err.getMessage)
case Success(generated) => generated.toOpening.future flatMap insertOpening
}
}
def insertOpening(opening: Opening.ID => Opening): Fu[Opening.ID] =
lila.db.Util findNextId openingColl flatMap { id =>
val o = opening(id)
openingColl.count(BSONDocument("fen" -> o.fen).some) flatMap {
case 0 => openingColl insert o inject o.id
case _ => fufail("Duplicate opening")
}
}
openingColl.byId[Opening](id)
}
object attempt {
def find(openingId: Opening.ID, userId: String): Fu[Option[Attempt]] =
attemptColl.find(BSONDocument(
attemptColl.find($doc(
Attempt.BSONFields.id -> Attempt.makeId(openingId, userId)
)).one[Attempt]
def add(a: Attempt) = attemptColl insert a void
def hasPlayed(user: User, opening: Opening): Fu[Boolean] =
attemptColl.count(BSONDocument(
attemptColl.count($doc(
Attempt.BSONFields.id -> Attempt.makeId(opening.id, user.id)
).some) map (0!=)
@ -62,9 +42,9 @@ private[opening] final class OpeningApi(
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Group, Limit, Match, Push }
val playedIdsGroup =
Group(BSONBoolean(true))("ids" -> Push(Attempt.BSONFields.openingId))
Group($boolean(true))("ids" -> Push(Attempt.BSONFields.openingId))
col.aggregate(Match(BSONDocument(Attempt.BSONFields.userId -> user.id)),
col.aggregate(Match($doc(Attempt.BSONFields.userId -> user.id)),
List(Limit(max), playedIdsGroup)).map(_.documents.headOption.flatMap(
_.getAs[BSONArray]("ids")).getOrElse(BSONArray()))
}
@ -72,9 +52,9 @@ private[opening] final class OpeningApi(
object identify {
def apply(fen: String, max: Int): Fu[List[String]] = nameColl.find(
BSONDocument("_id" -> fen),
BSONDocument("_id" -> false)
).one[BSONDocument] map { obj =>
$doc("_id" -> fen),
$doc("_id" -> false)
).one[Bdoc] map { obj =>
~obj.??(_.getAs[List[String]]("names"))
}
}

View File

@ -1,12 +1,10 @@
package lila.opening
import reactivemongo.bson.BSONArray
import scala.concurrent.duration._
import scala.util.Random
import reactivemongo.api.QueryOpts
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONArray }
import lila.db.Types.Coll
import lila.db.dsl._
import lila.user.User
private[opening] final class Selector(
@ -20,8 +18,8 @@ private[opening] final class Selector(
def apply(me: Option[User]): Fu[Opening] = (me match {
case None =>
openingColl.find(BSONDocument())
.options(QueryOpts(skipN = Random nextInt anonSkipMax))
openingColl.find($empty)
.skip(Random nextInt anonSkipMax)
.one[Opening] flatten "Can't find a opening for anon player!"
case Some(user) => api.attempt.playedIds(user, modulo) flatMap { ids =>
tryRange(user, toleranceStep, ids)
@ -31,16 +29,15 @@ private[opening] final class Selector(
}).mon(_.opening.selector.time) >>- lila.mon.opening.selector.count()
private def tryRange(user: User, tolerance: Int, ids: BSONArray): Fu[Opening] =
openingColl.find(BSONDocument(
Opening.BSONFields.id -> BSONDocument("$nin" -> ids),
Opening.BSONFields.rating -> BSONDocument(
"$gt" -> BSONInteger(user.perfs.opening.intRating - tolerance),
"$lt" -> BSONInteger(user.perfs.opening.intRating + tolerance)
)
)).one[Opening] flatMap {
case Some(opening) => fuccess(opening)
case None => if ((tolerance + toleranceStep) <= toleranceMax)
tryRange(user, tolerance + toleranceStep, ids)
else fufail(s"Can't find a opening for user $user!")
}
openingColl.one[Opening]($doc(
Opening.BSONFields.id $nin ids,
Opening.BSONFields.rating $gt
(user.perfs.opening.intRating - tolerance) $lt
(user.perfs.opening.intRating + tolerance)
)) flatMap {
case Some(opening) => fuccess(opening)
case None => if ((tolerance + toleranceStep) <= toleranceMax)
tryRange(user, tolerance + toleranceStep, ids)
else fufail(s"Can't find a opening for user $user!")
}
}

View File

@ -2,9 +2,8 @@ package lila.opening
import play.api.libs.json._
import reactivemongo.bson._
import reactivemongo.bson.Macros
import lila.db.Types.Coll
import lila.db.dsl._
import lila.rating.Glicko
import lila.user.User

View File

@ -4,8 +4,7 @@ import akka.actor.ActorRef
import play.api.libs.iteratee._
import lila.db.dsl._
import lila.db.Implicits._
import lila.game.{ Game, Pov, Query }
import lila.game.{ Game, GameRepo, Pov, Query }
import lila.hub.Sequencer
import lila.rating.PerfType
import lila.user.User
@ -21,16 +20,12 @@ final class PerfStatIndexer(storage: PerfStatStorage, sequencer: ActorRef) {
}
private def compute(user: User, perfType: PerfType): Funit = {
import lila.game.tube.gameTube
import lila.game.BSONHandlers.gameBSONHandler
pimpQB($query {
GameRepo.sortedCursor(
Query.user(user.id) ++
Query.finished ++
Query.turnsMoreThan(2) ++
Query.variant(PerfType variantOf perfType)
}).sort(Query.sortChronological)
.cursor[Game]()
Query.variant(PerfType variantOf perfType),
Query.sortChronological)
.enumerate(Int.MaxValue, stopOnError = true) |>>>
Iteratee.fold[Game, PerfStat](PerfStat.init(user.id, perfType)) {
case (perfStat, game) if game.perfType.contains(perfType) =>

View File

@ -2,17 +2,13 @@ package lila.perfStat
import org.joda.time.DateTime
import reactivemongo.bson._
import reactivemongo.bson.Macros
import scala.concurrent.duration._
import lila.db.BSON._
import lila.db.Types.Coll
import lila.db.dsl._
import lila.rating.PerfType
final class PerfStatStorage(coll: Coll) {
import lila.db.BSON.BSONJodaDateTimeHandler
import reactivemongo.bson.Macros
implicit val PerfTypeBSONHandler = new BSONHandler[BSONInteger, PerfType] {
def read(b: BSONInteger) = PerfType.byId get b.value err s"Invalid perf type id ${b.value}"
def write(p: PerfType) = BSONInteger(p.id)
@ -33,10 +29,10 @@ final class PerfStatStorage(coll: Coll) {
private implicit val PerfStatBSONHandler = Macros.handler[PerfStat]
def find(userId: String, perfType: PerfType): Fu[Option[PerfStat]] =
coll.find(BSONDocument("_id" -> PerfStat.makeId(userId, perfType))).one[PerfStat]
coll.byId[PerfStat](PerfStat.makeId(userId, perfType))
def update(perfStat: PerfStat): Funit =
coll.update(BSONDocument("_id" -> perfStat.id), perfStat).void
coll.update($id(perfStat.id), perfStat).void
def insert(perfStat: PerfStat): Funit =
coll.insert(perfStat).void

View File

@ -5,10 +5,8 @@ import scala.concurrent.duration._
import akka.actor.{ ActorSelection, Scheduler }
import akka.pattern.ask
import org.joda.time.DateTime
import reactivemongo.bson.BSONDocument
import lila.db.BSON.BSONJodaDateTimeHandler
import lila.db.Types.Coll
import lila.db.dsl._
private[puzzle] final class Daily(
coll: Coll,
@ -45,15 +43,15 @@ private[puzzle] final class Daily(
}
private def findCurrent = coll.find(
BSONDocument("day" -> BSONDocument("$gt" -> DateTime.now.minusMinutes(24 * 60 - 15)))
$doc("day" -> $doc("$gt" -> DateTime.now.minusMinutes(24 * 60 - 15)))
).one[Puzzle]
private def findNew = coll.find(
BSONDocument("day" -> BSONDocument("$exists" -> false))
).sort(BSONDocument("vote.sum" -> -1)).one[Puzzle] flatMap {
$doc("day" -> $doc("$exists" -> false))
).sort($doc("vote.sum" -> -1)).one[Puzzle] flatMap {
case Some(puzzle) => coll.update(
BSONDocument("_id" -> puzzle.id),
BSONDocument("$set" -> BSONDocument("day" -> DateTime.now))
$doc("_id" -> puzzle.id),
$doc("$set" -> $doc("day" -> DateTime.now))
) inject puzzle.some
case None => fuccess(none)
}

View File

@ -2,9 +2,8 @@ package lila.puzzle
import org.goochjs.glicko2._
import org.joda.time.DateTime
import reactivemongo.bson.{ BSONDocument, BSONInteger }
import lila.db.Types.Coll
import lila.db.dsl._
import lila.rating.{ Glicko, Perf }
import lila.user.{ User, UserRepo }
@ -38,13 +37,13 @@ private[puzzle] final class Finisher(
userRatingDiff = userPerf.intRating - user.perfs.puzzle.intRating)
((api.attempt add a) >> {
puzzleColl.update(
BSONDocument("_id" -> puzzle.id),
BSONDocument("$inc" -> BSONDocument(
Puzzle.BSONFields.attempts -> BSONInteger(1),
Puzzle.BSONFields.wins -> BSONInteger(data.isWin ? 1 | 0)
)) ++ BSONDocument("$set" -> BSONDocument(
$id(puzzle.id),
$inc(
Puzzle.BSONFields.attempts -> $int(1),
Puzzle.BSONFields.wins -> $int(data.isWin ? 1 | 0)
) ++ $set(
Puzzle.BSONFields.perf -> Perf.perfBSONHandler.write(puzzlePerf)
))) zip UserRepo.setPerf(user.id, "puzzle", userPerf)
)) zip UserRepo.setPerf(user.id, "puzzle", userPerf)
}) recover lila.db.recoverDuplicateKey(_ => ()) inject (a -> none)
}

View File

@ -5,9 +5,9 @@ import scala.util.{ Try, Success, Failure }
import org.joda.time.DateTime
import play.api.libs.json.JsValue
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONRegex, BSONArray, BSONBoolean }
import reactivemongo.bson. BSONArray
import lila.db.Types.Coll
import lila.db.dsl._
import lila.user.{ User, UserRepo }
private[puzzle] final class PuzzleApi(
@ -20,11 +20,11 @@ private[puzzle] final class PuzzleApi(
object puzzle {
def find(id: PuzzleId): Fu[Option[Puzzle]] =
puzzleColl.find(BSONDocument("_id" -> id)).one[Puzzle]
puzzleColl.find($doc("_id" -> id)).one[Puzzle]
def latest(nb: Int): Fu[List[Puzzle]] =
puzzleColl.find(BSONDocument())
.sort(BSONDocument("date" -> -1))
puzzleColl.find($empty)
.sort($doc("date" -> -1))
.cursor[Puzzle]()
.collect[List](nb)
@ -43,8 +43,8 @@ private[puzzle] final class PuzzleApi(
case Success(puzzle) :: rest => lila.db.Util findNextId puzzleColl flatMap { id =>
val p = puzzle(id)
val fenStart = p.fen.split(' ').take(2).mkString(" ")
puzzleColl.count(BSONDocument(
"fen" -> BSONRegex(fenStart.replace("/", "\\/"), "")
puzzleColl.count($doc(
"fen".$regex(fenStart.replace("/", "\\/"), "")
).some) flatMap {
case 0 => (puzzleColl insert p) >> {
insertPuzzles(rest) map (Success(id) :: _)
@ -55,22 +55,22 @@ private[puzzle] final class PuzzleApi(
}
def export(nb: Int): Fu[List[Puzzle]] = List(true, false).map { mate =>
puzzleColl.find(BSONDocument("mate" -> mate))
.sort(BSONDocument(Puzzle.BSONFields.voteSum -> -1))
puzzleColl.find($doc("mate" -> mate))
.sort($doc(Puzzle.BSONFields.voteSum -> -1))
.cursor[Puzzle]().collect[List](nb / 2)
}.sequenceFu.map(_.flatten)
def disable(id: PuzzleId): Funit =
puzzleColl.update(
BSONDocument("_id" -> id),
BSONDocument("$set" -> BSONDocument(Puzzle.BSONFields.vote -> Vote.disable))
$doc("_id" -> id),
$doc("$set" -> $doc(Puzzle.BSONFields.vote -> Vote.disable))
).void
}
object attempt {
def find(puzzleId: PuzzleId, userId: String): Fu[Option[Attempt]] =
attemptColl.find(BSONDocument(
attemptColl.find($doc(
Attempt.BSONFields.id -> Attempt.makeId(puzzleId, userId)
)).one[Attempt]
@ -83,11 +83,11 @@ private[puzzle] final class PuzzleApi(
}
val a2 = a1.copy(vote = v.some)
attemptColl.update(
BSONDocument("_id" -> a2.id),
BSONDocument("$set" -> BSONDocument(Attempt.BSONFields.vote -> v))) zip
$doc("_id" -> a2.id),
$doc("$set" -> $doc(Attempt.BSONFields.vote -> v))) zip
puzzleColl.update(
BSONDocument("_id" -> p2.id),
BSONDocument("$set" -> BSONDocument(Puzzle.BSONFields.vote -> p2.vote))) map {
$doc("_id" -> p2.id),
$doc("$set" -> $doc(Puzzle.BSONFields.vote -> p2.vote))) map {
case _ => p2 -> a2
}
}
@ -95,22 +95,22 @@ private[puzzle] final class PuzzleApi(
def add(a: Attempt) = attemptColl insert a void
def hasPlayed(user: User, puzzle: Puzzle): Fu[Boolean] =
attemptColl.count(BSONDocument(
attemptColl.count($doc(
Attempt.BSONFields.id -> Attempt.makeId(puzzle.id, user.id)
).some) map (0!=)
def playedIds(user: User, max: Int): Fu[BSONArray] =
attemptColl.distinct(Attempt.BSONFields.puzzleId,
BSONDocument(Attempt.BSONFields.userId -> user.id).some
$doc(Attempt.BSONFields.userId -> user.id).some
) map BSONArray.apply
def hasVoted(user: User): Fu[Boolean] = attemptColl.find(
BSONDocument(Attempt.BSONFields.userId -> user.id),
BSONDocument(
$doc(Attempt.BSONFields.userId -> user.id),
$doc(
Attempt.BSONFields.vote -> true,
Attempt.BSONFields.id -> false
)).sort(BSONDocument(Attempt.BSONFields.date -> -1))
.cursor[BSONDocument]()
)).sort($doc(Attempt.BSONFields.date -> -1))
.cursor[Bdoc]()
.collect[List](5) map {
case attempts if attempts.size < 5 => true
case attempts => attempts.foldLeft(false) {

View File

@ -3,10 +3,7 @@ package lila.puzzle
import scala.concurrent.duration._
import scala.util.Random
import reactivemongo.api.QueryOpts
import reactivemongo.bson.{ BSONDocument, BSONInteger, BSONArray }
import lila.db.Types.Coll
import lila.db.dsl._
import lila.user.User
private[puzzle] final class Selector(
@ -15,10 +12,10 @@ private[puzzle] final class Selector(
anonMinRating: Int,
maxAttempts: Int) {
private def popularSelector(mate: Boolean) = BSONDocument(
Puzzle.BSONFields.voteSum -> BSONDocument("$gt" -> BSONInteger(mate.fold(anonMinRating, 0))))
private def popularSelector(mate: Boolean) = $doc(
Puzzle.BSONFields.voteSum $gt mate.fold(anonMinRating, 0))
private def mateSelector(mate: Boolean) = BSONDocument("mate" -> mate)
private def mateSelector(mate: Boolean) = $doc("mate" -> mate)
private def difficultyDecay(difficulty: Int) = difficulty match {
case 1 => -200
@ -36,7 +33,7 @@ private[puzzle] final class Selector(
me match {
case None =>
puzzleColl.find(popularSelector(isMate) ++ mateSelector(isMate))
.options(QueryOpts(skipN = Random nextInt anonSkipMax))
.skip(Random nextInt anonSkipMax)
.one[Puzzle]
case Some(user) if user.perfs.puzzle.nb > maxAttempts => fuccess(none)
case Some(user) =>
@ -55,14 +52,13 @@ private[puzzle] final class Selector(
case d => 200
}
private def tryRange(rating: Int, tolerance: Int, step: Int, decay: Int, ids: BSONArray, isMate: Boolean): Fu[Option[Puzzle]] =
puzzleColl.find(mateSelector(isMate) ++ BSONDocument(
Puzzle.BSONFields.id -> BSONDocument("$nin" -> ids),
Puzzle.BSONFields.rating -> BSONDocument(
"$gt" -> BSONInteger(rating - tolerance + decay),
"$lt" -> BSONInteger(rating + tolerance + decay)
)
)).sort(BSONDocument(Puzzle.BSONFields.voteSum -> -1))
private def tryRange(rating: Int, tolerance: Int, step: Int, decay: Int, ids: Barr, isMate: Boolean): Fu[Option[Puzzle]] =
puzzleColl.find(mateSelector(isMate) ++ $doc(
Puzzle.BSONFields.id $nin ids,
Puzzle.BSONFields.rating $gt
(rating - tolerance + decay) $lt
(rating + tolerance + decay)
)).sort($sort desc Puzzle.BSONFields.voteSum)
.one[Puzzle] flatMap {
case None if (tolerance + step) <= toleranceMax =>
tryRange(rating, tolerance + step, step, decay, ids, isMate)

View File

@ -3,7 +3,7 @@ package lila.puzzle
import play.api.libs.json._
import reactivemongo.bson._
import lila.db.Types.Coll
import lila.db.dsl._
import lila.rating.Glicko
import lila.user.User

View File

@ -6,18 +6,19 @@ import reactivemongo.bson._
import lila.common.{ LilaCookie, LilaException }
import lila.db.dsl._
import lila.db.Implicits._
import lila.game.Game
import lila.user.User
import tube.anonConfigTube
private[setup] object AnonConfigRepo {
// dirty
private val coll = Env.current.anonConfigColl
def update(req: RequestHeader)(f: UserConfig => UserConfig): Funit =
configOption(req) flatMap {
_ ?? { config =>
anonConfigTube.coll.update(
BSONDocument("_id" -> config.id),
coll.update(
$doc("_id" -> config.id),
f(config),
upsert = true).void
}
@ -27,8 +28,8 @@ private[setup] object AnonConfigRepo {
configOption(req) map (_ | UserConfig.default("nocookie"))
def config(sid: String): Fu[UserConfig] =
$find byId sid recover {
case e: LilaException => {
coll.byId[UserConfig](sid) recover {
case e: Exception => {
logger.warn("Can't load config", e)
none[UserConfig]
}
@ -38,12 +39,7 @@ private[setup] object AnonConfigRepo {
sessionId(req).??(s => config(s) map (_.some))
def filter(req: RequestHeader): Fu[FilterConfig] = sessionId(req) ?? { sid =>
anonConfigTube.coll.find(
BSONDocument("_id" -> sid),
BSONDocument("filter" -> true)
).one[BSONDocument] map {
_ flatMap (_.getAs[FilterConfig]("filter"))
}
coll.primitiveOne[FilterConfig]($id(sid), "filter")
} map (_ | FilterConfig.default)
private def sessionId(req: RequestHeader): Option[String] =

View File

@ -74,6 +74,4 @@ object FilterConfig {
"s" -> o.speed.map(_.id),
"e" -> o.ratingRange.toString)
}
private[setup] val tube = lila.db.BsTube(filterConfigBSONHandler)
}

View File

@ -6,7 +6,6 @@ import lila.lobby.Color
import lila.user.UserContext
import play.api.data._
import play.api.data.Forms._
import tube.{ userConfigTube, anonConfigTube }
private[setup] final class FormFactory(casualOnly: Boolean) {

View File

@ -12,7 +12,6 @@ import lila.lobby.actorApi.{ AddHook, AddSeek }
import lila.lobby.Hook
import lila.user.{ User, UserContext }
import makeTimeout.short
import tube.{ userConfigTube, anonConfigTube }
private[setup] final class Processor(
lobby: ActorSelection,

View File

@ -29,7 +29,8 @@ private[setup] object UserConfig {
hook = HookConfig.default,
filter = FilterConfig.default)
import lila.db.{ BsTube, BSON }
import lila.db.BSON
import lila.db.dsl._
import reactivemongo.bson._
import AiConfig.aiConfigBSONHandler
import FriendConfig.friendConfigBSONHandler
@ -52,6 +53,4 @@ private[setup] object UserConfig {
"hook" -> o.hook,
"filter" -> o.filter)
}
private[setup] val tube = BsTube(userConfigBSONHandler)
}

View File

@ -5,34 +5,30 @@ import reactivemongo.bson._
import lila.common.LilaException
import lila.db.dsl._
import lila.db.Implicits._
import lila.game.Game
import lila.user.User
import tube.userConfigTube
private[setup] object UserConfigRepo {
// dirty
private val coll = Env.current.userConfigColl
def update(user: User)(f: UserConfig => UserConfig): Funit =
config(user) flatMap { config =>
userConfigTube.coll.update(
BSONDocument("_id" -> config.id),
coll.update(
$doc("_id" -> config.id),
f(config),
upsert = true).void
}
def config(user: User): Fu[UserConfig] =
$find byId user.id recover {
case e: LilaException => {
coll.byId[UserConfig](user.id) recover {
case e: Exception => {
logger.warn("Can't load config", e)
none[UserConfig]
}
} map (_ | UserConfig.default(user.id))
def filter(user: User): Fu[FilterConfig] =
userConfigTube.coll.find(
BSONDocument("_id" -> user.id),
BSONDocument("filter" -> true)
).one[BSONDocument] map {
_ flatMap (_.getAs[FilterConfig]("filter")) getOrElse FilterConfig.default
}
coll.primitiveOne[FilterConfig]($id(user.id), "filter") map (_ | FilterConfig.default)
}

View File

@ -4,14 +4,5 @@ import lila.socket.WithSocket
package object setup extends PackageObject with WithPlay with WithSocket {
object tube {
private[setup] implicit lazy val userConfigTube =
UserConfig.tube inColl Env.current.userConfigColl
private[setup] implicit lazy val anonConfigTube =
UserConfig.tube inColl Env.current.anonConfigColl
}
private[setup] def logger = lila.log("setup")
}

View File

@ -6,8 +6,8 @@ import reactivemongo.core.commands._
import scala.concurrent.duration._
import lila.common.paginator._
import lila.db.paginator.BSONAdapter
import lila.db.Types.Coll
import lila.db.dsl._
import lila.db.paginator.Adapter
import lila.memo.AsyncCache
import lila.user.{ User, UserRepo }
@ -41,16 +41,16 @@ private[video] final class VideoApi(
private val maxPerPage = 18
def find(id: Video.ID): Fu[Option[Video]] =
videoColl.find(BSONDocument("_id" -> id)).one[Video]
videoColl.find($doc("_id" -> id)).one[Video]
def search(user: Option[User], query: String, page: Int): Fu[Paginator[VideoView]] = {
val q = query.split(' ').map { word => s""""$word"""" } mkString " "
val textScore = BSONDocument("score" -> BSONDocument("$meta" -> "textScore"))
val textScore = $doc("score" -> $doc("$meta" -> "textScore"))
Paginator(
adapter = new BSONAdapter[Video](
adapter = new Adapter[Video](
collection = videoColl,
selector = BSONDocument(
"$text" -> BSONDocument("$search" -> q)
selector = $doc(
"$text" -> $doc("$search" -> q)
),
projection = textScore,
sort = textScore
@ -61,19 +61,19 @@ private[video] final class VideoApi(
def save(video: Video): Funit =
videoColl.update(
BSONDocument("_id" -> video.id),
BSONDocument("$set" -> video),
$doc("_id" -> video.id),
$doc("$set" -> video),
upsert = true).void
def removeNotIn(ids: List[Video.ID]) =
videoColl.remove(
BSONDocument("_id" -> BSONDocument("$nin" -> ids))
$doc("_id" -> $doc("$nin" -> ids))
).void
def setMetadata(id: Video.ID, metadata: Youtube.Metadata) =
videoColl.update(
BSONDocument("_id" -> id),
BSONDocument("$set" -> BSONDocument("metadata" -> metadata)),
$doc("_id" -> id),
$doc("$set" -> $doc("metadata" -> metadata)),
upsert = false
).void
@ -81,11 +81,11 @@ private[video] final class VideoApi(
videoColl.distinct("_id", none) map lila.db.BSON.asStrings
def popular(user: Option[User], page: Int): Fu[Paginator[VideoView]] = Paginator(
adapter = new BSONAdapter[Video](
adapter = new Adapter[Video](
collection = videoColl,
selector = BSONDocument(),
projection = BSONDocument(),
sort = BSONDocument("metadata.likes" -> -1)
selector = $empty,
projection = $empty,
sort = $doc("metadata.likes" -> -1)
) mapFutureList videoViews(user),
currentPage = page,
maxPerPage = maxPerPage)
@ -93,35 +93,31 @@ private[video] final class VideoApi(
def byTags(user: Option[User], tags: List[Tag], page: Int): Fu[Paginator[VideoView]] =
if (tags.isEmpty) popular(user, page)
else Paginator(
adapter = new BSONAdapter[Video](
adapter = new Adapter[Video](
collection = videoColl,
selector = BSONDocument(
"tags" -> BSONDocument("$all" -> tags)
),
projection = BSONDocument(),
sort = BSONDocument("metadata.likes" -> -1)
selector = $doc("tags" $all tags),
projection = $empty,
sort = $doc("metadata.likes" -> -1)
) mapFutureList videoViews(user),
currentPage = page,
maxPerPage = maxPerPage)
def byAuthor(user: Option[User], author: String, page: Int): Fu[Paginator[VideoView]] =
Paginator(
adapter = new BSONAdapter[Video](
adapter = new Adapter[Video](
collection = videoColl,
selector = BSONDocument(
"author" -> author
),
projection = BSONDocument(),
sort = BSONDocument("metadata.likes" -> -1)
selector = $doc("author" -> author),
projection = $empty,
sort = $doc("metadata.likes" -> -1)
) mapFutureList videoViews(user),
currentPage = page,
maxPerPage = maxPerPage)
def similar(user: Option[User], video: Video, max: Int): Fu[Seq[VideoView]] =
videoColl.find(BSONDocument(
"tags" -> BSONDocument("$in" -> video.tags),
"_id" -> BSONDocument("$ne" -> video.id)
)).sort(BSONDocument("metadata.likes" -> -1))
videoColl.find($doc(
"tags" $in video.tags,
"_id" $ne video.id
)).sort($doc("metadata.likes" -> -1))
.cursor[Video]()
.collect[List]().map { videos =>
videos.sortBy { v => -v.similarity(video) } take max
@ -142,7 +138,7 @@ private[video] final class VideoApi(
object view {
def find(videoId: Video.ID, userId: String): Fu[Option[View]] =
viewColl.find(BSONDocument(
viewColl.find($doc(
View.BSONFields.id -> View.makeId(videoId, userId)
)).one[View]
@ -150,17 +146,15 @@ private[video] final class VideoApi(
lila.db.recoverDuplicateKey(_ => ())
def hasSeen(user: User, video: Video): Fu[Boolean] =
viewColl.count(BSONDocument(
viewColl.count($doc(
View.BSONFields.id -> View.makeId(video.id, user.id)
).some) map (0!=)
def seenVideoIds(user: User, videos: Seq[Video]): Fu[Set[Video.ID]] =
viewColl.distinct(View.BSONFields.videoId,
BSONDocument(
"_id" -> BSONDocument("$in" -> videos.map { v =>
View.makeId(v.id, user.id)
})
).some) map lila.db.BSON.asStringSet
$inIds(videos.map { v =>
View.makeId(v.id, user.id)
}).some) map lila.db.BSON.asStringSet
}
object tag {
@ -182,8 +176,8 @@ private[video] final class VideoApi(
tags.filterNot(_.isNumeric)
}
else videoColl.aggregate(
Match(BSONDocument("tags" -> BSONDocument("$all" -> filterTags))),
List(Project(BSONDocument("tags" -> BSONBoolean(true))),
Match($doc("tags" $all filterTags)),
List(Project($doc("tags" -> true)),
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)))).map(
_.documents.flatMap(_.asOpt[TagNb]))
@ -208,7 +202,7 @@ private[video] final class VideoApi(
private val popularCache = AsyncCache.single[List[TagNb]](
f = videoColl.aggregate(
Project(BSONDocument("tags" -> BSONBoolean(true))), List(
Project($doc("tags" -> true)), List(
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)),
Sort(Descending("nb")))).map(
_.documents.flatMap(_.asOpt[TagNb])),