Files
Messenger/server/internal/store/search.go
T
vantablackTea 6fc6d977bf
CI / Go (build + vet + test) (push) Canceled after 0s
CI / Web (build + lint) (push) Canceled after 0s
added media fixes, search, push updates, pwa, metrics. preparing release 1.0
2026-09-27 23:26:15 +03:00

51 lines
1.4 KiB
Go

package store
import (
"context"
)
// MessageHit is a search result: a message scoped to the member's
// conversations, with its conversation context.
type MessageHit struct {
Message
ConversationType string
ConversationName string
}
// SearchMessages finds messages matching query in conversations the user
// belongs to, newest first. ILIKE substring matching keeps the search
// dependency-free at family scale; pg_trgm is the documented scaling path.
func (s *Store) SearchMessages(ctx context.Context, userID int64, query string, limit int) ([]MessageHit, error) {
if query == "" {
return nil, nil
}
pattern := "%" + query + "%"
rows, err := s.pool.Query(ctx, `
SELECT m.id, m.conversation_id, m.sender_id, m.body, m.media_id, m.created_at, m.edited_at, m.deleted_at,
c.type, c.name
FROM messages m
JOIN conversation_members cm ON cm.conversation_id = m.conversation_id AND cm.user_id = $1
JOIN conversations c ON c.id = m.conversation_id
WHERE m.body ILIKE $2
ORDER BY m.id DESC
LIMIT $3
`, userID, pattern, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var hits []MessageHit
for rows.Next() {
var h MessageHit
if err := rows.Scan(
&h.ID, &h.ConversationID, &h.SenderID, &h.Body, &h.MediaID, &h.CreatedAt, &h.EditedAt, &h.DeletedAt,
&h.ConversationType, &h.ConversationName,
); err != nil {
return nil, err
}
hits = append(hits, h)
}
return hits, nil
}