This repository has no description
5.5 kB
203 lines
1import { err, ok, Result } from 'src/shared/core/Result';
2import { UseCase } from 'src/shared/core/UseCase';
3import {
4 IUserStatsRepository,
5 UserGrowthStatsDTO,
6 UserEngagementStatsDTO,
7 DailyActivityStatsDTO,
8 ContentBreakdownStatsDTO,
9 UserStatType,
10 TimeInterval,
11} from '../../../domain/IUserStatsRepository';
12
13export interface GetUserStatsQuery {
14 statType: UserStatType;
15 interval?: TimeInterval;
16 limit?: number;
17 includeTimeSeries?: boolean; // For engagement stats
18 // Future parameters can be added here for other stat types
19}
20
21export type GetUserStatsResult =
22 | UserGrowthStatsDTO
23 | UserEngagementStatsDTO
24 | DailyActivityStatsDTO
25 | ContentBreakdownStatsDTO; // Union type for different stat types
26
27export class ValidationError extends Error {
28 constructor(message: string) {
29 super(message);
30 this.name = 'ValidationError';
31 }
32}
33
34export class GetUserStatsUseCase
35 implements UseCase<GetUserStatsQuery, Result<GetUserStatsResult>>
36{
37 constructor(private userStatsRepository: IUserStatsRepository) {}
38
39 async execute(query: GetUserStatsQuery): Promise<Result<GetUserStatsResult>> {
40 try {
41 // Validate query parameters
42 if (!query.statType) {
43 return err(new ValidationError('Stat type is required'));
44 }
45
46 // Route to appropriate repository method based on stat type
47 switch (query.statType) {
48 case 'growth':
49 return await this.handleGrowthStats(query);
50
51 case 'engagement':
52 return await this.handleEngagementStats(query);
53
54 case 'activity':
55 return await this.handleActivityStats(query);
56
57 case 'breakdown':
58 return await this.handleBreakdownStats(query);
59
60 default:
61 return err(
62 new ValidationError(`Invalid stat type: ${query.statType}`),
63 );
64 }
65 } catch (error) {
66 return err(
67 new Error(
68 `Failed to retrieve user stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
69 ),
70 );
71 }
72 }
73
74 private async handleGrowthStats(
75 query: GetUserStatsQuery,
76 ): Promise<Result<UserGrowthStatsDTO>> {
77 // Apply defaults
78 const interval = query.interval || 'day';
79 const limit = query.limit || 30;
80
81 // Validate parameters
82 if (!['day', 'week', 'month'].includes(interval)) {
83 return err(new ValidationError(`Invalid interval: ${interval}`));
84 }
85
86 if (limit < 1 || limit > 365) {
87 return err(new ValidationError('Limit must be between 1 and 365'));
88 }
89
90 try {
91 const stats = await this.userStatsRepository.getUserGrowthStats({
92 interval,
93 limit,
94 });
95
96 return ok(stats);
97 } catch (error) {
98 return err(
99 new Error(
100 `Failed to retrieve growth stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
101 ),
102 );
103 }
104 }
105
106 private async handleEngagementStats(
107 query: GetUserStatsQuery,
108 ): Promise<Result<UserEngagementStatsDTO>> {
109 // Apply defaults
110 const interval = query.interval || 'day';
111 const limit = query.limit || 30;
112 const includeTimeSeries = query.includeTimeSeries || false;
113
114 // Validate parameters
115 if (interval && !['day', 'week', 'month'].includes(interval)) {
116 return err(new ValidationError(`Invalid interval: ${interval}`));
117 }
118
119 if (limit < 1 || limit > 365) {
120 return err(new ValidationError('Limit must be between 1 and 365'));
121 }
122
123 try {
124 const stats = await this.userStatsRepository.getUserEngagementStats({
125 interval,
126 limit,
127 includeTimeSeries,
128 });
129
130 return ok(stats);
131 } catch (error) {
132 return err(
133 new Error(
134 `Failed to retrieve engagement stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
135 ),
136 );
137 }
138 }
139
140 private async handleActivityStats(
141 query: GetUserStatsQuery,
142 ): Promise<Result<DailyActivityStatsDTO>> {
143 // Apply defaults
144 const interval = query.interval || 'day';
145 const limit = query.limit || 30;
146
147 // Validate parameters
148 if (!['day', 'week', 'month'].includes(interval)) {
149 return err(new ValidationError(`Invalid interval: ${interval}`));
150 }
151
152 if (limit < 1 || limit > 365) {
153 return err(new ValidationError('Limit must be between 1 and 365'));
154 }
155
156 try {
157 const stats = await this.userStatsRepository.getDailyActivityStats({
158 interval,
159 limit,
160 });
161
162 return ok(stats);
163 } catch (error) {
164 return err(
165 new Error(
166 `Failed to retrieve activity stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
167 ),
168 );
169 }
170 }
171
172 private async handleBreakdownStats(
173 query: GetUserStatsQuery,
174 ): Promise<Result<ContentBreakdownStatsDTO>> {
175 // Apply defaults
176 const interval = query.interval || 'day';
177 const limit = query.limit || 30;
178
179 // Validate parameters
180 if (!['day', 'week', 'month'].includes(interval)) {
181 return err(new ValidationError(`Invalid interval: ${interval}`));
182 }
183
184 if (limit < 1 || limit > 365) {
185 return err(new ValidationError('Limit must be between 1 and 365'));
186 }
187
188 try {
189 const stats = await this.userStatsRepository.getContentBreakdownStats({
190 interval,
191 limit,
192 });
193
194 return ok(stats);
195 } catch (error) {
196 return err(
197 new Error(
198 `Failed to retrieve breakdown stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
199 ),
200 );
201 }
202 }
203}