make many DB accesses more type safe

pull/2055/merge
Thibault Duplessis 2016-07-18 12:10:45 +02:00
parent 139b82ffcf
commit a3fa8681b7
24 changed files with 64 additions and 73 deletions

View File

@ -27,7 +27,7 @@ private[bookmark] object BookmarkRepo {
coll.remove($doc("g" -> gameId)).void
def removeByGameIds(gameIds: List[String]): Funit =
coll.remove($doc("g" -> $in(gameIds: _*))).void
coll.remove($doc("g" $in gameIds)).void
private def add(gameId: String, userId: String, date: DateTime): Funit =
coll.insert($doc(

View File

@ -286,7 +286,7 @@ trait dsl {
}
/** Matches any of the values that exist in an array specified in the query.*/
def $in[T](values: T*)(implicit writer: BSONWriter[T, _ <: BSONValue]): SimpleExpression[BSONDocument] = {
def $in[T](values: Iterable[T])(implicit writer: BSONWriter[T, _ <: BSONValue]): SimpleExpression[BSONDocument] = {
SimpleExpression(field, $doc("$in" -> values))
}
@ -306,7 +306,7 @@ trait dsl {
}
/** Matches values that do not exist in an array specified to the query. */
def $nin[T](values: T*)(implicit writer: BSONWriter[T, _ <: BSONValue]): SimpleExpression[BSONDocument] = {
def $nin[T](values: Iterable[T])(implicit writer: BSONWriter[T, _ <: BSONValue]): SimpleExpression[BSONDocument] = {
SimpleExpression(field, $doc("$nin" -> values))
}

View File

@ -14,8 +14,8 @@ object CategRepo {
def withTeams(teams: Set[String]): Fu[List[Categ]] =
coll.find($or(
"team" $exists false,
$doc("team" -> $doc("$in" -> teams))
)).sort($sort asc "pos").cursor[Categ]().gather[List]()
$doc("team" $in teams))
).sort($sort asc "pos").cursor[Categ]().gather[List]()
def nextPosition: Fu[Int] =
coll.primitiveOne[Int]($empty, $sort desc "pos", "pos") map (~_ + 1)

View File

@ -48,16 +48,16 @@ sealed abstract class PostRepo(troll: Boolean) {
multi = true).void
def selectTopic(topicId: String) = $doc("topicId" -> topicId) ++ trollFilter
def selectTopics(topicIds: List[String]) = $doc("topicId" $in (topicIds: _*)) ++ trollFilter
def selectTopics(topicIds: List[String]) = $doc("topicId" $in topicIds) ++ trollFilter
def selectCateg(categId: String) = $doc("categId" -> categId) ++ trollFilter
def selectCategs(categIds: List[String]) = $doc("categId" $in (categIds: _*)) ++ trollFilter
def selectCategs(categIds: List[String]) = $doc("categId" $in categIds) ++ trollFilter
val selectNotHidden = $doc("hidden" -> false)
def selectLangs(langs: List[String]) =
if (langs.isEmpty) $empty
else $doc("lang" $in (langs: _*))
else $doc("lang" $in langs)
def findDuplicate(post: Post): Fu[Option[Post]] = coll.uno[Post]($doc(
"createdAt" $gt DateTime.now.minusHours(1),

View File

@ -187,12 +187,11 @@ object GameRepo {
coll.exists($id(id) ++ Query.analysed(true))
def filterAnalysed(ids: Seq[String]): Fu[Set[String]] =
coll.distinct("_id", $doc(
"_id" -> $doc("$in" -> ids),
coll.distinct("_id", ($inIds(ids) ++ $doc(
F.analysed -> true
).some) map lila.db.BSON.asStringSet
)).some) map lila.db.BSON.asStringSet
def exists(id: String) = coll.exists($doc("_id" -> id))
def exists(id: String) = coll.exists($id(id))
def incBookmarks(id: ID, value: Int) =
coll.update($id(id), $inc(F.bookmarks -> value)).void
@ -357,10 +356,10 @@ object GameRepo {
def findMirror(game: Game): Fu[Option[Game]] = coll.uno[Game]($doc(
F.id -> $doc("$ne" -> game.id),
F.playerUids -> $doc("$in" -> game.userIds),
F.playerUids $in game.userIds,
F.status -> Status.Started.id,
F.createdAt -> $doc("$gt" -> (DateTime.now minusMinutes 15)),
F.updatedAt -> $doc("$gt" -> (DateTime.now minusMinutes 5)),
F.createdAt $gt (DateTime.now minusMinutes 15),
F.updatedAt $gt (DateTime.now minusMinutes 5),
"$or" -> $arr(
$doc(s"${F.whitePlayer}.ai" -> $doc("$exists" -> true)),
$doc(s"${F.blackPlayer}.ai" -> $doc("$exists" -> true))

View File

@ -28,7 +28,7 @@ object Query {
val mate: Bdoc = status(Status.Mate)
val draw: Bdoc = F.status $in (Status.Draw.id, Status.Stalemate.id)
val draw: Bdoc = F.status $in List(Status.Draw.id, Status.Stalemate.id)
def draw(u: String): Bdoc = user(u) ++ draw
@ -50,7 +50,7 @@ object Query {
def user(u: String): Bdoc = F.playerUids $eq u
def user(u: User): Bdoc = F.playerUids $eq u.id
def users(u: Seq[String]) = F.playerUids $in (u: _*)
def users(u: Seq[String]) = F.playerUids $in u
val noAi: Bdoc = $doc(
"p0.ai" $exists false,
@ -65,7 +65,7 @@ object Query {
def win(u: String) = user(u) ++ $doc(F.winnerId -> u)
def loss(u: String) = user(u) ++ $doc(
F.status $in (Status.finishedWithWinner.map(_.id): _*),
F.status $in Status.finishedWithWinner.map(_.id),
F.winnerId -> $exists(true).++($ne(u))
)

View File

@ -145,7 +145,7 @@ object Dimension {
def filtersOf[X](d: Dimension[X], selected: List[X]): Bdoc = d match {
case Dimension.MovetimeRange => selected match {
case Nil => $empty
case xs => $doc(d.dbKey -> $doc("$in" -> xs.flatMap(_.tenths.list)))
case xs => $doc(d.dbKey $in xs.flatMap(_.tenths.list))
}
case _ => selected map d.bson.write match {
case Nil => $empty

View File

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

View File

@ -60,7 +60,7 @@ final class QaApi(
questionColl.find($doc("_id" -> id)).uno[Question]
def findByIds(ids: List[QuestionId]): Fu[List[Question]] =
questionColl.find($doc("_id" -> $doc("$in" -> ids.distinct))).cursor[Question]().gather[List]()
questionColl.find($inIds(ids.distinct)).cursor[Question]().gather[List]()
def accept(q: Question) = questionColl.update(
$doc("_id" -> q.id),
@ -99,7 +99,7 @@ final class QaApi(
.cursor[Question]().gather[List](max)
def byTags(tags: List[String], max: Int): Fu[List[Question]] =
questionColl.find($doc("tags" -> $doc("$in" -> tags.map(_.toLowerCase)))).cursor[Question]().gather[List](max)
questionColl.find($doc("tags" $in tags.map(_.toLowerCase))).cursor[Question]().gather[List](max)
def addComment(c: Comment)(q: Question) = questionColl.update(
$doc("_id" -> q.id),
@ -117,7 +117,7 @@ final class QaApi(
}
def incViews(q: Question) = questionColl.update(
$doc("_id" -> q.id),
$id(q.id),
$doc("$inc" -> $doc("views" -> BSONInteger(1))))
def recountAnswers(id: QuestionId) = answer.countByQuestionId(id) flatMap {

View File

@ -115,7 +115,7 @@ private[report] final class ReportApi(coll: Coll) {
def processEngine(userId: String, byModId: String): Funit = coll.update(
$doc(
"user" -> userId,
"reason" -> $in(Reason.Cheat.name, Reason.CheatPrint.name)
"reason" $in List(Reason.Cheat.name, Reason.CheatPrint.name)
) ++ unprocessedSelect,
$set("processedBy" -> byModId),
multi = true).void >>- monitorUnprocessed
@ -123,7 +123,7 @@ private[report] final class ReportApi(coll: Coll) {
def processTroll(userId: String, byModId: String): Funit = coll.update(
$doc(
"user" -> userId,
"reason" -> $in(Reason.Insult.name, Reason.Troll.name, Reason.Other.name)
"reason" $in List(Reason.Insult.name, Reason.Troll.name, Reason.Other.name)
) ++ unprocessedSelect,
$set("processedBy" -> byModId),
multi = true).void >>- monitorUnprocessed

View File

@ -28,7 +28,7 @@ final class ForecastApi(coll: Coll, roundMap: akka.actor.ActorSelection) {
private def saveSteps(pov: Pov, steps: Forecast.Steps): Funit = {
lila.mon.round.forecast.create()
coll.update(
$doc("_id" -> pov.fullId),
$id(pov.fullId),
Forecast(
_id = pov.fullId,
steps = steps,
@ -37,7 +37,7 @@ final class ForecastApi(coll: Coll, roundMap: akka.actor.ActorSelection) {
}
def save(pov: Pov, steps: Forecast.Steps): Funit = firstStep(steps) match {
case None => coll.remove($doc("_id" -> pov.fullId)).void
case None => coll.remove($id(pov.fullId)).void
case Some(step) if pov.game.turns == step.ply - 1 => saveSteps(pov, steps)
case _ => fufail(Forecast.OutOfSync)
}
@ -59,7 +59,7 @@ final class ForecastApi(coll: Coll, roundMap: akka.actor.ActorSelection) {
}
def loadForDisplay(pov: Pov): Fu[Option[Forecast]] =
pov.forecastable ?? coll.find($doc("_id" -> pov.fullId)).uno[Forecast] flatMap {
pov.forecastable ?? coll.find($id(pov.fullId)).uno[Forecast] flatMap {
case None => fuccess(none)
case Some(fc) =>
if (firstStep(fc.steps).exists(_.ply != pov.game.turns + 1)) clearPov(pov) inject none
@ -67,7 +67,7 @@ final class ForecastApi(coll: Coll, roundMap: akka.actor.ActorSelection) {
}
def loadForPlay(pov: Pov): Fu[Option[Forecast]] =
pov.game.forecastable ?? coll.find($doc("_id" -> pov.fullId)).uno[Forecast] flatMap {
pov.game.forecastable ?? coll.find($id(pov.fullId)).uno[Forecast] flatMap {
case None => fuccess(none)
case Some(fc) =>
if (firstStep(fc.steps).exists(_.ply != pov.game.turns)) clearPov(pov) inject none
@ -79,7 +79,7 @@ final class ForecastApi(coll: Coll, roundMap: akka.actor.ActorSelection) {
case None => fuccess(none)
case Some(fc) => fc(g, last) match {
case Some((newFc, uciMove)) if newFc.steps.nonEmpty =>
coll.update($doc("_id" -> fc._id), newFc) inject uciMove.some
coll.update($id(fc._id), newFc) inject uciMove.some
case Some((newFc, uciMove)) => clearPov(Pov player g) inject uciMove.some
case _ => clearPov(Pov player g) inject none
}
@ -88,9 +88,7 @@ final class ForecastApi(coll: Coll, roundMap: akka.actor.ActorSelection) {
private def firstStep(steps: Forecast.Steps) = steps.headOption.flatMap(_.headOption)
def clearGame(g: Game) = coll.remove($doc(
"_id" -> $doc("$in" -> chess.Color.all.map(g.fullIdOf))
)).void
def clearGame(g: Game) = coll.remove($inIds(chess.Color.all.map(g.fullIdOf))).void
def clearPov(pov: Pov) = coll.remove($doc("_id" -> pov.fullId)).void
def clearPov(pov: Pov) = coll.remove($id(pov.fullId)).void
}

View File

@ -10,7 +10,7 @@ final class NoteApi(coll: Coll) {
coll.primitiveOne[String]($id(makeId(gameId, userId)), "t") map (~_)
def set(gameId: String, userId: String, text: String) = {
if (text.isEmpty) coll.remove(BSONDocument("_id" -> makeId(gameId, userId)))
if (text.isEmpty) coll.remove($id(makeId(gameId, userId)))
else coll.update(
$id(makeId(gameId, userId)),
$set("t" -> text),

View File

@ -100,8 +100,8 @@ final class Api(
case values => coll.distinct(
"user",
$doc(
field -> $doc("$in" -> values),
"user" -> $doc("$ne" -> userId)
field $in values,
"user" $ne userId
).some
) map lila.db.BSON.asStrings
}

View File

@ -74,8 +74,8 @@ object UserSpy {
values.nonEmpty ?? {
coll.distinct("user",
$doc(
field -> $doc("$in" -> values),
"user" -> $doc("$ne" -> user.id)
field $in values,
"user" $ne user.id
).some
) map lila.db.BSON.asStrings flatMap { userIds =>
userIds.nonEmpty ?? (UserRepo byIds userIds) map (_.toSet)

View File

@ -56,7 +56,7 @@ final class ChapterRepo(coll: Coll) {
def namesByStudyIds(studyIds: Seq[Study.ID]): Fu[Map[Study.ID, Vector[String]]] =
coll.find(
$doc("studyId" -> $doc("$in" -> studyIds)),
$doc("studyId" $in studyIds),
$doc("studyId" -> true, "name" -> true)
).sort($sort asc "order").list[Bdoc]().map { docs =>
docs.foldLeft(Map.empty[Study.ID, Vector[String]]) {

View File

@ -33,5 +33,5 @@ object RequestRepo {
def selectId(teamId: ID, userId: ID) = $id(Request.makeId(teamId, userId))
def teamQuery(teamId: ID) = $doc("team" -> teamId)
def teamsQuery(teamIds: List[ID]) = $doc("team".$in(teamIds:_*))
def teamsQuery(teamIds: List[ID]) = $doc("team" $in teamIds)
}

View File

@ -21,9 +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", $doc(
"_id" $in (userIds.map { makeId(channel, _) }: _*)
).some) map lila.db.BSON.asStrings map { unsubs =>
userIds diff unsubs.map(_ takeWhile ('@' !=))
}
coll.distinct("_id", $inIds(userIds.map { makeId(channel, _) }).some) map
lila.db.BSON.asStrings map { unsubs =>
userIds diff unsubs.map(_ takeWhile ('@' !=))
}
}

View File

@ -30,7 +30,7 @@ object PairingRepo {
def lastOpponents(tourId: String, userIds: Iterable[String], nb: Int): Fu[Pairing.LastOpponents] =
coll.find(
selectTour(tourId) ++ $doc("u" -> $doc("$in" -> userIds)),
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) =>

View File

@ -131,7 +131,7 @@ object PlayerRepo {
}
def byTourAndUserIds(tourId: String, userIds: Iterable[String]): Fu[List[Player]] =
coll.find(selectTour(tourId) ++ $doc("uid" -> $doc("$in" -> userIds)))
coll.find(selectTour(tourId) ++ $doc("uid" $in userIds))
.list[Player]()
.chronometer.logIfSlow(200, logger) { players =>
s"PlayerRepo.byTourAndUserIds $tourId ${userIds.size} user IDs, ${players.size} players"

View File

@ -13,10 +13,8 @@ object TournamentRepo {
private lazy val coll = Env.current.tournamentColl
private def $id(id: String) = $doc("_id" -> id)
private val enterableSelect = $doc(
"status" $in (Status.Created.id, Status.Started.id))
"status" $in List(Status.Created.id, Status.Started.id))
private val createdSelect = $doc("status" -> Status.Created.id)
private val startedSelect = $doc("status" -> Status.Started.id)
@ -203,7 +201,7 @@ object TournamentRepo {
def lastFinishedScheduledByFreq(freq: Schedule.Freq, since: DateTime): Fu[List[Tournament]] = coll.find(
finishedSelect ++ sinceSelect(since) ++ variantSelect(chess.variant.Standard) ++ $doc(
"schedule.freq" -> freq.name,
"schedule.speed".$in(Schedule.Speed.mostPopular.map(_.name): _*)
"schedule.speed" $in Schedule.Speed.mostPopular.map(_.name)
)
).sort($doc("startsAt" -> -1))
.list[Tournament](Schedule.Speed.mostPopular.size.some)
@ -213,18 +211,18 @@ object TournamentRepo {
$doc("schedule.freq" -> Schedule.Freq.Daily.name)
).sort($doc("startsAt" -> -1)).uno[Tournament]
def update(tour: Tournament) = coll.update($doc("_id" -> tour.id), tour)
def update(tour: Tournament) = coll.update($id(tour.id), tour)
def insert(tour: Tournament) = coll.insert(tour)
def remove(tour: Tournament) = coll.remove($doc("_id" -> tour.id))
def remove(tour: Tournament) = coll.remove($id(tour.id))
def exists(id: String) = coll.count($doc("_id" -> id).some) map (0 !=)
def exists(id: String) = coll.exists($id(id))
def toursToWithdrawWhenEntering(tourId: String): Fu[List[Tournament]] =
coll.find(enterableSelect ++ $doc(
"_id" -> $doc("$ne" -> tourId),
"schedule.freq" $nin (
"_id" $ne tourId,
"schedule.freq" $nin List(
Schedule.Freq.Marathon.name,
Schedule.Freq.Unique.name
)

View File

@ -23,8 +23,8 @@ final class NoteApi(
coll.find(
$doc(
"to" -> user.id,
"from" -> $doc("$in" -> (myFriendIds + me.id))
) ++ me.troll.fold($doc(), $doc("troll" -> false))
"from" $in (myFriendIds + me.id)
) ++ me.troll.fold($empty, $doc("troll" -> false))
).sort($doc("date" -> -1)).cursor[Note]().gather[List](100)
def write(to: User, text: String, from: User) = {

View File

@ -36,10 +36,10 @@ final class RankingApi(
def remove(userId: User.ID): Funit = UserRepo byId userId flatMap {
_ ?? { user =>
coll.remove($doc(
"_id" -> $doc("$in" -> PerfType.leaderboardable.filter { pt =>
coll.remove($inIds(
PerfType.leaderboardable.filter { pt =>
user.perfs(pt).nonEmpty
}.map { makeId(user.id, _) })
}.map { makeId(user.id, _) }
)).void
}
}

View File

@ -85,7 +85,7 @@ object UserRepo {
def orderByGameCount(u1: String, u2: String): Fu[Option[(String, String)]] = {
coll.find(
$doc("_id".$in(u1, u2)),
$inIds(List(u1, u2)),
$doc(s"${F.count}.game" -> true)
).cursor[Bdoc]().gather[List]() map { docs =>
docs.sortBy {
@ -100,7 +100,7 @@ object UserRepo {
def firstGetsWhite(u1O: Option[String], u2O: Option[String]): Fu[Boolean] =
(u1O |@| u2O).tupled.fold(fuccess(scala.util.Random.nextBoolean)) {
case (u1, u2) => coll.find(
$doc("_id".$in(u1, u2)),
$inIds(List(u1, u2)),
$id(true)
).sort($doc(F.colorIt -> 1)).uno[Bdoc].map {
_.fold(scala.util.Random.nextBoolean) { doc =>

View File

@ -41,7 +41,7 @@ private[video] final class VideoApi(
private val maxPerPage = 18
def find(id: Video.ID): Fu[Option[Video]] =
videoColl.find($doc("_id" -> id)).uno[Video]
videoColl.find($id(id)).uno[Video]
def search(user: Option[User], query: String, page: Int): Fu[Paginator[VideoView]] = {
val q = query.split(' ').map { word => s""""$word"""" } mkString " "
@ -61,18 +61,16 @@ private[video] final class VideoApi(
def save(video: Video): Funit =
videoColl.update(
$doc("_id" -> video.id),
$id(video.id),
$doc("$set" -> video),
upsert = true).void
def removeNotIn(ids: List[Video.ID]) =
videoColl.remove(
$doc("_id" $nin (ids: _*))
).void
videoColl.remove($doc("_id" $nin ids)).void
def setMetadata(id: Video.ID, metadata: Youtube.Metadata) =
videoColl.update(
$doc("_id" -> id),
$id(id),
$doc("$set" -> $doc("metadata" -> metadata)),
upsert = false
).void
@ -115,7 +113,7 @@ private[video] final class VideoApi(
def similar(user: Option[User], video: Video, max: Int): Fu[Seq[VideoView]] =
videoColl.find($doc(
"tags" $in (video.tags: _*),
"tags" $in video.tags,
"_id" $ne video.id
)).sort($doc("metadata.likes" -> -1))
.cursor[Video]()