mirror of https://github.com/Xhofe/alist
193 lines
5.4 KiB
Go
193 lines
5.4 KiB
Go
package db
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/alist-org/alist/v3/internal/model"
|
|
"github.com/pkg/errors"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
"time"
|
|
)
|
|
|
|
// GetLabelIds Get all label_ids from database order by file_name
|
|
func GetLabelIds(userId uint, fileName string) ([]uint, error) {
|
|
//fmt.Printf(">>> [GetLabelIds] userId: %d, fileName: %s\n", userId, fileName)
|
|
labelFileBinDingDB := db.Model(&model.LabelFileBinding{})
|
|
var labelIds []uint
|
|
if err := labelFileBinDingDB.Where("file_name = ?", fileName).Where("user_id = ?", userId).Pluck("label_id", &labelIds).Error; err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
return labelIds, nil
|
|
}
|
|
|
|
func CreateLabelFileBinDing(fileName string, labelId, userId uint) error {
|
|
var labelFileBinDing model.LabelFileBinding
|
|
labelFileBinDing.UserId = userId
|
|
labelFileBinDing.LabelId = labelId
|
|
labelFileBinDing.FileName = fileName
|
|
labelFileBinDing.CreateTime = time.Now()
|
|
err := errors.WithStack(db.Create(&labelFileBinDing).Error)
|
|
if err != nil {
|
|
return errors.WithMessage(err, "failed create label in database")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetLabelFileBinDingByLabelIdExists Get Label by label_id, used to del label usually
|
|
func GetLabelFileBinDingByLabelIdExists(labelId, userId uint) bool {
|
|
var labelFileBinDing model.LabelFileBinding
|
|
result := db.Where("label_id = ?", labelId).Where("user_id = ?", userId).First(&labelFileBinDing)
|
|
exists := !errors.Is(result.Error, gorm.ErrRecordNotFound)
|
|
return exists
|
|
}
|
|
|
|
// DelLabelFileBinDingByFileName used to del usually
|
|
func DelLabelFileBinDingByFileName(userId uint, fileName string) error {
|
|
return errors.WithStack(db.Where("file_name = ?", fileName).Where("user_id = ?", userId).Delete(model.LabelFileBinding{}).Error)
|
|
}
|
|
|
|
// DelLabelFileBinDingById used to del usually
|
|
func DelLabelFileBinDingById(labelId, userId uint, fileName string) error {
|
|
return errors.WithStack(db.Where("label_id = ?", labelId).Where("file_name = ?", fileName).Where("user_id = ?", userId).Delete(model.LabelFileBinding{}).Error)
|
|
}
|
|
|
|
func GetLabelFileBinDingByLabelId(labelIds []uint, userId uint) (result []model.LabelFileBinding, err error) {
|
|
if err := db.Where("label_id in (?)", labelIds).Where("user_id = ?", userId).Find(&result).Error; err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func GetLabelBindingsByFileNamesPublic(fileNames []string) (map[string][]uint, error) {
|
|
var binds []model.LabelFileBinding
|
|
if err := db.Where("file_name IN ?", fileNames).Find(&binds).Error; err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
out := make(map[string][]uint, len(fileNames))
|
|
seen := make(map[string]struct{}, len(binds))
|
|
for _, b := range binds {
|
|
key := fmt.Sprintf("%s-%d", b.FileName, b.LabelId)
|
|
if _, ok := seen[key]; ok {
|
|
continue
|
|
}
|
|
seen[key] = struct{}{}
|
|
out[b.FileName] = append(out[b.FileName], b.LabelId)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func GetLabelsByFileNamesPublic(fileNames []string) (map[string][]model.Label, error) {
|
|
bindMap, err := GetLabelBindingsByFileNamesPublic(fileNames)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
idSet := make(map[uint]struct{})
|
|
for _, ids := range bindMap {
|
|
for _, id := range ids {
|
|
idSet[id] = struct{}{}
|
|
}
|
|
}
|
|
if len(idSet) == 0 {
|
|
return make(map[string][]model.Label, 0), nil
|
|
}
|
|
allIDs := make([]uint, 0, len(idSet))
|
|
for id := range idSet {
|
|
allIDs = append(allIDs, id)
|
|
}
|
|
labels, err := GetLabelByIds(allIDs) // 你已有的函数
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
labelByID := make(map[uint]model.Label, len(labels))
|
|
for _, l := range labels {
|
|
labelByID[l.ID] = l
|
|
}
|
|
|
|
out := make(map[string][]model.Label, len(bindMap))
|
|
for fname, ids := range bindMap {
|
|
for _, id := range ids {
|
|
if lab, ok := labelByID[id]; ok {
|
|
out[fname] = append(out[fname], lab)
|
|
}
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func ListLabelFileBinDing(userId uint, labelIDs []uint, fileName string, page, pageSize int) ([]model.LabelFileBinding, int64, error) {
|
|
q := db.Model(&model.LabelFileBinding{}).Where("user_id = ?", userId)
|
|
|
|
if len(labelIDs) > 0 {
|
|
q = q.Where("label_id IN ?", labelIDs)
|
|
}
|
|
if fileName != "" {
|
|
q = q.Where("file_name LIKE ?", "%"+fileName+"%")
|
|
}
|
|
|
|
var total int64
|
|
if err := q.Count(&total).Error; err != nil {
|
|
return nil, 0, errors.WithStack(err)
|
|
}
|
|
|
|
var rows []model.LabelFileBinding
|
|
if err := q.
|
|
Order("id DESC").
|
|
Offset((page - 1) * pageSize).
|
|
Limit(pageSize).
|
|
Find(&rows).Error; err != nil {
|
|
return nil, 0, errors.WithStack(err)
|
|
}
|
|
return rows, total, nil
|
|
}
|
|
|
|
func RestoreLabelFileBindings(bindings []model.LabelFileBinding, keepIDs bool, override bool) error {
|
|
if len(bindings) == 0 {
|
|
return nil
|
|
}
|
|
tx := db.Begin()
|
|
|
|
if override {
|
|
type key struct {
|
|
uid uint
|
|
name string
|
|
}
|
|
toDel := make(map[key]struct{}, len(bindings))
|
|
for i := range bindings {
|
|
k := key{uid: bindings[i].UserId, name: bindings[i].FileName}
|
|
toDel[k] = struct{}{}
|
|
}
|
|
for k := range toDel {
|
|
if err := tx.Where("user_id = ? AND file_name = ?", k.uid, k.name).
|
|
Delete(&model.LabelFileBinding{}).Error; err != nil {
|
|
tx.Rollback()
|
|
return errors.WithStack(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
for i := range bindings {
|
|
b := bindings[i]
|
|
if !keepIDs {
|
|
b.ID = 0
|
|
}
|
|
if b.CreateTime.IsZero() {
|
|
b.CreateTime = time.Now()
|
|
}
|
|
if override {
|
|
if err := tx.Create(&b).Error; err != nil {
|
|
tx.Rollback()
|
|
return errors.WithStack(err)
|
|
}
|
|
} else {
|
|
if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&b).Error; err != nil {
|
|
tx.Rollback()
|
|
return errors.WithStack(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return errors.WithStack(tx.Commit().Error)
|
|
}
|