Skip to content

Commit

Permalink
Add timestamp query params (#895)
Browse files Browse the repository at this point in the history
* Add timestamp query params
* Fix transaction history count query
* Remove transaction count function
* update docs

---------

Signed-off-by: Stanislav Viyachev <[email protected]>
  • Loading branch information
Coiling-Dragon authored May 25, 2023
1 parent 00ccc0e commit 8c6b157
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 90 deletions.
3 changes: 1 addition & 2 deletions app/domain/repository/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,5 @@ type Transfer interface {
Create(ct *payload.Transfer) (*entity.Transfer, error)
UpdateStatusCompleted(txId string) error
UpdateStatusFailed(txId string) error
Paged(req *transfer.PagedRequest) ([]*entity.Transfer, error)
Count() (int64, error)
Paged(req *transfer.PagedRequest) ([]*entity.Transfer, int64, error)
}
1 change: 1 addition & 0 deletions app/domain/service/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ import "errors"

var ErrNotFound = errors.New("not found")
var ErrBadRequestTransferTargetNetworkNoSignaturesRequired = errors.New("transfer target network does not require signatures")
var ErrWrongQuery = errors.New("wrong query parameter")
3 changes: 3 additions & 0 deletions app/helper/http/error-response.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ func WriteErrorResponse(w http.ResponseWriter, r *http.Request, err error) {
case service.ErrNotFound:
render.Status(r, http.StatusNotFound)
render.JSON(w, r, response.ErrorResponse(err))
case service.ErrWrongQuery:
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, response.ErrorResponse(err))
default:
render.Status(r, http.StatusInternalServerError)
render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError))
Expand Down
10 changes: 5 additions & 5 deletions app/model/transfer/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ type PagedRequest struct {
}

type Filter struct {
Originator string `json:"originator"`
Timestamp time.Time `json:"timestamp"`
TokenId string `json:"tokenId"`
TransactionId string `json:"transactionId"`
Originator string `json:"originator"`
TimestampQuery string `json:"timestamp"`
TokenId string `json:"tokenId"`
TransactionId string `json:"transactionId"`
}

type SanityCheckResult struct {
Expand All @@ -72,5 +72,5 @@ type TransferReset struct {
SourceChainId uint64 `json:"sourceChainId"`
TargetChainId uint64 `json:"targetChainId"`
SourceToken string `json:"sourceToken"`
Password string `json:"password"`
Password string `json:"password"`
}
106 changes: 74 additions & 32 deletions app/persistence/transfer/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ import (
"database/sql"
"errors"
"fmt"
"github.com/limechain/hedera-eth-bridge-validator/constants"
"strings"
"time"

"github.com/limechain/hedera-eth-bridge-validator/constants"

"github.com/ethereum/go-ethereum/common"
"github.com/limechain/hedera-eth-bridge-validator/app/domain/service"
"github.com/limechain/hedera-eth-bridge-validator/app/model/transfer"
"github.com/limechain/hedera-eth-bridge-validator/app/process/payload"

Expand Down Expand Up @@ -135,15 +138,66 @@ func (r *Repository) UpdateStatusFailed(txId string) error {
return r.updateStatus(txId, status.Failed)
}

func (r *Repository) Paged(req *transfer.PagedRequest) ([]*entity.Transfer, error) {
func formatTimestampFilter(q *gorm.DB, ts_query string) (*gorm.DB, error) {
qParams := strings.Split(ts_query, "&")
operators := map[string]string{
"eq": "=",
"gt": ">",
"lt": "<",
"gte": ">=",
"lte": "<=",
}

// This if statement handles legacy timestamp filter like:
// "timestamp": "2023-04-19T04:41:47.104114905Z"
if len(qParams) == 1 && !strings.Contains(ts_query, "=") {
timestamp, err := time.Parse(time.RFC3339Nano, qParams[0])
if err != nil {
return q, err
}

q = q.Where("timestamp = ?", timestamp.UnixNano())
return q, nil
}

// This for loop handles new timestamp filter like:
// "timestamp": "lte=2023-05-19T04:41:47.104114905Z&gte=2023-04-19T04:41:47.104114905Z"
// "timestamp": "eq=2023-04-19T04:41:47.104114905Z"
for _, param := range qParams {
parts := strings.Split(param, "=")

operator := parts[0]
datetime, err := time.Parse(time.RFC3339Nano, parts[1])
if err != nil {
return q, err
}

timestamp := datetime.UnixNano()

op, exists := operators[operator]
if !exists {
return q, service.ErrWrongQuery
}

q = q.Where("timestamp "+op+" ?", timestamp)

}

return q, nil
}

func (r *Repository) Paged(req *transfer.PagedRequest) ([]*entity.Transfer, int64, error) {
var (
err error
count int64
)

offset := (req.Page - 1) * req.PageSize
res := make([]*entity.Transfer, 0, req.PageSize)
f := req.Filter
q := r.db.
Model(entity.Transfer{}).
Order("timestamp desc, status asc").
Offset(int(offset)).
Limit(int(req.PageSize))
Order("timestamp desc, status asc")

if f.Originator != "" {
if strings.Contains(f.Originator, "0x") {
Expand All @@ -153,8 +207,14 @@ func (r *Repository) Paged(req *transfer.PagedRequest) ([]*entity.Transfer, erro
q = q.Where("originator = ?", f.Originator)
}
}
if !f.Timestamp.IsZero() {
q = q.Where("timestamp = ?", f.Timestamp.UnixNano())

if f.TimestampQuery != "" {
q, err = formatTimestampFilter(q, f.TimestampQuery)
if err != nil {
r.logger.Errorf("Failed to get paged transfers: [%s]", err)
return nil, 0, err
}

}
if f.TokenId != "" {
if strings.Contains(f.TokenId, "0x") {
Expand All @@ -168,35 +228,17 @@ func (r *Repository) Paged(req *transfer.PagedRequest) ([]*entity.Transfer, erro
q = q.Where("transaction_id LIKE ?", fmt.Sprintf(`%s%%`, f.TransactionId))
}

err := q.Find(&res).Error
if err != nil {
r.logger.Errorf("Failed to get paged transfers: [%s]", err)
return nil, err
}

return res, nil
}

func (r *Repository) Count() (int64, error) {
db, err := r.db.DB()
if err != nil {
return 0, err
}
q = q.Count(&count).
Offset(int(offset)).
Limit(int(req.PageSize))

cur, err := db.Query(`SELECT COUNT(*) FROM (SELECT DISTINCT transaction_id FROM transfers) AS t`)
err = q.Find(&res).Error
if err != nil {
return 0, err
}
defer cur.Close()

var res int64
if cur.Next() {
if err := cur.Scan(&res); err != nil {
return 0, err
}
r.logger.Errorf("Failed to get paged transfers: [%s]", err)
return nil, 0, err
}

return res, nil
return res, count, nil
}

func (r *Repository) create(ct *payload.Transfer, status string) (*entity.Transfer, error) {
Expand Down
Loading

0 comments on commit 8c6b157

Please sign in to comment.