Home > other >  How to edit only some fields in the database instead of all?
How to edit only some fields in the database instead of all?

Time:09-22

I have an application in go, and there is an endpoint for editing user information. But I found a problem, if in json it sees blank information (let's assume the user just wants to edit the name, and leaves the other fields blank), the data will be edited in the DB and the information that came blank will overwrite the information that are DB, even if the user didn't want to edit them.

How can I make only the fields that arrive in json to be effectively edited in the DB? Or is there a better way?

I'm looking forward to knowing!

My controller

func EditUser(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    userID, err := strconv.ParseUint(params["userID"], 10, 64)
    if err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }

    userIDInToken, err := auth.ExtractUserID(r)
    if err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }

    if userIDInToken != userID {
        returns.ERROR(w, http.StatusForbidden, errors.New("you can't update other user"))
        return
    }

    bodyRequest, err := ioutil.ReadAll(r.Body)
    if err != nil {
        returns.ERROR(w, http.StatusBadRequest, err)
        return
    }

    var user models.User

    if err := json.Unmarshal(bodyRequest, &user); err != nil {
        returns.ERROR(w, http.StatusUnprocessableEntity, err)
        return
    }

    db, err := db.ConnectToDB()
    if err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }
    defer db.Close()

    repository := repositories.NewUsersRepository(db)
    if err := repository.UpdateUserInfo(userID, user); err != nil {
        returns.ERROR(w, http.StatusInternalServerError, err)
        return
    }

    returns.JSON_RESPONSE(w, http.StatusOK, nil)

}

My repository (that access DB)

func (repository Users) UpdateUserInfo(userID uint64, user models.User) error {
    stmt, err := repository.db.Prepare(
        "UPDATE user SET name = ?, cpf = ?, email = ?, password = ?, city = ?, state = ? WHERE id = ?")
    if err != nil {
        return err
    }
    defer stmt.Close()

    if _, err := stmt.Exec(
        user.Name,
        user.CPF,
        user.Email,
        user.Password,
        user.City,
        user.State,
        userID,
    ); err != nil {
        return err
    }

    return nil
}

Model for user

type User struct {
    ID       uint64 `json:"id,omitempty"`
    Name     string `json:"name,omitempty"`
    CPF      string `json:"cpf,omitempty"`
    Email    string `json:"email,omitempty"`
    Password string `json:"password,omitempty"`
    City     string `json:"city,omitempty"`
    State    string `json:"state,omitempty"`
}

CodePudding user response:

I would dynamically construct the UPDATE statement as well as a slice of the fields that need to be edited by checking if the field is not empty before adding it to the slice.

Something like this:

func (repository Users) UpdateUserInfo(userID uint64, user User) error {
    fields := make([]string, 0)
    values := make([]string, 0)

    if user.Name != "" {
        values = append(values, user.Name)
        fields = append(fields, "name = ?")
    }
    if user.CPF != "" {
        values = append(values, user.CPF)
        fields = append(fields, "cpf = ?")
    }
    if user.Email != "" {
        values = append(values, user.Email)
        fields = append(fields, "email = ?")
    }
    if user.Password != "" {
        values = append(values, user.Password)
        fields = append(fields, "password = ?")
    }
    if user.City != "" {
        values = append(values, user.City)
        fields = append(fields, "city = ?")
    }
    if user.State != "" {
        values = append(values, user.State)
        fields = append(fields, "state = ?")
    }

    if len(fields) != 0 {
        return errors.New("no fields to update")
    }

    updateString := fmt.Sprintf("UPDATE user SET %s WHERE id = ?", strings.Join(fields, ","))
    stmt, err := repository.db.Prepare(updateString)
    if err != nil {
        return err
    }
    defer stmt.Close()

    if _, err := stmt.Exec(values...,userID); err != nil {
        return err
    }

    return nil
}

For cleaner code, I'd recommend maybe extracting the "if statements"/validation into a separate function.

  • Related