Skip to content

Commit 5870452

Browse files
authored
Merge pull request #18 from techbloghub/feat/posting-search
feat: 태그 검색 기능 추가
2 parents 672be9c + b9ee25c commit 5870452

File tree

1 file changed

+67
-25
lines changed

1 file changed

+67
-25
lines changed
Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package handler
22

33
import (
4+
"fmt"
45
"net/http"
6+
"strings"
57
"time"
68

9+
"entgo.io/ent/dialect/sql"
710
"github.com/gin-gonic/gin"
811
"github.com/techbloghub/server/ent"
12+
"github.com/techbloghub/server/ent/company"
913
"github.com/techbloghub/server/ent/posting"
1014
"github.com/techbloghub/server/internal/common"
1115
)
1216

13-
type TitleSearchResponse struct {
17+
type PostingSearchResponse struct {
1418
ID int `json:"posting_id"`
1519
Title string `json:"title"`
1620
Url string `json:"url"`
@@ -23,73 +27,111 @@ type TitleSearchResponse struct {
2327
}
2428

2529
type PostingSearchResponses struct {
26-
Count int `json:"count"`
27-
Postings []TitleSearchResponse `json:"postings"`
28-
HasNextPage bool `json:"has_next_page"`
30+
Count int `json:"count"`
31+
Postings []PostingSearchResponse `json:"postings"`
32+
HasNextPage bool `json:"has_next_page"`
2933
}
3034

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

36-
totalCount, err := countTotalPostings(client, titleSearchParam, c)
41+
postings, err := fetchPostings(client, titleSearchParam, tagsSearchParam, paging, c)
3742
if err != nil {
3843
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
3944
return
4045
}
4146

42-
postings, err := fetchPostings(client, titleSearchParam, paging, c)
47+
totalCount, err := countPostings(client, titleSearchParam, tagsSearchParam, c)
4348
if err != nil {
4449
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
4550
return
4651
}
4752

4853
c.JSON(http.StatusOK, PostingSearchResponses{
4954
Count: totalCount,
50-
Postings: convertToTitleSearchResponse(postings),
55+
Postings: toPostingSearchResponses(postings),
5156
HasNextPage: paging.HasNextPage(totalCount),
5257
})
5358
}
5459
}
5560

56-
func fetchPostings(client *ent.Client, title string, paging common.TechbloghubPaging, c *gin.Context) ([]*ent.Posting, error) {
57-
query := client.Posting.Query().WithCompany()
61+
func applySearchFilters(query *ent.PostingQuery, title, tags string) *ent.PostingQuery {
5862
if title != "" {
5963
query = query.Where(posting.TitleContainsFold(title))
6064
}
61-
if paging.Cursor > 0 {
62-
query = query.Where(posting.IDLT(paging.Cursor))
65+
// 태그 조회 케이스 -> postgresql ARRAY 검색 형식에 맞춰야함
66+
// tags: [react,java]
67+
// query : where tags @> ARRAY['react','java']
68+
if tags != "" {
69+
arr := strings.Split(tags, ",")
70+
arrayQuery := "ARRAY" + fmt.Sprintf("['%s']", strings.Join(arr, ","))
71+
72+
query = query.Where(func(s *sql.Selector) {
73+
s.Where(sql.ExprP(fmt.Sprintf("%s @> %s", s.C("tags"), arrayQuery)))
74+
})
6375
}
6476

65-
return query.Order(
66-
ent.Desc(posting.FieldPublishedAt),
67-
ent.Desc(posting.FieldID),
68-
).Limit(paging.Size).All(c)
77+
return query
6978
}
7079

71-
func countTotalPostings(client *ent.Client, title string, c *gin.Context) (int, error) {
80+
func fetchPostings(client *ent.Client, title, tags string, paging common.TechbloghubPaging, c *gin.Context) ([]*ent.Posting, error) {
7281
query := client.Posting.Query()
73-
if title != "" {
74-
query = query.Where(posting.TitleContainsFold(title))
82+
query = applySearchFilters(query, title, tags)
83+
84+
if paging.Cursor > common.CURSOR_DEFAULT {
85+
query = query.Where(posting.IDLT(paging.Cursor))
7586
}
87+
88+
return query.Where(posting.HasCompany()).
89+
WithCompany(func(q *ent.CompanyQuery) {
90+
q.Select(
91+
company.FieldLogoURL,
92+
company.FieldName,
93+
)
94+
}).
95+
Order(
96+
ent.Desc(posting.FieldPublishedAt),
97+
ent.Desc(posting.FieldID),
98+
).
99+
Limit(paging.Size).
100+
All(c.Request.Context())
101+
}
102+
103+
func countPostings(client *ent.Client, title, tags string, c *gin.Context) (int, error) {
104+
query := client.Posting.Query()
105+
query = applySearchFilters(query, title, tags)
76106
return query.Count(c)
77107
}
78108

79-
func convertToTitleSearchResponse(postings []*ent.Posting) []TitleSearchResponse {
80-
responses := make([]TitleSearchResponse, len(postings))
81-
for i, posting := range postings {
82-
responses[i] = TitleSearchResponse{
109+
// 대체 왜 못갖고오냐!!!!
110+
func getCompanyInfo(posting *ent.Posting) (string, string) {
111+
if posting.Edges.Company != nil {
112+
return posting.Edges.Company.Name, posting.Edges.Company.LogoURL.String()
113+
}
114+
return "Unknown", ""
115+
}
116+
117+
func toPostingSearchResponses(postings []*ent.Posting) []PostingSearchResponse {
118+
responses := make([]PostingSearchResponse, len(postings))
119+
120+
for _, posting := range postings {
121+
companyName, logoURL := getCompanyInfo(posting)
122+
123+
responses = append(responses, PostingSearchResponse{
83124
ID: posting.ID,
84125
Title: posting.Title,
85126
Url: posting.URL.String(),
86-
Company: posting.Edges.Company.Name,
87-
Logo: posting.Edges.Company.LogoURL.String(),
127+
Company: companyName,
128+
Logo: logoURL,
88129
Tags: posting.Tags.ToStringSlice(),
89130
CreateTime: posting.CreateTime,
90131
UpdateTime: posting.UpdateTime,
91132
PublishedTime: posting.PublishedAt,
92-
}
133+
})
93134
}
135+
94136
return responses
95137
}

0 commit comments

Comments
 (0)