Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 67 additions & 25 deletions internal/http/handler/postinghandler.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package handler

import (
"fmt"
"net/http"
"strings"
"time"

"entgo.io/ent/dialect/sql"
"github.com/gin-gonic/gin"
"github.com/techbloghub/server/ent"
"github.com/techbloghub/server/ent/company"
"github.com/techbloghub/server/ent/posting"
"github.com/techbloghub/server/internal/common"
)

type TitleSearchResponse struct {
type PostingSearchResponse struct {
ID int `json:"posting_id"`
Title string `json:"title"`
Url string `json:"url"`
Expand All @@ -23,73 +27,111 @@ type TitleSearchResponse struct {
}

type PostingSearchResponses struct {
Count int `json:"count"`
Postings []TitleSearchResponse `json:"postings"`
HasNextPage bool `json:"has_next_page"`
Count int `json:"count"`
Postings []PostingSearchResponse `json:"postings"`
HasNextPage bool `json:"has_next_page"`
}

func GetPostings(client *ent.Client) gin.HandlerFunc {
return func(c *gin.Context) {
titleSearchParam := c.DefaultQuery("title", "")
tagsSearchParam := c.DefaultQuery("tags", "")
paging := common.GenerateTechPaging(c.Query("cursor"), c.Query("size"))

totalCount, err := countTotalPostings(client, titleSearchParam, c)
postings, err := fetchPostings(client, titleSearchParam, tagsSearchParam, paging, c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

postings, err := fetchPostings(client, titleSearchParam, paging, c)
totalCount, err := countPostings(client, titleSearchParam, tagsSearchParam, c)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}

c.JSON(http.StatusOK, PostingSearchResponses{
Count: totalCount,
Postings: convertToTitleSearchResponse(postings),
Postings: toPostingSearchResponses(postings),
HasNextPage: paging.HasNextPage(totalCount),
})
}
}

func fetchPostings(client *ent.Client, title string, paging common.TechbloghubPaging, c *gin.Context) ([]*ent.Posting, error) {
query := client.Posting.Query().WithCompany()
func applySearchFilters(query *ent.PostingQuery, title, tags string) *ent.PostingQuery {
if title != "" {
query = query.Where(posting.TitleContainsFold(title))
}
if paging.Cursor > 0 {
query = query.Where(posting.IDLT(paging.Cursor))
// 태그 조회 케이스 -> postgresql ARRAY 검색 형식에 맞춰야함
// tags: [react,java]
// query : where tags @> ARRAY['react','java']
if tags != "" {
arr := strings.Split(tags, ",")
arrayQuery := "ARRAY" + fmt.Sprintf("['%s']", strings.Join(arr, ","))

query = query.Where(func(s *sql.Selector) {
s.Where(sql.ExprP(fmt.Sprintf("%s @> %s", s.C("tags"), arrayQuery)))
})
}

return query.Order(
ent.Desc(posting.FieldPublishedAt),
ent.Desc(posting.FieldID),
).Limit(paging.Size).All(c)
return query
}

func countTotalPostings(client *ent.Client, title string, c *gin.Context) (int, error) {
func fetchPostings(client *ent.Client, title, tags string, paging common.TechbloghubPaging, c *gin.Context) ([]*ent.Posting, error) {
query := client.Posting.Query()
if title != "" {
query = query.Where(posting.TitleContainsFold(title))
query = applySearchFilters(query, title, tags)

if paging.Cursor > common.CURSOR_DEFAULT {
query = query.Where(posting.IDLT(paging.Cursor))
}

return query.Where(posting.HasCompany()).
WithCompany(func(q *ent.CompanyQuery) {
q.Select(
company.FieldLogoURL,
company.FieldName,
)
}).
Order(
ent.Desc(posting.FieldPublishedAt),
ent.Desc(posting.FieldID),
).
Limit(paging.Size).
All(c.Request.Context())
}

func countPostings(client *ent.Client, title, tags string, c *gin.Context) (int, error) {
query := client.Posting.Query()
query = applySearchFilters(query, title, tags)
return query.Count(c)
}

func convertToTitleSearchResponse(postings []*ent.Posting) []TitleSearchResponse {
responses := make([]TitleSearchResponse, len(postings))
for i, posting := range postings {
responses[i] = TitleSearchResponse{
// 대체 왜 못갖고오냐!!!!
func getCompanyInfo(posting *ent.Posting) (string, string) {
if posting.Edges.Company != nil {
return posting.Edges.Company.Name, posting.Edges.Company.LogoURL.String()
}
return "Unknown", ""
}

func toPostingSearchResponses(postings []*ent.Posting) []PostingSearchResponse {
responses := make([]PostingSearchResponse, len(postings))

for _, posting := range postings {
companyName, logoURL := getCompanyInfo(posting)

responses = append(responses, PostingSearchResponse{
ID: posting.ID,
Title: posting.Title,
Url: posting.URL.String(),
Company: posting.Edges.Company.Name,
Logo: posting.Edges.Company.LogoURL.String(),
Company: companyName,
Logo: logoURL,
Tags: posting.Tags.ToStringSlice(),
CreateTime: posting.CreateTime,
UpdateTime: posting.UpdateTime,
PublishedTime: posting.PublishedAt,
}
})
}

return responses
}