Skip to content

Commit

Permalink
Feature: search app by name (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
aopoltorzhicky authored Dec 26, 2024
1 parent 5107e9f commit 80e7cdd
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 3 deletions.
43 changes: 43 additions & 0 deletions cmd/api/handler/responses/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,46 @@ func NewAppWithStats(r storage.AppWithStats) AppWithStats {

return app
}

type App struct {
Id uint64 `example:"321" format:"integer" json:"id" swaggertype:"integer"`
Name string `example:"Rollup name" format:"string" json:"name" swaggertype:"string"`
Description string `example:"Long rollup description" format:"string" json:"description,omitempty" swaggertype:"string"`
Website string `example:"https://website.com" format:"string" json:"website,omitempty" swaggertype:"string"`
Twitter string `example:"https://x.com/account" format:"string" json:"twitter,omitempty" swaggertype:"string"`
Github string `example:"https://github.com/account" format:"string" json:"github,omitempty" swaggertype:"string"`
Logo string `example:"https://some_link.com/image.png" format:"string" json:"logo,omitempty" swaggertype:"string"`
Slug string `example:"rollup_slug" format:"string" json:"slug" swaggertype:"string"`
L2Beat string `example:"https://l2beat.com/scaling/projects/karak" format:"string" json:"l2_beat,omitempty" swaggertype:"string"`
Explorer string `example:"https://explorer.karak.network/" format:"string" json:"explorer,omitempty" swaggertype:"string"`
Stack string `example:"op_stack" format:"string" json:"stack,omitempty" swaggertype:"string"`
Type string `example:"settled" format:"string" json:"type,omitempty" swaggertype:"string"`
Category string `example:"nft" format:"string" json:"category,omitempty" swaggertype:"string"`
VM string `example:"evm" format:"string" json:"vm,omitempty" swaggertype:"string"`
Provider string `example:"name" format:"string" json:"provider,omitempty" swaggertype:"string"`

Links []string `json:"links,omitempty"`
}

func NewApp(r storage.App) AppWithStats {
app := AppWithStats{
Id: r.Id,
Name: r.Name,
Description: r.Description,
Github: r.Github,
Twitter: r.Twitter,
Website: r.Website,
Logo: r.Logo,
L2Beat: r.L2Beat,
Explorer: r.Explorer,
Links: r.Links,
Stack: r.Stack,
Slug: r.Slug,
Category: r.Category.String(),
Type: r.Type.String(),
Provider: r.Provider,
VM: r.VM,
}

return app
}
9 changes: 9 additions & 0 deletions cmd/api/handler/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type SearchHandler struct {
rollups storage.IRollup
bridges storage.IBridge
validators storage.IValidator
app storage.IApp
}

func NewSearchHandler(
Expand All @@ -31,6 +32,7 @@ func NewSearchHandler(
rollups storage.IRollup,
bridges storage.IBridge,
validators storage.IValidator,
app storage.IApp,
) *SearchHandler {
return &SearchHandler{
constantCache: constantCache,
Expand All @@ -41,6 +43,7 @@ func NewSearchHandler(
rollups: rollups,
bridges: bridges,
validators: validators,
app: app,
}
}

Expand Down Expand Up @@ -113,6 +116,12 @@ func (s *SearchHandler) Search(c echo.Context) error {
return handleError(c, err, s.address)
}
body = responses.NewBridge(bridge)
case "app":
app, err := s.app.GetByID(c.Request().Context(), results[i].Id)
if err != nil {
return handleError(c, err, s.address)
}
body = responses.NewApp(*app)
}

response[i] = responses.NewSearchResult(results[i].Value, results[i].Type, body)
Expand Down
43 changes: 42 additions & 1 deletion cmd/api/handler/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type SearchTestSuite struct {
rollups *mock.MockIRollup
validators *mock.MockIValidator
bridges *mock.MockIBridge
app *mock.MockIApp
echo *echo.Echo
handler *SearchHandler
ctrl *gomock.Controller
Expand All @@ -47,8 +48,9 @@ func (s *SearchTestSuite) SetupSuite() {
s.rollups = mock.NewMockIRollup(s.ctrl)
s.validators = mock.NewMockIValidator(s.ctrl)
s.bridges = mock.NewMockIBridge(s.ctrl)
s.app = mock.NewMockIApp(s.ctrl)
cc := cache.NewConstantsCache(nil)
s.handler = NewSearchHandler(cc, s.search, s.address, s.blocks, s.txs, s.rollups, s.bridges, s.validators)
s.handler = NewSearchHandler(cc, s.search, s.address, s.blocks, s.txs, s.rollups, s.bridges, s.validators, s.app)
}

// TearDownSuite -
Expand Down Expand Up @@ -303,3 +305,42 @@ func (s *SearchTestSuite) TestSearchBridge() {
s.Require().Equal("name", result.Value)
s.Require().NotNil(result.Body)
}

func (s *SearchTestSuite) TestSearchApp() {
q := make(url.Values)
q.Add("query", "app")

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

s.search.EXPECT().
Search(gomock.Any(), "app").
Return([]storage.SearchResult{
{
Type: "app",
Value: testApplication.Name,
Id: 1,
},
}, nil).
Times(1)

s.app.EXPECT().
GetByID(gomock.Any(), uint64(1)).
Return(&testApplication, nil).
Times(1)

s.Require().NoError(s.handler.Search(c))
s.Require().Equal(http.StatusOK, rec.Code)

var results []responses.SearchResult
err := json.NewDecoder(rec.Body).Decode(&results)
s.Require().NoError(err)
s.Require().Len(results, 1)

result := results[0]
s.Require().Equal("app", result.Type)
s.Require().Equal("test app", result.Value)
s.Require().NotNil(result.Body)
}
2 changes: 1 addition & 1 deletion cmd/api/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func initHandlers(ctx context.Context, e *echo.Echo, cfg Config, db postgres.Sto
panic(err)
}

searchHandler := handler.NewSearchHandler(constantCache, db.Search, db.Address, db.Blocks, db.Tx, db.Rollup, db.Bridges, db.Validator)
searchHandler := handler.NewSearchHandler(constantCache, db.Search, db.Address, db.Blocks, db.Tx, db.Rollup, db.Bridges, db.Validator, db.App)
v1.GET("/search", searchHandler.Search)

addressHandler := handler.NewAddressHandler(constantCache, db.Address, db.Tx, db.Action, db.Rollup, db.Fee, db.Bridges, db.Deposit, db.State, cfg.Indexer.Name)
Expand Down
9 changes: 8 additions & 1 deletion internal/storage/postgres/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ func (s *Search) Search(ctx context.Context, query string) (results []storage.Se
ColumnExpr("id, asset as value, 'bridge' as type").
Where("asset ILIKE ?", text)

searchQuery = searchQuery.UnionAll(bridgeQuery)
appQuery := s.db.DB().NewSelect().
Model((*storage.App)(nil)).
ColumnExpr("id, name as value, 'app' as type").
Where("name ILIKE ?", text)

searchQuery = searchQuery.
UnionAll(bridgeQuery).
UnionAll(appQuery)

if height, err := strconv.ParseInt(query, 10, 64); err == nil {
heightQuery := s.db.DB().NewSelect().
Expand Down
14 changes: 14 additions & 0 deletions internal/storage/postgres/search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,17 @@ func (s *StorageTestSuite) TestSearchRollupByHash() {
s.Require().EqualValues("19ba8abb3e4b56a309df6756c47b97e298e3a72d88449d36a0fadb1ca7366539", result.Value)
s.Require().EqualValues("rollup", result.Type)
}

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

results, err := s.storage.Search.Search(ctx, "p 1")
s.Require().NoError(err)
s.Require().Len(results, 1)

result := results[0]
s.Require().EqualValues("App 1", result.Value)
s.Require().EqualValues("app", result.Type)
s.Require().EqualValues(1, result.Id)
}

0 comments on commit 80e7cdd

Please sign in to comment.