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

Top comments (0)