mnemo_cards/mnemo_cards_backend/lib/packs/pack_repository.dart

239 lines
7.7 KiB
Dart
Raw Normal View History

2026-01-08 16:07:56 +00:00
import 'package:drift/drift.dart';
import 'package:drift_postgres/drift_postgres.dart';
import 'package:injectable/injectable.dart';
import 'package:mnemo_cards_backend/database/database.dart';
import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart'
hide VoiceModel;
import 'card_pack_drift_extension.dart';
/// Extension для конвертации GameCard (Drift) в GameCardModel
extension GameCardToModel on GameCard {
GameCardModel toModel() {
return GameCardModel(
id: id,
image: image,
mnemo: mnemo ?? '',
original: original,
translation: translation,
transcription: transcription,
transcriptionMnemo: transcriptionMnemo,
imageBack: imageBack,
back: back,
);
}
}
/// Repository для работы с паками
/// Работает с доменными моделями (CardPackModel), использует DAO для доступа к БД
@lazySingleton
class PackRepository {
final AppDatabase _db;
PackRepository(this._db);
/// Получить пак по ID
/// [includeCards] - загружать ли связанные карточки
/// [includePreviewCards] - загружать ли превью карточки
Future<CardPackModel?> getPackById(
String id, {
bool includeCards = false,
bool includePreviewCards = false,
}) async {
final pack = await _db.packDao.getPackById(id);
if (pack == null) return null;
final packModel = await pack.toModel();
if (includeCards) {
final cards = await _db.packDao.getPackCards(id);
packModel.cards.addAll(cards.map((c) => c.toModel()));
}
if (includePreviewCards) {
final previewCards = await _db.packDao.getPreviewCards(id);
packModel.previewCards.addAll(previewCards.map((c) => c.toModel()));
}
return packModel;
}
/// Получить все паки
Future<List<CardPackModel>> getAllPacks({
bool enabledOnly = false,
String? orderByField,
bool orderDesc = false,
bool includeCards = false,
bool includePreviewCards = false,
}) async {
final packs = await _db.packDao.getAllPacks(
enabledOnly: enabledOnly,
orderByField: orderByField,
orderDesc: orderDesc,
);
if (includeCards || includePreviewCards) {
final packModels = <CardPackModel>[];
for (final pack in packs) {
final packModel = await pack.toModel();
if (includeCards) {
final cards = await _db.packDao.getPackCards(pack.id);
packModel.cards.addAll(cards.map((c) => c.toModel()));
}
if (includePreviewCards) {
final previewCards = await _db.packDao.getPreviewCards(pack.id);
packModel.previewCards.addAll(previewCards.map((c) => c.toModel()));
}
packModels.add(packModel);
}
return packModels;
}
return await Future.wait(packs.map((p) => p.toModel()));
}
/// Создать пак
Future<String> createPack(CardPackModel packModel) async {
final companion = CardPacksCompanion.insert(
title: packModel.title,
subtitle: packModel.subtitle,
size: packModel.size,
color: Value(packModel.color),
version: Value(packModel.version),
cover: Value(packModel.cover),
description: Value(packModel.description),
googlePlayId: Value(packModel.googlePlayId),
rustoreId: Value(packModel.rustoreId),
appStoreId: Value(packModel.appStoreId),
price: Value(packModel.price),
currency: packModel.currency != null
? Value(packModel.currency!)
: const Value.absent(),
enabled: Value(packModel.enabled),
order: Value(packModel.order),
cardsOrder: Value(packModel.cardsOrder),
);
return await _db.packDao.createPack(companion);
}
/// Обновить пак
Future<void> updatePack(CardPackModel packModel) async {
if (packModel.id == null) {
throw ArgumentError('Pack ID is required');
}
await _db.packDao.updatePackPartial(
CardPacksCompanion(
id: Value(packModel.id!),
title: Value(packModel.title),
subtitle: Value(packModel.subtitle),
size: Value(packModel.size),
color: Value(packModel.color),
version: Value(packModel.version),
cover: Value(packModel.cover),
description: Value(packModel.description),
googlePlayId: Value(packModel.googlePlayId),
rustoreId: Value(packModel.rustoreId),
appStoreId: Value(packModel.appStoreId),
price: Value(packModel.price),
currency: packModel.currency != null
? Value(packModel.currency!)
: const Value.absent(),
enabled: Value(packModel.enabled),
order: Value(packModel.order),
cardsOrder: Value(packModel.cardsOrder),
updatedAt: Value(PgDateTime(DateTime.now())),
),
);
}
/// Обновить пак частично
Future<void> updatePackPartial(CardPacksCompanion updates) async {
await _db.packDao.updatePackPartial(updates);
}
/// Удалить пак (soft delete)
Future<void> softDeletePack(String packId) async {
await _db.packDao.softDeletePack(packId);
}
/// Подсчитать паки
Future<int> countPacks({bool enabledOnly = false}) async {
return await _db.packDao.countPacks(enabledOnly: enabledOnly);
}
/// Получить карточки пака
Future<List<GameCardModel>> getPackCards(String packId) async {
final cards = await _db.packDao.getPackCards(packId);
return cards.map((c) => c.toModel()).toList();
}
/// Получить превью карточки пака
Future<List<GameCardModel>> getPreviewCards(String packId) async {
final cards = await _db.packDao.getPreviewCards(packId);
return cards.map((c) => c.toModel()).toList();
}
/// Получить карточку по ID
Future<GameCardModel?> getCardById(String id) async {
final card = await _db.packDao.getCardById(id);
return card?.toModel();
}
/// Получить паки для карточки
Future<List<CardPackModel>> getPacksForCard(String cardId) async {
final packs = await _db.packDao.getPacksForCard(cardId);
return await Future.wait(packs.map((p) => p.toModel()));
}
/// Добавить карточку в пак
Future<void> addCardToPack({
required String packId,
required String cardId,
int order = 0,
}) async {
await _db.packDao.addCardToPack(
packId: packId,
cardId: cardId,
order: order,
);
}
/// Удалить карточку из пака
Future<void> removeCardFromPack(String packId, String cardId) async {
await _db.packDao.removeCardFromPack(packId, cardId);
}
/// Обновить порядок карточек в паке
Future<void> updatePackCardsOrder(String packId, List<String> cardIds) async {
await _db.packDao.updatePackCardsOrder(packId, cardIds);
}
/// Установить preview карточки для пака
Future<void> setPreviewCards(String packId, List<String> cardIds) async {
await _db.packDao.setPreviewCards(packId, cardIds);
}
// ==================== VoiceModels ====================
/// Получить голосовые модели карточки
Future<List<VoiceModel>> getCardVoices(String cardId) async {
return await _db.packDao.getCardVoices(cardId);
}
/// Получить голосовую модель по ID
Future<VoiceModel?> getVoiceById(String id) async {
return await _db.packDao.getVoiceById(id);
}
/// Обновить путь/URL аудиофайла голосовой модели
Future<void> updateVoiceUrl(String voiceId, String voiceUrl) async {
await _db.packDao.updateVoiceUrl(voiceId, voiceUrl);
}
}