article_repository.go 7.6 KB
package repository

import (
	"context"

	"github.com/pkg/errors"
	"github.com/tiptok/gocomm/pkg/cache"
	"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/models"
	"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
	"gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
	"gorm.io/gorm"
)

type ArticleRepository struct {
	*cache.CachedRepository
}

func (repository *ArticleRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.Article) (*domain.Article, error) {
	var (
		err error
		m   = &models.Article{}
		tx  = conn.DB()
	)
	if m, err = repository.DomainModelToModel(dm); err != nil {
		return nil, err
	}
	if tx = tx.Model(m).Save(m); tx.Error != nil {
		return nil, tx.Error
	}
	dm.Id = m.Id
	return repository.ModelToDomainModel(m)

}

func (repository *ArticleRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.Article) (*domain.Article, error) {
	var (
		err error
		m   *models.Article
		tx  = conn.DB()
	)
	if m, err = repository.DomainModelToModel(dm); err != nil {
		return nil, err
	}
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Updates(m)
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *ArticleRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.Article) (*domain.Article, error) {
	var (
		err error
		m   *models.Article
		tx  = transaction.DB()
	)
	if m, err = repository.DomainModelToModel(dm); err != nil {
		return nil, err
	}
	oldVersion := dm.Version
	m.Version += 1
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
		if tx.RowsAffected == 0 {
			return nil, domain.ErrUpdateFail
		}
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *ArticleRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.Article) (*domain.Article, error) {
	var (
		tx = conn.DB()
		m  = &models.Article{Id: dm.Id}
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Where("id = ?", m.Id).Delete(m)
		return m, tx.Error
	}
	if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return dm, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *ArticleRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.Article, error) {
	var (
		err error
		tx  = conn.DB()
		m   = new(models.Article)
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Where("id = ?", id).First(m)
		if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
			return nil, domain.ErrNotFound
		}
		return m, tx.Error
	}
	cacheModel := new(models.Article)
	cacheModel.Id = id
	if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
		return nil, err
	}
	return repository.ModelToDomainModel(m)
}

func (repository *ArticleRepository) Find(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*domain.Article, error) {
	var (
		tx    = conn.DB()
		ms    []*models.Article
		dms   = make([]*domain.Article, 0)
		total int64
	)
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(&ms).Order("id desc").Where("company_id=?", companyId)
		if v, ok := queryOptions["ids"]; ok {
			tx.Where("id in (?)", v)
		}

		if v, ok := queryOptions["authorId"]; ok {
			tx = tx.Where("author_id = ?", v)
		}
		if v, ok := queryOptions["beginCreatedAt"]; ok {
			tx = tx.Where("created_at >= ?", v)
		}
		if v, ok := queryOptions["endCreatedAt"]; ok {
			tx = tx.Where("created_at < ?", v)
		}

		if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
			return dms, tx.Error
		}
		return dms, nil
	}

	if _, err := repository.Query(queryFunc); err != nil {
		return 0, nil, err
	}

	for _, item := range ms {
		if dm, err := repository.ModelToDomainModel(item); err != nil {
			return 0, dms, err
		} else {
			dms = append(dms, dm)
		}
	}
	return total, dms, nil
}

func (repository *ArticleRepository) ModelToDomainModel(from *models.Article) (*domain.Article, error) {
	to := &domain.Article{
		Id:           from.Id,
		CompanyId:    from.CompanyId,
		CreatedAt:    from.CreatedAt,
		UpdatedAt:    from.UpdatedAt,
		DeletedAt:    from.DeletedAt,
		Version:      from.Version,
		AuthorId:     from.AuthorId,
		Author:       from.Author,
		Title:        from.Title,
		Images:       from.Images,
		WhoRead:      from.WhoRead,
		WhoReview:    from.WhoReview,
		Location:     from.Location,
		TargetUser:   domain.ArticleTarget(from.TargetUser),
		CountLove:    from.CountLove,
		CountComment: from.CountComment,
		CountRead:    from.CountRead,
		Show:         domain.ArticleShow(from.Show),
		Tags:         from.Tags,
		Summary:      from.Summary,
	}
	return to, nil
}

func (repository *ArticleRepository) DomainModelToModel(from *domain.Article) (*models.Article, error) {
	to := &models.Article{
		Id:           from.Id,
		CompanyId:    from.CompanyId,
		CreatedAt:    from.CreatedAt,
		UpdatedAt:    from.UpdatedAt,
		DeletedAt:    from.DeletedAt,
		IsDel:        0,
		Version:      from.Version,
		AuthorId:     from.AuthorId,
		Author:       from.Author,
		Title:        from.Title,
		Images:       from.Images,
		WhoRead:      from.WhoRead,
		WhoReview:    from.WhoReview,
		Location:     from.Location,
		TargetUser:   int(from.TargetUser),
		CountLove:    from.CountLove,
		CountRead:    from.CountRead,
		CountComment: from.CountComment,
		Show:         int(from.Show),
		Tags:         from.Tags,
		Summary:      from.Summary,
	}
	// err := copier.Copy(to, from)
	return to, nil
}

// 点赞数量变动
func (repository *ArticleRepository) IncreaseCountLove(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error {
	//
	var (
		err error
		m   *models.Article
		tx  = conn.DB()
	)
	m = &models.Article{Id: articleId}
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Updates(map[string]interface{}{
			"count_love": gorm.Expr("count_love+?", incr),
			"version":    gorm.Expr("version+1"),
		})
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return err
	}
	return nil
}

// 浏览数量变动
func (repository *ArticleRepository) IncreaseCountRead(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error {
	var (
		err error
		m   *models.Article
		tx  = conn.DB()
	)
	m = &models.Article{Id: articleId}
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Updates(map[string]interface{}{
			"version":    gorm.Expr("version+1"),
			"count_read": gorm.Expr("count_read+?", incr),
		})
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return err
	}
	return nil
}

// 评论数量变动
func (repository *ArticleRepository) IncreaseCountComment(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error {
	var (
		err error
		m   *models.Article
		tx  = conn.DB()
	)
	m = &models.Article{Id: articleId}
	queryFunc := func() (interface{}, error) {
		tx = tx.Model(m).Updates(map[string]interface{}{
			"version":       gorm.Expr("version+1"),
			"count_comment": gorm.Expr("count_comment+?", incr),
		})
		return nil, tx.Error
	}
	if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
		return err
	}
	return nil
}

func NewArticleRepository(cache *cache.CachedRepository) domain.ArticleRepository {
	return &ArticleRepository{CachedRepository: cache}
}