Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/rollup grouped stats #306

Merged
merged 8 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions cmd/api/handler/responses/rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,21 @@ func NewRollupWithDayStats(r storage.RollupWithDayStats) RollupWithDayStats {

return response
}

type RollupGroupedStats struct {
Fee float64 `example:"123.456789" format:"string" json:"fee" swaggertype:"string"`
Size float64 `example:"1000" format:"integer" json:"size" swaggertype:"integer"`
BlobsCount int64 `example:"2" format:"integer" json:"blobs_count" swaggertype:"integer"`
Group string `example:"group" format:"string" json:"group" swaggertype:"string"`
}

func NewRollupGroupedStats(r storage.RollupGroupedStats) RollupGroupedStats {
response := RollupGroupedStats{
Fee: r.Fee,
Size: r.Size,
BlobsCount: r.BlobsCount,
Group: r.Group,
}

return response
}
40 changes: 40 additions & 0 deletions cmd/api/handler/rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,43 @@ func (handler RollupHandler) ExportBlobs(c echo.Context) error {
}
return nil
}

type rollupGroupStats struct {
Func string `query:"func" validate:"oneof=sum avg"`
Column string `query:"column" validate:"oneof=stack type category vm provider"`
}

// RollupGroupedStats godoc
//
// @Summary Rollup Grouped Statistics
// @Description Rollup Grouped Statistics
// @Tags rollup
// @ID rollup-grouped-statistics
// @Param func query string false "Aggregate function" Enums(sum, avg)
// @Param column query string false "Group column" Enums(stack, type, category, vm, provider)
// @Produce json
// @Success 200 {array} responses.RollupGroupedStats
// @Failure 400 {object} Error
// @Failure 500 {object} Error
// @Router /rollup/group [get]
func (handler RollupHandler) RollupGroupedStats(c echo.Context) error {
req, err := bindAndValidate[rollupGroupStats](c)
if err != nil {
return badRequestError(c, err)
}

rollups, err := handler.rollups.RollupStatsGrouping(c.Request().Context(), storage.RollupGroupStatsFilters{
Func: req.Func,
Column: req.Column,
})
if err != nil {
return handleError(c, err, handler.rollups)
}

response := make([]responses.RollupGroupedStats, len(rollups))
for i := range rollups {
response[i] = responses.NewRollupGroupedStats(rollups[i])
}

return returnArray(c, response)
}
52 changes: 52 additions & 0 deletions cmd/api/handler/rollup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ var (
SizePct: 0.3,
},
}
testRollupWithGroupedStats = storage.RollupGroupedStats{
Fee: 0.1,
Size: 0.2,
BlobsCount: 3,
Group: "stack",
}
)

// RollupTestSuite -
Expand Down Expand Up @@ -470,3 +476,49 @@ func (s *RollupTestSuite) TestAllSeries() {
s.Require().EqualValues(1, item.BlobsCount)
s.Require().EqualValues(testTime, item.Time)
}

func (s *RollupTestSuite) TestRollupStatsGrouping() {
for _, funcName := range []string{
"sum",
"avg",
} {
for _, groupName := range []string{
"stack",
"type",
"category",
"vm",
"provider",
} {
q := make(url.Values)
q.Add("func", funcName)
q.Add("column", groupName)

req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
rec := httptest.NewRecorder()
c := s.echo.NewContext(req, rec)
c.SetPath("/rollup/group")

s.rollups.EXPECT().
RollupStatsGrouping(gomock.Any(), storage.RollupGroupStatsFilters{
Func: funcName,
Column: groupName,
}).
Return([]storage.RollupGroupedStats{testRollupWithGroupedStats}, nil).
Times(1)

s.Require().NoError(s.handler.RollupGroupedStats(c))
s.Require().Equal(http.StatusOK, rec.Code)
var stats []responses.RollupGroupedStats
err := json.NewDecoder(rec.Body).Decode(&stats)
s.Require().NoError(err)
s.Require().Len(stats, 1)

groupedStats := stats[0]

s.Require().EqualValues(0.1, groupedStats.Fee)
s.Require().EqualValues(0.2, groupedStats.Size)
s.Require().EqualValues(3, groupedStats.BlobsCount)
s.Require().EqualValues("stack", groupedStats.Group)
}
}
}
1 change: 1 addition & 0 deletions cmd/api/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ func initHandlers(ctx context.Context, e *echo.Echo, cfg Config, db postgres.Sto
rollups.GET("", rollupHandler.Leaderboard)
rollups.GET("/count", rollupHandler.Count)
rollups.GET("/day", rollupHandler.LeaderboardDay)
rollups.GET("/group", rollupHandler.RollupGroupedStats)
rollups.GET("/stats/series", rollupHandler.AllSeries)
rollups.GET("/slug/:slug", rollupHandler.BySlug)
rollup := rollups.Group("/:id")
Expand Down
1 change: 1 addition & 0 deletions cmd/api/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func TestRoutes(t *testing.T) {
"/v1/stats/rollup_stats_24h GET": {},
"/v1/stats/messages_count_24h GET": {},
"/v1/rollup/stats/series GET": {},
"/v1/rollup/group GET": {},
}

ctx, cancel := context.WithCancel(context.Background())
Expand Down
40 changes: 40 additions & 0 deletions internal/storage/mock/rollup.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions internal/storage/postgres/rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,32 @@ func (r *Rollup) AllSeries(ctx context.Context) (items []storage.RollupHistogram

return
}

func (r *Rollup) RollupStatsGrouping(ctx context.Context, fltrs storage.RollupGroupStatsFilters) (results []storage.RollupGroupedStats, err error) {
query := r.DB().NewSelect().Table(storage.ViewLeaderboard)

switch fltrs.Func {
case "sum":
query = query.
ColumnExpr("sum(fee) as fee").
ColumnExpr("sum(size) as size").
ColumnExpr("sum(blobs_count) as blobs_count")
case "avg":
query = query.
ColumnExpr("avg(fee) as fee").
ColumnExpr("avg(size) as size").
ColumnExpr("avg(blobs_count) as blobs_count")
default:
return nil, errors.Errorf("unknown func field: %s", fltrs.Column)
}

switch fltrs.Column {
case "stack", "type", "category", "vm", "provider":
query = query.ColumnExpr(fltrs.Column + " as group").Group(fltrs.Column)
default:
return nil, errors.Errorf("unknown column field: %s", fltrs.Column)
}

err = query.Scan(ctx, &results)
return
}
22 changes: 22 additions & 0 deletions internal/storage/postgres/rollup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,25 @@ func (s *StorageTestSuite) TestRollupAllSeries() {
s.Require().NoError(err)
s.Require().Len(items, 5)
}

func (s *StorageTestSuite) TestRollupStatsGrouping() {
ctx, ctxCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer ctxCancel()

_, err := s.storage.Connection().Exec(ctx, "REFRESH MATERIALIZED VIEW leaderboard;")
s.Require().NoError(err)

column := "stack"
rollups, err := s.storage.Rollup.RollupStatsGrouping(ctx, storage.RollupGroupStatsFilters{
Func: "sum",
Column: column,
})
s.Require().NoError(err, column)
s.Require().Len(rollups, 2, column)

rollup := rollups[1]
s.Require().EqualValues(4000, rollup.Fee, column)
s.Require().EqualValues(52, rollup.Size, column)
s.Require().EqualValues(4, rollup.BlobsCount, column)
s.Require().EqualValues("OP Stack", rollup.Group, column)
}
13 changes: 13 additions & 0 deletions internal/storage/rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ type LeaderboardFilters struct {
Type []types.RollupType
}

type RollupGroupStatsFilters struct {
Func string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тест на запрос в Бд)

И здесь теги 'bun', наверное, нужны

Copy link
Collaborator Author

@k-karuna k-karuna Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты про какие теги bun? В RollupGroupStatsFilters их нет вроде бы..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А, да. Это ж фильтры😁

Column string
}

//go:generate mockgen -source=$GOFILE -destination=mock/$GOFILE -package=mock -typed
type IRollup interface {
sdk.Table[*Rollup]
Expand All @@ -37,6 +42,7 @@ type IRollup interface {
Count(ctx context.Context) (int64, error)
Distribution(ctx context.Context, rollupId uint64, series, groupBy string) (items []DistributionItem, err error)
BySlug(ctx context.Context, slug string) (RollupWithStats, error)
RollupStatsGrouping(ctx context.Context, fltrs RollupGroupStatsFilters) ([]RollupGroupedStats, error)
}

// Rollup -
Expand Down Expand Up @@ -129,3 +135,10 @@ type RollupHistogramItem struct {
Logo string `bun:"logo"`
Time time.Time `bun:"time"`
}

type RollupGroupedStats struct {
Fee float64 `bun:"fee"`
Size float64 `bun:"size"`
BlobsCount int64 `bun:"blobs_count"`
Group string `bun:"group"`
}
3 changes: 3 additions & 0 deletions test/data/rollup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
logo: https://rollup1.com/image.png
slug: rollup_1
category: finance
stack: OP Stack
type: settled
- id: 2
name: Rollup 2
Expand All @@ -17,6 +18,7 @@
logo: https://rollup2.com/image.png
slug: rollup_2
category: gaming
stack: OP Stack
type: settled
- id: 3
name: Rollup 3
Expand All @@ -27,4 +29,5 @@
logo: https://rollup3.com/image.png
slug: rollup_3
category: nft
stack: Custom Stack
type: sovereign
Loading