♻️ Use the universal post api replace some duplicated apis
This commit is contained in:
@ -1,81 +1,50 @@
|
||||
package services
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"code.smartsheep.studio/hydrogen/identity/pkg/grpc/proto"
|
||||
"code.smartsheep.studio/hydrogen/interactive/pkg/database"
|
||||
"code.smartsheep.studio/hydrogen/interactive/pkg/models"
|
||||
"errors"
|
||||
"fmt"
|
||||
pluralize "github.com/gertd/go-pluralize"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PostTypeContext[T models.PostInterface] struct {
|
||||
type PostTypeContext struct {
|
||||
Tx *gorm.DB
|
||||
|
||||
TypeName string
|
||||
CanReply bool
|
||||
CanRepost bool
|
||||
TableName string
|
||||
ColumnName string
|
||||
CanReply bool
|
||||
CanRepost bool
|
||||
}
|
||||
|
||||
var pluralizeHelper = pluralize.NewClient()
|
||||
|
||||
func (v *PostTypeContext[T]) GetTableName(plural ...bool) string {
|
||||
if len(plural) <= 0 || !plural[0] {
|
||||
return strings.ToLower(v.TypeName)
|
||||
} else {
|
||||
return pluralizeHelper.Plural(strings.ToLower(v.TypeName))
|
||||
}
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) Preload(noComments ...bool) *PostTypeContext[T] {
|
||||
v.Tx.Preload("Author").
|
||||
Preload("Attachments").
|
||||
Preload("Categories").
|
||||
Preload("Hashtags")
|
||||
|
||||
if len(noComments) <= 0 || !noComments[0] {
|
||||
v.Tx = v.Tx.Preload("Comments")
|
||||
}
|
||||
|
||||
if v.CanReply {
|
||||
v.Tx.Preload("ReplyTo")
|
||||
}
|
||||
if v.CanRepost {
|
||||
v.Tx.Preload("RepostTo")
|
||||
}
|
||||
|
||||
func (v *PostTypeContext) FilterWithCategory(alias string) *PostTypeContext {
|
||||
name := v.ColumnName
|
||||
v.Tx.Joins(fmt.Sprintf("JOIN %s_categories ON %s.id = %s_categories.%s_id", name, v.TableName, name, name)).
|
||||
Joins(fmt.Sprintf("JOIN %s_categories ON %s_categories.id = %s_categories.category_id", name, name, name)).
|
||||
Where(name+"_categories.alias = ?", alias)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) FilterWithCategory(alias string) *PostTypeContext[T] {
|
||||
table := v.GetTableName()
|
||||
v.Tx.Joins(fmt.Sprintf("JOIN %s_categories ON %s.id = %s_categories.%s_id", table, v.GetTableName(true), table, v.GetTableName())).
|
||||
Joins(fmt.Sprintf("JOIN %s_categories ON %s_categories.id = %s_categories.category_id", table, table, table)).
|
||||
Where(table+"_categories.alias = ?", alias)
|
||||
func (v *PostTypeContext) FilterWithTag(alias string) *PostTypeContext {
|
||||
name := v.ColumnName
|
||||
v.Tx.Joins(fmt.Sprintf("JOIN %s_tags ON %s.id = %s_tags.%s_id", name, v.TableName, name, name)).
|
||||
Joins(fmt.Sprintf("JOIN %s_tags ON %s_tags.id = %s_tags.category_id", name, name, name)).
|
||||
Where(name+"_tags.alias = ?", alias)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) FilterWithTag(alias string) *PostTypeContext[T] {
|
||||
table := v.GetTableName()
|
||||
v.Tx.Joins(fmt.Sprintf("JOIN %s_tags ON %s.id = %s_tags.%s_id", table, v.GetTableName(true), table, v.GetTableName())).
|
||||
Joins(fmt.Sprintf("JOIN %s_tags ON %s_tags.id = %s_tags.category_id", table, table, table)).
|
||||
Where(table+"_tags.alias = ?", alias)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) FilterPublishedAt(date time.Time) *PostTypeContext[T] {
|
||||
func (v *PostTypeContext) FilterPublishedAt(date time.Time) *PostTypeContext {
|
||||
v.Tx.Where("published_at <= ? AND published_at IS NULL", date)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) FilterRealm(id uint) *PostTypeContext[T] {
|
||||
func (v *PostTypeContext) FilterRealm(id uint) *PostTypeContext {
|
||||
if id > 0 {
|
||||
v.Tx = v.Tx.Where("realm_id = ?", id)
|
||||
} else {
|
||||
@ -84,12 +53,12 @@ func (v *PostTypeContext[T]) FilterRealm(id uint) *PostTypeContext[T] {
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) FilterAuthor(id uint) *PostTypeContext[T] {
|
||||
func (v *PostTypeContext) FilterAuthor(id uint) *PostTypeContext {
|
||||
v.Tx = v.Tx.Where("author_id = ?", id)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) FilterReply(condition bool) *PostTypeContext[T] {
|
||||
func (v *PostTypeContext) FilterReply(condition bool) *PostTypeContext {
|
||||
if condition {
|
||||
v.Tx = v.Tx.Where("reply_id IS NOT NULL")
|
||||
} else {
|
||||
@ -98,32 +67,34 @@ func (v *PostTypeContext[T]) FilterReply(condition bool) *PostTypeContext[T] {
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) SortCreatedAt(order string) *PostTypeContext[T] {
|
||||
func (v *PostTypeContext) SortCreatedAt(order string) *PostTypeContext {
|
||||
v.Tx.Order(fmt.Sprintf("created_at %s", order))
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) GetViaAlias(alias string, noComments ...bool) (T, error) {
|
||||
var item T
|
||||
if err := v.Preload(noComments...).Tx.Where("alias = ?", alias).First(&item).Error; err != nil {
|
||||
func (v *PostTypeContext) GetViaAlias(alias string, noComments ...bool) (models.Feed, error) {
|
||||
var item models.Feed
|
||||
if err := v.Tx.Where("alias = ?", alias).First(&item).Error; err != nil {
|
||||
return item, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) Get(id uint, noComments ...bool) (T, error) {
|
||||
var item T
|
||||
if err := v.Preload(noComments...).Tx.Where("id = ?", id).First(&item).Error; err != nil {
|
||||
func (v *PostTypeContext) Get(id uint, noComments ...bool) (models.Feed, error) {
|
||||
var item models.Feed
|
||||
if err := v.Tx.
|
||||
Select("*, ? as model_type", v.ColumnName).
|
||||
Where("id = ?", id).First(&item).Error; err != nil {
|
||||
return item, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) Count() (int64, error) {
|
||||
func (v *PostTypeContext) Count() (int64, error) {
|
||||
var count int64
|
||||
table := viper.GetString("database.prefix") + v.GetTableName(true)
|
||||
table := viper.GetString("database.prefix") + v.TableName
|
||||
if err := v.Tx.Table(table).Count(&count).Error; err != nil {
|
||||
return count, err
|
||||
}
|
||||
@ -131,7 +102,7 @@ func (v *PostTypeContext[T]) Count() (int64, error) {
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) CountReactions(id uint) (map[string]int64, error) {
|
||||
func (v *PostTypeContext) CountReactions(id uint) (map[string]int64, error) {
|
||||
var reactions []struct {
|
||||
Symbol string
|
||||
Count int64
|
||||
@ -139,7 +110,7 @@ func (v *PostTypeContext[T]) CountReactions(id uint) (map[string]int64, error) {
|
||||
|
||||
if err := database.C.Model(&models.Reaction{}).
|
||||
Select("symbol, COUNT(id) as count").
|
||||
Where(strings.ToLower(v.TypeName)+"_id = ?", id).
|
||||
Where(v.ColumnName+"_id = ?", id).
|
||||
Group("symbol").
|
||||
Scan(&reactions).Error; err != nil {
|
||||
return map[string]int64{}, err
|
||||
@ -148,23 +119,26 @@ func (v *PostTypeContext[T]) CountReactions(id uint) (map[string]int64, error) {
|
||||
return lo.SliceToMap(reactions, func(item struct {
|
||||
Symbol string
|
||||
Count int64
|
||||
}) (string, int64) {
|
||||
},
|
||||
) (string, int64) {
|
||||
return item.Symbol, item.Count
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, error) {
|
||||
func (v *PostTypeContext) List(take int, offset int, noReact ...bool) ([]*models.Feed, error) {
|
||||
if take > 20 {
|
||||
take = 20
|
||||
}
|
||||
|
||||
var items []T
|
||||
if err := v.Preload().Tx.Limit(take).Offset(offset).Find(&items).Error; err != nil {
|
||||
var items []*models.Feed
|
||||
if err := v.Tx.
|
||||
Select("*, ? as model_type", v.ColumnName).
|
||||
Limit(take).Offset(offset).Find(&items).Error; err != nil {
|
||||
return items, err
|
||||
}
|
||||
|
||||
idx := lo.Map(items, func(item T, index int) uint {
|
||||
return item.GetID()
|
||||
idx := lo.Map(items, func(item *models.Feed, index int) uint {
|
||||
return item.ID
|
||||
})
|
||||
|
||||
if len(noReact) <= 0 || !noReact[0] {
|
||||
@ -175,15 +149,15 @@ func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, e
|
||||
}
|
||||
|
||||
if err := database.C.Model(&models.Reaction{}).
|
||||
Select(strings.ToLower(v.TypeName)+"_id as post_id, symbol, COUNT(id) as count").
|
||||
Where(strings.ToLower(v.TypeName)+"_id IN (?)", idx).
|
||||
Select(v.ColumnName+"_id as post_id, symbol, COUNT(id) as count").
|
||||
Where(v.ColumnName+"_id IN (?)", idx).
|
||||
Group("post_id, symbol").
|
||||
Scan(&reactions).Error; err != nil {
|
||||
return items, err
|
||||
}
|
||||
|
||||
itemMap := lo.SliceToMap(items, func(item T) (uint, T) {
|
||||
return item.GetID(), item
|
||||
itemMap := lo.SliceToMap(items, func(item *models.Feed) (uint, *models.Feed) {
|
||||
return item.ID, item
|
||||
})
|
||||
|
||||
list := map[uint]map[string]int64{}
|
||||
@ -196,7 +170,7 @@ func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, e
|
||||
|
||||
for k, v := range list {
|
||||
if post, ok := itemMap[k]; ok {
|
||||
post.SetReactionList(v)
|
||||
post.ReactionList = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -204,7 +178,7 @@ func (v *PostTypeContext[T]) List(take int, offset int, noReact ...bool) ([]T, e
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) MapCategoriesAndTags(item T) (T, error) {
|
||||
func MapCategoriesAndTags[T models.PostInterface](item T) (T, error) {
|
||||
var err error
|
||||
categories := item.GetCategories()
|
||||
for idx, category := range categories {
|
||||
@ -225,8 +199,8 @@ func (v *PostTypeContext[T]) MapCategoriesAndTags(item T) (T, error) {
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) New(item T) (T, error) {
|
||||
item, err := v.MapCategoriesAndTags(item)
|
||||
func NewPost[T models.PostInterface](item T) (T, error) {
|
||||
item, err := MapCategoriesAndTags(item)
|
||||
if err != nil {
|
||||
return item, err
|
||||
}
|
||||
@ -294,8 +268,8 @@ func (v *PostTypeContext[T]) New(item T) (T, error) {
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) Edit(item T) (T, error) {
|
||||
item, err := v.MapCategoriesAndTags(item)
|
||||
func EditPost[T models.PostInterface](item T) (T, error) {
|
||||
item, err := MapCategoriesAndTags(item)
|
||||
if err != nil {
|
||||
return item, err
|
||||
}
|
||||
@ -305,11 +279,11 @@ func (v *PostTypeContext[T]) Edit(item T) (T, error) {
|
||||
return item, err
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) Delete(item T) error {
|
||||
func DeletePost[T models.PostInterface](item T) error {
|
||||
return database.C.Delete(&item).Error
|
||||
}
|
||||
|
||||
func (v *PostTypeContext[T]) React(reaction models.Reaction) (bool, models.Reaction, error) {
|
||||
func (v *PostTypeContext) React(reaction models.Reaction) (bool, models.Reaction, error) {
|
||||
if err := database.C.Where(reaction).First(&reaction).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return true, reaction, database.C.Save(&reaction).Error
|
||||
|
Reference in New Issue
Block a user