Improved queries & filtering #162

This commit is contained in:
Sven Heidemann 2023-01-16 19:18:23 +01:00
parent 807827e30f
commit 16066864ed
25 changed files with 286 additions and 302 deletions

View File

@ -1,20 +0,0 @@
from datetime import datetime
from bot_graphql.abc.query_type_abc import QueryTypeABC
class DiscordQueryTypeABC(QueryTypeABC):
def __init__(
self,
id: str,
discord_id: str,
created_at: datetime = None,
modified_at: datetime = None,
):
QueryTypeABC.__init__(self, id, created_at, modified_at)
self._discord_id = discord_id
@property
def discord_id(self) -> str:
return self._discord_id

View File

@ -1,7 +1,6 @@
import functools
from abc import ABC, abstractmethod
from inspect import signature, Parameter
from typing import Optional
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_query.extension import List
@ -11,35 +10,6 @@ class FilterABC(ABC):
def __init__(self):
ABC.__init__(self)
self._page_index = None
self._page_size = None
self._sort_direction = None
self._sort_column = None
@property
def page_index(self) -> Optional[int]:
return self._page_index
@property
def page_size(self) -> Optional[int]:
return self._page_size
@property
def sort_direction(self) -> Optional[str]:
return self._sort_direction
@property
def sort_column(self) -> Optional[str]:
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
@abstractmethod
def from_dict(self, values: dict):
pass

View File

@ -4,6 +4,8 @@ from ariadne import ObjectType
from cpl_query.extension import List
from bot_graphql.abc.filter_abc import FilterABC
from bot_graphql.filter.page import Page
from bot_graphql.filter.sort import Sort
class QueryABC(ObjectType):
@ -19,12 +21,30 @@ class QueryABC(ObjectType):
else:
kwargs["filter"] = None
if "page" in kwargs:
page = Page()
page.from_dict(kwargs["page"])
kwargs["page"] = page
if "sort" in kwargs:
sort = Sort()
sort.from_dict(kwargs["sort"])
kwargs["sort"] = sort
return self._resolve_collection(get_collection(*args), *args, **kwargs)
self.set_field(f"{name}s", wrapper)
self.set_field(f"{name}_count", lambda *args: get_collection(*args).count())
def _resolve_collection(self, collection: List, *_, filter: FilterABC = None):
# @FilterABC.resolve_filter_annotation
def _resolve_collection(self, collection: List, *_, filter: FilterABC = None, page: Page = None, sort: Sort = None):
if filter is not None:
return filter.filter(collection)
if page is not None:
return page.filter(collection)
if sort is not None:
return sort.filter(collection)
return collection

View File

@ -1,29 +0,0 @@
from abc import ABC
from datetime import datetime
from typing import Optional
class QueryTypeABC(ABC):
def __init__(
self,
id: str,
created_at: datetime = None,
modified_at: datetime = None,
):
ABC.__init__(self)
self._id = id
self._created_at = created_at
self._modified_at = modified_at
@property
def id(self) -> str:
return self._id
@property
def created_at(self) -> Optional[datetime]:
return self._created_at
@property
def modified_at(self) -> Optional[datetime]:
return self._modified_at

View File

@ -35,4 +35,4 @@ class AutoRoleFilter(FilterABC):
# if self._server_id is not None:
# query = query.where(lambda x: x.server.server_id == self._server_id)
return self.skip_and_take(query)
return query

View File

@ -42,4 +42,4 @@ class AutoRoleRuleFilter(FilterABC):
# if self._server_id is not None:
# query = query.where(lambda x: x.server.server_id == self._server_id)
return self.skip_and_take(query)
return query

View File

@ -17,7 +17,7 @@ class LevelFilter(FilterABC):
self._id = values["id"]
if "name" in values:
self._id = values["name"]
self._name = values["name"]
def filter(self, query: List[Level]) -> List[Level]:
if self._id is not None:
@ -26,4 +26,4 @@ class LevelFilter(FilterABC):
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())
return self.skip_and_take(query)
return query

View File

@ -0,0 +1,25 @@
from cpl_query.extension import List
from bot_graphql.abc.filter_abc import FilterABC
class Page(FilterABC):
def __init__(self):
FilterABC.__init__(self)
self._page_index = None
self._page_size = None
def from_dict(self, values: dict):
if "page_index" in values:
self._page_index = values["page_index"]
if "page_size" in values:
self._page_size = values["page_size"]
def filter(self, query: List, *args) -> 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

View File

@ -19,6 +19,12 @@ class ServerFilter(FilterABC):
if "id" in values:
self._id = int(values["id"])
if "discord_id" in values:
self._discord_id = values["discord_id"]
if "name" in values:
self._name = values["name"]
@ServiceProviderABC.inject
def filter(self, query: List[Server], bot: DiscordBotServiceABC) -> List[Server]:
if self._id is not None:
@ -37,4 +43,4 @@ class ServerFilter(FilterABC):
query = query.where(where_guild)
return self.skip_and_take(query)
return query

View File

@ -0,0 +1,20 @@
from cpl_query.extension import List
from bot_graphql.abc.filter_abc import FilterABC
class Sort(FilterABC):
def __init__(self):
FilterABC.__init__(self)
self._sort_direction = None
self._sort_column = None
def from_dict(self, values: dict):
if "sort_direction" in values:
self._sort_direction = values["sort_direction"]
if "sort_column" in values:
self._sort_column = values["sort_column"]
def filter(self, query: List, *args) -> List:
return query

View File

@ -1,21 +1,27 @@
from typing import Optional
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_query.extension import List
from bot_core.abc.client_utils_abc import ClientUtilsABC
from bot_data.model.user import User
from bot_graphql.abc.filter_abc import FilterABC
from bot_graphql.filter.level_filter import LevelFilter
from modules.level.service.level_service import LevelService
class UserFilter(FilterABC):
def __init__(
self,
services: ServiceProviderABC,
bot: DiscordBotServiceABC,
client_utils: ClientUtilsABC,
levels: LevelService,
):
FilterABC.__init__(self)
self._services = services
self._bot = bot
self._client_utils = client_utils
self._levels = levels
@ -25,7 +31,7 @@ class UserFilter(FilterABC):
self._name = None
self._xp = None
self._ontime = None
self._level = None
self._level: Optional[LevelFilter] = None
def from_dict(self, values: dict):
if "id" in values:
@ -39,7 +45,8 @@ class UserFilter(FilterABC):
if "ontime" in values:
self._ontime = values["ontime"]
if "level" in values:
self._level = values["level"]
self._level: LevelFilter = self._services.get_service(LevelFilter)
self._level.from_dict(values["level"])
def filter(self, query: List[User]) -> List[User]:
if self._id is not None:
@ -61,6 +68,7 @@ class UserFilter(FilterABC):
query = query.where(lambda x: self._client_utils.get_ontime_for_user(x) == self._ontime)
if self._level is not None:
query = query.where(lambda x: self._levels.get_level(x) == self._level)
levels = self._level.filter(query.select(lambda x: self._levels.get_level(x))).select(lambda x: x.id)
query = query.where(lambda x: self._levels.get_level(x).id in levels)
return self.skip_and_take(query)
return query

View File

@ -1,212 +0,0 @@
interface TableQuery {
created_at: String
modified_at: String
}
type Mutation {
level: LevelMutation
}
type Query {
auto_roles: [AutoRole]
auto_role_count: Int
auto_role_rules: [AutoRole]
auto_role_rule_count: Int
clients: [Client]
client_count: Int
known_users: [KnownUser]
known_user_count: Int
levels: [Level]
level_count: Int
servers(filter: ServerFilter): [Server]
server_count: Int
user_joined_servers: [User]
user_joined_server_count: Int
user_joined_voice_channels: [User]
user_joined_voice_channel_count: Int
users(filter: UserFilter): [User]
user_count: Int
}
type KnownUser implements TableQuery {
id: ID
discord_id: String
created_at: String
modified_at: String
}
input ServerFilter {
id: ID
discord_id: String
name: String
page_index: Int
page_size: Int
sort_direction: String
sort_column: String
}
type Server implements TableQuery {
id: ID
discord_id: String
name: String
auto_roles: [AutoRole]
auto_role_count: Int
clients: [Client]
client_count: Int
users(filter: UserFilter): [User]
user_count: Int
levels: [Level]
level_count: Int
created_at: String
modified_at: String
}
type Client implements TableQuery {
id: ID
discord_id: String
name: String
sent_message_count: Int
received_message_count: Int
deleted_message_count: Int
received_command_count: Int
moved_users_count: Int
server: Server
created_at: String
modified_at: String
}
type AutoRole implements TableQuery {
id: ID
channel_id: String
message_id: String
server: Server
auto_role_rules: [AutoRoleRule]
auto_role_rule_count: Int
created_at: String
modified_at: String
}
type AutoRoleRule implements TableQuery {
id: ID
emoji_name: String
role_id: String
auto_role: AutoRole
created_at: String
modified_at: String
}
input UserFilter {
id: ID
discord_id: String
name: String
xp: Int
ontime: Float
level: LevelFilter
page_index: Int
page_size: Int
sort_direction: String
sort_column: String
}
type User implements TableQuery {
id: ID
discord_id: String
name: String
xp: Int
ontime: Float
level: Level
joined_servers: [UserJoinedServer]
joined_server_count: Int
joined_voice_channels: [UserJoinedVoiceChannel]
joined_voice_channel_count: Int
server: Server
created_at: String
modified_at: String
}
type UserJoinedServer implements TableQuery {
id: ID
user: User
server: Server
joined_on: String
leaved_on: String
created_at: String
modified_at: String
}
type UserJoinedVoiceChannel implements TableQuery {
id: ID
channel_id: String
user: User
server: Server
joined_on: String
leaved_on: String
created_at: String
modified_at: String
}
input LevelFilter {
id: ID
name: String
page_index: Int
page_size: Int
sort_direction: String
sort_column: String
}
type Level implements TableQuery {
id: ID
name: String
color: String
min_xp: Int
permissions: String
server: Server
created_at: String
modified_at: String
}
input LevelInput {
name: String!
color: String!
min_xp: Int!
permissions: String!
server_id: ID!
}
type LevelMutation {
create_level(input: LevelInput!): Level
update_level(input: LevelInput!): Level
delete_level(id: ID): Level
}

View File

@ -0,0 +1,13 @@
type AutoRole implements TableQuery {
id: ID
channel_id: String
message_id: String
server: Server
auto_role_rules: [AutoRoleRule]
auto_role_rule_count: Int
created_at: String
modified_at: String
}

View File

@ -0,0 +1,10 @@
type AutoRoleRule implements TableQuery {
id: ID
emoji_name: String
role_id: String
auto_role: AutoRole
created_at: String
modified_at: String
}

View File

@ -0,0 +1,14 @@
interface TableQuery {
created_at: String
modified_at: String
}
input Page {
page_index: Int
page_size: Int
}
input Sort {
sort_direction: String
sort_column: String
}

View File

@ -0,0 +1,15 @@
type Client implements TableQuery {
id: ID
discord_id: String
name: String
sent_message_count: Int
received_message_count: Int
deleted_message_count: Int
received_command_count: Int
moved_users_count: Int
server: Server
created_at: String
modified_at: String
}

View File

@ -0,0 +1,7 @@
type KnownUser implements TableQuery {
id: ID
discord_id: String
created_at: String
modified_at: String
}

View File

@ -0,0 +1,31 @@
type Level implements TableQuery {
id: ID
name: String
color: String
min_xp: Int
permissions: String
server: Server
created_at: String
modified_at: String
}
input LevelFilter {
id: ID
name: String
}
type LevelMutation {
create_level(input: LevelInput!): Level
update_level(input: LevelInput!): Level
delete_level(id: ID): Level
}
input LevelInput {
name: String!
color: String!
min_xp: Int!
permissions: String!
server_id: ID!
}

View File

@ -0,0 +1,3 @@
type Mutation {
level: LevelMutation
}

View File

@ -0,0 +1,28 @@
type Query {
auto_roles: [AutoRole]
auto_role_count: Int
auto_role_rules: [AutoRole]
auto_role_rule_count: Int
clients: [Client]
client_count: Int
known_users: [KnownUser]
known_user_count: Int
levels(filter: LevelFilter, page: Page, sort: Sort): [Level]
level_count: Int
servers(filter: ServerFilter, page: Page, sort: Sort): [Server]
server_count: Int
user_joined_servers: [User]
user_joined_server_count: Int
user_joined_voice_channels: [User]
user_joined_voice_channel_count: Int
users(filter: UserFilter, page: Page, sort: Sort): [User]
user_count: Int
}

View File

@ -0,0 +1,26 @@
type Server implements TableQuery {
id: ID
discord_id: String
name: String
auto_roles: [AutoRole]
auto_role_count: Int
clients: [Client]
client_count: Int
users(filter: UserFilter): [User]
user_count: Int
levels: [Level]
level_count: Int
created_at: String
modified_at: String
}
input ServerFilter {
id: ID
discord_id: String
name: String
}

View File

@ -0,0 +1,28 @@
type User implements TableQuery {
id: ID
discord_id: String
name: String
xp: Int
ontime: Float
level: Level
joined_servers: [UserJoinedServer]
joined_server_count: Int
joined_voice_channels: [UserJoinedVoiceChannel]
joined_voice_channel_count: Int
server: Server
created_at: String
modified_at: String
}
input UserFilter {
id: ID
discord_id: String
name: String
xp: Int
ontime: Float
level: LevelFilter
}

View File

@ -0,0 +1,10 @@
type UserJoinedServer implements TableQuery {
id: ID
user: User
server: Server
joined_on: String
leaved_on: String
created_at: String
modified_at: String
}

View File

@ -0,0 +1,11 @@
type UserJoinedVoiceChannel implements TableQuery {
id: ID
channel_id: String
user: User
server: Server
joined_on: String
leaved_on: String
created_at: String
modified_at: String
}

View File

@ -10,7 +10,7 @@ from bot_graphql.query import Query
class Schema:
def __init__(self, query: Query, mutation: Mutation, queries: list[QueryABC]):
type_defs = load_schema_from_path(os.path.join(os.path.dirname(os.path.realpath(__file__)), "model.gql"))
type_defs = load_schema_from_path(os.path.join(os.path.dirname(os.path.realpath(__file__)), "model/"))
self._schema = make_executable_schema(type_defs, query, mutation, *queries)
@property