3
\$\begingroup\$

Newbie here. I have this gqlgen api with sqlc update code, which updates the user by given id with provided fields:

// graph/schema.resolvers.go

...

func (r *mutationResolver) UserUpdate(ctx context.Context, id string, input model.EditUser) (bool, error) {
    // Validate
    v := validator.New()
    if err := v.Struct(input); err != nil {
        for _, err := range err.(validator.ValidationErrors) {
            fmt.Println(err)
        }
        return false, errors.New(err.Error())
    }
    pg := db.ConnectPg()
    defer pg.Close()
    // Parse string id to int64
    parsedId, _ := strconv.ParseInt(id, 10, 64)
    u := db.User{}
    var err error
    // GetUserById is generated by sqlc
    if u, err = db.NewPg(pg).GetUserById(ctx, parsedId); err != nil {
        return false, err
    }
    // Confirm ownership or admin
    user := auth.ForContext(ctx)
    if user != nil || user.ID == parsedId || user.IsAdmin {
        if input.EmailVerified != nil {
            u.EmailVerified = *input.EmailVerified
        }
        if input.MobileVerified != nil {
            u.MobileVerified = *input.MobileVerified
        }
        if input.IsActive != nil {
            u.IsActive = *input.IsActive
        }
        if input.Name != nil {
            u.Name = sql.NullString{String: *input.Name, Valid: true}
        }
        if input.Avatar != nil {
            u.Name = sql.NullString{String: *input.Avatar, Valid: true}
        }
        if input.Email != nil {
            u.Email = sql.NullString{String: *input.Email, Valid: true}
        }
        if input.Mobile != nil {
            u.Mobile = sql.NullString{String: *input.Mobile, Valid: true}
        }
        if input.Password != nil {
            bytes, _ := bcrypt.GenerateFromPassword([]byte(*input.Password), 14)
            hashedPassword := string(bytes)
            u.Password = hashedPassword
        }
        if input.IsAdmin != nil {
            if user.IsAdmin {
                u.IsAdmin = *input.IsAdmin
            } else {
                return false, fmt.Errorf("Access denied")
            }
        }
        // UpdateUser and UpdateUserParams are generated by sqlc
        if _, err := db.NewPg(pg).UpdateUser(ctx, db.UpdateUserParams{
            ID:             u.ID,
            Name:           u.Name,
            Avatar:         u.Avatar,
            Email:          u.Email,
            EmailVerified:  u.EmailVerified,
            Mobile:         u.Mobile,
            MobileVerified: u.MobileVerified,
            Password:       u.Password,
            IsAdmin:        u.IsAdmin,
            IsActive:       u.IsActive,
            UpdatedAt:      time.Now(),
        }); err != nil {
            return false, err
        }
        return true, nil
    }
    return false, fmt.Errorf("Access denied")
}

...

And it is working correctly. However coming from Node land, I feel like it is too verbose. Or is this just how Golang does it? What if I have like more than 10 columns, do I have to check nil for each of them?

I tried searching some Golang tutorials but couldn't find much out there like Node. How would an experienced Gopher write this code in neat?


Other information you may need.

This is EditUser struct "generated" by gqlgen but can be edited:

// graph/models/user.go

type EditUser struct {
    Name           *string `json:"name,omitempty" validate:"omitempty,max=100"`
    Avatar         *string `json:"avatar,omitempty"`
    Email          *string `json:"email,omitempty" validate:"omitempty,email"`
    EmailVerified  *bool   `json:"emailVerified,omitempty"`
    Mobile         *string `json:"mobile,omitempty" validate:"omitempty,min=2,max=55"`
    MobileVerified *bool   `json:"mobileVerified,omitempty"`
    Password       *string `json:"password,omitempty"`
    IsAdmin        *bool   `json:"is_admin,omitempty"`
    IsActive       *bool   `json:"isActive,omitempty"`
}

This is User struct "generated" by sqlc:

// db/models.go
// Code generated by sqlc. DO NOT EDIT.

package db

type User struct {
    ID             int64          `json:"id"`
    Name           sql.NullString `json:"name"`
    Avatar         sql.NullString `json:"avatar"`
    Email          sql.NullString `json:"email"`
    EmailVerified  bool           `json:"email_verified"`
    Mobile         sql.NullString `json:"mobile"`
    MobileVerified bool           `json:"mobile_verified"`
    // is required
    Password   string         `json:"password"`
    IsAdmin    bool           `json:"is_admin"`
    IsActive   bool           `json:"is_active"`
    CreatedAt  time.Time      `json:"created_at"`
    UpdatedAt  time.Time      `json:"updated_at"`
    LastSignin sql.NullTime   `json:"last_signin"`
}

This is UpdateUserParams "genearted" by sqlc:

// db/user.sql.go
// Code generated by sqlc. DO NOT EDIT.
// source: user.sql

type UpdateUserParams struct {
    ID             int64          `json:"id"`
    Name           sql.NullString `json:"name"`
    Avatar         sql.NullString `json:"avatar"`
    Email          sql.NullString `json:"email"`
    EmailVerified  bool           `json:"email_verified"`
    Mobile         sql.NullString `json:"mobile"`
    MobileVerified bool           `json:"mobile_verified"`
    Password       string         `json:"password"`
    IsAdmin        bool           `json:"is_admin"`
    IsActive       bool           `json:"is_active"`
    UpdatedAt      time.Time      `json:"updated_at"`
}

go (v1.15), sqlc (v1.5.0), gqlgen (v0.13.0)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ The current question title of your question is too generic to be helpful. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?. \$\endgroup\$ Commented Oct 7, 2020 at 14:15
  • \$\begingroup\$ if input.Avatar != nil { u.Name = sql.NullString{… I hope you have unit tests in place. And yes, this is not the way to code this, me not knowing how to in Go notwithstanding. \$\endgroup\$ Commented May 11, 2022 at 12:21

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.