refactors data access layer to use pop ORM for eager loading, adds book titles rented to renters in response body
This commit is contained in:
@@ -1 +1,2 @@
|
||||
.env
|
||||
.DS_Store
|
||||
|
||||
@@ -10,9 +10,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/davidlick/bookish/bookish-server/cmd/http"
|
||||
"github.com/davidlick/bookish/bookish-server/inventory"
|
||||
"github.com/davidlick/bookish/bookish-server/mysql"
|
||||
"github.com/davidlick/bookish/bookish-server/rental"
|
||||
"github.com/davidlick/bookish/bookish-server/renter"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -43,7 +44,7 @@ func init() {
|
||||
|
||||
func main() {
|
||||
// Connect to application database and create store.
|
||||
appDSN := fmt.Sprintf("%s:%s@tcp(%s:%s)/bookish?parseTime=True&loc=Local",
|
||||
appDSN := fmt.Sprintf("mysql://%s:%s@tcp(%s:%s)/bookish?parseTime=true&loc=local&multiStatements=true",
|
||||
cfg.DBUser,
|
||||
cfg.DBPass,
|
||||
cfg.DBHost,
|
||||
@@ -56,15 +57,15 @@ func main() {
|
||||
|
||||
// Build domain services.
|
||||
renterService := renter.NewService(appDB)
|
||||
inventoryService := inventory.NewService(appDB)
|
||||
rentalService := rental.NewService(appDB)
|
||||
|
||||
// Initialize server.
|
||||
server := http.Server{
|
||||
Port: cfg.APIPort,
|
||||
BooksHost: cfg.BooksHost,
|
||||
Logger: logger,
|
||||
Renter: renterService,
|
||||
Inventory: inventoryService,
|
||||
Renters: renterService,
|
||||
Rentals: rentalService,
|
||||
}
|
||||
|
||||
// Create channels to listen for OS signals.
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
bookish "github.com/davidlick/bookish/bookish-server"
|
||||
"github.com/davidlick/bookish/bookish-server/inventory"
|
||||
"github.com/davidlick/bookish/bookish-server/rental"
|
||||
"github.com/davidlick/bookish/bookish-server/renter"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
@@ -21,8 +21,8 @@ type Server struct {
|
||||
Port string
|
||||
BooksHost string
|
||||
Logger *logrus.Logger
|
||||
Renter renter.Service
|
||||
Inventory inventory.Service
|
||||
Renters renter.Service
|
||||
Rentals rental.Service
|
||||
// LibraryMap holds a map of values that are returned by the books API. This is used to check
|
||||
// if a book exists in the library.
|
||||
LibraryMap struct {
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/davidlick/bookish/bookish-server/internal"
|
||||
"github.com/davidlick/bookish/bookish-server/mysql"
|
||||
@@ -36,13 +35,7 @@ func (s *Server) renterCtx(next http.Handler) http.Handler {
|
||||
ctx := r.Context()
|
||||
id := chi.URLParam(r, "renterId")
|
||||
|
||||
renterId, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
renter, err := s.Renter.FetchRenter(renterId)
|
||||
renter, err := s.Renters.FetchRenter(id)
|
||||
if err != nil && errors.Is(mysql.ErrNotFound, err) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
|
||||
+22
-7
@@ -2,12 +2,13 @@ package http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
bookish "github.com/davidlick/bookish/bookish-server"
|
||||
"github.com/davidlick/bookish/bookish-server/internal"
|
||||
"github.com/davidlick/bookish/bookish-server/inventory"
|
||||
"github.com/davidlick/bookish/bookish-server/mysql"
|
||||
"github.com/davidlick/bookish/bookish-server/rental"
|
||||
"github.com/gobuffalo/uuid"
|
||||
)
|
||||
|
||||
// checkoutBook is used to checkout a book for a renter.
|
||||
@@ -25,10 +26,16 @@ func (s *Server) checkoutBook(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err := s.Inventory.CheckoutBook(renter.ID, bookTitle)
|
||||
id, err := uuid.FromString(renter.ID)
|
||||
if err != nil {
|
||||
if errors.Is(inventory.ErrUnavailableBook, err) {
|
||||
http.Error(w, err.Error(), http.StatusForbidden)
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.Rentals.CheckoutBook(id, bookTitle)
|
||||
if err != nil {
|
||||
if errors.Is(rental.ErrUnavailableBook, err) {
|
||||
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -52,9 +59,17 @@ func (s *Server) returnBook(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err := s.Inventory.ReturnBook(renter.ID, bookTitle)
|
||||
id, err := uuid.FromString(renter.ID)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.Rentals.ReturnBook(id, bookTitle)
|
||||
if err != nil && errors.Is(mysql.ErrNotFound, err) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
bookish "github.com/davidlick/bookish/bookish-server"
|
||||
"github.com/davidlick/bookish/bookish-server/internal"
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
// registerRenter creates a record of a new renter.
|
||||
@@ -24,14 +25,14 @@ func (s *Server) registerRenter(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
id, err := s.Renter.RegisterRenter(renter.Name, renter.Address, renter.Email, renter.PhoneNumber)
|
||||
id, err := s.Renters.RegisterRenter(renter.Name, renter.Address, renter.Email, renter.PhoneNumber)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resp := struct {
|
||||
ID int `json:"renterId"`
|
||||
ID uuid.UUID `json:"renterId"`
|
||||
}{ID: id}
|
||||
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
@@ -39,7 +40,7 @@ func (s *Server) registerRenter(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// listRenters lists all renters registered in the API.
|
||||
func (s *Server) listRenters(w http.ResponseWriter, r *http.Request) {
|
||||
rr, err := s.Renter.ListRenters()
|
||||
rr, err := s.Renters.ListRenters()
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
development:
|
||||
dialect: mysql
|
||||
database: bookish
|
||||
user: root
|
||||
password: 123pass
|
||||
host: db
|
||||
+17
-2
@@ -3,13 +3,28 @@ module github.com/davidlick/bookish/bookish-server
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/cockroachdb/cockroach-go v0.0.0-20200528011702-6cc4ff37a11e // indirect
|
||||
github.com/fatih/color v1.9.0 // indirect
|
||||
github.com/go-chi/chi v4.1.1+incompatible
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/gobuffalo/envy v1.9.0 // indirect
|
||||
github.com/gobuffalo/fizz v1.9.10 // indirect
|
||||
github.com/gobuffalo/flect v0.2.1 // indirect
|
||||
github.com/gobuffalo/genny v0.6.0 // indirect
|
||||
github.com/gobuffalo/nulls v0.4.0
|
||||
github.com/gobuffalo/packd v1.0.0 // indirect
|
||||
github.com/gobuffalo/pop v4.13.1+incompatible
|
||||
github.com/gobuffalo/pop/v5 v5.1.3
|
||||
github.com/gobuffalo/uuid v2.0.5+incompatible
|
||||
github.com/gobuffalo/validate v2.0.4+incompatible // indirect
|
||||
github.com/gobuffalo/validate/v3 v3.1.0
|
||||
github.com/gofrs/uuid v3.3.0+incompatible
|
||||
github.com/golang/mock v1.4.3
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 // indirect
|
||||
github.com/stretchr/testify v1.6.0
|
||||
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
)
|
||||
|
||||
@@ -1,41 +1,301 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14=
|
||||
github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||
github.com/cockroachdb/cockroach-go v0.0.0-20200528011702-6cc4ff37a11e h1:U/LmtPG8RXOORWPJbJWJeSMW1DrnpkovQTuW/Rya/SA=
|
||||
github.com/cockroachdb/cockroach-go v0.0.0-20200528011702-6cc4ff37a11e/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davidlick/bookish v0.0.0-20200529020827-a06b4d70abb9 h1:4xzRnQvEl1tG3ypktRZHO6zoifkZefklaiBv4e1cTZc=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-chi/chi v4.1.1+incompatible h1:MmTgB0R8Bt/jccxp+t6S/1VGIKdJw5J74CK/c9tTfA4=
|
||||
github.com/go-chi/chi v4.1.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gobuffalo/attrs v0.1.0/go.mod h1:fmNpaWyHM0tRm8gCZWKx8yY9fvaNLo2PyzBNSrBZ5Hw=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
|
||||
github.com/gobuffalo/envy v1.8.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
|
||||
github.com/gobuffalo/envy v1.9.0 h1:eZR0DuEgVLfeIb1zIKt3bT4YovIMf9O9LXQeCZLXpqE=
|
||||
github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
|
||||
github.com/gobuffalo/fizz v1.9.8/go.mod h1:w1FEn1yKNVCc49KnADGyYGRPH7jFON3ak4Bj1yUudHo=
|
||||
github.com/gobuffalo/fizz v1.9.10 h1:B/p28Qy2VxFq6zr1EXWuxwI4dl0PUA/xW2dY+XdaDMY=
|
||||
github.com/gobuffalo/fizz v1.9.10/go.mod h1:J2XGPO0AfJ1zKw7+2BA+6FEGAkyEsdCOLvN93WCT2WI=
|
||||
github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
|
||||
github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
|
||||
github.com/gobuffalo/flect v0.2.1 h1:GPoRjEN0QObosV4XwuoWvSd5uSiL0N3e91/xqyY4crQ=
|
||||
github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
|
||||
github.com/gobuffalo/genny v0.2.0/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
|
||||
github.com/gobuffalo/genny v0.3.0/go.mod h1:ywJ2CoXrTZj7rbS8HTbzv7uybnLKlsNSBhEQ+yFI3E8=
|
||||
github.com/gobuffalo/genny v0.6.0 h1:d7c6d66ZrTHHty01hDX1/TcTWvAJQxRZl885KWX5kHY=
|
||||
github.com/gobuffalo/genny v0.6.0/go.mod h1:Vigx9VDiNscYpa/LwrURqGXLSIbzTfapt9+K6gF1kTA=
|
||||
github.com/gobuffalo/genny/v2 v2.0.5/go.mod h1:kRkJuAw9mdI37AiEYjV4Dl+TgkBDYf8HZVjLkqe5eBg=
|
||||
github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI=
|
||||
github.com/gobuffalo/github_flavored_markdown v1.1.0 h1:8Zzj4fTRl/OP2R7sGerzSf6g2nEJnaBEJe7UAOiEvbQ=
|
||||
github.com/gobuffalo/github_flavored_markdown v1.1.0/go.mod h1:TSpTKWcRTI0+v7W3x8dkSKMLJSUpuVitlptCkpeY8ic=
|
||||
github.com/gobuffalo/gogen v0.2.0/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
|
||||
github.com/gobuffalo/helpers v0.2.2/go.mod h1:xYbzUdCUpVzLwLnqV8HIjT6hmG0Cs7YIBCJkNM597jw=
|
||||
github.com/gobuffalo/helpers v0.2.4/go.mod h1:NX7v27yxPDOPTgUFYmJ5ow37EbxdoLraucOGvMNawyk=
|
||||
github.com/gobuffalo/helpers v0.5.0/go.mod h1:stpgxJ2C7T99NLyAxGUnYMM2zAtBk5NKQR0SIbd05j4=
|
||||
github.com/gobuffalo/helpers v0.6.0 h1:CL1xOSGeKCaKD1IUpo4RfrkDU83kmkMG4H3dXAS7dw0=
|
||||
github.com/gobuffalo/helpers v0.6.0/go.mod h1:pncVrer7x/KRvnL5aJABLAuT/RhKRR9klL6dkUOhyv8=
|
||||
github.com/gobuffalo/helpers v0.6.1 h1:LLcL4BsiyDQYtMRUUpyFdBFvFXQ6hNYOpwrcYeilVWM=
|
||||
github.com/gobuffalo/helpers v0.6.1/go.mod h1:wInbDi0vTJKZBviURTLRMFLE4+nF2uRuuL2fnlYo7w4=
|
||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
|
||||
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gqc=
|
||||
github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM=
|
||||
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
||||
github.com/gobuffalo/mapi v1.1.0/go.mod h1:pqQ1XAqvpy/JYtRwoieNps2yU8MFiMxBUpAm2FBtQ50=
|
||||
github.com/gobuffalo/nulls v0.2.0/go.mod h1:w4q8RoSCEt87Q0K0sRIZWYeIxkxog5mh3eN3C/n+dUc=
|
||||
github.com/gobuffalo/nulls v0.4.0 h1:xi+JHGWIetYqLmS520dSWc8Ifj1P0aNXKTVDMVsPXmw=
|
||||
github.com/gobuffalo/nulls v0.4.0/go.mod h1:2KmsoLnMrxpwPLN5LmBbm6tmttHSIZr/v/OdGsATM3M=
|
||||
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
||||
github.com/gobuffalo/packd v0.2.0/go.mod h1:k2CkHP3bjbqL2GwxwhxUy1DgnlbW644hkLC9iIUvZwY=
|
||||
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
|
||||
github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM=
|
||||
github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI=
|
||||
github.com/gobuffalo/packr/v2 v2.4.0/go.mod h1:ra341gygw9/61nSjAbfwcwh8IrYL4WmR4IsPkPBhQiY=
|
||||
github.com/gobuffalo/packr/v2 v2.5.2/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08=
|
||||
github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
|
||||
github.com/gobuffalo/plush v3.8.2+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
||||
github.com/gobuffalo/plush v3.8.3+incompatible h1:kzvUTnFPhwyfPEsx7U7LI05/IIslZVGnAlMA1heWub8=
|
||||
github.com/gobuffalo/plush v3.8.3+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
|
||||
github.com/gobuffalo/plush/v4 v4.0.0 h1:ZHdmfr2R7DQ77XzWZK2PGKJOXm9NRy21EZ6Rw7FhuNw=
|
||||
github.com/gobuffalo/plush/v4 v4.0.0/go.mod h1:ErFS3UxKqEb8fpFJT7lYErfN/Nw6vHGiDMTjxpk5bQ0=
|
||||
github.com/gobuffalo/plushgen v0.1.2/go.mod h1:3U71v6HWZpVER1nInTXeAwdoRNsRd4W8aeIa1Lyp+Bk=
|
||||
github.com/gobuffalo/pop v4.13.1+incompatible h1:AhbqPxNOBN/DBb2DBaiBqzOXIBQXxEYzngHHJ+ytP4g=
|
||||
github.com/gobuffalo/pop v4.13.1+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
|
||||
github.com/gobuffalo/pop/v5 v5.1.3 h1:XwXm2sJScNqc6dJOaMTAILECw6nqsf3cooNdleEcoWw=
|
||||
github.com/gobuffalo/pop/v5 v5.1.3/go.mod h1:fzUpBhQE48+kPczDbuJIuOCSS7OMqChoaGR6wj2j7Nc=
|
||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
||||
github.com/gobuffalo/tags v2.1.0+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
|
||||
github.com/gobuffalo/tags v2.1.7+incompatible h1:GUxxh34f9SI4U0Pj3ZqvopO9SlzuqSf+g4ZGSPSszt4=
|
||||
github.com/gobuffalo/tags v2.1.7+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
|
||||
github.com/gobuffalo/tags/v3 v3.0.2 h1:gxE6c6fA5radwQeg59aPIeYgCG8YA8AZd3Oh6fh5UXA=
|
||||
github.com/gobuffalo/tags/v3 v3.0.2/go.mod h1:ZQeN6TCTiwAFnS0dNcbDtSgZDwNKSpqajvVtt6mlYpA=
|
||||
github.com/gobuffalo/tags/v3 v3.1.0 h1:mzdCYooN2VsLRr8KIAdEZ1lh1Py7JSMsiEGCGata2AQ=
|
||||
github.com/gobuffalo/tags/v3 v3.1.0/go.mod h1:ZQeN6TCTiwAFnS0dNcbDtSgZDwNKSpqajvVtt6mlYpA=
|
||||
github.com/gobuffalo/uuid v2.0.5+incompatible h1:c5uWRuEnYggYCrT9AJm0U2v1QTG7OVDAvxhj8tIV5Gc=
|
||||
github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
|
||||
github.com/gobuffalo/validate v1.0.0 h1:Xdf2irctxenMaXZrgA13Aeo1sUD9+sgaKKVOaMauZ2U=
|
||||
github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM=
|
||||
github.com/gobuffalo/validate v2.0.4+incompatible h1:ZTxozrIw8qQ5nfhShmc4izjYPTsPhfdXTdhXOd5OS9o=
|
||||
github.com/gobuffalo/validate v2.0.4+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM=
|
||||
github.com/gobuffalo/validate/v3 v3.0.0 h1:dF7Bg8NMF9Zv8bZvUMXYJXxZdj+eSZ8z/lGM7/jVFUE=
|
||||
github.com/gobuffalo/validate/v3 v3.0.0/go.mod h1:HFpjq+AIiA2RHoQnQVTFKF/ZpUPXwyw82LgyDPxQ9r0=
|
||||
github.com/gobuffalo/validate/v3 v3.1.0 h1:/QQN920PciCfBs3aywtJTvDTHmBFMKoiwkshUWa/HLQ=
|
||||
github.com/gobuffalo/validate/v3 v3.1.0/go.mod h1:HFpjq+AIiA2RHoQnQVTFKF/ZpUPXwyw82LgyDPxQ9r0=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
|
||||
github.com/jackc/pgconn v1.3.2/go.mod h1:LvCquS3HbBKwgl7KbX9KyqEIumJAbm1UMcTvGaIf3bM=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
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.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.4.0 h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cSdjkOY=
|
||||
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w=
|
||||
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4=
|
||||
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200219183655-46282727080f/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b h1:IYiJPiJfzktmDAO1HQiwjMjwjlYKHAL7KzeD544RJPs=
|
||||
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@@ -43,9 +303,37 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190613204242-ed0dc450797f/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gobuffalo/nulls"
|
||||
"github.com/gobuffalo/uuid"
|
||||
)
|
||||
|
||||
type Rental struct {
|
||||
ID uuid.UUID `db:"id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
BookTitle string `db:"book_title"`
|
||||
RenterID uuid.UUID `db:"renter_id"`
|
||||
RentalDate time.Time `db:"rental_date"`
|
||||
ReturnDate nulls.Time `db:"return_date"`
|
||||
Renter *Renter `belongs_to:"renter"`
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gobuffalo/uuid"
|
||||
)
|
||||
|
||||
type Renter struct {
|
||||
ID uuid.UUID `json:"id" db:"id"`
|
||||
CreatedAt time.Time `json:"-" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"-" db:"updated_at"`
|
||||
Name string `json:"name" db:"name"`
|
||||
Address string `json:"address" db:"address"`
|
||||
Email string `json:"email" db:"email"`
|
||||
PhoneNumber string `json:"phoneNumber" db:"phone_number"`
|
||||
Rentals []Rental `json:"rentals" has_many:"rentals"`
|
||||
}
|
||||
@@ -5,6 +5,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("no renter found")
|
||||
ErrNotFound = errors.New("empty result")
|
||||
ErrAlreadyExists = errors.New("the provided value already exists")
|
||||
)
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IsBookAvailable queries the database for available books.
|
||||
func (s *store) IsBookAvailable(title string) (available bool, err error) {
|
||||
q := `
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
rentals
|
||||
WHERE
|
||||
book_title = ?
|
||||
AND return_date IS NULL;
|
||||
`
|
||||
|
||||
var rr []struct {
|
||||
ID int `db:"id"`
|
||||
RenterID int `db:"renter_id"`
|
||||
RentalDate time.Time `db:"rental_date"`
|
||||
ReturnDate sql.NullTime `db:"return_date"`
|
||||
BookTitle string `db:"book_title"`
|
||||
}
|
||||
|
||||
err = s.Select(&rr, q, title)
|
||||
if err != nil {
|
||||
// If no records are returned then the book is available for rent.
|
||||
if errors.Is(sql.ErrNoRows, err) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// If 5 books are rented out this book is not available.
|
||||
if len(rr) > 4 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// RenterAlreadyCheckedOut queries the database for the given renterId and title. If a record is returned checkedOut will be true.
|
||||
func (s *store) RenterAlreadyCheckedOut(renterId int, title string) (checkedOut bool, err error) {
|
||||
q := `
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
rentals
|
||||
WHERE
|
||||
renter_id = ?
|
||||
AND book_title = ?
|
||||
AND return_date IS NULL;
|
||||
`
|
||||
|
||||
var rr []struct {
|
||||
ID int `db:"id"`
|
||||
RenterID int `db:"renter_id"`
|
||||
RentalDate time.Time `db:"rental_date"`
|
||||
ReturnDate sql.NullTime `db:"return_date"`
|
||||
BookTitle string `db:"book_title"`
|
||||
}
|
||||
|
||||
err = s.Select(&rr, q, renterId, title)
|
||||
if err != nil {
|
||||
if errors.Is(sql.ErrNoRows, err) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
if len(rr) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// CheckoutBook inserts a record indicating the book is checked out to the renter.
|
||||
func (s *store) CheckoutBook(renterId int, title string) error {
|
||||
q := `
|
||||
INSERT INTO
|
||||
rentals (renter_id, rental_date, book_title)
|
||||
VALUES
|
||||
(?, ?, ?);
|
||||
`
|
||||
|
||||
_, err := s.Exec(q, renterId, time.Now(), title)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReturnBook sets the return_date field to now indicating the book has been returned.
|
||||
func (s *store) ReturnBook(renterId int, title string) error {
|
||||
q := `
|
||||
UPDATE
|
||||
rentals
|
||||
SET
|
||||
return_date = ?
|
||||
WHERE
|
||||
renter_id = ?
|
||||
AND book_title = ?;
|
||||
`
|
||||
|
||||
_, err := s.Exec(q, time.Now(), renterId, title)
|
||||
return err
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/gobuffalo/pop"
|
||||
)
|
||||
|
||||
// store holds a connection to the application database.
|
||||
type store struct {
|
||||
*sqlx.DB
|
||||
*pop.Connection
|
||||
}
|
||||
|
||||
// NewStore creates a new connection to the database and returns a store containing the connection.
|
||||
func NewStore(dsn string) (s *store, err error) {
|
||||
db, err := sqlx.Open("mysql", dsn)
|
||||
db, err := pop.Connect("development")
|
||||
if err != nil {
|
||||
return s, err
|
||||
return &store{}, err
|
||||
}
|
||||
|
||||
return &store{db}, nil
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/davidlick/bookish/bookish-server/models"
|
||||
"github.com/gobuffalo/nulls"
|
||||
"github.com/gobuffalo/uuid"
|
||||
)
|
||||
|
||||
// IsBookAvailable queries the database for available books.
|
||||
func (s *store) IsBookAvailable(title string) (available bool, err error) {
|
||||
rr := []models.Rental{}
|
||||
err = s.Where(fmt.Sprintf("book_title = '%s'", title)).Where("return_date IS NULL").All(&rr)
|
||||
if err != nil {
|
||||
// If no records are returned then the book is available for rent.
|
||||
if errors.Is(sql.ErrNoRows, err) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// If 5 books are rented out this book is not available.
|
||||
if len(rr) > 4 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// RenterAlreadyCheckedOut queries the database for the given renterId and title. If a record is returned checkedOut will be true.
|
||||
func (s *store) RenterAlreadyCheckedOut(renterId uuid.UUID, title string) (checkedOut bool, err error) {
|
||||
rr := []models.Rental{}
|
||||
err = s.Where(fmt.Sprintf("renter_id = '%s'", renterId)).
|
||||
Where(fmt.Sprintf("book_title = '%s'", title)).
|
||||
Where("return_date IS NULL").
|
||||
All(&rr)
|
||||
if err != nil {
|
||||
// If no records are returned then the book is available for rent.
|
||||
if errors.Is(sql.ErrNoRows, err) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
// If 5 books are rented out this book is not available.
|
||||
if len(rr) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// CheckoutBook inserts a record indicating the book is checked out to the renter.
|
||||
func (s *store) CheckoutBook(renterId uuid.UUID, title string) error {
|
||||
r := models.Rental{BookTitle: title, RenterID: renterId, RentalDate: time.Now()}
|
||||
err := s.Create(&r)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReturnBook sets the return_date field to now indicating the book has been returned.
|
||||
func (s *store) ReturnBook(renterId uuid.UUID, title string) error {
|
||||
r := models.Rental{}
|
||||
err := s.Where(fmt.Sprintf("renter_id = '%s'", renterId)).
|
||||
Where(fmt.Sprintf("book_title = '%s'", title)).
|
||||
Where("return_date IS NULL").
|
||||
First(&r)
|
||||
if err != nil {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
r.ReturnDate = nulls.Time{Time: time.Now(), Valid: true}
|
||||
|
||||
err = s.Save(&r)
|
||||
return err
|
||||
}
|
||||
@@ -4,63 +4,43 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
bookish "github.com/davidlick/bookish/bookish-server"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/davidlick/bookish/bookish-server/models"
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
// ListAll returns all renter records.
|
||||
func (s *store) ListAll() (rr []bookish.Renter, err error) {
|
||||
q := `
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
renters
|
||||
`
|
||||
|
||||
err = s.Select(&rr, q)
|
||||
func (s *store) ListAll() (rr []models.Renter, err error) {
|
||||
err = s.Eager().All(&rr)
|
||||
if err != nil && errors.Is(sql.ErrNoRows, err) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FetchDetails queries the database for a specific renter.
|
||||
func (s *store) FetchDetails(id int) (r bookish.Renter, err error) {
|
||||
q := `
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
renters
|
||||
WHERE
|
||||
id = ?
|
||||
`
|
||||
|
||||
err = s.Get(&r, q, id)
|
||||
if err != nil && errors.Is(sql.ErrNoRows, err) {
|
||||
return bookish.Renter{}, ErrNotFound
|
||||
}
|
||||
func (s *store) FetchDetails(id string) (r models.Renter, err error) {
|
||||
err = s.Eager().Find(&r, id)
|
||||
return
|
||||
}
|
||||
|
||||
// New inserts a record for a new renter. If that renter already exists it returns an ErrAlreadyExists.
|
||||
func (s *store) New(name string, address string, email string, phoneNumber string) (id int, err error) {
|
||||
q := `
|
||||
INSERT INTO
|
||||
renters (name, address, email, phone_number)
|
||||
VALUES
|
||||
(?, ?, ?, ?)
|
||||
`
|
||||
|
||||
result, err := s.Exec(q, name, address, email, phoneNumber)
|
||||
if err != nil {
|
||||
if _, ok := err.(*mysql.MySQLError); ok {
|
||||
return 0, ErrAlreadyExists
|
||||
}
|
||||
func (s *store) New(name string, address string, email string, phoneNumber string) (id uuid.UUID, err error) {
|
||||
r := models.Renter{
|
||||
Name: name,
|
||||
Address: address,
|
||||
Email: email,
|
||||
PhoneNumber: phoneNumber,
|
||||
}
|
||||
|
||||
lastId, err := result.LastInsertId()
|
||||
// Create the new renter.
|
||||
err = s.Create(&r)
|
||||
if err != nil {
|
||||
return id, err
|
||||
return
|
||||
}
|
||||
return int(lastId), nil
|
||||
|
||||
// Get the last renter created.
|
||||
r = models.Renter{}
|
||||
err = s.Last(&r)
|
||||
return r.ID, err
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package inventory
|
||||
package rental
|
||||
|
||||
import "errors"
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package inventory
|
||||
package rental
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
// Storage defines behavior for interacting with the inventory store.
|
||||
type Storage interface {
|
||||
IsBookAvailable(title string) (available bool, err error)
|
||||
RenterAlreadyCheckedOut(renterId int, title string) (checkedOut bool, err error)
|
||||
CheckoutBook(renterId int, title string) error
|
||||
ReturnBook(renterId int, title string) error
|
||||
RenterAlreadyCheckedOut(renterId uuid.UUID, title string) (checkedOut bool, err error)
|
||||
CheckoutBook(renterId uuid.UUID, title string) error
|
||||
ReturnBook(renterId uuid.UUID, title string) error
|
||||
}
|
||||
|
||||
type service struct {
|
||||
@@ -15,8 +21,8 @@ type service struct {
|
||||
// Service defines behavior for interacting with the inventory service.
|
||||
type Service interface {
|
||||
IsBookAvailable(title string) (available bool, err error)
|
||||
CheckoutBook(renterId int, title string) error
|
||||
ReturnBook(renterId int, title string) error
|
||||
CheckoutBook(renterId uuid.UUID, title string) error
|
||||
ReturnBook(renterId uuid.UUID, title string) error
|
||||
}
|
||||
|
||||
// NewService creates a new inventory service.
|
||||
@@ -32,7 +38,7 @@ func (s *service) IsBookAvailable(title string) (available bool, err error) {
|
||||
}
|
||||
|
||||
// CheckoutBook checks a book out to a renter.
|
||||
func (s *service) CheckoutBook(renterId int, title string) error {
|
||||
func (s *service) CheckoutBook(renterId uuid.UUID, title string) error {
|
||||
available, err := s.IsBookAvailable(title)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -46,6 +52,7 @@ func (s *service) CheckoutBook(renterId int, title string) error {
|
||||
// If there was an error or the book is checked out by the renter already we'll
|
||||
// say the book is unavailable.
|
||||
if err != nil || checkedOut {
|
||||
fmt.Println("unavailable book", err, checkedOut)
|
||||
return ErrUnavailableBook
|
||||
}
|
||||
|
||||
@@ -53,6 +60,6 @@ func (s *service) CheckoutBook(renterId int, title string) error {
|
||||
}
|
||||
|
||||
// ReturnBook returns a book for a renter.
|
||||
func (s *service) ReturnBook(renterId int, title string) error {
|
||||
func (s *service) ReturnBook(renterId uuid.UUID, title string) error {
|
||||
return s.store.ReturnBook(renterId, title)
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: inventory.go
|
||||
// Source: rental.go
|
||||
|
||||
// Package inventory is a generated GoMock package.
|
||||
package inventory
|
||||
// Package rental is a generated GoMock package.
|
||||
package rental
|
||||
|
||||
import (
|
||||
uuid "github.com/gofrs/uuid"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
@@ -48,7 +49,7 @@ func (mr *MockStorageMockRecorder) IsBookAvailable(title interface{}) *gomock.Ca
|
||||
}
|
||||
|
||||
// RenterAlreadyCheckedOut mocks base method
|
||||
func (m *MockStorage) RenterAlreadyCheckedOut(renterId int, title string) (bool, error) {
|
||||
func (m *MockStorage) RenterAlreadyCheckedOut(renterId uuid.UUID, title string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RenterAlreadyCheckedOut", renterId, title)
|
||||
ret0, _ := ret[0].(bool)
|
||||
@@ -63,7 +64,7 @@ func (mr *MockStorageMockRecorder) RenterAlreadyCheckedOut(renterId, title inter
|
||||
}
|
||||
|
||||
// CheckoutBook mocks base method
|
||||
func (m *MockStorage) CheckoutBook(renterId int, title string) error {
|
||||
func (m *MockStorage) CheckoutBook(renterId uuid.UUID, title string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CheckoutBook", renterId, title)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -77,7 +78,7 @@ func (mr *MockStorageMockRecorder) CheckoutBook(renterId, title interface{}) *go
|
||||
}
|
||||
|
||||
// ReturnBook mocks base method
|
||||
func (m *MockStorage) ReturnBook(renterId int, title string) error {
|
||||
func (m *MockStorage) ReturnBook(renterId uuid.UUID, title string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReturnBook", renterId, title)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -129,7 +130,7 @@ func (mr *MockServiceMockRecorder) IsBookAvailable(title interface{}) *gomock.Ca
|
||||
}
|
||||
|
||||
// CheckoutBook mocks base method
|
||||
func (m *MockService) CheckoutBook(renterId int, title string) error {
|
||||
func (m *MockService) CheckoutBook(renterId uuid.UUID, title string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CheckoutBook", renterId, title)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -143,7 +144,7 @@ func (mr *MockServiceMockRecorder) CheckoutBook(renterId, title interface{}) *go
|
||||
}
|
||||
|
||||
// ReturnBook mocks base method
|
||||
func (m *MockService) ReturnBook(renterId int, title string) error {
|
||||
func (m *MockService) ReturnBook(renterId uuid.UUID, title string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ReturnBook", renterId, title)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -1,18 +1,18 @@
|
||||
package inventory
|
||||
package rental
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInventory_IsBookAvailable(t *testing.T) {
|
||||
func TestRental_IsBookAvailable(t *testing.T) {
|
||||
testCases := []struct {
|
||||
TestName string
|
||||
Title string
|
||||
RenterId int
|
||||
Available bool
|
||||
Error error
|
||||
}{
|
||||
@@ -50,10 +50,9 @@ func TestInventory_IsBookAvailable(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInventory_CheckoutBook(t *testing.T) {
|
||||
func TestRental_CheckoutBook(t *testing.T) {
|
||||
testCases := []struct {
|
||||
TestName string
|
||||
RenterId int
|
||||
Title string
|
||||
Available bool
|
||||
AvailableError error
|
||||
@@ -63,27 +62,23 @@ func TestInventory_CheckoutBook(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
TestName: "success",
|
||||
RenterId: 1,
|
||||
Title: "Book #1",
|
||||
Available: true,
|
||||
},
|
||||
{
|
||||
TestName: "unavailable",
|
||||
RenterId: 2,
|
||||
Title: "Book #2",
|
||||
Available: false,
|
||||
Error: ErrUnavailableBook,
|
||||
},
|
||||
{
|
||||
TestName: "availability_error",
|
||||
RenterId: 3,
|
||||
Title: "Book #3",
|
||||
AvailableError: errors.New("test error"),
|
||||
Error: errors.New("test error"),
|
||||
},
|
||||
{
|
||||
TestName: "checked-out",
|
||||
RenterId: 4,
|
||||
Title: "Book #4",
|
||||
Available: true,
|
||||
CheckedOut: true,
|
||||
@@ -91,7 +86,6 @@ func TestInventory_CheckoutBook(t *testing.T) {
|
||||
},
|
||||
{
|
||||
TestName: "failure",
|
||||
RenterId: 4,
|
||||
Title: "Book #4",
|
||||
Available: true,
|
||||
Error: errors.New("test error"),
|
||||
@@ -103,38 +97,40 @@ func TestInventory_CheckoutBook(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
renterId, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
mockStorage := NewMockStorage(ctrl)
|
||||
mockStorage.EXPECT().IsBookAvailable(tc.Title).Return(tc.Available, tc.AvailableError)
|
||||
if tc.Available && tc.AvailableError == nil {
|
||||
mockStorage.EXPECT().RenterAlreadyCheckedOut(tc.RenterId, tc.Title).Return(tc.CheckedOut, tc.CheckedOutError)
|
||||
mockStorage.EXPECT().RenterAlreadyCheckedOut(renterId, tc.Title).Return(tc.CheckedOut, tc.CheckedOutError)
|
||||
if !tc.CheckedOut && tc.CheckedOutError == nil {
|
||||
mockStorage.EXPECT().CheckoutBook(tc.RenterId, tc.Title).Return(tc.Error)
|
||||
mockStorage.EXPECT().CheckoutBook(renterId, tc.Title).Return(tc.Error)
|
||||
}
|
||||
}
|
||||
|
||||
service := NewService(mockStorage)
|
||||
err := service.CheckoutBook(tc.RenterId, tc.Title)
|
||||
err = service.CheckoutBook(renterId, tc.Title)
|
||||
|
||||
assert.Equal(t, tc.Error, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInventory_ReturnBook(t *testing.T) {
|
||||
func TestRental_ReturnBook(t *testing.T) {
|
||||
testCases := []struct {
|
||||
TestName string
|
||||
RenterId int
|
||||
Title string
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
TestName: "success",
|
||||
RenterId: 1,
|
||||
Title: "Book #1",
|
||||
},
|
||||
{
|
||||
TestName: "failure",
|
||||
RenterId: 2,
|
||||
Title: "Book #2",
|
||||
Error: errors.New("test error"),
|
||||
},
|
||||
@@ -145,11 +141,16 @@ func TestInventory_ReturnBook(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
renterId, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
mockStorage := NewMockStorage(ctrl)
|
||||
mockStorage.EXPECT().ReturnBook(tc.RenterId, tc.Title).Return(tc.Error)
|
||||
mockStorage.EXPECT().ReturnBook(renterId, tc.Title).Return(tc.Error)
|
||||
|
||||
service := NewService(mockStorage)
|
||||
err := service.ReturnBook(tc.RenterId, tc.Title)
|
||||
err = service.ReturnBook(renterId, tc.Title)
|
||||
|
||||
assert.Equal(t, tc.Error, err)
|
||||
})
|
||||
@@ -2,9 +2,10 @@ package bookish_server
|
||||
|
||||
// Renter is an entity in the Bookish API wish rents books.
|
||||
type Renter struct {
|
||||
ID int `db:"id" json:"id"`
|
||||
ID string `db:"id" json:"id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Address string `db:"address" json:"address"`
|
||||
Email string `db:"email" json:"email"`
|
||||
PhoneNumber string `db:"phone_number" json:"phoneNumber"`
|
||||
Rentals []string `json:"rentals"`
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@ package renter
|
||||
|
||||
import (
|
||||
bookish "github.com/davidlick/bookish/bookish-server"
|
||||
"github.com/davidlick/bookish/bookish-server/models"
|
||||
"github.com/gobuffalo/uuid"
|
||||
)
|
||||
|
||||
// Storage defines behavior for interacting with the renter store.
|
||||
type Storage interface {
|
||||
ListAll() (rr []bookish.Renter, err error)
|
||||
FetchDetails(id int) (r bookish.Renter, err error)
|
||||
New(name string, address string, email string, phoneNumber string) (id int, err error)
|
||||
ListAll() (rr []models.Renter, err error)
|
||||
FetchDetails(id string) (r models.Renter, err error)
|
||||
New(name string, address string, email string, phoneNumber string) (id uuid.UUID, err error)
|
||||
}
|
||||
|
||||
type service struct {
|
||||
@@ -18,8 +20,8 @@ type service struct {
|
||||
// Service defines behavior for interacting with the renter service.
|
||||
type Service interface {
|
||||
ListRenters() (rr []bookish.Renter, err error)
|
||||
FetchRenter(id int) (r bookish.Renter, err error)
|
||||
RegisterRenter(fullName string, address string, email string, phoneNumber string) (id int, err error)
|
||||
FetchRenter(id string) (r bookish.Renter, err error)
|
||||
RegisterRenter(fullName string, address string, email string, phoneNumber string) (id uuid.UUID, err error)
|
||||
}
|
||||
|
||||
// NewService creates a new renter service.
|
||||
@@ -31,15 +33,50 @@ func NewService(s Storage) *service {
|
||||
|
||||
// ListRenters returns all renters from the renter store.
|
||||
func (s *service) ListRenters() (rr []bookish.Renter, err error) {
|
||||
return s.store.ListAll()
|
||||
renters, err := s.store.ListAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, renter := range renters {
|
||||
r := MutateRenterModel(renter)
|
||||
rr = append(rr, r)
|
||||
}
|
||||
|
||||
return rr, nil
|
||||
}
|
||||
|
||||
// FetchRenter returns a specific renter from the renter store.
|
||||
func (s *service) FetchRenter(id int) (r bookish.Renter, err error) {
|
||||
return s.store.FetchDetails(id)
|
||||
func (s *service) FetchRenter(id string) (r bookish.Renter, err error) {
|
||||
renter, err := s.store.FetchDetails(id)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
|
||||
r = MutateRenterModel(renter)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// RegisterRenter registers a new renter in the renter store.
|
||||
func (s *service) RegisterRenter(fullName string, address string, email string, phoneNumber string) (id int, err error) {
|
||||
func (s *service) RegisterRenter(fullName string, address string, email string, phoneNumber string) (id uuid.UUID, err error) {
|
||||
return s.store.New(fullName, address, email, phoneNumber)
|
||||
}
|
||||
|
||||
// MutateRenterModel is a convenience function to mutate a models.Renter into a bookish.Renter.
|
||||
func MutateRenterModel(m models.Renter) bookish.Renter {
|
||||
r := bookish.Renter{}
|
||||
|
||||
r.ID = m.ID.String()
|
||||
r.Name = m.Name
|
||||
r.Address = m.Address
|
||||
r.Email = m.Email
|
||||
r.PhoneNumber = m.PhoneNumber
|
||||
|
||||
for _, rental := range m.Rentals {
|
||||
if !rental.ReturnDate.Valid {
|
||||
r.Rentals = append(r.Rentals, rental.BookTitle)
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: ./renter.go
|
||||
// Source: renter.go
|
||||
|
||||
// Package renter is a generated GoMock package.
|
||||
package renter
|
||||
|
||||
import (
|
||||
bookish_server "github.com/davidlick/bookish/bookish-server"
|
||||
models "github.com/davidlick/bookish/bookish-server/models"
|
||||
uuid "github.com/gobuffalo/uuid"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
@@ -34,10 +36,10 @@ func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
|
||||
}
|
||||
|
||||
// ListAll mocks base method
|
||||
func (m *MockStorage) ListAll() ([]bookish_server.Renter, error) {
|
||||
func (m *MockStorage) ListAll() ([]models.Renter, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListAll")
|
||||
ret0, _ := ret[0].([]bookish_server.Renter)
|
||||
ret0, _ := ret[0].([]models.Renter)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -49,10 +51,10 @@ func (mr *MockStorageMockRecorder) ListAll() *gomock.Call {
|
||||
}
|
||||
|
||||
// FetchDetails mocks base method
|
||||
func (m *MockStorage) FetchDetails(id int) (bookish_server.Renter, error) {
|
||||
func (m *MockStorage) FetchDetails(id string) (models.Renter, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FetchDetails", id)
|
||||
ret0, _ := ret[0].(bookish_server.Renter)
|
||||
ret0, _ := ret[0].(models.Renter)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -64,10 +66,10 @@ func (mr *MockStorageMockRecorder) FetchDetails(id interface{}) *gomock.Call {
|
||||
}
|
||||
|
||||
// New mocks base method
|
||||
func (m *MockStorage) New(name, address, email, phoneNumber string) (int, error) {
|
||||
func (m *MockStorage) New(name, address, email, phoneNumber string) (uuid.UUID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "New", name, address, email, phoneNumber)
|
||||
ret0, _ := ret[0].(int)
|
||||
ret0, _ := ret[0].(uuid.UUID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -77,3 +79,71 @@ func (mr *MockStorageMockRecorder) New(name, address, email, phoneNumber interfa
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "New", reflect.TypeOf((*MockStorage)(nil).New), name, address, email, phoneNumber)
|
||||
}
|
||||
|
||||
// MockService is a mock of Service interface
|
||||
type MockService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockServiceMockRecorder is the mock recorder for MockService
|
||||
type MockServiceMockRecorder struct {
|
||||
mock *MockService
|
||||
}
|
||||
|
||||
// NewMockService creates a new mock instance
|
||||
func NewMockService(ctrl *gomock.Controller) *MockService {
|
||||
mock := &MockService{ctrl: ctrl}
|
||||
mock.recorder = &MockServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockService) EXPECT() *MockServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ListRenters mocks base method
|
||||
func (m *MockService) ListRenters() ([]bookish_server.Renter, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListRenters")
|
||||
ret0, _ := ret[0].([]bookish_server.Renter)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListRenters indicates an expected call of ListRenters
|
||||
func (mr *MockServiceMockRecorder) ListRenters() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRenters", reflect.TypeOf((*MockService)(nil).ListRenters))
|
||||
}
|
||||
|
||||
// FetchRenter mocks base method
|
||||
func (m *MockService) FetchRenter(id string) (bookish_server.Renter, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FetchRenter", id)
|
||||
ret0, _ := ret[0].(bookish_server.Renter)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FetchRenter indicates an expected call of FetchRenter
|
||||
func (mr *MockServiceMockRecorder) FetchRenter(id interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchRenter", reflect.TypeOf((*MockService)(nil).FetchRenter), id)
|
||||
}
|
||||
|
||||
// RegisterRenter mocks base method
|
||||
func (m *MockService) RegisterRenter(fullName, address, email, phoneNumber string) (uuid.UUID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RegisterRenter", fullName, address, email, phoneNumber)
|
||||
ret0, _ := ret[0].(uuid.UUID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// RegisterRenter indicates an expected call of RegisterRenter
|
||||
func (mr *MockServiceMockRecorder) RegisterRenter(fullName, address, email, phoneNumber interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterRenter", reflect.TypeOf((*MockService)(nil).RegisterRenter), fullName, address, email, phoneNumber)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"testing"
|
||||
|
||||
bookish "github.com/davidlick/bookish/bookish-server"
|
||||
"github.com/davidlick/bookish/bookish-server/models"
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -12,12 +14,12 @@ import (
|
||||
func TestRenter_ListRenters(t *testing.T) {
|
||||
testCases := []struct {
|
||||
TestName string
|
||||
Renters []bookish.Renter
|
||||
Renters []models.Renter
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
TestName: "success",
|
||||
Renters: []bookish.Renter{
|
||||
Renters: []models.Renter{
|
||||
{
|
||||
Name: "John Doe",
|
||||
Address: "123 Main Way",
|
||||
@@ -49,7 +51,13 @@ func TestRenter_ListRenters(t *testing.T) {
|
||||
service := NewService(mockStorage)
|
||||
renters, err := service.ListRenters()
|
||||
|
||||
assert.Equal(t, tc.Renters, renters)
|
||||
var expectedRenters []bookish.Renter
|
||||
for _, renter := range tc.Renters {
|
||||
r := MutateRenterModel(renter)
|
||||
expectedRenters = append(expectedRenters, r)
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRenters, renters)
|
||||
assert.Equal(t, tc.Error, err)
|
||||
})
|
||||
}
|
||||
@@ -59,13 +67,12 @@ func TestRenter_FetchRenter(t *testing.T) {
|
||||
testCases := []struct {
|
||||
TestName string
|
||||
ID int
|
||||
Renter bookish.Renter
|
||||
Renter models.Renter
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
TestName: "success",
|
||||
ID: 1,
|
||||
Renter: bookish.Renter{
|
||||
Renter: models.Renter{
|
||||
Name: "John Smith",
|
||||
Address: "123 Main Way",
|
||||
Email: "john@smith.com",
|
||||
@@ -74,7 +81,6 @@ func TestRenter_FetchRenter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
TestName: "error",
|
||||
ID: 1,
|
||||
Error: errors.New("test error"),
|
||||
},
|
||||
}
|
||||
@@ -84,13 +90,23 @@ func TestRenter_FetchRenter(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
renterId, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
mockStorage := NewMockStorage(ctrl)
|
||||
mockStorage.EXPECT().FetchDetails(tc.ID).Return(tc.Renter, tc.Error)
|
||||
mockStorage.EXPECT().FetchDetails(renterId.String()).Return(tc.Renter, tc.Error)
|
||||
|
||||
service := NewService(mockStorage)
|
||||
renter, err := service.FetchRenter(tc.ID)
|
||||
renter, err := service.FetchRenter(renterId.String())
|
||||
|
||||
assert.Equal(t, tc.Renter, renter)
|
||||
expectedRenter := MutateRenterModel(tc.Renter)
|
||||
if tc.Error != nil {
|
||||
renter.ID = "00000000-0000-0000-0000-000000000000"
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedRenter, renter)
|
||||
assert.Equal(t, tc.Error, err)
|
||||
})
|
||||
}
|
||||
@@ -103,7 +119,6 @@ func TestRenter_RegisterRenter(t *testing.T) {
|
||||
Address string
|
||||
Email string
|
||||
PhoneNumber string
|
||||
ReturnID int
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
@@ -116,13 +131,18 @@ func TestRenter_RegisterRenter(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
returnUuid, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
mockStorage := NewMockStorage(ctrl)
|
||||
mockStorage.EXPECT().New(tc.Name, tc.Address, tc.Email, tc.PhoneNumber).Return(tc.ReturnID, tc.Error)
|
||||
mockStorage.EXPECT().New(tc.Name, tc.Address, tc.Email, tc.PhoneNumber).Return(returnUuid, tc.Error)
|
||||
|
||||
service := NewService(mockStorage)
|
||||
id, err := service.RegisterRenter(tc.Name, tc.Address, tc.Email, tc.PhoneNumber)
|
||||
|
||||
assert.Equal(t, tc.ReturnID, id)
|
||||
assert.Equal(t, returnUuid, id)
|
||||
assert.Equal(t, tc.Error, err)
|
||||
})
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ services:
|
||||
- DBUSER=root
|
||||
- DBPASS=123pass
|
||||
- DBPORT=3306
|
||||
- BOOKSHOST=<ADD BOOKS API HOSTNAME HERE>
|
||||
- BOOKSHOST=https://servicepros-test-api.herokuapp.com
|
||||
db:
|
||||
image: mysql
|
||||
ports:
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
create table renters
|
||||
(
|
||||
id int auto_increment primary key,
|
||||
name varchar(255) not null,
|
||||
address varchar(255) not null,
|
||||
email varchar(255) not null,
|
||||
phone_number varchar(255) not null
|
||||
);
|
||||
|
||||
create unique index renters_id_uindex
|
||||
on renters (id);
|
||||
|
||||
create table rentals
|
||||
(
|
||||
id int auto_increment primary key,
|
||||
renter_id int not null,
|
||||
rental_date datetime not null,
|
||||
return_date datetime null,
|
||||
book_title varchar(255) not null,
|
||||
foreign key (renter_id) references renters(id)
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
create table if not exists renters
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
created_at datetime not null,
|
||||
updated_at datetime not null,
|
||||
name varchar(255) not null,
|
||||
address varchar(255) not null,
|
||||
email varchar(255) not null,
|
||||
phone_number varchar(255) not null
|
||||
);
|
||||
|
||||
create table if not exists rentals
|
||||
(
|
||||
id varchar(255) not null primary key,
|
||||
created_at datetime not null,
|
||||
updated_at datetime not null,
|
||||
book_title varchar(255) not null,
|
||||
renter_id varchar(255) not null,
|
||||
rental_date datetime not null,
|
||||
return_date datetime null,
|
||||
foreign key (renter_id) references renters(id)
|
||||
);
|
||||
Reference in New Issue
Block a user