get prices methods
This commit is contained in:
parent
c772f0a4d2
commit
9e97f082fa
4 changed files with 324 additions and 14 deletions
|
|
@ -38,6 +38,10 @@ func (h *Handler) RegisterRoutes(r *gin.RouterGroup) {
|
|||
originsGroup.GET("", h.controller.getOrigins)
|
||||
originsGroup.DELETE("", h.controller.deleteOrigin)
|
||||
|
||||
chartsGroup := r.Group("/prices")
|
||||
chartsGroup.GET("", h.controller.getChartsPrices)
|
||||
chartsGroup.GET("/:uuid", h.controller.getDistinctPrices)
|
||||
|
||||
}
|
||||
|
||||
// create godoc
|
||||
|
|
@ -105,13 +109,13 @@ func (co *controller) getMany(c *gin.Context) {
|
|||
// @Description Update merch general info (except extra data)
|
||||
// @Tags Merch
|
||||
// @Accept json
|
||||
// @Param uuid path string true "merch uuid"
|
||||
// @Param payload body updateMerchDTO true "payload"
|
||||
// @Param uuid path string true "merch uuid"
|
||||
// @Param payload body updateMerchDTO true "payload"
|
||||
// @Produce json
|
||||
// @Success 200 {object} merchDTO
|
||||
// @Failure 400 {object} responses.BadRequest
|
||||
// @Failure 401 {object} responses.Unauthorized
|
||||
// @Failure 500 {object} responses.InternalServerError
|
||||
// @Success 200 {object} merchDTO
|
||||
// @Failure 400 {object} responses.BadRequest
|
||||
// @Failure 401 {object} responses.Unauthorized
|
||||
// @Failure 500 {object} responses.InternalServerError
|
||||
// @Router /merch/{uuid} [PUT]
|
||||
func (co *controller) updateMerch(c *gin.Context) {
|
||||
merchUuid := c.Param("id")
|
||||
|
|
@ -150,13 +154,13 @@ func (co *controller) updateMerch(c *gin.Context) {
|
|||
// @Description Update ONLY merch extra data
|
||||
// @Tags Merch
|
||||
// @Accept json
|
||||
// @Param uuid path string true "merch uuid"
|
||||
// @Param payload body extraDataDTO true "payload"
|
||||
// @Param uuid path string true "merch uuid"
|
||||
// @Param payload body extraDataDTO true "payload"
|
||||
// @Produce json
|
||||
// @Success 200 {object} extraDataDTO
|
||||
// @Failure 400 {object} responses.BadRequest
|
||||
// @Failure 401 {object} responses.Unauthorized
|
||||
// @Failure 500 {object} responses.InternalServerError
|
||||
// @Success 200 {object} extraDataDTO
|
||||
// @Failure 400 {object} responses.BadRequest
|
||||
// @Failure 401 {object} responses.Unauthorized
|
||||
// @Failure 500 {object} responses.InternalServerError
|
||||
// @Router /merch/extra/{uuid} [PUT]
|
||||
func (co *controller) updateExtraData(c *gin.Context) {
|
||||
merchUuid := c.Param("id")
|
||||
|
|
@ -303,3 +307,66 @@ func (co *controller) deleteOrigin(c *gin.Context) {
|
|||
logDebug(controllerLogHeader, "delete origin success")
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// getChartsPrices godoc
|
||||
//
|
||||
// @Summary Получить цены мерча за период
|
||||
// @Description Получить цены мерча за период
|
||||
// @Tags Merch
|
||||
// @Security BearerAuth
|
||||
// @Produce json
|
||||
// @Param days query string false "period in days"
|
||||
// @Success 200 {array} PricesResponse
|
||||
// @Failure 400 {object} responses.BadRequest
|
||||
// @Failure 401 {object} responses.Unauthorized
|
||||
// @Failure 500 {object} responses.InternalServerError
|
||||
// @Router /prices [get]
|
||||
func (co *controller) getChartsPrices(c *gin.Context) {
|
||||
response, err := co.service.getPrices(c, getUserId(c), getDays(c))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, responses.InternalServerError{Error: err.Error()})
|
||||
logErr(controllerLogHeader, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// getDistinctPrices godoc
|
||||
//
|
||||
// @Summary Получить перепады цен мерча за период по его merch_uuid
|
||||
// @Description Получить перепады цен мерча за период по его merch_uuid
|
||||
// @Tags Merch
|
||||
// @Security BearerAuth
|
||||
// @Produce json
|
||||
// @Param uuid path string true "merch_uuid"
|
||||
// @Param days query string false "period in days"
|
||||
// @Success 200 {object} PricesResponse
|
||||
// @Success 204
|
||||
// @Failure 400 {object} responses.BadRequest
|
||||
// @Failure 401 {object} responses.Unauthorized
|
||||
// @Failure 500 {object} responses.InternalServerError
|
||||
// @Router /prices/{uuid} [get]
|
||||
func (co *controller) getDistinctPrices(c *gin.Context) {
|
||||
merchUuid := c.Param("uuid")
|
||||
if merchUuid == "" {
|
||||
err := errors.New("MerchUuid is empty")
|
||||
c.JSON(http.StatusBadRequest, responses.BadRequest{Error: err.Error()})
|
||||
logErr(controllerLogHeader, err)
|
||||
return
|
||||
}
|
||||
|
||||
response, err := co.service.getDistinctPrices(c, getUserId(c), merchUuid, getDays(c))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, responses.InternalServerError{Error: err.Error()})
|
||||
logErr(controllerLogHeader, err)
|
||||
return
|
||||
}
|
||||
|
||||
if response == nil {
|
||||
c.Status(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,3 +45,20 @@ type extraDataDTO struct {
|
|||
MerchUuid string `json:"merch_uuid"`
|
||||
Links []originLink `json:"links"`
|
||||
}
|
||||
|
||||
// prices dtos
|
||||
type PriceEntry struct {
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
Value int `json:"value"`
|
||||
}
|
||||
|
||||
type OriginWithPrices struct {
|
||||
Origin string `json:"origin"`
|
||||
Prices []PriceEntry
|
||||
}
|
||||
|
||||
type PricesResponse struct {
|
||||
Name string `json:"name"`
|
||||
MerchUuid string `json:"merch_uuid"`
|
||||
Origins []OriginWithPrices `json:"origins"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ type Repository interface {
|
|||
|
||||
getMerchIdByUuid(ctx context.Context, userId int64, uuid string) (int64, error)
|
||||
getMerchUuidMap(ctx context.Context, merchUuids []string) (map[string]int64, error)
|
||||
getAllUserMerch(ctx context.Context, userId int64) ([]Merch, error)
|
||||
|
||||
updateMerch(ctx context.Context, userId int64, merch *updateMerchDTO) (*merchDTO, error)
|
||||
updateExtraData(ctx context.Context, merchId int64, insertData []ExtraData) ([]ExtraData, error)
|
||||
|
|
@ -39,6 +40,8 @@ type Origins interface {
|
|||
|
||||
type Prices interface {
|
||||
insertPrices(ctx context.Context, prices []Price) error
|
||||
getPricesWithDays(ctx context.Context, userId int64, days time.Time) ([]Price, error)
|
||||
getDistinctPrices(ctx context.Context, userId int64, merchUuid string, days time.Time) ([]Price, error)
|
||||
}
|
||||
|
||||
type Tasks interface {
|
||||
|
|
@ -219,6 +222,32 @@ func (r *repo) getMerchUuidMap(ctx context.Context, merchUuids []string) (map[st
|
|||
return merchUuidMap, nil
|
||||
}
|
||||
|
||||
func (r *repo) getAllUserMerch(ctx context.Context, userId int64) ([]Merch, error) {
|
||||
var userMerch []Merch
|
||||
|
||||
q := `SELECT id, merch_uuid, name FROM merch WHERE user_id = $1 AND deleted_at IS NULL`
|
||||
|
||||
rows, err := r.db.Query(ctx, q, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var m Merch
|
||||
if err = rows.Scan(&m.Id, &m.MerchUuid, &m.Name); err != nil {
|
||||
rows.Close()
|
||||
return nil, err
|
||||
}
|
||||
userMerch = append(userMerch, m)
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userMerch, nil
|
||||
}
|
||||
|
||||
func (r *repo) deleteOneMerchRecord(ctx context.Context, userId int64, merchUuid string, delTime time.Time) error {
|
||||
tx, err := r.db.Begin(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -365,3 +394,78 @@ func (r *repo) getTaskData(ctx context.Context) ([]taskData, error) {
|
|||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *repo) getPricesWithDays(ctx context.Context, userId int64, days time.Time) ([]Price, error) {
|
||||
q := `
|
||||
SELECT mp.created_at, mp.merch_id, mp.price, mp.origin_id
|
||||
FROM merch_prices AS mp
|
||||
JOIN merch AS m ON m.id = mp.merch_id
|
||||
WHERE m.user_id = $1
|
||||
AND mp.created_at > $2
|
||||
AND mp.deleted_at IS NULL
|
||||
AND m.deleted_at IS NULL
|
||||
`
|
||||
|
||||
rows, err := r.db.Query(ctx, q, userId, days)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []Price
|
||||
for rows.Next() {
|
||||
var p Price
|
||||
if err = rows.Scan(&p.CreatedAt, &p.MerchId, &p.Price, &p.OriginId); err != nil {
|
||||
rows.Close()
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *repo) getDistinctPrices(ctx context.Context, userId int64, merchUuid string, days time.Time) ([]Price, error) {
|
||||
q := `
|
||||
SELECT price, created_at, origin_id
|
||||
FROM (
|
||||
SELECT DISTINCT ON (price) price, created_at, origin_id
|
||||
FROM merch_prices
|
||||
WHERE merch_id = (
|
||||
SELECT id
|
||||
FROM merch
|
||||
WHERE merch_uuid = $1
|
||||
AND user_id = $2
|
||||
AND deleted_at IS NULL
|
||||
)
|
||||
AND deleted_at IS NULL
|
||||
AND created_at > $3
|
||||
)
|
||||
ORDER BY created_at;
|
||||
`
|
||||
fmt.Println(merchUuid, userId, days)
|
||||
rows, err := r.db.Query(ctx, q, merchUuid, userId, days)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []Price
|
||||
for rows.Next() {
|
||||
var p Price
|
||||
if err = rows.Scan(&p.Price, &p.CreatedAt, &p.OriginId); err != nil {
|
||||
rows.Close()
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ package merch
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"merch-api/internal/user"
|
||||
"merch-api/pkg/utils"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const serviceLogHeader string = "[Service]"
|
||||
|
|
@ -111,6 +112,9 @@ func (s *service) createMerch(ctx context.Context, userId int64, payload *newMer
|
|||
return s.repo.createMerch(ctx, newMerch, merchExtra)
|
||||
}
|
||||
|
||||
// getOriginsMaps
|
||||
// first return name:id
|
||||
// second id:name
|
||||
func (s *service) getOriginsMaps(ctx context.Context) (map[string]int64, map[int64]string, error) {
|
||||
origins, err := s.repo.getOrigins(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -197,3 +201,121 @@ func (s *service) updateExtraData(ctx context.Context, userId int64, payload *ex
|
|||
func (s *service) deleteOneMerchRecord(ctx context.Context, userId int64, merchUuid string) error {
|
||||
return s.repo.deleteOneMerchRecord(ctx, userId, merchUuid, s.utils.TimeNowUTC())
|
||||
}
|
||||
|
||||
func (s *service) getPrices(ctx context.Context, userId int64, days int) ([]PricesResponse, error) {
|
||||
fmt.Println("Enter service")
|
||||
merchList, err := s.repo.getAllUserMerch(ctx, userId)
|
||||
if err != nil {
|
||||
logErr(serviceLogHeader, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(merchList) == 0 {
|
||||
errMsg := errors.New("no merch found")
|
||||
logErr(serviceLogHeader, errMsg)
|
||||
return nil, errMsg
|
||||
}
|
||||
|
||||
merchMap := make(map[int64]Merch, len(merchList))
|
||||
for _, merch := range merchList {
|
||||
merchMap[merch.Id] = merch
|
||||
}
|
||||
|
||||
var response []PricesResponse
|
||||
for _, item := range merchList {
|
||||
response = append(response, PricesResponse{
|
||||
MerchUuid: item.MerchUuid,
|
||||
Name: item.Name,
|
||||
Origins: []OriginWithPrices{},
|
||||
})
|
||||
}
|
||||
|
||||
pricesList, err := s.repo.getPricesWithDays(ctx, userId, getPeriod(days))
|
||||
if err != nil {
|
||||
logErr(serviceLogHeader, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, originNamesMap, err := s.getOriginsMaps(ctx)
|
||||
if err != nil {
|
||||
logErr(serviceLogHeader, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pricesMap := make(map[string]map[string][]PriceEntry)
|
||||
for _, item := range pricesList {
|
||||
merchUuid := merchMap[item.MerchId].MerchUuid
|
||||
|
||||
if _, ok := pricesMap[merchUuid]; !ok {
|
||||
pricesMap[merchUuid] = make(map[string][]PriceEntry)
|
||||
}
|
||||
|
||||
originName := originNamesMap[item.OriginId]
|
||||
pricesMap[merchUuid][originName] = append(pricesMap[merchUuid][originName], PriceEntry{
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
Value: item.Price,
|
||||
})
|
||||
}
|
||||
|
||||
for i := range response {
|
||||
for _, name := range originNamesMap {
|
||||
prices := pricesMap[response[i].MerchUuid][name]
|
||||
if prices == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
response[i].Origins = append(response[i].Origins, OriginWithPrices{
|
||||
Origin: name,
|
||||
Prices: prices,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *service) getDistinctPrices(ctx context.Context, userId int64, merchUuid string, days int) (*PricesResponse, error) {
|
||||
result, err := s.repo.getDistinctPrices(ctx, userId, merchUuid, getPeriod(days))
|
||||
if err != nil {
|
||||
logErr(serviceLogHeader, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
_, originNamesMap, err := s.getOriginsMaps(ctx)
|
||||
if err != nil {
|
||||
logErr(serviceLogHeader, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := PricesResponse{
|
||||
MerchUuid: merchUuid,
|
||||
Origins: []OriginWithPrices{},
|
||||
}
|
||||
|
||||
pricesMap := make(map[string][]PriceEntry)
|
||||
for _, item := range result {
|
||||
originName := originNamesMap[item.OriginId]
|
||||
if _, ok := pricesMap[originName]; !ok {
|
||||
pricesMap[originName] = make([]PriceEntry, 0)
|
||||
}
|
||||
|
||||
pricesMap[originName] = append(pricesMap[originName], PriceEntry{
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
Value: item.Price,
|
||||
})
|
||||
}
|
||||
|
||||
for key, item := range pricesMap {
|
||||
response.Origins = append(response.Origins, OriginWithPrices{
|
||||
Origin: key,
|
||||
Prices: item,
|
||||
})
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue