allsource_core/application/dto/
projection_dto.rs

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