From 3454cd57439cefa3ccf774592d96e4c22003cf8a Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 13 Sep 2021 09:57:18 +0300 Subject: [PATCH] - Now server does not store rates for equivalent currencies on bulk symbols requests. fix #1 --- README.md | 2 +- configs/config.yml.dist | 1 + internal/pkg/cache/store/MySQLStore.go | 15 +++++++++------ internal/pkg/customerror/BadRequestError.go | 18 ++++++++++++++++++ internal/pkg/customerror/DatabaseError.go | 18 ++++++++++++++++++ internal/pkg/customerror/NotFoundError.go | 18 ++++++++++++++++++ internal/pkg/model/FailedApiResponse.go | 6 +++++- internal/pkg/provider/emirates/Provider.go | 9 +++++---- internal/pkg/provider/fixer/Provider.go | 4 ++-- internal/pkg/util/constants.go | 1 + internal/pkg/util/functions.go | 1 + 11 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 internal/pkg/customerror/BadRequestError.go create mode 100644 internal/pkg/customerror/DatabaseError.go create mode 100644 internal/pkg/customerror/NotFoundError.go diff --git a/README.md b/README.md index 38359e1..e3573dc 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ Generate API docs in folder "api" $HOME/go/bin/swag init --output=./api ``` -You can test API here: ```http://localhost/swagger/index.html``` +You can test API here: ```http://localhost:9090/swagger/index.html``` ## Godoc You can run ```Go Documentation Server``` with actual version of documentation with this command: diff --git a/configs/config.yml.dist b/configs/config.yml.dist index 719ddae..5e35347 100644 --- a/configs/config.yml.dist +++ b/configs/config.yml.dist @@ -34,4 +34,5 @@ providers: rates_generated_time: 23:59 supported_currencies: ["AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTC", "BTN", "BWP", "BYN", "BYR", "BZD", "CAD", "CDF", "CHF", "CLF", "CLP", "CNY", "COP", "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GGP", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "IMP", "INR", "IQD", "IRR", "ISK", "JEP", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LVL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "STD", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VEF", "VND", "VUV", "WST", "XAF", "XAG", "XAU", "XCD", "XDR", "XOF", "XPF", "YER", "ZAR", "ZMK", "ZMW", "ZWL"] historical_preload: false + historical_start_date: "2000-05-31" api_key: xxxx diff --git a/internal/pkg/cache/store/MySQLStore.go b/internal/pkg/cache/store/MySQLStore.go index 831488f..94e56bd 100644 --- a/internal/pkg/cache/store/MySQLStore.go +++ b/internal/pkg/cache/store/MySQLStore.go @@ -1,10 +1,10 @@ -// Package cache_store use for custom store for caching historical currency rates -package cache_store +// Package cachestore use for custom store for caching historical currency rates +package cachestore import ( "encoding/json" "github.com/eko/gocache/store" - "github.com/netandreus/go-forex-rates/internal/pkg/custom_errors" + "github.com/netandreus/go-forex-rates/internal/pkg/customerror" "github.com/netandreus/go-forex-rates/internal/pkg/entity" "github.com/netandreus/go-forex-rates/internal/pkg/model" "github.com/netandreus/go-forex-rates/internal/pkg/util" @@ -117,7 +117,7 @@ func (store *MySQLStore) loadByKey(serviceRequest model.RatesRequest) (string, e // Latest data does not stored in database if serviceRequest.Endpoint == util.EndpointLatest { - return "", custom_errors.NewNotFoundError("Value not found in MySQLCache store") + return "", customerror.NewNotFoundError("Value not found in MySQLCache store") } // Remove base currency from symbols @@ -137,11 +137,11 @@ func (store *MySQLStore) loadByKey(serviceRequest model.RatesRequest) (string, e Where("rate_date = ?", serviceRequest.Date.Format(util.DateFormatEu)). Find(&entities) if result.Error != nil { - return "", custom_errors.NewDatabaseError(result.Error.Error()) + return "", customerror.NewDatabaseError(result.Error.Error()) } symbolsCount := int64(len(symbols)) if result.RowsAffected < symbolsCount { - return "", custom_errors.NewNotFoundError("Value not found in MySQLCache store") + return "", customerror.NewNotFoundError("Value not found in MySQLCache store") } // Provider generated time providerGeneratedTime = entities[0].ProviderGeneratedTime @@ -166,6 +166,9 @@ func (store *MySQLStore) loadByKey(serviceRequest model.RatesRequest) (string, e // saveByKey uses internally for save to database func (store *MySQLStore) saveByKey(key model.RatesRequest, value model.RatesResponse) error { for quotedCurrency, rate := range value.Rates { + if key.BaseCurrency == quotedCurrency { + continue + } entity := &entity.CurrencyRate{ Endpoint: key.Endpoint, BaseCurrency: key.BaseCurrency, // Base currency diff --git a/internal/pkg/customerror/BadRequestError.go b/internal/pkg/customerror/BadRequestError.go new file mode 100644 index 0000000..e5bd41a --- /dev/null +++ b/internal/pkg/customerror/BadRequestError.go @@ -0,0 +1,18 @@ +package customerror + +// BadRequestError represents bad RatesRequest error +type BadRequestError struct { + message string +} + +// Error returns error message +func (m *BadRequestError) Error() string { + return m.message +} + +// NewBadRequestError error constructor +func NewBadRequestError(message string) *BadRequestError { + return &BadRequestError{ + message: message, + } +} diff --git a/internal/pkg/customerror/DatabaseError.go b/internal/pkg/customerror/DatabaseError.go new file mode 100644 index 0000000..75e8298 --- /dev/null +++ b/internal/pkg/customerror/DatabaseError.go @@ -0,0 +1,18 @@ +package customerror + +// DatabaseError represents database error +type DatabaseError struct { + message string +} + +// Error returns error message +func (m *DatabaseError) Error() string { + return m.message +} + +// NewDatabaseError error constructor +func NewDatabaseError(message string) *DatabaseError { + return &DatabaseError{ + message: message, + } +} diff --git a/internal/pkg/customerror/NotFoundError.go b/internal/pkg/customerror/NotFoundError.go new file mode 100644 index 0000000..85dfe50 --- /dev/null +++ b/internal/pkg/customerror/NotFoundError.go @@ -0,0 +1,18 @@ +package customerror + +// NotFoundError is rates not found error +type NotFoundError struct { + message string +} + +// Error returns error message +func (m *NotFoundError) Error() string { + return m.message +} + +// NewNotFoundError error constructor +func NewNotFoundError(message string) *NotFoundError { + return &NotFoundError{ + message: message, + } +} diff --git a/internal/pkg/model/FailedApiResponse.go b/internal/pkg/model/FailedApiResponse.go index 8237862..12bf06a 100644 --- a/internal/pkg/model/FailedApiResponse.go +++ b/internal/pkg/model/FailedApiResponse.go @@ -9,7 +9,7 @@ type ApiError struct { Info string `json:"info"` } -// FailedApiResponse response, when error occured +// FailedApiResponse response, when error occurred type FailedApiResponse struct { // Success Returns true or false depending on whether or not your API request has succeeded. Success bool `json:"success"` @@ -26,19 +26,23 @@ func NewFailedApiResponse(code int, info string) *FailedApiResponse { } } +// GetSuccess returns Success value func (a *FailedApiResponse) GetSuccess() bool { return a.Success } +// SetSuccess sets Success value func (a *FailedApiResponse) SetSuccess(success bool) *FailedApiResponse { a.Success = success return a } +// GetError returns Error value func (a *FailedApiResponse) GetError() ApiError { return a.Error } +// SetError sets Error value func (a *FailedApiResponse) SetError(e ApiError) *FailedApiResponse { a.Error = e return a diff --git a/internal/pkg/provider/emirates/Provider.go b/internal/pkg/provider/emirates/Provider.go index a9e68c8..186b705 100644 --- a/internal/pkg/provider/emirates/Provider.go +++ b/internal/pkg/provider/emirates/Provider.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "github.com/PuerkitoBio/goquery" - "github.com/netandreus/go-forex-rates/internal/pkg/custom_errors" + "github.com/netandreus/go-forex-rates/internal/pkg/customerror" "github.com/netandreus/go-forex-rates/internal/pkg/entity" "github.com/netandreus/go-forex-rates/internal/pkg/model" "github.com/netandreus/go-forex-rates/internal/pkg/provider" @@ -24,6 +24,7 @@ import ( // Code emirates provider code const Code = "emirates" +// ApiResponse is Emirates service http api response type ApiResponse struct { // HTML table in json field Table string `json:"table"` @@ -100,7 +101,7 @@ func (p Provider) GetHistoricalRates(serviceRequest model.RatesRequest) (model.R } else { serviceResponse.Rates = make(map[string]float64) serviceResponse.Timestamp = providerGeneratedTime.Unix() - return serviceResponse, custom_errors.NewBadRequestError("base currency should be AED, or symbols should be [AED]") + return serviceResponse, customerror.NewBadRequestError("base currency should be AED, or symbols should be [AED]") } } @@ -184,8 +185,8 @@ func (p Provider) filterRates(rates map[string]float64, baseCurrency string, sym // fetchHistoricalRatesAllSymbols - fetches directRates and reverseRates. Return normalized (scale=6) rates func (p Provider) fetchHistoricalRatesAllSymbols(date string) (map[string]float64, map[string]float64, time.Time, error) { var ( - directRates = make(map[string]float64) - reverseRates = make(map[string]float64) + directRates map[string]float64 + reverseRates map[string]float64 providerDate time.Time err error resp *http.Response diff --git a/internal/pkg/provider/fixer/Provider.go b/internal/pkg/provider/fixer/Provider.go index 123fc59..7b76c0c 100644 --- a/internal/pkg/provider/fixer/Provider.go +++ b/internal/pkg/provider/fixer/Provider.go @@ -42,7 +42,7 @@ func New(db *gorm.DB, config *model.ApplicationConfig) *Provider { func (p Provider) GetHistoricalRates(serviceRequest model.RatesRequest) (model.RatesResponse, error) { var ( err error - rates = make(map[string]float64) + rates map[string]float64 providerGeneratedTime time.Time resp *http.Response body []byte @@ -81,7 +81,7 @@ func (p Provider) GetLatestRates(serviceRequest model.RatesRequest) (model.Rates var ( serviceResponse model.RatesResponse err error - rates = make(map[string]float64) + rates map[string]float64 providerGeneratedTime time.Time resp *http.Response body []byte diff --git a/internal/pkg/util/constants.go b/internal/pkg/util/constants.go index 0c7280a..d3da5f8 100644 --- a/internal/pkg/util/constants.go +++ b/internal/pkg/util/constants.go @@ -1,5 +1,6 @@ package util +// All project constants const ( DateFormatEu string = "2006-01-02" DateFormatRu = "02-01-2006" diff --git a/internal/pkg/util/functions.go b/internal/pkg/util/functions.go index 8a2ca3c..5296c3a 100644 --- a/internal/pkg/util/functions.go +++ b/internal/pkg/util/functions.go @@ -5,6 +5,7 @@ import ( "time" ) +// ToFixed rounds passed num to target precision. func ToFixed(num float64, precision int) float64 { output := math.Pow(10, float64(precision)) return float64(round(num*output)) / output