mirror of
https://github.com/djhackersdev/minime.git
synced 2026-03-21 17:54:13 -05:00
chuni: Correctly implement recent rating requests
This commit is contained in:
parent
6c22c4287e
commit
71a7cd7eed
|
|
@ -357,3 +357,16 @@ create table "cm_user_playlog" (
|
|||
"place_name" text not null,
|
||||
"is_maimai" text not null
|
||||
);
|
||||
|
||||
create table "cm_user_recent_rating" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "cm_user_data"("id")
|
||||
on delete cascade,
|
||||
"sort_order" integer not null,
|
||||
"music_id" integer not null,
|
||||
"difficult_id" integer not null,
|
||||
"rom_version_code" integer not null,
|
||||
"score" integer not null,
|
||||
constraint "cm_user_recent_rating_uq" unique ("profile_id", "sort_order")
|
||||
);
|
||||
|
|
|
|||
31
schema/migrate/M0015-cm-user-recent-rating.sql
Normal file
31
schema/migrate/M0015-cm-user-recent-rating.sql
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
create table if not exists "cm_user_recent_rating" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "cm_user_data"("id")
|
||||
on delete cascade,
|
||||
"sort_order" integer not null,
|
||||
"music_id" integer not null,
|
||||
"difficult_id" integer not null,
|
||||
"rom_version_code" integer not null,
|
||||
"score" integer not null,
|
||||
constraint "cm_user_recent_rating_uq" unique ("profile_id", "sort_order")
|
||||
);
|
||||
|
||||
-- Prepopulate this table by backfilling the most recent 30 scores per user.
|
||||
-- This isn't exactly correct since not every recent score should go in here, but it's probably close enough.
|
||||
INSERT INTO cm_user_recent_rating (profile_id, sort_order, music_id, difficult_id, rom_version_code, score)
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
profile_id,
|
||||
row_number()
|
||||
OVER (PARTITION BY profile_id ORDER BY user_play_date DESC) AS sort_order,
|
||||
music_id,
|
||||
level AS difficult_id,
|
||||
'1030000' AS rom_version_code,
|
||||
score
|
||||
FROM cm_user_playlog
|
||||
WHERE
|
||||
difficult_id < 4 -- skip world's end
|
||||
ORDER BY profile_id ASC, user_play_date DESC
|
||||
)
|
||||
WHERE sort_order <= 30;
|
||||
|
|
@ -2,7 +2,7 @@ import { Repositories } from "../repo";
|
|||
import { GetUserRecentRatingRequest } from "../request/getUserRecentRating";
|
||||
import { GetUserRecentRatingResponse } from "../response/getUserRecentRating";
|
||||
import { readAimeId } from "../proto/base";
|
||||
import { writeUserRecentRatingFromLog } from "../proto/userRecentRating";
|
||||
import { writeUserRecentRating } from "../proto/userRecentRating";
|
||||
|
||||
export default async function getUserRecentRating(
|
||||
rep: Repositories,
|
||||
|
|
@ -12,11 +12,11 @@ export default async function getUserRecentRating(
|
|||
|
||||
const profileId = await rep.userData().lookup(aimeId);
|
||||
// Return recent 30 plays to calculate rating
|
||||
const items = await rep.userPlaylog().loadLatest(profileId, 30);
|
||||
const items = await rep.userRecentRating().load(profileId);
|
||||
|
||||
return {
|
||||
userId: req.userId,
|
||||
length: items.length.toString(),
|
||||
userRecentRatingList: items.map(writeUserRecentRatingFromLog),
|
||||
userRecentRatingList: items.map(writeUserRecentRating),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { readUserDataEx } from "../proto/userDataEx";
|
|||
import { readUserDuelList } from "../proto/userDuelList";
|
||||
import { readUserPlaylog } from "../proto/userPlaylog";
|
||||
import { readUserCharge } from "../proto/userCharge";
|
||||
import { readUserRecentRating } from "../proto/userRecentRating";
|
||||
import { readUserCourse } from "../proto/userCourse";
|
||||
|
||||
// It shouldn't need to be said really, but seeing as this message (A) requires
|
||||
|
|
@ -84,5 +85,12 @@ export default async function upsertUserAll(
|
|||
await rep.userDuelList().save(profileId, readUserDuelList(item));
|
||||
}
|
||||
|
||||
await rep
|
||||
.userRecentRating()
|
||||
.save(
|
||||
profileId,
|
||||
(payload.userRecentRatingList || []).map(readUserRecentRating)
|
||||
);
|
||||
|
||||
return { returnCode: "1" };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,3 @@ export function writeUserRecentRating(
|
|||
): UserRecentRatingJson {
|
||||
return writeObject(obj);
|
||||
}
|
||||
|
||||
export function writeUserRecentRatingFromLog(
|
||||
obj: UserPlaylogItem
|
||||
): UserRecentRatingJson {
|
||||
return {
|
||||
musicId: obj.musicId.toString(),
|
||||
difficultId: obj.level.toString(),
|
||||
// game version not saved in play log, just return a fixed version now
|
||||
romVersionCode: "1030000",
|
||||
score: obj.score.toString(),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ export { Page } from "./_defs";
|
|||
|
||||
import { UserActivityRepository } from "./userActivity";
|
||||
import { UserCharacterRepository } from "./userCharacter";
|
||||
import { UserCourseRepository } from "./userCourse";
|
||||
import { UserDataRepository } from "./userData";
|
||||
import { UserDataExRepository } from "./userDataEx";
|
||||
import { UserDuelListRepository } from "./userDuelList";
|
||||
|
|
@ -12,13 +13,15 @@ import { UserMapRepository } from "./userMap";
|
|||
import { UserMusicRepository } from "./userMusic";
|
||||
import { UserPlaylogRepository } from "./userPlaylog";
|
||||
import { UserChargeRepository } from "./userCharge";
|
||||
import { UserCourseRepository } from "./userCourse";
|
||||
import { UserRecentRatingRepository } from "./userRecentRating";
|
||||
|
||||
export interface Repositories {
|
||||
userActivity(): UserActivityRepository;
|
||||
|
||||
userCharacter(): UserCharacterRepository;
|
||||
|
||||
userCourse(): UserCourseRepository;
|
||||
|
||||
userData(): UserDataRepository;
|
||||
|
||||
userDataEx(): UserDataExRepository;
|
||||
|
|
@ -40,4 +43,6 @@ export interface Repositories {
|
|||
userCharge(): UserChargeRepository;
|
||||
|
||||
userCourse(): UserCourseRepository;
|
||||
|
||||
userRecentRating(): UserRecentRatingRepository;
|
||||
}
|
||||
|
|
|
|||
12
src/chunithm/repo/userRecentRating.ts
Normal file
12
src/chunithm/repo/userRecentRating.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { UserDataItem } from "../model/userData";
|
||||
import { UserRecentRatingItem } from "../model/userRecentRating";
|
||||
import { Id } from "../../model";
|
||||
|
||||
export interface UserRecentRatingRepository {
|
||||
load(profileId: Id<UserDataItem>): Promise<UserRecentRatingItem[]>;
|
||||
|
||||
save(
|
||||
profileId: Id<UserDataItem>,
|
||||
objs: UserRecentRatingItem[]
|
||||
): Promise<void>;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import { SqlUserItemRepository } from "./userItem";
|
|||
import { SqlUserMapRepository } from "./userMap";
|
||||
import { SqlUserMusicRepository } from "./userMusic";
|
||||
import { SqlUserPlaylogRepository } from "./userPlaylog";
|
||||
import { SqlUserRecentRatingRepository } from "./userRecentRating";
|
||||
import { Repositories } from "../repo";
|
||||
import { UserActivityRepository } from "../repo/userActivity";
|
||||
import { UserCharacterRepository } from "../repo/userCharacter";
|
||||
|
|
@ -25,6 +26,7 @@ import { UserItemRepository } from "../repo/userItem";
|
|||
import { UserMapRepository } from "../repo/userMap";
|
||||
import { UserMusicRepository } from "../repo/userMusic";
|
||||
import { UserPlaylogRepository } from "../repo/userPlaylog";
|
||||
import { UserRecentRatingRepository } from "../repo/userRecentRating";
|
||||
import { Transaction } from "../../sql";
|
||||
|
||||
export class SqlRepositories implements Repositories {
|
||||
|
|
@ -81,4 +83,8 @@ export class SqlRepositories implements Repositories {
|
|||
userPlaylog(): UserPlaylogRepository {
|
||||
return new SqlUserPlaylogRepository(this._txn);
|
||||
}
|
||||
|
||||
userRecentRating(): UserRecentRatingRepository {
|
||||
return new SqlUserRecentRatingRepository(this._txn);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
54
src/chunithm/sql/userRecentRating.ts
Normal file
54
src/chunithm/sql/userRecentRating.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import sql from "sql-bricks-postgres";
|
||||
|
||||
import { Id } from "../../model";
|
||||
import { UserDataItem } from "../model/userData";
|
||||
import { UserRecentRatingItem } from "../model/userRecentRating";
|
||||
import { UserRecentRatingRepository } from "../repo/userRecentRating";
|
||||
import { Transaction } from "../../sql";
|
||||
import { T, createSqlMapper } from "../../sql/util";
|
||||
|
||||
const { readRow, writeRow, colNames } = createSqlMapper({
|
||||
musicId: T.number,
|
||||
difficultId: T.number,
|
||||
romVersionCode: T.number,
|
||||
score: T.number,
|
||||
});
|
||||
|
||||
export class SqlUserRecentRatingRepository
|
||||
implements UserRecentRatingRepository {
|
||||
constructor(private readonly _txn: Transaction) {}
|
||||
|
||||
async load(profileId: Id<UserDataItem>): Promise<UserRecentRatingItem[]> {
|
||||
const stmt = sql
|
||||
.select("music_id", "difficult_id", "rom_version_code", "score")
|
||||
.from("cm_user_recent_rating")
|
||||
.where("profile_id", profileId)
|
||||
.order("sort_order ASC");
|
||||
|
||||
const rows = await this._txn.fetchRows(stmt);
|
||||
|
||||
return rows.map(readRow);
|
||||
}
|
||||
|
||||
save(
|
||||
profileId: Id<UserDataItem>,
|
||||
objs: UserRecentRatingItem[]
|
||||
): Promise<void> {
|
||||
const stmt = sql
|
||||
.insert(
|
||||
"cm_user_recent_rating",
|
||||
objs.map((obj, idx) => {
|
||||
return {
|
||||
id: this._txn.generateId(),
|
||||
profile_id: profileId,
|
||||
sort_order: idx + 1,
|
||||
...writeRow(obj),
|
||||
};
|
||||
})
|
||||
)
|
||||
.onConflict("profile_id", "sort_order")
|
||||
.doUpdate(colNames);
|
||||
|
||||
return this._txn.modify(stmt);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user