From 61676598dd1f657064c0abcb2786bf3703919ec7 Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Thu, 7 Dec 2017 21:05:55 -0500 Subject: [PATCH] Move prices to store --- internal/handlers/prices.go | 66 ++++++------------------------- internal/store/db/db.go | 4 +- internal/store/db/prices.go | 78 +++++++++++++++++++++++++++++++++++++ internal/store/store.go | 37 ++++++++++++++---- 4 files changed, 121 insertions(+), 64 deletions(-) create mode 100644 internal/store/db/prices.go diff --git a/internal/handlers/prices.go b/internal/handlers/prices.go index f08d37e..c51d5c8 100644 --- a/internal/handlers/prices.go +++ b/internal/handlers/prices.go @@ -18,67 +18,25 @@ func CreatePriceIfNotExist(tx *db.Tx, price *models.Price) error { return nil } - var prices []*models.Price - - _, err := tx.Select(&prices, "SELECT * from prices where SecurityId=? AND CurrencyId=? AND Date=? AND Value=?", price.SecurityId, price.CurrencyId, price.Date, price.Value) + exists, err := tx.PriceExists(price) if err != nil { return err } - - if len(prices) > 0 { + if exists { return nil // price already exists } - err = tx.Insert(price) + err = tx.InsertPrice(price) if err != nil { return err } return nil } -func GetPrice(tx *db.Tx, priceid, securityid int64) (*models.Price, error) { - var p models.Price - err := tx.SelectOne(&p, "SELECT * from prices where PriceId=? AND SecurityId=?", priceid, securityid) - if err != nil { - return nil, err - } - return &p, nil -} - -func GetPrices(tx *db.Tx, securityid int64) (*[]*models.Price, error) { - var prices []*models.Price - - _, err := tx.Select(&prices, "SELECT * from prices where SecurityId=?", securityid) - if err != nil { - return nil, err - } - return &prices, nil -} - -// Return the latest price for security in currency units before date -func GetLatestPrice(tx *db.Tx, security, currency *models.Security, date *time.Time) (*models.Price, error) { - var p models.Price - err := tx.SelectOne(&p, "SELECT * from prices where SecurityId=? AND CurrencyId=? AND Date <= ? ORDER BY Date DESC LIMIT 1", security.SecurityId, currency.SecurityId, date) - if err != nil { - return nil, err - } - return &p, nil -} - -// Return the earliest price for security in currency units after date -func GetEarliestPrice(tx *db.Tx, security, currency *models.Security, date *time.Time) (*models.Price, error) { - var p models.Price - err := tx.SelectOne(&p, "SELECT * from prices where SecurityId=? AND CurrencyId=? AND Date >= ? ORDER BY Date ASC LIMIT 1", security.SecurityId, currency.SecurityId, date) - if err != nil { - return nil, err - } - return &p, nil -} - // Return the price for security in currency closest to date func GetClosestPrice(tx *db.Tx, security, currency *models.Security, date *time.Time) (*models.Price, error) { - earliest, _ := GetEarliestPrice(tx, security, currency, date) - latest, err := GetLatestPrice(tx, security, currency, date) + earliest, _ := tx.GetEarliestPrice(security, currency, date) + latest, err := tx.GetLatestPrice(security, currency, date) // Return early if either earliest or latest are invalid if earliest == nil { @@ -129,7 +87,7 @@ func PriceHandler(r *http.Request, context *Context, user *models.User, security //Return all this security's prices var pl models.PriceList - prices, err := GetPrices(context.Tx, security.SecurityId) + prices, err := context.Tx.GetPrices(security.SecurityId) if err != nil { log.Print(err) return NewError(999 /*Internal Error*/) @@ -144,7 +102,7 @@ func PriceHandler(r *http.Request, context *Context, user *models.User, security return NewError(3 /*Invalid Request*/) } - price, err := GetPrice(context.Tx, priceid, security.SecurityId) + price, err := context.Tx.GetPrice(priceid, security.SecurityId) if err != nil { return NewError(3 /*Invalid Request*/) } @@ -170,21 +128,21 @@ func PriceHandler(r *http.Request, context *Context, user *models.User, security return NewError(3 /*Invalid Request*/) } - count, err := context.Tx.Update(&price) - if err != nil || count != 1 { + err = context.Tx.UpdatePrice(&price) + if err != nil { log.Print(err) return NewError(999 /*Internal Error*/) } return &price } else if r.Method == "DELETE" { - price, err := GetPrice(context.Tx, priceid, security.SecurityId) + price, err := context.Tx.GetPrice(priceid, security.SecurityId) if err != nil { return NewError(3 /*Invalid Request*/) } - count, err := context.Tx.Delete(price) - if err != nil || count != 1 { + err = context.Tx.DeletePrice(price) + if err != nil { log.Print(err) return NewError(999 /*Internal Error*/) } diff --git a/internal/store/db/db.go b/internal/store/db/db.go index 3a4031e..d8b043b 100644 --- a/internal/store/db/db.go +++ b/internal/store/db/db.go @@ -39,11 +39,11 @@ func GetDbMap(db *sql.DB, dbtype config.DbType) (*gorp.DbMap, error) { dbmap := &gorp.DbMap{Db: db, Dialect: dialect} dbmap.AddTableWithName(models.User{}, "users").SetKeys(true, "UserId") dbmap.AddTableWithName(models.Session{}, "sessions").SetKeys(true, "SessionId") - dbmap.AddTableWithName(models.Account{}, "accounts").SetKeys(true, "AccountId") dbmap.AddTableWithName(models.Security{}, "securities").SetKeys(true, "SecurityId") + dbmap.AddTableWithName(models.Price{}, "prices").SetKeys(true, "PriceId") + dbmap.AddTableWithName(models.Account{}, "accounts").SetKeys(true, "AccountId") dbmap.AddTableWithName(models.Transaction{}, "transactions").SetKeys(true, "TransactionId") dbmap.AddTableWithName(models.Split{}, "splits").SetKeys(true, "SplitId") - dbmap.AddTableWithName(models.Price{}, "prices").SetKeys(true, "PriceId") rtable := dbmap.AddTableWithName(models.Report{}, "reports").SetKeys(true, "ReportId") rtable.ColMap("Lua").SetMaxSize(models.LuaMaxLength + luaMaxLengthBuffer) diff --git a/internal/store/db/prices.go b/internal/store/db/prices.go new file mode 100644 index 0000000..2df2ab9 --- /dev/null +++ b/internal/store/db/prices.go @@ -0,0 +1,78 @@ +package db + +import ( + "fmt" + "github.com/aclindsa/moneygo/internal/models" + "time" +) + +func (tx *Tx) PriceExists(price *models.Price) (bool, error) { + var prices []*models.Price + _, err := tx.Select(&prices, "SELECT * from prices where SecurityId=? AND CurrencyId=? AND Date=? AND Value=?", price.SecurityId, price.CurrencyId, price.Date, price.Value) + return len(prices) > 0, err +} + +func (tx *Tx) InsertPrice(price *models.Price) error { + return tx.Insert(price) +} + +func (tx *Tx) GetPrice(priceid, securityid int64) (*models.Price, error) { + var price models.Price + err := tx.SelectOne(&price, "SELECT * from prices where PriceId=? AND SecurityId=?", priceid, securityid) + if err != nil { + return nil, err + } + return &price, nil +} + +func (tx *Tx) GetPrices(securityid int64) (*[]*models.Price, error) { + var prices []*models.Price + + _, err := tx.Select(&prices, "SELECT * from prices where SecurityId=?", securityid) + if err != nil { + return nil, err + } + return &prices, nil +} + +// Return the latest price for security in currency units before date +func (tx *Tx) GetLatestPrice(security, currency *models.Security, date *time.Time) (*models.Price, error) { + var price models.Price + err := tx.SelectOne(&price, "SELECT * from prices where SecurityId=? AND CurrencyId=? AND Date <= ? ORDER BY Date DESC LIMIT 1", security.SecurityId, currency.SecurityId, date) + if err != nil { + return nil, err + } + return &price, nil +} + +// Return the earliest price for security in currency units after date +func (tx *Tx) GetEarliestPrice(security, currency *models.Security, date *time.Time) (*models.Price, error) { + var price models.Price + err := tx.SelectOne(&price, "SELECT * from prices where SecurityId=? AND CurrencyId=? AND Date >= ? ORDER BY Date ASC LIMIT 1", security.SecurityId, currency.SecurityId, date) + if err != nil { + return nil, err + } + return &price, nil +} + +func (tx *Tx) UpdatePrice(price *models.Price) error { + count, err := tx.Update(price) + if err != nil { + return err + } + if count != 1 { + return fmt.Errorf("Expected to update 1 price, was going to update %d", count) + } + return nil +} + +func (tx *Tx) DeletePrice(price *models.Price) error { + count, err := tx.Delete(price) + if err != nil { + return err + } + if count != 1 { + return fmt.Errorf("Expected to delete 1 price, was going to delete %d", count) + } + return nil +} diff --git a/internal/store/store.go b/internal/store/store.go index fe99c9c..b1ffc8a 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -2,15 +2,9 @@ package store import ( "github.com/aclindsa/moneygo/internal/models" + "time" ) -type SessionStore interface { - SessionExists(secret string) (bool, error) - InsertSession(session *models.Session) error - GetSession(secret string) (*models.Session, error) - DeleteSession(session *models.Session) error -} - type UserStore interface { UsernameExists(username string) (bool, error) InsertUser(user *models.User) error @@ -20,6 +14,13 @@ type UserStore interface { DeleteUser(user *models.User) error } +type SessionStore interface { + SessionExists(secret string) (bool, error) + InsertSession(session *models.Session) error + GetSession(secret string) (*models.Session, error) + DeleteSession(session *models.Session) error +} + type SecurityInUseError struct { Message string } @@ -37,6 +38,17 @@ type SecurityStore interface { DeleteSecurity(security *models.Security) error } +type PriceStore interface { + PriceExists(price *models.Price) (bool, error) + InsertPrice(price *models.Price) error + GetPrice(priceid, securityid int64) (*models.Price, error) + GetPrices(securityid int64) (*[]*models.Price, error) + GetLatestPrice(security, currency *models.Security, date *time.Time) (*models.Price, error) + GetEarliestPrice(security, currency *models.Security, date *time.Time) (*models.Price, error) + UpdatePrice(price *models.Price) error + DeletePrice(price *models.Price) error +} + type ParentAccountMissingError struct{} func (pame ParentAccountMissingError) Error() string { @@ -64,14 +76,23 @@ type AccountStore interface { DeleteAccount(account *models.Account) error } +type TransactionStore interface { +} + +type ReportStore interface { +} + type Tx interface { Commit() error Rollback() error - SessionStore UserStore + SessionStore SecurityStore + PriceStore AccountStore + TransactionStore + ReportStore } type Store interface {