repo_description: A new AList Fork to Anti Trust Crisis
repo_topics: alist aliyunpan baidupan openlist
code: package db
  
  import (
  	"fmt"
  	stdpath "path"
  	"strings"
  
  	"github.com/OpenListTeam/OpenList/v4/internal/conf"
  	"github.com/OpenListTeam/OpenList/v4/internal/model"
  	"github.com/OpenListTeam/OpenList/v4/pkg/utils"
  	"github.com/pkg/errors"
  	"gorm.io/gorm"
  )
  
  func whereInParent(parent string) *gorm.DB {
  	if parent == "/" {
  		return db.Where("1 = 1")
  	}
  	return db.Where(fmt.Sprintf("%s LIKE ?", columnName("parent")),
  		fmt.Sprintf("%s/%%", parent)).
  		Or(fmt.Sprintf("%s = ?", columnName("parent")), parent)
  }
  
  func CreateSearchNode(node *model.SearchNode) error {
  	return db.Create(node).Error
  }
  
  func BatchCreateSearchNodes(nodes *[]model.SearchNode) error {
  	return db.CreateInBatches(nodes, 1000).Error
  }
  
  func DeleteSearchNodesByParent(path string) error {
  	path = utils.FixAndCleanPath(path)
  	err := db.Where(whereInParent(path)).Delete(&model.SearchNode{}).Error
  	if err != nil {
  		return err
  	}
  	dir, name := stdpath.Split(path)
  	return db.Where(fmt.Sprintf("%s = ? AND %s = ?",
  		columnName("parent"), columnName("name")),
  		dir, name).Delete(&model.SearchNode{}).Error
  }
  
  func ClearSearchNodes() error {
  	return db.Where("1 = 1").Delete(&model.SearchNode{}).Error
  }
  
  func GetSearchNodesByParent(parent string) ([]model.SearchNode, error) {
  	var nodes []model.SearchNode
  	if err := db.Where(fmt.Sprintf("%s = ?",
  		columnName("parent")), parent).Find(&nodes).Error; err != nil {
  		return nil, err
  	}
  	return nodes, nil
  }
  
  func SearchNode(req model.SearchReq, useFullText bool) ([]model.SearchNode, int64, error) {
  	var searchDB *gorm.DB
  	if !useFullText || conf.Conf.Database.Type == "sqlite3" {
  		keywordsClause := db.Where("1 = 1")
  		for _, keyword := range strings.Fields(req.Keywords) {
  			keywordsClause = keywordsClause.Where("name LIKE ?", fmt.Sprintf("%%%s%%", keyword))
  		}
  		searchDB = db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)).Where(keywordsClause)
  	} else {
  		switch conf.Conf.Database.Type {
  		case "mysql":
  			searchDB = db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)).
  				Where("MATCH (name) AGAINST (? IN BOOLEAN MODE)", "'*"+req.Keywords+"*'")
  		case "postgres":
  			searchDB = db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)).
  				Where("to_tsvector(name) @@ to_tsquery(?)", strings.Join(strings.Fields(req.Keywords), " & "))
  		}
  	}
  
  	if req.Scope != 0 {
  		isDir := req.Scope == 1
  		searchDB.Where(db.Where("is_dir = ?", isDir))
  	}
  
  	var count int64
  	if err := searchDB.Count(&count).Error; err != nil {
  		return nil, 0, errors.Wrapf(err, "failed get search items count")
  	}
  	var files []model.SearchNode
  	if err := searchDB.Order("name asc").Offset((req.Page - 1) * req.PerPage).Limit(req.PerPage).
  		Find(&files).Error; err != nil {
  		return nil, 0, err
  	}
  	return files, count, nil
  }
  