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()
}