allsource_core/application/dto/
projection_dto.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4use crate::domain::entities::{Projection, ProjectionType, ProjectionStatus, ProjectionConfig, ProjectionStats};
5
6/// DTO for creating a new projection
7#[derive(Debug, Deserialize)]
8pub struct CreateProjectionRequest {
9    pub name: String,
10    pub projection_type: ProjectionTypeDto,
11    pub tenant_id: String,
12    pub event_types: Vec<String>,
13    pub description: Option<String>,
14    pub config: Option<ProjectionConfigDto>,
15}
16
17/// DTO for updating a projection
18#[derive(Debug, Deserialize)]
19pub struct UpdateProjectionRequest {
20    pub description: Option<String>,
21    pub config: Option<ProjectionConfigDto>,
22    pub event_types: Option<Vec<String>>,
23}
24
25/// DTO for projection type
26#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
27#[serde(rename_all = "snake_case")]
28pub enum ProjectionTypeDto {
29    EntitySnapshot,
30    EventCounter,
31    Custom,
32    TimeSeries,
33    Funnel,
34}
35
36impl From<ProjectionType> for ProjectionTypeDto {
37    fn from(ptype: ProjectionType) -> Self {
38        match ptype {
39            ProjectionType::EntitySnapshot => ProjectionTypeDto::EntitySnapshot,
40            ProjectionType::EventCounter => ProjectionTypeDto::EventCounter,
41            ProjectionType::Custom => ProjectionTypeDto::Custom,
42            ProjectionType::TimeSeries => ProjectionTypeDto::TimeSeries,
43            ProjectionType::Funnel => ProjectionTypeDto::Funnel,
44        }
45    }
46}
47
48impl From<ProjectionTypeDto> for ProjectionType {
49    fn from(dto: ProjectionTypeDto) -> Self {
50        match dto {
51            ProjectionTypeDto::EntitySnapshot => ProjectionType::EntitySnapshot,
52            ProjectionTypeDto::EventCounter => ProjectionType::EventCounter,
53            ProjectionTypeDto::Custom => ProjectionType::Custom,
54            ProjectionTypeDto::TimeSeries => ProjectionType::TimeSeries,
55            ProjectionTypeDto::Funnel => ProjectionType::Funnel,
56        }
57    }
58}
59
60/// DTO for projection status
61#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
62#[serde(rename_all = "snake_case")]
63pub enum ProjectionStatusDto {
64    Created,
65    Running,
66    Paused,
67    Failed,
68    Stopped,
69    Rebuilding,
70}
71
72impl From<ProjectionStatus> for ProjectionStatusDto {
73    fn from(status: ProjectionStatus) -> Self {
74        match status {
75            ProjectionStatus::Created => ProjectionStatusDto::Created,
76            ProjectionStatus::Running => ProjectionStatusDto::Running,
77            ProjectionStatus::Paused => ProjectionStatusDto::Paused,
78            ProjectionStatus::Failed => ProjectionStatusDto::Failed,
79            ProjectionStatus::Stopped => ProjectionStatusDto::Stopped,
80            ProjectionStatus::Rebuilding => ProjectionStatusDto::Rebuilding,
81        }
82    }
83}
84
85/// DTO for projection configuration
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct ProjectionConfigDto {
88    pub batch_size: Option<usize>,
89    pub checkpoint_interval: Option<usize>,
90}
91
92impl From<ProjectionConfig> for ProjectionConfigDto {
93    fn from(config: ProjectionConfig) -> Self {
94        Self {
95            batch_size: Some(config.batch_size),
96            checkpoint_interval: Some(config.checkpoint_interval),
97        }
98    }
99}
100
101impl From<ProjectionConfigDto> for ProjectionConfig {
102    fn from(dto: ProjectionConfigDto) -> Self {
103        Self {
104            batch_size: dto.batch_size.unwrap_or(100),
105            enable_checkpoints: true,
106            checkpoint_interval: dto.checkpoint_interval.unwrap_or(1000),
107            parallel_processing: false,
108            max_concurrency: 4,
109        }
110    }
111}
112
113/// DTO for projection statistics
114#[derive(Debug, Clone, Serialize)]
115pub struct ProjectionStatsDto {
116    pub events_processed: u64,
117    pub last_processed_at: Option<DateTime<Utc>>,
118    pub errors_count: u64,
119    pub last_error: Option<String>,
120    pub avg_processing_time_ms: Option<f64>,
121}
122
123impl From<&ProjectionStats> for ProjectionStatsDto {
124    fn from(stats: &ProjectionStats) -> Self {
125        Self {
126            events_processed: stats.events_processed(),
127            last_processed_at: stats.last_processed_at(),
128            errors_count: stats.errors_count(),
129            last_error: None, // Not available in domain entity
130            avg_processing_time_ms: Some(stats.avg_processing_time_ms()),
131        }
132    }
133}
134
135/// DTO for projection response
136#[derive(Debug, Serialize)]
137pub struct ProjectionDto {
138    pub id: Uuid,
139    pub name: String,
140    pub projection_type: ProjectionTypeDto,
141    pub tenant_id: String,
142    pub status: ProjectionStatusDto,
143    pub version: u32,
144    pub event_types: Vec<String>,
145    pub description: Option<String>,
146    pub config: ProjectionConfigDto,
147    pub stats: ProjectionStatsDto,
148    pub created_at: DateTime<Utc>,
149    pub updated_at: DateTime<Utc>,
150}
151
152impl From<&Projection> for ProjectionDto {
153    fn from(projection: &Projection) -> Self {
154        Self {
155            id: projection.id(),
156            name: projection.name().to_string(),
157            projection_type: projection.projection_type().into(),
158            tenant_id: projection.tenant_id().to_string(),
159            status: projection.status().into(),
160            version: projection.version(),
161            event_types: projection.event_types().iter().map(|s| s.to_string()).collect(),
162            description: projection.description().map(String::from),
163            config: projection.config().clone().into(),
164            stats: projection.stats().into(),
165            created_at: projection.created_at(),
166            updated_at: projection.updated_at(),
167        }
168    }
169}
170
171impl From<Projection> for ProjectionDto {
172    fn from(projection: Projection) -> Self {
173        ProjectionDto::from(&projection)
174    }
175}
176
177/// Response for projection creation
178#[derive(Debug, Serialize)]
179pub struct CreateProjectionResponse {
180    pub projection: ProjectionDto,
181}
182
183/// Response for listing projections
184#[derive(Debug, Serialize)]
185pub struct ListProjectionsResponse {
186    pub projections: Vec<ProjectionDto>,
187    pub count: usize,
188}
189
190/// Request to start a projection
191#[derive(Debug, Deserialize)]
192pub struct StartProjectionRequest {
193    pub projection_id: Uuid,
194}
195
196/// Request to pause a projection
197#[derive(Debug, Deserialize)]
198pub struct PauseProjectionRequest {
199    pub projection_id: Uuid,
200}
201
202/// Request to rebuild a projection
203#[derive(Debug, Deserialize)]
204pub struct RebuildProjectionRequest {
205    pub projection_id: Uuid,
206}