Improved query & filtering

This commit is contained in:
Sven Heidemann 2023-01-07 15:53:44 +01:00
parent 7a836a7f59
commit ce85bb332a
7 changed files with 122 additions and 20 deletions

View File

@ -1,6 +1,9 @@
import functools import functools
from abc import ABC from abc import ABC
from inspect import signature, Parameter from inspect import signature, Parameter
from typing import Optional
from cpl_query.extension import List
class FilterABC(ABC): class FilterABC(ABC):
@ -8,33 +11,41 @@ class FilterABC(ABC):
def __init__(self): def __init__(self):
ABC.__init__(self) ABC.__init__(self)
self._page_index = 0 self._page_index = None
self._page_size = 10 self._page_size = None
self._sort_direction = '' self._sort_direction = None
self._sort_column = '' self._sort_column = None
@property @property
def page_index(self) -> int: def page_index(self) -> Optional[int]:
return self._page_index return self._page_index
@property @property
def page_size(self) -> int: def page_size(self) -> Optional[int]:
return self._page_size return self._page_size
@property @property
def sort_direction(self) -> str: def sort_direction(self) -> Optional[str]:
return self._sort_direction return self._sort_direction
@property @property
def sort_column(self) -> str: def sort_column(self) -> Optional[str]:
return self._sort_column return self._sort_column
def skip_and_take(self, query: List):
if self._page_size is not None and self.page_index is not None:
skip = self.page_size * self.page_index
result = query.skip(skip).take(self.page_size)
return result
return query
@staticmethod @staticmethod
def get_filter(f, values: dict): def get_filter(f, values: dict):
sig = signature(f) sig = signature(f)
for param in sig.parameters.items(): for param in sig.parameters.items():
parameter = param[1] parameter = param[1]
if parameter.name == 'self' or parameter.annotation == Parameter.empty: if parameter.name == 'self' or parameter.name == 'cls' or parameter.annotation == Parameter.empty:
continue continue
if issubclass(parameter.annotation, FilterABC): if issubclass(parameter.annotation, FilterABC):
@ -45,7 +56,7 @@ class FilterABC(ABC):
@classmethod @classmethod
def resolve_filter_annotation(cls, f=None): def resolve_filter_annotation(cls, f=None):
if f is None: if f is None:
return functools.partial(cls.filter) return functools.partial(cls.resolve_filter_annotation)
@functools.wraps(f) @functools.wraps(f)
def decorator(*args, **kwargs): def decorator(*args, **kwargs):

View File

@ -0,0 +1,37 @@
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_discord.container import Guild
from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from bot_data.model.level import Level
from bot_data.model.server import Server
from bot_graphql.abc.filter_abc import FilterABC
class LevelFilter(FilterABC):
def __init__(self):
FilterABC.__init__(self)
self._id = None
self._name = None
# self._server_id = None
def from_dict(self, values: dict):
if 'id' in values:
self._id = values['id']
def filter(self, query: List[Level]) -> List[Level]:
if self._id is not None:
query = query.where(lambda x: x.id == self._id)
if self._name is not None:
query = query.where(lambda x: self._name.lower() == x.name.lower() or self._name.lower() in x.name.lower())
# if self._server_id is not None:
# query = query.where(lambda x: x.server.server_id == self._server_id)
skip = self.page_size * self.page_index
result = query.skip(skip).take(self.page_size)
return result

View File

@ -18,12 +18,10 @@ class ServerFilter(FilterABC):
def from_dict(self, values: dict): def from_dict(self, values: dict):
if 'id' in values: if 'id' in values:
self._id = values['id'] self._id = int(values['id'])
@ServiceProviderABC.inject @ServiceProviderABC.inject
def filter(self, query: List[Server], bot: DiscordBotServiceABC) -> List[Server]: def filter(self, query: List[Server], bot: DiscordBotServiceABC) -> List[Server]:
result = List(Server)
if self._id is not None: if self._id is not None:
query = query.where(lambda x: x.server_id == self._id) query = query.where(lambda x: x.server_id == self._id)
@ -37,7 +35,4 @@ class ServerFilter(FilterABC):
query = query.where(where_guild) query = query.where(where_guild)
skip = self.page_size * self.page_index return self.skip_and_take(query)
result = query.skip(skip).take(self.page_size)
return result

View File

@ -8,6 +8,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_data.service.seeder_service import SeederService from bot_data.service.seeder_service import SeederService
from bot_graphql.abc.query_abc import QueryABC from bot_graphql.abc.query_abc import QueryABC
from bot_graphql.graphql_service import GraphQLService from bot_graphql.graphql_service import GraphQLService
from bot_graphql.queries.level_query import LevelQuery
from bot_graphql.queries.server_query import ServerQuery from bot_graphql.queries.server_query import ServerQuery
from bot_graphql.query import Query from bot_graphql.query import Query
from bot_graphql.schema import Schema from bot_graphql.schema import Schema
@ -27,5 +28,6 @@ class GraphQLModule(ModuleABC):
services.add_singleton(GraphQLService) services.add_singleton(GraphQLService)
services.add_singleton(Query) services.add_singleton(Query)
services.add_transient(QueryABC, ServerQuery) services.add_transient(QueryABC, ServerQuery)
services.add_transient(QueryABC, LevelQuery)
services.add_transient(SeederService) services.add_transient(SeederService)

View File

@ -10,7 +10,7 @@ interface TableQuery {
} }
input ServerFilter { input ServerFilter {
id: Int id: ID
discord_id: String discord_id: String
name: String name: String
@ -26,7 +26,7 @@ type Server implements TableQuery {
name: String name: String
clients: [Client] clients: [Client]
members: [User] members: [User]
level: [Level] levels: [Level]
created_at: String created_at: String
modified_at: String modified_at: String
@ -86,6 +86,11 @@ type UserJoinedVoiceChannel implements TableQuery {
modified_at: String modified_at: String
} }
input LevelFilter {
id: ID
name: String
}
type Level implements TableQuery { type Level implements TableQuery {
id: ID id: ID
name: String name: String

View File

@ -0,0 +1,39 @@
from bot_data.model.level import Level
from bot_graphql.abc.data_query_abc import DataQueryABC
class LevelQuery(DataQueryABC):
def __init__(self):
DataQueryABC.__init__(self, 'Level')
self.set_field('id', self.resolve_id)
self.set_field('name', self.resolve_name)
self.set_field('color', self.resolve_color)
self.set_field('min_xp', self.resolve_min_xp)
self.set_field('permissions', self.resolve_permissions)
self.set_field('server', self.resolve_server)
@staticmethod
def resolve_id(level: Level, *_):
return level.id
@staticmethod
def resolve_name(level: Level, *_):
return level.name
@staticmethod
def resolve_color(level: Level, *_):
return level.color
@staticmethod
def resolve_min_xp(level: Level, *_):
return level.min_xp
@staticmethod
def resolve_permissions(level: Level, *_):
return level.permissions
@staticmethod
def resolve_server(level: Level, *_):
return level.server

View File

@ -1,22 +1,28 @@
from cpl_discord.service import DiscordBotServiceABC from cpl_discord.service import DiscordBotServiceABC
from bot_data.abc.level_repository_abc import LevelRepositoryABC
from bot_data.model.server import Server from bot_data.model.server import Server
from bot_graphql.abc.data_query_abc import DataQueryABC from bot_graphql.abc.data_query_abc import DataQueryABC
from bot_graphql.abc.filter_abc import FilterABC
from bot_graphql.filter.level_filter import LevelFilter
class ServerQuery(DataQueryABC): class ServerQuery(DataQueryABC):
def __init__( def __init__(
self, self,
bot: DiscordBotServiceABC bot: DiscordBotServiceABC,
levels: LevelRepositoryABC,
): ):
DataQueryABC.__init__(self, 'Server') DataQueryABC.__init__(self, 'Server')
self._bot = bot self._bot = bot
self._levels = levels
self.set_field('id', self.resolve_id) self.set_field('id', self.resolve_id)
self.set_field('discord_id', self.resolve_discord_id) self.set_field('discord_id', self.resolve_discord_id)
self.set_field('name', self.resolve_name) self.set_field('name', self.resolve_name)
self.set_field('levels', self.resolve_levels)
@staticmethod @staticmethod
def resolve_id(server: Server, *_): def resolve_id(server: Server, *_):
@ -29,3 +35,10 @@ class ServerQuery(DataQueryABC):
def resolve_name(self, server: Server, *_): def resolve_name(self, server: Server, *_):
guild = self._bot.get_guild(server.discord_server_id) guild = self._bot.get_guild(server.discord_server_id)
return None if guild is None else guild.name return None if guild is None else guild.name
@FilterABC.resolve_filter_annotation
def resolve_levels(self, server: Server, *_, filter: LevelFilter = None):
if filter is not None:
return filter.filter(self._levels.get_levels_by_server_id(server.server_id))
return self._levels.get_levels_by_server_id(server.server_id)