fix: eliminate N+1 queries in get_custom_commands (#26)
Expand the JOIN SELECT to include all creator fields (created_at, total_commands, active_commands) and build the CustomCommandCreatorModel directly from joined row data instead of issuing a separate SELECT per command. Reduces 26 queries to 2 for a full 25-command page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
580e8ea031
commit
e311de93aa
@ -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))
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user