chuni playlog actions

This commit is contained in:
sk1982 2024-03-12 06:52:52 -04:00
parent 8f9fe5278b
commit f69ad4da72
3 changed files with 92 additions and 0 deletions

View File

@ -0,0 +1,64 @@
'use server';
import { requireUser } from '@/actions/auth';
import { db } from '@/db';
import { CHUNI_MUSIC_PROPERTIES } from '@/helpers/chuni/music';
import { chuniRating } from '@/helpers/chuni/rating';
import { sql } from 'kysely';
export type GetPlaylogOptions = {
limit: number
} & ({} |
{ musicId: number } |
{ musicId: number, chartId: number });
export async function getPlaylog(opts: GetPlaylogOptions) {
const user = await requireUser();
const playlog = await db.with('p', db => db
.selectFrom('chuni_score_playlog as playlog')
.innerJoin('chuni_static_music as music', join => join
.onRef('music.songId', '=', 'playlog.musicId')
.onRef('music.chartId', '=', 'playlog.level'))
.where(({ and, eb, selectFrom }) => and([
eb('playlog.user', '=', user.id),
eb('music.version', '=', selectFrom('chuni_static_music')
.select(({ fn }) => fn.max('version').as('latest'))),
]))
.select(
({ ref }) => ['playlog.id', 'playlog.sortNumber', 'playlog.playDate', 'playlog.userPlayDate', 'playlog.track',
'playlog.score', 'playlog.rank', 'playlog.maxCombo', 'playlog.maxChain', 'playlog.rateTap',
'playlog.rateHold', 'playlog.rateSlide', 'playlog.rateAir', 'playlog.rateFlick', 'playlog.judgeGuilty',
'playlog.judgeAttack', 'playlog.judgeCritical', 'playlog.judgeHeaven', 'playlog.playerRating',
'playlog.isNewRecord', 'playlog.isFullCombo', 'playlog.fullChainKind', 'playlog.isAllJustice',
'playlog.playKind', 'playlog.isClear', 'playlog.placeName',
...CHUNI_MUSIC_PROPERTIES,
chuniRating(ref('playlog.score')),
sql<number>`(playlog.playerRating - (LEAD(playlog.playerRating) OVER (ORDER BY id DESC)))`
.as('playerRatingChange')
])
.orderBy('playlog.id desc')
)
.selectFrom('p')
.where(({ and, eb }) => and([
...('musicId' in opts ? [eb('p.songId', '=', opts.musicId)] : []),
...('chartId' in opts ? [eb('p.chartId', '=', opts.chartId)] : []),
]))
.selectAll()
.limit(+opts.limit)
.execute();
let remaining = 0;
if (playlog.length)
remaining = Number((await db.selectFrom('chuni_score_playlog as playlog')
.where(({ and, eb }) => and([
eb('playlog.user', '=', user.id),
eb('playlog.id', '<', playlog.at(-1)!.id),
...('musicId' in opts ? [eb('playlog.musicId', '=', opts.musicId)] : []),
...('chartId' in opts ? [eb('playlog.level', '=', opts.chartId)] : []),
]))
.select(({ fn }) => fn.countAll().as('remaining'))
.executeTakeFirstOrThrow()).remaining);
return { data: playlog, remaining };
}

View File

@ -0,0 +1,12 @@
import { sql } from 'kysely';
export const CHUNI_MUSIC_PROPERTIES = ['music.songId',
'music.chartId',
'music.title',
'music.artist',
'music.jacketPath',
'music.worldsEndTag',
'music.genre',
'music.level'
// sql<string>`CAST(music.level AS DECIMAL(3, 1))`.as('level')
] as const;

View File

@ -0,0 +1,16 @@
import { sql } from 'kysely';
export const chuniRating = (score: any = sql.raw(`CAST(score.scoreMax AS INT)`),
level: any = sql.raw(`(CAST(music.level AS DECIMAL(3, 1)) * 100)`)) => sql<string>`
CAST(GREATEST((CASE
WHEN ${score} IS NULL THEN NULL
WHEN ${score} >= 1009000 THEN ${level} + 215
WHEN ${score} >= 1007500 THEN ${level} + 200 + (${score} - 1007500) / 100
WHEN ${score} >= 1005000 THEN ${level} + 150 + (${score} - 1005000) / 50
WHEN ${score} >= 1000000 THEN ${level} + 100 + (${score} - 1000000) / 100
WHEN ${score} >= 975000 THEN ${level} + (${score} - 975000) / 250
WHEN ${score} >= 900000 THEN ${level} - 500 + (${score} - 900000) / 150
WHEN ${score} >= 800000 THEN (${level} - 500) / 2 + (${score} - 800000) * ((${level} - 500) / 2) / 100000
WHEN ${score} >= 500000 THEN ((${level} - 500) / 2 * (${score} - 500000)) / 300000
ELSE 0 END) / 100, 0) AS DECIMAL(10, 8))
`.as('rating');