From 756d2acca2edfcb3858d4294d181d88da70d4bfc Mon Sep 17 00:00:00 2001 From: Wellington Junior Date: Wed, 23 Aug 2023 13:25:08 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20the=20query=20params?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/docs/docs.go | 6 +- backend/docs/swagger.json | 6 +- backend/docs/swagger.yaml | 6 +- backend/internal/controller/http/v1/assets.go | 36 ++++++------ .../controller/http/v1/log_transaction.go | 33 +++++------ .../usecase/repo/log_transaction_postgres.go | 58 +++++++++++-------- 6 files changed, 77 insertions(+), 68 deletions(-) diff --git a/backend/docs/docs.go b/backend/docs/docs.go index dd305c45..08b0111f 100644 --- a/backend/docs/docs.go +++ b/backend/docs/docs.go @@ -573,16 +573,16 @@ const docTemplate = `{ }, { "type": "string", - "description": "Time range for the query (e.g., '24h')", + "description": "Time range for the query (e.g., '24h', ", "name": "time_range", "in": "path", "required": true }, { "type": "string", - "description": "Time frame for grouping (e.g., '1h'). Default is '1h'", + "description": "Time frame for the query (e.g., '1h')", "name": "time_frame", - "in": "query" + "in": "path" } ], "responses": { diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json index 79f5923a..7c9cf654 100644 --- a/backend/docs/swagger.json +++ b/backend/docs/swagger.json @@ -561,16 +561,16 @@ }, { "type": "string", - "description": "Time range for the query (e.g., '24h')", + "description": "Time range for the query (e.g., '24h', ", "name": "time_range", "in": "path", "required": true }, { "type": "string", - "description": "Time frame for grouping (e.g., '1h'). Default is '1h'", + "description": "Time frame for the query (e.g., '1h')", "name": "time_frame", - "in": "query" + "in": "path" } ], "responses": { diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml index 7b22f6db..164d22ed 100644 --- a/backend/docs/swagger.yaml +++ b/backend/docs/swagger.yaml @@ -805,13 +805,13 @@ paths: name: asset_id required: true type: integer - - description: Time range for the query (e.g., '24h') + - description: 'Time range for the query (e.g., ''24h'', ' in: path name: time_range required: true type: string - - description: Time frame for grouping (e.g., '1h'). Default is '1h' - in: query + - description: Time frame for the query (e.g., '1h') + in: path name: time_frame type: string produces: diff --git a/backend/internal/controller/http/v1/assets.go b/backend/internal/controller/http/v1/assets.go index 9c237c6e..5a019ae9 100644 --- a/backend/internal/controller/http/v1/assets.go +++ b/backend/internal/controller/http/v1/assets.go @@ -222,13 +222,13 @@ func (r *assetsRoutes) createAsset(c *gin.Context) { token := c.Request.Header.Get("Authorization") user, err := r.a.GetUserByToken(token) if err != nil { - errorResponse(c, http.StatusNotFound, "user not found") + errorResponse(c, http.StatusNotFound, "user not found", err) return } userID, err := strconv.Atoi(user.ID) if err != nil { - errorResponse(c, http.StatusNotFound, "error to parse user id") + errorResponse(c, http.StatusNotFound, "error to parse user id", err) } amount, err := strconv.ParseFloat(request.Amount, 64) @@ -243,7 +243,7 @@ func (r *assetsRoutes) createAsset(c *gin.Context) { Description: createLogDescription(entity.CreateAsset, asset.Code, nil, nil), }) if err != nil { - errorResponse(c, http.StatusNotFound, "error to create log transaction") + errorResponse(c, http.StatusNotFound, "error to create log transaction", err) return } @@ -308,13 +308,13 @@ func (r *assetsRoutes) mintAsset(c *gin.Context) { token := c.Request.Header.Get("Authorization") user, err := r.a.GetUserByToken(token) if err != nil { - errorResponse(c, http.StatusNotFound, "user not found") + errorResponse(c, http.StatusNotFound, "user not found", err) return } userID, err := strconv.Atoi(user.ID) if err != nil { - errorResponse(c, http.StatusNotFound, "error to parse user id") + errorResponse(c, http.StatusNotFound, "error to parse user id", err) } amount, err := strconv.ParseFloat(request.Amount, 64) @@ -329,7 +329,7 @@ func (r *assetsRoutes) mintAsset(c *gin.Context) { Description: createLogDescription(entity.MintAsset, asset.Code, nil, nil), }) if err != nil { - errorResponse(c, http.StatusNotFound, "error to create log transaction") + errorResponse(c, http.StatusNotFound, "error to create log transaction", err) return } @@ -396,13 +396,13 @@ func (r *assetsRoutes) burnAsset(c *gin.Context) { token := c.Request.Header.Get("Authorization") user, err := r.a.GetUserByToken(token) if err != nil { - errorResponse(c, http.StatusNotFound, "user not found") + errorResponse(c, http.StatusNotFound, "user not found", err) return } userID, err := strconv.Atoi(user.ID) if err != nil { - errorResponse(c, http.StatusNotFound, "error to parse user id") + errorResponse(c, http.StatusNotFound, "error to parse user id", err) } amount, err := strconv.ParseFloat(request.Amount, 64) @@ -417,7 +417,7 @@ func (r *assetsRoutes) burnAsset(c *gin.Context) { Description: createLogDescription(entity.BurnAsset, asset.Code, nil, nil), }) if err != nil { - errorResponse(c, http.StatusNotFound, "error to create log transaction") + errorResponse(c, http.StatusNotFound, "error to create log transaction", err) return } @@ -490,13 +490,13 @@ func (r *assetsRoutes) transferAsset(c *gin.Context) { token := c.Request.Header.Get("Authorization") user, err := r.a.GetUserByToken(token) if err != nil { - errorResponse(c, http.StatusNotFound, "user not found") + errorResponse(c, http.StatusNotFound, "user not found", err) return } userID, err := strconv.Atoi(user.ID) if err != nil { - errorResponse(c, http.StatusNotFound, "error to parse user id") + errorResponse(c, http.StatusNotFound, "error to parse user id", err) } amount, err := strconv.ParseFloat(request.Amount, 64) @@ -511,7 +511,7 @@ func (r *assetsRoutes) transferAsset(c *gin.Context) { Description: createLogDescription(entity.TransferAsset, asset.Code, nil, nil), }) if err != nil { - errorResponse(c, http.StatusNotFound, "error to create log transaction") + errorResponse(c, http.StatusNotFound, "error to create log transaction", err) return } @@ -578,13 +578,13 @@ func (r *assetsRoutes) clawbackAsset(c *gin.Context) { token := c.Request.Header.Get("Authorization") user, err := r.a.GetUserByToken(token) if err != nil { - errorResponse(c, http.StatusNotFound, "user not found") + errorResponse(c, http.StatusNotFound, "user not found", err) return } userID, err := strconv.Atoi(user.ID) if err != nil { - errorResponse(c, http.StatusNotFound, "error to parse user id") + errorResponse(c, http.StatusNotFound, "error to parse user id", err) } amount, err := strconv.ParseFloat(request.Amount, 64) @@ -599,7 +599,7 @@ func (r *assetsRoutes) clawbackAsset(c *gin.Context) { Description: createLogDescription(entity.ClawbackAsset, asset.Code, nil, nil), }) if err != nil { - errorResponse(c, http.StatusNotFound, "error to create log transaction") + errorResponse(c, http.StatusNotFound, "error to create log transaction", err) return } @@ -673,13 +673,13 @@ func (r *assetsRoutes) updateAuthFlags(c *gin.Context) { token := c.Request.Header.Get("Authorization") user, err := r.a.GetUserByToken(token) if err != nil { - errorResponse(c, http.StatusNotFound, "user not found") + errorResponse(c, http.StatusNotFound, "user not found", err) return } userID, err := strconv.Atoi(user.ID) if err != nil { - errorResponse(c, http.StatusNotFound, "error to parse user id") + errorResponse(c, http.StatusNotFound, "error to parse user id", err) } err = r.l.CreateLogTransaction(entity.LogTransaction{ @@ -689,7 +689,7 @@ func (r *assetsRoutes) updateAuthFlags(c *gin.Context) { Description: createLogDescription(entity.UpdateAuthFlags, asset.Code, request.SetFlags, request.ClearFlags), }) if err != nil { - errorResponse(c, http.StatusNotFound, "error to create log transaction") + errorResponse(c, http.StatusNotFound, "error to create log transaction", err) return } diff --git a/backend/internal/controller/http/v1/log_transaction.go b/backend/internal/controller/http/v1/log_transaction.go index 45622770..6aa0faef 100644 --- a/backend/internal/controller/http/v1/log_transaction.go +++ b/backend/internal/controller/http/v1/log_transaction.go @@ -45,7 +45,7 @@ func (r *logTransactionsRoutes) getLogTransactions(c *gin.Context) { logTransactions, err := r.l.GetLogTransactions(timeRange) if err != nil { - errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error())) + errorResponse(c, http.StatusInternalServerError, "error getting log transactions: %s", err) return } @@ -67,13 +67,13 @@ func (r *logTransactionsRoutes) getLogTransactionsByAssetID(c *gin.Context) { assetID, err := strconv.Atoi(assetIDStr) if err != nil { - errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid asset ID: %s", err.Error())) + errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid asset ID: %s", err.Error()), err) return } logTransactions, err := r.l.GetLogTransactionsByAssetID(assetID, timeRange) if err != nil { - errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error())) + errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error()), err) return } @@ -95,13 +95,13 @@ func (r *logTransactionsRoutes) getLogTransactionsByUserID(c *gin.Context) { userID, err := strconv.Atoi(userIDStr) if err != nil { - errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid user ID: %s", err.Error())) + errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid user ID: %s", err.Error()), err) return } logTransactions, err := r.l.GetLogTransactionsByUserID(userID, timeRange) if err != nil { - errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error())) + errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error()), err) return } @@ -123,13 +123,13 @@ func (r *logTransactionsRoutes) getLogTransactionsByTransactionTypeID(c *gin.Con transactionTypeID, err := strconv.Atoi(transactionTypeIDStr) if err != nil { - errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid asset ID: %s", err.Error())) + errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid asset ID: %s", err.Error()), err) return } logTransactions, err := r.l.GetLogTransactionsByTransactionTypeID(transactionTypeID, timeRange) if err != nil { - errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error())) + errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error()), err) return } @@ -142,8 +142,8 @@ func (r *logTransactionsRoutes) getLogTransactionsByTransactionTypeID(c *gin.Con // @Accept json // @Produce json // @Param asset_id path int true "Asset ID" -// @Param time_range path string true "Time range for the query (e.g., '24h')" -// @Param time_frame query string false "Time frame for grouping (e.g., '1h'). Default is '1h'" +// @Param time_range path string true "Time range for the query (e.g., '24h', "7d")" +// @Param time_frame path string false "Time frame for the query (e.g., '1h')". // @Security ApiKeyAuth // @Success 200 {object} entity.SumLogTransaction "Sum log transaction for the specified asset" // @Failure 400 {string} string "Invalid time_frame format" @@ -152,23 +152,23 @@ func (r *logTransactionsRoutes) getLogTransactionsByTransactionTypeID(c *gin.Con func (r *logTransactionsRoutes) sumAmountsByAssetID(c *gin.Context) { assetIDStr := c.Param("asset_id") timeRange := c.Param("time_range") - timeFrame := c.DefaultQuery("time_frame", "1h") // Default to 1 hour if not provided + timeFrame := c.Param("time_frame") duration, err := time.ParseDuration(timeFrame) if err != nil { - errorResponse(c, http.StatusBadRequest, "Invalid time_frame format") + errorResponse(c, http.StatusBadRequest, "Invalid time_frame format", err) return } assetID, err := strconv.Atoi(assetIDStr) if err != nil { - errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid asset ID: %s", err.Error())) + errorResponse(c, http.StatusBadRequest, fmt.Sprintf("invalid asset ID: %s", err.Error()), err) return } sum, err := r.l.SumLogTransactionsByAssetID(assetID, timeRange, duration) if err != nil { - errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error())) + errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error()), err) return } @@ -189,17 +189,16 @@ func (r *logTransactionsRoutes) sumAmountsByAssetID(c *gin.Context) { // @Router /log_transactions/assets/sum/{time_range}/{time_frame} [get] func (r *logTransactionsRoutes) sumAmountsForAllAssets(c *gin.Context) { timeRange := c.Param("time_range") - timeFrame := c.DefaultQuery("time_frame", "1h") // Default to 1 hour if not provided + timeFrame := c.Param("time_frame") duration, err := time.ParseDuration(timeFrame) if err != nil { - errorResponse(c, http.StatusBadRequest, "Invalid time_frame format") + errorResponse(c, http.StatusBadRequest, "Invalid time_frame format", err) return } - sum, err := r.l.SumLogTransactions(timeRange, duration) if err != nil { - errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error())) + errorResponse(c, http.StatusInternalServerError, fmt.Sprintf("error getting log transactions: %s", err.Error()), err) return } diff --git a/backend/internal/usecase/repo/log_transaction_postgres.go b/backend/internal/usecase/repo/log_transaction_postgres.go index 95efddba..dccb7a39 100644 --- a/backend/internal/usecase/repo/log_transaction_postgres.go +++ b/backend/internal/usecase/repo/log_transaction_postgres.go @@ -51,17 +51,20 @@ func (repo *LogTransactionRepo) SumLogTransactionsByAssetID(assetID int, timeRan } timeFrameUnit := getTimeFrame(timeFrame) + timeFrameSeconds := timeFrame.Seconds() query := ` - SELECT a.id, a.name, a.code, a.asset_type, SUM(lt.amount), DATE_TRUNC($3, lt.date) as dateFrame - FROM logtransactions AS lt - JOIN asset AS a ON lt.asset_id = a.id - WHERE lt.date >= $1 AND lt.asset_id = $2 - GROUP BY a.id, dateFrame - ORDER BY a.id, dateFrame - ` - - rows, err := repo.Db.Query(query, dateFilter, assetID, timeFrameUnit) + SELECT + a.id, a.name, a.code, a.asset_type, SUM(lt.amount), + DATE_TRUNC($3, TIMESTAMP 'epoch' + INTERVAL '1 second' * floor(EXTRACT(EPOCH FROM lt.date)/$4) * $4) as dateFrame + FROM logtransactions AS lt + JOIN asset AS a ON lt.asset_id = a.id + WHERE lt.date >= $1 AND lt.asset_id = $2 + GROUP BY a.id, dateFrame + ORDER BY a.id, dateFrame; + ` + + rows, err := repo.Db.Query(query, dateFilter, assetID, timeFrameUnit, timeFrameSeconds) if err != nil { return entity.SumLogTransaction{}, err } @@ -89,21 +92,24 @@ func (repo *LogTransactionRepo) SumLogTransactionsByAssetID(assetID int, timeRan func (repo *LogTransactionRepo) SumLogTransactions(timeRange string, timeFrame time.Duration) ([]entity.SumLogTransaction, error) { dateFilter, err := getDateFilter(timeRange) if err != nil { - return nil, err + return []entity.SumLogTransaction{}, err } timeFrameUnit := getTimeFrame(timeFrame) + timeFrameSeconds := timeFrame.Seconds() query := ` - SELECT a.id, a.name, a.code, a.asset_type, SUM(lt.amount), DATE_TRUNC($2, lt.date) as dateFrame - FROM logtransactions AS lt - JOIN asset AS a ON lt.asset_id = a.id - WHERE lt.date >= $1 - GROUP BY a.id, dateFrame - ORDER BY a.id, dateFrame - ` - - rows, err := repo.Db.Query(query, dateFilter, timeFrameUnit) + SELECT + a.id, a.name, a.code, a.asset_type, SUM(lt.amount), + DATE_TRUNC($2, TIMESTAMP 'epoch' + INTERVAL '1 second' * floor(EXTRACT(EPOCH FROM lt.date)/$3) * $3) as dateFrame + FROM logtransactions AS lt + JOIN asset AS a ON lt.asset_id = a.id + WHERE lt.date >= $1 + GROUP BY a.id, dateFrame + ORDER BY a.id, dateFrame; + ` + + rows, err := repo.Db.Query(query, dateFilter, timeFrameUnit, timeFrameSeconds) if err != nil { return nil, err } @@ -183,17 +189,21 @@ func getDateFilter(timeRange string) (time.Time, error) { return time.Time{}, fmt.Errorf("invalid numeric value in time range: %s", err.Error()) } - var duration time.Duration + currentTime := time.Now() switch unit { case 'h': - duration = time.Duration(-value) * time.Hour + return currentTime.Add(time.Duration(-value) * time.Hour), nil case 'd': - duration = time.Duration(-value) * 24 * time.Hour + // If value is 1, return the start of the current day. + if value == 1 { + return time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location()), nil + } + // For other values, adjust the date accordingly. + targetDate := currentTime.AddDate(0, 0, -value+1) + return time.Date(targetDate.Year(), targetDate.Month(), targetDate.Day(), 0, 0, 0, 0, targetDate.Location()), nil default: return time.Time{}, fmt.Errorf("invalid time unit in time range") } - - return time.Now().Add(duration), nil } func getTimeFrame(timeFrame time.Duration) string {