Мини-игры (/games): - Speed Round: 10 раундов, 10 секунд на ответ, очки за скорость - Match Pairs: 5 слов + 5 переводов, соединить пары Premium-функции: - Поля is_premium и premium_until для пользователей - AI режим проверки ответов (учитывает синонимы) - Batch проверка всех ответов одним запросом Улучшения: - Примеры использования для всех добавляемых слов - Разбиение переводов по запятой на отдельные записи - Полные предложения в контекстах (без ___) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
67 lines
2.4 KiB
Python
67 lines
2.4 KiB
Python
"""Rebuild word_translations table from vocabulary
|
||
|
||
Очищает word_translations и заново заполняет из vocabulary,
|
||
разбивая переводы по запятой/точке с запятой на отдельные записи.
|
||
|
||
Revision ID: 20251210_rebuild_translations
|
||
Revises: 20251210_is_premium
|
||
Create Date: 2025-12-10
|
||
|
||
"""
|
||
from typing import Sequence, Union
|
||
import re
|
||
|
||
from alembic import op
|
||
import sqlalchemy as sa
|
||
|
||
|
||
# revision identifiers, used by Alembic.
|
||
revision: str = '20251210_rebuild_translations'
|
||
down_revision: Union[str, None] = '20251210_is_premium'
|
||
branch_labels: Union[str, Sequence[str], None] = None
|
||
depends_on: Union[str, Sequence[str], None] = None
|
||
|
||
|
||
def upgrade() -> None:
|
||
# Получаем connection для выполнения SQL
|
||
connection = op.get_bind()
|
||
|
||
# 1. Очищаем таблицу word_translations
|
||
connection.execute(sa.text("DELETE FROM word_translations"))
|
||
|
||
# 2. Получаем все слова из vocabulary
|
||
result = connection.execute(sa.text(
|
||
"SELECT id, word_translation FROM vocabulary WHERE word_translation IS NOT NULL AND word_translation != ''"
|
||
))
|
||
|
||
# 3. Для каждого слова разбиваем перевод и вставляем
|
||
for row in result:
|
||
vocab_id = row[0]
|
||
translation_str = row[1]
|
||
|
||
if not translation_str:
|
||
continue
|
||
|
||
# Разбиваем по запятой или точке с запятой
|
||
parts = re.split(r'[,;]\s*', translation_str)
|
||
translations = [p.strip() for p in parts if p.strip()]
|
||
|
||
for i, translation in enumerate(translations):
|
||
is_primary = (i == 0) # Первый перевод - основной
|
||
connection.execute(
|
||
sa.text(
|
||
"INSERT INTO word_translations (vocabulary_id, translation, is_primary, created_at) "
|
||
"VALUES (:vocab_id, :translation, :is_primary, CURRENT_TIMESTAMP)"
|
||
),
|
||
{"vocab_id": vocab_id, "translation": translation, "is_primary": is_primary}
|
||
)
|
||
|
||
print(f"Word translations rebuilt successfully")
|
||
|
||
|
||
def downgrade() -> None:
|
||
# При откате просто очищаем таблицу
|
||
# (восстановить старые данные невозможно)
|
||
connection = op.get_bind()
|
||
connection.execute(sa.text("DELETE FROM word_translations"))
|