diff --git a/migrations/1678470811_add_indexes_column.go b/migrations/1678470811_add_indexes_column.go index e910d2fe..fbe75019 100644 --- a/migrations/1678470811_add_indexes_column.go +++ b/migrations/1678470811_add_indexes_column.go @@ -1,11 +1,18 @@ package migrations import ( + "fmt" + "strings" + "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/daos" + "github.com/pocketbase/pocketbase/models" + "github.com/pocketbase/pocketbase/tools/list" ) // Adds _collections indexes column (if not already). +// +// Note: This migration will be deleted once schema.SchemaField.Unuique is removed. func init() { AppMigrations.Register(func(db dbx.Builder) error { dao := daos.New(db) @@ -21,11 +28,76 @@ func init() { } } - _, err = db.AddColumn("_collections", "indexes", `JSON DEFAULT "[]" NOT NULL`).Execute() + if _, err := db.AddColumn("_collections", "indexes", `JSON DEFAULT "[]" NOT NULL`).Execute(); err != nil { + return err + } - // @todo populate existing indexes... + collections := []*models.Collection{} + if err := dao.CollectionQuery().AndWhere(dbx.NewExp("type != 'view'")).All(&collections); err != nil { + return err + } - return err + type indexInfo struct { + Sql string `db:"sql"` + IndexName string `db:"name"` + TableName string `db:"tbl_name"` + } + + indexesQuery := db.NewQuery(`SELECT * FROM sqlite_master WHERE type = "index" and sql is not null`) + rawIndexes := []indexInfo{} + if err := indexesQuery.All(&rawIndexes); err != nil { + return err + } + + indexesByTableName := map[string][]indexInfo{} + for _, idx := range rawIndexes { + indexesByTableName[idx.TableName] = append(indexesByTableName[idx.TableName], idx) + } + + for _, c := range collections { + totalIndexesBefore := len(c.Indexes) + + excludeIndexes := []string{ + "_" + c.Id + "_email_idx", + "_" + c.Id + "_username_idx", + "_" + c.Id + "_tokenKey_idx", + } + + // convert custom indexes into the related collections + for _, idx := range indexesByTableName[c.Name] { + if strings.Contains(idx.IndexName, "sqlite_autoindex_") || + list.ExistInSlice(idx.IndexName, excludeIndexes) { + continue + } + + // drop old index (it will be recreated witht the collection) + if _, err := db.DropIndex(idx.TableName, idx.IndexName).Execute(); err != nil { + return err + } + + c.Indexes = append(c.Indexes, idx.Sql) + } + + // convert unique fields to indexes + for _, f := range c.Schema.Fields() { + if f.Unique { + c.Indexes = append(c.Indexes, fmt.Sprintf( + `CREATE UNIQUE INDEX IF NOT EXISTS idx_%s on %s (%s)`, + f.Id, + c.Name, + f.Name, + )) + } + } + + if totalIndexesBefore != len(c.Indexes) { + if err := dao.SaveCollection(c); err != nil { + return err + } + } + } + + return nil }, func(db dbx.Builder) error { _, err := db.DropColumn("_collections", "indexes").Execute()