You've already forked pocketbase
							
							
				mirror of
				https://github.com/pocketbase/pocketbase.git
				synced 2025-10-31 08:37:38 +02:00 
			
		
		
		
	added plugins subpackage and added basic support for js migrations
This commit is contained in:
		| @@ -138,10 +138,10 @@ func autoIgnoreAuthRecordsEmailVisibility( | ||||
| 	collection := records[0].Collection() | ||||
|  | ||||
| 	mappedRecords := make(map[string]*models.Record, len(records)) | ||||
| 	recordIds := make([]any, 0, len(records)) | ||||
| 	for _, rec := range records { | ||||
| 	recordIds := make([]any, len(records)) | ||||
| 	for i, rec := range records { | ||||
| 		mappedRecords[rec.Id] = rec | ||||
| 		recordIds = append(recordIds, rec.Id) | ||||
| 		recordIds[i] = rec.Id | ||||
| 	} | ||||
|  | ||||
| 	if requestData != nil && requestData.AuthRecord != nil && mappedRecords[requestData.AuthRecord.Id] != nil { | ||||
|   | ||||
							
								
								
									
										15
									
								
								core/base.go
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								core/base.go
									
									
									
									
									
								
							| @@ -714,7 +714,10 @@ func (app *BaseApp) createDaoWithHooks(db dbx.Builder) *daos.Dao { | ||||
| 	} | ||||
|  | ||||
| 	dao.AfterCreateFunc = func(eventDao *daos.Dao, m models.Model) { | ||||
| 		app.OnModelAfterCreate().Trigger(&ModelEvent{eventDao, m}) | ||||
| 		err := app.OnModelAfterCreate().Trigger(&ModelEvent{eventDao, m}) | ||||
| 		if err != nil && app.isDebug { | ||||
| 			log.Println(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	dao.BeforeUpdateFunc = func(eventDao *daos.Dao, m models.Model) error { | ||||
| @@ -722,7 +725,10 @@ func (app *BaseApp) createDaoWithHooks(db dbx.Builder) *daos.Dao { | ||||
| 	} | ||||
|  | ||||
| 	dao.AfterUpdateFunc = func(eventDao *daos.Dao, m models.Model) { | ||||
| 		app.OnModelAfterUpdate().Trigger(&ModelEvent{eventDao, m}) | ||||
| 		err := app.OnModelAfterUpdate().Trigger(&ModelEvent{eventDao, m}) | ||||
| 		if err != nil && app.isDebug { | ||||
| 			log.Println(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	dao.BeforeDeleteFunc = func(eventDao *daos.Dao, m models.Model) error { | ||||
| @@ -730,7 +736,10 @@ func (app *BaseApp) createDaoWithHooks(db dbx.Builder) *daos.Dao { | ||||
| 	} | ||||
|  | ||||
| 	dao.AfterDeleteFunc = func(eventDao *daos.Dao, m models.Model) { | ||||
| 		app.OnModelAfterDelete().Trigger(&ModelEvent{eventDao, m}) | ||||
| 		err := app.OnModelAfterDelete().Trigger(&ModelEvent{eventDao, m}) | ||||
| 		if err != nil && app.isDebug { | ||||
| 			log.Println(err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return dao | ||||
|   | ||||
| @@ -93,8 +93,8 @@ func (dao *Dao) expandRecords(records []*models.Record, expandPath string, fetch | ||||
| 		} | ||||
|  | ||||
| 		recordIds := make([]any, len(records)) | ||||
| 		for _, record := range records { | ||||
| 			recordIds = append(recordIds, record.Id) | ||||
| 		for i, record := range records { | ||||
| 			recordIds[i] = record.Id | ||||
| 		} | ||||
|  | ||||
| 		indirectRecords, err := dao.FindRecordsByExpr( | ||||
|   | ||||
| @@ -2,42 +2,29 @@ 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 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") | ||||
| } | ||||
|  | ||||
| func main() { | ||||
| 	app := pocketbase.New() | ||||
|  | ||||
| 	var publicDirFlag string | ||||
| 	// load js pb_migrations | ||||
| 	jsvm.MustRegisterMigrationsLoader(app, nil) | ||||
|  | ||||
| 	// add "--publicDir" option flag | ||||
| 	app.RootCmd.PersistentFlags().StringVar( | ||||
| 		&publicDirFlag, | ||||
| 		"publicDir", | ||||
| 		defaultPublicDir(), | ||||
| 		"the directory to serve static files", | ||||
| 	) | ||||
| 	// migrate command (with js templates) | ||||
| 	migratecmd.MustRegister(app, app.RootCmd, &migratecmd.Options{ | ||||
| 		TemplateLang: migratecmd.TemplateLangJS, | ||||
| 		AutoMigrate:  true, | ||||
| 	}) | ||||
|  | ||||
| 	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(publicDirFlag), true)) | ||||
|  | ||||
| 		return nil | ||||
| 	// pb_public dir | ||||
| 	publicdir.MustRegister(app, &publicdir.Options{ | ||||
| 		FlagsCmd:      app.RootCmd, | ||||
| 		IndexFallback: true, | ||||
| 	}) | ||||
|  | ||||
| 	if err := app.Start(); err != nil { | ||||
|   | ||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							| @@ -7,6 +7,8 @@ require ( | ||||
| 	github.com/aws/aws-sdk-go v1.44.141 | ||||
| 	github.com/disintegration/imaging v1.6.2 | ||||
| 	github.com/domodwyer/mailyak/v3 v3.3.4 | ||||
| 	github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86 | ||||
| 	github.com/dop251/goja_nodejs v0.0.0-20221009164102-3aa5028e57f6 | ||||
| 	github.com/fatih/color v1.13.0 | ||||
| 	github.com/gabriel-vasile/mimetype v1.4.1 | ||||
| 	github.com/ganigeorgiev/fexpr v0.1.1 | ||||
| @@ -45,6 +47,8 @@ require ( | ||||
| 	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect | ||||
| 	github.com/aws/aws-sdk-go-v2/service/sts v1.17.4 // indirect | ||||
| 	github.com/aws/smithy-go v1.13.4 // indirect | ||||
| 	github.com/dlclark/regexp2 v1.7.0 // indirect | ||||
| 	github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect | ||||
| 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/google/uuid v1.3.0 // indirect | ||||
|   | ||||
							
								
								
									
										65
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								go.sum
									
									
									
									
									
								
							| @@ -47,18 +47,16 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m | ||||
| cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= | ||||
| cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= | ||||
| cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= | ||||
| cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4= | ||||
| cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0= | ||||
| cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48= | ||||
| cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | ||||
| cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= | ||||
| cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= | ||||
| cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= | ||||
| cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= | ||||
| cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= | ||||
| cloud.google.com/go/iam v0.6.0 h1:nsqQC88kT5Iwlm4MeNGTpfMWddp6NB/UOLFTH6m1QfQ= | ||||
| cloud.google.com/go/iam v0.7.0 h1:k4MuwOsS7zGJJ+QfZ5vBK8SgHBAvYN/23BWsiihJ1vs= | ||||
| cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= | ||||
| cloud.google.com/go/longrunning v0.1.1 h1:y50CXG4j0+qvEukslYFBCrzaXX0qpFbBzc3PchSu/LE= | ||||
| cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= | ||||
| cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4= | ||||
| cloud.google.com/go/monitoring v1.5.0/go.mod h1:/o9y8NYX5j91JjD/JvGLYbi86kL11OjyJXq2XziLJu4= | ||||
| @@ -208,12 +206,6 @@ github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4 | ||||
| github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= | ||||
| github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= | ||||
| github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= | ||||
| github.com/aws/aws-sdk-go v1.44.126 h1:7HQJw2DNiwpxqMe2H7odGNT2rhO4SRrUe5/8dYXl0Jk= | ||||
| github.com/aws/aws-sdk-go v1.44.126/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= | ||||
| github.com/aws/aws-sdk-go v1.44.127 h1:IoO2VfuIQg1aMXnl8l6OpNUKT4Qq5CnJMOyIWoTYXj0= | ||||
| github.com/aws/aws-sdk-go v1.44.127/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= | ||||
| github.com/aws/aws-sdk-go v1.44.130 h1:a/qwOxmYJF47xTZvTjECSJXnfRbjegb3YxvCXfETtnY= | ||||
| github.com/aws/aws-sdk-go v1.44.130/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= | ||||
| github.com/aws/aws-sdk-go v1.44.141 h1:kT/YIH9GUaKZa3yi8TEsZmVgvphwEzINJu19hYUzfGY= | ||||
| github.com/aws/aws-sdk-go v1.44.141/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= | ||||
| github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= | ||||
| @@ -224,21 +216,15 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXK | ||||
| github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k= | ||||
| github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg= | ||||
| github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E= | ||||
| github.com/aws/aws-sdk-go-v2/config v1.17.10 h1:zBy5QQ/mkvHElM1rygHPAzuH+sl8nsdSaxSWj0+rpdE= | ||||
| github.com/aws/aws-sdk-go-v2/config v1.17.10/go.mod h1:/4np+UiJJKpWHN7Q+LZvqXYgyjgeXm5+lLfDI6TPZao= | ||||
| github.com/aws/aws-sdk-go-v2/config v1.18.2 h1:tRhTb3xMZsB0gW0sXWpqs9FeIP8iQp5SvnvwiPXzHwo= | ||||
| github.com/aws/aws-sdk-go-v2/config v1.18.2/go.mod h1:9XVoZTdD8ICjrgI5ddb8j918q6lEZkFYpb7uohgvU6c= | ||||
| github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk= | ||||
| github.com/aws/aws-sdk-go-v2/credentials v1.12.23 h1:LctvcJMIb8pxvk5hQhChpCu0WlU6oKQmcYb1HA4IZSA= | ||||
| github.com/aws/aws-sdk-go-v2/credentials v1.12.23/go.mod h1:0awX9iRr/+UO7OwRQFpV1hNtXxOVuehpjVEzrIAYNcA= | ||||
| github.com/aws/aws-sdk-go-v2/credentials v1.13.2 h1:F/v1w0XcFDZjL0bCdi9XWJenoPKjGbzljBhDKcryzEQ= | ||||
| github.com/aws/aws-sdk-go-v2/credentials v1.13.2/go.mod h1:eAT5aj/WJ2UDIA0IVNFc2byQLeD89SDEi4cjzH/MKoQ= | ||||
| github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s= | ||||
| github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs= | ||||
| github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8= | ||||
| github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21/go.mod h1:iIYPrQ2rYfZiB/iADYlhj9HHZ9TTi6PqKQPAqygohbE= | ||||
| github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 h1:e1VtTBo+cLNjres0wTlMkmwCGGRjDEkkrz3frxxcaCs= | ||||
| github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37/go.mod h1:kdAV1UMnCkyG6tZJUC4mHbPoRjPA3dIK0L8mnsHERiM= | ||||
| github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.41 h1:ssgdsNm11dvFtO7F/AeiW4dAO3eGsDeg5fwpag/JP/I= | ||||
| github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.41/go.mod h1:CS+AbDFAaPU9TQOo7U6mVV23YvqCOElnqmh0XQjgJ1g= | ||||
| github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4= | ||||
| @@ -267,8 +253,6 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkV | ||||
| github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19/go.mod h1:BmQWRVkLTmyNzYPFAZgon53qKLWBNSvonugD1MrSWUs= | ||||
| github.com/aws/aws-sdk-go-v2/service/kms v1.18.1/go.mod h1:4PZMUkc9rXHWGVB5J9vKaZy3D7Nai79ORworQ3ASMiM= | ||||
| github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USXEh6sN8Nq4GrNXSg2RXVMo= | ||||
| github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 h1:/EMdFPW/Ppieh0WUtQf1+qCGNLdsq5UWUyevBQ6vMVc= | ||||
| github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0= | ||||
| github.com/aws/aws-sdk-go-v2/service/s3 v1.29.3 h1:F6wgg8aHGNyhaAy2ONnWBThiPdLa386qNA0j33FIuSM= | ||||
| github.com/aws/aws-sdk-go-v2/service/s3 v1.29.3/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0= | ||||
| github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU= | ||||
| @@ -281,8 +265,6 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vbo | ||||
| github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo= | ||||
| github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI= | ||||
| github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E= | ||||
| github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 h1:KRAix/KHvjGODaHAMXnxRk9t0D+4IJVUuS/uwXxngXk= | ||||
| github.com/aws/aws-sdk-go-v2/service/sts v1.17.1/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4= | ||||
| github.com/aws/aws-sdk-go-v2/service/sts v1.17.4 h1:YNncBj5dVYd05i4ZQ+YicOotSXo0ufc9P8kTioi13EM= | ||||
| github.com/aws/aws-sdk-go-v2/service/sts v1.17.4/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4= | ||||
| github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= | ||||
| @@ -498,6 +480,9 @@ github.com/digitalocean/godo v1.81.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5 | ||||
| github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= | ||||
| github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= | ||||
| github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= | ||||
| github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | ||||
| github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= | ||||
| github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= | ||||
| github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= | ||||
| github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= | ||||
| github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= | ||||
| @@ -521,6 +506,14 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ | ||||
| github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= | ||||
| github.com/domodwyer/mailyak/v3 v3.3.4 h1:AG/pvcz2/ocFqZkPEG7lPAa0MhCq1warfUEKJt6Fagk= | ||||
| github.com/domodwyer/mailyak/v3 v3.3.4/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c= | ||||
| github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= | ||||
| github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= | ||||
| github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86 h1:E2wycakfddWJ26v+ZyEY91Lb/HEZyaiZhbMX+KQcdmc= | ||||
| github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= | ||||
| github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= | ||||
| github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= | ||||
| github.com/dop251/goja_nodejs v0.0.0-20221009164102-3aa5028e57f6 h1:p3QZwRRfCN7Qr3GNBTMKBkLFjEm3DHR4MaJABvsiqgk= | ||||
| github.com/dop251/goja_nodejs v0.0.0-20221009164102-3aa5028e57f6/go.mod h1:+CJy9V5cGycP5qwp6RM5jLg+TFEMyGtD7A9xUbU/BOQ= | ||||
| github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= | ||||
| github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= | ||||
| github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= | ||||
| @@ -640,6 +633,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ | ||||
| github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= | ||||
| github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= | ||||
| github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= | ||||
| github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= | ||||
| github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= | ||||
| github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||
| github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||
| github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= | ||||
| @@ -816,8 +811,6 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 | ||||
| github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= | ||||
| github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= | ||||
| github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= | ||||
| github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU= | ||||
| github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= | ||||
| github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= | ||||
| github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= | ||||
| github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= | ||||
| @@ -1379,7 +1372,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ | ||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||
| github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | ||||
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||
| github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||||
| github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||||
| @@ -1464,7 +1456,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||
| go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||
| go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||
| go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= | ||||
| go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= | ||||
| go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= | ||||
| go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= | ||||
| go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= | ||||
| @@ -1567,8 +1558,6 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0 | ||||
| golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||
| golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||
| golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||
| golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= | ||||
| golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= | ||||
| golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= | ||||
| golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= | ||||
| golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||
| @@ -1613,8 +1602,6 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= | ||||
| golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= | ||||
| golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= | ||||
| golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||||
| golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= | ||||
| golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= | ||||
| golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= | ||||
| golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||||
| golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| @@ -1694,7 +1681,6 @@ golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug | ||||
| golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||||
| golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||||
| golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= | ||||
| golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= | ||||
| golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= | ||||
| golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= | ||||
| golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= | ||||
| @@ -1723,8 +1709,6 @@ golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7Lm | ||||
| golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= | ||||
| golang.org/x/oauth2 v0.0.0-20220628200809-02e64fa58f26/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= | ||||
| golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= | ||||
| golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= | ||||
| golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= | ||||
| golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU= | ||||
| golang.org/x/oauth2 v0.2.0/go.mod h1:Cwn6afJ8jrQwYMxQDTpISoXmXW9I6qF6vDeuuoX3Ibs= | ||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| @@ -1741,6 +1725,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ | ||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= | ||||
| golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| @@ -1883,7 +1868,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc | ||||
| golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= | ||||
| golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= | ||||
| golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| @@ -1893,7 +1877,6 @@ golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9sn | ||||
| golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= | ||||
| golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= | ||||
| golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= | ||||
| golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= | ||||
| @@ -1920,8 +1903,6 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb | ||||
| golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= | ||||
| golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= | ||||
| golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| @@ -2007,8 +1988,6 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= | ||||
| golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= | ||||
| golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= | ||||
| golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||||
| golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= | ||||
| golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= | ||||
| golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= | ||||
| golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= | ||||
| golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| @@ -2070,10 +2049,6 @@ google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6F | ||||
| google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= | ||||
| google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= | ||||
| google.golang.org/api v0.91.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= | ||||
| google.golang.org/api v0.101.0 h1:lJPPeEBIRxGpGLwnBTam1NPEM8Z2BmmXEd3z812pjwM= | ||||
| google.golang.org/api v0.101.0/go.mod h1:CjxAAWWt3A3VrUE2IGDY2bgK5qhoG/OkyWVlYcP05MY= | ||||
| google.golang.org/api v0.102.0 h1:JxJl2qQ85fRMPNvlZY/enexbxpCjLwGhZUtgfGeQ51I= | ||||
| google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= | ||||
| google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ= | ||||
| google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= | ||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||
| @@ -2184,8 +2159,6 @@ google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljW | ||||
| google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= | ||||
| google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= | ||||
| google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= | ||||
| google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= | ||||
| google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= | ||||
| google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c= | ||||
| google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= | ||||
| google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= | ||||
| @@ -2229,8 +2202,6 @@ google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu | ||||
| google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= | ||||
| google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= | ||||
| google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= | ||||
| google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= | ||||
| google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= | ||||
| google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= | ||||
| google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= | ||||
| google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= | ||||
| @@ -2365,8 +2336,6 @@ lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= | ||||
| lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= | ||||
| modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= | ||||
| modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= | ||||
| modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8 h1:0+dsXf0zeLx9ixj4nilg6jKe5Bg1ilzBwSFq4kJmIUc= | ||||
| modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= | ||||
| modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= | ||||
| modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= | ||||
| modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= | ||||
| @@ -2379,15 +2348,11 @@ modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= | ||||
| modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= | ||||
| modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= | ||||
| modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= | ||||
| modernc.org/sqlite v1.19.3 h1:dIoagx6yIQT3V/zOSeAyZ8OqQyEr17YTgETOXTZNJMA= | ||||
| modernc.org/sqlite v1.19.3/go.mod h1:xiyJD7FY8mTZXnQwE/gEL1STtFrrnDx03V8KhVQmcr8= | ||||
| modernc.org/sqlite v1.19.4 h1:nlPIDqumn6/mSvs7T5C8MNYEuN73sISzPdKtMdURpUI= | ||||
| modernc.org/sqlite v1.19.4/go.mod h1:x/yZNb3h5+I3zGQSlwIv4REL5eJhiRkUH5MReogAeIc= | ||||
| modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= | ||||
| modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= | ||||
| modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34= | ||||
| modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= | ||||
| modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= | ||||
| modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= | ||||
| modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= | ||||
| modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= | ||||
|   | ||||
							
								
								
									
										110
									
								
								plugins/jsvm/migrations.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								plugins/jsvm/migrations.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| package jsvm | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/dop251/goja_nodejs/console" | ||||
| 	"github.com/dop251/goja_nodejs/require" | ||||
| 	"github.com/pocketbase/dbx" | ||||
| 	"github.com/pocketbase/pocketbase/core" | ||||
| 	m "github.com/pocketbase/pocketbase/migrations" | ||||
| ) | ||||
|  | ||||
| // MigrationsLoaderOptions defines optional struct to customize the default plugin behavior. | ||||
| type MigrationsLoaderOptions struct { | ||||
| 	// Dir is the app migrations directory from where the js files will be loaded | ||||
| 	// (default to pb_data/migrations) | ||||
| 	Dir string | ||||
| } | ||||
|  | ||||
| // migrationsLoader is the plugin definition. | ||||
| // Usually it is instantiated via RegisterMigrationsLoader or MustRegisterMigrationsLoader. | ||||
| type migrationsLoader struct { | ||||
| 	app     core.App | ||||
| 	options *MigrationsLoaderOptions | ||||
| } | ||||
|  | ||||
| // | ||||
| // MustRegisterMigrationsLoader registers the plugin to the provided | ||||
| // app instance and panics if it fails. | ||||
| // | ||||
| // It it calls RegisterMigrationsLoader(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 { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // RegisterMigrationsLoader 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} | ||||
|  | ||||
| 	if options != nil { | ||||
| 		l.options = options | ||||
| 	} else { | ||||
| 		l.options = &MigrationsLoaderOptions{} | ||||
| 	} | ||||
|  | ||||
| 	if l.options.Dir == "" { | ||||
| 		l.options.Dir = filepath.Join(app.DataDir(), "../pb_migrations") | ||||
| 	} | ||||
|  | ||||
| 	files, err := readDirFiles(l.options.Dir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	registry := new(require.Registry) // this can be shared by multiple runtimes | ||||
|  | ||||
| 	for file, content := range files { | ||||
| 		vm := NewBaseVM(l.app) | ||||
| 		registry.Enable(vm) | ||||
| 		console.Enable(vm) | ||||
|  | ||||
| 		vm.Set("migrate", func(up, down func(db dbx.Builder) error) { | ||||
| 			m.AppMigrations.Register(up, down, file) | ||||
| 		}) | ||||
|  | ||||
| 		_, err := vm.RunString(string(content)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // readDirFiles returns a map with all directory files and their content. | ||||
| // | ||||
| // If directory with dirPath is missing, it returns an empty map and no error. | ||||
| func readDirFiles(dirPath string) (map[string][]byte, error) { | ||||
| 	files, err := os.ReadDir(dirPath) | ||||
| 	if err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return map[string][]byte{}, nil | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	result := map[string][]byte{} | ||||
|  | ||||
| 	for _, f := range files { | ||||
| 		if f.IsDir() { | ||||
| 			continue | ||||
| 		} | ||||
| 		raw, err := os.ReadFile(filepath.Join(dirPath, f.Name())) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		result[f.Name()] = raw | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
							
								
								
									
										135
									
								
								plugins/jsvm/vm.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								plugins/jsvm/vm.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| package jsvm | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
|  | ||||
| 	"github.com/dop251/goja" | ||||
| 	"github.com/pocketbase/dbx" | ||||
| 	"github.com/pocketbase/pocketbase/apis" | ||||
| 	"github.com/pocketbase/pocketbase/core" | ||||
| 	"github.com/pocketbase/pocketbase/daos" | ||||
| 	"github.com/pocketbase/pocketbase/models" | ||||
| ) | ||||
|  | ||||
| func NewBaseVM(app core.App) *goja.Runtime { | ||||
| 	vm := goja.New() | ||||
| 	vm.SetFieldNameMapper(goja.UncapFieldNameMapper()) | ||||
|  | ||||
| 	vm.Set("$app", app) | ||||
|  | ||||
| 	vm.Set("unmarshal", func(src map[string]any, dest any) (any, error) { | ||||
| 		raw, err := json.Marshal(src) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		if err := json.Unmarshal(raw, &dest); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return dest, nil | ||||
| 	}) | ||||
|  | ||||
| 	collectionConstructor(vm) | ||||
| 	recordConstructor(vm) | ||||
| 	adminConstructor(vm) | ||||
| 	daoConstructor(vm) | ||||
| 	dbxBinds(vm) | ||||
|  | ||||
| 	return vm | ||||
| } | ||||
|  | ||||
| func collectionConstructor(vm *goja.Runtime) { | ||||
| 	vm.Set("Collection", func(call goja.ConstructorCall) *goja.Object { | ||||
| 		instance := &models.Collection{} | ||||
| 		instanceValue := vm.ToValue(instance).(*goja.Object) | ||||
| 		instanceValue.SetPrototype(call.This.Prototype()) | ||||
| 		return instanceValue | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func recordConstructor(vm *goja.Runtime) { | ||||
| 	vm.Set("Record", func(call goja.ConstructorCall) *goja.Object { | ||||
| 		instance := &models.Record{} | ||||
| 		instanceValue := vm.ToValue(instance).(*goja.Object) | ||||
| 		instanceValue.SetPrototype(call.This.Prototype()) | ||||
| 		return instanceValue | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func adminConstructor(vm *goja.Runtime) { | ||||
| 	vm.Set("Admin", func(call goja.ConstructorCall) *goja.Object { | ||||
| 		instance := &models.Admin{} | ||||
| 		instanceValue := vm.ToValue(instance).(*goja.Object) | ||||
| 		instanceValue.SetPrototype(call.This.Prototype()) | ||||
| 		return instanceValue | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func daoConstructor(vm *goja.Runtime) { | ||||
| 	vm.Set("Dao", func(call goja.ConstructorCall) *goja.Object { | ||||
| 		db, ok := call.Argument(0).Export().(dbx.Builder) | ||||
| 		if !ok || db == nil { | ||||
| 			panic("missing required Dao(db) argument") | ||||
| 		} | ||||
|  | ||||
| 		instance := daos.New(db) | ||||
| 		instanceValue := vm.ToValue(instance).(*goja.Object) | ||||
| 		instanceValue.SetPrototype(call.This.Prototype()) | ||||
| 		return instanceValue | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func dbxBinds(vm *goja.Runtime) { | ||||
| 	obj := vm.NewObject() | ||||
| 	vm.Set("$dbx", obj) | ||||
|  | ||||
| 	obj.Set("exp", dbx.NewExp) | ||||
| 	obj.Set("hashExp", func(data map[string]any) dbx.HashExp { | ||||
| 		exp := dbx.HashExp{} | ||||
| 		for k, v := range data { | ||||
| 			exp[k] = v | ||||
| 		} | ||||
| 		return exp | ||||
| 	}) | ||||
| 	obj.Set("not", dbx.Not) | ||||
| 	obj.Set("and", dbx.And) | ||||
| 	obj.Set("or", dbx.Or) | ||||
| 	obj.Set("in", dbx.In) | ||||
| 	obj.Set("notIn", dbx.NotIn) | ||||
| 	obj.Set("like", dbx.Like) | ||||
| 	obj.Set("orLike", dbx.OrLike) | ||||
| 	obj.Set("notLike", dbx.NotLike) | ||||
| 	obj.Set("orNotLike", dbx.OrNotLike) | ||||
| 	obj.Set("exists", dbx.Exists) | ||||
| 	obj.Set("notExists", dbx.NotExists) | ||||
| 	obj.Set("between", dbx.Between) | ||||
| 	obj.Set("notBetween", dbx.NotBetween) | ||||
| } | ||||
|  | ||||
| func apisBind(vm *goja.Runtime) { | ||||
| 	obj := vm.NewObject() | ||||
| 	vm.Set("$apis", obj) | ||||
|  | ||||
| 	// middlewares | ||||
| 	obj.Set("requireRecordAuth", apis.RequireRecordAuth) | ||||
| 	obj.Set("requireRecordAuth", apis.RequireRecordAuth) | ||||
| 	obj.Set("requireSameContextRecordAuth", apis.RequireSameContextRecordAuth) | ||||
| 	obj.Set("requireAdminAuth", apis.RequireAdminAuth) | ||||
| 	obj.Set("requireAdminAuthOnlyIfAny", apis.RequireAdminAuthOnlyIfAny) | ||||
| 	obj.Set("requireAdminOrRecordAuth", apis.RequireAdminOrRecordAuth) | ||||
| 	obj.Set("requireAdminOrOwnerAuth", apis.RequireAdminOrOwnerAuth) | ||||
| 	obj.Set("activityLogger", apis.ActivityLogger) | ||||
|  | ||||
| 	// api errors | ||||
| 	obj.Set("notFoundError", apis.NewNotFoundError) | ||||
| 	obj.Set("badRequestError", apis.NewBadRequestError) | ||||
| 	obj.Set("forbiddenError", apis.NewForbiddenError) | ||||
| 	obj.Set("unauthorizedError", apis.NewUnauthorizedError) | ||||
|  | ||||
| 	// record helpers | ||||
| 	obj.Set("getRequestData", apis.GetRequestData) | ||||
| 	obj.Set("requestData", apis.RequestData) | ||||
| 	obj.Set("enrichRecord", apis.EnrichRecord) | ||||
| 	obj.Set("enrichRecords", apis.EnrichRecords) | ||||
| } | ||||
							
								
								
									
										154
									
								
								plugins/migratecmd/automigrate.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								plugins/migratecmd/automigrate.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| package migratecmd | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/pocketbase/dbx" | ||||
| 	"github.com/pocketbase/pocketbase/core" | ||||
| 	m "github.com/pocketbase/pocketbase/migrations" | ||||
| 	"github.com/pocketbase/pocketbase/models" | ||||
| 	"github.com/pocketbase/pocketbase/tools/list" | ||||
| ) | ||||
|  | ||||
| const migrationsTable = "_migrations" | ||||
|  | ||||
| // tidyMigrationsTable cleanups the migrations table by removing all | ||||
| // entries with deleted migration files. | ||||
| func (p *plugin) tidyMigrationsTable() error { | ||||
| 	names, filesErr := p.getAllMigrationNames() | ||||
| 	if filesErr != nil { | ||||
| 		return fmt.Errorf("failed to fetch migration files list: %v", filesErr) | ||||
| 	} | ||||
|  | ||||
| 	_, tidyErr := p.app.Dao().DB().Delete(migrationsTable, dbx.NotIn("file", list.ToInterfaceSlice(names)...)).Execute() | ||||
| 	if tidyErr != nil { | ||||
| 		return fmt.Errorf("failed to delete last automigrates from the db: %v", tidyErr) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *plugin) onCollectionChange() func(*core.ModelEvent) error { | ||||
| 	return func(e *core.ModelEvent) error { | ||||
| 		if e.Model.TableName() != "_collections" { | ||||
| 			return nil // not a collection | ||||
| 		} | ||||
|  | ||||
| 		collections := []*models.Collection{} | ||||
| 		if err := p.app.Dao().CollectionQuery().OrderBy("created ASC").All(&collections); err != nil { | ||||
| 			return fmt.Errorf("failed to fetch collections list: %v", err) | ||||
| 		} | ||||
| 		if len(collections) == 0 { | ||||
| 			return errors.New("missing collections to automigrate") | ||||
| 		} | ||||
|  | ||||
| 		names, err := p.getAllMigrationNames() | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to fetch migration files list: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		// delete last consequitive automigrates | ||||
| 		lastAutomigrates := []string{} | ||||
| 		for i := len(names) - 1; i >= 0; i-- { | ||||
| 			migrationFile := names[i] | ||||
| 			if !strings.Contains(migrationFile, "_automigrate.") { | ||||
| 				break | ||||
| 			} | ||||
| 			lastAutomigrates = append(lastAutomigrates, migrationFile) | ||||
| 		} | ||||
| 		if len(lastAutomigrates) > 0 { | ||||
| 			// delete last automigrates from the db | ||||
| 			_, err := p.app.Dao().DB().Delete(migrationsTable, dbx.In("file", list.ToInterfaceSlice(lastAutomigrates)...)).Execute() | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("failed to delete last automigrates from the db: %v", err) | ||||
| 			} | ||||
|  | ||||
| 			// delete last automigrates from the filesystem | ||||
| 			for _, f := range lastAutomigrates { | ||||
| 				if err := os.Remove(filepath.Join(p.options.Dir, f)); err != nil && !os.IsNotExist(err) { | ||||
| 					return fmt.Errorf("failed to delete last automigrates from the filesystem: %v", err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		var template string | ||||
| 		var templateErr error | ||||
| 		if p.options.TemplateLang == TemplateLangJS { | ||||
| 			template, templateErr = p.jsSnapshotTemplate(collections) | ||||
| 		} else { | ||||
| 			template, templateErr = p.goSnapshotTemplate(collections) | ||||
| 		} | ||||
| 		if templateErr != nil { | ||||
| 			return fmt.Errorf("failed to resolve template: %v", templateErr) | ||||
| 		} | ||||
|  | ||||
| 		// add a comment to not edit the template | ||||
| 		template = ("// Do not edit by hand since this file is autogenerated and may get overwritten.\n" + | ||||
| 			"// If you want to do further changes, create a new non '_automigrate' file instead.\n" + template) | ||||
|  | ||||
| 		appliedTime := time.Now().Unix() | ||||
| 		fileDest := filepath.Join(p.options.Dir, fmt.Sprintf("%d_automigrate.%s", appliedTime, p.options.TemplateLang)) | ||||
|  | ||||
| 		// ensure that the local migrations dir exist | ||||
| 		if err := os.MkdirAll(p.options.Dir, os.ModePerm); err != nil { | ||||
| 			return fmt.Errorf("failed to create migration dir: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		return os.WriteFile(fileDest, []byte(template), 0644) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // getAllMigrationNames return both applied and new local migration file names. | ||||
| func (p *plugin) getAllMigrationNames() ([]string, error) { | ||||
| 	names := []string{} | ||||
|  | ||||
| 	for _, migration := range m.AppMigrations.Items() { | ||||
| 		names = append(names, migration.File) | ||||
| 	} | ||||
|  | ||||
| 	localFiles, err := p.getLocalMigrationNames() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, name := range localFiles { | ||||
| 		if !list.ExistInSlice(name, names) { | ||||
| 			names = append(names, name) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	sort.Slice(names, func(i int, j int) bool { | ||||
| 		return names[i] < names[j] | ||||
| 	}) | ||||
|  | ||||
| 	return names, nil | ||||
| } | ||||
|  | ||||
| // getLocalMigrationNames returns a list with all local migration files | ||||
| // | ||||
| // Returns an empty slice if the migrations directory doesn't exist. | ||||
| func (p *plugin) getLocalMigrationNames() ([]string, error) { | ||||
| 	files, err := os.ReadDir(p.options.Dir) | ||||
| 	if err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return []string{}, nil | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	result := make([]string, 0, len(files)) | ||||
|  | ||||
| 	for _, f := range files { | ||||
| 		if f.IsDir() { | ||||
| 			continue | ||||
| 		} | ||||
| 		result = append(result, f.Name()) | ||||
| 	} | ||||
|  | ||||
| 	return result, nil | ||||
| } | ||||
							
								
								
									
										210
									
								
								plugins/migratecmd/migratecmd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								plugins/migratecmd/migratecmd.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| package migratecmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/AlecAivazis/survey/v2" | ||||
| 	"github.com/pocketbase/pocketbase/core" | ||||
| 	"github.com/pocketbase/pocketbase/migrations" | ||||
| 	"github.com/pocketbase/pocketbase/models" | ||||
| 	"github.com/pocketbase/pocketbase/tools/inflector" | ||||
| 	"github.com/pocketbase/pocketbase/tools/migrate" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
|  | ||||
| type Options struct { | ||||
| 	Dir          string // the directory with user defined migrations | ||||
| 	AutoMigrate  bool | ||||
| 	TemplateLang string | ||||
| } | ||||
|  | ||||
| type plugin struct { | ||||
| 	app     core.App | ||||
| 	options *Options | ||||
| } | ||||
|  | ||||
| func MustRegister(app core.App, rootCmd *cobra.Command, options *Options) { | ||||
| 	if err := Register(app, rootCmd, options); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Register(app core.App, rootCmd *cobra.Command, options *Options) error { | ||||
| 	p := &plugin{app: app} | ||||
|  | ||||
| 	if options != nil { | ||||
| 		p.options = options | ||||
| 	} else { | ||||
| 		p.options = &Options{} | ||||
| 	} | ||||
|  | ||||
| 	if p.options.TemplateLang == "" { | ||||
| 		p.options.TemplateLang = TemplateLangGo | ||||
| 	} | ||||
|  | ||||
| 	if p.options.Dir == "" { | ||||
| 		if p.options.TemplateLang == TemplateLangJS { | ||||
| 			p.options.Dir = filepath.Join(p.app.DataDir(), "../pb_migrations") | ||||
| 		} else { | ||||
| 			p.options.Dir = filepath.Join(p.app.DataDir(), "../migrations") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// attach the migrate command | ||||
| 	if rootCmd != nil { | ||||
| 		rootCmd.AddCommand(p.createCommand()) | ||||
| 	} | ||||
|  | ||||
| 	// watch for collection changes | ||||
| 	if p.options.AutoMigrate { | ||||
| 		// @todo replace with AfterBootstrap | ||||
| 		p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { | ||||
| 			if err := p.tidyMigrationsTable(); err != nil && p.app.IsDebug() { | ||||
| 				log.Println("Failed to tidy the migrations table.") | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
| 		}) | ||||
|  | ||||
| 		p.app.OnModelAfterCreate().Add(p.onCollectionChange()) | ||||
| 		p.app.OnModelAfterUpdate().Add(p.onCollectionChange()) | ||||
| 		p.app.OnModelAfterDelete().Add(p.onCollectionChange()) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *plugin) createCommand() *cobra.Command { | ||||
| 	const cmdDesc = `Supported arguments are: | ||||
| - up                   - runs all available migrations. | ||||
| - down [number]        - reverts the last [number] applied migrations. | ||||
| - create name [folder] - creates new blank migration template file. | ||||
| - collections [folder] - creates new migration file with the latest local collections snapshot (similar to the automigrate but allows editing). | ||||
| ` | ||||
|  | ||||
| 	command := &cobra.Command{ | ||||
| 		Use:       "migrate", | ||||
| 		Short:     "Executes app DB migration scripts", | ||||
| 		ValidArgs: []string{"up", "down", "create", "collections"}, | ||||
| 		Long:      cmdDesc, | ||||
| 		Run: func(command *cobra.Command, args []string) { | ||||
| 			cmd := "" | ||||
| 			if len(args) > 0 { | ||||
| 				cmd = args[0] | ||||
| 			} | ||||
|  | ||||
| 			// additional commands | ||||
| 			// --- | ||||
| 			if cmd == "create" { | ||||
| 				if err := p.migrateCreateHandler("", args[1:]); err != nil { | ||||
| 					log.Fatal(err) | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			if cmd == "collections" { | ||||
| 				if err := p.migrateCollectionsHandler(args[1:]); err != nil { | ||||
| 					log.Fatal(err) | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
| 			// --- | ||||
|  | ||||
| 			runner, err := migrate.NewRunner(p.app.DB(), migrations.AppMigrations) | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
|  | ||||
| 			if err := runner.Run(args...); err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	return command | ||||
| } | ||||
|  | ||||
| func (p *plugin) migrateCreateHandler(template string, args []string) error { | ||||
| 	if len(args) < 1 { | ||||
| 		return fmt.Errorf("Missing migration file name") | ||||
| 	} | ||||
|  | ||||
| 	name := args[0] | ||||
|  | ||||
| 	var dir string | ||||
| 	if len(args) == 2 { | ||||
| 		dir = args[1] | ||||
| 	} | ||||
| 	if dir == "" { | ||||
| 		dir = p.options.Dir | ||||
| 	} | ||||
|  | ||||
| 	resultFilePath := path.Join( | ||||
| 		dir, | ||||
| 		fmt.Sprintf("%d_%s.%s", time.Now().Unix(), inflector.Snakecase(name), p.options.TemplateLang), | ||||
| 	) | ||||
|  | ||||
| 	confirm := false | ||||
| 	prompt := &survey.Confirm{ | ||||
| 		Message: fmt.Sprintf("Do you really want to create migration %q?", resultFilePath), | ||||
| 	} | ||||
| 	survey.AskOne(prompt, &confirm) | ||||
| 	if !confirm { | ||||
| 		fmt.Println("The command has been cancelled") | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// get default create template | ||||
| 	if template == "" { | ||||
| 		var templateErr error | ||||
| 		if p.options.TemplateLang == TemplateLangJS { | ||||
| 			template, templateErr = p.jsCreateTemplate() | ||||
| 		} else { | ||||
| 			template, templateErr = p.goCreateTemplate() | ||||
| 		} | ||||
| 		if templateErr != nil { | ||||
| 			return fmt.Errorf("Failed to resolve create template: %v\n", templateErr) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// ensure that the migrations dir exist | ||||
| 	if err := os.MkdirAll(dir, os.ModePerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// save the migration file | ||||
| 	if err := os.WriteFile(resultFilePath, []byte(template), 0644); err != nil { | ||||
| 		return fmt.Errorf("Failed to save migration file %q: %v\n", resultFilePath, err) | ||||
| 	} | ||||
|  | ||||
| 	fmt.Printf("Successfully created file %q\n", resultFilePath) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *plugin) migrateCollectionsHandler(args []string) error { | ||||
| 	createArgs := []string{"collections_snapshot"} | ||||
| 	createArgs = append(createArgs, args...) | ||||
|  | ||||
| 	collections := []*models.Collection{} | ||||
| 	if err := p.app.Dao().CollectionQuery().OrderBy("created ASC").All(&collections); err != nil { | ||||
| 		return fmt.Errorf("Failed to fetch migrations list: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var template string | ||||
| 	var templateErr error | ||||
| 	if p.options.TemplateLang == TemplateLangJS { | ||||
| 		template, templateErr = p.jsSnapshotTemplate(collections) | ||||
| 	} else { | ||||
| 		template, templateErr = p.goSnapshotTemplate(collections) | ||||
| 	} | ||||
| 	if templateErr != nil { | ||||
| 		return fmt.Errorf("Failed to resolve template: %v", templateErr) | ||||
| 	} | ||||
|  | ||||
| 	return p.migrateCreateHandler(template, createArgs) | ||||
| } | ||||
							
								
								
									
										112
									
								
								plugins/migratecmd/templates.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								plugins/migratecmd/templates.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| package migratecmd | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/pocketbase/pocketbase/models" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	TemplateLangJS = "js" | ||||
| 	TemplateLangGo = "go" | ||||
| ) | ||||
|  | ||||
| // ------------------------------------------------------------------- | ||||
| // JavaScript templates | ||||
| // ------------------------------------------------------------------- | ||||
|  | ||||
| func (p *plugin) jsCreateTemplate() (string, error) { | ||||
| 	const template = `migrate((db) => { | ||||
|   // add up queries... | ||||
| }, (db) => { | ||||
|   // add down queries... | ||||
| }) | ||||
| ` | ||||
|  | ||||
| 	return template, nil | ||||
| } | ||||
|  | ||||
| func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, error) { | ||||
| 	jsonData, err := json.MarshalIndent(collections, "  ", "  ") | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("failed to serialize collections list: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	const template = `migrate((db) => { | ||||
|   const snapshot = %s; | ||||
|  | ||||
|   const collections = snapshot.map((item) => unmarshal(item, new Collection())); | ||||
|  | ||||
|   return Dao(db).importCollections(collections, true, null); | ||||
| }, (db) => { | ||||
|   return null; | ||||
| }) | ||||
| ` | ||||
|  | ||||
| 	return fmt.Sprintf(template, string(jsonData)), nil | ||||
| } | ||||
|  | ||||
| // ------------------------------------------------------------------- | ||||
| // Go templates | ||||
| // ------------------------------------------------------------------- | ||||
|  | ||||
| func (p *plugin) goCreateTemplate() (string, error) { | ||||
| 	const template = `package %s | ||||
|  | ||||
| import ( | ||||
| 	"github.com/pocketbase/dbx" | ||||
| 	m "github.com/pocketbase/pocketbase/migrations" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	m.Register(func(db dbx.Builder) error { | ||||
| 		// add up queries... | ||||
|  | ||||
| 		return nil | ||||
| 	}, func(db dbx.Builder) error { | ||||
| 		// add down queries... | ||||
|  | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
| ` | ||||
|  | ||||
| 	return fmt.Sprintf(template, filepath.Base(p.options.Dir)), nil | ||||
| } | ||||
|  | ||||
| func (p *plugin) goSnapshotTemplate(collections []*models.Collection) (string, error) { | ||||
| 	jsonData, err := json.MarshalIndent(collections, "\t", "\t\t") | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("failed to serialize collections list: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	const template = `package %s | ||||
|  | ||||
| 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 := ` + "`%s`" + ` | ||||
|  | ||||
| 		collections := []*models.Collection{} | ||||
| 		if err := json.Unmarshal([]byte(jsonData), &collections); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		return daos.New(db).ImportCollections(collections, true, nil) | ||||
| 	}, func(db dbx.Builder) error { | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
| ` | ||||
| 	return fmt.Sprintf(template, filepath.Base(p.options.Dir), string(jsonData)), nil | ||||
| } | ||||
							
								
								
									
										84
									
								
								plugins/publicdir/publicdir.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								plugins/publicdir/publicdir.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| // 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" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
|  | ||||
| type Options struct { | ||||
| 	Dir           string | ||||
| 	IndexFallback bool | ||||
| 	FlagsCmd      *cobra.Command | ||||
| } | ||||
|  | ||||
| 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() | ||||
| 	} | ||||
|  | ||||
| 	if options.FlagsCmd != nil { | ||||
| 		// add "--publicDir" option flag | ||||
| 		options.FlagsCmd.PersistentFlags().StringVar( | ||||
| 			&options.Dir, | ||||
| 			"publicDir", | ||||
| 			options.Dir, | ||||
| 			"the directory to serve static files", | ||||
| 		) | ||||
|  | ||||
| 		// add "--indexFallback" option flag | ||||
| 		options.FlagsCmd.PersistentFlags().BoolVar( | ||||
| 			&options.IndexFallback, | ||||
| 			"indexFallback", | ||||
| 			options.IndexFallback, | ||||
| 			"fallback the request to index.html on missing static path (eg. when pretty urls are used with SPA)", | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	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") | ||||
| } | ||||
| @@ -127,7 +127,6 @@ func NewWithConfig(config Config) *PocketBase { | ||||
| func (pb *PocketBase) Start() error { | ||||
| 	// register system commands | ||||
| 	pb.RootCmd.AddCommand(cmd.NewServeCommand(pb, !pb.hideStartBanner)) | ||||
| 	pb.RootCmd.AddCommand(cmd.NewMigrateCommand(pb)) | ||||
| 	pb.RootCmd.AddCommand(cmd.NewTempUpgradeCommand(pb)) | ||||
|  | ||||
| 	return pb.Execute() | ||||
|   | ||||
| @@ -357,19 +357,19 @@ func createTestDir(t *testing.T) string { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	file1, err := os.OpenFile(filepath.Join(dir, "test/sub1.txt"), os.O_WRONLY|os.O_CREATE, 0666) | ||||
| 	file1, err := os.OpenFile(filepath.Join(dir, "test/sub1.txt"), os.O_WRONLY|os.O_CREATE, 0644) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	file1.Close() | ||||
|  | ||||
| 	file2, err := os.OpenFile(filepath.Join(dir, "test/sub2.txt"), os.O_WRONLY|os.O_CREATE, 0666) | ||||
| 	file2, err := os.OpenFile(filepath.Join(dir, "test/sub2.txt"), os.O_WRONLY|os.O_CREATE, 0644) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	file2.Close() | ||||
|  | ||||
| 	file3, err := os.OpenFile(filepath.Join(dir, "image.png"), os.O_WRONLY|os.O_CREATE, 0666) | ||||
| 	file3, err := os.OpenFile(filepath.Join(dir, "image.png"), os.O_WRONLY|os.O_CREATE, 0644) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| @@ -377,18 +377,18 @@ func createTestDir(t *testing.T) string { | ||||
| 	imgRect := image.Rect(0, 0, 1, 1) | ||||
| 	png.Encode(file3, imgRect) | ||||
| 	file3.Close() | ||||
| 	err2 := os.WriteFile(filepath.Join(dir, "image.png.attrs"), []byte(`{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null}`), 0666) | ||||
| 	err2 := os.WriteFile(filepath.Join(dir, "image.png.attrs"), []byte(`{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null}`), 0644) | ||||
| 	if err2 != nil { | ||||
| 		t.Fatal(err2) | ||||
| 	} | ||||
|  | ||||
| 	file4, err := os.OpenFile(filepath.Join(dir, "image.svg"), os.O_WRONLY|os.O_CREATE, 0666) | ||||
| 	file4, err := os.OpenFile(filepath.Join(dir, "image.svg"), os.O_WRONLY|os.O_CREATE, 0644) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	file4.Close() | ||||
|  | ||||
| 	file5, err := os.OpenFile(filepath.Join(dir, "style.css"), os.O_WRONLY|os.O_CREATE, 0666) | ||||
| 	file5, err := os.OpenFile(filepath.Join(dir, "style.css"), os.O_WRONLY|os.O_CREATE, 0644) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|   | ||||
| @@ -8,24 +8,24 @@ import ( | ||||
| 	"github.com/pocketbase/dbx" | ||||
| ) | ||||
|  | ||||
| type migration struct { | ||||
| 	file string | ||||
| 	up   func(db dbx.Builder) error | ||||
| 	down func(db dbx.Builder) error | ||||
| type Migration struct { | ||||
| 	File string | ||||
| 	Up   func(db dbx.Builder) error | ||||
| 	Down func(db dbx.Builder) error | ||||
| } | ||||
|  | ||||
| // MigrationsList defines a list with migration definitions | ||||
| type MigrationsList struct { | ||||
| 	list []*migration | ||||
| 	list []*Migration | ||||
| } | ||||
|  | ||||
| // Item returns a single migration from the list by its index. | ||||
| func (l *MigrationsList) Item(index int) *migration { | ||||
| func (l *MigrationsList) Item(index int) *Migration { | ||||
| 	return l.list[index] | ||||
| } | ||||
|  | ||||
| // Items returns the internal migrations list slice. | ||||
| func (l *MigrationsList) Items() []*migration { | ||||
| func (l *MigrationsList) Items() []*Migration { | ||||
| 	return l.list | ||||
| } | ||||
|  | ||||
| @@ -47,13 +47,13 @@ func (l *MigrationsList) Register( | ||||
| 		file = filepath.Base(path) | ||||
| 	} | ||||
|  | ||||
| 	l.list = append(l.list, &migration{ | ||||
| 		file: file, | ||||
| 		up:   up, | ||||
| 		down: down, | ||||
| 	l.list = append(l.list, &Migration{ | ||||
| 		File: file, | ||||
| 		Up:   up, | ||||
| 		Down: down, | ||||
| 	}) | ||||
|  | ||||
| 	sort.Slice(l.list, func(i int, j int) bool { | ||||
| 		return l.list[i].file < l.list[j].file | ||||
| 		return l.list[i].File < l.list[j].File | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -26,8 +26,8 @@ func TestMigrationsList(t *testing.T) { | ||||
|  | ||||
| 	for i, name := range expected { | ||||
| 		item := l.Item(i) | ||||
| 		if item.file != name { | ||||
| 			t.Fatalf("Expected name %s for index %d, got %s", name, i, item.file) | ||||
| 		if item.File != name { | ||||
| 			t.Fatalf("Expected name %s for index %d, got %s", name, i, item.File) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -111,19 +111,19 @@ func (r *Runner) Up() ([]string, error) { | ||||
| 	err := r.db.Transactional(func(tx *dbx.Tx) error { | ||||
| 		for _, m := range r.migrationsList.Items() { | ||||
| 			// skip applied | ||||
| 			if r.isMigrationApplied(tx, m.file) { | ||||
| 			if r.isMigrationApplied(tx, m.File) { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			if err := m.up(tx); err != nil { | ||||
| 				return fmt.Errorf("Failed to apply migration %s: %w", m.file, err) | ||||
| 			if err := m.Up(tx); err != nil { | ||||
| 				return fmt.Errorf("Failed to apply migration %s: %w", m.File, err) | ||||
| 			} | ||||
|  | ||||
| 			if err := r.saveAppliedMigration(tx, m.file); err != nil { | ||||
| 				return fmt.Errorf("Failed to save applied migration info for %s: %w", m.file, err) | ||||
| 			if err := r.saveAppliedMigration(tx, m.File); err != nil { | ||||
| 				return fmt.Errorf("Failed to save applied migration info for %s: %w", m.File, err) | ||||
| 			} | ||||
|  | ||||
| 			applied = append(applied, m.file) | ||||
| 			applied = append(applied, m.File) | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| @@ -146,7 +146,7 @@ func (r *Runner) Down(toRevertCount int) ([]string, error) { | ||||
| 			m := r.migrationsList.Item(i) | ||||
|  | ||||
| 			// skip unapplied | ||||
| 			if !r.isMigrationApplied(tx, m.file) { | ||||
| 			if !r.isMigrationApplied(tx, m.File) { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| @@ -155,15 +155,15 @@ func (r *Runner) Down(toRevertCount int) ([]string, error) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			if err := m.down(tx); err != nil { | ||||
| 				return fmt.Errorf("Failed to revert migration %s: %w", m.file, err) | ||||
| 			if err := m.Down(tx); err != nil { | ||||
| 				return fmt.Errorf("Failed to revert migration %s: %w", m.File, err) | ||||
| 			} | ||||
|  | ||||
| 			if err := r.saveRevertedMigration(tx, m.file); err != nil { | ||||
| 				return fmt.Errorf("Failed to save reverted migration info for %s: %w", m.file, err) | ||||
| 			if err := r.saveRevertedMigration(tx, m.File); err != nil { | ||||
| 				return fmt.Errorf("Failed to save reverted migration info for %s: %w", m.File, err) | ||||
| 			} | ||||
|  | ||||
| 			reverted = append(reverted, m.file) | ||||
| 			reverted = append(reverted, m.File) | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
|   | ||||
| @@ -79,7 +79,7 @@ func TestRunnerUpAndDown(t *testing.T) { | ||||
| 	} | ||||
|  | ||||
| 	// simulate partially run migration | ||||
| 	r.saveAppliedMigration(testDB, r.migrationsList.Item(0).file) | ||||
| 	r.saveAppliedMigration(testDB, r.migrationsList.Item(0).File) | ||||
|  | ||||
| 	// Up() | ||||
| 	// --- | ||||
|   | ||||
							
								
								
									
										2
									
								
								ui/.env
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								ui/.env
									
									
									
									
									
								
							| @@ -7,4 +7,4 @@ PB_FILE_UPLOAD_DOCS  = "https://pocketbase.io/docs/files-handling/" | ||||
| PB_JS_SDK_URL        = "https://github.com/pocketbase/js-sdk" | ||||
| PB_DART_SDK_URL      = "https://github.com/pocketbase/dart-sdk" | ||||
| PB_RELEASES          = "https://github.com/pocketbase/pocketbase/releases" | ||||
| PB_VERSION           = "v0.8.0" | ||||
| PB_VERSION           = "v0.9.0-rc" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user