Bluemage/go/api/images_list.go

148 lines
3.4 KiB
Go
Raw Normal View History

2024-08-24 19:21:01 +07:00
package api
import (
"context"
"fmt"
"github.com/tigorlazuardi/bluemage/go/gen/jet/model"
2024-08-25 12:43:57 +07:00
"github.com/tigorlazuardi/bluemage/go/pkg/errs"
2024-08-24 19:21:01 +07:00
"github.com/tigorlazuardi/bluemage/go/pkg/telemetry"
. "github.com/go-jet/jet/v2/sqlite"
. "github.com/tigorlazuardi/bluemage/go/gen/jet/table"
)
type ImageListRequest struct {
Subreddits []string
Devices []string
Limit int64
After int64
Before int64
OrderBy string
Sort Sort
Search string
NSFW *bool
Blacklist *bool
}
// CREATE VIRTUAL TABLE images_fts5 USING fts5(
//
// post_author,
// post_title,
// post_name,
// image_relative_path,
// post_url,
// post_author_url,
// content='images',
// content_rowid='id'
//
// );
//
// matching list:
//
// - Author's name
// - Post Title
// - Post ID
// - Author's ID
// - Image filename (url path suffix to get this image from web browser)
// - Image original url
// - Post url
// - Author's url
var imagesFTSBM25 = fmt.Sprintf("bm25(%s, 25, 20, 10, 5, 3, 3)", ImagesFts5.TableName())
func (request ImageListRequest) Statement() SelectStatement {
2024-08-25 12:43:57 +07:00
// TODO: Change top level select query to WITH query
// so the result can be sorted by Devices and Subreddits.
cond := request.WhereExpression()
2024-08-24 19:21:01 +07:00
from := Images
2024-08-25 12:43:57 +07:00
if len(request.Search) > 0 {
cond.AND(ImagesFts5.ImagesFts5.EQ(String(request.Search)))
from.INNER_JOIN(ImagesFts5, Images.PostName.EQ(ImagesFts5.PostName))
stmt := SELECT(Images.AllColumns).FROM(from).WHERE(cond)
if request.Limit > 0 {
stmt.LIMIT(request.Limit)
}
return stmt.ORDER_BY(RawString(imagesFTSBM25).DESC())
}
stmt := SELECT(Images.AllColumns).FROM(from).WHERE(cond)
if request.Limit > 0 {
stmt.LIMIT(request.Limit)
}
if request.OrderBy == "" {
return stmt.ORDER_BY(Images.CreatedAt.DESC())
}
orderBy := StringColumn(request.OrderBy)
if request.Sort == SortDesc {
return stmt.ORDER_BY(orderBy.DESC())
}
return stmt.ORDER_BY(orderBy.ASC())
}
func (request ImageListRequest) WhereExpression() BoolExpression {
cond := Bool(true)
if len(request.Devices) > 0 {
cond.AND(Images.Device.IN(stringSliceExpressions(request.Devices)...))
}
if len(request.Subreddits) > 0 {
cond.AND(Images.Subreddit.IN(stringSliceExpressions(request.Subreddits)...))
}
2024-08-24 19:21:01 +07:00
if request.NSFW != nil {
n := *request.NSFW
if n {
cond.AND(Images.Nsfw.EQ(Int(1)))
} else {
cond.AND(Images.Nsfw.EQ(Int(0)))
}
}
if request.Blacklist != nil {
b := *request.Blacklist
if b {
cond.AND(Images.Blacklisted.EQ(Int(1)))
} else {
cond.AND(Images.Blacklisted.EQ(Int(0)))
}
}
if request.After > 0 {
cond.AND(Images.CreatedAt.LT_EQ(Int(request.After)))
}
if request.Before > 0 {
cond.AND(Images.CreatedAt.GT_EQ(Int(request.Before)))
}
2024-08-25 12:43:57 +07:00
return cond
2024-08-24 19:21:01 +07:00
}
2024-08-25 12:43:57 +07:00
// ImageList list images by request.
func (api *API) ImageList(ctx context.Context, request ImageListRequest) (images []model.Images, err error) {
2024-08-24 19:21:01 +07:00
ctx, span := tracer.Start(ctx, "ImageList")
defer func() { telemetry.EndWithStatus(span, err) }()
2024-08-25 12:43:57 +07:00
stmt := request.Statement()
if err := stmt.QueryContext(ctx, api.DB, &images); err != nil {
return images, errs.Wrapw(err, "failed to list images",
"request", request,
"query", stmt.DebugSql(),
)
}
2024-08-24 19:21:01 +07:00
return images, err
}
2024-08-25 12:43:57 +07:00
func stringSliceExpressions(s []string) []Expression {
var expr []Expression
if s != nil {
expr = make([]Expression, len(s))
for i, str := range s {
expr[i] = String(str)
}
}
return expr
}