subreddits: moved to bob
This commit is contained in:
parent
4f2905233d
commit
c8c8cc892d
2
Makefile
2
Makefile
|
@ -43,7 +43,7 @@ build: build-dependencies prepare
|
||||||
|
|
||||||
prepare: gen
|
prepare: gen
|
||||||
mkdir -p public
|
mkdir -p public
|
||||||
tailwindcss -i views/styles.css -o public/styles.css
|
tailwindcss -i views/style.css -o public/style.css
|
||||||
templ generate
|
templ generate
|
||||||
|
|
||||||
gen:
|
gen:
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
|
"github.com/stephenafamo/bob"
|
||||||
"github.com/teivah/broadcast"
|
"github.com/teivah/broadcast"
|
||||||
"github.com/tigorlazuardi/redmage/api/bmessage"
|
"github.com/tigorlazuardi/redmage/api/bmessage"
|
||||||
"github.com/tigorlazuardi/redmage/api/reddit"
|
"github.com/tigorlazuardi/redmage/api/reddit"
|
||||||
|
@ -18,6 +19,7 @@ import (
|
||||||
type API struct {
|
type API struct {
|
||||||
queries *queries.Queries
|
queries *queries.Queries
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
|
exec bob.Executor
|
||||||
|
|
||||||
scheduler *cron.Cron
|
scheduler *cron.Cron
|
||||||
scheduleMap map[cron.EntryID]queries.Subreddit
|
scheduleMap map[cron.EntryID]queries.Subreddit
|
||||||
|
@ -43,6 +45,7 @@ func New(deps Dependencies) *API {
|
||||||
return &API{
|
return &API{
|
||||||
queries: deps.Queries,
|
queries: deps.Queries,
|
||||||
db: deps.DB,
|
db: deps.DB,
|
||||||
|
exec: bob.New(deps.DB),
|
||||||
scheduler: cron.New(),
|
scheduler: cron.New(),
|
||||||
scheduleMap: make(map[cron.EntryID]queries.Subreddit, 8),
|
scheduleMap: make(map[cron.EntryID]queries.Subreddit, 8),
|
||||||
downloadBroadcast: broadcast.NewRelay[bmessage.ImageDownloadMessage](),
|
downloadBroadcast: broadcast.NewRelay[bmessage.ImageDownloadMessage](),
|
||||||
|
|
|
@ -3,7 +3,10 @@ package api
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/tigorlazuardi/redmage/db/queries"
|
"github.com/stephenafamo/bob"
|
||||||
|
"github.com/stephenafamo/bob/dialect/sqlite/dialect"
|
||||||
|
"github.com/stephenafamo/bob/dialect/sqlite/sm"
|
||||||
|
"github.com/tigorlazuardi/redmage/models"
|
||||||
"github.com/tigorlazuardi/redmage/pkg/errs"
|
"github.com/tigorlazuardi/redmage/pkg/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,46 +14,57 @@ type ListSubredditsParams struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Limit int64 `json:"limit"`
|
Limit int64 `json:"limit"`
|
||||||
Offset int64 `json:"offset"`
|
Offset int64 `json:"offset"`
|
||||||
|
OrderBy string `json:"order_by"`
|
||||||
|
Sort string `json:"sort"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l ListSubredditsParams) Query() (expr []bob.Mod[*dialect.SelectQuery]) {
|
||||||
|
if l.Name != "" {
|
||||||
|
expr = append(expr, models.SelectWhere.Subreddits.Name.Like("%"+l.Name+"%"))
|
||||||
|
}
|
||||||
|
if l.Limit > 0 {
|
||||||
|
expr = append(expr, sm.Limit(l.Limit))
|
||||||
|
}
|
||||||
|
if l.Offset > 0 {
|
||||||
|
expr = append(expr, sm.Offset(l.Offset))
|
||||||
|
}
|
||||||
|
if l.OrderBy != "" {
|
||||||
|
if l.Sort == "desc" {
|
||||||
|
expr = append(expr, sm.OrderBy(l.OrderBy).Desc())
|
||||||
|
} else {
|
||||||
|
expr = append(expr, sm.OrderBy(l.OrderBy).Asc())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l ListSubredditsParams) CountQuery() (expr []bob.Mod[*dialect.SelectQuery]) {
|
||||||
|
if l.Name != "" {
|
||||||
|
expr = append(expr, models.SelectWhere.Subreddits.Name.Like("%"+l.Name+"%"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return expr
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListSubredditsResult struct {
|
type ListSubredditsResult struct {
|
||||||
Total int64
|
Total int64
|
||||||
Data []queries.Subreddit
|
Data models.SubredditSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) ListSubreddits(ctx context.Context, arg ListSubredditsParams) (result ListSubredditsResult, err error) {
|
func (api *API) ListSubreddits(ctx context.Context, arg ListSubredditsParams) (result ListSubredditsResult, err error) {
|
||||||
ctx, span := tracer.Start(ctx, "api.ListSubreddits")
|
ctx, span := tracer.Start(ctx, "api.ListSubreddits")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
if arg.Name != "" {
|
|
||||||
result.Data, err = api.queries.SubredditsSearch(ctx, queries.SubredditsSearchParams{
|
result.Data, err = models.Subreddits.Query(ctx, api.exec, arg.Query()...).All()
|
||||||
Name: "%" + arg.Name + "%",
|
|
||||||
Limit: arg.Limit,
|
|
||||||
Offset: arg.Offset,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, errs.Wrapw(err, "failed to search subreddit", "query", arg)
|
return result, errs.Wrapw(err, "failed to list subreddits", "query", arg)
|
||||||
}
|
|
||||||
result.Total, err = api.queries.SubredditsSearchCount(ctx, queries.SubredditsSearchCountParams{
|
|
||||||
Name: "%" + arg.Name + "%",
|
|
||||||
Limit: arg.Limit,
|
|
||||||
Offset: arg.Offset,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return result, errs.Wrapw(err, "failed to count subreddit search", "query", arg)
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Data, err = api.queries.SubredditsList(ctx, queries.SubredditsListParams{
|
result.Total, err = models.Subreddits.Query(ctx, api.exec, arg.CountQuery()...).Count()
|
||||||
Limit: arg.Limit,
|
|
||||||
Offset: arg.Offset,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, errs.Wrapw(err, "failed to list subreddit", "query", arg)
|
return result, errs.Wrapw(err, "failed to count subreddits", "query", arg)
|
||||||
}
|
}
|
||||||
result.Total, err = api.queries.SubredditsListCount(ctx)
|
|
||||||
if err != nil {
|
return result, nil
|
||||||
return result, errs.Wrapw(err, "failed to count subreddit list", "query", arg)
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (ch *ChiEntry) Write(status int, bytes int, header http.Header, elapsed tim
|
||||||
message := fmt.Sprintf("%s %s %d %s", ch.request.Method, ch.request.URL, status, elasedStr)
|
message := fmt.Sprintf("%s %s %d %s", ch.request.Method, ch.request.URL, status, elasedStr)
|
||||||
|
|
||||||
requestLog := slog.Attr{Key: "request", Value: ch.extractRequestLog()}
|
requestLog := slog.Attr{Key: "request", Value: ch.extractRequestLog()}
|
||||||
responseLog := slog.Group("response", "status", status, "headers", flatHeader(header), "bytes", bytes)
|
responseLog := slog.Group("response", "status", status, "headers", flat(header), "bytes", bytes)
|
||||||
roundtripLog := slog.String("elapsed", elasedStr)
|
roundtripLog := slog.String("elapsed", elasedStr)
|
||||||
|
|
||||||
group := slog.Group("http", requestLog, responseLog, roundtripLog)
|
group := slog.Group("http", requestLog, responseLog, roundtripLog)
|
||||||
|
@ -57,13 +57,13 @@ func (ch *ChiEntry) extractRequestLog() slog.Value {
|
||||||
)
|
)
|
||||||
queries := ch.request.URL.Query()
|
queries := ch.request.URL.Query()
|
||||||
if len(queries) > 0 {
|
if len(queries) > 0 {
|
||||||
values = append(values, slog.Any("query", queries))
|
values = append(values, slog.Any("query", flat(queries)))
|
||||||
}
|
}
|
||||||
values = append(values, slog.Any("headers", flatHeader(ch.request.Header)))
|
values = append(values, slog.Any("headers", flat(ch.request.Header)))
|
||||||
return slog.GroupValue(values...)
|
return slog.GroupValue(values...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func flatHeader(header http.Header) map[string]string {
|
func flat(header map[string][]string) map[string]string {
|
||||||
m := make(map[string]string, len(header))
|
m := make(map[string]string, len(header))
|
||||||
|
|
||||||
for k := range header {
|
for k := range header {
|
||||||
|
|
|
@ -40,6 +40,7 @@ func (routes *Routes) registerV1APIRoutes(router chi.Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (routes *Routes) registerWWWRoutes(router chi.Router) {
|
func (routes *Routes) registerWWWRoutes(router chi.Router) {
|
||||||
|
router.Use(chimiddleware.Compress(5, "text/html", "text/css", "application/javascript"))
|
||||||
router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir))))
|
router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir))))
|
||||||
|
|
||||||
router.Group(func(r chi.Router) {
|
router.Group(func(r chi.Router) {
|
||||||
|
|
Loading…
Reference in a new issue