mirror of
https://github.com/pocketbase/pocketbase.git
synced 2025-04-20 15:08:05 +02:00
added automigrate tests
This commit is contained in:
parent
c6f03cda43
commit
33539452de
@ -15,9 +15,7 @@ import (
|
|||||||
"github.com/pocketbase/pocketbase/tools/list"
|
"github.com/pocketbase/pocketbase/tools/list"
|
||||||
)
|
)
|
||||||
|
|
||||||
const migrationsTable = "_migrations"
|
const collectionsCacheKey = "migratecmd_collections"
|
||||||
const automigrateSuffix = "_automigrate"
|
|
||||||
const collectionsCacheKey = "_automigrate_collections"
|
|
||||||
|
|
||||||
// onCollectionChange handles the automigration snapshot generation on
|
// onCollectionChange handles the automigration snapshot generation on
|
||||||
// collection change event (create/update/delete).
|
// collection change event (create/update/delete).
|
||||||
@ -27,6 +25,7 @@ func (p *plugin) afterCollectionChange() func(*core.ModelEvent) error {
|
|||||||
return nil // not a collection
|
return nil // not a collection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo replace with the OldModel when added to the ModelEvent
|
||||||
oldCollections, err := p.getCachedCollections()
|
oldCollections, err := p.getCachedCollections()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -50,8 +49,18 @@ func (p *plugin) afterCollectionChange() func(*core.ModelEvent) error {
|
|||||||
return fmt.Errorf("failed to resolve template: %v", templateErr)
|
return fmt.Errorf("failed to resolve template: %v", templateErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var action string
|
||||||
|
switch {
|
||||||
|
case new == nil:
|
||||||
|
action = "deleted_" + old.Name
|
||||||
|
case old == nil:
|
||||||
|
action = "created_" + new.Name
|
||||||
|
default:
|
||||||
|
action = "updated_" + old.Name
|
||||||
|
}
|
||||||
|
|
||||||
appliedTime := time.Now().Unix()
|
appliedTime := time.Now().Unix()
|
||||||
fileDest := filepath.Join(p.options.Dir, fmt.Sprintf("%d_automigrate.%s", appliedTime, p.options.TemplateLang))
|
fileDest := filepath.Join(p.options.Dir, fmt.Sprintf("%d_%s.%s", appliedTime, action, p.options.TemplateLang))
|
||||||
|
|
||||||
// ensure that the local migrations dir exist
|
// ensure that the local migrations dir exist
|
||||||
if err := os.MkdirAll(p.options.Dir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(p.options.Dir, os.ModePerm); err != nil {
|
||||||
@ -69,6 +78,10 @@ func (p *plugin) afterCollectionChange() func(*core.ModelEvent) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) refreshCachedCollections() error {
|
func (p *plugin) refreshCachedCollections() error {
|
||||||
|
if p.app.Dao() == nil {
|
||||||
|
return errors.New("app is not initialized yet")
|
||||||
|
}
|
||||||
|
|
||||||
var collections []*models.Collection
|
var collections []*models.Collection
|
||||||
if err := p.app.Dao().CollectionQuery().All(&collections); err != nil {
|
if err := p.app.Dao().CollectionQuery().All(&collections); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -72,11 +72,19 @@ func Register(app core.App, rootCmd *cobra.Command, options *Options) error {
|
|||||||
|
|
||||||
// watch for collection changes
|
// watch for collection changes
|
||||||
if p.options.Automigrate {
|
if p.options.Automigrate {
|
||||||
|
// refresh the cache right after app bootstap
|
||||||
p.app.OnAfterBootstrap().Add(func(e *core.BootstrapEvent) error {
|
p.app.OnAfterBootstrap().Add(func(e *core.BootstrapEvent) error {
|
||||||
p.refreshCachedCollections()
|
p.refreshCachedCollections()
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// refresh the cache to ensure that it constains the latest changes
|
||||||
|
// when migrations are applied on server start
|
||||||
|
p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||||
|
p.refreshCachedCollections()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
p.app.OnModelAfterCreate().Add(p.afterCollectionChange())
|
p.app.OnModelAfterCreate().Add(p.afterCollectionChange())
|
||||||
p.app.OnModelAfterUpdate().Add(p.afterCollectionChange())
|
p.app.OnModelAfterUpdate().Add(p.afterCollectionChange())
|
||||||
p.app.OnModelAfterDelete().Add(p.afterCollectionChange())
|
p.app.OnModelAfterDelete().Add(p.afterCollectionChange())
|
||||||
|
697
plugins/migratecmd/migratecmd_test.go
Normal file
697
plugins/migratecmd/migratecmd_test.go
Normal file
@ -0,0 +1,697 @@
|
|||||||
|
package migratecmd_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
"github.com/pocketbase/pocketbase/models/schema"
|
||||||
|
"github.com/pocketbase/pocketbase/plugins/migratecmd"
|
||||||
|
"github.com/pocketbase/pocketbase/tests"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAutomigrateCollectionCreate(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
lang string
|
||||||
|
expectedTemplate string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
migratecmd.TemplateLangJS,
|
||||||
|
`
|
||||||
|
migrate((db) => {
|
||||||
|
const collection = unmarshal({
|
||||||
|
"id": "new_id",
|
||||||
|
"created": "2022-01-01 00:00:00.000Z",
|
||||||
|
"updated": "2022-01-01 00:00:00.000Z",
|
||||||
|
"name": "new_name",
|
||||||
|
"type": "auth",
|
||||||
|
"system": true,
|
||||||
|
"schema": [],
|
||||||
|
"listRule": "@request.auth.id != '' && created > 0 || 'backtick` + "`" + `test' = 0",
|
||||||
|
"viewRule": "id = \"1\"",
|
||||||
|
"createRule": null,
|
||||||
|
"updateRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"options": {
|
||||||
|
"allowEmailAuth": false,
|
||||||
|
"allowOAuth2Auth": false,
|
||||||
|
"allowUsernameAuth": false,
|
||||||
|
"exceptEmailDomains": null,
|
||||||
|
"manageRule": "created > 0",
|
||||||
|
"minPasswordLength": 20,
|
||||||
|
"onlyEmailDomains": null,
|
||||||
|
"requireEmail": false
|
||||||
|
}
|
||||||
|
}, new Collection());
|
||||||
|
|
||||||
|
return Dao(db).saveCollection(collection);
|
||||||
|
}, (db) => {
|
||||||
|
const dao = new Dao(db);
|
||||||
|
const collection = dao.findCollectionByNameOrId("new_id");
|
||||||
|
|
||||||
|
return dao.deleteCollection(collection);
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
migratecmd.TemplateLangGo,
|
||||||
|
`
|
||||||
|
package _test_migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(db dbx.Builder) error {
|
||||||
|
jsonData := ` + "`" + `{
|
||||||
|
"id": "new_id",
|
||||||
|
"created": "2022-01-01 00:00:00.000Z",
|
||||||
|
"updated": "2022-01-01 00:00:00.000Z",
|
||||||
|
"name": "new_name",
|
||||||
|
"type": "auth",
|
||||||
|
"system": true,
|
||||||
|
"schema": [],
|
||||||
|
"listRule": "@request.auth.id != '' && created > 0 || ` + "'backtick` + \"`\" + `test' = 0" + `",
|
||||||
|
"viewRule": "id = \"1\"",
|
||||||
|
"createRule": null,
|
||||||
|
"updateRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"options": {
|
||||||
|
"allowEmailAuth": false,
|
||||||
|
"allowOAuth2Auth": false,
|
||||||
|
"allowUsernameAuth": false,
|
||||||
|
"exceptEmailDomains": null,
|
||||||
|
"manageRule": "created > 0",
|
||||||
|
"minPasswordLength": 20,
|
||||||
|
"onlyEmailDomains": null,
|
||||||
|
"requireEmail": false
|
||||||
|
}
|
||||||
|
}` + "`" + `
|
||||||
|
|
||||||
|
collection := &models.Collection{}
|
||||||
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return daos.New(db).SaveCollection(collection)
|
||||||
|
}, func(db dbx.Builder) error {
|
||||||
|
dao := daos.New(db);
|
||||||
|
|
||||||
|
collection, err := dao.FindCollectionByNameOrId("new_id")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.DeleteCollection(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
|
||||||
|
// @todo remove after collections cache is replaced
|
||||||
|
app.Bootstrap()
|
||||||
|
|
||||||
|
collection := &models.Collection{}
|
||||||
|
collection.Id = "new_id"
|
||||||
|
collection.Name = "new_name"
|
||||||
|
collection.Type = models.CollectionTypeAuth
|
||||||
|
collection.System = true
|
||||||
|
collection.Created, _ = types.ParseDateTime("2022-01-01 00:00:00.000Z")
|
||||||
|
collection.Updated = collection.Created
|
||||||
|
collection.ListRule = types.Pointer("@request.auth.id != '' && created > 0 || 'backtick`test' = 0")
|
||||||
|
collection.ViewRule = types.Pointer(`id = "1"`)
|
||||||
|
collection.SetOptions(models.CollectionAuthOptions{
|
||||||
|
ManageRule: types.Pointer("created > 0"),
|
||||||
|
MinPasswordLength: 20,
|
||||||
|
})
|
||||||
|
collection.MarkAsNew()
|
||||||
|
|
||||||
|
if err := app.Dao().SaveCollection(collection); err != nil {
|
||||||
|
t.Fatalf("[%d] Failed to save collection, got %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := os.ReadDir(migrationsDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[%d] Expected migrationsDir to be created, got: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if total := len(files); total != 1 {
|
||||||
|
t.Fatalf("[%d] Expected 1 file to be generated, got %d", i, total)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedName := "_created_new_name." + s.lang
|
||||||
|
if !strings.Contains(files[0].Name(), expectedName) {
|
||||||
|
t.Fatalf("Expected filename to contains %q, got %q", expectedName, files[0].Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
fullPath := filepath.Join(migrationsDir, files[0].Name())
|
||||||
|
content, err := os.ReadFile(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[%d] Failed to read the generated migration file: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := strings.TrimSpace(string(content)); v != strings.TrimSpace(s.expectedTemplate) {
|
||||||
|
t.Fatalf("[%d] Expected template \n%v \ngot \n%v", i, s.expectedTemplate, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutomigrateCollectionDelete(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
lang string
|
||||||
|
expectedTemplate string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
migratecmd.TemplateLangJS,
|
||||||
|
`
|
||||||
|
migrate((db) => {
|
||||||
|
const dao = new Dao(db);
|
||||||
|
const collection = dao.findCollectionByNameOrId("test123");
|
||||||
|
|
||||||
|
return dao.deleteCollection(collection);
|
||||||
|
}, (db) => {
|
||||||
|
const collection = unmarshal({
|
||||||
|
"id": "test123",
|
||||||
|
"created": "2022-01-01 00:00:00.000Z",
|
||||||
|
"updated": "2022-01-01 00:00:00.000Z",
|
||||||
|
"name": "test456",
|
||||||
|
"type": "auth",
|
||||||
|
"system": false,
|
||||||
|
"schema": [],
|
||||||
|
"listRule": "@request.auth.id != '' && created > 0 || 'backtick` + "`" + `test' = 0",
|
||||||
|
"viewRule": "id = \"1\"",
|
||||||
|
"createRule": null,
|
||||||
|
"updateRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"options": {
|
||||||
|
"allowEmailAuth": false,
|
||||||
|
"allowOAuth2Auth": false,
|
||||||
|
"allowUsernameAuth": false,
|
||||||
|
"exceptEmailDomains": null,
|
||||||
|
"manageRule": "created > 0",
|
||||||
|
"minPasswordLength": 20,
|
||||||
|
"onlyEmailDomains": null,
|
||||||
|
"requireEmail": false
|
||||||
|
}
|
||||||
|
}, new Collection());
|
||||||
|
|
||||||
|
return Dao(db).saveCollection(collection);
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
migratecmd.TemplateLangGo,
|
||||||
|
`
|
||||||
|
package _test_migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(db dbx.Builder) error {
|
||||||
|
dao := daos.New(db);
|
||||||
|
|
||||||
|
collection, err := dao.FindCollectionByNameOrId("test123")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.DeleteCollection(collection)
|
||||||
|
}, func(db dbx.Builder) error {
|
||||||
|
jsonData := ` + "`" + `{
|
||||||
|
"id": "test123",
|
||||||
|
"created": "2022-01-01 00:00:00.000Z",
|
||||||
|
"updated": "2022-01-01 00:00:00.000Z",
|
||||||
|
"name": "test456",
|
||||||
|
"type": "auth",
|
||||||
|
"system": false,
|
||||||
|
"schema": [],
|
||||||
|
"listRule": "@request.auth.id != '' && created > 0 || ` + "'backtick` + \"`\" + `test' = 0" + `",
|
||||||
|
"viewRule": "id = \"1\"",
|
||||||
|
"createRule": null,
|
||||||
|
"updateRule": null,
|
||||||
|
"deleteRule": null,
|
||||||
|
"options": {
|
||||||
|
"allowEmailAuth": false,
|
||||||
|
"allowOAuth2Auth": false,
|
||||||
|
"allowUsernameAuth": false,
|
||||||
|
"exceptEmailDomains": null,
|
||||||
|
"manageRule": "created > 0",
|
||||||
|
"minPasswordLength": 20,
|
||||||
|
"onlyEmailDomains": null,
|
||||||
|
"requireEmail": false
|
||||||
|
}
|
||||||
|
}` + "`" + `
|
||||||
|
|
||||||
|
collection := &models.Collection{}
|
||||||
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return daos.New(db).SaveCollection(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Id = "test123"
|
||||||
|
collection.Name = "test456"
|
||||||
|
collection.Type = models.CollectionTypeAuth
|
||||||
|
collection.Created, _ = types.ParseDateTime("2022-01-01 00:00:00.000Z")
|
||||||
|
collection.Updated = collection.Created
|
||||||
|
collection.ListRule = types.Pointer("@request.auth.id != '' && created > 0 || 'backtick`test' = 0")
|
||||||
|
collection.ViewRule = types.Pointer(`id = "1"`)
|
||||||
|
collection.SetOptions(models.CollectionAuthOptions{
|
||||||
|
ManageRule: types.Pointer("created > 0"),
|
||||||
|
MinPasswordLength: 20,
|
||||||
|
})
|
||||||
|
collection.MarkAsNew()
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
// delete the newly created dummy collection
|
||||||
|
if err := app.Dao().DeleteCollection(collection); err != nil {
|
||||||
|
t.Fatalf("[%d] Failed to delete dummy collection, got %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := os.ReadDir(migrationsDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[%d] Expected migrationsDir to be created, got: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if total := len(files); total != 1 {
|
||||||
|
t.Fatalf("[%d] Expected 1 file to be generated, got %d", i, total)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedName := "_deleted_test456." + s.lang
|
||||||
|
if !strings.Contains(files[0].Name(), expectedName) {
|
||||||
|
t.Fatalf("Expected filename to contains %q, got %q", expectedName, files[0].Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
fullPath := filepath.Join(migrationsDir, files[0].Name())
|
||||||
|
content, err := os.ReadFile(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[%d] Failed to read the generated migration file: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := strings.TrimSpace(string(content)); v != strings.TrimSpace(s.expectedTemplate) {
|
||||||
|
t.Fatalf("[%d] Expected template \n%v \ngot \n%v", i, s.expectedTemplate, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAutomigrateCollectionUpdate(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
lang string
|
||||||
|
expectedTemplate string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
migratecmd.TemplateLangJS,
|
||||||
|
`
|
||||||
|
migrate((db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("test123")
|
||||||
|
|
||||||
|
collection.name = "test456_update"
|
||||||
|
collection.type = "base"
|
||||||
|
collection.listRule = null
|
||||||
|
collection.deleteRule = "updated > 0 && @request.auth.id != ''"
|
||||||
|
collection.options = {}
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.schema.removeField("f3_id")
|
||||||
|
|
||||||
|
// add
|
||||||
|
collection.schema.addField(unmarshal({
|
||||||
|
"system": false,
|
||||||
|
"id": "f4_id",
|
||||||
|
"name": "f4_name",
|
||||||
|
"type": "text",
|
||||||
|
"required": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"pattern": "` + "`" + `test backtick` + "`" + `123"
|
||||||
|
}
|
||||||
|
}, new SchemaField()))
|
||||||
|
|
||||||
|
// update
|
||||||
|
collection.schema.addField(unmarshal({
|
||||||
|
"system": false,
|
||||||
|
"id": "f2_id",
|
||||||
|
"name": "f2_name_new",
|
||||||
|
"type": "number",
|
||||||
|
"required": false,
|
||||||
|
"unique": true,
|
||||||
|
"options": {
|
||||||
|
"min": 10,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}, new SchemaField()))
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
}, (db) => {
|
||||||
|
const dao = new Dao(db)
|
||||||
|
const collection = dao.findCollectionByNameOrId("test123")
|
||||||
|
|
||||||
|
collection.name = "test456"
|
||||||
|
collection.type = "auth"
|
||||||
|
collection.listRule = "@request.auth.id != '' && created > 0"
|
||||||
|
collection.deleteRule = null
|
||||||
|
collection.options = {
|
||||||
|
"allowEmailAuth": false,
|
||||||
|
"allowOAuth2Auth": false,
|
||||||
|
"allowUsernameAuth": false,
|
||||||
|
"exceptEmailDomains": null,
|
||||||
|
"manageRule": "created > 0",
|
||||||
|
"minPasswordLength": 20,
|
||||||
|
"onlyEmailDomains": null,
|
||||||
|
"requireEmail": false
|
||||||
|
}
|
||||||
|
|
||||||
|
// add
|
||||||
|
collection.schema.addField(unmarshal({
|
||||||
|
"system": false,
|
||||||
|
"id": "f3_id",
|
||||||
|
"name": "f3_name",
|
||||||
|
"type": "bool",
|
||||||
|
"required": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {}
|
||||||
|
}, new SchemaField()))
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.schema.removeField("f4_id")
|
||||||
|
|
||||||
|
// update
|
||||||
|
collection.schema.addField(unmarshal({
|
||||||
|
"system": false,
|
||||||
|
"id": "f2_id",
|
||||||
|
"name": "f2_name",
|
||||||
|
"type": "number",
|
||||||
|
"required": false,
|
||||||
|
"unique": true,
|
||||||
|
"options": {
|
||||||
|
"min": 10,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}, new SchemaField()))
|
||||||
|
|
||||||
|
return dao.saveCollection(collection)
|
||||||
|
})
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
migratecmd.TemplateLangGo,
|
||||||
|
`
|
||||||
|
package _test_migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models/schema"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
m.Register(func(db dbx.Builder) error {
|
||||||
|
dao := daos.New(db);
|
||||||
|
|
||||||
|
collection, err := dao.FindCollectionByNameOrId("test123")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Name = "test456_update"
|
||||||
|
|
||||||
|
collection.Type = "base"
|
||||||
|
|
||||||
|
collection.ListRule = nil
|
||||||
|
|
||||||
|
collection.DeleteRule = types.Pointer("updated > 0 && @request.auth.id != ''")
|
||||||
|
|
||||||
|
options := map[string]any{}
|
||||||
|
json.Unmarshal([]byte(` + "`" + `{}` + "`" + `), &options)
|
||||||
|
collection.SetOptions(options)
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.Schema.RemoveField("f3_id")
|
||||||
|
|
||||||
|
// add
|
||||||
|
new_f4_name := &schema.SchemaField{}
|
||||||
|
json.Unmarshal([]byte(` + "`" + `{
|
||||||
|
"system": false,
|
||||||
|
"id": "f4_id",
|
||||||
|
"name": "f4_name",
|
||||||
|
"type": "text",
|
||||||
|
"required": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {
|
||||||
|
"min": null,
|
||||||
|
"max": null,
|
||||||
|
"pattern": ` + "\"` + \"`\" + `test backtick` + \"`\" + `123\"" + `
|
||||||
|
}
|
||||||
|
}` + "`" + `), new_f4_name)
|
||||||
|
collection.Schema.AddField(new_f4_name)
|
||||||
|
|
||||||
|
// update
|
||||||
|
edit_f2_name_new := &schema.SchemaField{}
|
||||||
|
json.Unmarshal([]byte(` + "`" + `{
|
||||||
|
"system": false,
|
||||||
|
"id": "f2_id",
|
||||||
|
"name": "f2_name_new",
|
||||||
|
"type": "number",
|
||||||
|
"required": false,
|
||||||
|
"unique": true,
|
||||||
|
"options": {
|
||||||
|
"min": 10,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}` + "`" + `), edit_f2_name_new)
|
||||||
|
collection.Schema.AddField(edit_f2_name_new)
|
||||||
|
|
||||||
|
return dao.SaveCollection(collection)
|
||||||
|
}, func(db dbx.Builder) error {
|
||||||
|
dao := daos.New(db);
|
||||||
|
|
||||||
|
collection, err := dao.FindCollectionByNameOrId("test123")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Name = "test456"
|
||||||
|
|
||||||
|
collection.Type = "auth"
|
||||||
|
|
||||||
|
collection.ListRule = types.Pointer("@request.auth.id != '' && created > 0")
|
||||||
|
|
||||||
|
collection.DeleteRule = nil
|
||||||
|
|
||||||
|
options := map[string]any{}
|
||||||
|
json.Unmarshal([]byte(` + "`" + `{
|
||||||
|
"allowEmailAuth": false,
|
||||||
|
"allowOAuth2Auth": false,
|
||||||
|
"allowUsernameAuth": false,
|
||||||
|
"exceptEmailDomains": null,
|
||||||
|
"manageRule": "created > 0",
|
||||||
|
"minPasswordLength": 20,
|
||||||
|
"onlyEmailDomains": null,
|
||||||
|
"requireEmail": false
|
||||||
|
}` + "`" + `), &options)
|
||||||
|
collection.SetOptions(options)
|
||||||
|
|
||||||
|
// add
|
||||||
|
del_f3_name := &schema.SchemaField{}
|
||||||
|
json.Unmarshal([]byte(` + "`" + `{
|
||||||
|
"system": false,
|
||||||
|
"id": "f3_id",
|
||||||
|
"name": "f3_name",
|
||||||
|
"type": "bool",
|
||||||
|
"required": false,
|
||||||
|
"unique": false,
|
||||||
|
"options": {}
|
||||||
|
}` + "`" + `), del_f3_name)
|
||||||
|
collection.Schema.AddField(del_f3_name)
|
||||||
|
|
||||||
|
// remove
|
||||||
|
collection.Schema.RemoveField("f4_id")
|
||||||
|
|
||||||
|
// update
|
||||||
|
edit_f2_name_new := &schema.SchemaField{}
|
||||||
|
json.Unmarshal([]byte(` + "`" + `{
|
||||||
|
"system": false,
|
||||||
|
"id": "f2_id",
|
||||||
|
"name": "f2_name",
|
||||||
|
"type": "number",
|
||||||
|
"required": false,
|
||||||
|
"unique": true,
|
||||||
|
"options": {
|
||||||
|
"min": 10,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}` + "`" + `), edit_f2_name_new)
|
||||||
|
collection.Schema.AddField(edit_f2_name_new)
|
||||||
|
|
||||||
|
return dao.SaveCollection(collection)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Id = "test123"
|
||||||
|
collection.Name = "test456"
|
||||||
|
collection.Type = models.CollectionTypeAuth
|
||||||
|
collection.Created, _ = types.ParseDateTime("2022-01-01 00:00:00.000Z")
|
||||||
|
collection.Updated = collection.Created
|
||||||
|
collection.ListRule = types.Pointer("@request.auth.id != '' && created > 0")
|
||||||
|
collection.ViewRule = types.Pointer(`id = "1"`)
|
||||||
|
collection.SetOptions(models.CollectionAuthOptions{
|
||||||
|
ManageRule: types.Pointer("created > 0"),
|
||||||
|
MinPasswordLength: 20,
|
||||||
|
})
|
||||||
|
collection.MarkAsNew()
|
||||||
|
collection.Schema.AddField(&schema.SchemaField{
|
||||||
|
Id: "f1_id",
|
||||||
|
Name: "f1_name",
|
||||||
|
Type: schema.FieldTypeText,
|
||||||
|
Required: true,
|
||||||
|
})
|
||||||
|
collection.Schema.AddField(&schema.SchemaField{
|
||||||
|
Id: "f2_id",
|
||||||
|
Name: "f2_name",
|
||||||
|
Type: schema.FieldTypeNumber,
|
||||||
|
Unique: true,
|
||||||
|
Options: &schema.NumberOptions{
|
||||||
|
Min: types.Pointer(10.0),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
collection.Schema.AddField(&schema.SchemaField{
|
||||||
|
Id: "f3_id",
|
||||||
|
Name: "f3_name",
|
||||||
|
Type: schema.FieldTypeBool,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
collection.Name = "test456_update"
|
||||||
|
collection.Type = models.CollectionTypeBase
|
||||||
|
collection.DeleteRule = types.Pointer(`updated > 0 && @request.auth.id != ''`)
|
||||||
|
collection.ListRule = nil
|
||||||
|
collection.NormalizeOptions()
|
||||||
|
collection.Schema.RemoveField("f3_id")
|
||||||
|
collection.Schema.AddField(&schema.SchemaField{
|
||||||
|
Id: "f4_id",
|
||||||
|
Name: "f4_name",
|
||||||
|
Type: schema.FieldTypeText,
|
||||||
|
Options: &schema.TextOptions{
|
||||||
|
Pattern: "`test backtick`123",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
f := collection.Schema.GetFieldById("f2_id")
|
||||||
|
f.Name = "f2_name_new"
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := os.ReadDir(migrationsDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[%d] Expected migrationsDir to be created, got: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if total := len(files); total != 1 {
|
||||||
|
t.Fatalf("[%d] Expected 1 file to be generated, got %d", i, total)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedName := "_updated_test456." + s.lang
|
||||||
|
if !strings.Contains(files[0].Name(), expectedName) {
|
||||||
|
t.Fatalf("Expected filename to contains %q, got %q", expectedName, files[0].Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
fullPath := filepath.Join(migrationsDir, files[0].Name())
|
||||||
|
content, err := os.ReadFile(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("[%d] Failed to read the generated migration file: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := strings.TrimSpace(string(content)); v != strings.TrimSpace(s.expectedTemplate) {
|
||||||
|
t.Fatalf("[%d] Expected template \n%v \ngot \n%v", i, s.expectedTemplate, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ func (p *plugin) jsBlankTemplate() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, error) {
|
func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, error) {
|
||||||
jsonData, err := json.MarshalIndent(collections, " ", " ")
|
jsonData, err := marhshalWithoutEscape(collections, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) jsCreateTemplate(collection *models.Collection) (string, error) {
|
func (p *plugin) jsCreateTemplate(collection *models.Collection) (string, error) {
|
||||||
jsonData, err := json.MarshalIndent(collection, " ", " ")
|
jsonData, err := marhshalWithoutEscape(collection, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ func (p *plugin) jsCreateTemplate(collection *models.Collection) (string, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) jsDeleteTemplate(collection *models.Collection) (string, error) {
|
func (p *plugin) jsDeleteTemplate(collection *models.Collection) (string, error) {
|
||||||
jsonData, err := json.MarshalIndent(collection, " ", " ")
|
jsonData, err := marhshalWithoutEscape(collection, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
||||||
}
|
}
|
||||||
@ -181,11 +181,11 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
rawNewOptions, err := json.MarshalIndent(new.Options, " ", " ")
|
rawNewOptions, err := marhshalWithoutEscape(new.Options, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
rawOldOptions, err := json.MarshalIndent(old.Options, " ", " ")
|
rawOldOptions, err := marhshalWithoutEscape(old.Options, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -194,32 +194,53 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
downParts = append(downParts, fmt.Sprintf("%s.options = %s", varName, rawOldOptions))
|
downParts = append(downParts, fmt.Sprintf("%s.options = %s", varName, rawOldOptions))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure new line between regular and collection fields
|
||||||
|
if len(upParts) > 0 {
|
||||||
|
upParts[len(upParts)-1] += "\n"
|
||||||
|
}
|
||||||
|
if len(downParts) > 0 {
|
||||||
|
downParts[len(downParts)-1] += "\n"
|
||||||
|
}
|
||||||
|
|
||||||
// Schema
|
// Schema
|
||||||
// ---
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
// deleted fields
|
// deleted fields
|
||||||
for _, oldField := range old.Schema.Fields() {
|
for _, oldField := range old.Schema.Fields() {
|
||||||
if new.Schema.GetFieldById(oldField.Id) != nil {
|
if new.Schema.GetFieldById(oldField.Id) != nil {
|
||||||
continue // exist
|
continue // exist
|
||||||
}
|
}
|
||||||
rawOldField, err := json.MarshalIndent(oldField, " ", " ")
|
|
||||||
|
rawOldField, err := marhshalWithoutEscape(oldField, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.schema.removeField(%q)", varName, oldField.Id))
|
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))", varName, rawOldField))
|
upParts = append(upParts, "// remove")
|
||||||
|
upParts = append(upParts, fmt.Sprintf("%s.schema.removeField(%q)\n", varName, oldField.Id))
|
||||||
|
|
||||||
|
downParts = append(downParts, "// add")
|
||||||
|
downParts = append(downParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawOldField))
|
||||||
}
|
}
|
||||||
|
|
||||||
// created fields
|
// created fields
|
||||||
for _, newField := range new.Schema.Fields() {
|
for _, newField := range new.Schema.Fields() {
|
||||||
if old.Schema.GetFieldById(newField.Id) != nil {
|
if old.Schema.GetFieldById(newField.Id) != nil {
|
||||||
continue // exist
|
continue // exist
|
||||||
}
|
}
|
||||||
rawNewField, err := json.MarshalIndent(newField, " ", " ")
|
|
||||||
|
rawNewField, err := marhshalWithoutEscape(newField, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))", varName, rawNewField))
|
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.schema.removeField(%q)", varName, newField.Id))
|
upParts = append(upParts, "// add")
|
||||||
|
upParts = append(upParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawNewField))
|
||||||
|
|
||||||
|
downParts = append(downParts, "// remove")
|
||||||
|
downParts = append(downParts, fmt.Sprintf("%s.schema.removeField(%q)\n", varName, newField.Id))
|
||||||
}
|
}
|
||||||
|
|
||||||
// modified fields
|
// modified fields
|
||||||
for _, newField := range new.Schema.Fields() {
|
for _, newField := range new.Schema.Fields() {
|
||||||
oldField := old.Schema.GetFieldById(newField.Id)
|
oldField := old.Schema.GetFieldById(newField.Id)
|
||||||
@ -227,12 +248,12 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rawNewField, err := json.MarshalIndent(newField, " ", " ")
|
rawNewField, err := marhshalWithoutEscape(newField, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawOldField, err := json.MarshalIndent(oldField, " ", " ")
|
rawOldField, err := marhshalWithoutEscape(oldField, " ", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -241,12 +262,14 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
continue // no change
|
continue // no change
|
||||||
}
|
}
|
||||||
|
|
||||||
upParts = append(upParts, "// upsert")
|
upParts = append(upParts, "// update")
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))", varName, rawNewField))
|
upParts = append(upParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawNewField))
|
||||||
downParts = append(downParts, "// upsert")
|
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))", varName, rawOldField))
|
downParts = append(downParts, "// update")
|
||||||
|
downParts = append(downParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawOldField))
|
||||||
}
|
}
|
||||||
// ---
|
|
||||||
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
up := strings.Join(upParts, "\n ")
|
up := strings.Join(upParts, "\n ")
|
||||||
down := strings.Join(downParts, "\n ")
|
down := strings.Join(downParts, "\n ")
|
||||||
@ -255,20 +278,24 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
const dao = new Dao(db)
|
const dao = new Dao(db)
|
||||||
const collection = dao.findCollectionByNameOrId(%q)
|
const collection = dao.findCollectionByNameOrId(%q)
|
||||||
|
|
||||||
%s;
|
%s
|
||||||
|
|
||||||
return dao.saveCollection(collection)
|
return dao.saveCollection(collection)
|
||||||
}, (db) => {
|
}, (db) => {
|
||||||
const dao = new Dao(db)
|
const dao = new Dao(db)
|
||||||
const collection = dao.findCollectionByNameOrId(%q)
|
const collection = dao.findCollectionByNameOrId(%q)
|
||||||
|
|
||||||
%s;
|
%s
|
||||||
|
|
||||||
return dao.saveCollection(collection)
|
return dao.saveCollection(collection)
|
||||||
})
|
})
|
||||||
`
|
`
|
||||||
|
|
||||||
return fmt.Sprintf(template, old.Id, up, new.Id, down), nil
|
return fmt.Sprintf(
|
||||||
|
template,
|
||||||
|
old.Id, strings.TrimSpace(up),
|
||||||
|
new.Id, strings.TrimSpace(down),
|
||||||
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
@ -300,7 +327,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) goSnapshotTemplate(collections []*models.Collection) (string, error) {
|
func (p *plugin) goSnapshotTemplate(collections []*models.Collection) (string, error) {
|
||||||
jsonData, err := json.MarshalIndent(collections, "\t", "\t\t")
|
jsonData, err := marhshalWithoutEscape(collections, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
||||||
}
|
}
|
||||||
@ -312,8 +339,8 @@ import (
|
|||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
|
||||||
m "github.com/pocketbase/pocketbase/migrations"
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -331,11 +358,15 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
return fmt.Sprintf(template, filepath.Base(p.options.Dir), string(jsonData)), nil
|
return fmt.Sprintf(
|
||||||
|
template,
|
||||||
|
filepath.Base(p.options.Dir),
|
||||||
|
escapeBacktick(string(jsonData)),
|
||||||
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) goCreateTemplate(collection *models.Collection) (string, error) {
|
func (p *plugin) goCreateTemplate(collection *models.Collection) (string, error) {
|
||||||
jsonData, err := json.MarshalIndent(collection, "\t", "\t\t")
|
jsonData, err := marhshalWithoutEscape(collection, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
||||||
}
|
}
|
||||||
@ -347,15 +378,15 @@ import (
|
|||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
|
||||||
m "github.com/pocketbase/pocketbase/migrations"
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
m.Register(func(db dbx.Builder) error {
|
m.Register(func(db dbx.Builder) error {
|
||||||
jsonData := ` + "`%s`" + `
|
jsonData := ` + "`%s`" + `
|
||||||
|
|
||||||
collection := *models.Collection{}
|
collection := &models.Collection{}
|
||||||
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -377,13 +408,13 @@ func init() {
|
|||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
template,
|
template,
|
||||||
filepath.Base(p.options.Dir),
|
filepath.Base(p.options.Dir),
|
||||||
string(jsonData),
|
escapeBacktick(string(jsonData)),
|
||||||
collection.Id,
|
collection.Id,
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) goDeleteTemplate(collection *models.Collection) (string, error) {
|
func (p *plugin) goDeleteTemplate(collection *models.Collection) (string, error) {
|
||||||
jsonData, err := json.MarshalIndent(collection, "\t", "\t\t")
|
jsonData, err := marhshalWithoutEscape(collection, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
return "", fmt.Errorf("failed to serialize collections list: %v", err)
|
||||||
}
|
}
|
||||||
@ -395,8 +426,8 @@ import (
|
|||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
"github.com/pocketbase/pocketbase/daos"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
|
||||||
m "github.com/pocketbase/pocketbase/migrations"
|
m "github.com/pocketbase/pocketbase/migrations"
|
||||||
|
"github.com/pocketbase/pocketbase/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -412,7 +443,7 @@ func init() {
|
|||||||
}, func(db dbx.Builder) error {
|
}, func(db dbx.Builder) error {
|
||||||
jsonData := ` + "`%s`" + `
|
jsonData := ` + "`%s`" + `
|
||||||
|
|
||||||
collection := *models.Collection{}
|
collection := &models.Collection{}
|
||||||
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
if err := json.Unmarshal([]byte(jsonData), &collection); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -426,7 +457,7 @@ func init() {
|
|||||||
template,
|
template,
|
||||||
filepath.Base(p.options.Dir),
|
filepath.Base(p.options.Dir),
|
||||||
collection.Id,
|
collection.Id,
|
||||||
string(jsonData),
|
escapeBacktick(string(jsonData)),
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,9 +477,6 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
upParts := []string{}
|
upParts := []string{}
|
||||||
downParts := []string{}
|
downParts := []string{}
|
||||||
varName := "collection"
|
varName := "collection"
|
||||||
var importSchema bool
|
|
||||||
var importTypes bool
|
|
||||||
|
|
||||||
if old.Name != new.Name {
|
if old.Name != new.Name {
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.Name = %q\n", varName, new.Name))
|
upParts = append(upParts, fmt.Sprintf("%s.Name = %q\n", varName, new.Name))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.Name = %q\n", varName, old.Name))
|
downParts = append(downParts, fmt.Sprintf("%s.Name = %q\n", varName, old.Name))
|
||||||
@ -470,11 +498,9 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
|
|
||||||
if old.ListRule != new.ListRule {
|
if old.ListRule != new.ListRule {
|
||||||
if old.ListRule != nil && new.ListRule == nil {
|
if old.ListRule != nil && new.ListRule == nil {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.ListRule = nil\n", varName))
|
upParts = append(upParts, fmt.Sprintf("%s.ListRule = nil\n", varName))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.ListRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.ListRule)))
|
downParts = append(downParts, fmt.Sprintf("%s.ListRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.ListRule)))
|
||||||
} else if old.ListRule == nil && new.ListRule != nil || *old.ListRule != *new.ListRule {
|
} else if old.ListRule == nil && new.ListRule != nil || *old.ListRule != *new.ListRule {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.ListRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.ListRule)))
|
upParts = append(upParts, fmt.Sprintf("%s.ListRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.ListRule)))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.ListRule = nil\n", varName))
|
downParts = append(downParts, fmt.Sprintf("%s.ListRule = nil\n", varName))
|
||||||
}
|
}
|
||||||
@ -482,11 +508,9 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
|
|
||||||
if old.ViewRule != new.ViewRule {
|
if old.ViewRule != new.ViewRule {
|
||||||
if old.ViewRule != nil && new.ViewRule == nil {
|
if old.ViewRule != nil && new.ViewRule == nil {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.ViewRule = nil\n", varName))
|
upParts = append(upParts, fmt.Sprintf("%s.ViewRule = nil\n", varName))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.ViewRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.ViewRule)))
|
downParts = append(downParts, fmt.Sprintf("%s.ViewRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.ViewRule)))
|
||||||
} else if old.ViewRule == nil && new.ViewRule != nil || *old.ViewRule != *new.ViewRule {
|
} else if old.ViewRule == nil && new.ViewRule != nil || *old.ViewRule != *new.ViewRule {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.ViewRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.ViewRule)))
|
upParts = append(upParts, fmt.Sprintf("%s.ViewRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.ViewRule)))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.ViewRule = nil\n", varName))
|
downParts = append(downParts, fmt.Sprintf("%s.ViewRule = nil\n", varName))
|
||||||
}
|
}
|
||||||
@ -494,11 +518,9 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
|
|
||||||
if old.CreateRule != new.CreateRule {
|
if old.CreateRule != new.CreateRule {
|
||||||
if old.CreateRule != nil && new.CreateRule == nil {
|
if old.CreateRule != nil && new.CreateRule == nil {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.CreateRule = nil\n", varName))
|
upParts = append(upParts, fmt.Sprintf("%s.CreateRule = nil\n", varName))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.CreateRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.CreateRule)))
|
downParts = append(downParts, fmt.Sprintf("%s.CreateRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.CreateRule)))
|
||||||
} else if old.CreateRule == nil && new.CreateRule != nil || *old.CreateRule != *new.CreateRule {
|
} else if old.CreateRule == nil && new.CreateRule != nil || *old.CreateRule != *new.CreateRule {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.CreateRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.CreateRule)))
|
upParts = append(upParts, fmt.Sprintf("%s.CreateRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.CreateRule)))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.CreateRule = nil\n", varName))
|
downParts = append(downParts, fmt.Sprintf("%s.CreateRule = nil\n", varName))
|
||||||
}
|
}
|
||||||
@ -506,11 +528,9 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
|
|
||||||
if old.UpdateRule != new.UpdateRule {
|
if old.UpdateRule != new.UpdateRule {
|
||||||
if old.UpdateRule != nil && new.UpdateRule == nil {
|
if old.UpdateRule != nil && new.UpdateRule == nil {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.UpdateRule = nil\n", varName))
|
upParts = append(upParts, fmt.Sprintf("%s.UpdateRule = nil\n", varName))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.UpdateRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.UpdateRule)))
|
downParts = append(downParts, fmt.Sprintf("%s.UpdateRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.UpdateRule)))
|
||||||
} else if old.UpdateRule == nil && new.UpdateRule != nil || *old.UpdateRule != *new.UpdateRule {
|
} else if old.UpdateRule == nil && new.UpdateRule != nil || *old.UpdateRule != *new.UpdateRule {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.UpdateRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.UpdateRule)))
|
upParts = append(upParts, fmt.Sprintf("%s.UpdateRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.UpdateRule)))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.UpdateRule = nil\n", varName))
|
downParts = append(downParts, fmt.Sprintf("%s.UpdateRule = nil\n", varName))
|
||||||
}
|
}
|
||||||
@ -518,32 +538,30 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
|
|
||||||
if old.DeleteRule != new.DeleteRule {
|
if old.DeleteRule != new.DeleteRule {
|
||||||
if old.DeleteRule != nil && new.DeleteRule == nil {
|
if old.DeleteRule != nil && new.DeleteRule == nil {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.DeleteRule = nil\n", varName))
|
upParts = append(upParts, fmt.Sprintf("%s.DeleteRule = nil\n", varName))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.DeleteRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.DeleteRule)))
|
downParts = append(downParts, fmt.Sprintf("%s.DeleteRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.DeleteRule)))
|
||||||
} else if old.DeleteRule == nil && new.DeleteRule != nil || *old.DeleteRule != *new.DeleteRule {
|
} else if old.DeleteRule == nil && new.DeleteRule != nil || *old.DeleteRule != *new.DeleteRule {
|
||||||
importTypes = true
|
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.DeleteRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.DeleteRule)))
|
upParts = append(upParts, fmt.Sprintf("%s.DeleteRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.DeleteRule)))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.DeleteRule = nil\n", varName))
|
downParts = append(downParts, fmt.Sprintf("%s.DeleteRule = nil\n", varName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
rawNewOptions, err := json.MarshalIndent(new.Options, "\t\t", "\t")
|
rawNewOptions, err := marhshalWithoutEscape(new.Options, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
rawOldOptions, err := json.MarshalIndent(old.Options, "\t\t", "\t")
|
rawOldOptions, err := marhshalWithoutEscape(old.Options, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if !bytes.Equal(rawNewOptions, rawOldOptions) {
|
if !bytes.Equal(rawNewOptions, rawOldOptions) {
|
||||||
upParts = append(upParts, "options := map[string]any{}")
|
upParts = append(upParts, "options := map[string]any{}")
|
||||||
upParts = append(upParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), &options)", rawNewOptions))
|
upParts = append(upParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), &options)", escapeBacktick(string(rawNewOptions))))
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.SetOptions(options)\n", varName))
|
upParts = append(upParts, fmt.Sprintf("%s.SetOptions(options)\n", varName))
|
||||||
// ---
|
// ---
|
||||||
downParts = append(downParts, "options := map[string]any{}")
|
downParts = append(downParts, "options := map[string]any{}")
|
||||||
downParts = append(downParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), &options)", rawOldOptions))
|
downParts = append(downParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), &options)", escapeBacktick(string(rawOldOptions))))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.SetOptions(options)\n", varName))
|
downParts = append(downParts, fmt.Sprintf("%s.SetOptions(options)\n", varName))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,12 +573,11 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
continue // exist
|
continue // exist
|
||||||
}
|
}
|
||||||
|
|
||||||
rawOldField, err := json.MarshalIndent(oldField, "\t\t", "\t")
|
rawOldField, err := marhshalWithoutEscape(oldField, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
importSchema = true
|
|
||||||
fieldVar := fmt.Sprintf("del_%s", oldField.Name)
|
fieldVar := fmt.Sprintf("del_%s", oldField.Name)
|
||||||
|
|
||||||
upParts = append(upParts, "// remove")
|
upParts = append(upParts, "// remove")
|
||||||
@ -568,7 +585,7 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
|
|
||||||
downParts = append(downParts, "// add")
|
downParts = append(downParts, "// add")
|
||||||
downParts = append(downParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
downParts = append(downParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
||||||
downParts = append(downParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", rawOldField, fieldVar))
|
downParts = append(downParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", escapeBacktick(string(rawOldField)), fieldVar))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
downParts = append(downParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,17 +595,16 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
continue // exist
|
continue // exist
|
||||||
}
|
}
|
||||||
|
|
||||||
rawNewField, err := json.MarshalIndent(newField, "\t\t", "\t")
|
rawNewField, err := marhshalWithoutEscape(newField, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
importSchema = true
|
|
||||||
fieldVar := fmt.Sprintf("new_%s", newField.Name)
|
fieldVar := fmt.Sprintf("new_%s", newField.Name)
|
||||||
|
|
||||||
upParts = append(upParts, "// add")
|
upParts = append(upParts, "// add")
|
||||||
upParts = append(upParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
upParts = append(upParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
||||||
upParts = append(upParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", rawNewField, fieldVar))
|
upParts = append(upParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", escapeBacktick(string(rawNewField)), fieldVar))
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
upParts = append(upParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
||||||
|
|
||||||
downParts = append(downParts, "// remove")
|
downParts = append(downParts, "// remove")
|
||||||
@ -602,12 +618,12 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rawNewField, err := json.MarshalIndent(newField, "\t\t", "\t")
|
rawNewField, err := marhshalWithoutEscape(newField, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawOldField, err := json.MarshalIndent(oldField, "\t\t", "\t")
|
rawOldField, err := marhshalWithoutEscape(oldField, "\t\t", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -616,17 +632,16 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
continue // no change
|
continue // no change
|
||||||
}
|
}
|
||||||
|
|
||||||
importSchema = true
|
|
||||||
fieldVar := fmt.Sprintf("edit_%s", newField.Name)
|
fieldVar := fmt.Sprintf("edit_%s", newField.Name)
|
||||||
|
|
||||||
upParts = append(upParts, "// upsert")
|
upParts = append(upParts, "// update")
|
||||||
upParts = append(upParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
upParts = append(upParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
||||||
upParts = append(upParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", rawNewField, fieldVar))
|
upParts = append(upParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", escapeBacktick(string(rawNewField)), fieldVar))
|
||||||
upParts = append(upParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
upParts = append(upParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
||||||
|
|
||||||
downParts = append(downParts, "// upsert")
|
downParts = append(downParts, "// update")
|
||||||
downParts = append(downParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
downParts = append(downParts, fmt.Sprintf("%s := &schema.SchemaField{}", fieldVar))
|
||||||
downParts = append(downParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", rawOldField, fieldVar))
|
downParts = append(downParts, fmt.Sprintf("json.Unmarshal([]byte(`%s`), %s)", escapeBacktick(string(rawOldField)), fieldVar))
|
||||||
downParts = append(downParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
downParts = append(downParts, fmt.Sprintf("%s.Schema.AddField(%s)\n", varName, fieldVar))
|
||||||
}
|
}
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
@ -634,14 +649,30 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
|
|||||||
up := strings.Join(upParts, "\n\t\t")
|
up := strings.Join(upParts, "\n\t\t")
|
||||||
down := strings.Join(downParts, "\n\t\t")
|
down := strings.Join(downParts, "\n\t\t")
|
||||||
|
|
||||||
|
var optImports string
|
||||||
|
|
||||||
|
combined := up + down
|
||||||
|
|
||||||
|
if strings.Contains(combined, "json.Unmarshal(") ||
|
||||||
|
strings.Contains(combined, "json.Marshal(") {
|
||||||
|
optImports += "\n\t\"encoding/json\"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
optImports += "\n\t\"github.com/pocketbase/dbx\""
|
||||||
|
optImports += "\n\t\"github.com/pocketbase/pocketbase/daos\""
|
||||||
|
optImports += "\n\tm \"github.com/pocketbase/pocketbase/migrations\""
|
||||||
|
|
||||||
|
if strings.Contains(combined, "schema.SchemaField{") {
|
||||||
|
optImports += "\n\t\"github.com/pocketbase/pocketbase/models/schema\""
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(combined, "types.Pointer(") {
|
||||||
|
optImports += "\n\t\"github.com/pocketbase/pocketbase/tools/types\""
|
||||||
|
}
|
||||||
|
|
||||||
const template = `package %s
|
const template = `package %s
|
||||||
|
|
||||||
import (
|
import (%s
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
|
||||||
"github.com/pocketbase/pocketbase/daos"
|
|
||||||
m "github.com/pocketbase/pocketbase/migrations"%s
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -671,14 +702,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var optImports string
|
|
||||||
if importSchema {
|
|
||||||
optImports += "\n\t\"github.com/pocketbase/pocketbase/models/schema\""
|
|
||||||
}
|
|
||||||
if importTypes {
|
|
||||||
optImports += "\n\t\"github.com/pocketbase/pocketbase/tools/types\""
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
template,
|
template,
|
||||||
filepath.Base(p.options.Dir),
|
filepath.Base(p.options.Dir),
|
||||||
@ -687,3 +710,22 @@ func init() {
|
|||||||
new.Id, strings.TrimSpace(down),
|
new.Id, strings.TrimSpace(down),
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func marhshalWithoutEscape(v any, prefix string, indent string) ([]byte, error) {
|
||||||
|
raw, err := json.MarshalIndent(v, prefix, indent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unescape escaped unicode characters
|
||||||
|
unescaped, err := strconv.Unquote(strings.Replace(strconv.Quote(string(raw)), `\\u`, `\u`, -1))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(unescaped), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func escapeBacktick(v string) string {
|
||||||
|
return strings.ReplaceAll(v, "`", "` + \"`\" + `")
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user