<commit_before>package lila.history

import scala.concurrent.duration._

import play.api.libs.json._

import lila.rating.PerfType
import lila.user.User

final class RatingChartApi(
    historyApi: HistoryApi,
    mongoCache: lila.memo.MongoCache.Api
)(implicit ec: scala.concurrent.ExecutionContext) {

  def apply(user: User): Fu[Option[String]] =
    cache.get(user) dmap { chart =>
      chart.nonEmpty option chart
    }

  def singlePerf(user: User, perfType: PerfType): Fu[JsArray] =
    historyApi.ratingsMap(user, perfType) map {
      ratingsMapToJson(user, _)
    } map JsArray.apply

  private val cache = mongoCache[User, String](
    1024,
    "history:rating",
    60 minutes,
    _.id
  ) { loader =>
    _.expireAfterAccess(10 minutes)
      .maximumSize(2048)
      .buildAsyncFuture {
        loader { user =>
          build(user) dmap (~_)
        }
      }
  }

  private def ratingsMapToJson(user: User, ratingsMap: RatingsMap) =
    ratingsMap.map { case (days, rating) =>
      val date = user.createdAt plusDays days
      Json.arr(date.getYear, date.getMonthOfYear - 1, date.getDayOfMonth, rating)
    }

  private def build(user: User): Fu[Option[String]] =
    historyApi get user.id map2 { (history: History) =>
      lila.common.String.html.safeJsonValue {
        Json.toJson {
          import lila.rating.PerfType._
          List(
            Bullet,
            Blitz,
            Rapid,
            Classical,
            Correspondence,
            Chess960,
            KingOfTheHill,
            ThreeCheck,
            Antichess,
            Atomic,
            Horde,
            RacingKings,
            Crazyhouse,
            Puzzle,
            UltraBullet
          ) map { pt =>
            Json.obj(
              "name"   -> pt.trans(lila.i18n.defaultLang),
              "points" -> ratingsMapToJson(user, history(pt))
            )
          }
        }
      }
    }
}<commit_msg>stop caching the rating chart in the DB - for #7729<commit_after>package lila.history

import play.api.libs.json._
import scala.concurrent.duration._

import lila.rating.PerfType
import lila.user.{ User, UserRepo }
import org.joda.time.DateTime

final class RatingChartApi(
    historyApi: HistoryApi,
    userRepo: UserRepo,
    cacheApi: lila.memo.CacheApi
)(implicit ec: scala.concurrent.ExecutionContext) {

  def apply(user: User): Fu[Option[String]] =
    cache.get(user.id) dmap { chart =>
      chart.nonEmpty option chart
    }

  def singlePerf(user: User, perfType: PerfType): Fu[JsArray] =
    historyApi.ratingsMap(user, perfType) map {
      ratingsMapToJson(user.id, user.createdAt, _)
    } map JsArray.apply

  private val cache = cacheApi[User.ID, String](4096, "history.rating") {
    _.expireAfterAccess(10 minutes)
      .maximumSize(4096)
      .buildAsyncFuture { userId =>
        build(userId).dmap(~_)
      }
  }

  private def ratingsMapToJson(userId: User.ID, createdAt: DateTime, ratingsMap: RatingsMap) =
    ratingsMap.map { case (days, rating) =>
      val date = createdAt plusDays days
      Json.arr(date.getYear, date.getMonthOfYear - 1, date.getDayOfMonth, rating)
    }

  private def build(userId: User.ID): Fu[Option[String]] =
    userRepo.createdAtById(userId) flatMap {
      _ ?? { createdAt =>
        historyApi get userId map2 { (history: History) =>
          lila.common.String.html.safeJsonValue {
            Json.toJson {
              import lila.rating.PerfType._
              List(
                Bullet,
                Blitz,
                Rapid,
                Classical,
                Correspondence,
                Chess960,
                KingOfTheHill,
                ThreeCheck,
                Antichess,
                Atomic,
                Horde,
                RacingKings,
                Crazyhouse,
                Puzzle,
                UltraBullet
              ) map { pt =>
                Json.obj(
                  "name"   -> pt.trans(lila.i18n.defaultLang),
                  "points" -> ratingsMapToJson(userId, createdAt, history(pt))
                )
              }
            }
          }
        }
      }
    }
}
{'fraction_non_alphanumeric': 0.10074716799228729, 'fraction_numerical': 0.009640877319836105, 'mean_word_length': 1.8541953232462174, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3739503', 'n_tokens_mistral': 1305, 'n_tokens_neox': 1260, 'n_words': 255}