How do you do UUID in Golangs Gorm?
Asked Answered
C

8

31

I have the following model...

type User struct {
    ID        string  `sql:"type:uuid;primary_key;default:uuid_generate_v4()"`
    FirstName string `form:"first_name" json:"first_name,omitempty"`
    LastName  string `form:"last_name" json:"last_name,omitempty"`
    Password  string `form:"password" json:"password" bindind:"required"`
    Email     string `gorm:"type:varchar(110);unique_index" form:"email" json:"email,omitempty" binding:"required"`
    Location  string `form:"location" json:"location,omitempty"`
    Avatar    string `form:"avatar" json:"avatar,omitempty"`
    BgImg     string `form:"bg_img" json:"bg_img,omitempty"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt time.Time
}

I've tried several different ways, but this way throws (pq: relation "users" does not exist). I have no related models, it's literally just that one model.

I've tried using...

func (user *User) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", uuid.NewV4())
    return nil
}

Along with a uuid lib, but had no luck with that either.

Chak answered 7/4, 2016 at 20:26 Comment(2)
That seems that your users table is not exist on the database. Have you automigrate it?Expiate
Are there better methods in the meantime?Amato
S
25

For postgresql, here is what I did:

  • go get github.com/google/uuid
  • Use uuid.UUID (from "github.com/google/uuid"), as type,
    e.g
    ID       uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()"`
  • Add uuid-ossp extension for postgres database,
    e.g
    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
  • Then, when you call DB's Create() method, the uuid is generated automatically.

Update: pg14+ gen_random_uuid()

(as mentioned in Doron Segal's comment)

pg 14 has built-in function gen_random_uuid() to generate uuid v4, e.g:

create table:

create table uuid_test (uid text default gen_random_uuid());

insert a row:

insert into uuid_test(uid) values (DEFAULT);

Then uid column is generated automatically.


Similiar, in go you can use the function as defaul value I think, e.g:

ID uuid.UUID gorm:"type:uuid;default:gen_random_uuid()"


BTW, the gen_random_uuid() function only support uuid v4 now, to use other versions, you still need uuid-ossp extension.

Shakiashaking answered 27/7, 2021 at 4:37 Comment(1)
You don't need to use any extension if you're using Postgresql version > 14. just use gen_random_uuid()Galliard
C
13

Turns out I was trying to store the UUID as the wrong type, I was doing...

func (user *User) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", uuid.NewV4())
    return nil
}

When it needed to be...

func (user *User) BeforeCreate(scope *gorm.Scope) error {
    scope.SetColumn("ID", uuid.NewV4().String())
    return nil
}
Chak answered 10/4, 2016 at 17:36 Comment(1)
You should usereturn scope.SetColumn("ID", uuid.NewV4().String()) instead of ignoring the result for SetColumnIllsorted
M
8

This was my solution for Gorm v1.21

go get gorm.io/gorm
go get gorm.io/driver/postgres
go get github.com/google/uuid
import (
  "gorm.io/gorm"
  "github.com/google/uuid"
)

type User struct {
  Id string `gorm:"primaryKey"`
}

// Note: Gorm will fail if the function signature
//  does not include `*gorm.DB` and `error`

func (user *User) BeforeCreate(tx *gorm.DB) (err error) {
  // UUID version 4
  user.Id = uuid.NewString()
  return
}

Notes:

  1. For the Google UUID package, the methods uuid.New() and uuid.NewString() use UUID version 4. This is not clearly stated in the documentation (http://pkg.go.dev/github.com/google/uuid), but by looking into the source code, you can see that these are wrappers around uuid.NewRandom() which is stated as being UUID version 4.

  2. While some recommend the Satori UUID package (https://github.com/satori/go.uuid), benchmarks show that it has 3.3x lower performance than the Google UUID package (https://gist.github.com/mattes/69a4ab7027b9e8ee952b5843e7ca6955)

Madrigal answered 13/7, 2021 at 23:35 Comment(5)
It should be uuid.New() which works. Please update your answer.Muskrat
@Muskrat To my understanding uuid.New() returns a 16-byte array, and not a string. If you have a convincing argument as to why using uuid.New() is better than uuid.NewString(), then I'm happy to update the example code. As I see it, uuid.NewString() is better because strings are readable, and well supported across different databases.Madrigal
Umm, ok. From what I tried NewString() is not a method at all on uuidMuskrat
@Muskrat NewString was added in v1.2.0 (pkg.go.dev/github.com/google/uuid#NewString). Does updating the package with go get -u github.com/google/uuid include the method?Madrigal
Right, I thought I had latest package since I just worked on it. I am on 1.0.0 as it turns out. Will check for latest releaseMuskrat
B
6

For this you will need gorm and go.uuid

go get github.com/jinzhu/gorm

go get github.com/satori/go.uuid

Try creating your own model base model in place of gorm.Model like so:

type Base struct {
 ID         string     `sql:"type:uuid;primary_key;default:uuid_generate_v4()"`
 CreatedAt  time.Time  `json:"created_at"`
 UpdatedAt  time.Time  `json:"updated_at"`
 DeletedAt  *time.Time `sql:"index" json:"deleted_at"`
}

You would then populate this field using a method called before creation of any record, like so:

func (base *Base) BeforeCreate(scope *gorm.Scope) error {
 id, err := uuid.NewV4()
 if err != nil {
   return err
 }
 return scope.SetColumn("ID", uuid.String())
}

Therefore, for your particular case, you would have:

type User struct {
    Base
    FirstName string `form:"first_name" json:"first_name,omitempty"`
    LastName  string `form:"last_name" json:"last_name,omitempty"`
    Password  string `form:"password" json:"password" bindind:"required"`
    Email     string `gorm:"type:varchar(110);unique_index" form:"email" json:"email,omitempty" binding:"required"`
    Location  string `form:"location" json:"location,omitempty"`
    Avatar    string `form:"avatar" json:"avatar,omitempty"`
    BgImg     string `form:"bg_img" json:"bg_img,omitempty"`
}

More details on this can be found here

Behnken answered 9/7, 2019 at 5:20 Comment(4)
Wouldn't default:uuid_generate_v4() automatically generate an UUID for us?Gardenia
This certainly returns an error uuid, err := uuid.NewV4().String()Colligan
Put the .String() in this line return scope.SetColumn("ID", uuid.String())Holzer
This worked at the time of writing. I haven't followed up on it, nor I actively use Go in my current capacity, but I will make the requested changes.Behnken
F
2

The error (pq: relation "users" does not exist) usually means that, the table users does not exists in the database. It has nothing to do with the relationship between two models.

So basically, You first need to create the table in the database (Or auto migrate the database As per @Apin suggest). And try to re-run the same code.

Faucal answered 8/4, 2016 at 1:51 Comment(0)
M
0

None of these worked for me using gorm v1.21. Here was my solution. Note that I'm using the satori/go.uuid library for generating UUID, but code with google's library is near identical.

type UUIDBaseModel struct {
    ID        uuid.UUID       `gorm:"primary_key" json:"id"`
    CreatedAt time.Time  `json:"created_at"`
    UpdatedAt time.Time  `json:"updated_at"`
    DeletedAt *time.Time `sql:"index" json:"deleted_at"`
}

func (base *UUIDBaseModel) BeforeCreate(tx *gorm.DB) error {
    uuid := uuid.NewV4().String()
    tx.Statement.SetColumn("ID", uuid)
    return nil
}
Montero answered 12/10, 2021 at 6:34 Comment(0)
C
0

Now I used Gorm 2.0 and this worked:

go get github.com/satori/go.uuid 
type Tablename struct {
 ID         string     `sql:"type:uuid;primary_key;default:uuid_generate_v4()"`
 }
Cornflower answered 5/8, 2022 at 3:24 Comment(0)
S
0

With MySQL 8.0 and gorm (gorm.io/driver/mysql v1.5.0 and gorm.io/gorm v1.25.1):

type ModelUUID struct {
    ID        string         `gorm:"type:binary(16);column:id;primaryKey;default:(UUID_TO_BIN(UUID(), 1));" json:"id" validate:"required"`
    CreatedAt time.Time      `json:"createdAt"`
    UpdatedAt time.Time      `json:"-"`
    DeletedAt gorm.DeletedAt `json:"-" gorm:"index" swaggerignore:"true"`
}
Stillhunt answered 26/5, 2023 at 14:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.