├── .gitignore ├── README.md ├── main.go ├── model └── User.go └── repository ├── RepositoryRegistry.go └── UserRepository.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # repository-design-pattern 2 | 3 | The repository design pattern that has following characteristics 4 | 5 | * Easy to register new repositories with minimal repetitive code 6 | * Single database connection (aws session) across all repositories 7 | * Parent struct that contains shared fields 8 | * Each repository must implement standard Restful methods, however can contain any additional functions 9 | * All repositories are stored in a registry and can be passed down the application as a single struct 10 | 11 | Example: 12 | --------- 13 | main.go 14 | 15 | ```go 16 | logger := logrus.New() 17 | logger.SetLevel(logrus.DebugLevel) 18 | sess := session.Must(session.NewSessionWithOptions(session.Options{ 19 | SharedConfigState: session.SharedConfigEnable, 20 | })) 21 | 22 | rr := repository.NewRepositoryRegistry( 23 | dynamo.New(sess), 24 | logger, 25 | &repository.UserRepository{}, 26 | ) 27 | 28 | users, err := rr.MustRepository("UserRepository").List() 29 | if err != nil { 30 | logger.WithError(err).Fatal("an error has occurred") 31 | } 32 | 33 | fmt.Println(users) 34 | ``` 35 | 36 | UserRepository.go 37 | ```go 38 | package repository 39 | 40 | import ( 41 | "github.com/b-b3rn4rd/repository-design-pattern/model" 42 | "github.com/pkg/errors" 43 | ) 44 | 45 | type UserRepository struct { 46 | DynamoRepository 47 | } 48 | 49 | func (r *UserRepository) List() (interface{}, error) { 50 | r.logger.Debug("listing all users") 51 | 52 | var users []model.User 53 | 54 | err := r.db.Table("User").Scan().All(&users) 55 | if err != nil { 56 | return nil, errors.Wrap(err, "error while listing users") 57 | } 58 | 59 | return users, nil 60 | } 61 | 62 | func (r *UserRepository) Get(id interface{}) (interface{}, error) { 63 | r.logger.WithField("id", id).Debug("retrieving single user") 64 | 65 | var user []model.User 66 | 67 | err := r.db.Table("User").Get("Id", id).One(&user) 68 | if err != nil { 69 | return nil, errors.Wrap(err, "error while retrieving single user") 70 | } 71 | 72 | return user, nil 73 | } 74 | 75 | func (r *UserRepository) Create(entity interface{}) (interface{}, error) { 76 | r.logger.WithField("user", entity).Debug("create user") 77 | 78 | err := r.db.Table("User").Put(entity.(model.User)).Run() 79 | if err != nil { 80 | return false, errors.Wrap(err, "error while creating user") 81 | } 82 | 83 | return true, nil 84 | } 85 | 86 | func (r *UserRepository) Update(id interface{}, entity interface{}) (bool, error) { 87 | r.logger.WithField("user", entity).Debug("update user") 88 | 89 | err := r.db.Table("User").Update("Id", id).Set("Email", entity.(model.User).Email).Run() 90 | if err != nil { 91 | return false, errors.Wrap(err, "error while updating user") 92 | } 93 | 94 | return true, nil 95 | } 96 | 97 | func (r *UserRepository) Delete(id interface{}) (bool, error) { 98 | r.logger.WithField("id", id).Debug("delete user") 99 | 100 | err := r.db.Table("User").Delete("Id", id).Run() 101 | if err != nil { 102 | return false, errors.Wrap(err, "error while deleting user") 103 | } 104 | 105 | return false, nil 106 | } 107 | 108 | func (r *UserRepository) GetGroups(id interface{}) (interface{}, error) { 109 | r.logger.WithField("id", id).Debug("get user groups") 110 | 111 | return nil, errors.New("error retrieving user's groups") 112 | } 113 | 114 | ``` -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aws/aws-sdk-go/aws/session" 7 | "github.com/b-b3rn4rd/repository-design-pattern/repository" 8 | "github.com/guregu/dynamo" 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | func main() { 13 | logger := logrus.New() 14 | logger.SetLevel(logrus.DebugLevel) 15 | sess := session.Must(session.NewSessionWithOptions(session.Options{ 16 | SharedConfigState: session.SharedConfigEnable, 17 | })) 18 | 19 | rr := repository.NewRepositoryRegistry( 20 | dynamo.New(sess), 21 | logger, 22 | &repository.UserRepository{}, 23 | ) 24 | 25 | users, err := rr.MustRepository("UserRepository").List() 26 | if err != nil { 27 | logger.WithError(err).Fatal("an error has occurred") 28 | } 29 | 30 | fmt.Println(users) 31 | } 32 | -------------------------------------------------------------------------------- /model/User.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type User struct { 4 | Id int 5 | Email string `dynamo:"Email"` 6 | } 7 | -------------------------------------------------------------------------------- /repository/RepositoryRegistry.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "reflect" 5 | 6 | "fmt" 7 | 8 | "github.com/guregu/dynamo" 9 | "github.com/pkg/errors" 10 | "github.com/sirupsen/logrus" 11 | ) 12 | 13 | type Configurer interface { 14 | Configure(db *dynamo.DB, logger *logrus.Logger) 15 | } 16 | 17 | type Repository interface { 18 | Configure(*dynamo.DB, *logrus.Logger) 19 | List() (interface{}, error) 20 | Get(id interface{}) (interface{}, error) 21 | Create(entity interface{}) (interface{}, error) 22 | Update(id interface{}, entity interface{}) (bool, error) 23 | Delete(id interface{}) (bool, error) 24 | } 25 | 26 | type DynamoRepository struct { 27 | db *dynamo.DB 28 | logger *logrus.Logger 29 | } 30 | 31 | func (r *DynamoRepository) Configure(db *dynamo.DB, logger *logrus.Logger) { 32 | r.db = db 33 | r.logger = logger 34 | } 35 | 36 | type RepositoryRegistry struct { 37 | registry map[string]Repository 38 | 39 | db *dynamo.DB 40 | logger *logrus.Logger 41 | } 42 | 43 | func NewRepositoryRegistry(db *dynamo.DB, logger *logrus.Logger, repository ...Repository) *RepositoryRegistry { 44 | r := &RepositoryRegistry{ 45 | db: db, 46 | logger: logger, 47 | registry: map[string]Repository{}, 48 | } 49 | 50 | r.registerRepositories(repository) 51 | return r 52 | } 53 | 54 | func (r *RepositoryRegistry) registerRepositories(repositories []Repository) { 55 | for _, repository := range repositories { 56 | repositoryName := reflect.TypeOf(repository).Elem().Name() 57 | repository.Configure(r.db, r.logger) 58 | r.logger.WithField("repository", repositoryName).Debug("registering repository") 59 | r.registry[repositoryName] = repository 60 | } 61 | } 62 | 63 | func (r *RepositoryRegistry) Repository(repositoryName string) (Repository, error) { 64 | if repository, ok := r.registry[repositoryName]; ok { 65 | return repository, nil 66 | } 67 | 68 | return nil, errors.New(fmt.Sprintf("repository %s does not exist", repositoryName)) 69 | } 70 | 71 | func (r *RepositoryRegistry) MustRepository(repositoryName string) (repository Repository) { 72 | repository, err := r.Repository(repositoryName) 73 | if err != nil { 74 | r.logger.Panic(err.Error()) 75 | } 76 | 77 | return repository 78 | } 79 | -------------------------------------------------------------------------------- /repository/UserRepository.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "github.com/b-b3rn4rd/repository-design-pattern/model" 5 | "github.com/pkg/errors" 6 | ) 7 | 8 | type UserRepository struct { 9 | DynamoRepository 10 | } 11 | 12 | func (r *UserRepository) List() (interface{}, error) { 13 | r.logger.Debug("listing all users") 14 | 15 | var users []model.User 16 | 17 | err := r.db.Table("User").Scan().All(&users) 18 | if err != nil { 19 | return nil, errors.Wrap(err, "error while listing users") 20 | } 21 | 22 | return users, nil 23 | } 24 | 25 | func (r *UserRepository) Get(id interface{}) (interface{}, error) { 26 | r.logger.WithField("id", id).Debug("retrieving single user") 27 | 28 | var user []model.User 29 | 30 | err := r.db.Table("User").Get("Id", id).One(&user) 31 | if err != nil { 32 | return nil, errors.Wrap(err, "error while retrieving single user") 33 | } 34 | 35 | return user, nil 36 | } 37 | 38 | func (r *UserRepository) Create(entity interface{}) (interface{}, error) { 39 | r.logger.WithField("user", entity).Debug("create user") 40 | 41 | err := r.db.Table("User").Put(entity.(model.User)).Run() 42 | if err != nil { 43 | return false, errors.Wrap(err, "error while creating user") 44 | } 45 | 46 | return true, nil 47 | } 48 | 49 | func (r *UserRepository) Update(id interface{}, entity interface{}) (bool, error) { 50 | r.logger.WithField("user", entity).Debug("update user") 51 | 52 | err := r.db.Table("User").Update("Id", id).Set("Email", entity.(model.User).Email).Run() 53 | if err != nil { 54 | return false, errors.Wrap(err, "error while updating user") 55 | } 56 | 57 | return true, nil 58 | } 59 | 60 | func (r *UserRepository) Delete(id interface{}) (bool, error) { 61 | r.logger.WithField("id", id).Debug("delete user") 62 | 63 | err := r.db.Table("User").Delete("Id", id).Run() 64 | if err != nil { 65 | return false, errors.Wrap(err, "error while deleting user") 66 | } 67 | 68 | return false, nil 69 | } 70 | 71 | func (r *UserRepository) GetGroups(id interface{}) (interface{}, error) { 72 | r.logger.WithField("id", id).Debug("get user groups") 73 | 74 | return nil, errors.New("error retrieving user's groups") 75 | } 76 | --------------------------------------------------------------------------------