Some checks failed
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Mobile App CI / test (push) Has been cancelled
Deploy Telegram Bot / Deploy Telegram Bot (push) Has been cancelled
Mobile App CI / build-android (push) Has been cancelled
Mobile App CI / build-ios (push) Has been cancelled
238 lines
7.7 KiB
Dart
238 lines
7.7 KiB
Dart
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);
|
||
}
|
||
}
|
||
|