Integrating GORM with Revel and mysql

In one of my earlier post, I showed how we could integrate Gorp with Revel. Since, Gorp does not support relations between tables, I decided to give a look at Gorm. Gorm seems to support relations between tables.

Another thing I really liked about GORM was ability to specify constraints in struct itself.

To begin, lets start by installing GORM

go get -u github.com/jinzhu/gorm

Now, lets update the user struct, and specify constraints

type User struct {
	Id               int64
	Email            string `sql:"size:255; not null; unique"`
	FirstName        string `sql:"size:30"`
	LastName         string `sql:"size:30"`
	Password         string `sql:"size:255"`
	IsEnabled        bool `sql:"default:true"`
        ConfirmPassword string `sql:"-"`
}

Here ConfirmPassword is specified as a transient field.

Now lets say user has a Twitter account, So we created a new TwitterAccount struct

type TwitterAccount struct {
  Id int64
}

Now, since this twitter account is linked to user, we need to update the user as

type User struct {
	Id               int64
	Email            string `sql:"size:255; not null; unique"`
	FirstName        string `sql:"size:30"`
	LastName         string `sql:"size:30"`
	Password         string `sql:"size:255"`
	IsEnabled        bool `sql:"default:true"`
        ConfirmPassword string `sql:"-"`

        TwitterAccount   TwitterAccount
	TwitterAccountId sql.NullInt64 // Foreign key of TwitterAccount
}

Here, we added TwitterAccount and TwitterAccountId fields, we must note that the TwitterAccount field will not reflect in the user table, only TwitterAccountId field will be and when we check the constraints on the table, we would note that it is the foreign key for TwitterAccount table.

Now, lets further integrate GORM with our revel app to make it work.

Go to init.go file in controllers package (Or create one if its not there)

On app start, make it call InitDB method, which we will define a little later. It looks like this

package controllers

import (
	"github.com/revel/revel"
)

func init() {
	revel.OnAppStart(InitDB)
}

Now, lets define InitDB method.

Create a new file gorm.go and define a InitDB() function in it.

package controllers

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	"social-paster/app/models"
)

var (
	db *gorm.DB
)

func InitDB() {
	dbm, err := gorm.Open("mysql", "username:password@/dbname?charset=utf8&parseTime=True")
	if(err != nil){
		panic("Unable to connect to the database")
	}
	db = &dbm
	dbm.DB().Ping()
	dbm.DB().SetMaxIdleConns(10)
	dbm.DB().SetMaxOpenConns(100)
	dbm.SingularTable(true)

	if !dbm.HasTable(&models.User{}){
		dbm.CreateTable(&models.User{})
	}
	if !dbm.HasTable(&models.TwitterAccount{}){
		dbm.CreateTable(&models.TwitterAccount{})
	}
}

In here, we opened a connection to our mysql database and set max idle and max open connections on it. We also configured our table names to be singular and not plural, had we not done dbm.SingularTable(true), Gorm would have created “users” table for user struct, I wanted it to be a user table and not a users table.

Later we check that we create tables, only when they do not exist.

Now, when we run the app, we should see tables created in mysql.

We can verify that there is a foreign key constraint on TwitterAccountId field and ConfirmPassword is actually transient!

Thats about it. We are good to insert and query our tables using GORM. (A further update here)

Let me know, what you think of it.

~~ Whizdumb ~~
Email : sachin.xpert@gmail.com