poixpixel-discord-bot/src/db/functions/achievementFunctions.ts

275 lines
7.1 KiB
TypeScript

import { and, eq } from 'drizzle-orm';
import { db, ensureDbInitialized, handleDbError } from '../db.js';
import * as schema from '../schema.js';
/**
* Get all achievement definitions
* @returns Array of achievement definitions
*/
export async function getAllAchievements(): Promise<
schema.achievementDefinitionsTableTypes[]
> {
try {
await ensureDbInitialized();
if (!db) {
console.error('Database not initialized, cannot get achievements');
return [];
}
return await db
.select()
.from(schema.achievementDefinitionsTable)
.orderBy(schema.achievementDefinitionsTable.threshold);
} catch (error) {
return handleDbError('Failed to get all achievements', error as Error);
}
}
/**
* Get achievements for a specific user
* @param userId - Discord ID of the user
* @returns Array of user achievements
*/
export async function getUserAchievements(
userId: string,
): Promise<schema.userAchievementsTableTypes[]> {
try {
await ensureDbInitialized();
if (!db) {
console.error('Database not initialized, cannot get user achievements');
return [];
}
return await db
.select({
id: schema.userAchievementsTable.id,
discordId: schema.userAchievementsTable.discordId,
achievementId: schema.userAchievementsTable.achievementId,
earnedAt: schema.userAchievementsTable.earnedAt,
progress: schema.userAchievementsTable.progress,
})
.from(schema.userAchievementsTable)
.where(eq(schema.userAchievementsTable.discordId, userId));
} catch (error) {
return handleDbError('Failed to get user achievements', error as Error);
}
}
/**
* Award an achievement to a user
* @param userId - Discord ID of the user
* @param achievementId - ID of the achievement
* @returns Boolean indicating success
*/
export async function awardAchievement(
userId: string,
achievementId: number,
): Promise<boolean> {
try {
await ensureDbInitialized();
if (!db) {
console.error('Database not initialized, cannot award achievement');
return false;
}
const existing = await db
.select()
.from(schema.userAchievementsTable)
.where(
and(
eq(schema.userAchievementsTable.discordId, userId),
eq(schema.userAchievementsTable.achievementId, achievementId),
),
)
.then((rows) => rows[0]);
if (existing) {
if (existing.earnedAt) {
return false;
}
await db
.update(schema.userAchievementsTable)
.set({
earnedAt: new Date(),
progress: 100,
})
.where(eq(schema.userAchievementsTable.id, existing.id));
} else {
await db.insert(schema.userAchievementsTable).values({
discordId: userId,
achievementId: achievementId,
earnedAt: new Date(),
progress: 100,
});
}
return true;
} catch (error) {
handleDbError('Failed to award achievement', error as Error);
return false;
}
}
/**
* Update achievement progress for a user
* @param userId - Discord ID of the user
* @param achievementId - ID of the achievement
* @param progress - Progress value (0-100)
* @returns Boolean indicating success
*/
export async function updateAchievementProgress(
userId: string,
achievementId: number,
progress: number,
): Promise<boolean> {
try {
await ensureDbInitialized();
if (!db) {
console.error(
'Database not initialized, cannot update achievement progress',
);
return false;
}
const existing = await db
.select()
.from(schema.userAchievementsTable)
.where(
and(
eq(schema.userAchievementsTable.discordId, userId),
eq(schema.userAchievementsTable.achievementId, achievementId),
),
)
.then((rows) => rows[0]);
if (existing) {
await db
.update(schema.userAchievementsTable)
.set({ progress })
.where(eq(schema.userAchievementsTable.id, existing.id));
} else {
await db.insert(schema.userAchievementsTable).values({
discordId: userId,
achievementId,
progress,
});
}
return true;
} catch (error) {
handleDbError('Failed to update achievement progress', error as Error);
return false;
}
}
/**
* Create a new achievement definition
* @param achievementData - Achievement definition data
* @returns Created achievement or undefined on failure
*/
export async function createAchievement(achievementData: {
name: string;
description: string;
imageUrl?: string;
requirementType: string;
threshold: number;
requirement?: any;
rewardType?: string;
rewardValue?: string;
}): Promise<schema.achievementDefinitionsTableTypes | undefined> {
try {
await ensureDbInitialized();
if (!db) {
console.error('Database not initialized, cannot create achievement');
return undefined;
}
const [achievement] = await db
.insert(schema.achievementDefinitionsTable)
.values({
name: achievementData.name,
description: achievementData.description,
imageUrl: achievementData.imageUrl || null,
requirementType: achievementData.requirementType,
threshold: achievementData.threshold,
requirement: achievementData.requirement || {},
rewardType: achievementData.rewardType || null,
rewardValue: achievementData.rewardValue || null,
})
.returning();
return achievement;
} catch (error) {
return handleDbError('Failed to create achievement', error as Error);
}
}
/**
* Delete an achievement definition
* @param achievementId - ID of the achievement to delete
* @returns Boolean indicating success
*/
export async function deleteAchievement(
achievementId: number,
): Promise<boolean> {
try {
await ensureDbInitialized();
if (!db) {
console.error('Database not initialized, cannot delete achievement');
return false;
}
await db
.delete(schema.userAchievementsTable)
.where(eq(schema.userAchievementsTable.achievementId, achievementId));
await db
.delete(schema.achievementDefinitionsTable)
.where(eq(schema.achievementDefinitionsTable.id, achievementId));
return true;
} catch (error) {
handleDbError('Failed to delete achievement', error as Error);
return false;
}
}
/**
* Removes an achievement from a user
* @param discordId - Discord user ID
* @param achievementId - Achievement ID to remove
* @returns boolean indicating success
*/
export async function removeUserAchievement(
discordId: string,
achievementId: number,
): Promise<boolean> {
try {
await ensureDbInitialized();
if (!db) {
console.error('Database not initialized, cannot remove user achievement');
return false;
}
await db
.delete(schema.userAchievementsTable)
.where(
and(
eq(schema.userAchievementsTable.discordId, discordId),
eq(schema.userAchievementsTable.achievementId, achievementId),
),
);
return true;
} catch (error) {
handleDbError('Failed to remove user achievement', error as Error);
return false;
}
}