No matter how much we say SQL is better than NoSQL, we can all agree that writing SQL by hand is not much fun, especially where you have to do joins and the rest. The need to solve this annoying issue has led to the development of several different ORMs (Object Relational Mapper) that sit as an abstraction layer on top of our database.
They provide developers a way to interact with data typically an SQL-compatible database using Objects and code instead of writing a bunch of SQL code. All programming languages have their ORM but in today's post we will take a brief look at GORM an ORM that is developed for Go or Go Lang as it is commonly called hence we are going to consider the following talking points;
- Features of GORM
- Installation and setup
- Models
- Add data
- Read Data
- Update Data
- Delete Data
Features of GORM
GORM is a Full-Featured and developer-friendly ORM built with out-of-the-box support for all types of associations, and hooks that you can listen to extend the behavior of your models further. GORM is written in Go and supports multiple SQL-based databases like MySQL, SQL-Lite, Postgre SQL, and OracleDB. GORM has built-in support for Transactions, nested transactions, save points, and rollback to saved points. GORM allows us to run Batch Insert, FindInBatches, Find/Create with Map amongst others, let's see how we can install and setup GORM in a Go project.
Installation and Setup
To install GORM you need to run the following command;
go get -u gorm.io/gorm
Next, you need to install a driver compatible with your SQL database and as such we will install the driver for MySQL with the following command.
go get -u gorm.io/driver/mysql
Now we have GORM and a compatible SQL driver installed let's connect to a MySQL database.
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main () {
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "root@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=true",
}))
if err != nil {
panic("failed to connect database")
}
}
Models
Models serve as a way to map a struct in your Go program to a database table. Each Model corresponds to a table in your database, while the keys on the struct correspond to columns on that table. While the values for each key serve as a row in your database. Let's create a User
struct that will correspond to a user table.
import "gorm.io/gorm"
type User struct {
gorm.Model,
Name string `json:"name"`
Email string `json:"email"`
}
You can observe that each key on the struct has a type and that type will correspond to the type for that particular value on our SQL table. We can use other types like uint
and bool
. We can do things like specify foreign keys and unique columns.
import "gorm.io/gorm"
type User struct {
gorm.Model,
Name string `gorm:"type:varchar(20)" json:"name"`
Email string `gorm:"unique;not null" json:"email"`
}
You can embed the gorm.Model
struct into your model struct. This adds commonly used fields like:
ID
: A unique identifier for each record (usually the primary key).
CreatedAt
: Automatically set to the current time when a record is created.
UpdatedAt
: Automatically updated whenever a record is modified.
DeletedAt
(optional): Used for soft deletes (marking records as deleted without physically removing them).
Add data
Let’s see how we can add data to our database using the model we just created.
// cont’d
func CreateUser (db *gorm.DB, name string, email string) User {
newUser := User{
Name: name,
Email: email,
}
result := db.Create(&newUser)
if result.Error != nil {
panic("error creating user")
}
return newUser
}
user := CreateUser(db, "sam","sam@gmail.Com")
The code above defines a function called CreateUser
that takes a database connection (db)
, a name (name)
, and an email (email)
as arguments and returns a User model. We can also create multiple users easily.
// cont’d
func CreateUsers(db *gorm.DB) []User {
newUsers := []*User{
{ Name: “jay”, Email: “jay@gmail.Com” },
{ Name: “joe”, Email: “joe@gmail.Com” },
}
result := db.Create(&newUsers)
if result.Error != nil {
panic("error creating user")
}
return newUsers
}
users := CreateUsers(db)
Read Data
Now we’ve created some data let’s see how we can read those data we just added.
// get single record
func GetUser(db *gorm.DB, id uint) User {
user = User{
ID: id
}
result := db.First(&user)
if result.Error != nil {
panic("Error fetching data")
}
return user
}
user := GetUser(db, 1)
The code snippet above shows how to retrieve a single user, what if we are interested in getting multiple users?
// get single record
func GetUsers(db *gorm.DB) []User {
var users []User
result := db.Find(&users)
if result.Error != nil {
panic("Error fetching data")
}
return users
}
users := GetUsers(db);
Update Data
Now we’ve seen how to read our data let’s see how we can update our data.
func UpdateUser(db *gorm.DB, id uint, name string) user {
user := User{
ID: id,
}
result := db.Find(&users).Update("name", name)
if result.Error != nil {
panic("Error fetching data")
}
return user
}
users := UpdateUser(db, 1, "sam");
If we ware interested in updating multiple columns for a particular data we can use the following approach;
func UpdateUser(db *gorm.DB, id uint) user {
user := User{
Name: "phill"
Email: "phill@gmail.com"
}
result := db.Where("id = ?", id).Updates(&user)
if result.Error != nil {
panic("Error fetching data")
}
return user
}
users := UpdateUser(db, 1);
Delete Data
Now let’s see how we can delete a record or multiple records from our database
// delete single record
func DeleteUser(db *gorm.DB, id uint) {
result := db.Delete(&User{}, id)
if result.Error != nil {
panic("Error fetching data")
}
}
DeleteUser(db, 1)
// delete multiple records
func DeleteUsers(db *gorm.DB, ids []int{}) {
result := db.Delete(&User{}, ids)
if result.Error != nil {
panic("Error fetching data")
}
}
DeleteUsers(db, {1, 4, 10})
That’s going to be all for this one guys, I hope you found this useful leave your thoughts in the comments section below.