Files
urldb/db/repo/resource_repository.go

653 lines
22 KiB
Go
Raw Normal View History

2025-07-10 13:56:37 +08:00
package repo
import (
2025-07-11 17:45:16 +08:00
"fmt"
"time"
2025-07-10 13:56:37 +08:00
2025-07-18 09:42:07 +08:00
"github.com/ctwj/urldb/db/entity"
2025-10-28 11:07:00 +08:00
"github.com/ctwj/urldb/utils"
2025-07-10 13:56:37 +08:00
"gorm.io/gorm"
)
// ResourceRepository Resource的Repository接口
type ResourceRepository interface {
BaseRepository[entity.Resource]
FindWithRelations() ([]entity.Resource, error)
2025-07-11 17:45:16 +08:00
FindWithRelationsPaginated(page, limit int) ([]entity.Resource, int64, error)
2025-07-10 13:56:37 +08:00
FindByCategoryID(categoryID uint) ([]entity.Resource, error)
2025-07-11 17:45:16 +08:00
FindByCategoryIDPaginated(categoryID uint, page, limit int) ([]entity.Resource, int64, error)
2025-07-10 13:56:37 +08:00
FindByPanID(panID uint) ([]entity.Resource, error)
2025-07-11 17:45:16 +08:00
FindByPanIDPaginated(panID uint, page, limit int) ([]entity.Resource, int64, error)
2025-07-10 13:56:37 +08:00
FindByIsValid(isValid bool) ([]entity.Resource, error)
FindByIsPublic(isPublic bool) ([]entity.Resource, error)
Search(query string, categoryID *uint, page, limit int) ([]entity.Resource, int64, error)
2025-07-15 12:50:24 +08:00
SearchByPanID(query string, panID uint, page, limit int) ([]entity.Resource, int64, error)
2025-07-16 18:05:29 +08:00
SearchWithFilters(params map[string]interface{}) ([]entity.Resource, int64, error)
2025-07-10 13:56:37 +08:00
IncrementViewCount(id uint) error
FindWithTags() ([]entity.Resource, error)
UpdateWithTags(resource *entity.Resource, tagIDs []uint) error
2025-07-11 17:45:16 +08:00
GetLatestResources(limit int) ([]entity.Resource, error)
GetCachedLatestResources(limit int) ([]entity.Resource, error)
InvalidateCache() error
2025-07-12 21:23:23 +08:00
FindExists(url string, excludeID ...uint) (bool, error)
BatchFindByURLs(urls []string) ([]entity.Resource, error)
2025-08-05 18:09:14 +08:00
GetResourcesForTransfer(panID uint, sinceTime time.Time, limit int) ([]*entity.Resource, error)
2025-08-09 23:47:30 +08:00
GetByURL(url string) (*entity.Resource, error)
UpdateSaveURL(id uint, saveURL string) error
CreateResourceTag(resourceTag *entity.ResourceTag) error
2025-08-20 15:03:14 +08:00
FindByIDs(ids []uint) ([]entity.Resource, error)
FindUnsyncedToMeilisearch(page, limit int) ([]entity.Resource, int64, error)
FindSyncedToMeilisearch(page, limit int) ([]entity.Resource, int64, error)
CountUnsyncedToMeilisearch() (int64, error)
CountSyncedToMeilisearch() (int64, error)
MarkAsSyncedToMeilisearch(ids []uint) error
MarkAllAsUnsyncedToMeilisearch() error
FindAllWithPagination(page, limit int) ([]entity.Resource, int64, error)
2025-09-22 07:58:06 +08:00
GetRandomResourceWithFilters(categoryFilter, tagFilter string, isPushSavedInfo bool) (*entity.Resource, error)
2025-07-10 13:56:37 +08:00
}
// ResourceRepositoryImpl Resource的Repository实现
type ResourceRepositoryImpl struct {
BaseRepositoryImpl[entity.Resource]
2025-07-11 17:45:16 +08:00
cache map[string]interface{}
2025-07-10 13:56:37 +08:00
}
// NewResourceRepository 创建Resource Repository
func NewResourceRepository(db *gorm.DB) ResourceRepository {
return &ResourceRepositoryImpl{
BaseRepositoryImpl: BaseRepositoryImpl[entity.Resource]{db: db},
2025-07-11 17:45:16 +08:00
cache: make(map[string]interface{}),
2025-07-10 13:56:37 +08:00
}
}
// FindWithRelations 查找包含关联关系的资源
func (r *ResourceRepositoryImpl) FindWithRelations() ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Preload("Category").Preload("Pan").Preload("Tags").Find(&resources).Error
return resources, err
}
2025-07-11 17:45:16 +08:00
// FindWithRelationsPaginated 分页查找包含关联关系的资源
func (r *ResourceRepositoryImpl) FindWithRelationsPaginated(page, limit int) ([]entity.Resource, int64, error) {
// 使用新的分页查询功能
options := &PaginationOptions{
Page: page,
PageSize: limit,
OrderBy: "updated_at",
OrderDir: "desc",
Preloads: []string{"Category", "Pan"},
}
2025-07-11 18:37:28 +08:00
result, err := PaginatedQuery[entity.Resource](r.db, options)
if err != nil {
return nil, 0, err
2025-07-11 17:45:16 +08:00
}
return result.Data, result.Total, nil
2025-07-11 17:45:16 +08:00
}
2025-07-10 13:56:37 +08:00
// FindByCategoryID 根据分类ID查找
func (r *ResourceRepositoryImpl) FindByCategoryID(categoryID uint) ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Where("category_id = ?", categoryID).Preload("Category").Preload("Tags").Find(&resources).Error
return resources, err
}
2025-07-11 17:45:16 +08:00
// FindByCategoryIDPaginated 分页根据分类ID查找
func (r *ResourceRepositoryImpl) FindByCategoryIDPaginated(categoryID uint, page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
2025-07-15 12:50:24 +08:00
db := r.db.Model(&entity.Resource{}).Where("category_id = ?", categoryID).Preload("Category").Preload("Tags").Order("updated_at DESC")
2025-07-11 17:45:16 +08:00
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
// 获取分页数据
err := db.Offset(offset).Limit(limit).Find(&resources).Error
return resources, total, err
}
2025-07-10 13:56:37 +08:00
// FindByPanID 根据平台ID查找
func (r *ResourceRepositoryImpl) FindByPanID(panID uint) ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Where("pan_id = ?", panID).Preload("Category").Preload("Tags").Find(&resources).Error
return resources, err
}
2025-07-11 17:45:16 +08:00
// FindByPanIDPaginated 分页根据平台ID查找
func (r *ResourceRepositoryImpl) FindByPanIDPaginated(panID uint, page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
2025-07-15 12:50:24 +08:00
db := r.db.Model(&entity.Resource{}).Where("pan_id = ?", panID).Preload("Category").Preload("Tags").Order("updated_at DESC")
2025-07-11 17:45:16 +08:00
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
// 获取分页数据
err := db.Offset(offset).Limit(limit).Find(&resources).Error
return resources, total, err
}
2025-07-10 13:56:37 +08:00
// FindByIsValid 根据有效性查找
func (r *ResourceRepositoryImpl) FindByIsValid(isValid bool) ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Where("is_valid = ?", isValid).Preload("Category").Preload("Tags").Find(&resources).Error
return resources, err
}
// FindByIsPublic 根据公开性查找
func (r *ResourceRepositoryImpl) FindByIsPublic(isPublic bool) ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Where("is_public = ?", isPublic).Preload("Category").Preload("Tags").Find(&resources).Error
return resources, err
}
// Search 搜索资源
func (r *ResourceRepositoryImpl) Search(query string, categoryID *uint, page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
db := r.db.Model(&entity.Resource{}).Preload("Category").Preload("Tags")
// 构建查询条件
if query != "" {
db = db.Where("title ILIKE ? OR description ILIKE ?", "%"+query+"%", "%"+query+"%")
}
if categoryID != nil {
db = db.Where("category_id = ?", *categoryID)
}
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
2025-07-15 12:50:24 +08:00
// 获取分页数据,按更新时间倒序
err := db.Order("updated_at DESC").Offset(offset).Limit(limit).Find(&resources).Error
return resources, total, err
}
// SearchByPanID 在指定平台内搜索资源
func (r *ResourceRepositoryImpl) SearchByPanID(query string, panID uint, page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
db := r.db.Model(&entity.Resource{}).Preload("Category").Preload("Tags").Where("pan_id = ?", panID)
// 构建查询条件
if query != "" {
db = db.Where("title ILIKE ? OR description ILIKE ?", "%"+query+"%", "%"+query+"%")
}
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
// 获取分页数据,按更新时间倒序
err := db.Order("updated_at DESC").Offset(offset).Limit(limit).Find(&resources).Error
2025-07-10 13:56:37 +08:00
return resources, total, err
}
2025-07-16 18:05:29 +08:00
// SearchWithFilters 根据参数进行搜索
func (r *ResourceRepositoryImpl) SearchWithFilters(params map[string]interface{}) ([]entity.Resource, int64, error) {
2025-10-28 11:07:00 +08:00
startTime := utils.GetCurrentTime()
2025-07-16 18:05:29 +08:00
var resources []entity.Resource
var total int64
2025-08-11 01:34:07 +08:00
db := r.db.Model(&entity.Resource{}).Preload("Category").Preload("Pan").Preload("Tags")
2025-07-16 18:05:29 +08:00
// 处理参数
for key, value := range params {
switch key {
2025-07-31 17:28:10 +08:00
case "search": // 添加search参数支持
2025-07-16 18:05:29 +08:00
if query, ok := value.(string); ok && query != "" {
db = db.Where("title ILIKE ? OR description ILIKE ?", "%"+query+"%", "%"+query+"%")
}
2025-08-08 01:28:25 +08:00
case "category_id": // 添加category_id参数支持
if categoryID, ok := value.(uint); ok {
fmt.Printf("应用分类筛选: category_id = %d\n", categoryID)
db = db.Where("category_id = ?", categoryID)
} else {
fmt.Printf("分类ID类型错误: %T, value: %v\n", value, value)
}
2025-07-31 17:28:10 +08:00
case "category": // 添加category参数支持字符串形式
if category, ok := value.(string); ok && category != "" {
// 根据分类名称查找分类ID
var categoryEntity entity.Category
if err := r.db.Where("name ILIKE ?", "%"+category+"%").First(&categoryEntity).Error; err == nil {
db = db.Where("category_id = ?", categoryEntity.ID)
}
2025-07-16 18:05:29 +08:00
}
2025-07-31 17:28:10 +08:00
case "tag": // 添加tag参数支持
if tag, ok := value.(string); ok && tag != "" {
// 根据标签名称查找相关资源
var tagEntity entity.Tag
if err := r.db.Where("name ILIKE ?", "%"+tag+"%").First(&tagEntity).Error; err == nil {
// 通过中间表查找包含该标签的资源
db = db.Joins("JOIN resource_tags ON resources.id = resource_tags.resource_id").
Where("resource_tags.tag_id = ?", tagEntity.ID)
}
2025-07-16 18:05:29 +08:00
}
2025-08-04 14:18:45 +08:00
case "pan_id": // 添加pan_id参数支持
if panID, ok := value.(uint); ok {
db = db.Where("pan_id = ?", panID)
}
case "is_valid":
if isValid, ok := value.(bool); ok {
db = db.Where("is_valid = ?", isValid)
}
case "is_public":
if isPublic, ok := value.(bool); ok {
db = db.Where("is_public = ?", isPublic)
}
2025-08-11 01:34:07 +08:00
case "has_save_url": // 添加has_save_url参数支持
if hasSaveURL, ok := value.(bool); ok {
fmt.Printf("处理 has_save_url 参数: %v\n", hasSaveURL)
if hasSaveURL {
// 有转存链接save_url不为空且不为空格
db = db.Where("save_url IS NOT NULL AND save_url != '' AND TRIM(save_url) != ''")
fmt.Printf("应用 has_save_url=true 条件: save_url IS NOT NULL AND save_url != '' AND TRIM(save_url) != ''\n")
} else {
// 没有转存链接save_url为空、NULL或只有空格
db = db.Where("(save_url IS NULL OR save_url = '' OR TRIM(save_url) = '')")
fmt.Printf("应用 has_save_url=false 条件: (save_url IS NULL OR save_url = '' OR TRIM(save_url) = '')\n")
}
}
case "no_save_url": // 添加no_save_url参数支持与has_save_url=false相同
if noSaveURL, ok := value.(bool); ok && noSaveURL {
db = db.Where("(save_url IS NULL OR save_url = '' OR TRIM(save_url) = '')")
}
case "pan_name": // 添加pan_name参数支持
if panName, ok := value.(string); ok && panName != "" {
// 根据平台名称查找平台ID
var panEntity entity.Pan
if err := r.db.Where("name ILIKE ?", "%"+panName+"%").First(&panEntity).Error; err == nil {
db = db.Where("pan_id = ?", panEntity.ID)
}
}
2025-07-16 18:05:29 +08:00
}
}
2025-08-04 14:18:45 +08:00
2025-08-08 01:28:25 +08:00
// 管理后台显示所有资源公开API才限制为有效的公开资源
// 这里通过检查请求来源来判断是否为管理后台
// 如果没有明确指定is_valid和is_public则显示所有资源
// 注意:这个逻辑可能需要根据实际需求调整
2025-08-04 14:18:45 +08:00
if _, hasIsValid := params["is_valid"]; !hasIsValid {
2025-08-08 01:28:25 +08:00
// 管理后台不限制is_valid
// db = db.Where("is_valid = ?", true)
2025-08-04 14:18:45 +08:00
}
if _, hasIsPublic := params["is_public"]; !hasIsPublic {
2025-08-08 01:28:25 +08:00
// 管理后台不限制is_public
// db = db.Where("is_public = ?", true)
2025-08-04 14:18:45 +08:00
}
2025-07-16 18:05:29 +08:00
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
2025-07-31 17:28:10 +08:00
// 处理分页参数
page := 1
pageSize := 20
if pageVal, ok := params["page"].(int); ok && pageVal > 0 {
page = pageVal
}
if pageSizeVal, ok := params["page_size"].(int); ok && pageSizeVal > 0 {
pageSize = pageSizeVal
2025-08-08 01:28:25 +08:00
fmt.Printf("原始pageSize: %d\n", pageSize)
2025-08-11 17:51:04 +08:00
// 限制最大page_size为10000管理后台需要更大的数据量
if pageSize > 10000 {
pageSize = 10000
fmt.Printf("pageSize超过10000限制为: %d\n", pageSize)
2025-07-31 17:28:10 +08:00
}
2025-08-08 01:28:25 +08:00
fmt.Printf("最终pageSize: %d\n", pageSize)
2025-07-31 17:28:10 +08:00
}
// 计算偏移量
offset := (page - 1) * pageSize
2025-07-16 18:05:29 +08:00
// 获取分页数据,按更新时间倒序
2025-10-28 11:07:00 +08:00
queryStart := utils.GetCurrentTime()
2025-07-31 17:28:10 +08:00
err := db.Order("updated_at DESC").Offset(offset).Limit(pageSize).Find(&resources).Error
2025-10-28 11:07:00 +08:00
queryDuration := time.Since(queryStart)
totalDuration := time.Since(startTime)
utils.Debug("SearchWithFilters完成: 总数=%d, 当前页数据量=%d, 查询耗时=%v, 总耗时=%v", total, len(resources), queryDuration, totalDuration)
2025-07-16 18:05:29 +08:00
return resources, total, err
}
2025-07-10 13:56:37 +08:00
// IncrementViewCount 增加浏览次数
func (r *ResourceRepositoryImpl) IncrementViewCount(id uint) error {
return r.db.Model(&entity.Resource{}).Where("id = ?", id).
UpdateColumn("view_count", gorm.Expr("view_count + ?", 1)).Error
}
// FindWithTags 查找包含标签的资源
func (r *ResourceRepositoryImpl) FindWithTags() ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Preload("Tags").Find(&resources).Error
return resources, err
}
// UpdateWithTags 更新资源及其标签
func (r *ResourceRepositoryImpl) UpdateWithTags(resource *entity.Resource, tagIDs []uint) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// 更新资源
if err := tx.Save(resource).Error; err != nil {
return err
}
// 删除旧的标签关联
if err := tx.Where("resource_id = ?", resource.ID).Delete(&entity.ResourceTag{}).Error; err != nil {
return err
}
// 创建新的标签关联
for _, tagID := range tagIDs {
resourceTag := &entity.ResourceTag{
ResourceID: resource.ID,
TagID: tagID,
}
if err := tx.Create(resourceTag).Error; err != nil {
return err
}
}
return nil
})
}
2025-07-11 17:45:16 +08:00
// GetLatestResources 获取最新资源
func (r *ResourceRepositoryImpl) GetLatestResources(limit int) ([]entity.Resource, error) {
var resources []entity.Resource
err := r.db.Order("created_at DESC").Limit(limit).Find(&resources).Error
return resources, err
}
// GetCachedLatestResources 获取缓存的最新资源
func (r *ResourceRepositoryImpl) GetCachedLatestResources(limit int) ([]entity.Resource, error) {
cacheKey := fmt.Sprintf("latest_resources_%d", limit)
// 检查缓存
if cached, exists := r.cache[cacheKey]; exists {
if resources, ok := cached.([]entity.Resource); ok {
return resources, nil
}
}
// 从数据库获取
resources, err := r.GetLatestResources(limit)
if err != nil {
return nil, err
}
// 缓存结果5分钟过期
r.cache[cacheKey] = resources
go func() {
time.Sleep(5 * time.Minute)
delete(r.cache, cacheKey)
}()
return resources, nil
}
// InvalidateCache 清除缓存
func (r *ResourceRepositoryImpl) InvalidateCache() error {
r.cache = make(map[string]interface{})
return nil
}
2025-07-12 21:23:23 +08:00
// FindExists 检查是否存在相同URL的资源
func (r *ResourceRepositoryImpl) FindExists(url string, excludeID ...uint) (bool, error) {
var count int64
query := r.db.Model(&entity.Resource{}).Where("url = ? OR save_url = ?", url, url)
2025-07-12 21:23:23 +08:00
// 如果有排除ID则排除该记录用于更新时排除自己
if len(excludeID) > 0 {
query = query.Where("id != ?", excludeID[0])
}
err := query.Count(&count).Error
if err != nil {
return false, err
}
return count > 0, nil
}
func (r *ResourceRepositoryImpl) BatchFindByURLs(urls []string) ([]entity.Resource, error) {
var resources []entity.Resource
if len(urls) == 0 {
return resources, nil
}
err := r.db.Where("url IN ?", urls).Find(&resources).Error
return resources, err
}
2025-07-24 01:05:46 +08:00
// GetResourcesForTransfer 获取需要转存的资源
2025-08-05 18:09:14 +08:00
func (r *ResourceRepositoryImpl) GetResourcesForTransfer(panID uint, sinceTime time.Time, limit int) ([]*entity.Resource, error) {
2025-07-24 01:05:46 +08:00
var resources []*entity.Resource
query := r.db.Where("pan_id = ? AND (save_url = '' OR save_url IS NULL) AND (error_msg = '' OR error_msg IS NULL)", panID)
if !sinceTime.IsZero() {
query = query.Where("created_at >= ?", sinceTime)
}
2025-08-05 18:09:14 +08:00
// 添加数量限制
if limit > 0 {
query = query.Limit(limit)
}
2025-07-24 01:05:46 +08:00
err := query.Order("created_at DESC").Find(&resources).Error
if err != nil {
return nil, err
}
return resources, nil
}
2025-07-25 22:24:08 +08:00
2025-08-09 23:47:30 +08:00
// GetByURL 根据URL获取资源
func (r *ResourceRepositoryImpl) GetByURL(url string) (*entity.Resource, error) {
2025-10-28 11:07:00 +08:00
startTime := utils.GetCurrentTime()
2025-08-09 23:47:30 +08:00
var resource entity.Resource
2025-08-20 15:03:14 +08:00
err := r.db.Where("url = ?", url).First(&resource).Error
2025-10-28 11:07:00 +08:00
queryDuration := time.Since(startTime)
2025-08-09 23:47:30 +08:00
if err != nil {
2025-10-28 11:07:00 +08:00
utils.Debug("GetByURL失败: URL=%s, 错误=%v, 查询耗时=%v", url, err, queryDuration)
2025-08-09 23:47:30 +08:00
return nil, err
2025-07-25 22:24:08 +08:00
}
2025-10-28 11:07:00 +08:00
utils.Debug("GetByURL成功: URL=%s, 查询耗时=%v", url, queryDuration)
2025-08-09 23:47:30 +08:00
return &resource, nil
}
2025-08-20 15:03:14 +08:00
// FindByIDs 根据ID列表查找资源
func (r *ResourceRepositoryImpl) FindByIDs(ids []uint) ([]entity.Resource, error) {
if len(ids) == 0 {
return []entity.Resource{}, nil
}
var resources []entity.Resource
err := r.db.Where("id IN ?", ids).Preload("Category").Preload("Pan").Preload("Tags").Find(&resources).Error
return resources, err
}
// UpdateSaveURL 更新保存URL
2025-08-09 23:47:30 +08:00
func (r *ResourceRepositoryImpl) UpdateSaveURL(id uint, saveURL string) error {
2025-08-20 15:03:14 +08:00
return r.db.Model(&entity.Resource{}).Where("id = ?", id).Update("save_url", saveURL).Error
2025-08-09 23:47:30 +08:00
}
// CreateResourceTag 创建资源与标签的关联
func (r *ResourceRepositoryImpl) CreateResourceTag(resourceTag *entity.ResourceTag) error {
2025-08-20 15:03:14 +08:00
return r.db.Create(resourceTag).Error
}
// FindUnsyncedToMeilisearch 查找未同步到Meilisearch的资源
func (r *ResourceRepositoryImpl) FindUnsyncedToMeilisearch(page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
// 查询未同步的资源
db := r.db.Model(&entity.Resource{}).
Where("synced_to_meilisearch = ?", false).
Preload("Category").
Preload("Pan").
2025-08-25 09:51:45 +08:00
Preload("Tags"). // 添加Tags预加载
2025-08-20 15:03:14 +08:00
Order("updated_at DESC")
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
// 获取分页数据
err := db.Offset(offset).Limit(limit).Find(&resources).Error
return resources, total, err
}
// CountUnsyncedToMeilisearch 统计未同步到Meilisearch的资源数量
func (r *ResourceRepositoryImpl) CountUnsyncedToMeilisearch() (int64, error) {
var count int64
err := r.db.Model(&entity.Resource{}).
Where("synced_to_meilisearch = ?", false).
Count(&count).Error
return count, err
}
// MarkAsSyncedToMeilisearch 标记资源为已同步到Meilisearch
func (r *ResourceRepositoryImpl) MarkAsSyncedToMeilisearch(ids []uint) error {
if len(ids) == 0 {
return nil
}
now := time.Now()
return r.db.Model(&entity.Resource{}).
Where("id IN ?", ids).
Updates(map[string]interface{}{
"synced_to_meilisearch": true,
"synced_at": now,
}).Error
}
// MarkAllAsUnsyncedToMeilisearch 标记所有资源为未同步到Meilisearch
func (r *ResourceRepositoryImpl) MarkAllAsUnsyncedToMeilisearch() error {
return r.db.Model(&entity.Resource{}).
Where("1 = 1"). // 添加WHERE条件以更新所有记录
Updates(map[string]interface{}{
"synced_to_meilisearch": false,
"synced_at": nil,
}).Error
}
// FindSyncedToMeilisearch 查找已同步到Meilisearch的资源
func (r *ResourceRepositoryImpl) FindSyncedToMeilisearch(page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
// 查询已同步的资源
db := r.db.Model(&entity.Resource{}).
Where("synced_to_meilisearch = ?", true).
Preload("Category").
Preload("Pan").
2025-09-08 01:36:20 +08:00
Preload("Tags").
2025-08-20 15:03:14 +08:00
Order("updated_at DESC")
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
// 获取分页数据
err := db.Offset(offset).Limit(limit).Find(&resources).Error
return resources, total, err
}
// CountSyncedToMeilisearch 统计已同步到Meilisearch的资源数量
func (r *ResourceRepositoryImpl) CountSyncedToMeilisearch() (int64, error) {
var count int64
err := r.db.Model(&entity.Resource{}).
Where("synced_to_meilisearch = ?", true).
Count(&count).Error
return count, err
}
// FindAllWithPagination 分页查找所有资源
func (r *ResourceRepositoryImpl) FindAllWithPagination(page, limit int) ([]entity.Resource, int64, error) {
var resources []entity.Resource
var total int64
offset := (page - 1) * limit
// 查询所有资源
db := r.db.Model(&entity.Resource{}).
Preload("Category").
Preload("Pan").
2025-09-08 01:36:20 +08:00
Preload("Tags").
2025-08-20 15:03:14 +08:00
Order("updated_at DESC")
// 获取总数
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
// 获取分页数据
err := db.Offset(offset).Limit(limit).Find(&resources).Error
return resources, total, err
2025-07-25 22:24:08 +08:00
}
2025-09-22 07:58:06 +08:00
// GetRandomResourceWithFilters 使用 PostgreSQL RANDOM() 功能随机获取一个符合条件的资源
func (r *ResourceRepositoryImpl) GetRandomResourceWithFilters(categoryFilter, tagFilter string, isPushSavedInfo bool) (*entity.Resource, error) {
// 构建查询条件
query := r.db.Model(&entity.Resource{}).Preload("Category").Preload("Pan").Preload("Tags")
// 基础条件:有效且公开的资源
query = query.Where("is_valid = ? AND is_public = ?", true, true)
// 根据分类过滤
if categoryFilter != "" {
// 查找分类ID
var categoryEntity entity.Category
if err := r.db.Where("name ILIKE ?", "%"+categoryFilter+"%").First(&categoryEntity).Error; err == nil {
query = query.Where("category_id = ?", categoryEntity.ID)
}
}
// 根据标签过滤
if tagFilter != "" {
// 查找标签ID
var tagEntity entity.Tag
if err := r.db.Where("name ILIKE ?", "%"+tagFilter+"%").First(&tagEntity).Error; err == nil {
// 通过中间表查找包含该标签的资源
query = query.Joins("JOIN resource_tags ON resources.id = resource_tags.resource_id").
Where("resource_tags.tag_id = ?", tagEntity.ID)
}
}
// // 根据是否只推送已转存资源过滤
// if isPushSavedInfo {
// query = query.Where("save_url IS NOT NULL AND save_url != '' AND TRIM(save_url) != ''")
// }
// 使用 PostgreSQL 的 RANDOM() 进行随机排序并限制为1个结果
var resource entity.Resource
err := query.Order("RANDOM()").Limit(1).First(&resource).Error
if err != nil {
return nil, err
}
return &resource, nil
}