spark-server/internal/module/moment/model/write.go
2026-09-20 11:38:27 +08:00

265 lines
6.7 KiB
Go

package model
import (
"context"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"spark-server/internal/module/moment/entity"
"spark-server/internal/pkg/errs"
)
func (m *Repo) CreatePost(ctx context.Context, post *entity.Post, audience []int64) error {
if post == nil || post.ID <= 0 || post.UserID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
row := postFrom(post)
if row.CreatedAt.IsZero() {
row.CreatedAt = time.Now()
}
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(row).Error; err != nil {
return mapDBErr(err)
}
for _, peer := range audience {
if err := tx.Create(&Audience{PostID: post.ID, PeerID: peer}).Error; err != nil {
return mapDBErr(err)
}
}
return nil
})
}
func (m *Repo) SoftDeletePost(ctx context.Context, userID, postID int64) (*entity.Post, error) {
db, err := m.session(ctx)
if err != nil {
return nil, err
}
var row Post
err = db.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("id = ? AND user_id = ?", postID, userID).Take(&row).Error; err != nil {
return mapDBErr(err)
}
if row.Status == int16(entity.StatusDeleted) {
return errs.ErrNotFound
}
res := tx.Model(&row).Update("status", entity.StatusDeleted)
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
row.Status = int16(entity.StatusDeleted)
return nil
})
if err != nil {
return nil, err
}
return row.Entity(), nil
}
func (m *Repo) AddLike(ctx context.Context, like *entity.Like) (bool, error) {
if like == nil || like.PostID <= 0 || like.UserID <= 0 {
return false, errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return false, err
}
row := Like{PostID: like.PostID, UserID: like.UserID, CreatedAt: time.Now()}
if like.CreatedAtMS > 0 {
row.CreatedAt = time.UnixMilli(like.CreatedAtMS)
}
created := false
err = db.Transaction(func(tx *gorm.DB) error {
res := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "post_id"}, {Name: "user_id"}},
DoNothing: true,
}).Create(&row)
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return nil
}
created = true
return bumpCount(tx, like.PostID, "like_count", 1)
})
return created, err
}
func (m *Repo) RemoveLike(ctx context.Context, postID, userID int64) error {
db, err := m.session(ctx)
if err != nil {
return err
}
return db.Transaction(func(tx *gorm.DB) error {
res := tx.Where("post_id = ? AND user_id = ?", postID, userID).Delete(&Like{})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
return bumpCount(tx, postID, "like_count", -1)
})
}
func (m *Repo) AddComment(ctx context.Context, c *entity.Comment) error {
if c == nil || c.ID <= 0 || c.PostID <= 0 || c.UserID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
row := commentFrom(c)
if row.CreatedAt.IsZero() {
row.CreatedAt = time.Now()
}
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(row).Error; err != nil {
return mapDBErr(err)
}
return bumpCount(tx, c.PostID, "comment_count", 1)
})
}
func (m *Repo) SoftDeleteComment(ctx context.Context, id int64) error {
db, err := m.session(ctx)
if err != nil {
return err
}
return db.Transaction(func(tx *gorm.DB) error {
var row Comment
if err := tx.Where("id = ?", id).Take(&row).Error; err != nil {
return mapDBErr(err)
}
if row.Status == int16(entity.StatusDeleted) {
return errs.ErrNotFound
}
if err := tx.Model(&row).Update("status", entity.StatusDeleted).Error; err != nil {
return mapDBErr(err)
}
return bumpCount(tx, row.PostID, "comment_count", -1)
})
}
func (m *Repo) CreateNotices(ctx context.Context, rows []*entity.Notice) error {
if len(rows) == 0 {
return nil
}
db, err := m.session(ctx)
if err != nil {
return err
}
now := time.Now()
for _, n := range rows {
row := Notice{
ID: n.ID, ToUserID: n.ToUserID, FromUserID: n.FromUserID, Kind: int16(n.Kind),
PostID: n.PostID, CommentID: n.CommentID, CreatedAt: now,
}
if n.CreatedAtMS > 0 {
row.CreatedAt = time.UnixMilli(n.CreatedAtMS)
}
if err := db.Create(&row).Error; err != nil {
return mapDBErr(err)
}
}
return nil
}
func (m *Repo) MarkNoticesRead(ctx context.Context, userID, cursor int64) error {
db, err := m.session(ctx)
if err != nil {
return err
}
q := db.Model(&Notice{}).Where("to_user_id = ? AND read_at IS NULL", userID)
if cursor > 0 {
q = q.Where("id <= ?", cursor)
}
return mapDBErr(q.Update("read_at", time.Now()).Error)
}
func (m *Repo) UpsertSettings(ctx context.Context, s *entity.Settings) error {
if s == nil || s.UserID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
row := settingFrom(s)
if row.UpdatedAt.IsZero() {
row.UpdatedAt = time.Now()
}
return mapDBErr(db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}},
DoUpdates: clause.AssignmentColumns([]string{
"cover_key", "visible_days", "last_read_post_id", "updated_at",
}),
}).Create(row).Error)
}
func (m *Repo) AdvanceRead(ctx context.Context, userID, postID int64) error {
if userID <= 0 || postID <= 0 {
return errs.ErrInvalidArgument
}
cur, err := m.GetSettings(ctx, userID)
if err != nil {
return err
}
if cur.LastReadPostID >= postID {
return nil
}
cur.LastReadPostID = postID
cur.UpdatedAtMS = time.Now().UnixMilli()
return m.UpsertSettings(ctx, cur)
}
func (m *Repo) UpsertHide(ctx context.Context, h *entity.Hide) error {
if h == nil || h.UserID <= 0 || h.PeerID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
row := Hide{UserID: h.UserID, PeerID: h.PeerID, HideHim: h.HideHim, HideMe: h.HideMe}
return mapDBErr(db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "user_id"}, {Name: "peer_id"}},
DoUpdates: clause.AssignmentColumns([]string{"hide_him", "hide_me"}),
}).Create(&row).Error)
}
func (m *Repo) DeleteHide(ctx context.Context, userID, peerID int64) error {
db, err := m.session(ctx)
if err != nil {
return err
}
res := db.Where("user_id = ? AND peer_id = ?", userID, peerID).Delete(&Hide{})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
return nil
}
func bumpCount(tx *gorm.DB, postID int64, col string, delta int) error {
expr := col + " + ?"
if delta < 0 {
expr = "CASE WHEN " + col + " + ? < 0 THEN 0 ELSE " + col + " + ? END"
return mapDBErr(tx.Model(&Post{}).Where("id = ?", postID).Update(col, gorm.Expr(expr, delta, delta)).Error)
}
return mapDBErr(tx.Model(&Post{}).Where("id = ?", postID).Update(col, gorm.Expr(expr, delta)).Error)
}