from typing import Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from database.exceptions.constraints import DuplicateInsertException from database.exceptions.not_found import NoResultFoundException from database.schemas import CustomCommand, CustomCommandAlias __all__ = [ "clean_name", "create_alias", "create_command", "edit_command", "get_command", "get_command_by_alias", "get_command_by_name", ] def clean_name(name: str) -> str: """Convert a name to lowercase & remove spaces to allow easier matching""" return name.lower().replace(" ", "") async def create_command(session: AsyncSession, name: str, response: str) -> CustomCommand: """Create a new custom command""" # Check if command or alias already exists command = await get_command(session, name) if command is not None: raise DuplicateInsertException command = CustomCommand(name=name, indexed_name=clean_name(name), response=response) session.add(command) await session.commit() return command async def create_alias(session: AsyncSession, command: str, alias: str) -> CustomCommandAlias: """Create an alias for a command""" # Check if the command exists command_instance = await get_command(session, command) if command_instance is None: raise NoResultFoundException # Check if the alias exists (either as an alias or as a name) if await get_command(session, alias) is not None: raise DuplicateInsertException alias_instance = CustomCommandAlias(alias=alias, indexed_alias=clean_name(alias), command=command_instance) session.add(alias_instance) await session.commit() return alias_instance async def get_command(session: AsyncSession, message: str) -> Optional[CustomCommand]: """Try to get a command out of a message""" # Search lowercase & without spaces message = clean_name(message) return (await get_command_by_name(session, message)) or (await get_command_by_alias(session, message)) async def get_command_by_name(session: AsyncSession, message: str) -> Optional[CustomCommand]: """Try to get a command by its name""" statement = select(CustomCommand).where(CustomCommand.indexed_name == message) return (await session.execute(statement)).scalar_one_or_none() async def get_command_by_alias(session: AsyncSession, message: str) -> Optional[CustomCommand]: """Try to get a command by its alias""" statement = select(CustomCommandAlias).where(CustomCommandAlias.indexed_alias == message) alias = (await session.execute(statement)).scalar_one_or_none() if alias is None: return None return alias.command async def edit_command( session: AsyncSession, original_name: str, new_name: Optional[str] = None, new_response: Optional[str] = None ) -> CustomCommand: """Edit an existing command""" # Check if the command exists command = await get_command(session, original_name) if command is None: raise NoResultFoundException if new_name is not None: command.name = new_name if new_response is not None: command.response = new_response session.add(command) await session.commit() return command