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

Time:06-30

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")
);

CodePudding user response:

The .Select("Email", "Password") statement you added is restricting the return value to only those 2 fields. If you remove it, it should work fine.

CodePudding user response:

As far as I know, GORM doesn't support anything else that integer auto increment for the primary key. So either you keep that on PostgreSQL side (like you did) or you generate your own UUID in Go before creating the object (with BeforeCreate hook).

Also, the gorm.Model definition is the following:

type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

You don't have to use it, but if you don't, add gorm:"primaryKey" to your primary key field. By default primary field have auto increment, for your case, I would recommend to disable it with autoIncrement:false.

type User struct {
    Id        uuid.UUID      `gorm:"primaryKey;autoIncrement:false" json:"id"`
    Email     string         `json:"email"`
    Password  string         `json:"password"`
}

As you let PostgreSQL handle default value (and not GORM), you have to query again the object in order to access your id UUID and created_at TIMESTAMP.

Also note that you can use GormValuerInterface to use an SQL Expr on creation. But you will still have to query again your record. (https://gorm.io/docs/data_types.html#GormValuerInterface)

In case you are interested to handle all on Go side, here an example with and without gorm.Model.

package main

import (
    "fmt"
    "time"

    "github.com/google/uuid"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

var DB *gorm.DB

type User struct {
    UUID      uuid.UUID `gorm:"primaryKey;autoIncrement:false"`
    Name      string
    CreatedAt time.Time
}

type UserWithGormModel struct {
    gorm.Model
    UUID uuid.UUID `gorm:"primaryKey;autoIncrement:false"`
    Name string
}

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {

    // This is an example, refer to https://pkg.go.dev/github.com/google/UUID for good usage
    u.UUID = uuid.New()

    u.CreatedAt = time.Now()

    return
}

func (u *UserWithGormModel) BeforeCreate(tx *gorm.DB) (err error) {

    // This is an example, refer to https://pkg.go.dev/github.com/google/UUID for good usage
    u.UUID = uuid.New()

    return
}

func ConnectDatabase() {

    database, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    if err != nil {
        panic("Failed to connect to database!")
    }

    database.AutoMigrate(&User{}, &UserWithGormModel{})

    DB = database
}

func main() {
    ConnectDatabase()

    user := User{Name: "Bob"}
    DB.Create(&user)
    fmt.Printf("User{UUID: %s, User.Name: %s, CreatedAt: %s}\n", user.UUID, user.Name, user.CreatedAt)

    user2 := UserWithGormModel{Name: "John"}
    DB.Create(&user2)
    fmt.Printf("UserWithGormModel{UUID: %s, Name: %s, CreatedAt: %s}\n", user2.UUID, user2.Name, user2.CreatedAt)
}

Output:

User{UUID: 8551636a-540f-4733-8179-3f0cc45daf4f, User.Name: Bob, CreatedAt: 2022-06-28 11:40:10.9225724  0200 CEST}
UserWithGormModel{UUID: 2a6f94bd-a42b-4316-90be-0e93ea5091a6, Name: John, CreatedAt: 2022-06-28 11:40:10.9318004  0200 CEST}
  • Related