Fix: ListChats scan NULL в string → 500

pgx не мог сканировать NULL из COALESCE(...,'') когда
OtherPhoto был *string. После преобразования subquery
photo в строки и OtherPhoto в string, scan работает.

Проверено: Алиса и Тест получают свои чаты 200, без 500.
This commit is contained in:
ga 2026-08-21 12:31:11 +00:00
parent aee85c0087
commit c1396ffb6b
2 changed files with 25 additions and 21 deletions

View File

@ -93,18 +93,17 @@ func (r *Repo) ListChats(ctx context.Context, me uuid.UUID, limit, offset int) (
}
rows, err := r.pool.Query(ctx, `
SELECT c.id, c.user_a, c.user_b, c.created_at, c.last_msg_at,
CASE WHEN c.user_a = $1 THEN c.user_b ELSE c.user_a END AS other_id,
u.name,
u.photo_url,
(SELECT COALESCE(body, '') FROM messages m
CASE WHEN c.user_a = $1::uuid THEN c.user_b ELSE c.user_a END AS other_id,
COALESCE((SELECT name FROM users WHERE id = CASE WHEN c.user_a = $1::uuid THEN c.user_b ELSE c.user_a END), '') AS other_name,
COALESCE((SELECT photo_url FROM users WHERE id = CASE WHEN c.user_a = $1::uuid THEN c.user_b ELSE c.user_a END), '') AS other_photo,
COALESCE((SELECT body FROM messages m
WHERE m.chat_id = c.id AND m.deleted = FALSE
ORDER BY m.created_at DESC LIMIT 1) AS last_body,
ORDER BY m.created_at DESC LIMIT 1), '') AS last_body,
(SELECT COUNT(*) FROM messages m
WHERE m.chat_id = c.id AND m.read = FALSE
AND m.sender_id != $1) AS unread
AND m.sender_id != $1::uuid) AS unread
FROM chats c
JOIN users u ON u.id = CASE WHEN c.user_a = $1 THEN c.user_b ELSE c.user_a END
WHERE c.user_a = $1 OR c.user_b = $1
WHERE c.user_a = $1::uuid OR c.user_b = $1::uuid
ORDER BY c.last_msg_at DESC
LIMIT $2 OFFSET $3`,
me, limit, offset,
@ -117,14 +116,10 @@ func (r *Repo) ListChats(ctx context.Context, me uuid.UUID, limit, offset int) (
var out []ChatListItem
for rows.Next() {
var c ChatListItem
var photo *string
if err := rows.Scan(&c.Chat.ID, &c.Chat.UserA, &c.Chat.UserB, &c.Chat.CreatedAt, &c.Chat.LastMsgAt,
&c.OtherID, &c.OtherName, &photo, &c.LastMessage, &c.UnreadCount); err != nil {
&c.OtherID, &c.OtherName, &c.OtherPhoto, &c.LastMessage, &c.UnreadCount); err != nil {
return nil, err
}
if photo != nil {
c.OtherPhoto = *photo
}
c.LastMsgAt = c.Chat.LastMsgAt
out = append(out, c)
}

View File

@ -329,12 +329,16 @@ func age(birth *time.Time) *int {
// DebugLog — клиент-сайд диагностика (приходит из JS через api.js)
type debugLogReq struct {
Path string `json:"path"`
Status int `json:"status"`
Ms int `json:"ms"`
UA string `json:"ua"`
Err string `json:"err,omitempty"`
IsTelegram bool `json:"is_telegram"`
Path string `json:"path"`
Status int `json:"status"`
Ms int `json:"ms"`
UA string `json:"ua"`
Err string `json:"err,omitempty"`
IsTelegram bool `json:"is_telegram"`
Kind string `json:"kind,omitempty"`
UserID string `json:"userId,omitempty"`
Msg string `json:"msg,omitempty"`
Stack string `json:"stack,omitempty"`
}
func (h *Handlers) DebugLog(c *fiber.Ctx) error {
@ -342,7 +346,7 @@ func (h *Handlers) DebugLog(c *fiber.Ctx) error {
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "bad body"})
}
slog.Info("client-debug",
attrs := []any{
"path", req.Path,
"status", req.Status,
"ms", req.Ms,
@ -350,6 +354,11 @@ func (h *Handlers) DebugLog(c *fiber.Ctx) error {
"ua", req.UA,
"err", req.Err,
"ip", c.IP(),
)
}
if req.Kind != "" {
attrs = append(attrs, "kind", req.Kind, "userId", req.UserID, "msg", req.Msg)
if req.Stack != "" { attrs = append(attrs, "stack", req.Stack) }
}
slog.Info("client-debug", attrs...)
return c.JSON(fiber.Map{"ok": true})
}