Files
backend/internal/repository/post_ref_repo.go
lafay 23d7f1151e
All checks were successful
Build Backend / build (push) Successful in 2m19s
Build Backend / build-docker (push) Successful in 1m18s
feat(posts): add post reference/internal linking functionality
Add support for referencing other posts within messages through a new post_ref segment type. Includes new PostReference model to track relationships, PostRefService for processing references, and new endpoints for post suggestions, related posts, and reference click tracking.
2026-04-26 00:37:20 +08:00

98 lines
3.4 KiB
Go

package repository
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"with_you/internal/model"
)
type PostRefRepository interface {
BatchUpsert(ctx context.Context, sourcePostID string, targetPostIDs []string) error
DeleteBySourcePostID(ctx context.Context, sourcePostID string) error
GetSourcesByTargetPostID(ctx context.Context, targetPostID string, page, pageSize int) ([]model.PostReference, int64, error)
GetTargetsBySourcePostID(ctx context.Context, sourcePostID string) ([]model.PostReference, error)
MarkStatusByTargetPostID(ctx context.Context, targetPostID string, status model.PostReferenceStatus) error
IncrementClickCount(ctx context.Context, sourcePostID, targetPostID string) error
}
type postRefRepository struct {
db *gorm.DB
}
func NewPostRefRepository(db *gorm.DB) PostRefRepository {
return &postRefRepository{db: db}
}
func (r *postRefRepository) BatchUpsert(ctx context.Context, sourcePostID string, targetPostIDs []string) error {
if len(targetPostIDs) == 0 {
return nil
}
refs := make([]model.PostReference, 0, len(targetPostIDs))
for _, targetID := range targetPostIDs {
refs = append(refs, model.PostReference{
SourcePostID: sourcePostID,
TargetPostID: targetID,
Status: model.PostRefActive,
})
}
return r.db.WithContext(ctx).Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "source_post_id"}, {Name: "target_post_id"}},
DoUpdates: clause.AssignmentColumns([]string{"status", "updated_at"}),
}).Create(&refs).Error
}
func (r *postRefRepository) DeleteBySourcePostID(ctx context.Context, sourcePostID string) error {
return r.db.WithContext(ctx).Where("source_post_id = ?", sourcePostID).Delete(&model.PostReference{}).Error
}
func (r *postRefRepository) GetSourcesByTargetPostID(ctx context.Context, targetPostID string, page, pageSize int) ([]model.PostReference, int64, error) {
var refs []model.PostReference
var total int64
if err := r.db.WithContext(ctx).Model(&model.PostReference{}).
Where("target_post_id = ? AND status = ?", targetPostID, model.PostRefActive).
Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
if err := r.db.WithContext(ctx).
Where("target_post_id = ? AND status = ?", targetPostID, model.PostRefActive).
Preload("SourcePost").
Preload("SourcePost.User").
Order("created_at DESC").
Offset(offset).Limit(pageSize).
Find(&refs).Error; err != nil {
return nil, 0, err
}
return refs, total, nil
}
func (r *postRefRepository) GetTargetsBySourcePostID(ctx context.Context, sourcePostID string) ([]model.PostReference, error) {
var refs []model.PostReference
if err := r.db.WithContext(ctx).
Where("source_post_id = ?", sourcePostID).
Preload("TargetPost").
Preload("TargetPost.User").
Find(&refs).Error; err != nil {
return nil, err
}
return refs, nil
}
func (r *postRefRepository) MarkStatusByTargetPostID(ctx context.Context, targetPostID string, status model.PostReferenceStatus) error {
return r.db.WithContext(ctx).Model(&model.PostReference{}).
Where("target_post_id = ?", targetPostID).
Update("status", status).Error
}
func (r *postRefRepository) IncrementClickCount(ctx context.Context, sourcePostID, targetPostID string) error {
return r.db.WithContext(ctx).Model(&model.PostReference{}).
Where("source_post_id = ? AND target_post_id = ?", sourcePostID, targetPostID).
UpdateColumn("click_count", gorm.Expr("click_count + 1")).Error
}