Merge remote-tracking branch 'cchantep/rm-0.12-RC0' into rm012

* cchantep/rm-0.12-RC0:
  Upgrade to ReactiveMongo 0.12 (Release Candidate 0)
analysismenu2
Thibault Duplessis 2016-07-27 12:12:59 +02:00
commit dd9e84e828
38 changed files with 145 additions and 165 deletions

View File

@ -1,3 +1,4 @@
sudo: false
language: scala
# https://docs.travis-ci.com/user/notifications/#IRC-notification

View File

@ -10,12 +10,6 @@ cd gfc-semver
sbt publish-local
cd ..
git clone https://github.com/ornicar/ReactiveMongo --branch lichess
cd ReactiveMongo
git checkout b3e895f1c723d7cb518763f31fba62dc74311eab
sbt publish-local
cd ..
git clone https://github.com/ornicar/scalalib
cd scalalib
sbt publish-local

View File

@ -21,7 +21,7 @@ private[bookmark] object BookmarkRepo {
}
def gameIdsByUserId(userId: String): Fu[Set[String]] =
coll.distinct("g", $doc("u" -> userId).some) map lila.db.BSON.asStringSet
coll.distinct[String, Set]("g", $doc("u" -> userId).some)
def removeByGameId(gameId: String): Funit =
coll.remove($doc("g" -> gameId)).void

View File

@ -56,10 +56,10 @@ private final class ChallengeRepo(coll: Coll, maxPerUser: Int) {
)).cursor[Challenge]().gather[List](max)
private[challenge] def expiredIds(max: Int): Fu[List[Challenge.ID]] =
coll.distinct(
coll.distinct[String, List](
"_id",
$doc("expiresAt" -> $doc("$lt" -> DateTime.now)).some
) map lila.db.BSON.asStrings
)
def setSeenAgain(id: Challenge.ID) = coll.update(
$id(id),

View File

@ -196,23 +196,6 @@ object BSON extends Handlers {
def debugDoc(doc: Bdoc): String = (doc.elements.toList map {
case (k, v) => s"$k: ${debug(v)}"
}).mkString("{", ", ", "}")
def hashDoc(doc: Bdoc): String = debugDoc(doc).replace(" ", "")
def asStrings(vs: List[BSONValue]): List[String] = {
val b = new scala.collection.mutable.ListBuffer[String]
vs foreach {
case BSONString(s) => b += s
case _ =>
}
b.toList
}
def asStringSet(vs: List[BSONValue]): Set[String] = {
val b = Set.newBuilder[String]
vs foreach {
case BSONString(s) => b += s
case _ =>
}
b.result
}
}

View File

@ -3,8 +3,8 @@ package lila.db
import com.typesafe.config.Config
import reactivemongo.api._
import scala.concurrent.duration._
import scala.concurrent.Future
import scala.util.{ Success, Failure }
import scala.concurrent.{ Await, Future }
import scala.util.{ Failure, Success, Try }
import dsl._
final class Env(
@ -12,20 +12,29 @@ final class Env(
lifecycle: play.api.inject.ApplicationLifecycle) {
lazy val db = {
val parsedUri: MongoConnection.ParsedURI =
MongoConnection.parseURI(config.getString("uri")) match {
case Success(parsedURI) => parsedURI
case Failure(e) => sys error s"Invalid mongodb.uri"
}
val driver = new MongoDriver(Some(config))
val connection = driver.connection(parsedUri)
parsedUri.db.fold[DefaultDB](sys error s"cannot resolve database from URI: $parsedUri") { dbUri =>
val db = DB(dbUri, connection)
registerDriverShutdownHook(driver)
logger.info(s"""ReactiveMongoApi successfully started with DB '$dbUri'! Servers: ${parsedUri.hosts.map { s => s"[${s._1}:${s._2}]" }.mkString("\n\t\t")}""")
db
}
registerDriverShutdownHook(driver)
(for {
parsedUri <- MongoConnection.parseURI(config getString "uri")
con <- driver.connection(parsedUri, true)
db <- parsedUri.db match {
case Some(name) => {
def resolvedDB = con.database(name).andThen {
case _ =>
logger.info(s"""ReactiveMongoApi successfully started with DB '$name'! Servers: ${parsedUri.hosts.map { s => s"[${s._1}:${s._2}]" }.mkString("\n\t\t")}""")
}
Try(Await.result(resolvedDB, 10.seconds))
}
case _ => {
Failure[DefaultDB](new IllegalArgumentException(
s"cannot resolve database from URI: $parsedUri"))
}
}
} yield db).get
}
def apply(name: String): Coll = db(name)

View File

@ -68,10 +68,10 @@ sealed abstract class PostRepo(troll: Boolean) {
def sortQuery = $sort.createdAsc
def userIdsByTopicId(topicId: String): Fu[List[String]] =
coll.distinct("userId", $doc("topicId" -> topicId).some) map lila.db.BSON.asStrings
coll.distinct[String, List]("userId", $doc("topicId" -> topicId).some)
def idsByTopicId(topicId: String): Fu[List[String]] =
coll.distinct("_id", $doc("topicId" -> topicId).some) map lila.db.BSON.asStrings
coll.distinct[String, List]("_id", $doc("topicId" -> topicId).some)
import reactivemongo.api.ReadPreference
def cursor(

View File

@ -1,5 +1,7 @@
package lila.forumSearch
import reactivemongo.api.Cursor
import lila.forum.actorApi._
import lila.forum.{ Post, PostView, PostLiteView, PostApi, PostRepo }
import lila.search._
@ -37,14 +39,15 @@ final class ForumSearchApi(
case c: ESClientHttp => c.putMapping >> {
lila.log("forumSearch").info(s"Index to ${c.index.name}")
import lila.db.dsl._
import play.api.libs.iteratee._
PostRepo.cursor($empty).enumerateBulks(Int.MaxValue) |>>>
Iteratee.foldM[Iterator[Post], Unit](()) {
case (_, posts) => (postApi liteViews posts.toList) flatMap { views =>
c.storeBulk(views map (v => Id(v.post.id) -> toDoc(v)))
}
}
PostRepo.cursor($empty).foldBulksM({}) { (_, posts) =>
for {
views <- postApi liteViews posts.toList
_ <- c.storeBulk(views map (v => Id(v.post.id) -> toDoc(v)))
} yield Cursor.Cont({})
}
}
case _ => funit
}
}

View File

@ -190,9 +190,9 @@ object GameRepo {
coll.exists($id(id) ++ Query.analysed(true))
def filterAnalysed(ids: Seq[String]): Fu[Set[String]] =
coll.distinct("_id", ($inIds(ids) ++ $doc(
coll.distinct[String, Set]("_id", ($inIds(ids) ++ $doc(
F.analysed -> true
)).some) map lila.db.BSON.asStringSet
)).some)
def exists(id: String) = coll.exists($id(id))
@ -345,7 +345,7 @@ object GameRepo {
Match($doc(F.playerUids -> $doc("$ne" -> userId))),
GroupField(F.playerUids)("gs" -> SumValue(1)),
Sort(Descending("gs")),
Limit(limit))).map(_.documents.flatMap { obj =>
Limit(limit))).map(_.firstBatch.flatMap { obj =>
obj.getAs[String]("_id") flatMap { id =>
obj.getAs[Int]("gs") map { id -> _ }
}
@ -423,7 +423,7 @@ object GameRepo {
)),
GroupField(F.playerUids)("nb" -> SumValue(1)),
Sort(Descending("nb")),
Limit(max))).map(_.documents.flatMap { obj =>
Limit(max))).map(_.firstBatch.flatMap { obj =>
obj.getAs[Int]("nb") map { nb =>
UidNb(~obj.getAs[String]("_id"), nb)
}

View File

@ -15,7 +15,7 @@ final class PlayTime(gameColl: Coll) {
def apply(user: User): Fu[User.PlayTime] = user.playTime match {
case Some(pt) => fuccess(pt)
case None => {
case _ => {
gameColl
.find($doc(
Game.BSONFields.playerUids -> user.id,
@ -25,15 +25,13 @@ final class PlayTime(gameColl: Coll) {
moveTimeField -> true,
tvField -> true
))
.cursor[Bdoc]()
.enumerate() |>>> (Iteratee.fold(User.PlayTime(0, 0)) {
case (pt, doc) =>
val t = doc.getAs[ByteArray](moveTimeField) ?? { times =>
BinaryFormat.moveTime.read(times).sum
} / 10
val isTv = doc.get(tvField).isDefined
User.PlayTime(pt.total + t, pt.tv + isTv.fold(t, 0))
})
.cursor[Bdoc]().fold(User.PlayTime(0, 0)) { (pt, doc) =>
val t = doc.getAs[ByteArray](moveTimeField) ?? { times =>
BinaryFormat.moveTime.read(times).sum
} / 10
val isTv = doc.get(tvField).isDefined
User.PlayTime(pt.total + t, pt.tv + isTv.fold(t, 0))
}
}.addEffect { UserRepo.setPlayTime(user, _) }
}
}

View File

@ -12,7 +12,7 @@ object AggregationClusters {
}
private def single[X](question: Question[X], res: AggregationResult): List[Cluster[X]] =
res.documents.flatMap { doc =>
res.firstBatch.flatMap { doc =>
for {
x <- doc.getAs[X]("_id")(question.dimension.bson)
value <- doc.getAs[BSONNumberLike]("v")
@ -25,7 +25,7 @@ object AggregationClusters {
private implicit val StackEntryBSONReader = Macros.reader[StackEntry]
private def stacked[X](question: Question[X], res: AggregationResult): List[Cluster[X]] =
res.documents.flatMap { doc =>
res.firstBatch.flatMap { doc =>
val metricValues = Metric valuesOf question.metric
// println(lila.db.BSON debug doc)
for {

View File

@ -44,13 +44,13 @@ private final class Storage(coll: Coll) {
def find(id: String) = coll.find(selectId(id)).uno[Entry]
def ecos(userId: String): Fu[Set[String]] =
coll.distinct(F.eco, selectUserId(userId).some) map lila.db.BSON.asStringSet
coll.distinct[String, Set](F.eco, selectUserId(userId).some)
def nbByPerf(userId: String): Fu[Map[PerfType, Int]] = coll.aggregate(
Match(BSONDocument(F.userId -> userId)),
List(GroupField(F.perf)("nb" -> SumValue(1)))
).map {
_.documents.flatMap { doc =>
_.firstBatch.flatMap { doc =>
for {
perfType <- doc.getAs[PerfType]("_id")
nb <- doc.getAs[Int]("nb")

View File

@ -84,7 +84,7 @@ final class Gamify(
)), List(
GroupField("mod")("nb" -> SumValue(1)),
Sort(Descending("nb")))).map {
_.documents.flatMap { obj =>
_.firstBatch.flatMap { obj =>
obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply
}
}
@ -97,7 +97,7 @@ final class Gamify(
)), List(
GroupField("processedBy")("nb" -> SumValue(1)),
Sort(Descending("nb")))).map {
_.documents.flatMap { obj =>
_.firstBatch.flatMap { obj =>
obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply
}
}

View File

@ -3,7 +3,7 @@ package lila.opening
import scala.util.{ Try, Success, Failure }
import org.joda.time.DateTime
import reactivemongo.bson.BSONArray
import reactivemongo.bson.{ BSONArray, BSONValue }
import reactivemongo.core.commands._
import lila.db.dsl._
@ -38,7 +38,7 @@ private[opening] final class OpeningApi(
))
def playedIds(user: User): Fu[BSONArray] =
attemptColl.distinct(Attempt.BSONFields.openingId,
attemptColl.distinct[BSONValue, List](Attempt.BSONFields.openingId,
$doc(Attempt.BSONFields.userId -> user.id).some
) map BSONArray.apply
}

View File

@ -25,13 +25,11 @@ final class PerfStatIndexer(storage: PerfStatStorage, sequencer: ActorRef) {
Query.finished ++
Query.turnsMoreThan(2) ++
Query.variant(PerfType variantOf perfType),
Query.sortChronological)
.enumerate(Int.MaxValue, stopOnError = true) |>>>
Iteratee.fold[Game, PerfStat](PerfStat.init(user.id, perfType)) {
Query.sortChronological).fold(PerfStat.init(user.id, perfType)) {
case (perfStat, game) if game.perfType.contains(perfType) =>
Pov.ofUserId(game, user.id).fold(perfStat)(perfStat.agg)
case (perfStat, _) => perfStat
}
}
} flatMap storage.insert
def addGame(game: Game): Funit = game.players.flatMap { player =>

View File

@ -17,7 +17,7 @@ private final class MonthlyGoalApi(goal: Cents, chargeColl: Coll) {
Match($doc("date" $gt DateTime.now.withDayOfMonth(1).withTimeAtStartOfDay)), List(
Group(BSONNull)("cents" -> SumField("cents"))
)).map {
~_.documents.headOption.flatMap { _.getAs[Int]("cents") }
~_.firstBatch.headOption.flatMap { _.getAs[Int]("cents") }
} map Cents.apply
}

View File

@ -219,7 +219,7 @@ final class PlanApi(
GroupField("userId")("total" -> SumField("cents")),
Sort(Descending("total")),
Limit(nb))).map {
_.documents.flatMap { _.getAs[User.ID]("_id") }
_.firstBatch.flatMap { _.getAs[User.ID]("_id") }
} flatMap filterUserIds,
timeToLive = 1 hour)

View File

@ -115,9 +115,9 @@ final class PrefApi(
}
def unfollowableIds(userIds: List[String]): Fu[Set[String]] =
coll.distinct("_id", ($inIds(userIds) ++ $doc(
coll.distinct[String, Set]("_id", ($inIds(userIds) ++ $doc(
"follow" -> false
)).some) map lila.db.BSON.asStringSet
)).some)
def followableIds(userIds: List[String]): Fu[Set[String]] =
unfollowableIds(userIds) map userIds.toSet.diff

View File

@ -5,7 +5,7 @@ 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. BSONArray
import reactivemongo.bson.{ BSONArray, BSONValue }
import lila.db.dsl._
import lila.user.{ User, UserRepo }
@ -100,7 +100,7 @@ private[puzzle] final class PuzzleApi(
))
def playedIds(user: User): Fu[BSONArray] =
attemptColl.distinct(Attempt.BSONFields.puzzleId,
attemptColl.distinct[BSONValue, List](Attempt.BSONFields.puzzleId,
$doc(Attempt.BSONFields.userId -> user.id).some
) map BSONArray.apply

View File

@ -293,7 +293,7 @@ final class QaApi(
col.aggregate(Project($doc("tags" -> BSONBoolean(true))), List(
Unwind("tags"), Group(BSONBoolean(true))("tags" -> AddToSet("tags")))).
map(_.documents.headOption.flatMap(_.getAs[List[String]]("tags")).
map(_.firstBatch.headOption.flatMap(_.getAs[List[String]]("tags")).
getOrElse(List.empty[String]).map(_.toLowerCase).distinct)
}
}

View File

@ -44,7 +44,7 @@ final class RelationApi(
"u2" -> AddToSet("u2")),
Project($id($doc("$setIntersection" -> $arr("$u1", "$u2"))))
)).map {
~_.documents.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId
~_.firstBatch.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId
}
def fetchFollows(u1: ID, u2: ID) =

View File

@ -16,16 +16,16 @@ private[relation] object RelationRepo {
def blocking(userId: ID) = relating(userId, Block)
private def relaters(userId: ID, relation: Relation): Fu[Set[ID]] =
coll.distinct("u1", $doc(
coll.distinct[String, Set]("u1", $doc(
"u2" -> userId,
"r" -> relation
).some) map lila.db.BSON.asStringSet
).some)
private def relating(userId: ID, relation: Relation): Fu[Set[ID]] =
coll.distinct("u2", $doc(
coll.distinct[String, Set]("u2", $doc(
"u1" -> userId,
"r" -> relation
).some) map lila.db.BSON.asStringSet
).some)
def follow(u1: ID, u2: ID): Funit = save(u1, u2, Follow)
def unfollow(u1: ID, u2: ID): Funit = remove(u1, u2)

View File

@ -92,18 +92,18 @@ final class Api(
def userIdsSharingFingerprint = userIdsSharingField("fp") _
private def userIdsSharingField(field: String)(userId: String): Fu[List[String]] =
coll.distinct(
coll.distinct[String, List](
field,
$doc("user" -> userId, field -> $doc("$exists" -> true)).some
).flatMap {
case Nil => fuccess(Nil)
case values => coll.distinct(
case values => coll.distinct[String, List](
"user",
$doc(
field $in values,
"user" $ne userId
).some
) map lila.db.BSON.asStrings
)
}
def recentUserIdsByFingerprint = recentUserIdsByField("fp") _
@ -111,13 +111,13 @@ final class Api(
def recentUserIdsByIp = recentUserIdsByField("ip") _
private def recentUserIdsByField(field: String)(value: String): Fu[List[String]] =
coll.distinct(
coll.distinct[String, List](
"user",
$doc(
field -> value,
"date" $gt DateTime.now.minusYears(1)
).some
) map lila.db.BSON.asStrings
)
}
object Api {

View File

@ -75,9 +75,7 @@ final class Firewall(
def clear { cache.clear }
def contains(ip: String) = apply map (_ contains strToIp(ip))
def fetch: Fu[Set[IP]] =
coll.distinct("_id") map { res =>
lila.db.BSON.asStringSet(res) map strToIp
} addEffect { ips =>
coll.distinct[String, Set]("_id").map(_.map(strToIp)).addEffect { ips =>
lila.mon.security.firewall.ip(ips.size)
}
}

View File

@ -72,12 +72,12 @@ object UserSpy {
private def nextUsers(field: String)(values: Set[Value], user: User)(implicit coll: Coll): Fu[Set[User]] =
values.nonEmpty ?? {
coll.distinct("user",
coll.distinct[String, Set]("user",
$doc(
field $in values,
"user" $ne user.id
).some
) map lila.db.BSON.asStrings flatMap { userIds =>
) flatMap { userIds =>
userIds.nonEmpty ?? (UserRepo byIds userIds) map (_.toSet)
}
}

View File

@ -1,6 +1,7 @@
package lila.study
import org.joda.time.DateTime
import reactivemongo.api.Cursor
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Project, Match }
import scala.concurrent.duration._
@ -105,20 +106,16 @@ final class StudyRepo(private[study] val coll: Coll) {
def filterLiked(user: User, studyIds: Seq[Study.ID]): Fu[Set[Study.ID]] =
coll.primitive[Study.ID]($inIds(studyIds) ++ selectLiker(user.id), "_id").map(_.toSet)
def resetAllRanks: Fu[Int] = {
import play.api.libs.iteratee._
coll.find(
$empty, $doc("likes" -> true, "createdAt" -> true)
).cursor[Bdoc]().enumerate() |>>>
Iteratee.foldM[Bdoc, Int](0) {
case (count, doc) => ~(for {
id <- doc.getAs[Study.ID]("_id")
likes <- doc.getAs[Study.Likes]("likes")
createdAt <- doc.getAs[DateTime]("createdAt")
} yield coll.update(
$id(id), $set("rank" -> Study.Rank.compute(likes, createdAt))
).void) inject (count + 1)
}
def resetAllRanks: Fu[Int] = coll.find(
$empty, $doc("likes" -> true, "createdAt" -> true)
).cursor[Bdoc]().foldWhileM(0) { (count, doc) =>
~(for {
id <- doc.getAs[Study.ID]("_id")
likes <- doc.getAs[Study.Likes]("likes")
createdAt <- doc.getAs[DateTime]("createdAt")
} yield coll.update(
$id(id), $set("rank" -> Study.Rank.compute(likes, createdAt))
).void) inject Cursor.Cont(count + 1)
}
private def doLike(studyId: Study.ID, userId: User.ID, v: Boolean): Funit =
@ -138,7 +135,7 @@ final class StudyRepo(private[study] val coll: Coll) {
)))
).map { res =>
for {
doc <- res.documents.headOption
doc <- res.firstBatch.headOption
likes <- doc.getAs[Study.Likes]("likes")
createdAt <- doc.getAs[DateTime]("createdAt")
} yield likes -> createdAt

View File

@ -15,10 +15,10 @@ object MemberRepo {
type ID = String
def userIdsByTeam(teamId: ID): Fu[Set[ID]] =
coll.distinct("user", $doc("team" -> teamId).some) map lila.db.BSON.asStringSet
coll.distinct[String, Set]("user", $doc("team" -> teamId).some)
def teamIdsByUser(userId: ID): Fu[Set[ID]] =
coll.distinct("team", $doc("user" -> userId).some) map lila.db.BSON.asStringSet
coll.distinct[String, Set]("team", $doc("user" -> userId).some)
def removeByteam(teamId: ID): Funit =
coll.remove(teamQuery(teamId)).void

View File

@ -7,6 +7,7 @@ import lila.hub.actorApi.forum.MakeTeam
import lila.hub.actorApi.timeline.{ Propagate, TeamJoin, TeamCreate }
import lila.user.{ User, UserRepo, UserContext }
import org.joda.time.Period
import reactivemongo.api.Cursor
final class TeamApi(
coll: Colls,
@ -162,13 +163,11 @@ final class TeamApi(
def nbRequests(teamId: String) = cached nbRequests teamId
import play.api.libs.iteratee._
def recomputeNbMembers =
coll.team.find($empty).cursor[Team]()
.enumerate(Int.MaxValue, stopOnError = true) |>>>
Iteratee.foldM[Team, Unit](()) {
case (_, team) => MemberRepo.countByTeam(team.id) flatMap { nb =>
coll.team.updateField($id(team.id), "nbMembers", nb).void
}
}
coll.team.find($empty).cursor[Team]().foldWhileM({}) { (_, team) =>
for {
nb <- MemberRepo.countByTeam(team.id)
_ <- coll.team.updateField($id(team.id), "nbMembers", nb)
} yield Cursor.Cont({})
}
}

View File

@ -24,7 +24,7 @@ object TeamRepo {
coll.uno[Team]($id(id) ++ $doc("createdBy" -> createdBy))
def teamIdsByCreator(userId: String): Fu[List[String]] =
coll.distinct("_id", BSONDocument("createdBy" -> userId).some) map lila.db.BSON.asStrings
coll.distinct[String, List]("_id", BSONDocument("createdBy" -> userId).some)
def name(id: String): Fu[Option[String]] =
coll.primitiveOne[String]($id(id), "name")

View File

@ -1,11 +1,12 @@
package lila.teamSearch
import reactivemongo.api.Cursor
import lila.search._
import lila.team.actorApi._
import lila.team.{ Team, TeamRepo }
import play.api.libs.json._
import play.api.libs.iteratee._
final class TeamSearchApi(client: ESClient) extends SearchReadApi[Team, Query] {
@ -28,13 +29,13 @@ final class TeamSearchApi(client: ESClient) extends SearchReadApi[Team, Query] {
case c: ESClientHttp => c.putMapping >> {
lila.log("teamSearch").info(s"Index to ${c.index.name}")
import lila.db.dsl._
TeamRepo.cursor($doc("enabled" -> true))
.enumerateBulks(Int.MaxValue) |>>>
Iteratee.foldM[Iterator[Team], Unit](()) {
case (_, teams) =>
c.storeBulk(teams.toList map (t => Id(t.id) -> toDoc(t)))
}
TeamRepo.cursor($doc("enabled" -> true)).foldBulksM({}) { (_, teams) =>
c.storeBulk(teams.toList map (t => Id(t.id) -> toDoc(t))).
map(Cursor.Cont(_))
}
}
case _ => funit
}
}

View File

@ -21,8 +21,8 @@ private[timeline] final class UnsubApi(coll: Coll) {
coll.count(select(channel, userId).some) map (0 !=)
def filterUnsub(channel: String, userIds: List[String]): Fu[List[String]] =
coll.distinct("_id", $inIds(userIds.map { makeId(channel, _) }).some) map
lila.db.BSON.asStrings map { unsubs =>
coll.distinct[String, List](
"_id", $inIds(userIds.map { makeId(channel, _) }).some) map { unsubs =>
userIds diff unsubs.map(_ takeWhile ('@' !=))
}
}

View File

@ -31,7 +31,7 @@ final class LeaderboardApi(
Match($doc("u" -> user.id)),
List(GroupField("v")("nb" -> SumValue(1), "points" -> Push("s"), "ratios" -> Push("w")))
).map {
_.documents map leaderboardAggregationResultBSONHandler.read
_.firstBatch map leaderboardAggregationResultBSONHandler.read
}.map { aggs =>
ChartData {
aggs.flatMap { agg =>

View File

@ -32,8 +32,8 @@ object PairingRepo {
coll.find(
selectTour(tourId) ++ $doc("u" $in userIds),
$doc("_id" -> false, "u" -> true)
).sort(recentSort).cursor[Bdoc]().enumerate(nb) |>>>
Iteratee.fold(scala.collection.immutable.Map.empty[String, String]) { (acc, doc) =>
).sort(recentSort).cursor[Bdoc]().fold(
scala.collection.immutable.Map.empty[String, String], nb) { (acc, doc) =>
~doc.getAs[List[String]]("u") match {
case List(u1, u2) =>
val acc1 = acc.contains(u1).fold(acc, acc.updated(u1, u2))
@ -81,7 +81,7 @@ object PairingRepo {
Unwind("u"),
GroupField("u")("nb" -> SumValue(1))
)).map {
_.documents.flatMap { doc =>
_.firstBatch.flatMap { doc =>
doc.getAs[String]("_id") flatMap { uid =>
doc.getAs[Int]("nb") map { uid -> _ }
}
@ -132,12 +132,12 @@ object PairingRepo {
Project($doc(
"u" -> BSONBoolean(true), "_id" -> BSONBoolean(false))),
Unwind("u"), Group(BSONBoolean(true))("ids" -> AddToSet("u")))).map(
_.documents.headOption.flatMap(_.getAs[Set[String]]("ids")).
_.firstBatch.headOption.flatMap(_.getAs[Set[String]]("ids")).
getOrElse(Set.empty[String]))
def playingGameIds(tourId: String): Fu[List[String]] =
coll.aggregate(Match(selectTour(tourId) ++ selectPlaying), List(
Group(BSONBoolean(true))("ids" -> Push("_id")))).map(
_.documents.headOption.flatMap(_.getAs[List[String]]("ids")).
_.firstBatch.headOption.flatMap(_.getAs[List[String]]("ids")).
getOrElse(List.empty[String]))
}

View File

@ -102,10 +102,11 @@ object PlayerRepo {
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Descending, Group, Match, Push, Sort }
def userIds(tourId: String): Fu[List[String]] =
coll.distinct("uid", selectTour(tourId).some) map lila.db.BSON.asStrings
coll.distinct[String, List]("uid", selectTour(tourId).some)
def activeUserIds(tourId: String): Fu[List[String]] =
coll.distinct("uid", (selectTour(tourId) ++ selectActive).some) map lila.db.BSON.asStrings
coll.distinct[String, List](
"uid", (selectTour(tourId) ++ selectActive).some)
def winner(tourId: String): Fu[Option[Player]] =
coll.find(selectTour(tourId)).sort(bestSort).uno[Player]
@ -114,7 +115,7 @@ object PlayerRepo {
private[tournament] def computeRanking(tourId: String): Fu[Ranking] =
coll.aggregate(Match(selectTour(tourId)), List(Sort(Descending("m")),
Group(BSONNull)("uids" -> Push("uid")))) map {
_.documents.headOption.fold(Map.empty: Ranking) {
_.firstBatch.headOption.fold(Map.empty: Ranking) {
_ get "uids" match {
case Some(BSONArray(uids)) =>
// mutable optimized implementation

View File

@ -2,6 +2,7 @@ package lila.user
import org.joda.time.DateTime
import play.api.libs.iteratee._
import reactivemongo.api.Cursor
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Match, Project, Group, GroupField, SumField, SumValue }
import reactivemongo.bson._
import scala.concurrent.duration._
@ -77,21 +78,18 @@ final class RankingApi(
f = compute,
timeToLive = 15 minutes)
private def compute(perfId: Perf.ID): Fu[Map[User.ID, Rank]] = {
val enumerator = coll.find(
private def compute(perfId: Perf.ID): Fu[Map[User.ID, Rank]] =
coll.find(
$doc("perf" -> perfId, "stable" -> true),
$doc("user" -> true, "_id" -> false)
).sort($doc("rating" -> -1)).cursor[Bdoc]().enumerate()
var rank = 1
val b = Map.newBuilder[User.ID, Rank]
val mapBuilder: Iteratee[Bdoc, Unit] = Iteratee.foreach { doc =>
doc.getAs[User.ID]("user") foreach { user =>
b += (user -> rank)
rank = rank + 1
}
}
enumerator.run(mapBuilder) inject b.result
}
).sort($doc("rating" -> -1)).cursor[Bdoc]().
fold(1 -> Map.newBuilder[User.ID, Rank]) {
case (state @ (rank, b), doc) =>
doc.getAs[User.ID]("user").fold(state) { user =>
b += (user -> rank)
(rank + 1) -> b
}
}.map(_._2.result())
}
object weeklyRatingDistribution {
@ -122,7 +120,7 @@ final class RankingApi(
)),
GroupField("r")("nb" -> SumValue(1))
)).map { res =>
val hash = res.documents.flatMap { obj =>
val hash = res.firstBatch.flatMap { obj =>
for {
rating <- obj.getAs[Int]("_id")
nb <- obj.getAs[NbUsers]("nb")

View File

@ -81,7 +81,7 @@ object UserRepo {
coll.primitiveOne[String]($id(id), F.username)
def usernamesByIds(ids: List[ID]) =
coll.distinct(F.username, $inIds(ids).some) map lila.db.BSON.asStrings
coll.distinct[String, List](F.username, $inIds(ids).some)
def orderByGameCount(u1: String, u2: String): Fu[Option[(String, String)]] = {
coll.find(
@ -242,7 +242,7 @@ object UserRepo {
coll.primitive[String]($inIds(usernames.map(normalize)), "_id")
def engineIds: Fu[Set[String]] =
coll.distinct("_id", $doc("engine" -> true).some) map lila.db.BSON.asStringSet
coll.distinct[String, Set]("_id", $doc("engine" -> true).some)
private val userIdPattern = """^[\w-]{3,20}$""".r.pattern
@ -339,7 +339,7 @@ object UserRepo {
def idsSumToints(ids: Iterable[String]): Fu[Int] =
ids.nonEmpty ?? coll.aggregate(Match($inIds(ids)),
List(Group(BSONNull)(F.toints -> SumField(F.toints)))).map(
_.documents.headOption flatMap { _.getAs[Int](F.toints) }
_.firstBatch.headOption flatMap { _.getAs[Int](F.toints) }
).map(~_)
def filterByEngine(userIds: List[String]): Fu[List[String]] =

View File

@ -76,7 +76,7 @@ private[video] final class VideoApi(
).void
def allIds: Fu[List[Video.ID]] =
videoColl.distinct("_id", none) map lila.db.BSON.asStrings
videoColl.distinct[String, List]("_id", none)
def popular(user: Option[User], page: Int): Fu[Paginator[VideoView]] = Paginator(
adapter = new Adapter[Video](
@ -149,10 +149,10 @@ private[video] final class VideoApi(
).some) map (0!=)
def seenVideoIds(user: User, videos: Seq[Video]): Fu[Set[Video.ID]] =
viewColl.distinct(View.BSONFields.videoId,
viewColl.distinct[String, Set](View.BSONFields.videoId,
$inIds(videos.map { v =>
View.makeId(v.id, user.id)
}).some) map lila.db.BSON.asStringSet
}).some)
}
object tag {
@ -177,7 +177,7 @@ private[video] final class VideoApi(
Match($doc("tags" $all filterTags)),
List(Project($doc("tags" -> true)),
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)))).map(
_.documents.flatMap(_.asOpt[TagNb]))
_.firstBatch.flatMap(_.asOpt[TagNb]))
allPopular zip allPaths map {
case (all, paths) =>
@ -203,7 +203,7 @@ private[video] final class VideoApi(
Project($doc("tags" -> true)), List(
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)),
Sort(Descending("nb")))).map(
_.documents.flatMap(_.asOpt[TagNb])),
_.firstBatch.flatMap(_.asOpt[TagNb])),
timeToLive = 1.day)
}
}

View File

@ -34,7 +34,7 @@ object Dependencies {
val hasher = "com.roundeights" %% "hasher" % "1.2.0"
val jgit = "org.eclipse.jgit" % "org.eclipse.jgit" % "3.2.0.201312181205-r"
val jodaTime = "joda-time" % "joda-time" % "2.9.2"
val RM = "org.reactivemongo" % "reactivemongo_2.11" % "0.11.9.1-LILA"
val RM = "org.reactivemongo" %% "reactivemongo" % "0.12-RC0"
val maxmind = "com.sanoma.cda" %% "maxmind-geoip2-scala" % "1.2.3-THIB"
val prismic = "io.prismic" %% "scala-kit" % "1.2.11-THIB"
val java8compat = "org.scala-lang.modules" %% "scala-java8-compat" % "0.7.0"