DEV Community

Santosh Anand
Santosh Anand

Posted on

Implementing the repository pattern in Go with both in-memory and MySQL repositories

  1. - We define the User struct representing a user entity.
  2. - We define the UserRepository interface with methods for managing users.
  3. - We implement InMemoryUserRepository and MySQLUserRepository to provide in-memory and MySQL-based repositories, respectively.
  4. - NewInMemoryUserRepository and NewMySQLUserRepository are constructor functions for creating instances of the respective repositories.
  5. - We demonstrate how to use both repositories in the main function by inserting users, getting a user by ID, and getting all users.
package main

import (
    "database/sql"
    "errors"
    "fmt"

    _ "github.com/go-sql-driver/mysql"
)

// User represents a user entity
type User struct {
    ID       int
    Username string
    Email    string
}

// UserRepository defines the methods a user repository must implement
type UserRepository interface {
    Insert(user *User) error
    GetByID(id int) (*User, error)
    GetAll() ([]*User, error)
}

// InMemoryUserRepository is an in-memory implementation of UserRepository
type InMemoryUserRepository struct {
    users []*User
}

// NewInMemoryUserRepository creates a new instance of InMemoryUserRepository
func NewInMemoryUserRepository() *InMemoryUserRepository {
    return &InMemoryUserRepository{
        users: make([]*User, 0),
    }
}

// Insert inserts a new user into the repository
func (repo *InMemoryUserRepository) Insert(user *User) error {
    repo.users = append(repo.users, user)
    return nil
}

// GetByID retrieves a user by its ID from the repository
func (repo *InMemoryUserRepository) GetByID(id int) (*User, error) {
    for _, user := range repo.users {
        if user.ID == id {
            return user, nil
        }
    }
    return nil, errors.New("user not found")
}

// GetAll retrieves all users from the repository
func (repo *InMemoryUserRepository) GetAll() ([]*User, error) {
    return repo.users, nil
}

// MySQLUserRepository is a MySQL implementation of UserRepository
type MySQLUserRepository struct {
    db *sql.DB
}

// NewMySQLUserRepository creates a new instance of MySQLUserRepository
func NewMySQLUserRepository(dataSourceName string) (*MySQLUserRepository, error) {
    db, err := sql.Open("mysql", dataSourceName)
    if err != nil {
        return nil, err
    }
    return &MySQLUserRepository{
        db: db,
    }, nil
}

// Insert inserts a new user into the MySQL repository
func (repo *MySQLUserRepository) Insert(user *User) error {
    _, err := repo.db.Exec("INSERT INTO users (id, username, email) VALUES (?, ?, ?)", user.ID, user.Username, user.Email)
    if err != nil {
        return err
    }
    return nil
}

// GetByID retrieves a user by its ID from the MySQL repository
func (repo *MySQLUserRepository) GetByID(id int) (*User, error) {
    row := repo.db.QueryRow("SELECT id, username, email FROM users WHERE id = ?", id)
    user := &User{}
    err := row.Scan(&user.ID, &user.Username, &user.Email)
    if err != nil {
        return nil, err
    }
    return user, nil
}

// GetAll retrieves all users from the MySQL repository
func (repo *MySQLUserRepository) GetAll() ([]*User, error) {
    rows, err := repo.db.Query("SELECT id, username, email FROM users")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var users []*User
    for rows.Next() {
        user := &User{}
        err := rows.Scan(&user.ID, &user.Username, &user.Email)
        if err != nil {
            return nil, err
        }
        users = append(users, user)
    }
    return users, nil
}

func main() {
    // Example usage of in-memory repository
    memRepo := NewInMemoryUserRepository()
    memRepo.Insert(&User{ID: 1, Username: "user1", Email: "user1@example.com"})
    memRepo.Insert(&User{ID: 2, Username: "user2", Email: "user2@example.com"})

    user, err := memRepo.GetByID(1)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("In-Memory User:", user)
    }

    allUsers, err := memRepo.GetAll()
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("In-Memory All Users:", allUsers)
    }

    // Example usage of MySQL repository
    mysqlRepo, err := NewMySQLUserRepository("user:password@tcp(127.0.0.1:3306)/database_name")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    mysqlRepo.Insert(&User{ID: 3, Username: "user3", Email: "user3@example.com"})
    mysqlRepo.Insert(&User{ID: 4, Username: "user4", Email: "user4@example.com"})

    user, err = mysqlRepo.GetByID(3)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("MySQL User:", user)
    }

    allUsers, err = mysqlRepo.GetAll()
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("MySQL All Users:", allUsers)
    }
}

Enter fullscreen mode Exit fullscreen mode

Billboard image

Use Playwright to test. Use Playwright to monitor.

Join Vercel, CrowdStrike, and thousands of other teams that run end-to-end monitors on Checkly's programmable monitoring platform.

Get started now!

Top comments (0)

Heroku

This site is powered by Heroku

Heroku was created by developers, for developers. Get started today and find out why Heroku has been the platform of choice for brands like DEV for over a decade.

Sign Up

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay