Files
multica/server/pkg/db/queries/chat.sql
Naiyuan Qing 63fa5c3e0e feat(chat): float unread sessions to the top of the list
Sort is now (unread_since IS NOT NULL) DESC, updated_at DESC. An unread
reply never gets buried below a newer action on a different session the
user already caught up on.

Within each group (unread and caught-up) the existing most-recent-first
order is preserved. Once the user opens the session and it's marked
read, it falls back to its time-ordered position; this shift is
intentional and won't be noticed because nothing points at it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:54:06 +08:00

108 lines
3.8 KiB
SQL

-- name: CreateChatSession :one
INSERT INTO chat_session (workspace_id, agent_id, creator_id, title)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetChatSession :one
SELECT * FROM chat_session
WHERE id = $1;
-- name: GetChatSessionInWorkspace :one
SELECT * FROM chat_session
WHERE id = $1 AND workspace_id = $2;
-- name: ListChatSessionsByCreator :many
-- Returns active sessions with a boolean unread flag. Unread is strictly
-- per-session: either the user has uncleared assistant replies in this
-- session or they don't. Counting messages would be misleading.
SELECT cs.*,
(cs.unread_since IS NOT NULL)::bool AS has_unread
FROM chat_session cs
WHERE cs.workspace_id = $1 AND cs.creator_id = $2 AND cs.status = 'active'
-- Unread sessions float to the top so new activity never gets buried
-- under routine reads; within each group, most-recent activity wins.
ORDER BY (cs.unread_since IS NOT NULL) DESC, cs.updated_at DESC;
-- name: ListAllChatSessionsByCreator :many
SELECT cs.*,
(cs.unread_since IS NOT NULL)::bool AS has_unread
FROM chat_session cs
WHERE cs.workspace_id = $1 AND cs.creator_id = $2
-- Unread sessions float to the top so new activity never gets buried
-- under routine reads; within each group, most-recent activity wins.
ORDER BY (cs.unread_since IS NOT NULL) DESC, cs.updated_at DESC;
-- name: UpdateChatSessionTitle :one
UPDATE chat_session SET title = $2, updated_at = now()
WHERE id = $1
RETURNING *;
-- name: UpdateChatSessionSession :exec
UPDATE chat_session SET session_id = $2, work_dir = $3, updated_at = now()
WHERE id = $1;
-- name: ArchiveChatSession :exec
UPDATE chat_session SET status = 'archived', updated_at = now()
WHERE id = $1;
-- name: TouchChatSession :exec
UPDATE chat_session SET updated_at = now()
WHERE id = $1;
-- name: CreateChatMessage :one
INSERT INTO chat_message (chat_session_id, role, content, task_id)
VALUES ($1, $2, $3, sqlc.narg(task_id))
RETURNING *;
-- name: ListChatMessages :many
SELECT * FROM chat_message
WHERE chat_session_id = $1
ORDER BY created_at ASC;
-- name: GetChatMessage :one
SELECT * FROM chat_message
WHERE id = $1;
-- name: CreateChatTask :one
INSERT INTO agent_task_queue (agent_id, runtime_id, issue_id, status, priority, chat_session_id)
VALUES ($1, $2, NULL, 'queued', $3, $4)
RETURNING *;
-- name: GetLastChatTaskSession :one
SELECT session_id, work_dir FROM agent_task_queue
WHERE chat_session_id = $1 AND status = 'completed' AND session_id IS NOT NULL
ORDER BY completed_at DESC
LIMIT 1;
-- name: GetPendingChatTask :one
-- Returns the most recent in-flight task for a chat session, if any.
-- Used by the frontend to recover pending state after refresh / reopen.
SELECT id, status FROM agent_task_queue
WHERE chat_session_id = $1 AND status IN ('queued', 'dispatched', 'running')
ORDER BY created_at DESC
LIMIT 1;
-- name: ListPendingChatTasksByCreator :many
-- Aggregate view of all in-flight chat tasks owned by a given creator in a
-- workspace. Drives the FAB's "running" indicator when the chat window is
-- closed and no single session's query is active.
SELECT atq.id AS task_id, atq.status, atq.chat_session_id
FROM agent_task_queue atq
JOIN chat_session cs ON cs.id = atq.chat_session_id
WHERE cs.workspace_id = $1
AND cs.creator_id = $2
AND atq.status IN ('queued', 'dispatched', 'running')
ORDER BY atq.created_at DESC;
-- name: MarkChatSessionRead :exec
-- Clears unread_since, dropping the session's unread count to 0.
UPDATE chat_session SET unread_since = NULL
WHERE id = $1;
-- name: SetUnreadSinceIfNull :exec
-- Atomically stamps the first unread assistant message's arrival time.
-- No-op if the session is already in "has unread" state — keeps the earliest
-- unread boundary stable across multiple incoming replies.
UPDATE chat_session SET unread_since = now()
WHERE id = $1 AND unread_since IS NULL;