Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating Table Overrides null values in struct #62

Open
tonespy opened this issue May 1, 2018 · 1 comment
Open

Updating Table Overrides null values in struct #62

tonespy opened this issue May 1, 2018 · 1 comment

Comments

@tonespy
Copy link

tonespy commented May 1, 2018

Hi.

I am developer transitioning from Node.js to go and it has been smooth. But, I'm finding it hard to update a model without overwriting the role in the db with the null data. Example:

I've a User Struct:

// User represents a user's record
type User struct {
	ID            int       `json:"id" db:"pk,id"`
	Firstname     string    `json:"firstname" db:"firstname"`
	Lastname      string    `json:"lastname" db:"lastname"`
	Email         string    `json:"email" db:"email"`
	IsDeleted     bool      `json:"isDeleted" db:"isDeleted"`
	Password      string    `json:"-" db:"password"`
	Country       string    `json:"country" db:"country"`
	State         string    `json:"state" db:"state"`
	FacebookToken *string   `json:"fbToken" db:"fbToken"`
	TwitterToken  *string   `json:"twitterToken" db:"twitterToken"`
	CreatedAt     time.Time `json:"createdAt" db:"createdAt"`
	UpdatedAt     time.Time `json:"updatedAt" db:"updatedAt"`
}

// Validate helps with validating the user field
func (u User) Validate() error {
	return validation.ValidateStruct(&u,
		validation.Field(&u.Firstname, validation.Required, validation.Length(0, 120)),
		validation.Field(&u.Lastname, validation.Required, validation.Length(0, 120)),
		validation.Field(&u.Password, validation.Required, validation.Length(8, 120), is.Alphanumeric),
		validation.Field(&u.Email, validation.Required, is.Email),
		validation.Field(&u.Country, validation.Required),
		validation.Field(&u.State, validation.Required),
	)
}

// IsPassValid - Verify if password is valid
func (u User) IsPassValid(pass string) error {
	return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(pass))
}

// GenerateHash - Helper function to help generate password hash. It returns error if hasing fails, and user if successful.
func (u *User) GenerateHash() error {
	bytes, err := bcrypt.GenerateFromPassword([]byte(u.Password), 14)
	u.Password = string(bytes)
	return err
}

// TableName - Utilized by ozzo-dbx for referencing main table name
func (u User) TableName() string {
	return "users"
}

So, to create a user, I did:

func userManipulation(db *dbx.DB) {
	user := User{
		Firstname: randomdata.FirstName(randomdata.Male),
		Lastname:  randomdata.LastName(),
		Email:     randomdata.Email(),
		Password:  "password",
		Country:   randomdata.Country(randomdata.FullCountry),
		State:     randomdata.State(randomdata.Large),
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}

	if err := user.Validate(); err != nil {
		panic(err)
	}

	if err := user.GenerateHash(); err != nil {
		panic(err)
	}

	if err := db.Model(&user).Insert(); err != nil {
		// panic(err)
		processErr(err)
	}
  fmt.Println(user)
}

And this gives me:

{
  "id": 2,
  "firstname": "William",
  "lastname": "White",
  "email": "[email protected]",
  "isDeleted": false,
  "country": "Rwanda",
  "state": "Missouri",
  "fbToken": null,
  "twitterToken": null,
  "createdAt": "2018-05-01T11:21:18.080069+01:00",
  "updatedAt": "2018-05-01T11:21:18.08007+01:00"
}

But, whenever I try to update just a specific field, such as in this case:

func userUpdateManipulation(db *dbx.DB) {
	user := User{
		ID:        1,
		Firstname: randomdata.FirstName(randomdata.Female),
		UpdatedAt: time.Now(),
	}

	if err := db.Model(&user).Update(); err != nil {
		panic(err)
	}

	byte, err := json.Marshal(user)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(byte))
}

The data I didn't add are overwritten. How can I update without hardcoding which fields needs to be updated.

{
  "id": 2,
  "firstname": "Addison",
  "lastname": "",
  "email": "",
  "isDeleted": false,
  "country": "",
  "state": "",
  "fbToken": null,
  "twitterToken": null,
  "createdAt": "0001-01-01T00:00:00Z",
  "updatedAt": "2018-05-01T11:38:52.036203+01:00"
}

This is what I had to do to fix that. If you think there is a better way, please, do let me know:

// ExcludeData - Parameters to exclude while updating
func (u User) ExcludeData() []string {
	mainExlude := []string{}
	if len(u.Firstname) <= 0 { mainExlude = append(mainExlude, "Firstname") }
	if len(u.Lastname) <= 0 { mainExlude = append(mainExlude, "Lastname") }
	if len(u.Email) <= 0 { mainExlude = append(mainExlude, "Email") }
	if len(u.Password) <= 0 { mainExlude = append(mainExlude, "Password") }
	if len(u.Country) <= 0 { mainExlude = append(mainExlude, "Country") }
	if len(u.State) <= 0 { mainExlude = append(mainExlude, "Country") }
	if u.FacebookToken == nil { mainExlude = append(mainExlude, "FacebookToken") }
	if u.TwitterToken == nil { mainExlude = append(mainExlude, "TwitterToken") }
	if time.Time.IsZero(u.CreatedAt) { mainExlude = append(mainExlude, "CreatedAt") }
	if time.Time.IsZero(u.UpdatedAt) { mainExlude = append(mainExlude, "UpdatedAt") }
	mainExlude = append(mainExlude, "IsDeleted")
	return mainExlude
}

What would you suggest I do to get this done. Thanks

@kPshi
Copy link

kPshi commented Jul 24, 2018

The update works as a crud operation so it updates all the data available in the object. To update only specific fields you would have to define them as described in https://github.com/go-ozzo/ozzo-dbx/blob/master/README.md#building-data-manipulation-queries .
Alternatively load the data into a struct, update the fields there and write it all back using a common update ()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants