From 49fe0e71a06ee1fb5de60c934f0b0faea7b74e86 Mon Sep 17 00:00:00 2001 From: Imre Nagi Date: Tue, 29 Jun 2021 23:45:01 +0700 Subject: [PATCH] Use sqlite as default datastore Signed-off-by: Imre Nagi --- .gitignore | 2 + datastore/{mysql => sql}/invoice.go | 11 ++- datastore/{mysql => sql}/midtrans_status.go | 14 ++-- datastore/{mysql => sql}/subscription.go | 12 ++-- example/server/README.md | 79 +++++++++++---------- example/server/server.go | 27 ++++--- gateway/midtrans/transaction_status.go | 4 +- go.mod | 3 +- go.sum | 14 +++- invoice/invoice.go | 4 +- server/server.go | 2 +- types.go | 4 +- util/db/mysql/conn.go | 34 --------- 13 files changed, 100 insertions(+), 110 deletions(-) rename datastore/{mysql => sql}/invoice.go (87%) rename datastore/{mysql => sql}/midtrans_status.go (83%) rename datastore/{mysql => sql}/subscription.go (87%) delete mode 100644 util/db/mysql/conn.go diff --git a/.gitignore b/.gitignore index 38cdbcf..2ceadab 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ Thumbs.db _output/ bin/ vendor/ + +example/server/gorm.db diff --git a/datastore/mysql/invoice.go b/datastore/sql/invoice.go similarity index 87% rename from datastore/mysql/invoice.go rename to datastore/sql/invoice.go index e508f34..5ece9c5 100644 --- a/datastore/mysql/invoice.go +++ b/datastore/sql/invoice.go @@ -1,4 +1,4 @@ -package mysql +package sql import ( "context" @@ -6,7 +6,7 @@ import ( "github.com/imrenagi/go-payment" "github.com/imrenagi/go-payment/invoice" - "github.com/jinzhu/gorm" + "gorm.io/gorm" "github.com/rs/zerolog" ) @@ -45,13 +45,12 @@ func (r *InvoiceRepository) FindByNumber(ctx context.Context, number string) (*i Preload("BillingAddress"). Where("number = ?", number).Find(&invoice) - if req.RecordNotFound() { + if req.Error == gorm.ErrRecordNotFound { return nil, fmt.Errorf("invoice %s %w", number, payment.ErrNotFound) } - errs := req.GetErrors() - if len(errs) > 0 { - log.Error().Err(errs[0]).Msg("can't find invoice") + if req.Error != nil { + log.Error().Err(req.Error).Msg("can't find invoice") return nil, payment.ErrDatabase } return &invoice, nil diff --git a/datastore/mysql/midtrans_status.go b/datastore/sql/midtrans_status.go similarity index 83% rename from datastore/mysql/midtrans_status.go rename to datastore/sql/midtrans_status.go index 3c8f00a..a1ef683 100644 --- a/datastore/mysql/midtrans_status.go +++ b/datastore/sql/midtrans_status.go @@ -1,4 +1,4 @@ -package mysql +package sql import ( "context" @@ -6,7 +6,7 @@ import ( "github.com/imrenagi/go-payment" "github.com/imrenagi/go-payment/gateway/midtrans" - "github.com/jinzhu/gorm" + "gorm.io/gorm" "github.com/rs/zerolog" ) @@ -20,7 +20,7 @@ type MidtransTransactionRepository struct { DB *gorm.DB } -// Save will update the notification stored in mysql database +// Save will update the notification stored in sql database func (m *MidtransTransactionRepository) Save(ctx context.Context, status *midtrans.TransactionStatus) error { log := zerolog.Ctx(ctx).With().Str("function", "MidtransTransactionRepository.Save").Logger() @@ -40,14 +40,14 @@ func (m *MidtransTransactionRepository) FindByOrderID(ctx context.Context, order Where("order_id = ?", orderID). First(&status) - if req.RecordNotFound() { + if req.Error == gorm.ErrRecordNotFound { return nil, fmt.Errorf("payment status for order %s %w", orderID, payment.ErrNotFound) } - errs := req.GetErrors() - if len(errs) > 0 { - log.Error().Err(errs[0]).Msg("cant find midtrans transaction status") + if req.Error != nil { + log.Error().Err(req.Error).Msg("cant find midtrans transaction status") return nil, payment.ErrDatabase } + return &status, nil } diff --git a/datastore/mysql/subscription.go b/datastore/sql/subscription.go similarity index 87% rename from datastore/mysql/subscription.go rename to datastore/sql/subscription.go index d8e01c8..34f9a75 100644 --- a/datastore/mysql/subscription.go +++ b/datastore/sql/subscription.go @@ -1,4 +1,4 @@ -package mysql +package sql import ( "context" @@ -7,7 +7,7 @@ import ( "github.com/imrenagi/go-payment/subscription" "github.com/imrenagi/go-payment" - "github.com/jinzhu/gorm" + "gorm.io/gorm" "github.com/rs/zerolog" ) @@ -43,14 +43,14 @@ func (r *SubscriptionRepository) FindByNumber(ctx context.Context, number string Preload("Invoices"). Where("number = ?", number).Find(&subs) - if req.RecordNotFound() { + if req.Error == gorm.ErrRecordNotFound{ return nil, fmt.Errorf("subscription %s %w", number, payment.ErrNotFound) } - errs := req.GetErrors() - if len(errs) > 0 { - log.Error().Err(errs[0]).Msg("can't find subscription") + if req.Error != nil { + log.Error().Err(req.Error).Msg("can't find subscription") return nil, payment.ErrDatabase } + return &subs, nil } diff --git a/example/server/README.md b/example/server/README.md index 2c79c6a..330d7b7 100644 --- a/example/server/README.md +++ b/example/server/README.md @@ -3,56 +3,61 @@ Example To start using this module, you can try the example [server.go](/server.go) +This example is using sqlite as the datastore. If you want to change the database, +please read gorm docs for connecting to database [here](https://gorm.io/docs/connecting_to_the_database.html) ```go package main import ( - "net/http" + "net/http" - "github.com/gorilla/mux" - "github.com/imrenagi/go-payment/datastore/inmemory" - dsmysql "github.com/imrenagi/go-payment/datastore/mysql" - "github.com/imrenagi/go-payment/gateway/midtrans" - "github.com/imrenagi/go-payment/invoice" - "github.com/imrenagi/go-payment/manage" - "github.com/imrenagi/go-payment/server" - "github.com/imrenagi/go-payment/util/db/mysql" - "github.com/imrenagi/go-payment/util/localconfig" - "github.com/rs/cors" - "github.com/rs/zerolog/log" + "github.com/gorilla/mux" + "github.com/imrenagi/go-payment/datastore/inmemory" + dsmysql "github.com/imrenagi/go-payment/datastore/sql" + "github.com/imrenagi/go-payment/gateway/midtrans" + "github.com/imrenagi/go-payment/invoice" + "github.com/imrenagi/go-payment/manage" + "github.com/imrenagi/go-payment/server" + "github.com/imrenagi/go-payment/util/db/mysql" + "github.com/imrenagi/go-payment/util/localconfig" + "github.com/rs/cors" + "github.com/rs/zerolog/log" ) func main() { - secret, err := localconfig.LoadSecret("example/server/secret.yaml") - if err != nil { - panic(err) - } + secret, err := localconfig.LoadSecret("example/server/secret.yaml") + if err != nil { + panic(err) + } - db := mysql.NewGorm(secret.DB) - db.AutoMigrate( - &midtrans.TransactionStatus{}, - &invoice.Invoice{}, - &invoice.Payment{}, - &invoice.CreditCardDetail{}, - &invoice.LineItem{}, - &invoice.BillingAddress{}, - ) + db, err := gorm.Open(sqlite.Open("example/server/gorm.db"), &gorm.Config{}) + if err != nil { + log.Fatal().Msg(err.Error()) + } + db.AutoMigrate( + &midtrans.TransactionStatus{}, + &invoice.Invoice{}, + &invoice.Payment{}, + &invoice.CreditCardDetail{}, + &invoice.LineItem{}, + &invoice.BillingAddress{}, + ) - m := manage.NewManager(secret.Payment) - m.MustMidtransTransactionStatusRepository(dsmysql.NewMidtransTransactionRepository(db)) - m.MustInvoiceRepository(dsmysql.NewInvoiceRepository(db)) - m.MustPaymentConfigReader(inmemory.NewPaymentConfigRepository("example/server/payment-methods.yml")) + m := manage.NewManager(secret.Payment) + m.MustMidtransTransactionStatusRepository(dsmysql.NewMidtransTransactionRepository(db)) + m.MustInvoiceRepository(dsmysql.NewInvoiceRepository(db)) + m.MustPaymentConfigReader(inmemory.NewPaymentConfigRepository("example/server/payment-methods.yml")) - srv := srv{ - Router: mux.NewRouter(), - paymentSrv: server.NewServer(m), - } - srv.routes() + srv := srv{ + Router: mux.NewRouter(), + paymentSrv: server.NewServer(m), + } + srv.routes() - if err := http.ListenAndServe(":8080", srv.GetHandler()); err != nil { - log.Fatal().Msgf("Server can't run. Got: `%v`", err) - } + if err := http.ListenAndServe(":8080", srv.GetHandler()); err != nil { + log.Fatal().Msgf("Server can't run. Got: `%v`", err) + } } ``` diff --git a/example/server/server.go b/example/server/server.go index 0e94389..1598658 100644 --- a/example/server/server.go +++ b/example/server/server.go @@ -3,19 +3,21 @@ package main import ( "net/http" - "github.com/imrenagi/go-payment/subscription" - "github.com/gorilla/mux" + "github.com/rs/cors" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + + "github.com/rs/zerolog/log" + "github.com/imrenagi/go-payment/datastore/inmemory" - dsmysql "github.com/imrenagi/go-payment/datastore/mysql" + dssql "github.com/imrenagi/go-payment/datastore/sql" "github.com/imrenagi/go-payment/gateway/midtrans" "github.com/imrenagi/go-payment/invoice" "github.com/imrenagi/go-payment/manage" "github.com/imrenagi/go-payment/server" - "github.com/imrenagi/go-payment/util/db/mysql" + "github.com/imrenagi/go-payment/subscription" "github.com/imrenagi/go-payment/util/localconfig" - "github.com/rs/cors" - "github.com/rs/zerolog/log" ) func main() { @@ -25,7 +27,10 @@ func main() { panic(err) } - db := mysql.NewGorm(secret.DB) + db, err := gorm.Open(sqlite.Open("example/server/gorm.db"), &gorm.Config{}) + if err != nil { + log.Fatal().Msg(err.Error()) + } db.AutoMigrate( &midtrans.TransactionStatus{}, &invoice.Invoice{}, @@ -38,9 +43,9 @@ func main() { ) m := manage.NewManager(secret.Payment) - m.MustMidtransTransactionStatusRepository(dsmysql.NewMidtransTransactionRepository(db)) - m.MustInvoiceRepository(dsmysql.NewInvoiceRepository(db)) - m.MustSubscriptionRepository(dsmysql.NewSubscriptionRepository(db)) + m.MustMidtransTransactionStatusRepository(dssql.NewMidtransTransactionRepository(db)) + m.MustInvoiceRepository(dssql.NewInvoiceRepository(db)) + m.MustSubscriptionRepository(dssql.NewSubscriptionRepository(db)) m.MustPaymentConfigReader(inmemory.NewPaymentConfigRepository("example/server/payment-methods.yaml")) srv := srv{ @@ -66,7 +71,7 @@ func (s *srv) GetHandler() http.Handler { AllowedOrigins: []string{"http://localhost:3000", "https://localhost:3000"}, AllowedMethods: []string{"POST", "GET", "PUT", "DELETE", "HEAD", "OPTIONS"}, AllowedHeaders: []string{"Accept", "Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization", "Mode"}, - MaxAge: 60, //1 minutes + MaxAge: 60, // 1 minutes AllowCredentials: true, OptionsPassthrough: false, Debug: false, diff --git a/gateway/midtrans/transaction_status.go b/gateway/midtrans/transaction_status.go index 766d6b6..b46246c 100644 --- a/gateway/midtrans/transaction_status.go +++ b/gateway/midtrans/transaction_status.go @@ -12,8 +12,8 @@ import ( // TransactionStatus is object used to store notification from midtrans type TransactionStatus struct { ID uint64 `json:"id" gorm:"primary_key"` - CreatedAt time.Time `json:"created_at" gorm:"not null;default:CURRENT_TIMESTAMP"` - UpdatedAt time.Time `json:"updated_at" gorm:"not null;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"` + CreatedAt time.Time `json:"created_at" gorm:"not null;"` + UpdatedAt time.Time `json:"updated_at" gorm:"not null;"` StatusCode string `json:"status_code" gorm:"not null"` StatusMessage string `json:"status_message" gorm:"type:text;not null"` SignKey string `json:"signature_key" gorm:"type:text;column:signature_key;not null"` diff --git a/go.mod b/go.mod index 1c37f75..f1c4e0c 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/go-sql-driver/mysql v1.5.0 github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.4 - github.com/jinzhu/gorm v1.9.12 github.com/lib/pq v1.3.0 // indirect github.com/rs/cors v1.7.0 github.com/rs/zerolog v1.18.0 @@ -19,6 +18,8 @@ require ( golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 // indirect golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect gopkg.in/yaml.v2 v2.2.8 + gorm.io/driver/sqlite v1.1.4 + gorm.io/gorm v1.21.11 ) replace github.com/veritrans/go-midtrans v0.0.0-20200303064216-54da2d269748 => github.com/schoters/go-midtrans v0.0.0-20200301123106-412075ea875d diff --git a/go.sum b/go.sum index ba0a11a..d75f113 100644 --- a/go.sum +++ b/go.sum @@ -68,12 +68,13 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= -github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= +github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -95,6 +96,8 @@ github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= +github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -232,4 +235,11 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= +gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= +gorm.io/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q= +gorm.io/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.21.11 h1:CxkXW6Cc+VIBlL8yJEHq+Co4RYXdSLiMKNvgoZPjLK4= +gorm.io/gorm v1.21.11/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/invoice/invoice.go b/invoice/invoice.go index e777b55..b7c9a08 100644 --- a/invoice/invoice.go +++ b/invoice/invoice.go @@ -5,6 +5,8 @@ import ( "encoding/json" "time" + "gorm.io/gorm" + "github.com/imrenagi/go-payment" "github.com/imrenagi/go-payment/config" @@ -121,7 +123,7 @@ func (i *Invoice) Clear() { // AfterFind assign a state controller after the entity is fetched from // database -func (i *Invoice) AfterFind() error { +func (i *Invoice) AfterFind(tx *gorm.DB) error { i.StateController = NewState(i.State.String()) return nil } diff --git a/server/server.go b/server/server.go index 1d3ab85..3f076e5 100644 --- a/server/server.go +++ b/server/server.go @@ -11,7 +11,7 @@ import ( "github.com/imrenagi/go-payment/gateway/xendit" "github.com/imrenagi/go-payment/invoice" "github.com/imrenagi/go-payment/manage" - "github.com/jinzhu/gorm" + "gorm.io/gorm" mgo "github.com/veritrans/go-midtrans" ) diff --git a/types.go b/types.go index 1c7e7c4..d609221 100644 --- a/types.go +++ b/types.go @@ -5,8 +5,8 @@ import "time" // Model is base for database struct type Model struct { ID uint64 `json:"id" gorm:"primary_key"` - CreatedAt time.Time `json:"created_at" gorm:"not null;default:CURRENT_TIMESTAMP"` - UpdatedAt time.Time `json:"updated_at" gorm:"not null;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"` + CreatedAt time.Time `json:"created_at" gorm:"not null;"` + UpdatedAt time.Time `json:"updated_at" gorm:"not null;"` DeletedAt *time.Time `json:"deleted_at" sql:"index"` } diff --git a/util/db/mysql/conn.go b/util/db/mysql/conn.go deleted file mode 100644 index 854f167..0000000 --- a/util/db/mysql/conn.go +++ /dev/null @@ -1,34 +0,0 @@ -package mysql - -import ( - "fmt" - - // Adding mysql driver - _ "github.com/go-sql-driver/mysql" - "github.com/imrenagi/go-payment/util/localconfig" - "github.com/jinzhu/gorm" - - // Mysql dialect for gorm - _ "github.com/jinzhu/gorm/dialects/mysql" -) - -// URI return mysql uri -func URI(creds localconfig.DBCredential) string { - return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=true&multiStatements=true", - creds.UserName, - creds.Password, - creds.Host, - creds.Port, - creds.DBName) -} - -//NewGorm return gorm DB connection to mysql -func NewGorm(creds localconfig.DBCredential) *gorm.DB { - dbURL := URI(creds) - db, err := gorm.Open("mysql", dbURL) - if err != nil { - panic(fmt.Sprintf("gorm cant open connection to mysql: %v", err)) - } - - return db -}