Mengenal Repository Pattern pada Golang
Dalam buku Domain-Driven Design, Eric Evans menjelaskan bahwa
Pattern Repository ini biasanya digunakan sebagai jembatan antara business logic aplikasi kita dengan semua perintah SQL ke dalam Database. Jadi semua SQL itu akan kita tulis di repository sedangkan busines logic kode kita hanya cukup menggunakan repository yang sudah kita buat tersebut.
Agar lebih terbayang oleh teman-teman berikut ini diagram repository pattern dibawha ini.

Entity atau Model
Dalam pemrograman berorientasi object, biasanya sebuah table di database akan selalu dibuat merepresentasikan sebagai class Entity atau Model namu pada Golang tidak mengenal Class, sehingga kita bisa merepresentasikan datanya dalam bentuk Struct. Struct tersebut akan mempermudah kita membuat kode program. Pada saat kita melakukan query ke Repository ketika kita mengembalikan array lebih baik kita melakukan konversi terlebih dahulu ke struct Entity atau model sehingga kita tinggal menggunakan objectnya saja.
Contohnya struct yang nanti kita akan pakai pada implementasinya bisa dilihat dibawah ini.
1package model
2
3type Comment struct {
4 Id int32
5 Email string
6 Comment string
7}Implementasi Repository Pattern
Sebelumnya kita sudah memahami entity atau model, kita akan mencoba mencoba belajar dari awal bagaimana mengimplementasikannya.
Pertama kita perlu membuat folder project learn-golang-repository-pattern dan lakukan inisialisasi project Golang dengan perintah dibawah ini.
1go mod init github.com/santekno/learn-golang-repository-patternSelanjutnya, kita akan membuat beberapa folder seperti dibawah ini.
1├── model
2│ ├── comment.go
3├── repository
4│ ├── new.go
5│ ├── comment.go
6├── database.go
7├── main.go
8└── go.modIsi dari file comment.go adalah entity atau model untuk comment sama seperti diatas yaitu.
1package model
2
3type Comment struct {
4 Id int32
5 Email string
6 Comment string
7}Lalu, kita buat file init.go pada folder repository untuk menyimpan method-method yang akan kita panggil saat kita membutuhkan fungsi ke dalam database.
1package repository
2
3import (
4 "context"
5 "database/sql"
6
7 model "github.com/santekno/golang-belajar-repository-pattern/model"
8)
9
10type CommentRepo struct {
11 DB *sql.DB
12}
13
14func NewCommentRepository(db *sql.DB) CommentRepository {
15 return &CommentRepo{
16 DB: db,
17 }
18}
19
20type CommentRepository interface {
21 Insert(ctx context.Context, comment model.Comment) (model.Comment, error)
22 FindById(ctx context.Context, id int32) (model.Comment, error)
23 FindAll(ctx context.Context) ([]model.Comment, error)
24}Agar bisa melakukan implementasikan method-method yang sudah didefinisikan pada inteface diatas maka kita perlu membuat satu file yaitu comment.go dengan isi seperti dibawah ini.
1package repository
2
3import (
4 "context"
5 "fmt"
6
7 model "github.com/santekno/golang-belajar-repository-pattern/model"
8)
9
10func (repo *CommentRepo) Insert(ctx context.Context, comment model.Comment) (model.Comment, error) {
11 result, err := repo.DB.ExecContext(ctx, "INSERT INTO comments(email,comment) VALUES(?,?)", comment.Email, comment.Email)
12 if err != nil {
13 return comment, err
14 }
15
16 insertId, err := result.LastInsertId()
17 if err != nil {
18 return comment, err
19 }
20
21 comment.Id = int32(insertId)
22 return comment, nil
23}
24
25func (repo *CommentRepo) FindById(ctx context.Context, id int32) (model.Comment, error) {
26 var comment model.Comment
27 query := "SELECT id, email, comment FROM comments WHERE id=? LIMIT 1"
28 rows, err := repo.DB.QueryContext(ctx, query, id)
29 if err != nil {
30 return comment, err
31 }
32 defer rows.Close()
33
34 for rows.Next() {
35 err := rows.Scan(&comment.Id, &comment.Email, &comment.Comment)
36 if err != nil {
37 return comment, err
38 }
39 }
40 return comment, nil
41}
42
43func (repo *CommentRepo) FindAll(ctx context.Context) ([]model.Comment, error) {
44 var comments []model.Comment
45 query := "SELECT id, email, comment FROM comments"
46 rows, err := repo.DB.QueryContext(ctx, query)
47 if err != nil {
48 return comments, err
49 }
50 defer rows.Close()
51
52 for rows.Next() {
53 var comment model.Comment
54 err := rows.Scan(&comment.Id, &comment.Email, &comment.Comment)
55 if err != nil {
56 fmt.Printf("error scan rows %v", err)
57 continue
58 }
59 comments = append(comments, comment)
60 }
61
62 return comments, nil
63}Nah repository semua sudah kita buat saatnya kita panggil di fungsi main program agar kita bisa menjalankan semua repositorynya. Sebelum ke main kita perlu tambahkan koneksi database terlebih dahulu agar bisa terkoneksi dengan database.
1func GetConnection() *sql.DB {
2 db, err := sql.Open("mysql", "root:belajargolang@tcp(localhost:3306)/belajar-golang")
3 if err != nil {
4 panic(err)
5 }
6
7 db.SetMaxIdleConns(10)
8 db.SetMaxOpenConns(100)
9 db.SetConnMaxIdleTime(5 * time.Minute)
10 db.SetConnMaxLifetime(60 * time.Minute)
11 return db
12}Dan berikut ini isi fungsi main() yang memanggil repository yang sudah kita buat.
1func main() {
2 ctx := context.Background()
3 db := GetConnection()
4 defer db.Close()
5
6 commentRepo := repository.NewCommentRepository(db)
7
8 // find all data comments
9 comments, err := commentRepo.FindAll(ctx)
10 if err != nil {
11 panic(err)
12 }
13
14 for _, cm := range comments {
15 fmt.Printf("data %d: %v\n", cm.Id, cm)
16 }
17
18 // find all data by id
19 comment, err := commentRepo.FindById(ctx, 2)
20 if err != nil {
21 panic(err)
22 }
23 fmt.Printf("data : %v", comment)
24
25 // insert data
26 id, err := commentRepo.Insert(ctx, model.Comment{Email: "test@gmail.com", Comment: "komentar yuk"})
27 if err != nil {
28 panic(err)
29 }
30 fmt.Printf("lastId: %v", id)
31}Pada fungsi main() ini kita akan memanggil fungsi untuk koneksi ke dalam database selanjutnya kita melakukan initialisasi repository comment dan selanjutnya kita bisa menggunakan repository itu untuk memanggil source data dari database.
Jika kita ingin menambahkan method baru atau fungsi baru yang mana itu berhubungan dengan mengambil data atau menyimpan data ke dalam database. Maka, kita cukup menambahkan Method pada Interface dan implementasinya pada file comment.go. Mudah kan? Sehingga code program kita dienkapsulasi ke dalam interface dan nantinya akan implementasikan ke berbagai method yang bisa di buat.