I am working on a REST API. At the moment I’ve been creating a PATCH endpoint to update user information such as their username, birthday, etc. I’ve been stuck for a couple days trying to make updating the information work with my Postgres database.
I am using Bun ORM https://bun.uptrace.dev/guide/query-update.html to interact with the database. The issues I’ve been having stem from this code snippet below:
/* Database Model */
type User struct {
Id uuid.UUID `json:"id,omitempty" bun:"column:pk,type:uuid,default:gen_random_uuid()"`
Email string `json:"email,omitempty"`
Name string `json:"name,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"-" dbKey:"password"`
Verified bool `json:"verified,omitempty"`
EmailVerified bool `json:"emailVerified,omitempty"`
Avatar *string `json:"avatar,omitempty"`
GraduationYear int `json:"graduationYear,omitempty"`
Degree *string `json:"degree,omitempty"`
Major *string `json:"major,omitempty"`
Intrests int `json:"intrests,omitempty"`
Clubs int `json:"clubs,omitempty"`
Sports int `json:"sports,omitempty"`
NotificationId string `json:"notificationId,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty" bun:"type:timestamp,default:now()"`
UpdatedAt time.Time `json:"updatedAt,omitempty" bun:"type:timestamp,default:now()"`
}
func (r *userRepositoryImpl) UpdateUser(userId string, data models.User) (*models.User, error) {
user := models.User(data)
_, err := r.db.NewUpdate().Model(&user).Where("id = ?", userId).Returning("*").Exec(r.context)
if err != nil {
return nil, err
}
return &user, nil
}
This function is meant to update the user depending on what data I give the User struct. However, if I want to update only ONE of the fields, it sets all of the columns in my Postgres database to their default or zero value. Example:
/* This resets all other column values to their default or zero value, just affecting the avatar column */
updatedUser, err := s.userRepository.UpdateUser(userId, models.User{
Avatar: &avatarUrl,
})
I later came across this method in Bun ORM: Omit Zero Values. This allowed me to update the avatar column only, and the ORM ignored the empty fields in the struct. But then I cannot reset the avatar column back to an empty string, cause it will be ignored.
I have tried several things, most likely really over-engineered. I even tried reflection since I got desperate.
- Tried converting the User struct fields that weren’t empty to a
map[string]interface{}
, and passing that to theModel
method. Unfortunately the ORM did not convert my types to how they were defined in my User struct since I used a map. - I tried merging the old struct with a struct containing the data I wanted to update, which worked at first but was extremely hacky and I wouldn’t prefer to use that as a solution.
- I tried using pointer values like
*string
to represent null values, but just got the same result as I described at the beginning of my post.
I would really appreciate some guidance and help with this, part of me feels like I’m over thinking it, and I would like to hear others thoughts. If extra clarification is needed, Ill edit this post as necessary.