-- name: ListMessageRecipientsForUser :many SELECT u.id AS user_id, u.email AS user_email, u.role AS user_role, u.full_name AS user_full_name, p.preferred_name, p.profile_icon_url, p.headline FROM users u LEFT JOIN profiles p ON p.user_id = u.id WHERE u.id <> $1 AND u.is_active = TRUE AND ( EXISTS ( SELECT 1 FROM classrooms c JOIN classroom_students cs ON cs.classroom_id = c.id WHERE c.teacher_id = u.id AND cs.student_id = $1 ) OR EXISTS ( SELECT 1 FROM classrooms c JOIN classroom_students cs ON cs.classroom_id = c.id WHERE c.teacher_id = $1 AND cs.student_id = u.id ) ) ORDER BY COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC; -- name: GetMessageRecipientByIDForUser :one SELECT u.id AS user_id, u.email AS user_email, u.role AS user_role, u.full_name AS user_full_name, p.preferred_name, p.profile_icon_url, p.headline FROM users u LEFT JOIN profiles p ON p.user_id = u.id WHERE u.id = $2 AND u.id <> $1 AND u.is_active = TRUE AND ( EXISTS ( SELECT 1 FROM classrooms c JOIN classroom_students cs ON cs.classroom_id = c.id WHERE c.teacher_id = u.id AND cs.student_id = $1 ) OR EXISTS ( SELECT 1 FROM classrooms c JOIN classroom_students cs ON cs.classroom_id = c.id WHERE c.teacher_id = $1 AND cs.student_id = u.id ) ) LIMIT 1; -- name: ListMessageThreadsForUser :many SELECT t.id AS thread_id, t.subject, t.created_by_user_id, t.created_at AS thread_created_at, t.updated_at AS thread_updated_at, COALESCE(last_message.id, 0)::bigint AS last_message_id, COALESCE(last_message.body, '') AS last_message_body, last_message.created_at AS last_message_created_at, COALESCE(last_message.sender_user_id, 0)::bigint AS last_message_sender_user_id, sender.full_name AS last_message_sender_full_name, sender_profile.preferred_name AS last_message_sender_preferred_name, sender_profile.profile_icon_url AS last_message_sender_profile_icon_url, COALESCE(( SELECT COUNT(*)::bigint FROM messages unread WHERE unread.thread_id = t.id AND unread.sender_user_id <> $1 AND (participant.last_read_at IS NULL OR unread.created_at > participant.last_read_at) ), 0)::bigint AS unread_count FROM message_thread_participants participant JOIN message_threads t ON t.id = participant.thread_id LEFT JOIN LATERAL ( SELECT m.id, m.body, m.created_at, m.sender_user_id FROM messages m WHERE m.thread_id = t.id ORDER BY m.created_at DESC, m.id DESC LIMIT 1 ) AS last_message ON TRUE LEFT JOIN users sender ON sender.id = last_message.sender_user_id LEFT JOIN profiles sender_profile ON sender_profile.user_id = sender.id WHERE participant.user_id = $1 AND participant.archived_at IS NULL ORDER BY COALESCE(last_message.created_at, t.updated_at) DESC, t.id DESC; -- name: ListMessageThreadParticipantsForUser :many SELECT mtp.thread_id, u.id AS user_id, u.email AS user_email, u.role AS user_role, u.full_name AS user_full_name, p.preferred_name, p.profile_icon_url, p.headline, mtp.joined_at, mtp.last_read_at, mtp.archived_at FROM message_thread_participants mtp JOIN users u ON u.id = mtp.user_id LEFT JOIN profiles p ON p.user_id = u.id WHERE mtp.thread_id IN ( SELECT participant.thread_id FROM message_thread_participants participant WHERE participant.user_id = $1 AND participant.archived_at IS NULL ) ORDER BY mtp.thread_id ASC, COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC; -- name: GetMessageThreadForUser :one SELECT t.id, t.subject, t.created_by_user_id, t.created_at, t.updated_at, participant.last_read_at, COALESCE(( SELECT COUNT(*)::bigint FROM messages unread WHERE unread.thread_id = t.id AND unread.sender_user_id <> $2 AND (participant.last_read_at IS NULL OR unread.created_at > participant.last_read_at) ), 0)::bigint AS unread_count FROM message_threads t JOIN message_thread_participants participant ON participant.thread_id = t.id WHERE t.id = $1 AND participant.user_id = $2 AND participant.archived_at IS NULL; -- name: ListMessagesForThreadForUser :many SELECT m.id, m.thread_id, m.sender_user_id, m.body, m.created_at, m.updated_at, sender.email AS sender_email, sender.role AS sender_role, sender.full_name AS sender_full_name, sender_profile.preferred_name AS sender_preferred_name, sender_profile.profile_icon_url AS sender_profile_icon_url, sender_profile.headline AS sender_headline FROM messages m JOIN message_thread_participants participant ON participant.thread_id = m.thread_id JOIN users sender ON sender.id = m.sender_user_id LEFT JOIN profiles sender_profile ON sender_profile.user_id = sender.id WHERE m.thread_id = $1 AND participant.user_id = $2 AND participant.archived_at IS NULL ORDER BY m.created_at ASC, m.id ASC; -- name: ListParticipantsForThreadForUser :many SELECT mtp.thread_id, u.id AS user_id, u.email AS user_email, u.role AS user_role, u.full_name AS user_full_name, p.preferred_name, p.profile_icon_url, p.headline, mtp.joined_at, mtp.last_read_at, mtp.archived_at FROM message_thread_participants mtp JOIN users u ON u.id = mtp.user_id LEFT JOIN profiles p ON p.user_id = u.id WHERE mtp.thread_id = $1 AND EXISTS ( SELECT 1 FROM message_thread_participants participant WHERE participant.thread_id = mtp.thread_id AND participant.user_id = $2 AND participant.archived_at IS NULL ) ORDER BY COALESCE(NULLIF(p.preferred_name, ''), u.full_name) ASC, u.id ASC; -- name: CreateMessageThread :one INSERT INTO message_threads ( created_by_user_id, subject ) VALUES ( $1, $2 ) RETURNING *; -- name: AddMessageThreadParticipant :exec INSERT INTO message_thread_participants ( thread_id, user_id, last_read_at ) VALUES ( $1, $2, $3 ) ON CONFLICT (thread_id, user_id) DO NOTHING; -- name: CreateThreadMessage :one INSERT INTO messages ( thread_id, sender_user_id, body ) VALUES ( $1, $2, $3 ) RETURNING *; -- name: TouchMessageThread :exec UPDATE message_threads SET updated_at = NOW() WHERE id = $1; -- name: UpdateMessageThreadSubject :one UPDATE message_threads SET subject = sqlc.arg(subject), updated_at = NOW() WHERE id = sqlc.arg(thread_id) RETURNING *; -- name: UpdateThreadMessageBody :one UPDATE messages SET body = sqlc.arg(body), updated_at = NOW() WHERE id = sqlc.arg(message_id) AND thread_id = sqlc.arg(thread_id) AND sender_user_id = sqlc.arg(user_id) RETURNING *; -- name: DeleteThreadMessage :one DELETE FROM messages WHERE id = sqlc.arg(message_id) AND thread_id = sqlc.arg(thread_id) AND sender_user_id = sqlc.arg(user_id) RETURNING *; -- name: DeleteMessageThread :one DELETE FROM message_threads WHERE id = sqlc.arg(thread_id) RETURNING *; -- name: MarkMessageThreadRead :one UPDATE message_thread_participants SET last_read_at = COALESCE((SELECT MAX(m.created_at) FROM messages m WHERE m.thread_id = $1), NOW()) WHERE message_thread_participants.thread_id = $1 AND message_thread_participants.user_id = $2 RETURNING *;