Skip to content

LaysDragon/go-bson-migrator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BSON Migrator

For example please see here

Definition

The whole idea is base on a Migrator which will auto call the registered func to complete the transformer progress for need.

package model

type User struct {
	Home                 string
	AddressButNotTHeSame string
	ANotherGender        string
	Age                  int
}

//for global usage latest version for this struct
var UserCurrentVersion = loader.NewVersionPanic("0.3")
//for global usage latest version struct for this struct
type UserCurrent = User_0_3

//v0.1 struct
type User_0_1 struct {
	Home    string
	Address string
	Gender  string
}

//v0.2 struct
type User_0_2 struct {
	Home     string
	XAddress string
	XGender  string
	Age      int
}

//v0.3 struct
type User_0_3 User

}

For auto migration from old version to new version struct with this migrator,you need to create a Registry with loader and transformer.

package model
import loader "github.com/LaysDragon/bson-migrator"

//v0.1 loader
func User_0_3_Loader(src []byte, dst loader.VersionWrapper) error {
	dst.SetData(User_0_3{})//as custom loader,you need to set your data struct into wrapper for it to Unmarshal 

	if err := bson.Unmarshal(src, dst); err != nil {
		return err
	}
	return nil
}

//
func User_0_1_to_0_2_Transformer(container loader.VersionWrapper) error {
	if user_0_1, ok := container.GetData().(User_0_1); ok {
		user_0_2 := User_0_2{
			Home:     user_0_1.Home,
			XAddress: user_0_1.Address,
			XGender:  user_0_1.Address,
			Age:      0,
		}
		container.SetData(user_0_2)
		container.SetVersion(loader.NewVersionPanic("0.2"))
		return nil
	}
	return xerrors.Errorf("Cannot cast %T to %T:%w", container, User_0_1{}, loader.TransformerSrcTypeIncorrectError)

}

func User_0_2_to_0_3_Transformer(container loader.VersionWrapper) error {
	if user_0_2, ok := container.GetData().(User_0_2); ok {
		user_0_3 := User_0_3{
			Home:                 user_0_2.Home + "03version",
			AddressButNotTHeSame: user_0_2.XAddress + "new address format",
			ANotherGender:        user_0_2.XGender + "i am dragon",
			Age:                  user_0_2.Age + 25,
		}
		container.SetData(user_0_3)
		container.SetVersion(loader.NewVersionPanic("0.3"))
		return nil
	}
	return xerrors.Errorf("Cannot cast %T to %T:%w", container, User_0_2{}, loader.TransformerSrcTypeIncorrectError)

}

var UserLoadersRegistry = loader.NewRegistry(
	loader.SLoaders{//Loaders set version with responsible loader func
		"0.1": User_0_1{},//simply give a zero value struct,it will use default loader
   	    "0.2": loader.DefaultLoader(User_0_2{}) ,//same as above
	    "0.1": User_0_3_Loader,//use custom loader
	},
	loader.STransformers{//Transformer set with source version to target version with responsible transformer func
		"0.1": loader.STargetTransformers{
			"0.2": User_0_1_to_0_2_Transformer,
			...
		},
		"0.2": loader.STargetTransformers{
			"0.3": User_0_2_to_0_3_Transformer,
		},
	},
)

Usage

package model

func (s User) MarshalBSON() ([]byte, error) {
	//use versionCapture to wrapper before Marshal can add version inline field into bson data
	return bson.Marshal(loader.VersionCapture{Version: UserCurrentVersion, Data: s})
}

func (s *User) UnmarshalBSON(src []byte) error {
    //use registry Load method,it will load src byte into VersionWrapper with the specified struct you registered
	versionUser, err := UserLoadersRegistry.Load(src, UserCurrentVersion)
	if err != nil {
		return err
	}
    //extract it and cast back to current version
	*s = User(versionUser.GetData().(UserCurrent))
	return nil
}
package main
import "go.mongodb.org/mongo-driver/bson"

func main(){
var bsonByte := ...//from mongodb go driver or something else
user:= User{}
bson.Unmarshal(bsonByte,&user)

}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages