Merge pull request 'fix: eliminate N+1 queries in get_custom_commands (#26)' (#51) from ai/major-domo-database-26 into next-release

This commit is contained in:
cal 2026-04-08 03:51:42 +00:00
commit ad8cd08b76
2 changed files with 27 additions and 23 deletions

View File

@ -2438,8 +2438,7 @@ class Decision(BaseModel):
class CustomCommandCreator(BaseModel):
"""Model for custom command creators."""
discord_id = CharField(max_length=20, unique=True) # Discord snowflake ID as string
discord_id = BigIntegerField(unique=True)
username = CharField(max_length=32)
display_name = CharField(max_length=32, null=True)
created_at = DateTimeField()

View File

@ -175,7 +175,7 @@ def delete_custom_command(command_id: int):
def get_creator_by_discord_id(discord_id: int):
"""Get a creator by Discord ID"""
creator = CustomCommandCreator.get_or_none(
CustomCommandCreator.discord_id == str(discord_id)
CustomCommandCreator.discord_id == discord_id
)
if creator:
return model_to_dict(creator)
@ -273,7 +273,10 @@ async def get_custom_commands(
sql = f"""
SELECT cc.*, creator.discord_id as creator_discord_id,
creator.username as creator_username,
creator.display_name as creator_display_name
creator.display_name as creator_display_name,
creator.created_at as creator_created_at,
creator.total_commands as creator_total_commands,
creator.active_commands as creator_active_commands
FROM custom_commands cc
LEFT JOIN custom_command_creators creator ON cc.creator_id = creator.id
{where_clause}
@ -298,24 +301,23 @@ async def get_custom_commands(
command_dict["tags"] = json.loads(command_dict["tags"])
except Exception:
command_dict["tags"] = []
# Get full creator information
creator_id = command_dict["creator_id"]
creator_cursor = db.execute_sql(
"SELECT * FROM custom_command_creators WHERE id = %s", (creator_id,)
)
creator_result = creator_cursor.fetchone()
if creator_result:
# Create complete creator object
creator_columns = [desc[0] for desc in creator_cursor.description]
creator_dict = dict(zip(creator_columns, creator_result))
# Convert datetime to ISO string
if creator_dict.get("created_at") and hasattr(
creator_dict["created_at"], "isoformat"
):
creator_dict["created_at"] = creator_dict[
"created_at"
].isoformat()
# Build creator object from joined data (avoids N+1 queries)
if command_dict.get("creator_discord_id") is not None:
creator_created_at = command_dict.get("creator_created_at")
if creator_created_at and hasattr(creator_created_at, "isoformat"):
creator_created_at = creator_created_at.isoformat()
creator_dict = {
"id": command_dict["creator_id"],
"discord_id": command_dict["creator_discord_id"],
"username": command_dict["creator_username"],
"display_name": command_dict.get("creator_display_name"),
"created_at": creator_created_at,
"total_commands": command_dict.get("creator_total_commands", 0),
"active_commands": command_dict.get(
"creator_active_commands", 0
),
}
try:
creator_model = CustomCommandCreatorModel(**creator_dict)
command_dict["creator"] = creator_model
@ -325,13 +327,15 @@ async def get_custom_commands(
)
command_dict["creator"] = None
else:
# No creator found, set to None
command_dict["creator"] = None
# Remove the individual creator fields now that we have the creator object
# Remove joined creator fields before building the command model
command_dict.pop("creator_discord_id", None)
command_dict.pop("creator_username", None)
command_dict.pop("creator_display_name", None)
command_dict.pop("creator_created_at", None)
command_dict.pop("creator_total_commands", None)
command_dict.pop("creator_active_commands", None)
# Convert datetime fields to ISO strings
for field in ["created_at", "updated_at", "last_used"]:
@ -1055,3 +1059,4 @@ async def get_custom_command(command_id: int):
except Exception as e:
logger.error(f"Error getting custom command {command_id}: {e}")
raise HTTPException(status_code=500, detail=str(e))