refactor: normalize script_builder_messages into separate table
Extract JSONB messages array from script_builder_sessions into a proper script_builder_messages table with individual columns for role, content, script, tokens, etc. Migration handles data migration from JSONB to rows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,10 +9,12 @@ from app.core.database import get_db
|
||||
from app.core.rate_limit import limiter
|
||||
from app.api.deps import get_current_active_user
|
||||
from app.models.user import User
|
||||
from app.models.script_builder_session import ScriptBuilderSession
|
||||
from app.schemas.script_builder import (
|
||||
ScriptBuilderCreateRequest,
|
||||
ScriptBuilderMessageRequest,
|
||||
ScriptBuilderMessageResponse,
|
||||
ScriptBuilderMessageSchema,
|
||||
ScriptBuilderSessionDetail,
|
||||
ScriptBuilderSessionSummary,
|
||||
SaveToLibraryRequest,
|
||||
@@ -25,6 +27,39 @@ router = APIRouter(prefix="/scripts/builder", tags=["script-builder"])
|
||||
MAX_SESSIONS_PER_USER = 5
|
||||
|
||||
|
||||
def _session_to_detail(session: ScriptBuilderSession) -> ScriptBuilderSessionDetail:
|
||||
"""Convert a session ORM object (with message_records loaded) to detail schema."""
|
||||
messages = [
|
||||
ScriptBuilderMessageSchema.model_validate(m)
|
||||
for m in session.message_records
|
||||
]
|
||||
return ScriptBuilderSessionDetail(
|
||||
id=session.id,
|
||||
language=session.language,
|
||||
title=session.title,
|
||||
messages=messages,
|
||||
latest_script=session.latest_script,
|
||||
latest_script_filename=session.latest_script_filename,
|
||||
message_count=len([m for m in messages if m.role == "user"]),
|
||||
ai_session_id=session.ai_session_id,
|
||||
created_at=session.created_at,
|
||||
updated_at=session.updated_at,
|
||||
)
|
||||
|
||||
|
||||
def _session_to_summary(session: ScriptBuilderSession) -> ScriptBuilderSessionSummary:
|
||||
"""Convert a session ORM object to summary schema (no messages needed)."""
|
||||
return ScriptBuilderSessionSummary(
|
||||
id=session.id,
|
||||
language=session.language,
|
||||
title=session.title,
|
||||
message_count=0, # Summary doesn't eagerly load messages
|
||||
latest_script_filename=session.latest_script_filename,
|
||||
created_at=session.created_at,
|
||||
updated_at=session.updated_at,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/sessions", response_model=ScriptBuilderSessionDetail, status_code=201)
|
||||
async def create_session(
|
||||
data: ScriptBuilderCreateRequest,
|
||||
@@ -47,7 +82,9 @@ async def create_session(
|
||||
language=data.language,
|
||||
)
|
||||
await db.commit()
|
||||
return ScriptBuilderSessionDetail.model_validate(session)
|
||||
# Re-fetch with message_records loaded
|
||||
session = await script_builder_service.get_session(db, session.id, current_user.id)
|
||||
return _session_to_detail(session)
|
||||
|
||||
|
||||
@router.get("/sessions", response_model=list[ScriptBuilderSessionSummary])
|
||||
@@ -61,7 +98,7 @@ async def list_sessions(
|
||||
sessions = await script_builder_service.list_sessions(
|
||||
db=db, user_id=current_user.id, limit=limit, offset=offset
|
||||
)
|
||||
return [ScriptBuilderSessionSummary.model_validate(s) for s in sessions]
|
||||
return [_session_to_summary(s) for s in sessions]
|
||||
|
||||
|
||||
@router.get("/sessions/{session_id}", response_model=ScriptBuilderSessionDetail)
|
||||
@@ -74,7 +111,7 @@ async def get_session(
|
||||
session = await script_builder_service.get_session(db, session_id, current_user.id)
|
||||
if not session:
|
||||
raise HTTPException(status_code=404, detail="Session not found")
|
||||
return ScriptBuilderSessionDetail.model_validate(session)
|
||||
return _session_to_detail(session)
|
||||
|
||||
|
||||
@router.post(
|
||||
|
||||
Reference in New Issue
Block a user