From dbb754199f182937eeeeeaf2e40cf54ab5bdf05c Mon Sep 17 00:00:00 2001 From: Tigor Hutasuhut Date: Thu, 15 Aug 2024 16:02:23 +0700 Subject: [PATCH] api: implemented list subreddits endpoint --- go/api/subreddits_list.go | 76 +++++++++++++++++++++++++++++++++ go/converts/subreddit.go | 27 +++++++++++- go/server/subreddit_handlers.go | 14 ++++-- 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 go/api/subreddits_list.go diff --git a/go/api/subreddits_list.go b/go/api/subreddits_list.go new file mode 100644 index 0000000..2b5233a --- /dev/null +++ b/go/api/subreddits_list.go @@ -0,0 +1,76 @@ +package api + +import ( + "context" + + "github.com/tigorlazuardi/bluemage/go/gen/jet/model" + "github.com/tigorlazuardi/bluemage/go/pkg/errs" + "github.com/tigorlazuardi/bluemage/go/pkg/telemetry" + + . "github.com/go-jet/jet/v2/sqlite" + . "github.com/tigorlazuardi/bluemage/go/gen/jet/table" +) + +type ListSubredditsRequest struct { + Search string + Disabled *bool + Limit int64 + Offset int64 + OrderBy string + Sort Sort +} + +func (request ListSubredditsRequest) Statement() SelectStatement { + cond := Bool(true) + + if request.Search != "" { + cond.AND(Subreddits.Name.LIKE(String("%" + request.Search + "%"))) + } + if request.Disabled != nil { + b := *request.Disabled + if b { + cond.AND(Subreddits.Disabled.EQ(Int(1))) + } else { + cond.AND(Subreddits.Disabled.EQ(Int(0))) + } + } + + stmt := SELECT(Subreddits.AllColumns).WHERE(cond) + + if request.Limit > 0 { + stmt.LIMIT(request.Limit) + } + + if request.Offset > 0 { + stmt.OFFSET(request.Offset) + } + + if request.OrderBy == "" { + return stmt.ORDER_BY(Subreddits.UpdatedAt.DESC()) + } + + orderBy := StringColumn(request.OrderBy) + if request.Sort == SortDesc { + return stmt.ORDER_BY(orderBy.DESC()) + } else { + return stmt.ORDER_BY(orderBy.ASC()) + } +} + +func (api *API) ListSubreddits(ctx context.Context, request ListSubredditsRequest) (subreddits []model.Subreddits, err error) { + ctx, span := tracer.Start(ctx, "ListSubreddits") + defer func() { telemetry.EndWithStatus(span, err) }() + + stmt := request.Statement() + err = stmt.QueryContext(ctx, api.DB, &subreddits) + if err != nil { + err = errs.Wrapw( + err, "failed to list subreddits", + "request", request, + "query", stmt.DebugSql(), + ) + return subreddits, err + } + + return subreddits, nil +} diff --git a/go/converts/subreddit.go b/go/converts/subreddit.go index 3ef224e..958305e 100644 --- a/go/converts/subreddit.go +++ b/go/converts/subreddit.go @@ -1,6 +1,8 @@ package converts import ( + "strings" + "github.com/aarondl/opt/omit" "github.com/tigorlazuardi/bluemage/go/api" "github.com/tigorlazuardi/bluemage/go/gen/jet/model" @@ -30,6 +32,8 @@ import ( // goverter:extend SubredditsDisabledFilterToPtrBool // goverter:extend Int8ToSubredditDisabledFilter // goverter:extend StringToSubredditType +// goverter:extend SubredditsOrderByToString +// goverter:extend SubredditsSortToString type SubredditConverter interface { // goverter:ignore CreatedAt UpdatedAt CoverImageID CreateSubredditRequestToModelsSubredditSetter(*subreddits.CreateSubredditRequest) *models.SubredditSetter @@ -39,7 +43,11 @@ type SubredditConverter interface { // goverter:ignore state sizeCache unknownFields // goverter:map CoverImageID CoverImageId - JetSubredditToProtoGetSubredditResponse(model.Subreddits) *subreddits.Subreddit + JetSubredditToProtoSubreddit(model.Subreddits) *subreddits.Subreddit + JetSubredditsToProtoSubreddits([]model.Subreddits) []*subreddits.Subreddit + + // goverter:useZeroValueOnPointerInconsistency + ProtoListSubredditsRequestToAPIListSubredditsRequest(*subreddits.ListSubredditsRequest) api.ListSubredditsRequest } func SubredditTypeToString(subType subreddits.SubredditType) string { @@ -53,6 +61,7 @@ func SubredditTypeToOmitString(subType subreddits.SubredditType) omit.Val[string if subType == subreddits.SubredditType_SUBREDDIT_TYPE_USER { return omit.From("user") } + return omit.From("r") } @@ -79,3 +88,19 @@ func StringToSubredditType(s string) subreddits.SubredditType { } return subreddits.SubredditType_SUBREDDIT_TYPE_SUBREDDIT } + +func SubredditsOrderByToString(order subreddits.OrderBy) string { + if order == subreddits.OrderBy_ORDER_BY_UNSPECIFIED { + return "" + } + field, _ := strings.CutPrefix(subreddits.OrderBy_name[int32(order)], "ORDER_BY_") + field = strings.ToLower(field) + return field +} + +func SubredditsSortToString(sort subreddits.Sort) api.Sort { + if sort == subreddits.Sort_SORT_DESCENDING { + return api.SortDesc + } + return api.SortAsc +} diff --git a/go/server/subreddit_handlers.go b/go/server/subreddit_handlers.go index badc4cf..8be3993 100644 --- a/go/server/subreddit_handlers.go +++ b/go/server/subreddit_handlers.go @@ -63,14 +63,22 @@ func (su *SubredditHandler) GetSubreddit(ctx context.Context, request *connect.R } resp := &subreddits.GetSubredditResponse{ - Subreddit: subredditConverter.JetSubredditToProtoGetSubredditResponse(data), + Subreddit: subredditConverter.JetSubredditToProtoSubreddit(data), } return connect.NewResponse(resp), nil } // ListSubreddits returns a list of subreddits. -func (su *SubredditHandler) ListSubreddits(_ context.Context, _ *connect.Request[subreddits.ListSubredditsRequest]) (*connect.Response[subreddits.ListSubredditsResponse], error) { - panic("not implemented") // TODO: Implement +func (su *SubredditHandler) ListSubreddits(ctx context.Context, request *connect.Request[subreddits.ListSubredditsRequest]) (*connect.Response[subreddits.ListSubredditsResponse], error) { + req := subredditConverter.ProtoListSubredditsRequestToAPIListSubredditsRequest(request.Msg) + subs, err := su.API.ListSubreddits(ctx, req) + if err != nil { + return nil, errs.IntoConnectError(err) + } + resp := &subreddits.ListSubredditsResponse{ + Subreddits: subredditConverter.JetSubredditsToProtoSubreddits(subs), + } + return connect.NewResponse(resp), nil } // UpdateSubreddit updates a subreddit.