From c21644229310547908e3bc4be547dd59c8d81439 Mon Sep 17 00:00:00 2001 From: piraces Date: Thu, 14 Apr 2022 12:48:11 +0200 Subject: [PATCH 1/3] Add stores command --- 02-refactor-to-cobra/cmd/beers-cli/main.go | 1 + 02-refactor-to-cobra/internal/cli/beers.go | 32 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/02-refactor-to-cobra/cmd/beers-cli/main.go b/02-refactor-to-cobra/cmd/beers-cli/main.go index 4b3ae21..e074938 100644 --- a/02-refactor-to-cobra/cmd/beers-cli/main.go +++ b/02-refactor-to-cobra/cmd/beers-cli/main.go @@ -8,5 +8,6 @@ import ( func main() { rootCmd := &cobra.Command{Use: "beers-cli"} rootCmd.AddCommand(cli.InitBeersCmd()) + rootCmd.AddCommand(cli.InitStoresCmd()) rootCmd.Execute() } diff --git a/02-refactor-to-cobra/internal/cli/beers.go b/02-refactor-to-cobra/internal/cli/beers.go index 26c141f..c07a48a 100644 --- a/02-refactor-to-cobra/internal/cli/beers.go +++ b/02-refactor-to-cobra/internal/cli/beers.go @@ -15,7 +15,14 @@ var beers = map[string]string{ "01D9X5CVS1M9VR5ZD627XDF6ND": "Belgian Moon", } +var stores = map[string]string{ + "01DC9ZAPGKEQJS4P4A48EG3P43": "Mercadona", + "01DC9ZB23EW0J0ARAER09SJDKC": "Carrefour", + "01DC9ZB89V1PQD977ZE6QXSQHH": "Alcampo", +} + const idFlag = "id" +const storeIdFlag = "store" // InitBeersCmd initialize beers command func InitBeersCmd() *cobra.Command { @@ -30,6 +37,19 @@ func InitBeersCmd() *cobra.Command { return beersCmd } +// InitStoresCmd initialize stores command +func InitStoresCmd() *cobra.Command { + storeCmd := &cobra.Command{ + Use: "stores", + Short: "Print data about stores that sell beers", + Run: runStoresFn(), + } + + storeCmd.Flags().StringP(storeIdFlag, "s", "", "id of the store") + + return storeCmd +} + func runBeersFn() CobraFn { return func(cmd *cobra.Command, args []string) { id, _ := cmd.Flags().GetString(idFlag) @@ -41,3 +61,15 @@ func runBeersFn() CobraFn { } } } + +func runStoresFn() CobraFn { + return func(cmd *cobra.Command, args []string) { + id, _ := cmd.Flags().GetString(storeIdFlag) + + if id != "" { + fmt.Println(stores[id]) + } else { + fmt.Println(stores) + } + } +} From bc2af4479533a91fb2944a93efd623cd7a3020ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Pirac=C3=A9s?= Date: Thu, 28 Apr 2022 09:22:34 +0200 Subject: [PATCH 2/3] Error handling in go (exercise) --- 07-behaviour_error_handling/internal/beer.go | 6 +++- .../internal/cli/beers.go | 12 ++++++- .../internal/errors/conversionerror.go | 28 +++++++++++++++++ .../internal/errors/filehandlingerror.go | 28 +++++++++++++++++ .../errors/{errortypes.go => httperror.go} | 0 .../internal/storage/csv/repository.go | 31 ++++++++++++++++--- 6 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 07-behaviour_error_handling/internal/errors/conversionerror.go create mode 100644 07-behaviour_error_handling/internal/errors/filehandlingerror.go rename 07-behaviour_error_handling/internal/errors/{errortypes.go => httperror.go} (100%) diff --git a/07-behaviour_error_handling/internal/beer.go b/07-behaviour_error_handling/internal/beer.go index 4ed7c21..90b4da0 100644 --- a/07-behaviour_error_handling/internal/beer.go +++ b/07-behaviour_error_handling/internal/beer.go @@ -2,6 +2,8 @@ package beerscli import ( "encoding/json" + + "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/errors" ) // Beer representation of beer into data struct @@ -65,9 +67,11 @@ var toID = map[string]BeerType{ func (t *BeerType) UnmarshalJSON(b []byte) error { var j string err := json.Unmarshal(b, &j) + if err != nil { - return err + return errors.WrapConversionError(err, "Could not convert retrieved bytes to JSON") } + *t = toID[j] return nil } diff --git a/07-behaviour_error_handling/internal/cli/beers.go b/07-behaviour_error_handling/internal/cli/beers.go index 8f8e666..a3f7987 100644 --- a/07-behaviour_error_handling/internal/cli/beers.go +++ b/07-behaviour_error_handling/internal/cli/beers.go @@ -36,10 +36,20 @@ func runBeersFn(repository beerscli.BeerRepo) CobraFn { log.Fatal(err) } + if errors.IsFileHandlingError(err) { + log.Fatal(err) + } + id, _ := cmd.Flags().GetString(idFlag) if id != "" { - i, _ := strconv.Atoi(id) + var i int + i, err = strconv.Atoi(id) + + if errors.IsConversionError(err) { + log.Fatal(err) + } + for _, beer := range beers { if beer.ProductID == i { fmt.Println(beer) diff --git a/07-behaviour_error_handling/internal/errors/conversionerror.go b/07-behaviour_error_handling/internal/errors/conversionerror.go new file mode 100644 index 0000000..d48b822 --- /dev/null +++ b/07-behaviour_error_handling/internal/errors/conversionerror.go @@ -0,0 +1,28 @@ +package errors + +import ( + "github.com/pkg/errors" +) + +type conversionError struct { + error +} + +// WrapConversionError returns an error which wraps err that satisfies +// IsConversionError() +func WrapConversionError(err error, format string, args ...interface{}) error { + return &conversionError{errors.Wrapf(err, format, args...)} +} + +// NewConversionError returns an error which satisfies IsConversionError() +func NewConversionError(format string, args ...interface{}) error { + return &conversionError{errors.Errorf(format, args...)} +} + +// IsConversionError reports whether err was created with ConversionError() or +// NewConversionError() +func IsConversionError(err error) bool { + err = errors.Cause(err) + _, ok := err.(*conversionError) + return ok +} diff --git a/07-behaviour_error_handling/internal/errors/filehandlingerror.go b/07-behaviour_error_handling/internal/errors/filehandlingerror.go new file mode 100644 index 0000000..fec5e77 --- /dev/null +++ b/07-behaviour_error_handling/internal/errors/filehandlingerror.go @@ -0,0 +1,28 @@ +package errors + +import ( + "github.com/pkg/errors" +) + +type fileHandlingError struct { + error +} + +// WrapFileHandlingError returns an error which wraps err that satisfies +// IsFileHandlingError() +func WrapFileHandlingError(err error, format string, args ...interface{}) error { + return &fileHandlingError{errors.Wrapf(err, format, args...)} +} + +// NewFileHandlingError returns an error which satisfies IsFileHandlingError() +func NewFileHandlingError(format string, args ...interface{}) error { + return &fileHandlingError{errors.Errorf(format, args...)} +} + +// IsFileHandlingError reports whether err was created with FileHandlingError() or +// NewFileHandlingError() +func IsFileHandlingError(err error) bool { + err = errors.Cause(err) + _, ok := err.(*fileHandlingError) + return ok +} diff --git a/07-behaviour_error_handling/internal/errors/errortypes.go b/07-behaviour_error_handling/internal/errors/httperror.go similarity index 100% rename from 07-behaviour_error_handling/internal/errors/errortypes.go rename to 07-behaviour_error_handling/internal/errors/httperror.go diff --git a/07-behaviour_error_handling/internal/storage/csv/repository.go b/07-behaviour_error_handling/internal/storage/csv/repository.go index cb1e7cc..1072077 100644 --- a/07-behaviour_error_handling/internal/storage/csv/repository.go +++ b/07-behaviour_error_handling/internal/storage/csv/repository.go @@ -7,6 +7,7 @@ import ( "strings" beerscli "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal" + "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/errors" ) type repository struct { @@ -19,15 +20,31 @@ func NewRepository() beerscli.BeerRepo { // GetBeers fetch beers data from csv func (r *repository) GetBeers() ([]beerscli.Beer, error) { - f, _ := os.Open("07-behaviour_error_handling/data/beers.csv") + const filePath = "07-behaviour_error_handling/data/beers.csv" + f, err := os.Open(filePath) + + if err != nil { + return nil, errors.WrapFileHandlingError(err, "error opening file %s", filePath) + } + reader := bufio.NewReader(f) var beers []beerscli.Beer - for line := readLine(reader); line != nil; line = readLine(reader) { + var line []byte + + for line, err = readLine(reader); line != nil; line, err = readLine(reader) { + if err != nil { + return nil, err + } values := strings.Split(string(line), ",") - productID, _ := strconv.Atoi(values[0]) + var productID int + productID, err = strconv.Atoi(values[0]) + + if err != nil { + return nil, errors.WrapConversionError(err, "error while converting 'productId' from ascii to integer: %s", values[0]) + } beer := beerscli.NewBeer( productID, @@ -45,7 +62,11 @@ func (r *repository) GetBeers() ([]beerscli.Beer, error) { return beers, nil } -func readLine(reader *bufio.Reader) (line []byte) { - line, _, _ = reader.ReadLine() +func readLine(reader *bufio.Reader) (line []byte, err error) { + line, _, err = reader.ReadLine() + + if err != nil { + return nil, errors.WrapFileHandlingError(err, "could not read next line of buffer") + } return } From c3ba4ac75c0e4dbcb31e6bf2a56a54d9170be33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Pirac=C3=A9s?= Date: Thu, 28 Apr 2022 09:27:09 +0200 Subject: [PATCH 3/3] Revert changes --- 02-refactor-to-cobra/cmd/beers-cli/main.go | 1 - 02-refactor-to-cobra/internal/cli/beers.go | 32 ---------------------- 2 files changed, 33 deletions(-) diff --git a/02-refactor-to-cobra/cmd/beers-cli/main.go b/02-refactor-to-cobra/cmd/beers-cli/main.go index e074938..4b3ae21 100644 --- a/02-refactor-to-cobra/cmd/beers-cli/main.go +++ b/02-refactor-to-cobra/cmd/beers-cli/main.go @@ -8,6 +8,5 @@ import ( func main() { rootCmd := &cobra.Command{Use: "beers-cli"} rootCmd.AddCommand(cli.InitBeersCmd()) - rootCmd.AddCommand(cli.InitStoresCmd()) rootCmd.Execute() } diff --git a/02-refactor-to-cobra/internal/cli/beers.go b/02-refactor-to-cobra/internal/cli/beers.go index c07a48a..26c141f 100644 --- a/02-refactor-to-cobra/internal/cli/beers.go +++ b/02-refactor-to-cobra/internal/cli/beers.go @@ -15,14 +15,7 @@ var beers = map[string]string{ "01D9X5CVS1M9VR5ZD627XDF6ND": "Belgian Moon", } -var stores = map[string]string{ - "01DC9ZAPGKEQJS4P4A48EG3P43": "Mercadona", - "01DC9ZB23EW0J0ARAER09SJDKC": "Carrefour", - "01DC9ZB89V1PQD977ZE6QXSQHH": "Alcampo", -} - const idFlag = "id" -const storeIdFlag = "store" // InitBeersCmd initialize beers command func InitBeersCmd() *cobra.Command { @@ -37,19 +30,6 @@ func InitBeersCmd() *cobra.Command { return beersCmd } -// InitStoresCmd initialize stores command -func InitStoresCmd() *cobra.Command { - storeCmd := &cobra.Command{ - Use: "stores", - Short: "Print data about stores that sell beers", - Run: runStoresFn(), - } - - storeCmd.Flags().StringP(storeIdFlag, "s", "", "id of the store") - - return storeCmd -} - func runBeersFn() CobraFn { return func(cmd *cobra.Command, args []string) { id, _ := cmd.Flags().GetString(idFlag) @@ -61,15 +41,3 @@ func runBeersFn() CobraFn { } } } - -func runStoresFn() CobraFn { - return func(cmd *cobra.Command, args []string) { - id, _ := cmd.Flags().GetString(storeIdFlag) - - if id != "" { - fmt.Println(stores[id]) - } else { - fmt.Println(stores) - } - } -}