package posts import ( "context" "database/sql" "backend/app/requests" "backend/database" "backend/database/models/qvyun_v2/public/model" "backend/database/models/qvyun_v2/public/table" "backend/providers/otel" . "github.com/go-jet/jet/v2/postgres" "github.com/samber/lo" log "github.com/sirupsen/logrus" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) // @provider:except type Service struct { db *sql.DB log *log.Entry `inject:"false"` } func (svc *Service) Prepare() error { svc.log = log.WithField("module", "posts.service") _ = Int(1) return nil } // GetBoughtPosts func (svc *Service) GetBoughtPosts(ctx context.Context, pagination *requests.Pagination, filter *UserPostFilter) ([]model.Posts, int64, error) { _, span := otel.Start(ctx, "users.service.GetBoughtPosts") defer span.End() span.SetAttributes( attribute.Int64("user.id", filter.UserID), attribute.Int64("page.page", pagination.Page), attribute.Int64("page.limit", pagination.Limit), ) tbl := table.Posts boughtIds, err := svc.GetUserBoughtIDs(ctx, filter.TenantID, filter.UserID) if err != nil { return nil, 0, err } if len(boughtIds) == 0 { return nil, 0, nil } idExprs := lo.Map(boughtIds, func(id int64, _ int) Expression { return Int64(id) }) cond := tbl.ID.IN( idExprs..., ).AND( tbl.TenantID.EQ(Int64(filter.TenantID)), ).AND( tbl.UserID.EQ(Int64(filter.UserID)), ) if filter.CreatedAt != nil { cond = cond.AND(tbl.CreatedAt.LT_EQ(TimestampT(*filter.CreatedAt))) } if filter.Keyword != nil { cond = cond.AND( tbl.Title. LIKE(String(database.WrapLike(*filter.Keyword))). OR( tbl.Description.LIKE(String(database.WrapLike(*filter.Keyword))), ). OR( tbl.Content.LIKE(String(database.WrapLike(*filter.Keyword))), ), ) } cntStmt := tbl.SELECT(COUNT(tbl.ID).AS("cnt")).WHERE(cond) span.SetAttributes(semconv.DBStatementKey.String(cntStmt.DebugSql())) var count struct { Cnt int64 } if err := cntStmt.QueryContext(ctx, svc.db, &count); err != nil { return nil, 0, err } stmt := tbl. SELECT(tbl.AllColumns). ORDER_BY(tbl.ID.DESC()). LIMIT(pagination.Limit). OFFSET(pagination.Offset()) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var posts []model.Posts if err := stmt.QueryContext(ctx, svc.db, &posts); err != nil { return nil, 0, err } return posts, count.Cnt, nil } // GetPosts func (svc *Service) GetPosts(ctx context.Context, pagination *requests.Pagination, filter *UserPostFilter) ([]model.Posts, int64, error) { _, span := otel.Start(ctx, "users.service.GetPosts") defer span.End() span.SetAttributes( attribute.Int64("user.id", filter.UserID), attribute.Int64("page.page", pagination.Page), attribute.Int64("page.limit", pagination.Limit), ) tbl := table.Posts cond := Bool(true) if filter.ID != nil { cond = cond.AND(tbl.ID.EQ(Int64(*filter.ID))) } if filter.UserID != 0 { cond = cond.AND(tbl.UserID.EQ(Int64(filter.UserID))) } if filter.CreatedAt != nil { cond = cond.AND(tbl.CreatedAt.LT_EQ(TimestampT(*filter.CreatedAt))) } if filter.TenantID != 0 { cond = cond.AND(tbl.TenantID.EQ(Int64(filter.TenantID))) } if filter.Keyword != nil { cond = cond.AND( tbl.Title. LIKE(String(database.WrapLike(*filter.Keyword))). OR( tbl.Description.LIKE(String(database.WrapLike(*filter.Keyword))), ). OR( tbl.Content.LIKE(String(database.WrapLike(*filter.Keyword))), ), ) } cntStmt := tbl.SELECT(COUNT(tbl.ID).AS("cnt")).WHERE(cond) span.SetAttributes(semconv.DBStatementKey.String(cntStmt.DebugSql())) var count struct { Cnt int64 } if err := cntStmt.QueryContext(ctx, svc.db, &count); err != nil { return nil, 0, err } stmt := tbl. SELECT(tbl.AllColumns). ORDER_BY(tbl.ID.DESC()). LIMIT(pagination.Limit). OFFSET(pagination.Offset()) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var posts []model.Posts if err := stmt.QueryContext(ctx, svc.db, &posts); err != nil { return nil, 0, err } return posts, count.Cnt, nil } // GetPostByHash func (svc *Service) GetPostByHash(ctx context.Context, tenantID int64, hash string) (*model.Posts, error) { _, span := otel.Start(ctx, "users.service.GetPostByHash") defer span.End() span.SetAttributes( attribute.String("hash", hash), ) tbl := table.Posts stmt := tbl. SELECT(tbl.AllColumns). WHERE( tbl.Hash.EQ(String(hash)).AND( tbl.TenantID.EQ(Int64(tenantID)), ), ) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) var post model.Posts if err := stmt.QueryContext(ctx, svc.db, &post); err != nil { return nil, err } return &post, nil } // GetUserBoughtPosts func (svc *Service) GetUserBoughtIDs(ctx context.Context, tenantID, userID int64) ([]int64, error) { _, span := otel.Start(ctx, "users.service.GetUserBoughtIDs") defer span.End() span.SetAttributes( attribute.Int64("tenant.id", tenantID), attribute.Int64("user.id", userID), ) tbl := table.UserBoughtPosts stmt := tbl. SELECT(tbl.PostID.AS("post_id")). WHERE( tbl.TenantID.EQ(Int64(tenantID)).AND( tbl.UserID.EQ(Int64(userID)), ), ) span.SetAttributes(semconv.DBStatementKey.String(stmt.DebugSql())) type tmp struct { PostID int64 } var results []tmp if err := stmt.QueryContext(ctx, svc.db, &results); err != nil { return nil, err } return lo.Map(results, func(item tmp, _ int) int64 { return item.PostID }), nil }