Merge remote-tracking branch 'cchantep/rm-0.12-RC0' into rm012
* cchantep/rm-0.12-RC0: Upgrade to ReactiveMongo 0.12 (Release Candidate 0)
This commit is contained in:
commit
dd9e84e828
|
@ -1,3 +1,4 @@
|
||||||
|
sudo: false
|
||||||
language: scala
|
language: scala
|
||||||
|
|
||||||
# https://docs.travis-ci.com/user/notifications/#IRC-notification
|
# https://docs.travis-ci.com/user/notifications/#IRC-notification
|
||||||
|
|
|
@ -10,12 +10,6 @@ cd gfc-semver
|
||||||
sbt publish-local
|
sbt publish-local
|
||||||
cd ..
|
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
|
git clone https://github.com/ornicar/scalalib
|
||||||
cd scalalib
|
cd scalalib
|
||||||
sbt publish-local
|
sbt publish-local
|
||||||
|
|
|
@ -21,7 +21,7 @@ private[bookmark] object BookmarkRepo {
|
||||||
}
|
}
|
||||||
|
|
||||||
def gameIdsByUserId(userId: String): Fu[Set[String]] =
|
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 =
|
def removeByGameId(gameId: String): Funit =
|
||||||
coll.remove($doc("g" -> gameId)).void
|
coll.remove($doc("g" -> gameId)).void
|
||||||
|
|
|
@ -56,10 +56,10 @@ private final class ChallengeRepo(coll: Coll, maxPerUser: Int) {
|
||||||
)).cursor[Challenge]().gather[List](max)
|
)).cursor[Challenge]().gather[List](max)
|
||||||
|
|
||||||
private[challenge] def expiredIds(max: Int): Fu[List[Challenge.ID]] =
|
private[challenge] def expiredIds(max: Int): Fu[List[Challenge.ID]] =
|
||||||
coll.distinct(
|
coll.distinct[String, List](
|
||||||
"_id",
|
"_id",
|
||||||
$doc("expiresAt" -> $doc("$lt" -> DateTime.now)).some
|
$doc("expiresAt" -> $doc("$lt" -> DateTime.now)).some
|
||||||
) map lila.db.BSON.asStrings
|
)
|
||||||
|
|
||||||
def setSeenAgain(id: Challenge.ID) = coll.update(
|
def setSeenAgain(id: Challenge.ID) = coll.update(
|
||||||
$id(id),
|
$id(id),
|
||||||
|
|
|
@ -196,23 +196,6 @@ object BSON extends Handlers {
|
||||||
def debugDoc(doc: Bdoc): String = (doc.elements.toList map {
|
def debugDoc(doc: Bdoc): String = (doc.elements.toList map {
|
||||||
case (k, v) => s"$k: ${debug(v)}"
|
case (k, v) => s"$k: ${debug(v)}"
|
||||||
}).mkString("{", ", ", "}")
|
}).mkString("{", ", ", "}")
|
||||||
|
|
||||||
def hashDoc(doc: Bdoc): String = debugDoc(doc).replace(" ", "")
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ package lila.db
|
||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import reactivemongo.api._
|
import reactivemongo.api._
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.{ Await, Future }
|
||||||
import scala.util.{ Success, Failure }
|
import scala.util.{ Failure, Success, Try }
|
||||||
import dsl._
|
import dsl._
|
||||||
|
|
||||||
final class Env(
|
final class Env(
|
||||||
|
@ -12,20 +12,29 @@ final class Env(
|
||||||
lifecycle: play.api.inject.ApplicationLifecycle) {
|
lifecycle: play.api.inject.ApplicationLifecycle) {
|
||||||
|
|
||||||
lazy val db = {
|
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 driver = new MongoDriver(Some(config))
|
||||||
val connection = driver.connection(parsedUri)
|
|
||||||
|
|
||||||
parsedUri.db.fold[DefaultDB](sys error s"cannot resolve database from URI: $parsedUri") { dbUri =>
|
registerDriverShutdownHook(driver)
|
||||||
val db = DB(dbUri, connection)
|
|
||||||
registerDriverShutdownHook(driver)
|
(for {
|
||||||
logger.info(s"""ReactiveMongoApi successfully started with DB '$dbUri'! Servers: ${parsedUri.hosts.map { s => s"[${s._1}:${s._2}]" }.mkString("\n\t\t")}""")
|
parsedUri <- MongoConnection.parseURI(config getString "uri")
|
||||||
db
|
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)
|
def apply(name: String): Coll = db(name)
|
||||||
|
|
|
@ -68,10 +68,10 @@ sealed abstract class PostRepo(troll: Boolean) {
|
||||||
def sortQuery = $sort.createdAsc
|
def sortQuery = $sort.createdAsc
|
||||||
|
|
||||||
def userIdsByTopicId(topicId: String): Fu[List[String]] =
|
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]] =
|
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
|
import reactivemongo.api.ReadPreference
|
||||||
def cursor(
|
def cursor(
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package lila.forumSearch
|
package lila.forumSearch
|
||||||
|
|
||||||
|
import reactivemongo.api.Cursor
|
||||||
|
|
||||||
import lila.forum.actorApi._
|
import lila.forum.actorApi._
|
||||||
import lila.forum.{ Post, PostView, PostLiteView, PostApi, PostRepo }
|
import lila.forum.{ Post, PostView, PostLiteView, PostApi, PostRepo }
|
||||||
import lila.search._
|
import lila.search._
|
||||||
|
@ -37,14 +39,15 @@ final class ForumSearchApi(
|
||||||
case c: ESClientHttp => c.putMapping >> {
|
case c: ESClientHttp => c.putMapping >> {
|
||||||
lila.log("forumSearch").info(s"Index to ${c.index.name}")
|
lila.log("forumSearch").info(s"Index to ${c.index.name}")
|
||||||
import lila.db.dsl._
|
import lila.db.dsl._
|
||||||
import play.api.libs.iteratee._
|
|
||||||
PostRepo.cursor($empty).enumerateBulks(Int.MaxValue) |>>>
|
PostRepo.cursor($empty).foldBulksM({}) { (_, posts) =>
|
||||||
Iteratee.foldM[Iterator[Post], Unit](()) {
|
for {
|
||||||
case (_, posts) => (postApi liteViews posts.toList) flatMap { views =>
|
views <- postApi liteViews posts.toList
|
||||||
c.storeBulk(views map (v => Id(v.post.id) -> toDoc(v)))
|
_ <- c.storeBulk(views map (v => Id(v.post.id) -> toDoc(v)))
|
||||||
}
|
} yield Cursor.Cont({})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => funit
|
case _ => funit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,9 +190,9 @@ object GameRepo {
|
||||||
coll.exists($id(id) ++ Query.analysed(true))
|
coll.exists($id(id) ++ Query.analysed(true))
|
||||||
|
|
||||||
def filterAnalysed(ids: Seq[String]): Fu[Set[String]] =
|
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
|
F.analysed -> true
|
||||||
)).some) map lila.db.BSON.asStringSet
|
)).some)
|
||||||
|
|
||||||
def exists(id: String) = coll.exists($id(id))
|
def exists(id: String) = coll.exists($id(id))
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ object GameRepo {
|
||||||
Match($doc(F.playerUids -> $doc("$ne" -> userId))),
|
Match($doc(F.playerUids -> $doc("$ne" -> userId))),
|
||||||
GroupField(F.playerUids)("gs" -> SumValue(1)),
|
GroupField(F.playerUids)("gs" -> SumValue(1)),
|
||||||
Sort(Descending("gs")),
|
Sort(Descending("gs")),
|
||||||
Limit(limit))).map(_.documents.flatMap { obj =>
|
Limit(limit))).map(_.firstBatch.flatMap { obj =>
|
||||||
obj.getAs[String]("_id") flatMap { id =>
|
obj.getAs[String]("_id") flatMap { id =>
|
||||||
obj.getAs[Int]("gs") map { id -> _ }
|
obj.getAs[Int]("gs") map { id -> _ }
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ object GameRepo {
|
||||||
)),
|
)),
|
||||||
GroupField(F.playerUids)("nb" -> SumValue(1)),
|
GroupField(F.playerUids)("nb" -> SumValue(1)),
|
||||||
Sort(Descending("nb")),
|
Sort(Descending("nb")),
|
||||||
Limit(max))).map(_.documents.flatMap { obj =>
|
Limit(max))).map(_.firstBatch.flatMap { obj =>
|
||||||
obj.getAs[Int]("nb") map { nb =>
|
obj.getAs[Int]("nb") map { nb =>
|
||||||
UidNb(~obj.getAs[String]("_id"), nb)
|
UidNb(~obj.getAs[String]("_id"), nb)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ final class PlayTime(gameColl: Coll) {
|
||||||
|
|
||||||
def apply(user: User): Fu[User.PlayTime] = user.playTime match {
|
def apply(user: User): Fu[User.PlayTime] = user.playTime match {
|
||||||
case Some(pt) => fuccess(pt)
|
case Some(pt) => fuccess(pt)
|
||||||
case None => {
|
case _ => {
|
||||||
gameColl
|
gameColl
|
||||||
.find($doc(
|
.find($doc(
|
||||||
Game.BSONFields.playerUids -> user.id,
|
Game.BSONFields.playerUids -> user.id,
|
||||||
|
@ -25,15 +25,13 @@ final class PlayTime(gameColl: Coll) {
|
||||||
moveTimeField -> true,
|
moveTimeField -> true,
|
||||||
tvField -> true
|
tvField -> true
|
||||||
))
|
))
|
||||||
.cursor[Bdoc]()
|
.cursor[Bdoc]().fold(User.PlayTime(0, 0)) { (pt, doc) =>
|
||||||
.enumerate() |>>> (Iteratee.fold(User.PlayTime(0, 0)) {
|
val t = doc.getAs[ByteArray](moveTimeField) ?? { times =>
|
||||||
case (pt, doc) =>
|
BinaryFormat.moveTime.read(times).sum
|
||||||
val t = doc.getAs[ByteArray](moveTimeField) ?? { times =>
|
} / 10
|
||||||
BinaryFormat.moveTime.read(times).sum
|
val isTv = doc.get(tvField).isDefined
|
||||||
} / 10
|
User.PlayTime(pt.total + t, pt.tv + isTv.fold(t, 0))
|
||||||
val isTv = doc.get(tvField).isDefined
|
}
|
||||||
User.PlayTime(pt.total + t, pt.tv + isTv.fold(t, 0))
|
|
||||||
})
|
|
||||||
}.addEffect { UserRepo.setPlayTime(user, _) }
|
}.addEffect { UserRepo.setPlayTime(user, _) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ object AggregationClusters {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def single[X](question: Question[X], res: AggregationResult): List[Cluster[X]] =
|
private def single[X](question: Question[X], res: AggregationResult): List[Cluster[X]] =
|
||||||
res.documents.flatMap { doc =>
|
res.firstBatch.flatMap { doc =>
|
||||||
for {
|
for {
|
||||||
x <- doc.getAs[X]("_id")(question.dimension.bson)
|
x <- doc.getAs[X]("_id")(question.dimension.bson)
|
||||||
value <- doc.getAs[BSONNumberLike]("v")
|
value <- doc.getAs[BSONNumberLike]("v")
|
||||||
|
@ -25,7 +25,7 @@ object AggregationClusters {
|
||||||
private implicit val StackEntryBSONReader = Macros.reader[StackEntry]
|
private implicit val StackEntryBSONReader = Macros.reader[StackEntry]
|
||||||
|
|
||||||
private def stacked[X](question: Question[X], res: AggregationResult): List[Cluster[X]] =
|
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
|
val metricValues = Metric valuesOf question.metric
|
||||||
// println(lila.db.BSON debug doc)
|
// println(lila.db.BSON debug doc)
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -44,13 +44,13 @@ private final class Storage(coll: Coll) {
|
||||||
def find(id: String) = coll.find(selectId(id)).uno[Entry]
|
def find(id: String) = coll.find(selectId(id)).uno[Entry]
|
||||||
|
|
||||||
def ecos(userId: String): Fu[Set[String]] =
|
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(
|
def nbByPerf(userId: String): Fu[Map[PerfType, Int]] = coll.aggregate(
|
||||||
Match(BSONDocument(F.userId -> userId)),
|
Match(BSONDocument(F.userId -> userId)),
|
||||||
List(GroupField(F.perf)("nb" -> SumValue(1)))
|
List(GroupField(F.perf)("nb" -> SumValue(1)))
|
||||||
).map {
|
).map {
|
||||||
_.documents.flatMap { doc =>
|
_.firstBatch.flatMap { doc =>
|
||||||
for {
|
for {
|
||||||
perfType <- doc.getAs[PerfType]("_id")
|
perfType <- doc.getAs[PerfType]("_id")
|
||||||
nb <- doc.getAs[Int]("nb")
|
nb <- doc.getAs[Int]("nb")
|
||||||
|
|
|
@ -84,7 +84,7 @@ final class Gamify(
|
||||||
)), List(
|
)), List(
|
||||||
GroupField("mod")("nb" -> SumValue(1)),
|
GroupField("mod")("nb" -> SumValue(1)),
|
||||||
Sort(Descending("nb")))).map {
|
Sort(Descending("nb")))).map {
|
||||||
_.documents.flatMap { obj =>
|
_.firstBatch.flatMap { obj =>
|
||||||
obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply
|
obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ final class Gamify(
|
||||||
)), List(
|
)), List(
|
||||||
GroupField("processedBy")("nb" -> SumValue(1)),
|
GroupField("processedBy")("nb" -> SumValue(1)),
|
||||||
Sort(Descending("nb")))).map {
|
Sort(Descending("nb")))).map {
|
||||||
_.documents.flatMap { obj =>
|
_.firstBatch.flatMap { obj =>
|
||||||
obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply
|
obj.getAs[String]("_id") |@| obj.getAs[Int]("nb") apply ModCount.apply
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package lila.opening
|
||||||
import scala.util.{ Try, Success, Failure }
|
import scala.util.{ Try, Success, Failure }
|
||||||
|
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import reactivemongo.bson.BSONArray
|
import reactivemongo.bson.{ BSONArray, BSONValue }
|
||||||
import reactivemongo.core.commands._
|
import reactivemongo.core.commands._
|
||||||
|
|
||||||
import lila.db.dsl._
|
import lila.db.dsl._
|
||||||
|
@ -38,7 +38,7 @@ private[opening] final class OpeningApi(
|
||||||
))
|
))
|
||||||
|
|
||||||
def playedIds(user: User): Fu[BSONArray] =
|
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
|
$doc(Attempt.BSONFields.userId -> user.id).some
|
||||||
) map BSONArray.apply
|
) map BSONArray.apply
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,11 @@ final class PerfStatIndexer(storage: PerfStatStorage, sequencer: ActorRef) {
|
||||||
Query.finished ++
|
Query.finished ++
|
||||||
Query.turnsMoreThan(2) ++
|
Query.turnsMoreThan(2) ++
|
||||||
Query.variant(PerfType variantOf perfType),
|
Query.variant(PerfType variantOf perfType),
|
||||||
Query.sortChronological)
|
Query.sortChronological).fold(PerfStat.init(user.id, perfType)) {
|
||||||
.enumerate(Int.MaxValue, stopOnError = true) |>>>
|
|
||||||
Iteratee.fold[Game, PerfStat](PerfStat.init(user.id, perfType)) {
|
|
||||||
case (perfStat, game) if game.perfType.contains(perfType) =>
|
case (perfStat, game) if game.perfType.contains(perfType) =>
|
||||||
Pov.ofUserId(game, user.id).fold(perfStat)(perfStat.agg)
|
Pov.ofUserId(game, user.id).fold(perfStat)(perfStat.agg)
|
||||||
case (perfStat, _) => perfStat
|
case (perfStat, _) => perfStat
|
||||||
}
|
}
|
||||||
} flatMap storage.insert
|
} flatMap storage.insert
|
||||||
|
|
||||||
def addGame(game: Game): Funit = game.players.flatMap { player =>
|
def addGame(game: Game): Funit = game.players.flatMap { player =>
|
||||||
|
|
|
@ -17,7 +17,7 @@ private final class MonthlyGoalApi(goal: Cents, chargeColl: Coll) {
|
||||||
Match($doc("date" $gt DateTime.now.withDayOfMonth(1).withTimeAtStartOfDay)), List(
|
Match($doc("date" $gt DateTime.now.withDayOfMonth(1).withTimeAtStartOfDay)), List(
|
||||||
Group(BSONNull)("cents" -> SumField("cents"))
|
Group(BSONNull)("cents" -> SumField("cents"))
|
||||||
)).map {
|
)).map {
|
||||||
~_.documents.headOption.flatMap { _.getAs[Int]("cents") }
|
~_.firstBatch.headOption.flatMap { _.getAs[Int]("cents") }
|
||||||
} map Cents.apply
|
} map Cents.apply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ final class PlanApi(
|
||||||
GroupField("userId")("total" -> SumField("cents")),
|
GroupField("userId")("total" -> SumField("cents")),
|
||||||
Sort(Descending("total")),
|
Sort(Descending("total")),
|
||||||
Limit(nb))).map {
|
Limit(nb))).map {
|
||||||
_.documents.flatMap { _.getAs[User.ID]("_id") }
|
_.firstBatch.flatMap { _.getAs[User.ID]("_id") }
|
||||||
} flatMap filterUserIds,
|
} flatMap filterUserIds,
|
||||||
timeToLive = 1 hour)
|
timeToLive = 1 hour)
|
||||||
|
|
||||||
|
|
|
@ -115,9 +115,9 @@ final class PrefApi(
|
||||||
}
|
}
|
||||||
|
|
||||||
def unfollowableIds(userIds: List[String]): Fu[Set[String]] =
|
def unfollowableIds(userIds: List[String]): Fu[Set[String]] =
|
||||||
coll.distinct("_id", ($inIds(userIds) ++ $doc(
|
coll.distinct[String, Set]("_id", ($inIds(userIds) ++ $doc(
|
||||||
"follow" -> false
|
"follow" -> false
|
||||||
)).some) map lila.db.BSON.asStringSet
|
)).some)
|
||||||
|
|
||||||
def followableIds(userIds: List[String]): Fu[Set[String]] =
|
def followableIds(userIds: List[String]): Fu[Set[String]] =
|
||||||
unfollowableIds(userIds) map userIds.toSet.diff
|
unfollowableIds(userIds) map userIds.toSet.diff
|
||||||
|
|
|
@ -5,7 +5,7 @@ import scala.util.{ Try, Success, Failure }
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import play.api.libs.json.JsValue
|
import play.api.libs.json.JsValue
|
||||||
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
|
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework._
|
||||||
import reactivemongo.bson. BSONArray
|
import reactivemongo.bson.{ BSONArray, BSONValue }
|
||||||
|
|
||||||
import lila.db.dsl._
|
import lila.db.dsl._
|
||||||
import lila.user.{ User, UserRepo }
|
import lila.user.{ User, UserRepo }
|
||||||
|
@ -100,7 +100,7 @@ private[puzzle] final class PuzzleApi(
|
||||||
))
|
))
|
||||||
|
|
||||||
def playedIds(user: User): Fu[BSONArray] =
|
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
|
$doc(Attempt.BSONFields.userId -> user.id).some
|
||||||
) map BSONArray.apply
|
) map BSONArray.apply
|
||||||
|
|
||||||
|
|
|
@ -293,7 +293,7 @@ final class QaApi(
|
||||||
|
|
||||||
col.aggregate(Project($doc("tags" -> BSONBoolean(true))), List(
|
col.aggregate(Project($doc("tags" -> BSONBoolean(true))), List(
|
||||||
Unwind("tags"), Group(BSONBoolean(true))("tags" -> AddToSet("tags")))).
|
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)
|
getOrElse(List.empty[String]).map(_.toLowerCase).distinct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ final class RelationApi(
|
||||||
"u2" -> AddToSet("u2")),
|
"u2" -> AddToSet("u2")),
|
||||||
Project($id($doc("$setIntersection" -> $arr("$u1", "$u2"))))
|
Project($id($doc("$setIntersection" -> $arr("$u1", "$u2"))))
|
||||||
)).map {
|
)).map {
|
||||||
~_.documents.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId
|
~_.firstBatch.headOption.flatMap(_.getAs[Set[String]]("_id")) - userId
|
||||||
}
|
}
|
||||||
|
|
||||||
def fetchFollows(u1: ID, u2: ID) =
|
def fetchFollows(u1: ID, u2: ID) =
|
||||||
|
|
|
@ -16,16 +16,16 @@ private[relation] object RelationRepo {
|
||||||
def blocking(userId: ID) = relating(userId, Block)
|
def blocking(userId: ID) = relating(userId, Block)
|
||||||
|
|
||||||
private def relaters(userId: ID, relation: Relation): Fu[Set[ID]] =
|
private def relaters(userId: ID, relation: Relation): Fu[Set[ID]] =
|
||||||
coll.distinct("u1", $doc(
|
coll.distinct[String, Set]("u1", $doc(
|
||||||
"u2" -> userId,
|
"u2" -> userId,
|
||||||
"r" -> relation
|
"r" -> relation
|
||||||
).some) map lila.db.BSON.asStringSet
|
).some)
|
||||||
|
|
||||||
private def relating(userId: ID, relation: Relation): Fu[Set[ID]] =
|
private def relating(userId: ID, relation: Relation): Fu[Set[ID]] =
|
||||||
coll.distinct("u2", $doc(
|
coll.distinct[String, Set]("u2", $doc(
|
||||||
"u1" -> userId,
|
"u1" -> userId,
|
||||||
"r" -> relation
|
"r" -> relation
|
||||||
).some) map lila.db.BSON.asStringSet
|
).some)
|
||||||
|
|
||||||
def follow(u1: ID, u2: ID): Funit = save(u1, u2, Follow)
|
def follow(u1: ID, u2: ID): Funit = save(u1, u2, Follow)
|
||||||
def unfollow(u1: ID, u2: ID): Funit = remove(u1, u2)
|
def unfollow(u1: ID, u2: ID): Funit = remove(u1, u2)
|
||||||
|
|
|
@ -92,18 +92,18 @@ final class Api(
|
||||||
def userIdsSharingFingerprint = userIdsSharingField("fp") _
|
def userIdsSharingFingerprint = userIdsSharingField("fp") _
|
||||||
|
|
||||||
private def userIdsSharingField(field: String)(userId: String): Fu[List[String]] =
|
private def userIdsSharingField(field: String)(userId: String): Fu[List[String]] =
|
||||||
coll.distinct(
|
coll.distinct[String, List](
|
||||||
field,
|
field,
|
||||||
$doc("user" -> userId, field -> $doc("$exists" -> true)).some
|
$doc("user" -> userId, field -> $doc("$exists" -> true)).some
|
||||||
).flatMap {
|
).flatMap {
|
||||||
case Nil => fuccess(Nil)
|
case Nil => fuccess(Nil)
|
||||||
case values => coll.distinct(
|
case values => coll.distinct[String, List](
|
||||||
"user",
|
"user",
|
||||||
$doc(
|
$doc(
|
||||||
field $in values,
|
field $in values,
|
||||||
"user" $ne userId
|
"user" $ne userId
|
||||||
).some
|
).some
|
||||||
) map lila.db.BSON.asStrings
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def recentUserIdsByFingerprint = recentUserIdsByField("fp") _
|
def recentUserIdsByFingerprint = recentUserIdsByField("fp") _
|
||||||
|
@ -111,13 +111,13 @@ final class Api(
|
||||||
def recentUserIdsByIp = recentUserIdsByField("ip") _
|
def recentUserIdsByIp = recentUserIdsByField("ip") _
|
||||||
|
|
||||||
private def recentUserIdsByField(field: String)(value: String): Fu[List[String]] =
|
private def recentUserIdsByField(field: String)(value: String): Fu[List[String]] =
|
||||||
coll.distinct(
|
coll.distinct[String, List](
|
||||||
"user",
|
"user",
|
||||||
$doc(
|
$doc(
|
||||||
field -> value,
|
field -> value,
|
||||||
"date" $gt DateTime.now.minusYears(1)
|
"date" $gt DateTime.now.minusYears(1)
|
||||||
).some
|
).some
|
||||||
) map lila.db.BSON.asStrings
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Api {
|
object Api {
|
||||||
|
|
|
@ -75,9 +75,7 @@ final class Firewall(
|
||||||
def clear { cache.clear }
|
def clear { cache.clear }
|
||||||
def contains(ip: String) = apply map (_ contains strToIp(ip))
|
def contains(ip: String) = apply map (_ contains strToIp(ip))
|
||||||
def fetch: Fu[Set[IP]] =
|
def fetch: Fu[Set[IP]] =
|
||||||
coll.distinct("_id") map { res =>
|
coll.distinct[String, Set]("_id").map(_.map(strToIp)).addEffect { ips =>
|
||||||
lila.db.BSON.asStringSet(res) map strToIp
|
|
||||||
} addEffect { ips =>
|
|
||||||
lila.mon.security.firewall.ip(ips.size)
|
lila.mon.security.firewall.ip(ips.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,12 +72,12 @@ object UserSpy {
|
||||||
|
|
||||||
private def nextUsers(field: String)(values: Set[Value], user: User)(implicit coll: Coll): Fu[Set[User]] =
|
private def nextUsers(field: String)(values: Set[Value], user: User)(implicit coll: Coll): Fu[Set[User]] =
|
||||||
values.nonEmpty ?? {
|
values.nonEmpty ?? {
|
||||||
coll.distinct("user",
|
coll.distinct[String, Set]("user",
|
||||||
$doc(
|
$doc(
|
||||||
field $in values,
|
field $in values,
|
||||||
"user" $ne user.id
|
"user" $ne user.id
|
||||||
).some
|
).some
|
||||||
) map lila.db.BSON.asStrings flatMap { userIds =>
|
) flatMap { userIds =>
|
||||||
userIds.nonEmpty ?? (UserRepo byIds userIds) map (_.toSet)
|
userIds.nonEmpty ?? (UserRepo byIds userIds) map (_.toSet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package lila.study
|
package lila.study
|
||||||
|
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
import reactivemongo.api.Cursor
|
||||||
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Project, Match }
|
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Project, Match }
|
||||||
import scala.concurrent.duration._
|
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]] =
|
def filterLiked(user: User, studyIds: Seq[Study.ID]): Fu[Set[Study.ID]] =
|
||||||
coll.primitive[Study.ID]($inIds(studyIds) ++ selectLiker(user.id), "_id").map(_.toSet)
|
coll.primitive[Study.ID]($inIds(studyIds) ++ selectLiker(user.id), "_id").map(_.toSet)
|
||||||
|
|
||||||
def resetAllRanks: Fu[Int] = {
|
def resetAllRanks: Fu[Int] = coll.find(
|
||||||
import play.api.libs.iteratee._
|
$empty, $doc("likes" -> true, "createdAt" -> true)
|
||||||
coll.find(
|
).cursor[Bdoc]().foldWhileM(0) { (count, doc) =>
|
||||||
$empty, $doc("likes" -> true, "createdAt" -> true)
|
~(for {
|
||||||
).cursor[Bdoc]().enumerate() |>>>
|
id <- doc.getAs[Study.ID]("_id")
|
||||||
Iteratee.foldM[Bdoc, Int](0) {
|
likes <- doc.getAs[Study.Likes]("likes")
|
||||||
case (count, doc) => ~(for {
|
createdAt <- doc.getAs[DateTime]("createdAt")
|
||||||
id <- doc.getAs[Study.ID]("_id")
|
} yield coll.update(
|
||||||
likes <- doc.getAs[Study.Likes]("likes")
|
$id(id), $set("rank" -> Study.Rank.compute(likes, createdAt))
|
||||||
createdAt <- doc.getAs[DateTime]("createdAt")
|
).void) inject Cursor.Cont(count + 1)
|
||||||
} yield coll.update(
|
|
||||||
$id(id), $set("rank" -> Study.Rank.compute(likes, createdAt))
|
|
||||||
).void) inject (count + 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def doLike(studyId: Study.ID, userId: User.ID, v: Boolean): Funit =
|
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 =>
|
).map { res =>
|
||||||
for {
|
for {
|
||||||
doc <- res.documents.headOption
|
doc <- res.firstBatch.headOption
|
||||||
likes <- doc.getAs[Study.Likes]("likes")
|
likes <- doc.getAs[Study.Likes]("likes")
|
||||||
createdAt <- doc.getAs[DateTime]("createdAt")
|
createdAt <- doc.getAs[DateTime]("createdAt")
|
||||||
} yield likes -> createdAt
|
} yield likes -> createdAt
|
||||||
|
|
|
@ -15,10 +15,10 @@ object MemberRepo {
|
||||||
type ID = String
|
type ID = String
|
||||||
|
|
||||||
def userIdsByTeam(teamId: ID): Fu[Set[ID]] =
|
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]] =
|
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 =
|
def removeByteam(teamId: ID): Funit =
|
||||||
coll.remove(teamQuery(teamId)).void
|
coll.remove(teamQuery(teamId)).void
|
||||||
|
|
|
@ -7,6 +7,7 @@ import lila.hub.actorApi.forum.MakeTeam
|
||||||
import lila.hub.actorApi.timeline.{ Propagate, TeamJoin, TeamCreate }
|
import lila.hub.actorApi.timeline.{ Propagate, TeamJoin, TeamCreate }
|
||||||
import lila.user.{ User, UserRepo, UserContext }
|
import lila.user.{ User, UserRepo, UserContext }
|
||||||
import org.joda.time.Period
|
import org.joda.time.Period
|
||||||
|
import reactivemongo.api.Cursor
|
||||||
|
|
||||||
final class TeamApi(
|
final class TeamApi(
|
||||||
coll: Colls,
|
coll: Colls,
|
||||||
|
@ -162,13 +163,11 @@ final class TeamApi(
|
||||||
|
|
||||||
def nbRequests(teamId: String) = cached nbRequests teamId
|
def nbRequests(teamId: String) = cached nbRequests teamId
|
||||||
|
|
||||||
import play.api.libs.iteratee._
|
|
||||||
def recomputeNbMembers =
|
def recomputeNbMembers =
|
||||||
coll.team.find($empty).cursor[Team]()
|
coll.team.find($empty).cursor[Team]().foldWhileM({}) { (_, team) =>
|
||||||
.enumerate(Int.MaxValue, stopOnError = true) |>>>
|
for {
|
||||||
Iteratee.foldM[Team, Unit](()) {
|
nb <- MemberRepo.countByTeam(team.id)
|
||||||
case (_, team) => MemberRepo.countByTeam(team.id) flatMap { nb =>
|
_ <- coll.team.updateField($id(team.id), "nbMembers", nb)
|
||||||
coll.team.updateField($id(team.id), "nbMembers", nb).void
|
} yield Cursor.Cont({})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ object TeamRepo {
|
||||||
coll.uno[Team]($id(id) ++ $doc("createdBy" -> createdBy))
|
coll.uno[Team]($id(id) ++ $doc("createdBy" -> createdBy))
|
||||||
|
|
||||||
def teamIdsByCreator(userId: String): Fu[List[String]] =
|
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]] =
|
def name(id: String): Fu[Option[String]] =
|
||||||
coll.primitiveOne[String]($id(id), "name")
|
coll.primitiveOne[String]($id(id), "name")
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package lila.teamSearch
|
package lila.teamSearch
|
||||||
|
|
||||||
|
import reactivemongo.api.Cursor
|
||||||
|
|
||||||
import lila.search._
|
import lila.search._
|
||||||
import lila.team.actorApi._
|
import lila.team.actorApi._
|
||||||
import lila.team.{ Team, TeamRepo }
|
import lila.team.{ Team, TeamRepo }
|
||||||
|
|
||||||
import play.api.libs.json._
|
import play.api.libs.json._
|
||||||
import play.api.libs.iteratee._
|
|
||||||
|
|
||||||
final class TeamSearchApi(client: ESClient) extends SearchReadApi[Team, Query] {
|
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 >> {
|
case c: ESClientHttp => c.putMapping >> {
|
||||||
lila.log("teamSearch").info(s"Index to ${c.index.name}")
|
lila.log("teamSearch").info(s"Index to ${c.index.name}")
|
||||||
import lila.db.dsl._
|
import lila.db.dsl._
|
||||||
TeamRepo.cursor($doc("enabled" -> true))
|
|
||||||
.enumerateBulks(Int.MaxValue) |>>>
|
TeamRepo.cursor($doc("enabled" -> true)).foldBulksM({}) { (_, teams) =>
|
||||||
Iteratee.foldM[Iterator[Team], Unit](()) {
|
c.storeBulk(teams.toList map (t => Id(t.id) -> toDoc(t))).
|
||||||
case (_, teams) =>
|
map(Cursor.Cont(_))
|
||||||
c.storeBulk(teams.toList map (t => Id(t.id) -> toDoc(t)))
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ => funit
|
case _ => funit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ private[timeline] final class UnsubApi(coll: Coll) {
|
||||||
coll.count(select(channel, userId).some) map (0 !=)
|
coll.count(select(channel, userId).some) map (0 !=)
|
||||||
|
|
||||||
def filterUnsub(channel: String, userIds: List[String]): Fu[List[String]] =
|
def filterUnsub(channel: String, userIds: List[String]): Fu[List[String]] =
|
||||||
coll.distinct("_id", $inIds(userIds.map { makeId(channel, _) }).some) map
|
coll.distinct[String, List](
|
||||||
lila.db.BSON.asStrings map { unsubs =>
|
"_id", $inIds(userIds.map { makeId(channel, _) }).some) map { unsubs =>
|
||||||
userIds diff unsubs.map(_ takeWhile ('@' !=))
|
userIds diff unsubs.map(_ takeWhile ('@' !=))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ final class LeaderboardApi(
|
||||||
Match($doc("u" -> user.id)),
|
Match($doc("u" -> user.id)),
|
||||||
List(GroupField("v")("nb" -> SumValue(1), "points" -> Push("s"), "ratios" -> Push("w")))
|
List(GroupField("v")("nb" -> SumValue(1), "points" -> Push("s"), "ratios" -> Push("w")))
|
||||||
).map {
|
).map {
|
||||||
_.documents map leaderboardAggregationResultBSONHandler.read
|
_.firstBatch map leaderboardAggregationResultBSONHandler.read
|
||||||
}.map { aggs =>
|
}.map { aggs =>
|
||||||
ChartData {
|
ChartData {
|
||||||
aggs.flatMap { agg =>
|
aggs.flatMap { agg =>
|
||||||
|
|
|
@ -32,8 +32,8 @@ object PairingRepo {
|
||||||
coll.find(
|
coll.find(
|
||||||
selectTour(tourId) ++ $doc("u" $in userIds),
|
selectTour(tourId) ++ $doc("u" $in userIds),
|
||||||
$doc("_id" -> false, "u" -> true)
|
$doc("_id" -> false, "u" -> true)
|
||||||
).sort(recentSort).cursor[Bdoc]().enumerate(nb) |>>>
|
).sort(recentSort).cursor[Bdoc]().fold(
|
||||||
Iteratee.fold(scala.collection.immutable.Map.empty[String, String]) { (acc, doc) =>
|
scala.collection.immutable.Map.empty[String, String], nb) { (acc, doc) =>
|
||||||
~doc.getAs[List[String]]("u") match {
|
~doc.getAs[List[String]]("u") match {
|
||||||
case List(u1, u2) =>
|
case List(u1, u2) =>
|
||||||
val acc1 = acc.contains(u1).fold(acc, acc.updated(u1, u2))
|
val acc1 = acc.contains(u1).fold(acc, acc.updated(u1, u2))
|
||||||
|
@ -81,7 +81,7 @@ object PairingRepo {
|
||||||
Unwind("u"),
|
Unwind("u"),
|
||||||
GroupField("u")("nb" -> SumValue(1))
|
GroupField("u")("nb" -> SumValue(1))
|
||||||
)).map {
|
)).map {
|
||||||
_.documents.flatMap { doc =>
|
_.firstBatch.flatMap { doc =>
|
||||||
doc.getAs[String]("_id") flatMap { uid =>
|
doc.getAs[String]("_id") flatMap { uid =>
|
||||||
doc.getAs[Int]("nb") map { uid -> _ }
|
doc.getAs[Int]("nb") map { uid -> _ }
|
||||||
}
|
}
|
||||||
|
@ -132,12 +132,12 @@ object PairingRepo {
|
||||||
Project($doc(
|
Project($doc(
|
||||||
"u" -> BSONBoolean(true), "_id" -> BSONBoolean(false))),
|
"u" -> BSONBoolean(true), "_id" -> BSONBoolean(false))),
|
||||||
Unwind("u"), Group(BSONBoolean(true))("ids" -> AddToSet("u")))).map(
|
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]))
|
getOrElse(Set.empty[String]))
|
||||||
|
|
||||||
def playingGameIds(tourId: String): Fu[List[String]] =
|
def playingGameIds(tourId: String): Fu[List[String]] =
|
||||||
coll.aggregate(Match(selectTour(tourId) ++ selectPlaying), List(
|
coll.aggregate(Match(selectTour(tourId) ++ selectPlaying), List(
|
||||||
Group(BSONBoolean(true))("ids" -> Push("_id")))).map(
|
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]))
|
getOrElse(List.empty[String]))
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,10 +102,11 @@ object PlayerRepo {
|
||||||
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Descending, Group, Match, Push, Sort }
|
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Descending, Group, Match, Push, Sort }
|
||||||
|
|
||||||
def userIds(tourId: String): Fu[List[String]] =
|
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]] =
|
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]] =
|
def winner(tourId: String): Fu[Option[Player]] =
|
||||||
coll.find(selectTour(tourId)).sort(bestSort).uno[Player]
|
coll.find(selectTour(tourId)).sort(bestSort).uno[Player]
|
||||||
|
@ -114,7 +115,7 @@ object PlayerRepo {
|
||||||
private[tournament] def computeRanking(tourId: String): Fu[Ranking] =
|
private[tournament] def computeRanking(tourId: String): Fu[Ranking] =
|
||||||
coll.aggregate(Match(selectTour(tourId)), List(Sort(Descending("m")),
|
coll.aggregate(Match(selectTour(tourId)), List(Sort(Descending("m")),
|
||||||
Group(BSONNull)("uids" -> Push("uid")))) map {
|
Group(BSONNull)("uids" -> Push("uid")))) map {
|
||||||
_.documents.headOption.fold(Map.empty: Ranking) {
|
_.firstBatch.headOption.fold(Map.empty: Ranking) {
|
||||||
_ get "uids" match {
|
_ get "uids" match {
|
||||||
case Some(BSONArray(uids)) =>
|
case Some(BSONArray(uids)) =>
|
||||||
// mutable optimized implementation
|
// mutable optimized implementation
|
||||||
|
|
|
@ -2,6 +2,7 @@ package lila.user
|
||||||
|
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import play.api.libs.iteratee._
|
import play.api.libs.iteratee._
|
||||||
|
import reactivemongo.api.Cursor
|
||||||
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Match, Project, Group, GroupField, SumField, SumValue }
|
import reactivemongo.api.collections.bson.BSONBatchCommands.AggregationFramework.{ Match, Project, Group, GroupField, SumField, SumValue }
|
||||||
import reactivemongo.bson._
|
import reactivemongo.bson._
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
@ -77,21 +78,18 @@ final class RankingApi(
|
||||||
f = compute,
|
f = compute,
|
||||||
timeToLive = 15 minutes)
|
timeToLive = 15 minutes)
|
||||||
|
|
||||||
private def compute(perfId: Perf.ID): Fu[Map[User.ID, Rank]] = {
|
private def compute(perfId: Perf.ID): Fu[Map[User.ID, Rank]] =
|
||||||
val enumerator = coll.find(
|
coll.find(
|
||||||
$doc("perf" -> perfId, "stable" -> true),
|
$doc("perf" -> perfId, "stable" -> true),
|
||||||
$doc("user" -> true, "_id" -> false)
|
$doc("user" -> true, "_id" -> false)
|
||||||
).sort($doc("rating" -> -1)).cursor[Bdoc]().enumerate()
|
).sort($doc("rating" -> -1)).cursor[Bdoc]().
|
||||||
var rank = 1
|
fold(1 -> Map.newBuilder[User.ID, Rank]) {
|
||||||
val b = Map.newBuilder[User.ID, Rank]
|
case (state @ (rank, b), doc) =>
|
||||||
val mapBuilder: Iteratee[Bdoc, Unit] = Iteratee.foreach { doc =>
|
doc.getAs[User.ID]("user").fold(state) { user =>
|
||||||
doc.getAs[User.ID]("user") foreach { user =>
|
b += (user -> rank)
|
||||||
b += (user -> rank)
|
(rank + 1) -> b
|
||||||
rank = rank + 1
|
}
|
||||||
}
|
}.map(_._2.result())
|
||||||
}
|
|
||||||
enumerator.run(mapBuilder) inject b.result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object weeklyRatingDistribution {
|
object weeklyRatingDistribution {
|
||||||
|
@ -122,7 +120,7 @@ final class RankingApi(
|
||||||
)),
|
)),
|
||||||
GroupField("r")("nb" -> SumValue(1))
|
GroupField("r")("nb" -> SumValue(1))
|
||||||
)).map { res =>
|
)).map { res =>
|
||||||
val hash = res.documents.flatMap { obj =>
|
val hash = res.firstBatch.flatMap { obj =>
|
||||||
for {
|
for {
|
||||||
rating <- obj.getAs[Int]("_id")
|
rating <- obj.getAs[Int]("_id")
|
||||||
nb <- obj.getAs[NbUsers]("nb")
|
nb <- obj.getAs[NbUsers]("nb")
|
||||||
|
|
|
@ -81,7 +81,7 @@ object UserRepo {
|
||||||
coll.primitiveOne[String]($id(id), F.username)
|
coll.primitiveOne[String]($id(id), F.username)
|
||||||
|
|
||||||
def usernamesByIds(ids: List[ID]) =
|
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)]] = {
|
def orderByGameCount(u1: String, u2: String): Fu[Option[(String, String)]] = {
|
||||||
coll.find(
|
coll.find(
|
||||||
|
@ -242,7 +242,7 @@ object UserRepo {
|
||||||
coll.primitive[String]($inIds(usernames.map(normalize)), "_id")
|
coll.primitive[String]($inIds(usernames.map(normalize)), "_id")
|
||||||
|
|
||||||
def engineIds: Fu[Set[String]] =
|
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
|
private val userIdPattern = """^[\w-]{3,20}$""".r.pattern
|
||||||
|
|
||||||
|
@ -339,7 +339,7 @@ object UserRepo {
|
||||||
def idsSumToints(ids: Iterable[String]): Fu[Int] =
|
def idsSumToints(ids: Iterable[String]): Fu[Int] =
|
||||||
ids.nonEmpty ?? coll.aggregate(Match($inIds(ids)),
|
ids.nonEmpty ?? coll.aggregate(Match($inIds(ids)),
|
||||||
List(Group(BSONNull)(F.toints -> SumField(F.toints)))).map(
|
List(Group(BSONNull)(F.toints -> SumField(F.toints)))).map(
|
||||||
_.documents.headOption flatMap { _.getAs[Int](F.toints) }
|
_.firstBatch.headOption flatMap { _.getAs[Int](F.toints) }
|
||||||
).map(~_)
|
).map(~_)
|
||||||
|
|
||||||
def filterByEngine(userIds: List[String]): Fu[List[String]] =
|
def filterByEngine(userIds: List[String]): Fu[List[String]] =
|
||||||
|
|
|
@ -76,7 +76,7 @@ private[video] final class VideoApi(
|
||||||
).void
|
).void
|
||||||
|
|
||||||
def allIds: Fu[List[Video.ID]] =
|
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(
|
def popular(user: Option[User], page: Int): Fu[Paginator[VideoView]] = Paginator(
|
||||||
adapter = new Adapter[Video](
|
adapter = new Adapter[Video](
|
||||||
|
@ -149,10 +149,10 @@ private[video] final class VideoApi(
|
||||||
).some) map (0!=)
|
).some) map (0!=)
|
||||||
|
|
||||||
def seenVideoIds(user: User, videos: Seq[Video]): Fu[Set[Video.ID]] =
|
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 =>
|
$inIds(videos.map { v =>
|
||||||
View.makeId(v.id, user.id)
|
View.makeId(v.id, user.id)
|
||||||
}).some) map lila.db.BSON.asStringSet
|
}).some)
|
||||||
}
|
}
|
||||||
|
|
||||||
object tag {
|
object tag {
|
||||||
|
@ -177,7 +177,7 @@ private[video] final class VideoApi(
|
||||||
Match($doc("tags" $all filterTags)),
|
Match($doc("tags" $all filterTags)),
|
||||||
List(Project($doc("tags" -> true)),
|
List(Project($doc("tags" -> true)),
|
||||||
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)))).map(
|
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)))).map(
|
||||||
_.documents.flatMap(_.asOpt[TagNb]))
|
_.firstBatch.flatMap(_.asOpt[TagNb]))
|
||||||
|
|
||||||
allPopular zip allPaths map {
|
allPopular zip allPaths map {
|
||||||
case (all, paths) =>
|
case (all, paths) =>
|
||||||
|
@ -203,7 +203,7 @@ private[video] final class VideoApi(
|
||||||
Project($doc("tags" -> true)), List(
|
Project($doc("tags" -> true)), List(
|
||||||
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)),
|
Unwind("tags"), GroupField("tags")("nb" -> SumValue(1)),
|
||||||
Sort(Descending("nb")))).map(
|
Sort(Descending("nb")))).map(
|
||||||
_.documents.flatMap(_.asOpt[TagNb])),
|
_.firstBatch.flatMap(_.asOpt[TagNb])),
|
||||||
timeToLive = 1.day)
|
timeToLive = 1.day)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ object Dependencies {
|
||||||
val hasher = "com.roundeights" %% "hasher" % "1.2.0"
|
val hasher = "com.roundeights" %% "hasher" % "1.2.0"
|
||||||
val jgit = "org.eclipse.jgit" % "org.eclipse.jgit" % "3.2.0.201312181205-r"
|
val jgit = "org.eclipse.jgit" % "org.eclipse.jgit" % "3.2.0.201312181205-r"
|
||||||
val jodaTime = "joda-time" % "joda-time" % "2.9.2"
|
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 maxmind = "com.sanoma.cda" %% "maxmind-geoip2-scala" % "1.2.3-THIB"
|
||||||
val prismic = "io.prismic" %% "scala-kit" % "1.2.11-THIB"
|
val prismic = "io.prismic" %% "scala-kit" % "1.2.11-THIB"
|
||||||
val java8compat = "org.scala-lang.modules" %% "scala-java8-compat" % "0.7.0"
|
val java8compat = "org.scala-lang.modules" %% "scala-java8-compat" % "0.7.0"
|
||||||
|
|
Loading…
Reference in a new issue