<commit_before>/**
 * ステージ人気ランキングモデルクラスのNode.jsモジュール。
 * @module ./models/redis/stage-play-ranking
 */
import { IRedisMultiAsync } from '../../core/redis/redis-async';
import redisHelper from '../../core/redis/redis-helper';
import { SortedSet, Entry } from '../../core/redis/sorted-set';
import objectUtils from '../../core/utils/object-utils';
import Stage from '../stage';
import Playlog from '../playlog';
import redis from './redis';

const BASE_NAME = "stagePlayRankings";

export interface RankingEntry extends Entry {
	info?: { stageId: number, tried: number, score: number, cleared: number }[];
}

/**
 * ステージ人気ランキングコレクションクラス。
 */
export default class StagePlayRanking extends SortedSet {
	/** 年 */
	year: number;
	/** 月 */
	month: number;

	/**
	 * コレクションインスタンスを生成する。
	 * @param year 年。※年間／月間ランキングの場合
	 * @param month 月。※月間ランキングの場合
	 */
	constructor(year: number = null, month: number = null) {
		super(StagePlayRanking.makeKey(year, month), redis.getClient());
		this.year = year;
		this.month = month;
	}

	/**
	 * 年・月からキー用の文字列を生成する。
	 * @param year 年。※年間／月間ランキングの場合
	 * @param month 月。※月間ランキングの場合
	 * @returns キー文字列。
	 */
	static makeKey(year: number = null, month: number = null): string {
		// 累計／年間／月間を引数で振り分け
		const args = [];
		if (year) {
			args.push(year);
		}
		if (month) {
			args.push(month);
		}
		return redisHelper.makeKey(BASE_NAME, ...args);
	}

	/**
	 * データをプレイログから登録する。
	 * @param playlog プレイログ。
	 * @returns 更新結果。
	 */
	static async addByLog(playlog: Playlog): Promise<void> {
		// 累計／年間／月間を一度に登録する
		const date = playlog.createdAt ? new Date(playlog.createdAt) : new Date();

		const keys = [date.getFullYear(), date.getMonth() + 1];
		const multi = redis.getClient().multi();
		for (let i = 0; i < 3; i++) {
			let ranking = new StagePlayRanking(...keys.slice(0, i));
			ranking.multi = multi;
			ranking.increment(String(playlog.stageId));
		}
		await multi.execAsync();
	}

	/**
	 * ランキングデータを取得する。
	 * @param start 取得開始位置。デフォルトは先頭。
	 * @param end 取得終了位置。デフォルトは末尾。
	 * @returns  検索結果。スコアの降順。
	 */
	async findRankingAsync(start: number = undefined, end: number = undefined): Promise<RankingEntry[]> {
		const rankings = await this.entriesAsync(start, end, true);
		if (rankings.length === 0) {
			return rankings;
		}
		await redisHelper.bulkLoadDbModels(rankings, Stage.scope("withuser"), "stage");<commit_msg>余分なスペース除去<commit_after>/**
 * ステージ人気ランキングモデルクラスのNode.jsモジュール。
 * @module ./models/redis/stage-play-ranking
 */
import { IRedisMultiAsync } from '../../core/redis/redis-async';
import redisHelper from '../../core/redis/redis-helper';
import { SortedSet, Entry } from '../../core/redis/sorted-set';
import objectUtils from '../../core/utils/object-utils';
import Stage from '../stage';
import Playlog from '../playlog';
import redis from './redis';

const BASE_NAME = "stagePlayRankings";

export interface RankingEntry extends Entry {
	info?: { stageId: number, tried: number, score: number, cleared: number }[];
}

/**
 * ステージ人気ランキングコレクションクラス。
 */
export default class StagePlayRanking extends SortedSet {
	/** 年 */
	year: number;
	/** 月 */
	month: number;

	/**
	 * コレクションインスタンスを生成する。
	 * @param year 年。※年間／月間ランキングの場合
	 * @param month 月。※月間ランキングの場合
	 */
	constructor(year: number = null, month: number = null) {
		super(StagePlayRanking.makeKey(year, month), redis.getClient());
		this.year = year;
		this.month = month;
	}

	/**
	 * 年・月からキー用の文字列を生成する。
	 * @param year 年。※年間／月間ランキングの場合
	 * @param month 月。※月間ランキングの場合
	 * @returns キー文字列。
	 */
	static makeKey(year: number = null, month: number = null): string {
		// 累計／年間／月間を引数で振り分け
		const args = [];
		if (year) {
			args.push(year);
		}
		if (month) {
			args.push(month);
		}
		return redisHelper.makeKey(BASE_NAME, ...args);
	}

	/**
	 * データをプレイログから登録する。
	 * @param playlog プレイログ。
	 * @returns 更新結果。
	 */
	static async addByLog(playlog: Playlog): Promise<void> {
		// 累計／年間／月間を一度に登録する
		const date = playlog.createdAt ? new Date(playlog.createdAt) : new Date();

		const keys = [date.getFullYear(), date.getMonth() + 1];
		const multi = redis.getClient().multi();
		for (let i = 0; i < 3; i++) {
			let ranking = new StagePlayRanking(...keys.slice(0, i));
			ranking.multi = multi;
			ranking.increment(String(playlog.stageId));
		}
		await multi.execAsync();
	}

	/**
	 * ランキングデータを取得する。
	 * @param start 取得開始位置。デフォルトは先頭。
	 * @param end 取得終了位置。デフォルトは末尾。
	 * @returns 検索結果。スコアの降順。
	 */
	async findRankingAsync(start: number = undefined, end: number = undefined): Promise<RankingEntry[]> {
		const rankings = await this.entriesAsync(start, end, true);
		if (rankings.length === 0) {
			return rankings;
		}
		await redisHelper.bulkLoadDbModels(rankings, Stage.scope("withuser"), "stage");
{'fraction_non_alphanumeric': 0.16464064832586905, 'fraction_numerical': 0.0021326508850501172, 'mean_word_length': 3.7565922920892496, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, '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': '5103373', 'n_tokens_mistral': 2091, 'n_tokens_neox': 1994, 'n_words': 375}