72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package store
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Reaction represents a single emoji reaction on a message.
|
||
|
|
type Reaction struct {
|
||
|
|
MessageID int64
|
||
|
|
UserID int64
|
||
|
|
Emoji string
|
||
|
|
}
|
||
|
|
|
||
|
|
// AddReaction adds a reaction to a message; it is a no-op if it already exists.
|
||
|
|
func (s *Store) AddReaction(ctx context.Context, messageID, userID int64, emoji string) error {
|
||
|
|
_, err := s.pool.Exec(ctx, `
|
||
|
|
INSERT INTO message_reactions(message_id, user_id, emoji)
|
||
|
|
VALUES($1, $2, $3)
|
||
|
|
ON CONFLICT (message_id, user_id, emoji) DO NOTHING
|
||
|
|
`, messageID, userID, emoji)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
// RemoveReaction removes a reaction from a message; it is a no-op if absent.
|
||
|
|
func (s *Store) RemoveReaction(ctx context.Context, messageID, userID int64, emoji string) error {
|
||
|
|
_, err := s.pool.Exec(ctx, `
|
||
|
|
DELETE FROM message_reactions WHERE message_id=$1 AND user_id=$2 AND emoji=$3
|
||
|
|
`, messageID, userID, emoji)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
// ReactionsForMessages returns all reactions for the given message IDs.
|
||
|
|
func (s *Store) ReactionsForMessages(ctx context.Context, messageIDs []int64) ([]Reaction, error) {
|
||
|
|
if len(messageIDs) == 0 {
|
||
|
|
return nil, nil
|
||
|
|
}
|
||
|
|
rows, err := s.pool.Query(ctx, `
|
||
|
|
SELECT message_id, user_id, emoji
|
||
|
|
FROM message_reactions
|
||
|
|
WHERE message_id = ANY($1)
|
||
|
|
ORDER BY message_id, created_at
|
||
|
|
`, messageIDs)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
defer rows.Close()
|
||
|
|
|
||
|
|
var reactions []Reaction
|
||
|
|
for rows.Next() {
|
||
|
|
var r Reaction
|
||
|
|
if err := rows.Scan(&r.MessageID, &r.UserID, &r.Emoji); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
reactions = append(reactions, r)
|
||
|
|
}
|
||
|
|
return reactions, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// MessageBelongsToConversation reports whether a message belongs to a conversation.
|
||
|
|
func (s *Store) MessageBelongsToConversation(ctx context.Context, conversationID, messageID int64) (bool, error) {
|
||
|
|
var exists bool
|
||
|
|
err := s.pool.QueryRow(ctx, `
|
||
|
|
SELECT EXISTS(
|
||
|
|
SELECT 1 FROM messages WHERE id=$1 AND conversation_id=$2
|
||
|
|
)
|
||
|
|
`, messageID, conversationID).Scan(&exists)
|
||
|
|
if err != nil {
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
return exists, nil
|
||
|
|
}
|