diff --git a/bot/handlers/common/routing.py b/bot/handlers/common/routing.py index 59298f9..caa79ce 100644 --- a/bot/handlers/common/routing.py +++ b/bot/handlers/common/routing.py @@ -52,9 +52,7 @@ async def route_callback(message: Message | CallbackQuery, back: bool = True, ** app: "QBotApp" = kwargs["app"] cmd = app.bot_commands.get(context.user_command.split("&")[0]) - await user_handler.cammand_handler( - message=message, cmd=cmd, **kwargs - ) + await user_handler.cammand_handler(message=message, cmd=cmd, **kwargs) else: raise ValueError(f"Unknown command {context.command}") else: diff --git a/bot/handlers/editors/main_callbacks.py b/bot/handlers/editors/main_callbacks.py index 60290a4..fd7cdd3 100644 --- a/bot/handlers/editors/main_callbacks.py +++ b/bot/handlers/editors/main_callbacks.py @@ -339,7 +339,7 @@ async def process_field_edit_callback(message: Message | CallbackQuery, **kwargs } ) - cmd=app.bot_commands.get(callback_data.user_command.split("&")[0]) + cmd = app.bot_commands.get(callback_data.user_command.split("&")[0]) return await cammand_handler(message=message, cmd=cmd, **kwargs) diff --git a/bot/handlers/forms/entity_form.py b/bot/handlers/forms/entity_form.py index 4bb76ca..076f195 100644 --- a/bot/handlers/forms/entity_form.py +++ b/bot/handlers/forms/entity_form.py @@ -166,12 +166,11 @@ async def entity_item( ) elif isinstance(button, InlineButton): - if isinstance(button.inline_button, InlineKeyboardButton): btn_row.append(button.inline_button) elif callable(button.inline_button): btn_row.append(button.inline_button(entity_item)) - + if btn_row: keyboard_builder.row(*btn_row) @@ -238,11 +237,19 @@ async def entity_item( field_caption = get_callable_str( field_descriptor.caption, field_descriptor, entity_item ) - value = get_value_repr( - value=getattr(entity_item, field_descriptor.name), - field_descriptor=field_descriptor, - locale=user.lang, - ) + if field_descriptor.caption_value: + value = get_callable_str( + field_descriptor.caption_value, + field_descriptor, + entity_item, + getattr(entity_item, field_descriptor.field_name), + ) + else: + value = get_value_repr( + value=getattr(entity_item, field_descriptor.field_name), + field_descriptor=field_descriptor, + locale=user.lang, + ) item_text += f"\n{field_caption or field_descriptor.name}:{f' {value}' if value else ''}" context = pop_navigation_context(navigation_stack) diff --git a/bot/handlers/user_handlers/main.py b/bot/handlers/user_handlers/main.py index be76459..cd4bd90 100644 --- a/bot/handlers/user_handlers/main.py +++ b/bot/handlers/user_handlers/main.py @@ -37,7 +37,9 @@ async def command_text(message: Message, **kwargs): state_data = await state.get_data() kwargs["state_data"] = state_data - await process_command_handler(message=message, callback_data=callback_data, **kwargs) + await process_command_handler( + message=message, callback_data=callback_data, **kwargs + ) @router.callback_query(ContextData.filter(F.command == CallbackCommand.USER_COMMAND)) @@ -50,7 +52,6 @@ async def command_callback(message: CallbackQuery, **kwargs): async def process_command_handler(message: Message | CallbackQuery, **kwargs): - state_data: dict = kwargs["state_data"] callback_data: ContextData = kwargs["callback_data"] app: "QBotApp" = kwargs["app"] diff --git a/model/bot_entity.py b/model/bot_entity.py index 99142fa..22ad7cf 100644 --- a/model/bot_entity.py +++ b/model/bot_entity.py @@ -11,12 +11,13 @@ from typing import ( TYPE_CHECKING, ) from pydantic import BaseModel -from sqlmodel import SQLModel, BigInteger, Field, select, func, column +from sqlmodel import SQLModel, BigInteger, Field, select, func, column, col from sqlmodel.ext.asyncio.session import AsyncSession from sqlmodel.sql.expression import SelectOfScalar from sqlmodel.main import SQLModelMetaclass, RelationshipInfo + from .descriptors import EntityDescriptor, EntityField, FieldDescriptor, Filter from .entity_metadata import EntityMetadata from . import session_dep @@ -233,30 +234,33 @@ class BotEntity[CreateSchemaType: BaseModel, UpdateSchemaType: BaseModel]( cls, select_statement: SelectOfScalar[Self], static_filter: list[Filter] ): for sfilt in static_filter: + column = col(getattr(cls, sfilt.field_name)) if sfilt.operator == "==": - condition = column(sfilt.field_name).__eq__(sfilt.value) + condition = column.__eq__(sfilt.value) elif sfilt.operator == "!=": - condition = column(sfilt.field_name).__ne__(sfilt.value) + condition = column.__ne__(sfilt.value) elif sfilt.operator == "<": - condition = column(sfilt.field_name).__lt__(sfilt.value) + condition = column.__lt__(sfilt.value) elif sfilt.operator == "<=": - condition = column(sfilt.field_name).__le__(sfilt.value) + condition = column.__le__(sfilt.value) elif sfilt.operator == ">": - condition = column(sfilt.field_name).__gt__(sfilt.value) + condition = column.__gt__(sfilt.value) elif sfilt.operator == ">=": - condition = column(sfilt.field_name).__ge__(sfilt.value) + condition = column.__ge__(sfilt.value) elif sfilt.operator == "ilike": - condition = column(sfilt.field_name).ilike(f"%{sfilt.value}%") + condition = column.ilike(f"%{sfilt.value}%") elif sfilt.operator == "like": - condition = column(sfilt.field_name).like(f"%{sfilt.value}%") + condition = column.like(f"%{sfilt.value}%") elif sfilt.operator == "in": - condition = column(sfilt.field_name).in_(sfilt.value) + condition = column.in_(sfilt.value) elif sfilt.operator == "not in": - condition = column(sfilt.field_name).notin_(sfilt.value) - elif sfilt.operator == "is": - condition = column(sfilt.field_name).is_(None) - elif sfilt.operator == "is not": - condition = column(sfilt.field_name).isnot(None) + condition = column.notin_(sfilt.value) + elif sfilt.operator == "is none": + condition = column.is_(None) + elif sfilt.operator == "is not none": + condition = column.isnot(None) + elif sfilt.operator == "contains": + condition = sfilt.value == column.any_() else: condition = None if condition is not None: diff --git a/model/descriptors.py b/model/descriptors.py index df369de..b3bc1f0 100644 --- a/model/descriptors.py +++ b/model/descriptors.py @@ -55,10 +55,11 @@ class Filter: "not in", "like", "ilike", - "is", - "is not", + "is none", + "is not none", + "contains", ] - value_type: Literal["const", "param"] + value_type: Literal["const", "param"] = "const" value: Any | None = None param_index: int | None = None