/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see .
*/
import type {MemeID, UserID} from '@fluxer/api/src/BrandedTypes';
import {BatchBuilder, fetchMany, fetchOne, upsertOne} from '@fluxer/api/src/database/Cassandra';
import type {FavoriteMemeRow} from '@fluxer/api/src/database/types/UserTypes';
import {
type CreateFavoriteMemeParams,
IFavoriteMemeRepository,
} from '@fluxer/api/src/favorite_meme/IFavoriteMemeRepository';
import {FavoriteMeme} from '@fluxer/api/src/models/FavoriteMeme';
import {FavoriteMemes, FavoriteMemesByMemeId} from '@fluxer/api/src/Tables';
const FETCH_FAVORITE_MEME_CQL = FavoriteMemes.selectCql({
where: [FavoriteMemes.where.eq('user_id'), FavoriteMemes.where.eq('meme_id')],
limit: 1,
});
const FETCH_FAVORITE_MEMES_BY_USER_CQL = FavoriteMemes.selectCql({
where: FavoriteMemes.where.eq('user_id'),
});
const COUNT_FAVORITE_MEMES_CQL = FavoriteMemes.selectCountCql({
where: FavoriteMemes.where.eq('user_id'),
});
export class FavoriteMemeRepository extends IFavoriteMemeRepository {
async findById(userId: UserID, memeId: MemeID): Promise {
const meme = await fetchOne(FETCH_FAVORITE_MEME_CQL, {
user_id: userId,
meme_id: memeId,
});
return meme ? new FavoriteMeme(meme) : null;
}
async findByUserId(userId: UserID): Promise> {
const memes = await fetchMany(FETCH_FAVORITE_MEMES_BY_USER_CQL, {user_id: userId});
return memes.map((meme) => new FavoriteMeme(meme));
}
async count(userId: UserID): Promise {
const result = await fetchOne<{count: bigint}>(COUNT_FAVORITE_MEMES_CQL, {user_id: userId});
return result ? Number(result.count) : 0;
}
async create(data: CreateFavoriteMemeParams): Promise {
const memeRow: FavoriteMemeRow = {
user_id: data.user_id,
meme_id: data.meme_id,
name: data.name,
alt_text: data.alt_text ?? null,
tags: data.tags ?? [],
attachment_id: data.attachment_id,
filename: data.filename,
content_type: data.content_type,
content_hash: data.content_hash ?? null,
size: data.size,
width: data.width ?? null,
height: data.height ?? null,
duration: data.duration ?? null,
is_gifv: data.is_gifv ?? false,
klipy_slug: data.klipy_slug ?? null,
tenor_id_str: data.tenor_slug_id ?? null,
version: 1,
};
const batch = new BatchBuilder();
batch.addPrepared(FavoriteMemes.upsertAll(memeRow));
batch.addPrepared(
FavoriteMemesByMemeId.upsertAll({
meme_id: memeRow.meme_id,
user_id: memeRow.user_id,
}),
);
await batch.execute();
return new FavoriteMeme(memeRow);
}
async update(userId: UserID, memeId: MemeID, data: CreateFavoriteMemeParams): Promise {
const memeRow: FavoriteMemeRow = {
user_id: userId,
meme_id: memeId,
name: data.name,
alt_text: data.alt_text ?? null,
tags: data.tags ?? [],
attachment_id: data.attachment_id,
filename: data.filename,
content_type: data.content_type,
content_hash: data.content_hash ?? null,
size: data.size,
width: data.width ?? null,
height: data.height ?? null,
duration: data.duration ?? null,
is_gifv: data.is_gifv ?? false,
klipy_slug: data.klipy_slug ?? null,
tenor_id_str: data.tenor_slug_id ?? null,
version: 1,
};
await upsertOne(FavoriteMemes.upsertAll(memeRow));
return new FavoriteMeme(memeRow);
}
async delete(userId: UserID, memeId: MemeID): Promise {
const batch = new BatchBuilder();
batch.addPrepared(FavoriteMemes.deleteByPk({user_id: userId, meme_id: memeId}));
batch.addPrepared(FavoriteMemesByMemeId.deleteByPk({meme_id: memeId, user_id: userId}));
await batch.execute();
}
async deleteAllByUserId(userId: UserID): Promise {
const memes = await this.findByUserId(userId);
for (const meme of memes) {
await this.delete(userId, meme.id);
}
}
}