Source code for loglan_core.addons.key_selector

"""
This module provides the `KeySelector` class, which inherits from `Select`
and provides methods for filtering keys based on certain criteria.

The KeySelector class has methods to filter keys by event ID, key, and language.
Each method returns a new instance of KeySelector with the applied filters.

The KeySelector class is initialized with a class object and a boolean
indicating if it is being used with SQLite. The class object must be
a subclass of BaseKey.

Classes:
    KeySelector: A class used to select keys meeting certain criteria.

Example:
    key_selector = KeySelector(MyKeyClass)
    filtered_by_event = key_selector.by_event(1)
    filtered_by_key = key_selector.by_key('mykey')
    filtered_by_language = key_selector.by_language('English')

This allows for flexible and powerful querying of keys in a codebase.
"""

from __future__ import annotations

from typing import Type

from sqlalchemy import select

from loglan_core.relationships import t_connect_keys
from .base_selector import BaseSelector
from .filters import (
    filter_word_by_event_id,
    filter_key_by_word_cs,
    filter_key_by_language,
)
from ..definition import BaseDefinition
from ..key import BaseKey
from ..word import BaseWord


[docs] class KeySelector(BaseSelector): # pylint: disable=too-many-ancestors """ A class used to select keys meeting certain criteria. Attributes: model (Type[BaseKey]): The class to be used as the base key. Must be a subclass of BaseKey. is_sqlite (bool): If SQLite is being used. Defaults to False. case_sensitive (bool): If the queries should be case-sensitive. disable_model_check (bool): If the model check is disabled during initialization. """
[docs] def __init__( self, model: Type[BaseKey] = BaseKey, is_sqlite: bool = False, case_sensitive: bool = False, disable_model_check: bool = False, ) -> None: """ Initializes the KeySelector object with the provided parameters. Args: model (Type[BaseKey]): The class to be used as the base key. Must be a subclass of BaseKey. is_sqlite (bool): If SQLite is being used. Defaults to False. case_sensitive (bool): If the queries should be case-sensitive. disable_model_check (bool): If the model check is disabled during initialization. Raises: ValueError: If the provided model is not a subclass of BaseKey. """ super().__init__(model, is_sqlite, case_sensitive, disable_model_check) if not self.disable_model_check: self._is_model_accepted(model, BaseKey) self.model = model
[docs] def by_event(self, event_id: int | None = None) -> KeySelector: """ Filters the keys by the given event ID. Args: event_id (int | None): The identifier of the event to filter by. If None, no event filtering is applied. Returns: KeySelector: The filtered KeySelector instance. """ subquery = ( select(self.model.id) .join(t_connect_keys) .join(BaseDefinition) .join(BaseWord) .where(filter_word_by_event_id(event_id)) .scalar_subquery() ) self._statement = self._statement.where(self.model.id.in_(subquery)) return self
[docs] def by_key(self, key: str) -> KeySelector: """ Filters the keys by the given key. Args: key (str): The key to filter by. Returns: KeySelector: The filtered KeySelector instance. """ self._statement = self._statement.where( filter_key_by_word_cs(key, self.case_sensitive, self.is_sqlite) ) return self
[docs] def by_language(self, language: str | None = None) -> KeySelector: """ Filters the keys by the given language. Args: language (str | None): The language to filter by. If None, no language filtering is applied. Returns: KeySelector: The filtered KeySelector instance. """ self._statement = self._statement.where(filter_key_by_language(language)) return self
[docs] def by_word_id(self, word_id: int, distinct: bool = False) -> KeySelector: """ Filters the keys by the given word ID. Args: word_id (int): The identifier of the word to filter by. distinct (bool): If the query should be distinct. Defaults to False. Returns: KeySelector: The filtered KeySelector instance. Keep in mind that duplicated keys from related definitions will be counted with ```.count()``` but excluded from ```.all()``` request """ self._statement = ( self._statement.join(t_connect_keys) .join(BaseDefinition, BaseDefinition.id == t_connect_keys.c.DID) .join(BaseWord, BaseWord.id == BaseDefinition.word_id) .filter(BaseWord.id == word_id) .order_by(BaseKey.word.asc()) ) if distinct: self._statement = self._statement.distinct() return self