diff --git a/internal/bootstrap/db.go b/internal/bootstrap/db.go index 48d1f241..3408d8c4 100644 --- a/internal/bootstrap/db.go +++ b/internal/bootstrap/db.go @@ -42,6 +42,7 @@ func InitDB() { var err error if flags.Dev { dB, err = gorm.Open(sqlite.Open("file::memory:?cache=shared"), gormConfig) + conf.Conf.Database.Type = "sqlite3" } else { database := conf.Conf.Database switch database.Type { diff --git a/internal/db/db.go b/internal/db/db.go index c7480a64..400731b6 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -1,6 +1,7 @@ package db import ( + "fmt" "log" "github.com/alist-org/alist/v3/internal/conf" @@ -12,7 +13,21 @@ var db *gorm.DB func Init(d *gorm.DB) { db = d - err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode)) + var err error + switch conf.Conf.Database.Type { + case "sqlite3": + err = AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode)) + case "mysql": + err = AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNodeMySQL)) + case "postgres": + err = AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode)) + if err == nil { + db.Exec("CREATE EXTENSION pg_trgm;") + db.Exec("CREATE EXTENSION btree_gin;") + tableName := fmt.Sprintf("%ssearch_nodes", conf.Conf.Database.TablePrefix) + db.Exec(fmt.Sprintf("CREATE INDEX idx_%s_name ON %s USING GIN (name);", tableName, tableName)) + } + } if err != nil { log.Fatalf("failed migrate database: %s", err.Error()) } diff --git a/internal/db/searchnode.go b/internal/db/searchnode.go index 9479c366..97e00e9f 100644 --- a/internal/db/searchnode.go +++ b/internal/db/searchnode.go @@ -5,6 +5,7 @@ import ( "path" "strings" + "github.com/alist-org/alist/v3/internal/conf" "github.com/alist-org/alist/v3/internal/model" "github.com/alist-org/alist/v3/pkg/utils" "github.com/pkg/errors" @@ -53,13 +54,21 @@ func GetSearchNodesByParent(parent string) ([]model.SearchNode, error) { } func SearchNode(req model.SearchReq) ([]model.SearchNode, int64, error) { - keywordsClause := db.Where("1 = 1") - for _, keyword := range strings.Split(req.Keywords, " ") { - keywordsClause = keywordsClause.Where( - fmt.Sprintf("%s LIKE ?", columnName("name")), - fmt.Sprintf("%%%s%%", keyword)) + var searchDB *gorm.DB + switch conf.Conf.Database.Type { + case "sqlite3": + keywordsClause := db.Where("1 = 1") + for _, keyword := range strings.Split(req.Keywords, " ") { + keywordsClause = keywordsClause.Where("name LIKE ?", fmt.Sprintf("%%%s%%", keyword)) + } + searchDB = db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)).Where(keywordsClause) + case "mysql": + searchDB = db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)). + Where("MATCH (name) AGAINST (? IN NATURAL LANGUAGE MODE)", req.Keywords) + case "postgres": + searchDB = db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)). + Where("to_tsvector(name) @@ to_tsquery(?)", req.Keywords) } - searchDB := db.Model(&model.SearchNode{}).Where(whereInParent(req.Parent)).Where(keywordsClause) var count int64 if err := searchDB.Count(&count).Error; err != nil { return nil, 0, errors.Wrapf(err, "failed get users count") diff --git a/internal/model/search.go b/internal/model/search.go index ddcaee28..697e0a93 100644 --- a/internal/model/search.go +++ b/internal/model/search.go @@ -18,6 +18,13 @@ type SearchReq struct { PageReq } +type SearchNodeMySQL struct { + Parent string `json:"parent" gorm:"index"` + Name string `json:"name" gorm:"index:,class:FULLTEXT"` + IsDir bool `json:"is_dir"` + Size int64 `json:"size"` +} + type SearchNode struct { Parent string `json:"parent" gorm:"index"` Name string `json:"name"`