Search code examples
gogo-gorm

How to return a newly created record back from the database using gorm


I have a function that creates a new user, however the reccomended way to get the values of the user does not include the autogenerated values created by the database (id, created_at)

type User struct {
    Id         string `json:"id" gorm:"primaryKey"`
    Email      string `json:"email"`
    Password   string `json:"password"`
    Created_At string `json:"created_at"`
    Updated_At string `json:"updated_at"`
    Deleted_At string `json:"deleted_at"`
}

type UserRequest struct {
    Email    string `json:"email"`
    Password string `json:"password"`
}

func CreateUserRepo(newUser UserRequest) (*User, error) {

    user := User{Email: newUser.Email, Password: newUser.Password}
    fmt.Println(user)
    result := services.PostgresSQLDB.Select("Email", "Password").Create(&user)
    fmt.Println(result.RowsAffected)

    if result.Error != nil {
        modules.Logger.Error(result.Error)
        return nil, result.Error
    }

    return &user, nil

}

You can see i get an empty string for both id and created_at although those values have been auto generated by my database.

{
    "id": "",
    "email": "[email protected]",
    "password": "password",
    "created_at": "",
    "updated_at": "",
    "deleted_at": ""
}

enter image description here

testing

To some extend i think this comes down to writing the "proper" types that gorm expects.

  1. It seems like Id will return the uuid if i add gorm.Model to my struct, but it also returns back a bunch of fields that seem like duplicates that i dont want (ID, CreatedAt, UpdatedAt, DeletedAt). Removing gorm.Model, Id no longer gives me back the uuid generated by postgres
    type User struct {
        gorm.Model
        Id        uuid.UUID      `json:"id"`
        Email     string         `json:"email"`
        Password  string         `json:"password"`
        CreatedAt time.Time      `json:"created_at"`
        UpdatedAt time.Time      `json:"updated_at"`
        DeletedAt gorm.DeletedAt `json:"deleted_at"`
    }
{
    "ID": 0,
    "CreatedAt": "0001-01-01T00:00:00Z",
    "UpdatedAt": "0001-01-01T00:00:00Z",
    "DeletedAt": null,
    "id": "b4dea226-3be2-4ee7-8548-67ccbbbcbcca",
    "email": "[email protected]",
    "password": "password",
    "created_at": "2022-06-25T20:59:27.872198797+01:00",
    "updated_at": "2022-06-25T20:59:27.872198797+01:00",
    "deleted_at": null
}

enter image description here

database postgres

-- CreateTable
CREATE TABLE "users" (
    "id" UUID NOT NULL DEFAULT gen_random_uuid(),
    "email" TEXT NOT NULL,
    "password" TEXT,
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMP(3) NOT NULL,
    "deleted_at" TIMESTAMP(3),

    CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);

Solution

  • I finally found the answer without comprising.

    Adding the default return clause, returns all the newly created values. https://gorm.io/docs/update.html#Returning-Data-From-Modified-Rows

    Clauses.(clause.Returning{})
    

    model.go

    type User struct {
        ID        uuid.UUID      `json:"id" gorm:"primaryKey:type:uuid"`
        Email     string         `json:"email"`
        Password  string         `json:"password"`
        CreatedAt time.Time      `json:"created_at"`
        UpdatedAt time.Time      `json:"updated_at"`
        DeletedAt gorm.DeletedAt `json:"deleted_at"`
    }
    

    repository.go

    func CreateUserRepo(newUser UserRequest) (*User, error) {
    
        hash, errHash := modules.HashPassword(newUser.Password)
    
        if errHash != nil {
            return nil, errHash
        }
    
        user := User{Email: newUser.Email, Password: *hash}
        result := services.PostgresSQLDB.Clauses(clause.Returning{}).Select("Email", "Password").Create(&user)
        fmt.Println(result.RowsAffected)
        fmt.Println(&user)
    
        if result.Error != nil {
            modules.Logger.Error(result.Error)
            return nil, result.Error
        }
    
        return &user, nil
    
    }
    

    thanks to @TheFool comment for this find.