@@ -2,7 +2,7 @@ import { Pool } from 'pg';
22import logger from '@/configs/logger.config' ;
33import { DBError } from '@/exception' ;
44import { TotalStatsType } from '@/types' ;
5- import { getCurrentKSTDateString , getKSTDateStringWithOffset } from '@/utils/date.util' ;
5+ import { getKSTDateStringWithOffset } from '@/utils/date.util' ;
66
77interface RawStatsResult {
88 date : string ;
@@ -110,46 +110,9 @@ export class TotalStatsRepository {
110110 async getUserBadgeStats ( username : string , dateRange : number = 30 ) {
111111 try {
112112 const pastDateKST = getKSTDateStringWithOffset ( - dateRange * 24 * 60 ) ;
113- const nowDateKST =
114- new Date ( ) . getUTCHours ( ) === 15 ? getKSTDateStringWithOffset ( - 24 * 60 ) : getCurrentKSTDateString ( ) ;
113+ const query = buildBadgeStatsQuery ( ) ;
115114
116- const query = `
117- WITH
118- today_stats AS (
119- SELECT DISTINCT ON (post_id)
120- post_id,
121- daily_view_count AS today_view,
122- daily_like_count AS today_like
123- FROM posts_postdailystatistics
124- WHERE date = $2
125- ORDER BY post_id, date DESC
126- ),
127- start_stats AS (
128- SELECT DISTINCT ON (post_id)
129- post_id,
130- daily_view_count AS start_view,
131- daily_like_count AS start_like
132- FROM posts_postdailystatistics
133- WHERE date = $3
134- ORDER BY post_id, date DESC
135- )
136- SELECT
137- u.username,
138- COALESCE(SUM(ts.today_view), 0) AS total_views,
139- COALESCE(SUM(ts.today_like), 0) AS total_likes,
140- COUNT(DISTINCT CASE WHEN p.is_active = true THEN p.id END) AS total_posts,
141- SUM(COALESCE(ts.today_view, 0) - COALESCE(ss.start_view, 0)) AS view_diff,
142- SUM(COALESCE(ts.today_like, 0) - COALESCE(ss.start_like, 0)) AS like_diff,
143- COUNT(DISTINCT CASE WHEN p.released_at >= $3 AND p.is_active = true THEN p.id END) AS post_diff
144- FROM users_user u
145- LEFT JOIN posts_post p ON p.user_id = u.id
146- LEFT JOIN today_stats ts ON ts.post_id = p.id
147- LEFT JOIN start_stats ss ON ss.post_id = p.id
148- WHERE u.username = $1
149- GROUP BY u.username
150- ` ;
151-
152- const result = await this . pool . query ( query , [ username , nowDateKST , pastDateKST ] ) ;
115+ const result = await this . pool . query ( query , [ username , pastDateKST ] ) ;
153116 return result . rows [ 0 ] || null ;
154117 } catch ( error ) {
155118 logger . error ( 'TotalStatsRepository getUserBadgeStats error:' , error ) ;
@@ -160,46 +123,9 @@ export class TotalStatsRepository {
160123 async getUserRecentPosts ( username : string , dateRange : number = 30 , limit : number = 4 ) {
161124 try {
162125 const pastDateKST = getKSTDateStringWithOffset ( - dateRange * 24 * 60 ) ;
163- const nowDateKST =
164- new Date ( ) . getUTCHours ( ) === 15 ? getKSTDateStringWithOffset ( - 24 * 60 ) : getCurrentKSTDateString ( ) ;
126+ const query = buildRecentPostsQuery ( ) ;
165127
166- const query = `
167- WITH
168- today_stats AS (
169- SELECT DISTINCT ON (post_id)
170- post_id,
171- daily_view_count AS today_view,
172- daily_like_count AS today_like
173- FROM posts_postdailystatistics
174- WHERE date = $3
175- ORDER BY post_id, date DESC
176- ),
177- start_stats AS (
178- SELECT DISTINCT ON (post_id)
179- post_id,
180- daily_view_count AS start_view,
181- daily_like_count AS start_like
182- FROM posts_postdailystatistics
183- WHERE date = $4
184- ORDER BY post_id, date DESC
185- )
186- SELECT
187- p.title,
188- p.released_at,
189- COALESCE(ts.today_view, 0) AS today_view,
190- COALESCE(ts.today_like, 0) AS today_like,
191- (COALESCE(ts.today_view, 0) - COALESCE(ss.start_view, 0)) AS view_diff
192- FROM posts_post p
193- JOIN users_user u ON u.id = p.user_id
194- LEFT JOIN today_stats ts ON ts.post_id = p.id
195- LEFT JOIN start_stats ss ON ss.post_id = p.id
196- WHERE u.username = $1
197- AND p.is_active = true
198- ORDER BY p.released_at DESC
199- LIMIT $2
200- ` ;
201-
202- const result = await this . pool . query ( query , [ username , limit , nowDateKST , pastDateKST ] ) ;
128+ const result = await this . pool . query ( query , [ username , limit , pastDateKST ] ) ;
203129 return result . rows ;
204130 } catch ( error ) {
205131 logger . error ( 'TotalStatsRepository getUserRecentPosts error:' , error ) ;
@@ -231,3 +157,84 @@ export class TotalStatsRepository {
231157 }
232158 }
233159}
160+
161+ function buildUserPostsCTE ( includeTitle : boolean = false , includeLimit : boolean = false ) : string {
162+ const titleColumn = includeTitle ? ', p.title' : '' ;
163+ const limitClause = includeLimit ? 'ORDER BY p.released_at DESC\n LIMIT $2' : '' ;
164+
165+ return `
166+ user_posts AS (
167+ SELECT p.id${ titleColumn } , p.released_at
168+ FROM posts_post p
169+ INNER JOIN users_user u ON u.id = p.user_id
170+ WHERE u.username = $1 AND p.is_active = true
171+ ${ limitClause }
172+ )` ;
173+ }
174+
175+ function buildLatestStatsCTE ( ) : string {
176+ return `
177+ latest_stats AS (
178+ SELECT DISTINCT ON (pds.post_id)
179+ pds.post_id,
180+ pds.daily_view_count AS total_view,
181+ pds.daily_like_count AS total_like
182+ FROM posts_postdailystatistics pds
183+ INNER JOIN user_posts up ON up.id = pds.post_id
184+ ORDER BY pds.post_id, pds.date DESC
185+ )` ;
186+ }
187+
188+ function buildStartStatsCTE ( includeLike : boolean = true , paramIndex : number = 2 ) : string {
189+ const likeColumn = includeLike ? ',\n pds.daily_like_count AS start_like' : '' ;
190+
191+ return `
192+ start_stats AS (
193+ SELECT DISTINCT ON (pds.post_id)
194+ pds.post_id,
195+ pds.daily_view_count AS start_view${ likeColumn }
196+ FROM posts_postdailystatistics pds
197+ INNER JOIN user_posts up ON up.id = pds.post_id
198+ WHERE pds.date <= $${ paramIndex }
199+ ORDER BY pds.post_id, pds.date DESC
200+ )` ;
201+ }
202+
203+ function buildBadgeStatsQuery ( ) : string {
204+ return `
205+ WITH
206+ ${ buildUserPostsCTE ( false , false ) } ,
207+ ${ buildLatestStatsCTE ( ) } ,
208+ ${ buildStartStatsCTE ( true , 2 ) }
209+ SELECT
210+ $1 AS username,
211+ COALESCE(SUM(ls.total_view), 0) AS total_views,
212+ COALESCE(SUM(ls.total_like), 0) AS total_likes,
213+ COUNT(up.id) AS total_posts,
214+ COALESCE(SUM(ls.total_view - COALESCE(ss.start_view, 0)), 0) AS view_diff,
215+ COALESCE(SUM(ls.total_like - COALESCE(ss.start_like, 0)), 0) AS like_diff,
216+ COUNT(CASE WHEN up.released_at >= $2 THEN 1 END) AS post_diff
217+ FROM user_posts up
218+ LEFT JOIN latest_stats ls ON ls.post_id = up.id
219+ LEFT JOIN start_stats ss ON ss.post_id = up.id
220+ ` ;
221+ }
222+
223+ function buildRecentPostsQuery ( ) : string {
224+ return `
225+ WITH
226+ ${ buildUserPostsCTE ( true , true ) } ,
227+ ${ buildLatestStatsCTE ( ) } ,
228+ ${ buildStartStatsCTE ( false , 3 ) }
229+ SELECT
230+ up.title,
231+ up.released_at,
232+ COALESCE(ls.total_view, 0) AS today_view,
233+ COALESCE(ls.total_like, 0) AS today_like,
234+ ls.total_view - COALESCE(ss.start_view, 0) AS view_diff
235+ FROM user_posts up
236+ LEFT JOIN latest_stats ls ON ls.post_id = up.id
237+ LEFT JOIN start_stats ss ON ss.post_id = up.id
238+ ORDER BY up.released_at DESC
239+ ` ;
240+ }
0 commit comments