updated automigrate templates, added js bindings tests and updated models IsNew behavior
This commit is contained in:
		
							parent
							
								
									604009bd10
								
							
						
					
					
						commit
						b8cd686b32
					
				| 
						 | 
				
			
			@ -1,5 +1,9 @@
 | 
			
		|||
## (WIP) v0.9.0
 | 
			
		||||
 | 
			
		||||
- `BaseModel.UnmarkAsNew()` method was renamed to `BaseModel.MarkAsNotNew()`.
 | 
			
		||||
  Additionally, to simplify the insert model queries with custom IDs, it is no longer required to call `MarkAsNew()` for manually initialized models with set ID since now this is the default state.
 | 
			
		||||
  When the model is populated with values from the database (eg. after row `Scan`) it will be marked automatically as "not new".
 | 
			
		||||
 | 
			
		||||
- Added `Record.OriginalCopy()` method that returns a new `Record` copy populated with the initially loaded record data (useful if you want to compare old and new field values).
 | 
			
		||||
 | 
			
		||||
- Added new event hooks:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								core/app.go
								
								
								
								
							
							
						
						
									
										44
									
								
								core/app.go
								
								
								
								
							| 
						 | 
				
			
			@ -308,70 +308,70 @@ type App interface {
 | 
			
		|||
	// record data and token.
 | 
			
		||||
	OnRecordAuthRequest() *hook.Hook[*RecordAuthEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordBeforeRequestPasswordResetRequest hook is triggered before each API Record
 | 
			
		||||
	// request password reset request (after request data load and before sending the reset email).
 | 
			
		||||
	// OnRecordBeforeRequestPasswordResetRequest hook is triggered before each Record
 | 
			
		||||
	// request password reset API request (after request data load and before sending the reset email).
 | 
			
		||||
	//
 | 
			
		||||
	// Could be used to additionally validate the request data or implement
 | 
			
		||||
	// completely different persistence behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	// completely different password reset behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	OnRecordBeforeRequestPasswordResetRequest() *hook.Hook[*RecordRequestPasswordResetEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordAfterRequestPasswordResetRequest hook is triggered after each
 | 
			
		||||
	// successful API request password reset request.
 | 
			
		||||
	// successful request password reset API request.
 | 
			
		||||
	OnRecordAfterRequestPasswordResetRequest() *hook.Hook[*RecordRequestPasswordResetEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordBeforeConfirmPasswordResetRequest hook is triggered before each API Record
 | 
			
		||||
	// confirm password reset request (after request data load and before persistence).
 | 
			
		||||
	// OnRecordBeforeConfirmPasswordResetRequest hook is triggered before each Record
 | 
			
		||||
	// confirm password reset API request (after request data load and before persistence).
 | 
			
		||||
	//
 | 
			
		||||
	// Could be used to additionally validate the request data or implement
 | 
			
		||||
	// completely different persistence behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	OnRecordBeforeConfirmPasswordResetRequest() *hook.Hook[*RecordConfirmPasswordResetEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordAfterConfirmPasswordResetRequest hook is triggered after each
 | 
			
		||||
	// successful API confirm password reset request.
 | 
			
		||||
	// successful confirm password reset API request.
 | 
			
		||||
	OnRecordAfterConfirmPasswordResetRequest() *hook.Hook[*RecordConfirmPasswordResetEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordBeforeRequestVerificationRequest hook is triggered before each API Record
 | 
			
		||||
	// request verification request (after request data load and before sending the verification email).
 | 
			
		||||
	// OnRecordBeforeRequestVerificationRequest hook is triggered before each Record
 | 
			
		||||
	// request verification API request (after request data load and before sending the verification email).
 | 
			
		||||
	//
 | 
			
		||||
	// Could be used to additionally validate the request data or implement
 | 
			
		||||
	// completely different persistence behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	// Could be used to additionally validate the loaded request data or implement
 | 
			
		||||
	// completely different verification behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	OnRecordBeforeRequestVerificationRequest() *hook.Hook[*RecordRequestVerificationEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordAfterRequestVerificationRequest hook is triggered after each
 | 
			
		||||
	// successful API request verification request.
 | 
			
		||||
	// successful request verification API request.
 | 
			
		||||
	OnRecordAfterRequestVerificationRequest() *hook.Hook[*RecordRequestVerificationEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordBeforeConfirmVerificationRequest hook is triggered before each API Record
 | 
			
		||||
	// confirm verification request (after request data load and before persistence).
 | 
			
		||||
	// OnRecordBeforeConfirmVerificationRequest hook is triggered before each Record
 | 
			
		||||
	// confirm verification API request (after request data load and before persistence).
 | 
			
		||||
	//
 | 
			
		||||
	// Could be used to additionally validate the request data or implement
 | 
			
		||||
	// completely different persistence behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	OnRecordBeforeConfirmVerificationRequest() *hook.Hook[*RecordConfirmVerificationEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordAfterConfirmVerificationRequest hook is triggered after each
 | 
			
		||||
	// successful API confirm verification request.
 | 
			
		||||
	// successful confirm verification API request.
 | 
			
		||||
	OnRecordAfterConfirmVerificationRequest() *hook.Hook[*RecordConfirmVerificationEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordBeforeRequestEmailChangeRequest hook is triggered before each API Record request email change request
 | 
			
		||||
	// (after request data load and before sending the email change confirmation email).
 | 
			
		||||
	// OnRecordBeforeRequestEmailChangeRequest hook is triggered before each Record request email change API request
 | 
			
		||||
	// (after request data load and before sending the email link to confirm the change).
 | 
			
		||||
	//
 | 
			
		||||
	// Could be used to additionally validate the request data or implement
 | 
			
		||||
	// completely different persistence behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	// completely different request email change behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	OnRecordBeforeRequestEmailChangeRequest() *hook.Hook[*RecordRequestEmailChangeEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordAfterRequestEmailChangeRequest hook is triggered after each
 | 
			
		||||
	// successful API request email change request.
 | 
			
		||||
	// successful request email change API request.
 | 
			
		||||
	OnRecordAfterRequestEmailChangeRequest() *hook.Hook[*RecordRequestEmailChangeEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordBeforeConfirmEmailChangeRequest hook is triggered before each API Record
 | 
			
		||||
	// confirm email change request (after request data load and before persistence).
 | 
			
		||||
	// OnRecordBeforeConfirmEmailChangeRequest hook is triggered before each Record
 | 
			
		||||
	// confirm email change API request (after request data load and before persistence).
 | 
			
		||||
	//
 | 
			
		||||
	// Could be used to additionally validate the request data or implement
 | 
			
		||||
	// completely different persistence behavior (returning [hook.StopPropagation]).
 | 
			
		||||
	OnRecordBeforeConfirmEmailChangeRequest() *hook.Hook[*RecordConfirmEmailChangeEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordAfterConfirmEmailChangeRequest hook is triggered after each
 | 
			
		||||
	// successful API confirm email change request.
 | 
			
		||||
	// successful confirm email change API request.
 | 
			
		||||
	OnRecordAfterConfirmEmailChangeRequest() *hook.Hook[*RecordConfirmEmailChangeEvent]
 | 
			
		||||
 | 
			
		||||
	// OnRecordListExternalAuthsRequest hook is triggered on each API record external auths list request.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -768,14 +768,12 @@ func (app *BaseApp) initDataDB() error {
 | 
			
		|||
		return connectErr
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app.db.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
 | 
			
		||||
	if app.IsDebug() {
 | 
			
		||||
		app.db.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
 | 
			
		||||
			color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), sql)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		app.db.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {
 | 
			
		||||
		if app.IsDebug() {
 | 
			
		||||
			color.HiBlack("[%.2fms] %v\n", float64(t.Milliseconds()), sql)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -239,7 +239,7 @@ func (dao *Dao) create(m models.Model) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// clears the "new" model flag
 | 
			
		||||
	m.UnmarkAsNew()
 | 
			
		||||
	m.MarkAsNotNew()
 | 
			
		||||
 | 
			
		||||
	if dao.AfterCreateFunc != nil {
 | 
			
		||||
		dao.AfterCreateFunc(dao, m)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -212,6 +212,8 @@ func (dao *Dao) ImportCollections(
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			if existing, ok := mappedExisting[imported.GetId()]; ok {
 | 
			
		||||
				imported.MarkAsNotNew()
 | 
			
		||||
 | 
			
		||||
				// preserve original created date
 | 
			
		||||
				if !existing.Created.IsZero() {
 | 
			
		||||
					imported.Created = existing.Created
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,6 +103,7 @@ func (form *CollectionsImport) beforeRecordsSync(txDao *daos.Dao, mappedNew, map
 | 
			
		|||
		if upsertModel == nil {
 | 
			
		||||
			upsertModel = collection
 | 
			
		||||
		}
 | 
			
		||||
		upsertModel.MarkAsNotNew()
 | 
			
		||||
 | 
			
		||||
		upsertForm := NewCollectionUpsert(form.app, upsertModel)
 | 
			
		||||
		upsertForm.SetDao(txDao)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										58
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										58
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -4,7 +4,7 @@ go 1.18
 | 
			
		|||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/AlecAivazis/survey/v2 v2.3.6
 | 
			
		||||
	github.com/aws/aws-sdk-go v1.44.145
 | 
			
		||||
	github.com/aws/aws-sdk-go v1.44.152
 | 
			
		||||
	github.com/disintegration/imaging v1.6.2
 | 
			
		||||
	github.com/domodwyer/mailyak/v3 v3.3.4
 | 
			
		||||
	github.com/dop251/goja v0.0.0-20221118162653-d4bf6fde1b86
 | 
			
		||||
| 
						 | 
				
			
			@ -13,40 +13,40 @@ require (
 | 
			
		|||
	github.com/gabriel-vasile/mimetype v1.4.1
 | 
			
		||||
	github.com/ganigeorgiev/fexpr v0.1.1
 | 
			
		||||
	github.com/go-ozzo/ozzo-validation/v4 v4.3.0
 | 
			
		||||
	github.com/golang-jwt/jwt/v4 v4.4.2
 | 
			
		||||
	github.com/golang-jwt/jwt/v4 v4.4.3
 | 
			
		||||
	github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
 | 
			
		||||
	github.com/mattn/go-sqlite3 v1.14.16
 | 
			
		||||
	github.com/pocketbase/dbx v1.7.0
 | 
			
		||||
	github.com/pocketbase/dbx v1.8.0
 | 
			
		||||
	github.com/spf13/cast v1.5.0
 | 
			
		||||
	github.com/spf13/cobra v1.6.1
 | 
			
		||||
	gocloud.dev v0.27.0
 | 
			
		||||
	golang.org/x/crypto v0.3.0
 | 
			
		||||
	golang.org/x/net v0.2.0
 | 
			
		||||
	golang.org/x/oauth2 v0.2.0
 | 
			
		||||
	modernc.org/sqlite v1.19.5
 | 
			
		||||
	modernc.org/sqlite v1.20.0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2 v1.17.1 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/config v1.18.3 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 // indirect
 | 
			
		||||
	github.com/aws/smithy-go v1.13.4 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2 v1.17.2 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/config v1.18.4 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/credentials v1.13.4 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 // indirect
 | 
			
		||||
	github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 // indirect
 | 
			
		||||
	github.com/aws/smithy-go v1.13.5 // 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
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ require (
 | 
			
		|||
	github.com/google/uuid v1.3.0 // indirect
 | 
			
		||||
	github.com/google/wire v0.5.0 // indirect
 | 
			
		||||
	github.com/googleapis/gax-go/v2 v2.7.0 // indirect
 | 
			
		||||
	github.com/inconshreveable/mousetrap v1.0.1 // indirect
 | 
			
		||||
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 | 
			
		||||
	github.com/jmespath/go-jmespath v0.4.0 // indirect
 | 
			
		||||
	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
 | 
			
		||||
	github.com/mattn/go-colorable v0.1.13 // indirect
 | 
			
		||||
| 
						 | 
				
			
			@ -67,15 +67,15 @@ require (
 | 
			
		|||
	go.opencensus.io v0.24.0 // indirect
 | 
			
		||||
	golang.org/x/image v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/mod v0.7.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.2.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.3.0 // indirect
 | 
			
		||||
	golang.org/x/term v0.2.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.4.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.2.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.5.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.3.0 // indirect
 | 
			
		||||
	golang.org/x/tools v0.3.0 // indirect
 | 
			
		||||
	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 | 
			
		||||
	google.golang.org/api v0.103.0 // indirect
 | 
			
		||||
	google.golang.org/appengine v1.6.7 // indirect
 | 
			
		||||
	google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
 | 
			
		||||
	google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect
 | 
			
		||||
	google.golang.org/grpc v1.51.0 // indirect
 | 
			
		||||
	google.golang.org/protobuf v1.28.1 // indirect
 | 
			
		||||
	lukechampine.com/uint128 v1.2.0 // indirect
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ require (
 | 
			
		|||
	modernc.org/ccgo/v3 v3.16.13 // indirect
 | 
			
		||||
	modernc.org/libc v1.21.5 // indirect
 | 
			
		||||
	modernc.org/mathutil v1.5.0 // indirect
 | 
			
		||||
	modernc.org/memory v1.4.0 // indirect
 | 
			
		||||
	modernc.org/memory v1.5.0 // indirect
 | 
			
		||||
	modernc.org/opt v0.1.3 // indirect
 | 
			
		||||
	modernc.org/strutil v1.1.3 // indirect
 | 
			
		||||
	modernc.org/token v1.1.0 // indirect
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										132
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										132
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -47,7 +47,7 @@ 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.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
 | 
			
		||||
cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU=
 | 
			
		||||
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=
 | 
			
		||||
| 
						 | 
				
			
			@ -206,82 +206,70 @@ 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.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 v1.44.145 h1:KMVRrIyjBsNz3xGPuHIRnhIuKlb5h3Ii5e5jbi3cgnc=
 | 
			
		||||
github.com/aws/aws-sdk-go v1.44.145/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 | 
			
		||||
github.com/aws/aws-sdk-go v1.44.152 h1:L9aaepO8wHB67gwuGD8VgIYH/cmQDxieCt7FeLa0+fI=
 | 
			
		||||
github.com/aws/aws-sdk-go v1.44.152/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2 v1.17.2 h1:r0yRZInwiPBNpQ4aDy/Ssh3ROWsGtKDwar2JS8Lm+N8=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2 v1.17.2/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y=
 | 
			
		||||
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/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
 | 
			
		||||
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.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/config v1.18.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/config v1.18.3/go.mod h1:BYdrbeCse3ZnOD5+2/VE/nATOK8fEUpBtmPMdKSyhMU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/config v1.18.4 h1:VZKhr3uAADXHStS/Gf9xSYVmmaluTUfkc0dcbPiDsKE=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/config v1.18.4/go.mod h1:EZxMPLSdGAZ3eAmkqXfYbRppZJTzFTkv8VyEzJhKko4=
 | 
			
		||||
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.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/credentials v1.13.3 h1:ur+FHdp4NbVIv/49bUjBW+FE7e57HOo03ELodttmagk=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.3/go.mod h1:/rOMmqYBcFfNbRPU0iN9IgGqD5+V2yp3iWNmIlz0wI4=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.4 h1:nEbHIyJy7mCvQ/kzGG7VWHSBpRB4H6sJy3bWierWUtg=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.4/go.mod h1:/Cj5w9LRsNTLSwexsohwDME32OzJ6U81Zs33zr2ZWOM=
 | 
			
		||||
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/ec2/imds v1.12.20 h1:tpNOglTZ8kg9T38NpcGBxudqfUAwUzyUnLQ4XSd0CHE=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20/go.mod h1:d9xFpWd3qYwdIXM0fvu7deD08vvdRXyc/ueV+0SqaWE=
 | 
			
		||||
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.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/feature/s3/manager v1.11.42 h1:bxgBYvvBh+W1RnNYP4ROXEB8N+HSSucDszfE7Rb+kfU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42/go.mod h1:LHOsygMiW/14CkFxdXxvzKyMh3jbk/QfZVaDtCbLkl8=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43 h1:+bkAMTd5OGyHu2nwNOangjEsP65fR0uhMbZJA52sZ64=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.43/go.mod h1:sS2tu0VEspKuY5eM1vQgy7P/hpZX8F62o6qsghZExWc=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 h1:5WU31cY7m0tG+AiaXuXGoMzo2GBQ1IixtWa8Yywsgco=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26/go.mod h1:2E0LdbJW6lbeU4uxjum99GZzI0ZjDpAb0CoSCM0oeEY=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9/go.mod h1:08tUpeSGN33QKSO7fwxXczNfiwCpbj+GxK6XKwqWVv0=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 h1:WW0qSzDWoiWU2FS5DbKpxGilFVlCEJPwx4YtjdfI0Jw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20/go.mod h1:/+6lSiby8TBFpTVXZgKiN/rCfkYXEGvhlM4zCgPpt7w=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16/go.mod h1:CYmI+7x03jjJih8kBEEFKRQc40UjUokT0k7GbvrhhTc=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 h1:N2eKFw2S+JWRCtTt0IhIX7uoGGQciD4p6ba+SJv4WEU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27/go.mod h1:RdwFVc7PBYWY33fa2+8T1mSqQ7ZEK4ILpM0wfioDC3w=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.6/go.mod h1:O7Oc4peGZDEKlddivslfYFvAbgzvl/GH3J8j3JIGBXc=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 h1:2EXB7dtGwRYIN3XQ9qwIW504DVbKIw3r89xQnonGdsQ=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16/go.mod h1:XH+3h395e3WVdd6T2Z3mPxuI+x/HVtdqVOREkTiyubs=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17 h1:5tXbMJ7Jq0iG65oiMg6tCLsHkSaO2xLXa2EmZ29vaTA=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.17/go.mod h1:twV0fKMQuqLY4klyFH56aXNq3AFiA5LO0/frTczEOFE=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3/go.mod h1:gkb2qADY+OHaGLKNTYxMaQNacfeyQpZ4csDTQMeFmcw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 h1:dpiPHgmFstgkLG07KaYAewvuptq5kvo52xn7tVSrtrQ=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10/go.mod h1:9cBNUHI2aW4ho0A5T87O294iPDuuUOSIEDjnd1Lq/z0=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.10/go.mod h1:Qks+dxK3O+Z2deAhNo6cJ8ls1bam3tUGUAcgxQP1c70=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 h1:KSvtm1+fPXE0swe9GPjc6msyrdTT0LB/BP8eLugL1FI=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20/go.mod h1:Mp4XI/CkWGD79AQxZ5lIFlgvC0A+gl+4BmyG1F+SfNc=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21 h1:77b1GfaSuIok5yB/3HYbG+ypWvOJDQ2rVdq943D17R4=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.21/go.mod h1:sPOz31BVdqeeurKEuUpLNSve4tdCNPluE+070HNcEHI=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9/go.mod h1:yQowTpvdZkFVuHrLBXmczat4W+WJKg/PafBZnGBLga0=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 h1:jlgyHbkZQAgAc7VIxJDmtouH8eNjOk2REVAQfVhdaiQ=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20/go.mod h1:Xs52xaLBqDEKRcAfX/hgjmD3YQ7c/W+BEyfamlO/W2E=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9/go.mod h1:Rc5+wn2k8gFSi3V1Ch4mhxOzjMh+bYSXVFfVaqowQOY=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkVV3xJJbTehXCZRXYs49kvpi/LG6LR2o=
 | 
			
		||||
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/internal/s3shared v1.13.20 h1:4K6dbmR0mlp3o4Bo78PnpvzHtYAqEeVMguvEenpMGsI=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.20/go.mod h1:1XpDcReIEOHsjwNToDKhIAO3qwLo1BnfbtSqWJa8j7g=
 | 
			
		||||
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.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/s3 v1.29.4 h1:QgmmWifaYZZcpaw3y1+ccRlgH6jAvLm4K/MBGUc7cNM=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5 h1:nRSEQj1JergKTVc8RGkhZvOEGgcvo4fWpDPwGDeg2ok=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.5/go.mod h1:wcaJTmjKFDW0s+Se55HBNIds6ghdAGoDDw+SGUdrfAk=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sns v1.17.10/go.mod h1:uITsRNVMeCB3MkWpXxXw0eDz8pW4TYLzj+eyQtbhSxM=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.19.1/go.mod h1:A94o564Gj+Yn+7QO1eLFeI7UVv3riy/YBFOfICVqFvU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.27.6/go.mod h1:fiFzQgj4xNOg4/wqmAiPvzgDMXPD+cUEplX/CYn+0j0=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.13/go.mod h1:d7ptRksDDgvXaUvxyHZ9SYh+iMDymm94JbVcgvSYSzU=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI=
 | 
			
		||||
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/sso v1.11.26 h1:ActQgdTNQej/RuUJjB9uxYVLDOvRGtUreXF8L3c8wyg=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.26/go.mod h1:uB9tV79ULEZUXc6Ob18A46KSQ0JDlrplPni9XW6Ot60=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 h1:wihKuqYUlA2T/Rx+yu2s6NDAns8B9DgnRooB1PVhY+Q=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9/go.mod h1:2E/3D/mB8/r2J7nK42daoKP/ooCwbf0q1PznNc+DZTU=
 | 
			
		||||
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.4 h1:YNncBj5dVYd05i4ZQ+YicOotSXo0ufc9P8kTioi13EM=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sts v1.17.4/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 h1:60SJ4lhvn///8ygCzYy2l53bFW/Q15bVfyjyAWo6zuw=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sts v1.17.5/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 h1:VQFOLQVL3BrKM/NLO/7FiS4vcp5bqK0mGMyk09xLoAY=
 | 
			
		||||
github.com/aws/aws-sdk-go-v2/service/sts v1.17.6/go.mod h1:Az3OXXYGyfNwQNsK/31L4R75qFYnO641RZGAoV3uH1c=
 | 
			
		||||
github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
 | 
			
		||||
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
 | 
			
		||||
github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
 | 
			
		||||
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
 | 
			
		||||
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
 | 
			
		||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
 | 
			
		||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 | 
			
		||||
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 | 
			
		||||
| 
						 | 
				
			
			@ -705,8 +693,9 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
 | 
			
		|||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
 | 
			
		||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 | 
			
		||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 | 
			
		||||
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
 | 
			
		||||
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 | 
			
		||||
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
 | 
			
		||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 | 
			
		||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
 | 
			
		||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
 | 
			
		||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 | 
			
		||||
| 
						 | 
				
			
			@ -803,6 +792,7 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe
 | 
			
		|||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
			
		||||
github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
 | 
			
		||||
github.com/google/pprof v0.0.0-20220608213341-c488b8fa1db3/go.mod h1:gSuNB+gJaOiQKLEZ+q+PK9Mq3SOzhRcw2GsGS/FhYDk=
 | 
			
		||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
 | 
			
		||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
			
		||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 | 
			
		||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
			
		||||
| 
						 | 
				
			
			@ -920,8 +910,9 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
 | 
			
		|||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 | 
			
		||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 | 
			
		||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 | 
			
		||||
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
 | 
			
		||||
github.com/ionos-cloud/sdk-go/v6 v6.1.0/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME=
 | 
			
		||||
| 
						 | 
				
			
			@ -1229,8 +1220,8 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J
 | 
			
		|||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/pocketbase/dbx v1.7.0 h1:MY6/up//aIeH6WA8VqYt3EeQt082bEdKcUDcEF4UrWw=
 | 
			
		||||
github.com/pocketbase/dbx v1.7.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
 | 
			
		||||
github.com/pocketbase/dbx v1.8.0 h1:kjf3mgmmE12t8IG48kJOeIyBmRi0A1sl6Hsezv4PoiA=
 | 
			
		||||
github.com/pocketbase/dbx v1.8.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
 | 
			
		||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 | 
			
		||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
 | 
			
		||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
 | 
			
		||||
| 
						 | 
				
			
			@ -1881,8 +1872,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
 | 
			
		|||
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/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=
 | 
			
		||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
 | 
			
		||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
| 
						 | 
				
			
			@ -1901,8 +1892,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 | 
			
		||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 | 
			
		||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
 | 
			
		||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 | 
			
		||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
 | 
			
		||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 | 
			
		||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
| 
						 | 
				
			
			@ -1915,8 +1907,8 @@ 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.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
 | 
			
		||||
golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 | 
			
		||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
			
		||||
| 
						 | 
				
			
			@ -2171,8 +2163,8 @@ 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-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/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks=
 | 
			
		||||
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
 | 
			
		||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 | 
			
		||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 | 
			
		||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 | 
			
		||||
| 
						 | 
				
			
			@ -2352,20 +2344,16 @@ 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=
 | 
			
		||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
 | 
			
		||||
modernc.org/libc v1.21.4 h1:CzTlumWeIbPV5/HVIMzYHNPCRP8uiU/CWiN2gtd/Qu8=
 | 
			
		||||
modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
 | 
			
		||||
modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
 | 
			
		||||
modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
 | 
			
		||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
 | 
			
		||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
 | 
			
		||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
 | 
			
		||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
 | 
			
		||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
 | 
			
		||||
modernc.org/memory v1.5.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.4 h1:nlPIDqumn6/mSvs7T5C8MNYEuN73sISzPdKtMdURpUI=
 | 
			
		||||
modernc.org/sqlite v1.19.4/go.mod h1:x/yZNb3h5+I3zGQSlwIv4REL5eJhiRkUH5MReogAeIc=
 | 
			
		||||
modernc.org/sqlite v1.19.5 h1:E3iHL55c1Vw1knqIeU9N7B0fSjuiOjHZo7iVMsO6U5U=
 | 
			
		||||
modernc.org/sqlite v1.19.5/go.mod h1:EsYz8rfOvLCiYTy5ZFsOYzoCcRMu98YYkwAcCw5YIYw=
 | 
			
		||||
modernc.org/sqlite v1.20.0 h1:80zmD3BGkm8BZ5fUi/4lwJQHiO3GXgIUvZRXpoIfROY=
 | 
			
		||||
modernc.org/sqlite v1.20.0/go.mod h1:EsYz8rfOvLCiYTy5ZFsOYzoCcRMu98YYkwAcCw5YIYw=
 | 
			
		||||
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=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,7 +31,7 @@ type Model interface {
 | 
			
		|||
	TableName() string
 | 
			
		||||
	IsNew() bool
 | 
			
		||||
	MarkAsNew()
 | 
			
		||||
	UnmarkAsNew()
 | 
			
		||||
	MarkAsNotNew()
 | 
			
		||||
	HasId() bool
 | 
			
		||||
	GetId() string
 | 
			
		||||
	SetId(id string)
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ type Model interface {
 | 
			
		|||
 | 
			
		||||
// BaseModel defines common fields and methods used by all other models.
 | 
			
		||||
type BaseModel struct {
 | 
			
		||||
	isNewFlag bool
 | 
			
		||||
	isNotNew bool
 | 
			
		||||
 | 
			
		||||
	Id      string         `db:"id" json:"id"`
 | 
			
		||||
	Created types.DateTime `db:"created" json:"created"`
 | 
			
		||||
| 
						 | 
				
			
			@ -70,20 +70,20 @@ func (m *BaseModel) SetId(id string) {
 | 
			
		|||
	m.Id = id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarkAsNew sets the model isNewFlag enforcing [m.IsNew()] to be true.
 | 
			
		||||
// MarkAsNew marks the model as "new" (aka. enforces m.IsNew() to be true).
 | 
			
		||||
func (m *BaseModel) MarkAsNew() {
 | 
			
		||||
	m.isNewFlag = true
 | 
			
		||||
	m.isNotNew = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarkAsNew resets the model isNewFlag.
 | 
			
		||||
func (m *BaseModel) UnmarkAsNew() {
 | 
			
		||||
	m.isNewFlag = false
 | 
			
		||||
// MarkAsNotNew marks the model as "not new" (aka. enforces m.IsNew() to be false)
 | 
			
		||||
func (m *BaseModel) MarkAsNotNew() {
 | 
			
		||||
	m.isNotNew = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsNew indicates what type of db query (insert or update)
 | 
			
		||||
// should be used with the model instance.
 | 
			
		||||
func (m *BaseModel) IsNew() bool {
 | 
			
		||||
	return m.isNewFlag || !m.HasId()
 | 
			
		||||
	return !m.isNotNew
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCreated returns the model Created datetime.
 | 
			
		||||
| 
						 | 
				
			
			@ -100,9 +100,6 @@ func (m *BaseModel) GetUpdated() types.DateTime {
 | 
			
		|||
//
 | 
			
		||||
// The generated id is a cryptographically random 15 characters length string.
 | 
			
		||||
func (m *BaseModel) RefreshId() {
 | 
			
		||||
	if m.Id == "" { // no previous id
 | 
			
		||||
		m.MarkAsNew()
 | 
			
		||||
	}
 | 
			
		||||
	m.Id = security.RandomStringWithAlphabet(DefaultIdLength, DefaultIdAlphabet)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -115,3 +112,11 @@ func (m *BaseModel) RefreshCreated() {
 | 
			
		|||
func (m *BaseModel) RefreshUpdated() {
 | 
			
		||||
	m.Updated = types.NowDateTime()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PostScan implements the [dbx.PostScanner] interface.
 | 
			
		||||
//
 | 
			
		||||
// It is executed right after the model was populated with the db row values.
 | 
			
		||||
func (m *BaseModel) PostScan() error {
 | 
			
		||||
	m.MarkAsNotNew()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,15 +58,19 @@ func TestBaseModelIsNew(t *testing.T) {
 | 
			
		|||
	m1 := models.BaseModel{Id: ""}
 | 
			
		||||
	m2 := models.BaseModel{Id: "test"}
 | 
			
		||||
	m3 := models.BaseModel{}
 | 
			
		||||
	m3.MarkAsNew()
 | 
			
		||||
	m3.MarkAsNotNew()
 | 
			
		||||
	m4 := models.BaseModel{Id: "test"}
 | 
			
		||||
	m4.MarkAsNew()
 | 
			
		||||
	m4.MarkAsNotNew()
 | 
			
		||||
	m5 := models.BaseModel{Id: "test"}
 | 
			
		||||
	m5.MarkAsNew()
 | 
			
		||||
	m5.UnmarkAsNew()
 | 
			
		||||
	// check if MarkAsNew will be called on initial RefreshId()
 | 
			
		||||
	m5.MarkAsNotNew()
 | 
			
		||||
	m6 := models.BaseModel{}
 | 
			
		||||
	m6.RefreshId()
 | 
			
		||||
	m7 := models.BaseModel{}
 | 
			
		||||
	m7.MarkAsNotNew()
 | 
			
		||||
	m7.RefreshId()
 | 
			
		||||
	m8 := models.BaseModel{}
 | 
			
		||||
	m8.PostScan()
 | 
			
		||||
 | 
			
		||||
	scenarios := []struct {
 | 
			
		||||
		model    models.BaseModel
 | 
			
		||||
| 
						 | 
				
			
			@ -74,11 +78,13 @@ func TestBaseModelIsNew(t *testing.T) {
 | 
			
		|||
	}{
 | 
			
		||||
		{m0, true},
 | 
			
		||||
		{m1, true},
 | 
			
		||||
		{m2, false},
 | 
			
		||||
		{m3, true},
 | 
			
		||||
		{m4, true},
 | 
			
		||||
		{m2, true},
 | 
			
		||||
		{m3, false},
 | 
			
		||||
		{m4, false},
 | 
			
		||||
		{m5, false},
 | 
			
		||||
		{m6, true},
 | 
			
		||||
		{m7, false},
 | 
			
		||||
		{m8, false},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, s := range scenarios {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,6 +79,7 @@ func NewRecordFromNullStringMap(collection *Collection, data dbx.NullStringMap)
 | 
			
		|||
	record := NewRecord(collection)
 | 
			
		||||
 | 
			
		||||
	record.Load(resultMap)
 | 
			
		||||
	record.PostScan()
 | 
			
		||||
 | 
			
		||||
	return record
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -111,6 +112,10 @@ func (m *Record) OriginalCopy() *Record {
 | 
			
		|||
	newRecord := NewRecord(m.collection)
 | 
			
		||||
	newRecord.Load(m.originalData)
 | 
			
		||||
 | 
			
		||||
	if !m.IsNew() {
 | 
			
		||||
		newRecord.MarkAsNotNew()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newRecord
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -195,7 +195,14 @@ func (s *Schema) UnmarshalJSON(data []byte) error {
 | 
			
		|||
		s.AddField(f)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s.InitFieldsOptions()
 | 
			
		||||
	for _, field := range s.fields {
 | 
			
		||||
		if err := field.InitOptions(); err != nil {
 | 
			
		||||
			// ignore the error and remove the invalid field
 | 
			
		||||
			s.RemoveField(field.Id)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Value implements the [driver.Valuer] interface.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ func RegisterMigrations(app core.App, options *MigrationsOptions) error {
 | 
			
		|||
	registry := new(require.Registry) // this can be shared by multiple runtimes
 | 
			
		||||
 | 
			
		||||
	for file, content := range files {
 | 
			
		||||
		vm := NewBaseVM(l.app)
 | 
			
		||||
		vm := NewBaseVM()
 | 
			
		||||
		registry.Enable(vm)
 | 
			
		||||
		console.Enable(vm)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,24 +9,22 @@ import (
 | 
			
		|||
	"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"
 | 
			
		||||
	"github.com/pocketbase/pocketbase/models/schema"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewBaseVM(app core.App) *goja.Runtime {
 | 
			
		||||
func NewBaseVM() *goja.Runtime {
 | 
			
		||||
	vm := goja.New()
 | 
			
		||||
	vm.SetFieldNameMapper(fieldMapper{})
 | 
			
		||||
	vm.Set("$app", app)
 | 
			
		||||
	vm.SetFieldNameMapper(FieldMapper{})
 | 
			
		||||
 | 
			
		||||
	baseBind(vm)
 | 
			
		||||
	dbxBind(vm)
 | 
			
		||||
	baseBinds(vm)
 | 
			
		||||
	dbxBinds(vm)
 | 
			
		||||
 | 
			
		||||
	return vm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func baseBind(vm *goja.Runtime) {
 | 
			
		||||
func baseBinds(vm *goja.Runtime) {
 | 
			
		||||
	vm.Set("unmarshal", func(src map[string]any, dest any) (any, error) {
 | 
			
		||||
		raw, err := json.Marshal(src)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,39 +38,46 @@ func baseBind(vm *goja.Runtime) {
 | 
			
		|||
		return dest, nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	vm.Set("Collection", func(call goja.ConstructorCall) *goja.Object {
 | 
			
		||||
		instance := &models.Collection{}
 | 
			
		||||
	vm.Set("Record", func(call goja.ConstructorCall) *goja.Object {
 | 
			
		||||
		var instance *models.Record
 | 
			
		||||
 | 
			
		||||
		collection, ok := call.Argument(0).Export().(*models.Collection)
 | 
			
		||||
		if ok {
 | 
			
		||||
			instance = models.NewRecord(collection)
 | 
			
		||||
			data, ok := call.Argument(1).Export().(map[string]any)
 | 
			
		||||
			if ok {
 | 
			
		||||
				if raw, err := json.Marshal(data); err == nil {
 | 
			
		||||
					json.Unmarshal(raw, instance)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			instance = &models.Record{}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		instanceValue := vm.ToValue(instance).(*goja.Object)
 | 
			
		||||
		instanceValue.SetPrototype(call.This.Prototype())
 | 
			
		||||
 | 
			
		||||
		return instanceValue
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
	vm.Set("Collection", func(call goja.ConstructorCall) *goja.Object {
 | 
			
		||||
		instance := &models.Collection{}
 | 
			
		||||
		return defaultConstructor(vm, call, instance)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
		return defaultConstructor(vm, call, instance)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	vm.Set("Schema", func(call goja.ConstructorCall) *goja.Object {
 | 
			
		||||
		instance := &schema.Schema{}
 | 
			
		||||
		instanceValue := vm.ToValue(instance).(*goja.Object)
 | 
			
		||||
		instanceValue.SetPrototype(call.This.Prototype())
 | 
			
		||||
		return instanceValue
 | 
			
		||||
		return defaultConstructor(vm, call, instance)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	vm.Set("SchemaField", func(call goja.ConstructorCall) *goja.Object {
 | 
			
		||||
		instance := &schema.SchemaField{}
 | 
			
		||||
		instanceValue := vm.ToValue(instance).(*goja.Object)
 | 
			
		||||
		instanceValue.SetPrototype(call.This.Prototype())
 | 
			
		||||
		return instanceValue
 | 
			
		||||
		return defaultConstructor(vm, call, instance)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	vm.Set("Dao", func(call goja.ConstructorCall) *goja.Object {
 | 
			
		||||
| 
						 | 
				
			
			@ -84,11 +89,25 @@ func baseBind(vm *goja.Runtime) {
 | 
			
		|||
		instance := daos.New(db)
 | 
			
		||||
		instanceValue := vm.ToValue(instance).(*goja.Object)
 | 
			
		||||
		instanceValue.SetPrototype(call.This.Prototype())
 | 
			
		||||
 | 
			
		||||
		return instanceValue
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbxBind(vm *goja.Runtime) {
 | 
			
		||||
func defaultConstructor(vm *goja.Runtime, call goja.ConstructorCall, instance any) *goja.Object {
 | 
			
		||||
	if data := call.Argument(0).Export(); data != nil {
 | 
			
		||||
		if raw, err := json.Marshal(data); err == nil {
 | 
			
		||||
			json.Unmarshal(raw, instance)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -141,27 +160,27 @@ func apisBind(vm *goja.Runtime) {
 | 
			
		|||
	obj.Set("enrichRecords", apis.EnrichRecords)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fieldMapper provides custom mapping between Go and JavaScript property names.
 | 
			
		||||
// FieldMapper provides custom mapping between Go and JavaScript property names.
 | 
			
		||||
//
 | 
			
		||||
// It is similar to the builtin "uncapFieldNameMapper" but also converts
 | 
			
		||||
// all uppercase identifiers to their lowercase equivalent (eg. "GET" -> "get").
 | 
			
		||||
type fieldMapper struct {
 | 
			
		||||
type FieldMapper struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FieldName implements the [FieldNameMapper.FieldName] interface method.
 | 
			
		||||
func (u fieldMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
 | 
			
		||||
func (u FieldMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
 | 
			
		||||
	return convertGoToJSName(f.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MethodName implements the [FieldNameMapper.MethodName] interface method.
 | 
			
		||||
func (u fieldMapper) MethodName(_ reflect.Type, m reflect.Method) string {
 | 
			
		||||
func (u FieldMapper) MethodName(_ reflect.Type, m reflect.Method) string {
 | 
			
		||||
	return convertGoToJSName(m.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertGoToJSName(name string) string {
 | 
			
		||||
	allUppercase := true
 | 
			
		||||
	for _, c := range name {
 | 
			
		||||
		if !unicode.IsUpper(c) {
 | 
			
		||||
		if c != '_' && !unicode.IsUpper(c) {
 | 
			
		||||
			allUppercase = false
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,268 @@
 | 
			
		|||
package jsvm_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/pocketbase/pocketbase/daos"
 | 
			
		||||
	"github.com/pocketbase/pocketbase/models"
 | 
			
		||||
	"github.com/pocketbase/pocketbase/models/schema"
 | 
			
		||||
	"github.com/pocketbase/pocketbase/plugins/jsvm"
 | 
			
		||||
	"github.com/pocketbase/pocketbase/tests"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestBaseVMUnmarshal(t *testing.T) {
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
 | 
			
		||||
	v, err := vm.RunString(`unmarshal({ name: "test" }, new Collection())`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m, ok := v.Export().(*models.Collection)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected models.Collection, got %v", m)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m.Name != "test" {
 | 
			
		||||
		t.Fatalf("Expected collection with name %q, got %q", "test", m.Name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBaseVMRecordBind(t *testing.T) {
 | 
			
		||||
	app, _ := tests.NewTestApp()
 | 
			
		||||
	defer app.Cleanup()
 | 
			
		||||
 | 
			
		||||
	collection, err := app.Dao().FindCollectionByNameOrId("users")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
	vm.Set("collection", collection)
 | 
			
		||||
 | 
			
		||||
	// without record data
 | 
			
		||||
	// ---
 | 
			
		||||
	v1, err := vm.RunString(`new Record(collection)`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m1, ok := v1.Export().(*models.Record)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected m1 to be models.Record, got \n%v", m1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// with record data
 | 
			
		||||
	// ---
 | 
			
		||||
	v2, err := vm.RunString(`new Record(collection, { email: "test@example.com" })`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m2, ok := v2.Export().(*models.Record)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected m2 to be models.Record, got \n%v", m2)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m2.Collection().Name != "users" {
 | 
			
		||||
		t.Fatalf("Expected record with collection %q, got \n%v", "users", m2.Collection())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m2.Email() != "test@example.com" {
 | 
			
		||||
		t.Fatalf("Expected record with email field set to %q, got \n%v", "test@example.com", m2)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// @todo enable after https://github.com/dop251/goja/issues/426
 | 
			
		||||
// func TestBaseVMRecordGetAndSetBind(t *testing.T) {
 | 
			
		||||
// 	app, _ := tests.NewTestApp()
 | 
			
		||||
// 	defer app.Cleanup()
 | 
			
		||||
 | 
			
		||||
// 	collection, err := app.Dao().FindCollectionByNameOrId("users")
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		t.Fatal(err)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	vm := jsvm.NewBaseVM()
 | 
			
		||||
// 	vm.Set("collection", collection)
 | 
			
		||||
// 	vm.Set("getRecord", func() *models.Record {
 | 
			
		||||
// 		return models.NewRecord(collection)
 | 
			
		||||
// 	})
 | 
			
		||||
 | 
			
		||||
// 	_, runErr := vm.RunString(`
 | 
			
		||||
// 		const jsRecord = new Record(collection);
 | 
			
		||||
// 		jsRecord.email = "test@example.com"; // test js record setter
 | 
			
		||||
// 		const email    = jsRecord.email; // test js record getter
 | 
			
		||||
 | 
			
		||||
// 		const goRecord = getRecord()
 | 
			
		||||
// 		goRecord.name  = "test" // test go record setter
 | 
			
		||||
// 		const name     = goRecord.name; // test go record getter
 | 
			
		||||
// 	`)
 | 
			
		||||
// 	if runErr != nil {
 | 
			
		||||
// 		t.Fatal(runErr)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	expectedEmail := "test@example.com"
 | 
			
		||||
// 	expectedName := "test"
 | 
			
		||||
 | 
			
		||||
// 	jsRecord, ok := vm.Get("jsRecord").Export().(*models.Record)
 | 
			
		||||
// 	if !ok {
 | 
			
		||||
// 		t.Fatalf("Failed to export jsRecord")
 | 
			
		||||
// 	}
 | 
			
		||||
// 	if v := jsRecord.Email(); v != expectedEmail {
 | 
			
		||||
// 		t.Fatalf("Expected the js created record to have email %q, got %q", expectedEmail, v)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	email := vm.Get("email").Export().(string)
 | 
			
		||||
// 	if email != expectedEmail {
 | 
			
		||||
// 		t.Fatalf("Expected exported email %q, got %q", expectedEmail, email)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	goRecord, ok := vm.Get("goRecord").Export().(*models.Record)
 | 
			
		||||
// 	if !ok {
 | 
			
		||||
// 		t.Fatalf("Failed to export goRecord")
 | 
			
		||||
// 	}
 | 
			
		||||
// 	if v := goRecord.GetString("name"); v != expectedName {
 | 
			
		||||
// 		t.Fatalf("Expected the go created record to have name %q, got %q", expectedName, v)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	name := vm.Get("name").Export().(string)
 | 
			
		||||
// 	if name != expectedName {
 | 
			
		||||
// 		t.Fatalf("Expected exported name %q, got %q", expectedName, name)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	// ensure that the two record instances are not mixed
 | 
			
		||||
// 	if v := goRecord.Email(); v != "" {
 | 
			
		||||
// 		t.Fatalf("Expected the go created record to not have an email, got %q", v)
 | 
			
		||||
// 	}
 | 
			
		||||
// 	if v := jsRecord.GetString("name"); v != "" {
 | 
			
		||||
// 		t.Fatalf("Expected the js created record to not have a name, got %q", v)
 | 
			
		||||
// 	}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func TestBaseVMCollectionBind(t *testing.T) {
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
 | 
			
		||||
	v, err := vm.RunString(`new Collection({ name: "test", schema: [{name: "title", "type": "text"}] })`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m, ok := v.Export().(*models.Collection)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected models.Collection, got %v", m)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m.Name != "test" {
 | 
			
		||||
		t.Fatalf("Expected collection with name %q, got %q", "test", m.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f := m.Schema.GetFieldByName("title"); f == nil {
 | 
			
		||||
		t.Fatalf("Expected schema to be set, got %v", m.Schema)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBaseVMAdminBind(t *testing.T) {
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
 | 
			
		||||
	v, err := vm.RunString(`new Admin({ email: "test@example.com" })`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m, ok := v.Export().(*models.Admin)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected models.Admin, got %v", m)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBaseVMSchemaBind(t *testing.T) {
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
 | 
			
		||||
	v, err := vm.RunString(`new Schema([{name: "title", "type": "text"}])`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m, ok := v.Export().(*schema.Schema)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected schema.Schema, got %v", m)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f := m.GetFieldByName("title"); f == nil {
 | 
			
		||||
		t.Fatalf("Expected schema fields to be loaded, got %v", m.Fields())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBaseVMSchemaFieldBind(t *testing.T) {
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
 | 
			
		||||
	v, err := vm.RunString(`new SchemaField({name: "title", "type": "text"})`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f, ok := v.Export().(*schema.SchemaField)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected schema.SchemaField, got %v", f)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.Name != "title" {
 | 
			
		||||
		t.Fatalf("Expected field %q, got %v", "title", f)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBaseVMDaoBind(t *testing.T) {
 | 
			
		||||
	app, _ := tests.NewTestApp()
 | 
			
		||||
	defer app.Cleanup()
 | 
			
		||||
 | 
			
		||||
	vm := jsvm.NewBaseVM()
 | 
			
		||||
	vm.Set("db", app.DB())
 | 
			
		||||
 | 
			
		||||
	v, err := vm.RunString(`new Dao(db)`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d, ok := v.Export().(*daos.Dao)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("Expected daos.Dao, got %v", d)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if d.DB() != app.DB() {
 | 
			
		||||
		t.Fatalf("The db instances doesn't match")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFieldMapper(t *testing.T) {
 | 
			
		||||
	mapper := jsvm.FieldMapper{}
 | 
			
		||||
 | 
			
		||||
	scenarios := []struct {
 | 
			
		||||
		name     string
 | 
			
		||||
		expected string
 | 
			
		||||
	}{
 | 
			
		||||
		{"", ""},
 | 
			
		||||
		{"test", "test"},
 | 
			
		||||
		{"Test", "test"},
 | 
			
		||||
		{"miXeD", "miXeD"},
 | 
			
		||||
		{"MiXeD", "miXeD"},
 | 
			
		||||
		{"ResolveRequestAsJSON", "resolveRequestAsJSON"},
 | 
			
		||||
		{"Variable_with_underscore", "variable_with_underscore"},
 | 
			
		||||
		{"ALLCAPS", "allcaps"},
 | 
			
		||||
		{"NOTALLCAPs", "nOTALLCAPs"},
 | 
			
		||||
		{"ALL_CAPS_WITH_UNDERSCORE", "all_caps_with_underscore"},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, s := range scenarios {
 | 
			
		||||
		field := reflect.StructField{Name: s.name}
 | 
			
		||||
		if v := mapper.FieldName(nil, field); v != s.expected {
 | 
			
		||||
			t.Fatalf("[%d] Expected FieldName %q, got %q", i, s.expected, v)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		method := reflect.Method{Name: s.name}
 | 
			
		||||
		if v := mapper.MethodName(nil, method); v != s.expected {
 | 
			
		||||
			t.Fatalf("[%d] Expected MethodName %q, got %q", i, s.expected, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -136,3 +136,19 @@ func (p *plugin) getCachedCollections() (map[string]*models.Collection, error) {
 | 
			
		|||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *plugin) hasCustomMigrations() bool {
 | 
			
		||||
	files, err := os.ReadDir(p.options.Dir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, f := range files {
 | 
			
		||||
		if f.IsDir() {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,6 +82,15 @@ func Register(app core.App, rootCmd *cobra.Command, options *Options) error {
 | 
			
		|||
		// when migrations are applied on server start
 | 
			
		||||
		p.app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
 | 
			
		||||
			p.refreshCachedCollections()
 | 
			
		||||
 | 
			
		||||
			cachedCollections, _ := p.getCachedCollections()
 | 
			
		||||
			// create a full initial snapshot, if there are no custom
 | 
			
		||||
			// migrations but there is already at least 1 collection created,
 | 
			
		||||
			// to ensure that the automigrate will work with up-to-date collections data
 | 
			
		||||
			if !p.hasCustomMigrations() && len(cachedCollections) > 1 {
 | 
			
		||||
				p.migrateCollectionsHandler(nil, false)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -114,11 +123,11 @@ func (p *plugin) createCommand() *cobra.Command {
 | 
			
		|||
 | 
			
		||||
			switch cmd {
 | 
			
		||||
			case "create":
 | 
			
		||||
				if err := p.migrateCreateHandler("", args[1:]); err != nil {
 | 
			
		||||
				if err := p.migrateCreateHandler("", args[1:], true); err != nil {
 | 
			
		||||
					log.Fatal(err)
 | 
			
		||||
				}
 | 
			
		||||
			case "collections":
 | 
			
		||||
				if err := p.migrateCollectionsHandler(args[1:]); err != nil {
 | 
			
		||||
				if err := p.migrateCollectionsHandler(args[1:], true); err != nil {
 | 
			
		||||
					log.Fatal(err)
 | 
			
		||||
				}
 | 
			
		||||
			default:
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +146,7 @@ func (p *plugin) createCommand() *cobra.Command {
 | 
			
		|||
	return command
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *plugin) migrateCreateHandler(template string, args []string) error {
 | 
			
		||||
func (p *plugin) migrateCreateHandler(template string, args []string, interactive bool) error {
 | 
			
		||||
	if len(args) < 1 {
 | 
			
		||||
		return fmt.Errorf("Missing migration file name")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +159,7 @@ func (p *plugin) migrateCreateHandler(template string, args []string) error {
 | 
			
		|||
		fmt.Sprintf("%d_%s.%s", time.Now().Unix(), inflector.Snakecase(name), p.options.TemplateLang),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if interactive {
 | 
			
		||||
		confirm := false
 | 
			
		||||
		prompt := &survey.Confirm{
 | 
			
		||||
			Message: fmt.Sprintf("Do you really want to create migration %q?", resultFilePath),
 | 
			
		||||
| 
						 | 
				
			
			@ -159,6 +169,7 @@ func (p *plugin) migrateCreateHandler(template string, args []string) error {
 | 
			
		|||
			fmt.Println("The command has been cancelled")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get default create template
 | 
			
		||||
	if template == "" {
 | 
			
		||||
| 
						 | 
				
			
			@ -183,11 +194,14 @@ func (p *plugin) migrateCreateHandler(template string, args []string) error {
 | 
			
		|||
		return fmt.Errorf("Failed to save migration file %q: %v\n", resultFilePath, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if interactive {
 | 
			
		||||
		fmt.Printf("Successfully created file %q\n", resultFilePath)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *plugin) migrateCollectionsHandler(args []string) error {
 | 
			
		||||
func (p *plugin) migrateCollectionsHandler(args []string, interactive bool) error {
 | 
			
		||||
	createArgs := []string{"collections_snapshot"}
 | 
			
		||||
	createArgs = append(createArgs, args...)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -207,5 +221,5 @@ func (p *plugin) migrateCollectionsHandler(args []string) error {
 | 
			
		|||
		return fmt.Errorf("Failed to resolve template: %v", templateErr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p.migrateCreateHandler(template, createArgs)
 | 
			
		||||
	return p.migrateCreateHandler(template, createArgs, interactive)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ func TestAutomigrateCollectionCreate(t *testing.T) {
 | 
			
		|||
			migratecmd.TemplateLangJS,
 | 
			
		||||
			`
 | 
			
		||||
migrate((db) => {
 | 
			
		||||
  const collection = unmarshal({
 | 
			
		||||
  const collection = new Collection({
 | 
			
		||||
    "id": "new_id",
 | 
			
		||||
    "created": "2022-01-01 00:00:00.000Z",
 | 
			
		||||
    "updated": "2022-01-01 00:00:00.000Z",
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ migrate((db) => {
 | 
			
		|||
      "onlyEmailDomains": null,
 | 
			
		||||
      "requireEmail": false
 | 
			
		||||
    }
 | 
			
		||||
  }, new Collection());
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return Dao(db).saveCollection(collection);
 | 
			
		||||
}, (db) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +193,7 @@ migrate((db) => {
 | 
			
		|||
 | 
			
		||||
  return dao.deleteCollection(collection);
 | 
			
		||||
}, (db) => {
 | 
			
		||||
  const collection = unmarshal({
 | 
			
		||||
  const collection = new Collection({
 | 
			
		||||
    "id": "test123",
 | 
			
		||||
    "created": "2022-01-01 00:00:00.000Z",
 | 
			
		||||
    "updated": "2022-01-01 00:00:00.000Z",
 | 
			
		||||
| 
						 | 
				
			
			@ -216,7 +216,7 @@ migrate((db) => {
 | 
			
		|||
      "onlyEmailDomains": null,
 | 
			
		||||
      "requireEmail": false
 | 
			
		||||
    }
 | 
			
		||||
  }, new Collection());
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return Dao(db).saveCollection(collection);
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -372,7 +372,7 @@ migrate((db) => {
 | 
			
		|||
  collection.schema.removeField("f3_id")
 | 
			
		||||
 | 
			
		||||
  // add
 | 
			
		||||
  collection.schema.addField(unmarshal({
 | 
			
		||||
  collection.schema.addField(new SchemaField({
 | 
			
		||||
    "system": false,
 | 
			
		||||
    "id": "f4_id",
 | 
			
		||||
    "name": "f4_name",
 | 
			
		||||
| 
						 | 
				
			
			@ -384,10 +384,10 @@ migrate((db) => {
 | 
			
		|||
      "max": null,
 | 
			
		||||
      "pattern": "` + "`" + `test backtick` + "`" + `123"
 | 
			
		||||
    }
 | 
			
		||||
  }, new SchemaField()))
 | 
			
		||||
  }))
 | 
			
		||||
 | 
			
		||||
  // update
 | 
			
		||||
  collection.schema.addField(unmarshal({
 | 
			
		||||
  collection.schema.addField(new SchemaField({
 | 
			
		||||
    "system": false,
 | 
			
		||||
    "id": "f2_id",
 | 
			
		||||
    "name": "f2_name_new",
 | 
			
		||||
| 
						 | 
				
			
			@ -398,7 +398,7 @@ migrate((db) => {
 | 
			
		|||
      "min": 10,
 | 
			
		||||
      "max": null
 | 
			
		||||
    }
 | 
			
		||||
  }, new SchemaField()))
 | 
			
		||||
  }))
 | 
			
		||||
 | 
			
		||||
  return dao.saveCollection(collection)
 | 
			
		||||
}, (db) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -421,7 +421,7 @@ migrate((db) => {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  // add
 | 
			
		||||
  collection.schema.addField(unmarshal({
 | 
			
		||||
  collection.schema.addField(new SchemaField({
 | 
			
		||||
    "system": false,
 | 
			
		||||
    "id": "f3_id",
 | 
			
		||||
    "name": "f3_name",
 | 
			
		||||
| 
						 | 
				
			
			@ -429,13 +429,13 @@ migrate((db) => {
 | 
			
		|||
    "required": false,
 | 
			
		||||
    "unique": false,
 | 
			
		||||
    "options": {}
 | 
			
		||||
  }, new SchemaField()))
 | 
			
		||||
  }))
 | 
			
		||||
 | 
			
		||||
  // remove
 | 
			
		||||
  collection.schema.removeField("f4_id")
 | 
			
		||||
 | 
			
		||||
  // update
 | 
			
		||||
  collection.schema.addField(unmarshal({
 | 
			
		||||
  collection.schema.addField(new SchemaField({
 | 
			
		||||
    "system": false,
 | 
			
		||||
    "id": "f2_id",
 | 
			
		||||
    "name": "f2_name",
 | 
			
		||||
| 
						 | 
				
			
			@ -446,7 +446,7 @@ migrate((db) => {
 | 
			
		|||
      "min": 10,
 | 
			
		||||
      "max": null
 | 
			
		||||
    }
 | 
			
		||||
  }, new SchemaField()))
 | 
			
		||||
  }))
 | 
			
		||||
 | 
			
		||||
  return dao.saveCollection(collection)
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,7 @@ func (p *plugin) jsSnapshotTemplate(collections []*models.Collection) (string, e
 | 
			
		|||
	const template = `migrate((db) => {
 | 
			
		||||
  const snapshot = %s;
 | 
			
		||||
 | 
			
		||||
  const collections = snapshot.map((item) => unmarshal(item, new Collection()));
 | 
			
		||||
  const collections = snapshot.map((item) => new Collection(item));
 | 
			
		||||
 | 
			
		||||
  return Dao(db).importCollections(collections, true, null);
 | 
			
		||||
}, (db) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +61,7 @@ func (p *plugin) jsCreateTemplate(collection *models.Collection) (string, error)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	const template = `migrate((db) => {
 | 
			
		||||
  const collection = unmarshal(%s, new Collection());
 | 
			
		||||
  const collection = new Collection(%s);
 | 
			
		||||
 | 
			
		||||
  return Dao(db).saveCollection(collection);
 | 
			
		||||
}, (db) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +87,7 @@ func (p *plugin) jsDeleteTemplate(collection *models.Collection) (string, error)
 | 
			
		|||
 | 
			
		||||
  return dao.deleteCollection(collection);
 | 
			
		||||
}, (db) => {
 | 
			
		||||
  const collection = unmarshal(%s, new Collection());
 | 
			
		||||
  const collection = new Collection(%s);
 | 
			
		||||
 | 
			
		||||
  return Dao(db).saveCollection(collection);
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -222,7 +222,7 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
 | 
			
		|||
		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))
 | 
			
		||||
		downParts = append(downParts, fmt.Sprintf("%s.schema.addField(new SchemaField(%s))\n", varName, rawOldField))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// created fields
 | 
			
		||||
| 
						 | 
				
			
			@ -237,7 +237,7 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		upParts = append(upParts, "// add")
 | 
			
		||||
		upParts = append(upParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawNewField))
 | 
			
		||||
		upParts = append(upParts, fmt.Sprintf("%s.schema.addField(new SchemaField(%s))\n", varName, rawNewField))
 | 
			
		||||
 | 
			
		||||
		downParts = append(downParts, "// remove")
 | 
			
		||||
		downParts = append(downParts, fmt.Sprintf("%s.schema.removeField(%q)\n", varName, newField.Id))
 | 
			
		||||
| 
						 | 
				
			
			@ -265,10 +265,10 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		upParts = append(upParts, "// update")
 | 
			
		||||
		upParts = append(upParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawNewField))
 | 
			
		||||
		upParts = append(upParts, fmt.Sprintf("%s.schema.addField(new SchemaField(%s))\n", varName, rawNewField))
 | 
			
		||||
 | 
			
		||||
		downParts = append(downParts, "// update")
 | 
			
		||||
		downParts = append(downParts, fmt.Sprintf("%s.schema.addField(unmarshal(%s, new SchemaField()))\n", varName, rawOldField))
 | 
			
		||||
		downParts = append(downParts, fmt.Sprintf("%s.schema.addField(new SchemaField(%s))\n", varName, rawOldField))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -----------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ func FindUploadedFiles(r *http.Request, key string) ([]*UploadedFile, error) {
 | 
			
		|||
		sanitizedName := inflector.Snakecase(originalName)
 | 
			
		||||
		if length := len(sanitizedName); length < 3 {
 | 
			
		||||
			// the name is too short so we concatenate an additional random part
 | 
			
		||||
			sanitizedName += ("_" + security.RandomString(10))
 | 
			
		||||
			sanitizedName += security.RandomString(10)
 | 
			
		||||
		} else if length > 100 {
 | 
			
		||||
			// keep only the first 100 characters (it is multibyte safe after Snakecase)
 | 
			
		||||
			sanitizedName = sanitizedName[:100]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ func TestFindUploadedFiles(t *testing.T) {
 | 
			
		|||
		filename        string
 | 
			
		||||
		expectedPattern string
 | 
			
		||||
	}{
 | 
			
		||||
		{"ab.png", `^ab_\w{10}_\w{10}\.png$`},
 | 
			
		||||
		{"ab.png", `^ab\w{10}_\w{10}\.png$`},
 | 
			
		||||
		{"test", `^test_\w{10}\.txt$`},
 | 
			
		||||
		{"a b c d!@$.j!@$pg", `^a_b_c_d_\w{10}\.jpg$`},
 | 
			
		||||
		{strings.Repeat("a", 150), `^a{100}_\w{10}\.txt$`},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue