tux.database.controllers.levels
¶
Classes:
Name | Description |
---|---|
LevelsController | Controller for managing user levels and experience. |
Classes¶
LevelsController()
¶
Bases: BaseController[Levels]
Controller for managing user levels and experience.
This controller provides methods for tracking, updating, and querying user levels and experience points across guilds.
Initialize the LevelsController with the levels table.
Methods:
Name | Description |
---|---|
get_xp | Get the XP of a member in a guild. |
get_level | Get the level of a member in a guild. |
get_xp_and_level | Get the XP and level of a member in a guild. |
get_last_message_time | Get the last message time of a member in a guild. |
is_blacklisted | Check if a member is blacklisted in a guild. |
update_xp_and_level | Update the XP and level of a member in a guild. |
toggle_blacklist | Toggle the blacklist status of a member in a guild. |
find_one | Finds the first record matching specified criteria. |
find_unique | Finds a single record by a unique constraint (e.g., ID). |
reset_xp | Reset the XP and level of a member in a guild. |
find_many | Finds multiple records matching specified criteria. |
get_top_members | Get the top members in a guild by XP. |
add_xp | Add XP to a member and calculate if they leveled up. |
count | Counts records matching the specified criteria. |
create | Creates a new record in the table. |
calculate_level | Calculate level based on XP. |
update | Updates a single existing record matching the criteria. |
count_ranked_members | Count the number of ranked members in a guild. |
get_rank | Get the rank of a member in a guild. |
delete | Deletes a single record matching the criteria. |
upsert | Updates a record if it exists, otherwise creates it. |
bulk_delete_by_guild_id | Delete all levels data for a guild. |
update_many | Updates multiple records matching the criteria. |
delete_many | Deletes multiple records matching the criteria. |
execute_transaction | Executes a series of database operations within a transaction. |
connect_or_create_relation | Builds a Prisma 'connect_or_create' relation structure. |
safe_get_attr | Safely retrieves an attribute from an object, returning a default if absent. |
Source code in tux/database/controllers/levels.py
Functions¶
get_xp(member_id: int, guild_id: int) -> float
async
¶
Get the XP of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
float | The XP of the member, or 0.0 if not found |
Source code in tux/database/controllers/levels.py
async def get_xp(self, member_id: int, guild_id: int) -> float:
"""Get the XP of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
float
The XP of the member, or 0.0 if not found
"""
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
return self.safe_get_attr(levels, "xp", 0.0)
except Exception as e:
logger.error(f"Error querying XP for member_id: {member_id}, guild_id: {guild_id}: {e}")
return 0.0
get_level(member_id: int, guild_id: int) -> int
async
¶
Get the level of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
int | The level of the member, or 0 if not found |
Source code in tux/database/controllers/levels.py
async def get_level(self, member_id: int, guild_id: int) -> int:
"""Get the level of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
int
The level of the member, or 0 if not found
"""
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
return self.safe_get_attr(levels, "level", 0)
except Exception as e:
logger.error(f"Error querying level for member_id: {member_id}, guild_id: {guild_id}: {e}")
return 0
get_xp_and_level(member_id: int, guild_id: int) -> tuple[float, int]
async
¶
Get the XP and level of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
tuple[float, int] | A tuple containing the XP and level of the member, or (0.0, 0) if not found |
Source code in tux/database/controllers/levels.py
async def get_xp_and_level(self, member_id: int, guild_id: int) -> tuple[float, int]:
"""Get the XP and level of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
tuple[float, int]
A tuple containing the XP and level of the member, or (0.0, 0) if not found
"""
try:
record = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
if record:
return (self.safe_get_attr(record, "xp", 0.0), self.safe_get_attr(record, "level", 0))
return (0.0, 0) # noqa: TRY300
except Exception as e:
logger.error(f"Error querying XP and level for member_id: {member_id}, guild_id: {guild_id}: {e}")
return (0.0, 0)
_execute_query(operation: Callable[[], Any], error_msg: str) -> Any
async
¶
Executes a database query with standardized error logging.
Wraps the Prisma client operation call in a try-except block, logging any exceptions with a contextual error message.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
operation | Callable[[], Any] | A zero-argument function (e.g., a lambda) that performs the database call. | required |
error_msg | str | The base error message to log if an exception occurs. | required |
Returns:
Type | Description |
---|---|
Any | The result of the database operation. |
Raises:
Type | Description |
---|---|
Exception | Re-raises any exception caught during the database operation. |
Source code in tux/database/controllers/levels.py
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
tuple[float, int]
A tuple containing the XP and level of the member, or (0.0, 0) if not found
"""
try:
record = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
if record:
return (self.safe_get_attr(record, "xp", 0.0), self.safe_get_attr(record, "level", 0))
return (0.0, 0) # noqa: TRY300
except Exception as e:
logger.error(f"Error querying XP and level for member_id: {member_id}, guild_id: {guild_id}: {e}")
return (0.0, 0)
async def get_last_message_time(self, member_id: int, guild_id: int) -> datetime.datetime | None:
"""Get the last message time of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
datetime.datetime | None
The last message time of the member, or None if not found
"""
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
return self.safe_get_attr(levels, "last_message", None)
except Exception as e:
logger.error(f"Error querying last message time for member_id: {member_id}, guild_id: {guild_id}: {e}")
return None
async def is_blacklisted(self, member_id: int, guild_id: int) -> bool:
get_last_message_time(member_id: int, guild_id: int) -> datetime.datetime | None
async
¶
Get the last message time of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
datetime | None | The last message time of the member, or None if not found |
Source code in tux/database/controllers/levels.py
async def get_last_message_time(self, member_id: int, guild_id: int) -> datetime.datetime | None:
"""Get the last message time of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
datetime.datetime | None
The last message time of the member, or None if not found
"""
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
return self.safe_get_attr(levels, "last_message", None)
except Exception as e:
logger.error(f"Error querying last message time for member_id: {member_id}, guild_id: {guild_id}: {e}")
return None
is_blacklisted(member_id: int, guild_id: int) -> bool
async
¶
Check if a member is blacklisted in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
bool | True if the member is blacklisted, False otherwise |
Source code in tux/database/controllers/levels.py
async def is_blacklisted(self, member_id: int, guild_id: int) -> bool:
"""Check if a member is blacklisted in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
bool
True if the member is blacklisted, False otherwise
"""
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
return self.safe_get_attr(levels, "blacklisted", False)
except Exception as e:
logger.error(f"Error querying blacklist status for member_id: {member_id}, guild_id: {guild_id}: {e}")
return False
_add_include_arg_if_present(args: dict[str, Any], include: dict[str, bool] | None) -> None
¶
_build_find_args(where: dict[str, Any], include: dict[str, bool] | None = None, order: dict[str, str] | None = None, take: int | None = None, skip: int | None = None, cursor: dict[str, Any] | None = None) -> dict[str, Any]
¶
Constructs the keyword arguments dictionary for Prisma find operations.
Source code in tux/database/controllers/levels.py
guild_id : int
The ID of the guild
Returns
-------
bool
True if the member is blacklisted, False otherwise
"""
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
return self.safe_get_attr(levels, "blacklisted", False)
except Exception as e:
logger.error(f"Error querying blacklist status for member_id: {member_id}, guild_id: {guild_id}: {e}")
return False
async def update_xp_and_level(
self,
member_id: int,
guild_id: int,
xp: float,
level: int,
update_xp_and_level(member_id: int, guild_id: int, xp: float, level: int, last_message: datetime.datetime) -> Levels | None
async
¶
Update the XP and level of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
xp | float | The XP of the member | required |
level | int | The level of the member | required |
last_message | datetime | The last message time of the member | required |
Returns:
Type | Description |
---|---|
Levels | None | The updated levels record, or None if the update failed |
Source code in tux/database/controllers/levels.py
async def update_xp_and_level(
self,
member_id: int,
guild_id: int,
xp: float,
level: int,
last_message: datetime.datetime,
) -> Levels | None:
"""Update the XP and level of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
xp : float
The XP of the member
level : int
The level of the member
last_message : datetime.datetime
The last message time of the member
Returns
-------
Levels | None
The updated levels record, or None if the update failed
"""
try:
return await self.upsert(
where={"member_id_guild_id": {"member_id": member_id, "guild_id": guild_id}},
create={
"member_id": member_id,
"xp": xp,
"level": level,
"last_message": last_message,
"guild": self.connect_or_create_relation("guild_id", guild_id),
},
update={"xp": xp, "level": level, "last_message": last_message},
)
except Exception as e:
logger.error(f"Error updating XP and level for member_id: {member_id}, guild_id: {guild_id}: {e}")
return None
_build_simple_args(key_name: str, key_value: dict[str, Any], include: dict[str, bool] | None = None) -> dict[str, Any]
¶
Constructs simple keyword arguments for Prisma (e.g., create, delete).
_build_create_args(data: dict[str, Any], include: dict[str, bool] | None = None) -> dict[str, Any]
¶
_build_update_args(where: dict[str, Any], data: dict[str, Any], include: dict[str, bool] | None = None) -> dict[str, Any]
¶
Constructs keyword arguments for Prisma update operations.
Source code in tux/database/controllers/levels.py
_build_delete_args(where: dict[str, Any], include: dict[str, bool] | None = None) -> dict[str, Any]
¶
Constructs keyword arguments for Prisma delete operations.
toggle_blacklist(member_id: int, guild_id: int) -> bool
async
¶
Toggle the blacklist status of a member in a guild.
This method uses a transaction to ensure atomicity.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
bool | The new blacklist status of the member |
Source code in tux/database/controllers/levels.py
async def toggle_blacklist(self, member_id: int, guild_id: int) -> bool:
"""Toggle the blacklist status of a member in a guild.
This method uses a transaction to ensure atomicity.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
bool
The new blacklist status of the member
"""
async def toggle_tx():
try:
levels = await self.find_one(where={"member_id": member_id, "guild_id": guild_id})
if levels is None:
# Create new record with blacklisted=True
await self.create(
data={
"member_id": member_id,
"blacklisted": True,
"xp": 0.0,
"level": 0,
"guild": self.connect_or_create_relation("guild_id", guild_id),
},
)
return True
# Toggle existing record's blacklisted status
current_status = self.safe_get_attr(levels, "blacklisted", False)
new_status = not current_status
await self.update(
where={"member_id_guild_id": {"member_id": member_id, "guild_id": guild_id}},
data={"blacklisted": new_status},
)
return new_status # noqa: TRY300
except Exception as e:
logger.error(f"Error toggling blacklist for member_id: {member_id}, guild_id: {guild_id}: {e}")
return False
return await self.execute_transaction(toggle_tx)
_build_upsert_args(where: dict[str, Any], create: dict[str, Any], update: dict[str, Any], include: dict[str, bool] | None = None) -> dict[str, Any]
¶
Constructs keyword arguments for Prisma upsert operations.
Source code in tux/database/controllers/levels.py
find_one(where: dict[str, Any], include: dict[str, bool] | None = None, order: dict[str, str] | None = None) -> Levels | None
async
¶
Finds the first record matching specified criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to match. | required |
include | dict[str, bool] | Specifies relations to include in the result. | None |
order | dict[str, str] | Specifies the field and direction for ordering. | None |
Returns:
Type | Description |
---|---|
ModelType | None | The found record or None if no match exists. |
Source code in tux/database/controllers/levels.py
if levels is None:
# Create new record with blacklisted=True
await self.create(
data={
"member_id": member_id,
"blacklisted": True,
"xp": 0.0,
"level": 0,
"guild": self.connect_or_create_relation("guild_id", guild_id),
},
)
return True
# Toggle existing record's blacklisted status
current_status = self.safe_get_attr(levels, "blacklisted", False)
new_status = not current_status
await self.update(
where={"member_id_guild_id": {"member_id": member_id, "guild_id": guild_id}},
data={"blacklisted": new_status},
)
return new_status # noqa: TRY300
except Exception as e:
logger.error(f"Error toggling blacklist for member_id: {member_id}, guild_id: {guild_id}: {e}")
return False
find_unique(where: dict[str, Any], include: dict[str, bool] | None = None) -> Levels | None
async
¶
Finds a single record by a unique constraint (e.g., ID).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Unique query conditions (e.g., {'id': 1}). | required |
include | dict[str, bool] | Specifies relations to include in the result. | None |
Returns:
Type | Description |
---|---|
ModelType | None | The found record or None if no match exists. |
Source code in tux/database/controllers/levels.py
return await self.execute_transaction(toggle_tx)
async def reset_xp(self, member_id: int, guild_id: int) -> Levels | None:
"""Reset the XP and level of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
Levels | None
The updated levels record, or None if the update failed
"""
try:
result = await self.update(
where={"member_id_guild_id": {"member_id": member_id, "guild_id": guild_id}},
data={"xp": 0.0, "level": 0},
)
except Exception as e:
logger.error(f"Error resetting XP for member_id: {member_id}, guild_id: {guild_id}: {e}")
reset_xp(member_id: int, guild_id: int) -> Levels | None
async
¶
Reset the XP and level of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
Levels | None | The updated levels record, or None if the update failed |
Source code in tux/database/controllers/levels.py
async def reset_xp(self, member_id: int, guild_id: int) -> Levels | None:
"""Reset the XP and level of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
Levels | None
The updated levels record, or None if the update failed
"""
try:
result = await self.update(
where={"member_id_guild_id": {"member_id": member_id, "guild_id": guild_id}},
data={"xp": 0.0, "level": 0},
)
except Exception as e:
logger.error(f"Error resetting XP for member_id: {member_id}, guild_id: {guild_id}: {e}")
return None
else:
return result
find_many(where: dict[str, Any], include: dict[str, bool] | None = None, order: dict[str, str] | None = None, take: int | None = None, skip: int | None = None, cursor: dict[str, Any] | None = None) -> list[Levels]
async
¶
Finds multiple records matching specified criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to match. | required |
include | dict[str, bool] | Specifies relations to include in the results. | None |
order | dict[str, str] | Specifies the field and direction for ordering. | None |
take | int | Maximum number of records to return. | None |
skip | int | Number of records to skip (for pagination). | None |
cursor | dict[str, Any] | Cursor for pagination based on a unique field. | None |
Returns:
Type | Description |
---|---|
list[ModelType] | A list of found records, potentially empty. |
Source code in tux/database/controllers/levels.py
else:
return result
async def get_top_members(self, guild_id: int, limit: int = 10, skip: int = 0) -> list[Levels]:
"""Get the top members in a guild by XP.
Parameters
----------
guild_id : int
The ID of the guild
limit : int
The maximum number of members to return
skip : int
The number of members to skip
Returns
-------
list[Levels]
The top members in the guild by XP
"""
try:
return await self.find_many(
where={"guild_id": guild_id, "blacklisted": False},
order={"xp": "desc"},
take=limit,
skip=skip,
)
except Exception as e:
logger.error(f"Error querying top members for guild_id: {guild_id}: {e}")
return []
async def add_xp(self, member_id: int, guild_id: int, xp_to_add: float) -> tuple[float, int, bool]:
"""Add XP to a member and calculate if they leveled up.
This method uses a transaction to ensure atomicity.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
xp_to_add : float
get_top_members(guild_id: int, limit: int = 10, skip: int = 0) -> list[Levels]
async
¶
Get the top members in a guild by XP.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
guild_id | int | The ID of the guild | required |
limit | int | The maximum number of members to return | 10 |
skip | int | The number of members to skip | 0 |
Returns:
Type | Description |
---|---|
list[Levels] | The top members in the guild by XP |
Source code in tux/database/controllers/levels.py
async def get_top_members(self, guild_id: int, limit: int = 10, skip: int = 0) -> list[Levels]:
"""Get the top members in a guild by XP.
Parameters
----------
guild_id : int
The ID of the guild
limit : int
The maximum number of members to return
skip : int
The number of members to skip
Returns
-------
list[Levels]
The top members in the guild by XP
"""
try:
return await self.find_many(
where={"guild_id": guild_id, "blacklisted": False},
order={"xp": "desc"},
take=limit,
skip=skip,
)
except Exception as e:
logger.error(f"Error querying top members for guild_id: {guild_id}: {e}")
return []
add_xp(member_id: int, guild_id: int, xp_to_add: float) -> tuple[float, int, bool]
async
¶
Add XP to a member and calculate if they leveled up.
This method uses a transaction to ensure atomicity.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
xp_to_add | float | The amount of XP to add | required |
Returns:
Type | Description |
---|---|
tuple[float, int, bool] | A tuple containing the new XP, new level, and whether the member leveled up |
Source code in tux/database/controllers/levels.py
async def add_xp(self, member_id: int, guild_id: int, xp_to_add: float) -> tuple[float, int, bool]:
"""Add XP to a member and calculate if they leveled up.
This method uses a transaction to ensure atomicity.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
xp_to_add : float
The amount of XP to add
Returns
-------
tuple[float, int, bool]
A tuple containing the new XP, new level, and whether the member leveled up
"""
async def add_xp_tx():
# Initialize with defaults in case of failure
current_xp = 0.0
current_level = 0
try:
# Get current XP and level
current_xp, current_level = await self.get_xp_and_level(member_id, guild_id)
# Calculate new XP and level
new_xp = current_xp + xp_to_add
new_level = self.calculate_level(new_xp)
leveled_up = new_level > current_level
# Update database
now = datetime.datetime.now(datetime.UTC)
await self.update_xp_and_level(
member_id=member_id,
guild_id=guild_id,
xp=new_xp,
level=new_level,
last_message=now,
)
except Exception as e:
logger.error(f"Error adding XP for member_id: {member_id}, guild_id: {guild_id}: {e}")
return (current_xp, current_level, False)
else:
return (new_xp, new_level, leveled_up)
return await self.execute_transaction(add_xp_tx)
count(where: dict[str, Any]) -> int
async
¶
Counts records matching the specified criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to match. | required |
Returns:
Type | Description |
---|---|
int | The total number of matching records. |
Source code in tux/database/controllers/levels.py
Returns
-------
tuple[float, int, bool]
A tuple containing the new XP, new level, and whether the member leveled up
"""
async def add_xp_tx():
# Initialize with defaults in case of failure
current_xp = 0.0
current_level = 0
try:
# Get current XP and level
current_xp, current_level = await self.get_xp_and_level(member_id, guild_id)
# Calculate new XP and level
new_xp = current_xp + xp_to_add
new_level = self.calculate_level(new_xp)
leveled_up = new_level > current_level
create(data: dict[str, Any], include: dict[str, bool] | None = None) -> Levels
async
¶
Creates a new record in the table.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data | dict[str, Any] | The data for the new record. | required |
include | dict[str, bool] | Specifies relations to include in the returned record. | None |
Returns:
Type | Description |
---|---|
ModelType | The newly created record. |
Source code in tux/database/controllers/levels.py
# Update database
now = datetime.datetime.now(datetime.UTC)
await self.update_xp_and_level(
member_id=member_id,
guild_id=guild_id,
xp=new_xp,
level=new_level,
last_message=now,
)
except Exception as e:
logger.error(f"Error adding XP for member_id: {member_id}, guild_id: {guild_id}: {e}")
return (current_xp, current_level, False)
else:
return (new_xp, new_level, leveled_up)
return await self.execute_transaction(add_xp_tx)
@staticmethod
def calculate_level(xp: float) -> int:
"""Calculate level based on XP.
This uses a standard RPG-style level curve.
Parameters
calculate_level(xp: float) -> int
staticmethod
¶
Calculate level based on XP.
This uses a standard RPG-style level curve.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
xp | float | The XP to calculate the level from | required |
Returns:
Type | Description |
---|---|
int | The calculated level |
Source code in tux/database/controllers/levels.py
@staticmethod
def calculate_level(xp: float) -> int:
"""Calculate level based on XP.
This uses a standard RPG-style level curve.
Parameters
----------
xp : float
The XP to calculate the level from
Returns
-------
int
The calculated level
"""
# Base calculation: level = floor(sqrt(xp / 100))
import math
return math.floor(math.sqrt(xp / 100))
update(where: dict[str, Any], data: dict[str, Any], include: dict[str, bool] | None = None) -> Levels | None
async
¶
Updates a single existing record matching the criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to find the record to update. | required |
data | dict[str, Any] | The data to update the record with. | required |
include | dict[str, bool] | Specifies relations to include in the returned record. | None |
Returns:
Type | Description |
---|---|
ModelType | None | The updated record, or None if no matching record was found. |
Source code in tux/database/controllers/levels.py
xp : float
The XP to calculate the level from
Returns
-------
int
The calculated level
"""
# Base calculation: level = floor(sqrt(xp / 100))
import math
return math.floor(math.sqrt(xp / 100))
async def count_ranked_members(self, guild_id: int) -> int:
"""Count the number of ranked members in a guild.
Parameters
----------
guild_id : int
The ID of the guild
Returns
-------
int
The number of ranked members
"""
return await self.count(where={"guild_id": guild_id, "blacklisted": False})
count_ranked_members(guild_id: int) -> int
async
¶
Count the number of ranked members in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
int | The number of ranked members |
Source code in tux/database/controllers/levels.py
async def count_ranked_members(self, guild_id: int) -> int:
"""Count the number of ranked members in a guild.
Parameters
----------
guild_id : int
The ID of the guild
Returns
-------
int
The number of ranked members
"""
return await self.count(where={"guild_id": guild_id, "blacklisted": False})
get_rank(member_id: int, guild_id: int) -> int
async
¶
Get the rank of a member in a guild.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
member_id | int | The ID of the member | required |
guild_id | int | The ID of the guild | required |
Returns:
Type | Description |
---|---|
int | The rank of the member (1-based), or 0 if not found |
Source code in tux/database/controllers/levels.py
async def get_rank(self, member_id: int, guild_id: int) -> int:
"""Get the rank of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
int
The rank of the member (1-based), or 0 if not found
"""
try:
# Get the member's XP
member_xp = await self.get_xp(member_id, guild_id)
# Count members with more XP
higher_ranked = await self.count(
where={
"guild_id": guild_id,
"blacklisted": False,
"xp": {"gt": member_xp},
},
)
# Rank is position (1-based)
return higher_ranked + 1
except Exception as e:
logger.error(f"Error getting rank for member_id: {member_id}, guild_id: {guild_id}: {e}")
return 0
delete(where: dict[str, Any], include: dict[str, bool] | None = None) -> Levels | None
async
¶
Deletes a single record matching the criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to find the record to delete. | required |
include | dict[str, bool] | Specifies relations to include in the returned deleted record. | None |
Returns:
Type | Description |
---|---|
ModelType | None | The deleted record, or None if no matching record was found. |
Source code in tux/database/controllers/levels.py
async def get_rank(self, member_id: int, guild_id: int) -> int:
"""Get the rank of a member in a guild.
Parameters
----------
member_id : int
The ID of the member
guild_id : int
The ID of the guild
Returns
-------
int
The rank of the member (1-based), or 0 if not found
"""
try:
# Get the member's XP
member_xp = await self.get_xp(member_id, guild_id)
# Count members with more XP
higher_ranked = await self.count(
where={
"guild_id": guild_id,
"blacklisted": False,
upsert(where: dict[str, Any], create: dict[str, Any], update: dict[str, Any], include: dict[str, bool] | None = None) -> Levels
async
¶
Updates a record if it exists, otherwise creates it.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to find the existing record. | required |
create | dict[str, Any] | Data to use if creating a new record. | required |
update | dict[str, Any] | Data to use if updating an existing record. | required |
include | dict[str, bool] | Specifies relations to include in the returned record. | None |
Returns:
Type | Description |
---|---|
ModelType | The created or updated record. |
Source code in tux/database/controllers/levels.py
},
)
# Rank is position (1-based)
return higher_ranked + 1
except Exception as e:
logger.error(f"Error getting rank for member_id: {member_id}, guild_id: {guild_id}: {e}")
return 0
async def bulk_delete_by_guild_id(self, guild_id: int) -> int:
"""Delete all levels data for a guild.
Parameters
----------
guild_id : int
The ID of the guild
Returns
-------
int
The number of records deleted
"""
return await self.delete_many(where={"guild_id": guild_id})
bulk_delete_by_guild_id(guild_id: int) -> int
async
¶
update_many(where: dict[str, Any], data: dict[str, Any]) -> int
async
¶
Updates multiple records matching the criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to find the records to update. | required |
data | dict[str, Any] | The data to update the records with. | required |
Returns:
Type | Description |
---|---|
int | The number of records updated. |
Raises:
Type | Description |
---|---|
ValueError | If the database operation does not return a valid count. |
delete_many(where: dict[str, Any]) -> int
async
¶
Deletes multiple records matching the criteria.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
where | dict[str, Any] | Query conditions to find the records to delete. | required |
Returns:
Type | Description |
---|---|
int | The number of records deleted. |
Raises:
Type | Description |
---|---|
ValueError | If the database operation does not return a valid count. |
execute_transaction(callback: Callable[[], Any]) -> Any
async
¶
Executes a series of database operations within a transaction.
Ensures atomicity: all operations succeed or all fail and roll back. Note: Does not use _execute_query internally to preserve specific transaction context in error messages.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback | Callable[[], Any] | An async function containing the database operations to execute. | required |
Returns:
Type | Description |
---|---|
Any | The result returned by the callback function. |
Raises:
Type | Description |
---|---|
Exception | Re-raises any exception that occurs during the transaction. |
connect_or_create_relation(id_field: str, model_id: Any, create_data: dict[str, Any] | None = None) -> dict[str, Any]
staticmethod
¶
Builds a Prisma 'connect_or_create' relation structure.
Simplifies linking or creating related records during create/update operations.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
id_field | str | The name of the ID field used for connection (e.g., 'guild_id'). | required |
model_id | Any | The ID value of the record to connect to. | required |
create_data | dict[str, Any] | Additional data required if creating the related record. Must include at least the | None |
Returns:
Type | Description |
---|---|
dict[str, Any] | A dictionary formatted for Prisma's connect_or_create. |
safe_get_attr(obj: Any, attr: str, default: Any = None) -> Any
staticmethod
¶
Safely retrieves an attribute from an object, returning a default if absent.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj | Any | The object to retrieve the attribute from. | required |
attr | str | The name of the attribute. | required |
default | Any | The value to return if the attribute is not found. Defaults to None. | None |
Returns:
Type | Description |
---|---|
Any | The attribute's value or the default value. |