This repository has no description
3.8 kB
134 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 UserStatType,
8 TimeInterval,
9} from '../../../domain/IUserStatsRepository';
10
11export interface GetUserStatsQuery {
12 statType: UserStatType;
13 interval?: TimeInterval;
14 limit?: number;
15 includeTimeSeries?: boolean; // For engagement stats
16 // Future parameters can be added here for other stat types
17}
18
19export type GetUserStatsResult = UserGrowthStatsDTO | UserEngagementStatsDTO; // Union type for different stat types
20
21export class ValidationError extends Error {
22 constructor(message: string) {
23 super(message);
24 this.name = 'ValidationError';
25 }
26}
27
28export class GetUserStatsUseCase
29 implements UseCase<GetUserStatsQuery, Result<GetUserStatsResult>>
30{
31 constructor(private userStatsRepository: IUserStatsRepository) {}
32
33 async execute(query: GetUserStatsQuery): Promise<Result<GetUserStatsResult>> {
34 try {
35 // Validate query parameters
36 if (!query.statType) {
37 return err(new ValidationError('Stat type is required'));
38 }
39
40 // Route to appropriate repository method based on stat type
41 switch (query.statType) {
42 case 'growth':
43 return await this.handleGrowthStats(query);
44
45 case 'engagement':
46 return await this.handleEngagementStats(query);
47
48 // Future stat types can be added here
49 // case 'activity':
50 // return await this.handleActivityStats(query);
51
52 default:
53 return err(
54 new ValidationError(`Invalid stat type: ${query.statType}`),
55 );
56 }
57 } catch (error) {
58 return err(
59 new Error(
60 `Failed to retrieve user stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
61 ),
62 );
63 }
64 }
65
66 private async handleGrowthStats(
67 query: GetUserStatsQuery,
68 ): Promise<Result<UserGrowthStatsDTO>> {
69 // Apply defaults
70 const interval = query.interval || 'day';
71 const limit = query.limit || 30;
72
73 // Validate parameters
74 if (!['day', 'week', 'month'].includes(interval)) {
75 return err(new ValidationError(`Invalid interval: ${interval}`));
76 }
77
78 if (limit < 1 || limit > 365) {
79 return err(new ValidationError('Limit must be between 1 and 365'));
80 }
81
82 try {
83 const stats = await this.userStatsRepository.getUserGrowthStats({
84 interval,
85 limit,
86 });
87
88 return ok(stats);
89 } catch (error) {
90 return err(
91 new Error(
92 `Failed to retrieve growth stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
93 ),
94 );
95 }
96 }
97
98 private async handleEngagementStats(
99 query: GetUserStatsQuery,
100 ): Promise<Result<UserEngagementStatsDTO>> {
101 // Apply defaults
102 const interval = query.interval || 'day';
103 const limit = query.limit || 30;
104 const includeTimeSeries = query.includeTimeSeries || false;
105
106 // Validate parameters
107 if (interval && !['day', 'week', 'month'].includes(interval)) {
108 return err(new ValidationError(`Invalid interval: ${interval}`));
109 }
110
111 if (limit < 1 || limit > 365) {
112 return err(new ValidationError('Limit must be between 1 and 365'));
113 }
114
115 try {
116 const stats = await this.userStatsRepository.getUserEngagementStats({
117 interval,
118 limit,
119 includeTimeSeries,
120 });
121
122 return ok(stats);
123 } catch (error) {
124 return err(
125 new Error(
126 `Failed to retrieve engagement stats: ${error instanceof Error ? error.message : 'Unknown error'}`,
127 ),
128 );
129 }
130 }
131
132 // Future handler methods can be added here
133 // private async handleActivityStats(query: GetUserStatsQuery): Promise<Result<UserActivityStatsDTO>> { ... }
134}