chat_back_go/internal/repository/messages.go

190 lines
5.6 KiB
Go

package repository
import (
"errors"
"github.com/jmoiron/sqlx"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"time"
"git.urec56.ru/urec/chat_back_go/internal/database"
"git.urec56.ru/urec/chat_back_go/internal/domain"
"git.urec56.ru/urec/chat_back_go/internal/logger"
)
type messageRepository struct {
db *sqlx.DB
mc *mongo.Collection
l *logger.Logger
}
type SendMessage struct {
ID domain.UUID `bson:"id"`
Message string `bson:"message,omitempty"`
ImageUrl string `bson:"image_url,omitempty"`
ChatID int `bson:"chat_id"`
UserID int `bson:"user_id"`
CreatedAt time.Time `bson:"created_at"`
AnswerID domain.UUID `bson:"answer_id,omitempty"`
AnswerMessage string `bson:"answer_message,omitempty"`
AnswerImageUrl string `bson:"answer_image_url,omitempty"`
Visibility bool `bson:"visibility"`
}
type EditMessage struct {
ID domain.UUID
Message, ImageUrl string
}
type PinMessage struct {
ChatID, UserID int
MessageID domain.UUID
}
type UnpinMessage struct {
ChatID int
MessageID domain.UUID
}
type GetSome struct {
ChatID, Offset, Limit int
}
func newMessageRepo(db *sqlx.DB, mdb *mongo.Database, l *logger.Logger) *messageRepository {
return &messageRepository{db: db, mc: mdb.Collection("message"), l: l}
}
func (r *messageRepository) Get(ID domain.UUID) (domain.RawMessage, error) {
var msg domain.RawMessage
res := r.mc.FindOne(nil, bson.M{"id": ID})
if err := res.Decode(&msg); err != nil {
r.l.Errorf("getting message: %s", err)
return domain.RawMessage{}, domain.InternalServerError
}
return msg, nil
}
func (r *messageRepository) GetByIDs(IDs []domain.UUID) ([]domain.RawMessage, error) {
var messages []domain.RawMessage
res, err := r.mc.Find(nil, bson.M{"visibility": true, "id": bson.M{"$in": IDs}})
if err != nil {
r.l.Errorf("getting messages by ids: %s", err)
return nil, domain.InternalServerError
}
if err = res.All(nil, &messages); err != nil {
r.l.Errorf("decoding messages by ids: %s", err)
return nil, domain.InternalServerError
}
return messages, nil
}
func (r *messageRepository) GetSome(messagesInfo GetSome) ([]domain.RawMessage, error) {
var messages []domain.RawMessage
findOptions := options.Find().SetSort(bson.M{"created_at": -1}).SetLimit(int64(messagesInfo.Limit)).SetSkip(int64(messagesInfo.Offset))
res, err := r.mc.Find(nil, bson.M{"visibility": true, "chat_id": messagesInfo.ChatID}, findOptions)
if err != nil {
r.l.Errorf("getting some messages: %s", err)
return nil, domain.InternalServerError
}
if err = res.All(nil, &messages); err != nil {
r.l.Errorf("decoding some messages: %s", err)
return nil, domain.InternalServerError
}
return messages, nil
}
func (r *messageRepository) Send(message SendMessage) (domain.RawMessage, error) {
message.ID = domain.GenerateUUID()
message.CreatedAt = time.Now()
message.Visibility = true
_, err := r.mc.InsertOne(nil, message)
if err != nil {
r.l.Errorf("inserting message: %s", err)
return domain.RawMessage{}, domain.InternalServerError
}
return domain.RawMessage{
ID: message.ID,
Message: message.Message,
ImageUrl: message.ImageUrl,
ChatID: message.ChatID,
UserID: message.UserID,
CreatedAt: message.CreatedAt,
AnswerID: message.AnswerID,
AnswerMessage: message.AnswerMessage,
AnswerImageUrl: message.AnswerImageUrl,
}, nil
}
func (r *messageRepository) Delete(ID domain.UUID) error {
if _, err := r.mc.UpdateOne(nil, bson.M{"id": ID}, bson.M{"$set": bson.M{"visibility": false}}); err != nil {
r.l.Errorf("deleting message: %s", err)
return domain.InternalServerError
}
_, err := r.mc.UpdateMany(nil, bson.M{"answer_id": ID}, bson.M{"$set": bson.M{"answer_message": nil, "answer_image_url": nil}})
if err != nil {
r.l.Errorf("deleting message: %s", err)
return domain.InternalServerError
}
return nil
}
func (r *messageRepository) Edit(newMessage EditMessage) error {
_, err := r.mc.UpdateOne(nil, bson.M{"id": newMessage.ID}, bson.M{"$set": bson.M{"message": newMessage.Message, "image_url": newMessage.ImageUrl}})
if err != nil {
r.l.Errorf("edditing message: %s", err)
return domain.InternalServerError
}
_, err = r.mc.UpdateMany(nil, bson.M{"answer_id": newMessage.ID}, bson.M{"$set": bson.M{"answer_message": newMessage.Message, "answer_image_url": newMessage.ImageUrl}})
if err != nil {
r.l.Errorf("edditing message: %s", err)
return domain.InternalServerError
}
return nil
}
func (r *messageRepository) Pin(msg PinMessage) error {
query := `INSERT INTO pinned_message (chat_id, message_id, user_id) VALUES ($1, $2, $3)`
if _, err := r.db.Exec(query, msg.ChatID, msg.MessageID, msg.UserID); err != nil {
if errors.Is(err, database.IntegrityError) {
return domain.MessageAlreadyPinnedError
}
r.l.Errorf("pining message: %s", err)
return domain.InternalServerError
}
return nil
}
func (r *messageRepository) Unpin(msg UnpinMessage) error {
query := `DELETE FROM pinned_message WHERE chat_id = $1 AND message_id = $2`
if _, err := r.db.Exec(query, msg.ChatID, msg.MessageID); err != nil {
r.l.Errorf("unpining message: %s", err)
return domain.InternalServerError
}
return nil
}
func (r *messageRepository) GetPinnedIDs(chatID int) ([]domain.UUID, error) {
var IDs []domain.UUID
query := `SELECT message_id FROM pinned_message WHERE chat_id = $1`
if err := r.db.Select(&IDs, query, chatID); err != nil {
r.l.Errorf("getting pinned ids: %s", err)
return []domain.UUID{}, domain.InternalServerError
}
return IDs, nil
}