diff --git a/CHANGELOG.md b/CHANGELOG.md index 11839c3e..2e7a3824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## (WIP) v0.9.0 +- Added `Record.OriginalCopy()` method that returns a new `Record` copy populated with the initially loaded record data (useful if you want to compare old and new field values). + - Added new event hooks: ```go app.OnBeforeBootstrap() @@ -16,7 +18,7 @@ migrationsDir := "" // default to "pb_migrations" (for js) and "migrations" (for go) // load js files if you want to allow loading external JavaScript migrations - jsvm.MustRegisterMigrationsLoader(app, &jsvm.MigrationsLoaderOptions{ + jsvm.MustRegisterMigrations(app, &jsvm.MigrationsOptions{ Dir: migrationsDir, }) diff --git a/examples/base/main.go b/examples/base/main.go index 92fd20d2..7af1d144 100644 --- a/examples/base/main.go +++ b/examples/base/main.go @@ -3,11 +3,14 @@ package main import ( "log" "os" + "path/filepath" + "strings" "github.com/pocketbase/pocketbase" + "github.com/pocketbase/pocketbase/apis" + "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/plugins/jsvm" "github.com/pocketbase/pocketbase/plugins/migratecmd" - "github.com/pocketbase/pocketbase/plugins/publicdir" ) func main() { @@ -37,7 +40,7 @@ func main() { app.RootCmd.PersistentFlags().StringVar( &publicDir, "publicDir", - "", + defaultPublicDir(), "the directory to serve static files", ) @@ -52,11 +55,11 @@ func main() { app.RootCmd.ParseFlags(os.Args[1:]) // --------------------------------------------------------------- - // Plugins: + // Plugins and hooks: // --------------------------------------------------------------- // load js pb_migrations - jsvm.MustRegisterMigrationsLoader(app, &jsvm.MigrationsLoaderOptions{ + jsvm.MustRegisterMigrations(app, &jsvm.MigrationsOptions{ Dir: migrationsDir, }) @@ -67,13 +70,22 @@ func main() { Dir: migrationsDir, }) - // pb_public dir - publicdir.MustRegister(app, &publicdir.Options{ - Dir: publicDir, - IndexFallback: indexFallback, + app.OnBeforeServe().Add(func(e *core.ServeEvent) error { + // serves static files from the provided public dir (if exists) + e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS(publicDir), indexFallback)) + return nil }) if err := app.Start(); err != nil { log.Fatal(err) } } + +// the default pb_public dir location is relative to the executable +func defaultPublicDir() string { + if strings.HasPrefix(os.Args[0], os.TempDir()) { + // most likely ran with go run + return "./pb_public" + } + return filepath.Join(os.Args[0], "../pb_public") +} diff --git a/plugins/jsvm/migrations.go b/plugins/jsvm/migrations.go index 04087f9e..754c92c2 100644 --- a/plugins/jsvm/migrations.go +++ b/plugins/jsvm/migrations.go @@ -11,46 +11,46 @@ import ( m "github.com/pocketbase/pocketbase/migrations" ) -// MigrationsLoaderOptions defines optional struct to customize the default plugin behavior. -type MigrationsLoaderOptions struct { +// MigrationsOptions defines optional struct to customize the default migrations loader behavior. +type MigrationsOptions struct { // Dir specifies the directory with the JS migrations. // // If not set it fallbacks to a relative "pb_data/../pb_migrations" directory. Dir string } -// migrationsLoader is the plugin definition. -// Usually it is instantiated via RegisterMigrationsLoader or MustRegisterMigrationsLoader. -type migrationsLoader struct { +// migrations is the migrations loader plugin definition. +// Usually it is instantiated via RegisterMigrations or MustRegisterMigrations. +type migrations struct { app core.App - options *MigrationsLoaderOptions + options *MigrationsOptions } // -// MustRegisterMigrationsLoader registers the plugin to the provided -// app instance and panics if it fails. +// MustRegisterMigrations registers the migrations loader plugin to +// the provided app instance and panics if it fails. // -// It it calls RegisterMigrationsLoader(app, options) +// Internally it calls RegisterMigrations(app, options). // // If options is nil, by default the js files from pb_data/migrations are loaded. // Set custom options.Dir if you want to change it to some other directory. -func MustRegisterMigrationsLoader(app core.App, options *MigrationsLoaderOptions) { - if err := RegisterMigrationsLoader(app, options); err != nil { +func MustRegisterMigrations(app core.App, options *MigrationsOptions) { + if err := RegisterMigrations(app, options); err != nil { panic(err) } } -// RegisterMigrationsLoader registers the plugin to the provided app instance. +// RegisterMigrations registers the plugin to the provided app instance. // // If options is nil, by default the js files from pb_data/migrations are loaded. // Set custom options.Dir if you want to change it to some other directory. -func RegisterMigrationsLoader(app core.App, options *MigrationsLoaderOptions) error { - l := &migrationsLoader{app: app} +func RegisterMigrations(app core.App, options *MigrationsOptions) error { + l := &migrations{app: app} if options != nil { l.options = options } else { - l.options = &MigrationsLoaderOptions{} + l.options = &MigrationsOptions{} } if l.options.Dir == "" { diff --git a/plugins/migratecmd/migratecmd_test.go b/plugins/migratecmd/migratecmd_test.go index 95074a14..8264341b 100644 --- a/plugins/migratecmd/migratecmd_test.go +++ b/plugins/migratecmd/migratecmd_test.go @@ -667,7 +667,7 @@ func init() { // save the changes and trigger automigrate if err := app.Dao().SaveCollection(collection); err != nil { - t.Fatalf("[%d] Failed to delete dummy collection, got %v", i, err) + t.Fatalf("[%d] Failed to save dummy collection changes, got %v", i, err) } files, err := os.ReadDir(migrationsDir) @@ -695,3 +695,52 @@ func init() { } } } + +func TestAutomigrateCollectionNoChanges(t *testing.T) { + scenarios := []struct { + lang string + }{ + { + migratecmd.TemplateLangJS, + }, + { + migratecmd.TemplateLangGo, + }, + } + + for i, s := range scenarios { + app, _ := tests.NewTestApp() + defer app.Cleanup() + + migrationsDir := filepath.Join(app.DataDir(), "_test_migrations") + + migratecmd.MustRegister(app, nil, &migratecmd.Options{ + TemplateLang: s.lang, + Automigrate: true, + Dir: migrationsDir, + }) + + // create dummy collection + collection := &models.Collection{} + collection.Name = "test123" + collection.Type = models.CollectionTypeAuth + + // use different dao to avoid triggering automigrate while saving the dummy collection + if err := daos.New(app.DB()).SaveCollection(collection); err != nil { + t.Fatalf("[%d] Failed to save dummy collection, got %v", i, err) + } + + // @todo remove after collections cache is replaced + app.Bootstrap() + + // resave without changes and trigger automigrate + if err := app.Dao().SaveCollection(collection); err != nil { + t.Fatalf("[%d] Failed to save dummy collection update, got %v", i, err) + } + + files, _ := os.ReadDir(migrationsDir) + if total := len(files); total != 0 { + t.Fatalf("[%d] Expected 0 files to be generated, got %d", i, total) + } + } +} diff --git a/plugins/publicdir/publicdir.go b/plugins/publicdir/publicdir.go deleted file mode 100644 index 5152e278..00000000 --- a/plugins/publicdir/publicdir.go +++ /dev/null @@ -1,63 +0,0 @@ -// Example -// -// publicdir.MustRegister(app, &publicdir.Options{ -// FlagsCmd: app.RootCmd, -// IndexFallback: false, -// }) -package publicdir - -import ( - "os" - "path/filepath" - "strings" - - "github.com/pocketbase/pocketbase/apis" - "github.com/pocketbase/pocketbase/core" -) - -type Options struct { - Dir string - IndexFallback bool -} - -type plugin struct { - app core.App - options *Options -} - -func MustRegister(app core.App, options *Options) { - if err := Register(app, options); err != nil { - panic(err) - } -} - -func Register(app core.App, options *Options) error { - p := &plugin{app: app} - - if options != nil { - p.options = options - } else { - p.options = &Options{} - } - - if options.Dir == "" { - options.Dir = defaultPublicDir() - } - - p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { - // serves static files from the provided public dir (if exists) - e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS(options.Dir), options.IndexFallback)) - - return nil - }) - - return nil -} - -func defaultPublicDir() string { - if strings.HasPrefix(os.Args[0], os.TempDir()) { - // most likely ran with go run - return "./pb_public" - } - return filepath.Join(os.Args[0], "../pb_public") -}