# #region DictionaryEntryCRUD [C:3] [TYPE Class] [SEMANTICS dictionary, entries, crud] # @BRIEF CRUD operations for DictionaryEntry records. # @RELATION DEPENDS_ON -> [DictionaryEntry] # @RELATION DEPENDS_ON -> [TerminologyDictionary] from sqlalchemy import func from sqlalchemy.orm import Session from ...core.logger import belief_scope, logger from ...models.translate import DictionaryEntry, TerminologyDictionary from .[EXT:internal:_utils] import _normalize_term from .dictionary_validation import _validate_bcp47 class DictionaryEntryCRUD: """CRUD operations for dictionary entries.""" # region add_entry [TYPE Function] # @PURPOSE: Add an entry to a dictionary with language-pair-aware uniqueness validation. @staticmethod def add_entry( db: Session, dict_id: str, source_term: str, target_term: str, context_notes: str | None = None, source_language: str = "und", target_language: str = "und", ) -> DictionaryEntry: with belief_scope("DictionaryEntryCRUD.add_entry"): _validate_bcp47(source_language, "source_language") _validate_bcp47(target_language, "target_language") normalized = _normalize_term(source_term) existing = ( db.query(DictionaryEntry) .filter( DictionaryEntry.dictionary_id == dict_id, DictionaryEntry.source_term_normalized == normalized, DictionaryEntry.source_language == source_language, DictionaryEntry.target_language == target_language, ) .first() ) if existing: raise ValueError( f"Duplicate entry: '{source_term}' (lang: {source_language}→{target_language}) " f"already exists in this dictionary (id={existing.id}). " "Use overwrite or keep_existing conflict mode." ) logger.reason("Adding dictionary entry", {"dict_id": dict_id, "term": source_term}) entry = DictionaryEntry( dictionary_id=dict_id, source_term=source_term.strip(), source_term_normalized=normalized, target_term=target_term.strip(), context_notes=context_notes.strip() if context_notes else None, source_language=source_language.strip(), target_language=target_language.strip(), ) db.add(entry) db.commit() db.refresh(entry) logger.reflect("Entry added", {"entry_id": entry.id}) return entry # endregion add_entry # region edit_entry [TYPE Function] # @PURPOSE: Edit an existing dictionary entry with language-pair-aware duplicate check. @staticmethod def edit_entry( db: Session, entry_id: str, source_term: str | None = None, target_term: str | None = None, context_notes: str | None = None, source_language: str | None = None, target_language: str | None = None, ) -> DictionaryEntry: with belief_scope("DictionaryEntryCRUD.edit_entry"): entry = db.query(DictionaryEntry).filter(DictionaryEntry.id == entry_id).first() if not entry: raise ValueError(f"Entry not found: {entry_id}") logger.reason("Editing dictionary entry", {"entry_id": entry_id}) if source_language is not None: _validate_bcp47(source_language, "source_language") entry.source_language = source_language.strip() if target_language is not None: _validate_bcp47(target_language, "target_language") entry.target_language = target_language.strip() if source_term is not None: normalized = _normalize_term(source_term) existing = ( db.query(DictionaryEntry) .filter( DictionaryEntry.dictionary_id == entry.dictionary_id, DictionaryEntry.source_term_normalized == normalized, DictionaryEntry.source_language == entry.source_language, DictionaryEntry.target_language == entry.target_language, DictionaryEntry.id != entry_id, ) .first() ) if existing: raise ValueError(f"Duplicate entry: '{source_term}' already exists in this dictionary (id={existing.id}).") entry.source_term = source_term.strip() entry.source_term_normalized = normalized if target_term is not None: entry.target_term = target_term.strip() if context_notes is not None: entry.context_notes = context_notes.strip() if context_notes else None db.commit() db.refresh(entry) logger.reflect("Entry updated", {"entry_id": entry.id}) return entry # endregion edit_entry # region delete_entry [TYPE Function] # @PURPOSE: Delete a single dictionary entry. @staticmethod def delete_entry(db: Session, entry_id: str) -> None: with belief_scope("DictionaryEntryCRUD.delete_entry"): entry = db.query(DictionaryEntry).filter(DictionaryEntry.id == entry_id).first() if not entry: raise ValueError(f"Entry not found: {entry_id}") logger.reason("Deleting dictionary entry", {"entry_id": entry_id}) db.delete(entry) db.commit() logger.reflect("Entry deleted", {"entry_id": entry_id}) # endregion delete_entry # region clear_entries [TYPE Function] # @PURPOSE: Delete all entries for a dictionary. @staticmethod def clear_entries(db: Session, dict_id: str) -> int: with belief_scope("DictionaryEntryCRUD.clear_entries"): dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first() if not dictionary: raise ValueError(f"Dictionary not found: {dict_id}") logger.reason("Clearing all entries", {"dict_id": dict_id}) deleted = db.query(DictionaryEntry).filter(DictionaryEntry.dictionary_id == dict_id).delete() db.commit() logger.reflect("Entries cleared", {"dict_id": dict_id, "count": deleted}) return deleted # endregion clear_entries # region list_entries [TYPE Function] # @PURPOSE: List entries for a dictionary with pagination. @staticmethod def list_entries( db: Session, dict_id: str, page: int = 1, page_size: int = 50, ) -> tuple[list[DictionaryEntry], int]: total = ( db.query(func.count(DictionaryEntry.id)) .filter(DictionaryEntry.dictionary_id == dict_id) .scalar() or 0 ) entries = ( db.query(DictionaryEntry) .filter(DictionaryEntry.dictionary_id == dict_id) .order_by(DictionaryEntry.source_term.asc()) .offset((page - 1) * page_size) .limit(page_size) .all() ) return entries, total # endregion list_entries # #endregion DictionaryEntryCRUD