3

I have an existing mysql table, which uses mysql's UUID_SHORT() function to generate unique IDs. A simplified version of the table:

CREATE TABLE `users` (
  `user_uuid` bigint(20) unsigned NOT NULL,
  `user_name` varchar(64) NOT NULL
);

And a new user would be created via:

INSERT INTO users (user_uuid, user_name) values (UUID_SHORT(), "new user name");

I started to implement the DBs model using gorm and I'm drawing a blank on how to tell gorm and database/sql to call UUID_SHORT() when a new instance of User is created.

From model/users.go:

package model

type User struct {
    UserUUID          uint64     `gorm:"column:user_uuid;primary_key:yes";sql:"notnull;default:uuid_short"`
    UserName          string     `sql:"notnull"`
}

func (user User) TableName() string {
    return "users"
}

From model/users_test.go:

package model_test

import (
    "testing"

    ".../model"
    ".../model/testutil"
)

func TestUserCreate(t *testing.T) {
    user := model.User{
        // UserUUID: **HOW DO I CALL UUID_SHORT() HERE?**,
        UserName: "Go Test",
    }
    // testutil.DB is the successful result of gorm.Open("mysql", ...)
    testutil.DB.Create(&user)
}

How can I call UUID_SHORT() for the user_uuid column when the instance is saved?

1 Answer 1

3

In order to make a call to MySQL's UUID_SHORT() in your model.User call, it would seem that you'd need to make an additional SQL call to the database before reaching the testutil.DB.Create(&user) line at some point.

It might be nice to find a way to use gorm for the MySQL UUID_SHORT() call itself, but that might end up requiring more work just to map a single row value (user_uuid in this case) for use in your model.User (possibly requiring an additional struct just for UUID_SHORT()).

Therefore, using a simpler approach might help. The following code is a basic (though perhaps poor*) example of how UUID_SHORT() could be found using the sql package (specifically with the get_uuid_short() user-defined function, in this case):

package model_test

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    "github.com/stretchr/testify/assert"
    "log"
    "testing"
)

type User struct {
    UserUUID uint64 `gorm:"column:user_uuid;primary_key:yes";sql:"notnull;default:uuid_short"`
    UserName string `sql:"notnull"`
}

func (user User) TableName() string {
    return "users"
}

func get_uuid_short() uint64 {
    var uuid_short uint64

    /* connect to db using `sql` package */
    db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/uuid_test")
    if err != nil {
        log.Fatal(err)
    }

    /* select UUID_SHORT() */
    rows, err := db.Query("select UUID_SHORT()")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    /* get value of uuid_short */
    for rows.Next() {
        err := rows.Scan(&uuid_short)
        if err != nil {
            log.Fatal(err)
        }
    }

    return uuid_short
}

func TestUserCreate(t *testing.T) {
    user := User{
        UserUUID: get_uuid_short(),    /* get next UUID_SHORT() value */
        UserName: "Go Test",
    }
    db, err := gorm.Open("mysql", "username:password@/uuid_test?charset=utf8&parseTime=True&loc=Local")
    db.Create(&user)
    assert.Nil(t, err)
}

With results like this in the MySQL table:

mysql> select * from users;
+-------------------+-----------+
| user_uuid         | user_name |
+-------------------+-----------+
| 24070794506141712 | Go Test   |
| 24070794506141713 | Go Test   |
| 24070794506141714 | Go Test   |
+-------------------+-----------+
3 rows in set (0.00 sec)

*Note: This code might not address times where multiple users are concurrently calling get_uuid_short() (though MySQL may already provide a way to deal with this).

Sign up to request clarification or add additional context in comments.

2 Comments

I ended up doing something similar and had totally forgotten about this question. Thanks for taking the time to answer it after 1/2 a year :-)
@tobiash Glad to hear it worked out! (And there may still be a more efficient way to go about this type of thing...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.