Add HTTP /v1 MVC, TCP send path, groups with server-side member-avatar collage, object-storage upload, and friends/favorites around the architecture-v3 layout. Co-authored-by: Cursor <cursoragent@cursor.com>
115 lines
2.5 KiB
Go
115 lines
2.5 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
mysqldriver "github.com/go-sql-driver/mysql"
|
|
"gorm.io/gorm"
|
|
|
|
"spark-server/internal/module/favorite/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
// Repo is MySQL persistence for favorites.
|
|
type Repo struct {
|
|
gdb *gorm.DB
|
|
}
|
|
|
|
func NewRepo(gdb *gorm.DB) *Repo {
|
|
return &Repo{gdb: gdb}
|
|
}
|
|
|
|
func (m *Repo) session(ctx context.Context) (*gorm.DB, error) {
|
|
if m == nil || m.gdb == nil {
|
|
return nil, errs.ErrAvailable
|
|
}
|
|
return m.gdb.WithContext(ctx), nil
|
|
}
|
|
|
|
func mapDBErr(err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return errs.ErrNotFound
|
|
}
|
|
var me *mysqldriver.MySQLError
|
|
if errors.As(err, &me) && me.Number == 1062 {
|
|
return errs.ErrDuplicate
|
|
}
|
|
return errs.ErrInner.WithError("favorite-mysql", err)
|
|
}
|
|
|
|
func (m *Repo) Get(ctx context.Context, id int64) (*entity.Favorite, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var row Favorite
|
|
if err := db.Where("id = ?", id).Take(&row).Error; err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
return row.Entity(), nil
|
|
}
|
|
|
|
func (m *Repo) GetByUserMsg(ctx context.Context, userID, msgID int64) (*entity.Favorite, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var row Favorite
|
|
if err := db.Where("user_id = ? AND msg_id = ?", userID, msgID).Take(&row).Error; err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
return row.Entity(), nil
|
|
}
|
|
|
|
func (m *Repo) Create(ctx context.Context, fav *entity.Favorite) error {
|
|
if fav == nil || fav.ID <= 0 || fav.UserID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
row := fromEntity(fav)
|
|
if row.CreatedAt.IsZero() {
|
|
row.CreatedAt = time.Now()
|
|
}
|
|
return mapDBErr(db.Create(row).Error)
|
|
}
|
|
|
|
func (m *Repo) ListByUser(ctx context.Context, userID int64, limit int) ([]*entity.Favorite, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
limit = entity.ClampLimit(limit)
|
|
var rows []Favorite
|
|
if err := db.Where("user_id = ?", userID).Order("id DESC").Limit(limit).Find(&rows).Error; err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
out := make([]*entity.Favorite, 0, len(rows))
|
|
for i := range rows {
|
|
out = append(out, rows[i].Entity())
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (m *Repo) Delete(ctx context.Context, userID, id int64) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := db.Where("id = ? AND user_id = ?", id, userID).Delete(&Favorite{})
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|