Skip to content

Commit

Permalink
feat: user & airing anime mongoose models & services
Browse files Browse the repository at this point in the history
  • Loading branch information
skuzow committed Sep 25, 2023
1 parent f015c6f commit 1b06659
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/models/AiringAnime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { model, Schema, Types } from 'mongoose';

export interface IAiringAnime {
name: string;
episode: number;
airingDate: Date;
subscribers: Types.ObjectId[];
}

const airingAnimeSchema = new Schema<IAiringAnime>({
name: { type: String, required: true, unique: true },
episode: { type: Number, required: true },
airingDate: { type: Date, required: true },
subscribers: [
{
type: Schema.Types.ObjectId,
ref: 'User',
required: true
}
]
});

export default model<IAiringAnime>('AiringAnime', airingAnimeSchema);
25 changes: 25 additions & 0 deletions src/models/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { model, Schema } from 'mongoose';
import { unSuscribeUserFromAiringAnimes } from '../services/airingAnimeService.js';

export interface IUser {
discordId: string;
anilistUsername: string;
}

const userSchema = new Schema<IUser>({
discordId: { type: String, required: true, unique: true },
anilistUsername: { type: String, required: true }
});

userSchema.pre(
'deleteOne',
{ document: false, query: true },
async function (next) {
const doc = await this.model.findOne(this.getFilter());
const userId = doc._id;
unSuscribeUserFromAiringAnimes(userId);
next();
}
);

export default model<IUser>('User', userSchema);
73 changes: 73 additions & 0 deletions src/services/airingAnimeService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { HydratedDocument } from 'mongoose';
import AiringAnime, { IAiringAnime } from '../models/AiringAnime.js';
import { AnimeEntry } from '../types/Anilist.js';
import { IUser } from '../models/User.js';

export async function createAiringAnime(
anime: AnimeEntry
): Promise<HydratedDocument<IAiringAnime>> {
return await AiringAnime.create({
name: anime.media.title.english,
episode: anime.media.nextAiringEpisode?.episode,
airingDate: generateAiringDate(anime.media.nextAiringEpisode?.airingAt || 0)
});
}

function generateAiringDate(airingAt: number): Date {
return new Date(airingAt * 1000);
}

export async function deleteAiringAnime(name: string) {
await AiringAnime.deleteOne({ name: name });
}

export async function getAiringAnime(
name: string
): Promise<HydratedDocument<IAiringAnime> | null> {
return await AiringAnime.findOne({ name: name });
}

export async function getOrCreateAiringAnime(
anime: AnimeEntry
): Promise<HydratedDocument<IAiringAnime> | null> {
const animeTitle: string = anime.media.title.english;
if (await existAiringAnime(animeTitle)) {
return await getAiringAnime(animeTitle);
}
return await createAiringAnime(anime);
}

export async function existAiringAnime(name: string): Promise<boolean> {
return !!(await getAiringAnime(name));
}

export async function insertUserAiringAnimesData(
user: HydratedDocument<IUser>,
animes: AnimeEntry[]
) {
// Promise.all for async map
await Promise.all(
animes.map(async (anime: AnimeEntry) => {
const foundAnime: HydratedDocument<IAiringAnime> | null =
await getOrCreateAiringAnime(anime);
if (!foundAnime) return;
await subscribeUserToAiringAnime(foundAnime, user);
})
);
}

export async function subscribeUserToAiringAnime(
anime: HydratedDocument<IAiringAnime>,
user: HydratedDocument<IUser>
) {
if (anime.subscribers.includes(user._id)) return;
anime.subscribers.push(user._id);
await anime.save();
}

export async function unSuscribeUserFromAiringAnimes(userId: string) {
await AiringAnime.updateMany(
{ subscribers: userId },
{ $pull: { subscribers: userId } }
);
}
34 changes: 34 additions & 0 deletions src/services/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { HydratedDocument } from 'mongoose';
import User, { IUser } from '../models/User.js';

export async function createUser(
discordId: string,
anilistUsername: string
): Promise<HydratedDocument<IUser>> {
return await User.create({
discordId: discordId,
anilistUsername: anilistUsername
});
}

export async function deleteUser(discordId: string) {
await User.deleteOne({ discordId: discordId });
}

export async function getUser(
discordId: string
): Promise<HydratedDocument<IUser> | null> {
return await User.findOne({ discordId: discordId });
}

export async function getOrCreateUser(
discordId: string,
username: string
): Promise<HydratedDocument<IUser> | null> {
if (await existUser(discordId)) return await getUser(discordId);
return await createUser(discordId, username);
}

export async function existUser(discordId: string): Promise<boolean> {
return !!(await getUser(discordId));
}

0 comments on commit 1b06659

Please sign in to comment.