Skip to main content

backbone_bucket/presentation/dto/
file_lock_dto.rs

1//! FileLock DTOs (Data Transfer Objects)
2//!
3//! Generated by metaphor-schema. Do not edit manually.
4//!
5//! DTOs provide a clean separation between domain entities and API
6//! representations, with validation and OpenAPI documentation support.
7
8use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10use chrono::{DateTime, Utc};
11
12#[cfg(feature = "openapi")]
13#[cfg(feature = "openapi")]
14use utoipa::ToSchema;
15
16#[cfg(feature = "validation")]
17use validator::Validate;
18
19use crate::domain::entity::FileLock;
20use crate::domain::entity::AuditMetadata;
21use crate::domain::entity::LockStatus;
22
23// =============================================================================
24// Create DTO
25// =============================================================================
26
27/// Request DTO for creating a new FileLock
28///
29/// Used in POST requests to create new entities.
30/// Excludes auto-generated fields (id, created_at, updated_at, deleted_at).
31#[derive(Debug, Clone, Deserialize)]
32#[cfg_attr(feature = "openapi", derive(ToSchema))]
33#[cfg_attr(feature = "validation", derive(Validate))]
34#[serde(rename_all = "camelCase")]
35pub struct CreateFileLockDto {
36    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
37    #[serde(alias = "file_id")]
38    pub file_id: Uuid,
39    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
40    #[serde(alias = "user_id")]
41    pub user_id: Uuid,
42    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
43    #[serde(alias = "locked_at")]
44    pub locked_at: DateTime<Utc>,
45    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
46    #[serde(alias = "expires_at")]
47    pub expires_at: DateTime<Utc>,
48    #[serde(default, skip_serializing_if = "Option::is_none", alias = "refreshed_at")]
49    pub refreshed_at: Option<DateTime<Utc>>,
50    pub status: LockStatus,
51}
52
53// =============================================================================
54// Update DTO
55// =============================================================================
56
57/// Request DTO for full update of a FileLock
58///
59/// Used in PUT requests for full entity replacement.
60/// All fields are required (except auto-generated ones).
61#[derive(Debug, Clone, Deserialize)]
62#[cfg_attr(feature = "openapi", derive(ToSchema))]
63#[cfg_attr(feature = "validation", derive(Validate))]
64#[serde(rename_all = "camelCase")]
65pub struct UpdateFileLockDto {
66    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
67    #[serde(alias = "file_id")]
68    pub file_id: Uuid,
69    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
70    #[serde(alias = "user_id")]
71    pub user_id: Uuid,
72    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
73    #[serde(alias = "locked_at")]
74    pub locked_at: DateTime<Utc>,
75    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
76    #[serde(alias = "expires_at")]
77    pub expires_at: DateTime<Utc>,
78    #[serde(default, skip_serializing_if = "Option::is_none", alias = "refreshed_at")]
79    pub refreshed_at: Option<DateTime<Utc>>,
80    pub status: LockStatus,
81}
82
83// =============================================================================
84// Patch DTO
85// =============================================================================
86
87/// Request DTO for partial update of a FileLock
88///
89/// Used in PATCH requests for partial updates.
90/// All fields are optional - only provided fields will be updated.
91#[derive(Debug, Clone, Default, Deserialize)]
92#[cfg_attr(feature = "openapi", derive(ToSchema))]
93#[cfg_attr(feature = "validation", derive(Validate))]
94#[serde(rename_all = "camelCase")]
95pub struct PatchFileLockDto {
96    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
97    #[serde(skip_serializing_if = "Option::is_none", alias = "file_id")]
98    pub file_id: Option<Uuid>,
99    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
100    #[serde(skip_serializing_if = "Option::is_none", alias = "user_id")]
101    pub user_id: Option<Uuid>,
102    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
103    #[serde(skip_serializing_if = "Option::is_none", alias = "locked_at")]
104    pub locked_at: Option<DateTime<Utc>>,
105    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
106    #[serde(skip_serializing_if = "Option::is_none", alias = "expires_at")]
107    pub expires_at: Option<DateTime<Utc>>,
108    #[serde(skip_serializing_if = "Option::is_none", alias = "refreshed_at")]
109    pub refreshed_at: Option<DateTime<Utc>>,
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub status: Option<LockStatus>,
112}
113
114impl PatchFileLockDto {
115    /// Check if any field is set
116    pub fn has_changes(&self) -> bool {
117        self.file_id.is_some() || self.user_id.is_some() || self.locked_at.is_some() || self.expires_at.is_some() || self.refreshed_at.is_some() || self.status.is_some()
118    }
119}
120
121// =============================================================================
122// Response DTO
123// =============================================================================
124
125/// Response DTO for FileLock entity
126///
127/// Used in API responses for single entity.
128/// Includes all fields including metadata.
129#[derive(Debug, Clone, Serialize)]
130#[cfg_attr(feature = "openapi", derive(ToSchema))]
131#[serde(rename_all = "camelCase")]
132pub struct FileLockResponseDto {
133    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
134    pub id: Uuid,
135    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
136    pub file_id: Uuid,
137    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
138    pub user_id: Uuid,
139    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
140    pub locked_at: DateTime<Utc>,
141    #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
142    pub expires_at: DateTime<Utc>,
143    pub refreshed_at: Option<DateTime<Utc>>,
144    pub status: LockStatus,
145    pub metadata: AuditMetadata,
146}
147
148// =============================================================================
149// List Response DTO
150// =============================================================================
151
152/// Paginated list response for FileLock entities
153///
154/// Used in API responses for list endpoints.
155/// Includes pagination metadata.
156#[derive(Debug, Clone, Serialize)]
157#[cfg_attr(feature = "openapi", derive(ToSchema))]
158#[serde(rename_all = "camelCase")]
159pub struct FileLockListResponseDto {
160    /// List of items
161    pub items: Vec<FileLockResponseDto>,
162    /// Total number of items (across all pages)
163    pub total: u64,
164    /// Current page number (1-indexed)
165    pub page: u32,
166    /// Number of items per page
167    pub per_page: u32,
168    /// Total number of pages
169    pub total_pages: u32,
170    /// Whether there is a next page
171    pub has_next: bool,
172    /// Whether there is a previous page
173    pub has_prev: bool,
174}
175
176impl FileLockListResponseDto {
177    /// Create a new list response from items and pagination info
178    pub fn new(items: Vec<FileLockResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
179        let total_pages = if per_page > 0 {
180            ((total as f64) / (per_page as f64)).ceil() as u32
181        } else {
182            0
183        };
184        Self {
185            items,
186            total,
187            page,
188            per_page,
189            total_pages,
190            has_next: page < total_pages,
191            has_prev: page > 1,
192        }
193    }
194}
195
196/// Summary DTO for list views (compact version)
197#[derive(Debug, Clone, Serialize)]
198#[cfg_attr(feature = "openapi", derive(ToSchema))]
199#[serde(rename_all = "camelCase")]
200pub struct FileLockSummaryDto {
201    pub id: Uuid,
202    pub file_id: Uuid,
203    pub user_id: Uuid,
204    pub locked_at: DateTime<Utc>,
205    pub created_at: Option<DateTime<Utc>>,
206}
207
208// =============================================================================
209// Conversions
210// =============================================================================
211
212impl From<FileLock> for FileLockResponseDto {
213    fn from(entity: FileLock) -> Self {
214        Self {
215            id: entity.id,
216            file_id: entity.file_id,
217            user_id: entity.user_id,
218            locked_at: entity.locked_at,
219            expires_at: entity.expires_at,
220            refreshed_at: entity.refreshed_at,
221            status: entity.status,
222            metadata: entity.metadata,
223        }
224    }
225}
226
227impl From<FileLock> for FileLockSummaryDto {
228    fn from(entity: FileLock) -> Self {
229        let created_at = backbone_core::PersistentEntity::created_at(&entity);
230        Self {
231            id: entity.id,
232            file_id: entity.file_id,
233            user_id: entity.user_id,
234            locked_at: entity.locked_at,
235            created_at,
236        }
237    }
238}
239
240impl From<CreateFileLockDto> for FileLock {
241    fn from(dto: CreateFileLockDto) -> Self {
242        Self {
243            id: Uuid::new_v4(),
244            file_id: dto.file_id,
245            user_id: dto.user_id,
246            locked_at: dto.locked_at,
247            expires_at: dto.expires_at,
248            refreshed_at: dto.refreshed_at,
249            status: dto.status,
250            metadata: AuditMetadata::default(),
251        }
252    }
253}
254
255impl From<&FileLock> for FileLockResponseDto {
256    fn from(entity: &FileLock) -> Self {
257        Self {
258            id: entity.id.clone(),
259            file_id: entity.file_id.clone(),
260            user_id: entity.user_id.clone(),
261            locked_at: entity.locked_at.clone(),
262            expires_at: entity.expires_at.clone(),
263            refreshed_at: entity.refreshed_at.clone(),
264            status: entity.status.clone(),
265            metadata: entity.metadata.clone(),
266        }
267    }
268}
269
270impl backbone_core::FromCreateDto<CreateFileLockDto> for FileLock {
271    fn from_create_dto(dto: CreateFileLockDto) -> backbone_core::ServiceResult<Self> {
272        Ok(FileLock::from(dto))
273    }
274}
275
276impl backbone_core::ApplyUpdateDto<UpdateFileLockDto> for FileLock {
277    fn apply_update(mut self, dto: UpdateFileLockDto) -> backbone_core::ServiceResult<Self> {
278        self.file_id = dto.file_id;
279        self.user_id = dto.user_id;
280        self.locked_at = dto.locked_at;
281        self.expires_at = dto.expires_at;
282        self.refreshed_at = dto.refreshed_at;
283        self.status = dto.status;
284        Ok(self)
285    }
286}
287
288// =============================================================================
289// Custom DTOs
290// =============================================================================
291
292// <<< CUSTOM DTOs
293// Add custom DTOs specific to FileLock here.
294// This section will be preserved during regeneration.
295// >>> END CUSTOM DTOs