Skip to content

Commit

Permalink
Merge pull request #306 from celenium-io/feat/rollup-grouped-stats
Browse files Browse the repository at this point in the history
Feat/rollup grouped stats
  • Loading branch information
k-karuna authored Nov 15, 2024
2 parents cdb8da1 + 392a1dd commit fbc3b9a
Show file tree
Hide file tree
Showing 10 changed files with 219 additions and 0 deletions.
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
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

0 comments on commit fbc3b9a

Please sign in to comment.