fix: mysql server compatibility

closes #2
This commit is contained in:
sk1982 2024-04-17 07:49:22 -04:00
parent 0508ff8759
commit 607c5cacf8
7 changed files with 24 additions and 16 deletions

View File

@ -10,6 +10,8 @@ You can change the encoding by running `ALTER DATABASE aime CHARACTER SET utf8mb
## Creating Database Tables ## Creating Database Tables
Before running the database importer script, you must create the tables in your database. This can be done by running the server once with `AUTOMIGRATE` enabled ([see below](#runtime-variables)), or by running `npm run migrate` (make sure you have run `npm i` first and have the [`DATABASE_URL`](#runtime-variables) environment variable set). Before running the database importer script, you must create the tables in your database. This can be done by running the server once with `AUTOMIGRATE` enabled ([see below](#runtime-variables)), or by running `npm run migrate` (make sure you have run `npm i` first and have the [`DATABASE_URL`](#runtime-variables) environment variable set).
If you are running MySQL server, you may need to run `SET GLOBAL log_bin_trust_function_creators = 1;`
# Building # Building
Make sure you have set the required [build-time variables](#build-time-variables) correctly. Make sure you have set the required [build-time variables](#build-time-variables) correctly.

View File

@ -96,8 +96,8 @@ export async function getUserRating(user: UserPayload) {
.innerJoin('actaeon_chuni_static_music_ext as musicExt', join => join .innerJoin('actaeon_chuni_static_music_ext as musicExt', join => join
.onRef('music.songId', '=', 'musicExt.songId') .onRef('music.songId', '=', 'musicExt.songId')
.onRef('music.chartId', '=', 'musicExt.chartId')) .onRef('music.chartId', '=', 'musicExt.chartId'))
.select(({ lit }) => [...CHUNI_MUSIC_PROPERTIES, sqlChuniRating(sql.raw(`CAST(score.scoreMax AS INT)`)), .select(({ lit }) => [...CHUNI_MUSIC_PROPERTIES, sqlChuniRating(),
sql<string>`CAST(score.scoreMax AS INT)`.as('scoreMax'), sql<number>`(score.scoreMax + 0)`.as('scoreMax'),
lit<number>(1).as('pastIndex') lit<number>(1).as('pastIndex')
]) ])
.where(({ selectFrom, eb }) => eb('music.version', '=', selectFrom('chuni_static_music') .where(({ selectFrom, eb }) => eb('music.version', '=', selectFrom('chuni_static_music')
@ -229,11 +229,13 @@ export const updateProfile = async (data: ProfileUpdate) => {
} }
} }
await db.updateTable('chuni_profile_data') await db
.updateTable('chuni_profile_data')
.where(({ and, eb, selectFrom }) => and([ .where(({ and, eb, selectFrom }) => and([
eb('user', '=', user.id), eb('user', '=', user.id),
eb('version', '=', selectFrom('chuni_profile_data') eb('version', '=', selectFrom(db.selectFrom('chuni_profile_data')
.select(({ fn }) => fn.max('version').as('latest'))) .select(({ fn }) => fn.max('version').as('latest')).as('l'))
.select('latest'))
])) ]))
.set(update) .set(update)
.execute(); .execute();

View File

@ -86,6 +86,7 @@ export const getUserboxItems = async (user: UserPayload, profile: ChuniUserData)
'avatar.texturePath' 'avatar.texturePath'
]).as('avatar')] as const)) ]).as('avatar')] as const))
.selectFrom(['map_icons', 'name_plates', 'system_voices', 'trophies', 'avatars']) .selectFrom(['map_icons', 'name_plates', 'system_voices', 'trophies', 'avatars'])
.groupBy(['map_icons.mapIcon', 'name_plates.namePlate', 'system_voices.systemVoice', 'trophies.trophy'])
.select(eb => ['map_icons.mapIcon', 'name_plates.namePlate', 'system_voices.systemVoice', 'trophies.trophy', .select(eb => ['map_icons.mapIcon', 'name_plates.namePlate', 'system_voices.systemVoice', 'trophies.trophy',
jsonObjectArray(eb, [ jsonObjectArray(eb, [
'avatars.category', 'avatars.avatar' 'avatars.category', 'avatars.avatar'

View File

@ -33,7 +33,7 @@ export default async function TeamPage() {
<Link href={`/team/${team.uuid}`} className="font-semibold transition hover:text-secondary"> <Link href={`/team/${team.uuid}`} className="font-semibold transition hover:text-secondary">
{team.name} {team.name}
</Link> </Link>
{team.isMember && <Tooltip content="Your team"> {!!team.isMember && <Tooltip content="Your team">
<StarIcon className="h-6 text-amber-400" /> <StarIcon className="h-6 text-amber-400" />
</Tooltip>} </Tooltip>}

View File

@ -32,18 +32,21 @@ export const getArcades = async ({ user, uuids, includeUnlisted }: { user?: User
await createArcadeExtIfNecessary().catch(console.error); await createArcadeExtIfNecessary().catch(console.error);
const result = await withUsersVisibleTo(user) const result = await withUsersVisibleTo(user)
.selectFrom('arcade') .with('owners', eb => eb.selectFrom('arcade_owner as o')
.innerJoin('actaeon_arcade_ext as ext', 'arcade.id', 'ext.arcadeId')
.leftJoin('arcade_owner', join => join.onRef('arcade_owner.arcade', '=', 'arcade.id')
.on('arcade_owner.user', '=', user?.id!))
.leftJoin(eb => eb.selectFrom('arcade_owner as o')
.innerJoin('aime_user as u', 'u.id', 'o.user') .innerJoin('aime_user as u', 'u.id', 'o.user')
.innerJoin('actaeon_user_ext as owner_ext', 'u.id', 'owner_ext.userId') .innerJoin('actaeon_user_ext as owner_ext', 'u.id', 'owner_ext.userId')
.where('o.permissions', '>=', 1 << ArcadePermissions.OWNER) .where('o.permissions', '>=', 1 << ArcadePermissions.OWNER)
.where(userIsVisible('o.user')) .where(userIsVisible('o.user'))
.select(({ fn }) => ['u.username', fn.min('u.id').as('id'), 'owner_ext.uuid', 'o.arcade']) .select(({ fn }) => ['u.username', fn.min('u.id').as('id'), 'owner_ext.uuid', 'o.arcade'] as const)
.groupBy('o.arcade') .groupBy(['o.arcade', 'u.id']))
.as('owner'), join => join.onRef('owner.arcade', '=', 'arcade.id')) .selectFrom('arcade')
.innerJoin('actaeon_arcade_ext as ext', 'arcade.id', 'ext.arcadeId')
.leftJoin('arcade_owner', join => join.onRef('arcade_owner.arcade', '=', 'arcade.id')
.on('arcade_owner.user', '=', user?.id!))
.leftJoin('owners as owner', join => join.onRef('owner.arcade', '=', 'arcade.id')
.on(eb => eb('owner.id', '=', eb.selectFrom('owners')
.whereRef('owners.arcade', '=', 'arcade.id')
.select(({ fn }) => fn.min('owners.id').as('least')))))
.where(({ eb, and }) => and([ .where(({ eb, and }) => and([
...(uuids?.length ? [eb('ext.uuid', 'in', uuids)] : [eb.lit(true)]) ...(uuids?.length ? [eb('ext.uuid', 'in', uuids)] : [eb.lit(true)])
])) ]))

View File

@ -1,7 +1,7 @@
import { sql } from 'kysely'; import { sql } from 'kysely';
import { BigDecimal } from '../big-decimal'; import { BigDecimal } from '../big-decimal';
export const sqlChuniRating = (score: any = sql.raw(`CAST(score.scoreMax AS INT)`), export const sqlChuniRating = (score: any = sql.raw(`(score.scoreMax + 0)`),
level: any = sql.raw(`(CAST(music.level AS DECIMAL(3, 1)) * 100)`)) => sql<string>` level: any = sql.raw(`(CAST(music.level AS DECIMAL(3, 1)) * 100)`)) => sql<string>`
CAST(GREATEST((CASE CAST(GREATEST((CASE
WHEN ${score} IS NULL THEN NULL WHEN ${score} IS NULL THEN NULL

View File

@ -14,5 +14,5 @@ export const parseJsonResult = (<T extends object, K extends ParseableKeys<T>>(d
if (Array.isArray(data)) if (Array.isArray(data))
return data.map(d => parseJsonResult(d, keys)); return data.map(d => parseJsonResult(d, keys));
return Object.fromEntries((Object.entries(data) as Entries<T>) return Object.fromEntries((Object.entries(data) as Entries<T>)
.map(([key, val]) => [key, keys.includes(key as any) ? JSON.parse(val as any) : val])); .map(([key, val]) => [key, typeof val === 'string' && keys.includes(key as any) ? JSON.parse(val as any) : val]));
}) as ParseJSONResultOptions; }) as ParseJSONResultOptions;