feat: implement character overrides and update daily character retrieval logic
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { db } from '$lib/server/db';
|
||||
import { arc, character, characterHistory, devilFruit } from '$lib/server/db/schema';
|
||||
import { desc, eq } from 'drizzle-orm';
|
||||
import { arc, character, characterHistory, characterOverride, devilFruit } from '$lib/server/db/schema';
|
||||
import { desc, eq, inArray } from 'drizzle-orm';
|
||||
|
||||
const characterWithRelationsSelect = {
|
||||
id: character.id,
|
||||
@@ -32,6 +32,113 @@ export type CharacterWithRelations = typeof character.$inferSelect & {
|
||||
arcName: string | null;
|
||||
};
|
||||
|
||||
type CharacterOverrideRow = typeof characterOverride.$inferSelect;
|
||||
|
||||
type RelationMaps = {
|
||||
arcNameById: Map<string, string | null>;
|
||||
devilFruitById: Map<string, { name: string | null; type: string | null }>;
|
||||
};
|
||||
|
||||
function isNotNullish<T>(value: T | null | undefined): value is T {
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
|
||||
function mergeCharacterWithOverride(
|
||||
baseCharacter: CharacterWithRelations,
|
||||
overrideRow?: CharacterOverrideRow,
|
||||
relationMaps?: RelationMaps
|
||||
): CharacterWithRelations {
|
||||
if (!overrideRow) {
|
||||
return baseCharacter;
|
||||
}
|
||||
|
||||
const mergedCharacter = { ...baseCharacter } as CharacterWithRelations;
|
||||
|
||||
for (const [key, value] of Object.entries(overrideRow)) {
|
||||
if (key === 'characterId' || key === 'notes') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isNotNullish(value)) {
|
||||
(mergedCharacter as Record<string, unknown>)[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (relationMaps) {
|
||||
if (mergedCharacter.arcId) {
|
||||
mergedCharacter.arcName = relationMaps.arcNameById.get(mergedCharacter.arcId) ?? null;
|
||||
} else {
|
||||
mergedCharacter.arcName = null;
|
||||
}
|
||||
|
||||
if (mergedCharacter.devilFruitId) {
|
||||
const devilFruitData = relationMaps.devilFruitById.get(mergedCharacter.devilFruitId);
|
||||
mergedCharacter.devilFruitName = devilFruitData?.name ?? null;
|
||||
mergedCharacter.devilFruitType = devilFruitData?.type ?? null;
|
||||
} else {
|
||||
mergedCharacter.devilFruitName = null;
|
||||
mergedCharacter.devilFruitType = null;
|
||||
}
|
||||
}
|
||||
|
||||
return mergedCharacter;
|
||||
}
|
||||
|
||||
async function applyCharacterOverrides(
|
||||
characters: CharacterWithRelations[]
|
||||
): Promise<CharacterWithRelations[]> {
|
||||
if (characters.length === 0) {
|
||||
return characters;
|
||||
}
|
||||
|
||||
const characterIds = characters.map((currentCharacter) => currentCharacter.id);
|
||||
const overrideRows = await db
|
||||
.select()
|
||||
.from(characterOverride)
|
||||
.where(inArray(characterOverride.characterId, characterIds));
|
||||
|
||||
if (overrideRows.length === 0) {
|
||||
return characters;
|
||||
}
|
||||
|
||||
const overrideByCharacterId = new Map<string, CharacterOverrideRow>(
|
||||
overrideRows.map((overrideRow) => [overrideRow.characterId, overrideRow])
|
||||
);
|
||||
|
||||
const shouldRefreshRelations = overrideRows.some(
|
||||
(overrideRow) => isNotNullish(overrideRow.arcId) || isNotNullish(overrideRow.devilFruitId)
|
||||
);
|
||||
|
||||
let relationMaps: RelationMaps | undefined;
|
||||
|
||||
if (shouldRefreshRelations) {
|
||||
const [allArcs, allDevilFruits] = await Promise.all([
|
||||
db.select({ id: arc.id, name: arc.name }).from(arc),
|
||||
db
|
||||
.select({ id: devilFruit.id, name: devilFruit.name, type: devilFruit.type })
|
||||
.from(devilFruit)
|
||||
]);
|
||||
|
||||
relationMaps = {
|
||||
arcNameById: new Map(allArcs.map((currentArc) => [currentArc.id, currentArc.name])),
|
||||
devilFruitById: new Map(
|
||||
allDevilFruits.map((currentDevilFruit) => [
|
||||
currentDevilFruit.id,
|
||||
{ name: currentDevilFruit.name, type: currentDevilFruit.type }
|
||||
])
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
return characters.map((currentCharacter) =>
|
||||
mergeCharacterWithOverride(
|
||||
currentCharacter,
|
||||
overrideByCharacterId.get(currentCharacter.id),
|
||||
relationMaps
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getDateKey(date: Date): string {
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
@@ -50,13 +157,15 @@ function pickDailyCharacter(characters: CharacterWithRelations[], date: Date): C
|
||||
}
|
||||
|
||||
export async function getDailyModeCharacters(): Promise<CharacterWithRelations[]> {
|
||||
return db
|
||||
const characters = (await db
|
||||
.select(characterWithRelationsSelect)
|
||||
.from(character)
|
||||
.leftJoin(arc, eq(character.arcId, arc.id))
|
||||
.leftJoin(devilFruit, eq(character.devilFruitId, devilFruit.id))
|
||||
.where(eq(character.isInDailyMode, true))
|
||||
.all() as Promise<CharacterWithRelations[]>;
|
||||
.all()) as CharacterWithRelations[];
|
||||
|
||||
return applyCharacterOverrides(characters);
|
||||
}
|
||||
|
||||
export async function getCharacterById(characterId: string): Promise<CharacterWithRelations | null> {
|
||||
@@ -68,7 +177,12 @@ export async function getCharacterById(characterId: string): Promise<CharacterWi
|
||||
.where(eq(character.id, characterId))
|
||||
.limit(1);
|
||||
|
||||
return (found ?? null) as CharacterWithRelations | null;
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [overriddenCharacter] = await applyCharacterOverrides([found as CharacterWithRelations]);
|
||||
return overriddenCharacter ?? null;
|
||||
}
|
||||
|
||||
export async function getOrCreateTodayCharacter(
|
||||
|
||||
Reference in New Issue
Block a user