3 min read

Golang Gorm Postgresql

Table of Contents

Create new Go project

mkdir go-postgres-gorm
cd go-postgres-gorm

go mod init example/go-postgres-gorm

Install required dependencies

go get -u gorm.io/gorm
go get -u gorm.io/driver/postgres

go get github.com/joho/godotenv

Project structure

.
├── cmd/
│   └── main.go
├── pkg/
│   ├── database/
│   │   └── database.go
│   ├── model/
│   │   └── user.go
│   └── seeder/
│       └── seeder.go
├── .env
├── go.mod
└── go.sum

Create .env

DB_USER=<DATABASE_USERNAME>
DB_PASSWORD=<DATABASE_PASSWORD>
DB_NAME=<DATABASE_NAME>
DB_HOST=<DATABASE_HOST>
DB_PORT=<DATABASE_PORT>

Database

We will create our connection to database in database/database.go

package database

import (
	"log"
	"os"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

var Db *gorm.DB

func InitDb() *gorm.DB {
	Db = connectDb()
	return Db
}

func connectDb() *gorm.DB {
	var err error

	host := os.Getenv("DB_HOST")
	port := os.Getenv("DB_PORT")
	user := os.Getenv("DB_USER")
	dbname := os.Getenv("DB_NAME")
	password := os.Getenv("DB_PASSWORD")

	dsn := "host=" + host + " user=" + user + " password=" + password + " dbname=" + dbname + " port=" + port + " sslmode=disable TimeZone=Asia/Shanghai"
	Db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})

	if err != nil {
		log.Panic(err)
		panic(err)
	}

	log.Println("Database connected")

	return Db
}

Then we will update our cmd/main.go

package main

import (
	"example/go-postgres-gorm/pkg/database"
	"log"

	"github.com/joho/godotenv"
)

func main() {
	// Load env
	loadEnv()

	// Load database
	loadDatabase()
}

func loadEnv() {
	err := godotenv.Load(".env")

	if err != nil {
		log.Fatal("Error loading .env file")
	}

	log.Println("Environment loaded")
}

func loadDatabase() {
	database.InitDb()
}
🚨

You will see output such as 2024/07/27 14:52:34 Environment loaded and 2024/07/27 14:52:34 Database connected if everything setup correctly.

User model

We will create our model for our migration and seeder

package model

import (
	"database/sql/driver"
	"example/go-postgres-gorm/pkg/database"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type Gender string

const (
	Male   Gender = "male"
	Female Gender = "female"
)

func (g *Gender) Scan(value interface{}) error {
	*g = Gender(value.([]byte))
	return nil
}

func (g Gender) Value() (driver.Value, error) {
	return string(g), nil
}

type User struct {
	gorm.Model
	ID          uint   `json:"id" gorm:"primaryKey"`
	Username    string `json:"username"`
	Name        string `json:"name"`
	Email       string `json:"email"`
	Password    string `json:"password"`
	AboutMe     string `json:"about_me"`
	Address     string `json:"address"`
	PhoneNumber string `json:"phone_number"`
	Gender      Gender `json:"gender" sql:"type:ENUM('male', 'female')"`
	DateOfBirth string `json:"date_of_birth"`
}

// Save user to database
func (user *User) Save() (*User, error) {
	err := database.Db.Create(&user).Error

	if err != nil {
		return &User{}, err
	}

	return user, nil
}

Create seeder/seeder.go

package seeder

import "junianto/jendaka/pkg/model"

func SeedData() {
    var users = []model.User{
		{
			Username: "superadmin",
			Name:     "Super Admin",
			Email:    "superadmin@gmail.com",
			Password: "superadmin",
		},
	}

    for _, user := range users {
		user.Save()
	}
}

Then update cmd/main.go to

package main

import (
	"example/go-postgres-gorm/pkg/database"
	"example/go-postgres-gorm/pkg/model"
	"example/go-postgres-gorm/pkg/seeder"
	"log"

	"github.com/joho/godotenv"
)

func main() {
	// Load env
	loadEnv()

	// Load database
	loadDatabase()
}

func loadEnv() {
	err := godotenv.Load(".env")

	if err != nil {
		log.Fatal("Error loading .env file")
	}

	log.Println("Environment loaded")
}

func loadDatabase() {
	database.InitDb()

	database.Db.AutoMigrate(&model.User{})
	database.Db.AutoMigrate(&model.Role{})
	database.Db.AutoMigrate(&model.UserHasRole{})
	database.Db.AutoMigrate(&model.Permission{})
	database.Db.AutoMigrate(&model.RoleHasPermission{})

	log.Println("Database migrated")

	seedDatabase()

	log.Println("Database seeded")
}

func seedDatabase() {
	seeder.SeedData()
}