move scripts to toplevel

This commit is contained in:
zkldi
2021-04-27 03:33:53 +01:00
parent 724a46c94c
commit 41fe51c0dc
19 changed files with 12 additions and 9 deletions
-8
View File
@@ -1,8 +0,0 @@
Hey. If by any chance I'm not available, you can (and should) run these scripts with TS-Node.
https://github.com/TypeStrong/ts-node
They have only been tested for ts-node.
npm install -g ts-node
it's probably installed on the machine you're seeing this on, winter(?). love ya.
@@ -1,5 +0,0 @@
This folder is for porting documents from the old KamaitachiDB to the newer formats.
The scripts here should NOT be ran unless you know *exactly* what the hell you're doing.
And, even then - basically only I know, so. Please be careful.
@@ -1,53 +0,0 @@
import { ChartDocument } from "kamaitachi-common";
import db from "../../db/db";
import { rootLogger } from "../../logger";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): ChartDocument<"iidx:SP" | "iidx:DP"> {
const newChartDoc: ChartDocument<"iidx:SP" | "iidx:DP"> = {
rgcID: null,
chartID: c.chartID,
difficulty: c.difficulty,
songID: c.id,
playtype: c.playtype,
levelNum: c.levelNum,
isRemoved: false,
level: c.level.toString(),
length: c.length,
bpmString: "", // sentinel
flags: {
"IN BASE GAME": !!c.flags["IN BASE GAME"],
OMNIMIX: !!c.flags.OMNIMIX,
"N-1": !!c.flags["N-1"],
},
data: {
inGameID: c.internals.inGameINTID,
notecount: c.notedata.notecount,
},
};
if (typeof c.length === "number") {
let m = Math.floor(c.length / 60_000);
let s = c.length - m * 60_000;
newChartDoc.length = `${m}:${s}`;
}
if (c.monoBPM) {
newChartDoc.bpmString = c.bpmMin.toString();
} else {
newChartDoc.bpmString = `${c.bpmMin}-${c.bpmMax}`;
}
if (newChartDoc.length === null) {
rootLogger.warn(`Length of chart ${newChartDoc.chartID} is null, continuing anyway?`);
}
return newChartDoc;
}
(async () => {
await MigrateRecords(db.charts.iidx, "charts-iidx", ConvertFn);
process.exit(0);
})();
@@ -1,46 +0,0 @@
import { ICollection } from "monk";
import CreateLogCtx from "../../logger";
import { oldKTDB } from "./old-db";
const logger = CreateLogCtx("MIGRATE.ts");
let newDocuments: unknown[] = [];
export default async function MigrateRecords(
existingCollection: ICollection,
collectionName: string,
HandlerFN: (c: unknown) => unknown
) {
let existingRecords = await existingCollection.count({});
logger.info(`Starting migration for ${collectionName}...`);
if (existingRecords > 0) {
logger.error(`${existingRecords} documents already exist in db, terminating.`);
process.exit(1);
}
let i = 0;
await oldKTDB
.get(collectionName)
.find({})
// @ts-expect-error it exists.
.each((c) => {
i++;
if (i % 10000 === 0) {
logger.info(`Processed ${i} documents.`);
}
const newDoc = HandlerFN(c);
if (newDoc !== null) {
newDocuments.push(newDoc);
}
});
logger.info(`Inserting ${newDocuments.length} documents.`);
await existingCollection.insert(newDocuments);
logger.info(`Done!`);
process.exit(0);
}
@@ -1,3 +0,0 @@
import monk from "monk";
export const oldKTDB = monk(`${process.env.MONGO_BASE_URL}/kamaitachidb`);
@@ -1,145 +0,0 @@
import { PrivateUserDocument, ScoreDocument } from "kamaitachi-common";
import { grades, lamps, supportedGames, validPlaytypes } from "kamaitachi-common/js/config";
import db from "../../db/db";
import { rootLogger } from "../../logger";
import { CreateScoreID } from "../../score-import/framework/core/score-id";
import MigrateRecords from "./migrate";
// HERE. WE. GO!
function ConditionalAssign(base: any, baseProp: string, other: any, otherProp: string) {
if (Object.prototype.hasOwnProperty.call(other, otherProp)) {
base[baseProp] = other[otherProp];
}
}
function ConvertFn(c: any): ScoreDocument | null {
if (!supportedGames.includes(c.game)) {
rootLogger.warn(`Ignored game ${c.game}`);
return null;
}
if (["popn", "jubeat", "gitadora", "usc"].includes(c.game)) {
return null;
}
// @ts-expect-error yea
if (validPlaytypes[c.game].includes(c.playtype)) {
rootLogger.warn(`Ignored game pt ${c.game}, ${c.playtype}`);
}
let base: Omit<ScoreDocument, "scoreID"> = {
userID: c.userID,
songID: c.songID,
playtype: c.scoreData.playtype,
chartID: c.chartID,
game: c.game,
timeAdded: c.timeAdded,
timeAchieved: Number.isNaN(c.timeAchieved) ? null : c.timeAchieved,
isScorePB: !!c.isScorePB,
isLampPB: !!c.isLampPB,
comment: c.comment ?? null,
highlight: c.highlight ?? false,
service: c.service,
importType: null,
calculatedData: c.calculatedData,
scoreData: {
esd: c.scoreData.esd ?? null,
grade: c.scoreData.grade,
// @ts-expect-error shut
gradeIndex: grades[c.game].indexOf(c.scoreData.grade),
lamp: c.scoreData.lamp,
// @ts-expect-error shut
lampIndex: lamps[c.game].indexOf(c.scoreData.lamp),
percent: c.scoreData.percent,
score: c.scoreData.score,
hitData: c.scoreData.hitData,
hitMeta: c.scoreData.hitMeta,
},
scoreMeta: {},
};
if (c.scoreMeta) {
if (base.game === "iidx") {
ConditionalAssign(base.scoreMeta, "random", c.scoreMeta, "optionsRandom");
ConditionalAssign(base.scoreMeta, "gauge", c.scoreMeta, "optionsGauge");
ConditionalAssign(base.scoreMeta, "assist", c.scoreMeta, "optionsAssist");
ConditionalAssign(base.scoreMeta, "range", c.scoreMeta, "optionsRange");
ConditionalAssign(base.scoreMeta, "pacemaker", c.scoreMeta, "pacemaker");
ConditionalAssign(base.scoreMeta, "pacemakerName", c.scoreMeta, "pacemakerName");
ConditionalAssign(base.scoreMeta, "pacemakerTarget", c.scoreMeta, "pacemakerTarget");
if (base.playtype === "DP" && !Array.isArray(base.scoreMeta.random)) {
base.scoreMeta.random = null;
}
// @ts-expect-error asdf
if (base.scoreMeta.range === "") {
// @ts-expect-error asdf
base.scoreMeta.range = "NONE";
}
} else if (base.game === "bms") {
ConditionalAssign(base.scoreMeta, "random", c.scoreMeta, "optionsRandom");
ConditionalAssign(base.scoreMeta, "inputDevice", c.scoreData.hitMeta, "inputDevice");
}
}
// @ts-expect-error shut
if (base.scoreData.hitMeta.bp === -1 || Number.isNaN(base.scoreData.hitMeta.bp)) {
// @ts-expect-error shut
base.scoreData.hitMeta.bp = null;
}
if (base.game === "iidx") {
// @ts-expect-error fuck you
if (base.scoreData.hitMeta.gauge > 200) {
// @ts-expect-error fuck you
base.scoreData.hitMeta.gauge = null;
}
// @ts-expect-error fuck you
if (base.scoreData.hitMeta.gaugeHistory) {
// @ts-expect-error fuck you
base.scoreData.hitMeta.gaugeHistory = base.scoreData.hitMeta.gaugeHistory.map((e) =>
e > 200 ? null : e
);
}
} else if (base.game === "bms") {
// @ts-expect-error shut
if (base.scoreData.hitMeta.gauge === -1) {
// @ts-expect-error shut
base.scoreData.hitMeta.gauge = null;
}
// @ts-expect-error shut
delete base.scoreData.hitMeta.inputDevice;
} else if (base.game === "sdvx" || base.game === "usc") {
ConditionalAssign(base.scoreData.hitData, "miss", base.scoreData.hitData, "error");
//@ts-expect-error yea
delete base.scoreData.hitData.error;
} else if (base.game === "chunithm") {
if (base.scoreData.percent === 101) {
base.scoreData.grade === "SSS";
}
}
if (base.service === "mm") {
base.service = "maimagic";
}
let scoreID = CreateScoreID(base.userID, base, base.chartID);
let score: ScoreDocument = {
...base,
scoreID,
};
return score;
}
(async () => {
await MigrateRecords(db.scores, "scores", ConvertFn);
process.exit(0);
})();
@@ -1,40 +0,0 @@
import { SongDocument } from "kamaitachi-common";
import { gameOrders } from "kamaitachi-common/js/config";
import db from "../../db/db";
import { rootLogger } from "../../logger";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): SongDocument<"iidx"> {
const newSongDoc: SongDocument<"iidx"> = {
title: c.title,
artist: c.artist,
id: c.id,
isAvailable: true, // NOT NECESSARILY
firstVersion: c.firstAppearance,
"alt-titles": c["alt-titles"].filter((e: string) => e !== c.title),
"search-titles": c["search-titles"]
.map((e: string) => e.toString())
.filter((e: string) => e !== c.title),
versions: [], // sentinel
data: {
genre: c.genre,
},
};
let idx = gameOrders.iidx.indexOf(c.firstAppearance);
if (idx === -1) {
rootLogger.warn(`Invalid firstAppearance of ${c.firstAppearance}, running anyway.`);
newSongDoc.versions = [c.firstAppearance];
} else {
newSongDoc.versions = gameOrders.iidx.slice(idx);
}
return newSongDoc;
}
(async () => {
await MigrateRecords(db.songs.iidx, "songs-iidx", ConvertFn);
process.exit(0);
})();
@@ -1,40 +0,0 @@
import { PrivateUserDocument } from "kamaitachi-common";
import db from "../../db/db";
import MigrateRecords from "./migrate";
function ConvertFn(c: any): PrivateUserDocument {
const newUserDoc: PrivateUserDocument = {
username: c.username,
usernameLowercase: c.username.toLowerCase(),
about: c.about,
clan: c.clan,
customBanner: c.custombanner,
customPfp: c.custompfp,
email: c.email,
friends: c.friends,
id: c.id,
lastSeen: c.lastSeen,
password: c.password,
permissions: {},
settings: {
invisible: !!c.settings.invisible,
nsfwSplashes: !!c.settings.nsfwsplashes,
},
socialMedia: {
discord: c.socialmedia.discord || null,
twitter: c.socialmedia.twitter || null,
youtube: c.socialmedia.youtube || null,
twitch: c.socialmedia.twitch || null,
github: c.socialmedia.github || null,
steam: c.socialmedia.steam || null,
},
};
return newUserDoc;
}
(async () => {
await MigrateRecords(db.users, "users", ConvertFn);
process.exit(0);
})();
File diff suppressed because it is too large Load Diff
-22
View File
@@ -1,22 +0,0 @@
import db from "../db/db";
import CreateLogCtx from "../logger";
const logger = CreateLogCtx("scripts/initialise-counters.ts");
(async () => {
let users = await db.counters.findOne({
counterName: "users",
});
if (users) {
throw new Error(`"users" document already exists, exiting.`);
}
await db.counters.insert({
counterName: "users",
value: 1,
});
logger.info("Successfully initialised counter documents. Exiting.");
process.exit(0);
})();
@@ -1,33 +0,0 @@
import monk from "monk";
import fs from "fs";
import path from "path";
import { Command } from "commander";
import CreateLogCtx from "../logger";
const program = new Command();
const logger = CreateLogCtx("save-testdata-from-ktblack.ts");
program.option("-c, --collection <collection>", "The collection to fetch ktblack data from.");
program.parse(process.argv);
const options = program.opts();
const collection = options.collection;
logger.info(`Connecting to ${process.env.MONGO_BASE_URL}/ktblackdb...`);
const ktBlackDB = monk(`${process.env.MONGO_BASE_URL}/ktblackdb`);
(async () => {
logger.info(`Fetching data for ${collection}...`);
let data = await ktBlackDB.get(collection).find({}, { projection: { _id: 0 } });
logger.info(`Fetched ${data.length} documents, Writing...`);
fs.writeFileSync(
path.join(__dirname, `../test-utils/test-data/kamaitachi/ktblack-${collection}.json`),
JSON.stringify(data)
);
logger.info("Done!");
process.exit(0);
})();
-65
View File
@@ -1,65 +0,0 @@
import monk from "monk";
import { Command } from "commander";
import CreateLogCtx from "../logger";
import { IndexOptions } from "mongodb";
import { ValidDatabases } from "kamaitachi-common";
const logger = CreateLogCtx("set-indexes.ts");
const program = new Command();
program.option("-d, --db <database>", "The database to index.");
program.option(
"-r, --reset",
"Whether to reset all indexes on this database before indexing or not."
);
program.parse(process.argv);
const options = program.opts();
const db = monk(`${process.env.MONGO_BASE_URL ?? "127.0.0.1"}/${options.db}`);
interface Index {
fields: Record<string, unknown>;
options?: IndexOptions;
}
function index(fields: Record<string, unknown>, options?: IndexOptions) {
return { fields, options };
}
const UNIQUE = { unique: true };
const indexes: Partial<Record<ValidDatabases, Index[]>> = {
scores: [index({ scoreID: 1 }, UNIQUE)],
"charts-iidx": [
index({ chartID: 1 }, UNIQUE),
index({ songID: 1, difficulty: 1, playtype: 1 }, UNIQUE),
],
"songs-iidx": [index({ id: 1 }, UNIQUE), index({ title: 1 })],
sessions: [
// lol
index({ timeStarted: 1, timeEnded: 1, userID: 1, game: 1, playtype: 1 }),
],
};
(async () => {
logger.info(`Starting indexing for ${options.db}...`);
for (const collection in indexes) {
if (options.reset) {
// eslint-disable-next-line no-await-in-loop
await db.get(collection).dropIndexes();
}
// @ts-expect-error yeah blah blah
for (const index of indexes[collection]) {
// eslint-disable-next-line no-await-in-loop
let r = await db.get(collection).createIndex(index.fields, index.options);
logger.info(r);
}
}
logger.info("Done.");
})();
@@ -1,21 +0,0 @@
/* eslint-disable no-console */
import fs from "fs";
import path from "path";
import { PRUDENCE_CHART_SCHEMAS } from "../../db/schemas";
import p from "prudence";
import db from "../../db/db";
let data = JSON.parse(fs.readFileSync(path.join(__dirname, "./hcnverdata.json"), "utf-8"));
for (const d of data) {
let r = p(d, PRUDENCE_CHART_SCHEMAS.iidx);
if (r) {
console.dir(r);
throw r;
}
}
db.charts.iidx.insert(data).then(() => {
console.log("Done.");
process.exit(0);
});
@@ -1,4 +0,0 @@
/* eslint-disable no-console */
import bcrypt from "bcrypt";
console.log(bcrypt.hashSync("password", 12));
@@ -1,242 +0,0 @@
[
{
"songID": 919,
"rgcID": null,
"chartID": "90a2e4664a1a3f8a3a2fd2d8d6a89fd0a47ca659",
"level": "11",
"length": null,
"levelNum": 11,
"bpmString": "178",
"playtype": "SP",
"difficulty": "HYPER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 1146,
"inGameID": 17100
}
},
{
"songID": 919,
"rgcID": null,
"chartID": "360ac8bd65fe8b019d0457bd6603c2bff29d0cd8",
"level": "7",
"length": null,
"levelNum": 7,
"bpmString": "178",
"playtype": "SP",
"difficulty": "NORMAL",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 518,
"inGameID": 17100
}
},
{
"songID": 919,
"rgcID": null,
"chartID": "d7b1c2beb792de3f76a13297a02d8326367f71bc",
"level": "12",
"length": null,
"levelNum": 12,
"bpmString": "178",
"playtype": "SP",
"difficulty": "ANOTHER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 1629,
"inGameID": 17100
}
},
{
"songID": 919,
"rgcID": null,
"chartID": "e36e466c21f208b7489fadf465a257c5ab00f672",
"level": "11",
"length": null,
"levelNum": 11,
"bpmString": "178",
"playtype": "DP",
"difficulty": "HYPER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 1117,
"inGameID": 17100
}
},
{
"songID": 919,
"rgcID": null,
"chartID": "b421a3efeed03f97f5d0ab1901bf539d398755c8",
"level": "6",
"length": null,
"levelNum": 6,
"bpmString": "178",
"playtype": "DP",
"difficulty": "NORMAL",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 506,
"inGameID": 17100
}
},
{
"songID": 919,
"rgcID": null,
"chartID": "7292edfe76c7178f1f608d5e34c0fa09d8cfcc17",
"level": "12",
"length": null,
"levelNum": 12,
"bpmString": "178",
"playtype": "DP",
"difficulty": "ANOTHER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 1764,
"inGameID": 17100
}
},
{
"songID": 994,
"rgcID": null,
"chartID": "125dd4e63a8fced77696313a7a274b4e1c51df4d",
"level": "9",
"length": null,
"levelNum": 9,
"bpmString": "146",
"playtype": "SP",
"difficulty": "HYPER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 708,
"inGameID": 18102
}
},
{
"songID": 994,
"rgcID": null,
"chartID": "7de251ff40cca708de47cce82cbe58d60bc13561",
"level": "5",
"length": null,
"levelNum": 5,
"bpmString": "146",
"playtype": "SP",
"difficulty": "NORMAL",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 268,
"inGameID": 18102
}
},
{
"songID": 994,
"rgcID": null,
"chartID": "20aabe8ae38b5facc6a4f7953f6c73c4c9817840",
"level": "11",
"length": null,
"levelNum": 11,
"bpmString": "146",
"playtype": "SP",
"difficulty": "ANOTHER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 1125,
"inGameID": 18102
}
},
{
"songID": 994,
"rgcID": null,
"chartID": "fa58148d78b33fdb6bc7437065d35285a962d27d",
"level": "9",
"length": null,
"levelNum": 9,
"bpmString": "146",
"playtype": "DP",
"difficulty": "HYPER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 740,
"inGameID": 18102
}
},
{
"songID": 994,
"rgcID": null,
"chartID": "731a4407beeba780e429796ddc6d64444ea64079",
"level": "4",
"length": null,
"levelNum": 4,
"bpmString": "146",
"playtype": "DP",
"difficulty": "NORMAL",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 429,
"inGameID": 18102
}
},
{
"songID": 994,
"rgcID": null,
"chartID": "1807545aa0e71df21c6ab518a0dccdc12aa3535e",
"level": "12",
"length": null,
"levelNum": 12,
"bpmString": "146",
"playtype": "DP",
"difficulty": "ANOTHER",
"flags": {
"IN BASE GAME": false,
"OMNIMIX": true,
"N-1": true
},
"data": {
"notecount": 1120,
"inGameID": 18102
}
}
]
@@ -1,9 +0,0 @@
import fs from "fs";
import db from "../../db/db";
import path from "path";
(async () => {
let data = await db.scores.find({ game: "iidx", playtype: "SP" }, { limit: 1000 });
fs.writeFileSync(path.join(__dirname, "data.json"), JSON.stringify(data));
process.exit(0);
})();
-101
View File
@@ -1,101 +0,0 @@
/* eslint-disable no-await-in-loop */
import fetch from "node-fetch";
import { Command } from "commander";
import fs from "fs";
import path from "path";
import { config, Difficulties, ESDCore, IIDXBPIData, ChartDocument } from "kamaitachi-common";
import { FindSongOnTitleVersion } from "../score-import/database-lookup/song-title";
import { FindChartWithPTDF } from "../score-import/database-lookup/chart-ptdf";
import db from "../db/db";
import CreateLogCtx from "../logger";
const program = new Command();
const logger = CreateLogCtx("update-bpi-poyashi.ts");
program.option("-f, --fetch", "Fetch the latest data from the poyashi repo.");
program.parse(process.argv);
const options = program.opts();
const dataLoc = path.join(__dirname, "../bpi-poyashi-data/output.json");
const difficultyResolve: Record<string, [string, string]> = {
3: ["SP", "HYPER"],
4: ["SP", "ANOTHER"],
8: ["DP", "HYPER"],
9: ["DP", "ANOTHER"],
10: ["SP", "LEGGENDARIA"],
11: ["DP", "LEGGENDARIA"],
};
async function UpdatePoyashiData() {
let data;
if (options.fetch) {
// lol!
logger.info("Fetching data from github...");
let rj = await fetch(
"https://raw.githubusercontent.com/potakusan/bpim-score-repo/master/output/release.json"
).then((r) => r.json());
logger.info("Fetched data.");
fs.writeFileSync(dataLoc, JSON.stringify(rj));
logger.info("Saved data to output.json.");
data = rj;
} else {
logger.info("Reading data from output.json...");
data = JSON.parse(fs.readFileSync(dataLoc, "utf-8"));
}
let realData: IIDXBPIData[] = [];
for (const d of data) {
const res = difficultyResolve[d.difficulty];
if (!res) {
throw new Error(`Unknown difficulty ${d.difficulty}`);
}
const [playtype, diff] = res;
let ktchiSong = await FindSongOnTitleVersion("iidx", d.title, "28");
if (!ktchiSong) {
throw new Error(`Cannot find song ${d.title}?`);
}
let ktchiChart = (await FindChartWithPTDF(
"iidx",
ktchiSong.id,
playtype as "SP" | "DP",
diff as Difficulties["iidx:DP" | "iidx:SP"]
)) as ChartDocument<"iidx:SP" | "iidx:DP">;
if (!ktchiChart) {
throw new Error(
`Cannot find chart ${ktchiSong.title} (${ktchiSong.id}) ${playtype}, ${diff}?`
);
}
let kavg = Number(d.avg);
let kesd = ESDCore.CalculateESD(
config.judgementWindows.iidx.SP,
kavg / (ktchiChart.data.notecount * 2)
);
realData.push({
coef: d.coef === -1 ? null : d.coef,
kavg: Number(d.avg),
wr: Number(d.wr),
chartID: ktchiChart.chartID,
kesd,
});
}
await db["iidx-bpi-data"].remove({});
await db["iidx-bpi-data"].insert(realData);
logger.info(`Inserted ${realData.length} documents.`);
}
UpdatePoyashiData();
-196
View File
@@ -1,196 +0,0 @@
import Prudence, { PrudenceSchema } from "prudence";
import db from "../db/db";
import { PRUDENCE_CHART_SCHEMAS, PRUDENCE_SCORE_SCHEMAS, STATIC_SCHEMAS } from "../db/schemas";
import CreateLogCtx from "../logger";
import fs from "fs";
import path from "path";
import { PrudenceError } from "prudence/js/error";
import { supportedGames, validPlaytypes } from "kamaitachi-common/js/config";
const BASE_DIR = path.join(__dirname, "./validate-database-errs");
// note: a hell of a lot of this code is copy pasted
// this is just a script, so, feel free to refactor it.
const logger = CreateLogCtx("validate-database.ts");
async function ValidateStaticSchemas(): Promise<void> {
for (const x in STATIC_SCHEMAS) {
const c = x as keyof typeof STATIC_SCHEMAS;
const schema = STATIC_SCHEMAS[c] as PrudenceSchema;
logger.info(`=== Validating Collection ${c}... ===`);
let successCount = 0;
let total = 0;
let fails: { err: PrudenceError; doc: unknown }[] = [];
let start = process.hrtime.bigint();
// @ts-expect-error shut UP
// eslint-disable-next-line no-await-in-loop
await db[c].find({}, { projection: { _id: 0 } }).each((c: unknown) => {
total++;
let res = Prudence(c, schema);
if (res === null) {
successCount++;
} else {
logger.error(res);
fails.push({ err: res, doc: c });
}
});
let end = process.hrtime.bigint();
logger.info(`Validated ${total} objects. Took ${Number(end - start) / 1e9} seconds.`);
logger.info(`Success: ${successCount} (${((successCount * 100) / total).toFixed(2)}%)`);
logger.info(`Fail: ${fails.length} (${((fails.length * 100) / total).toFixed(2)}%)`);
if (fails.length !== 0) {
logger.severe(`Invalid documents found! Please resolve them.`);
fs.writeFileSync(path.join(BASE_DIR, `${c}.json`), JSON.stringify(fails));
}
}
logger.info("Done!");
process.exit(0);
}
async function ValidateScores(): Promise<void> {
let globalStart = process.hrtime.bigint();
let globalTotal = 0;
let globalSuccess = 0;
let globalFail = 0;
for (const game of supportedGames) {
for (const playtype of validPlaytypes[game]) {
// @ts-expect-error shut up
let schema = PRUDENCE_SCORE_SCHEMAS[game][playtype];
let successCount = 0;
let total = 0;
let fails: { err: PrudenceError; doc: unknown }[] = [];
logger.info(`=== Validating Collection scores (${game} ${playtype}) ... ===`);
let start = process.hrtime.bigint();
// eslint-disable-next-line no-await-in-loop
await db.scores
.find({ playtype, game }, { projection: { _id: 0 } })
// @ts-expect-error shut UP
.each((c: unknown) => {
total++;
let res = Prudence(c, schema);
if (res === null) {
successCount++;
} else {
logger.error(
`[${game} ${playtype}] [${res.keychain}] ${res.message}: ${res.userVal}`
);
fails.push({ err: res, doc: c });
}
});
let end = process.hrtime.bigint();
logger.info(`Validated ${total} objects. Took ${Number(end - start) / 1e9} seconds.`);
logger.info(`Success: ${successCount} (${((successCount * 100) / total).toFixed(2)}%)`);
logger.info(`Fail: ${fails.length} (${((fails.length * 100) / total).toFixed(2)}%)`);
if (fails.length !== 0) {
logger.severe(`Invalid documents found! Please resolve them.`);
fs.writeFileSync(
path.join(BASE_DIR, `scores-${game}-${playtype}.json`),
JSON.stringify(fails)
);
fs.writeFileSync(
path.join(BASE_DIR, `scores-${game}-${playtype}.log`),
`Validated ${total} objects. Took ${
Number(end - start) / 1e9
} seconds.\nSuccess: ${successCount} (${((successCount * 100) / total).toFixed(
2
)}%)\nFail: ${fails.length} (${((fails.length * 100) / total).toFixed(2)}%)`
);
}
globalTotal += total;
globalFail += fails.length;
globalSuccess += successCount;
}
}
let globalEnd = process.hrtime.bigint();
logger.info(
`Validated ${globalTotal} objects. Took ${Number(globalEnd - globalStart) / 1e9} seconds.`
);
logger.info(`Success: ${globalSuccess} (${((globalSuccess * 100) / globalTotal).toFixed(2)}%)`);
logger.info(`Fail: ${globalFail} (${((globalFail * 100) / globalTotal).toFixed(2)}%)`);
// process.exit(1);
}
async function ValidateChartsOrSongs(type: "songs" | "charts"): Promise<void> {
let globalStart = process.hrtime.bigint();
let globalTotal = 0;
let globalSuccess = 0;
let globalFail = 0;
for (const game of supportedGames) {
let schema = STATIC_SCHEMAS[type]![game];
let successCount = 0;
let total = 0;
let fails: { err: PrudenceError; doc: unknown }[] = [];
logger.info(`=== Validating Collection ${type} (${game}) ... ===`);
let start = process.hrtime.bigint();
// eslint-disable-next-line no-await-in-loop
await db[type][game]
// @ts-expect-error whatever bro
.find({}, { projection: { _id: 0 } })
.each((c: unknown) => {
total++;
let res = Prudence(c, schema);
if (res === null) {
successCount++;
} else {
logger.error(`[${game}] [${res.keychain}] ${res.message}: ${res.userVal}`);
fails.push({ err: res, doc: c });
}
});
let end = process.hrtime.bigint();
logger.info(`Validated ${total} objects. Took ${Number(end - start) / 1e9} seconds.`);
logger.info(`Success: ${successCount} (${((successCount * 100) / total).toFixed(2)}%)`);
logger.info(`Fail: ${fails.length} (${((fails.length * 100) / total).toFixed(2)}%)`);
if (fails.length !== 0) {
logger.severe(`Invalid documents found! Please resolve them.`);
fs.writeFileSync(path.join(BASE_DIR, `${type}-${game}.json`), JSON.stringify(fails));
fs.writeFileSync(
path.join(BASE_DIR, `${type}-${game}.log`),
`Validated ${total} objects. Took ${
Number(end - start) / 1e9
} seconds.\nSuccess: ${successCount} (${((successCount * 100) / total).toFixed(
2
)}%)\nFail: ${fails.length} (${((fails.length * 100) / total).toFixed(2)}%)`
);
}
globalTotal += total;
globalFail += fails.length;
globalSuccess += successCount;
}
let globalEnd = process.hrtime.bigint();
logger.info(
`Validated ${globalTotal} objects. Took ${Number(globalEnd - globalStart) / 1e9} seconds.`
);
logger.info(`Success: ${globalSuccess} (${((globalSuccess * 100) / globalTotal).toFixed(2)}%)`);
logger.info(`Fail: ${globalFail} (${((globalFail * 100) / globalTotal).toFixed(2)}%)`);
}
// ValidateStaticSchemas();
// ValidateScores();
ValidateChartsOrSongs("songs");