Skip to main content

backbone_catalog/presentation/dto/
attribute_dto.rs

1//! Attribute 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 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
16use crate::domain::entity::Attribute;
17use crate::domain::entity::AuditMetadata;
18use crate::domain::entity::AttributeType;
19use crate::domain::entity::CatalogStatus;
20
21// =============================================================================
22// Create DTO
23// =============================================================================
24
25/// Request DTO for creating a new Attribute
26///
27/// Used in POST requests to create new entities.
28/// Excludes auto-generated fields (id, created_at, updated_at, deleted_at).
29#[derive(Debug, Clone, Deserialize)]
30#[cfg_attr(feature = "openapi", derive(ToSchema))]
31#[serde(rename_all = "camelCase")]
32pub struct CreateAttributeDto {
33    #[cfg_attr(feature = "openapi", schema(example = "example"))]
34    pub code: String,
35    #[cfg_attr(feature = "openapi", schema(example = "example"))]
36    pub name: String,
37    #[serde(alias = "attribute_type")]
38    pub attribute_type: AttributeType,
39    pub status: CatalogStatus,
40}
41
42// =============================================================================
43// Update DTO
44// =============================================================================
45
46/// Request DTO for full update of a Attribute
47///
48/// Used in PUT requests for full entity replacement.
49/// All fields are required (except auto-generated ones).
50#[derive(Debug, Clone, Deserialize)]
51#[cfg_attr(feature = "openapi", derive(ToSchema))]
52#[serde(rename_all = "camelCase")]
53pub struct UpdateAttributeDto {
54    #[cfg_attr(feature = "openapi", schema(example = "example"))]
55    pub code: String,
56    #[cfg_attr(feature = "openapi", schema(example = "example"))]
57    pub name: String,
58    #[serde(alias = "attribute_type")]
59    pub attribute_type: AttributeType,
60    pub status: CatalogStatus,
61}
62
63// =============================================================================
64// Patch DTO
65// =============================================================================
66
67/// Request DTO for partial update of a Attribute
68///
69/// Used in PATCH requests for partial updates.
70/// All fields are optional - only provided fields will be updated.
71#[derive(Debug, Clone, Default, Deserialize)]
72#[cfg_attr(feature = "openapi", derive(ToSchema))]
73#[serde(rename_all = "camelCase")]
74pub struct PatchAttributeDto {
75    #[cfg_attr(feature = "openapi", schema(example = "example"))]
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub code: Option<String>,
78    #[cfg_attr(feature = "openapi", schema(example = "example"))]
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub name: Option<String>,
81    #[serde(skip_serializing_if = "Option::is_none", alias = "attribute_type")]
82    pub attribute_type: Option<AttributeType>,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub status: Option<CatalogStatus>,
85}
86
87impl PatchAttributeDto {
88    /// Check if any field is set
89    pub fn has_changes(&self) -> bool {
90        self.code.is_some() || self.name.is_some() || self.attribute_type.is_some() || self.status.is_some()
91    }
92}
93
94// =============================================================================
95// Response DTO
96// =============================================================================
97
98/// Response DTO for Attribute entity
99///
100/// Used in API responses for single entity.
101/// Includes all fields including metadata.
102#[derive(Debug, Clone, Serialize)]
103#[cfg_attr(feature = "openapi", derive(ToSchema))]
104#[serde(rename_all = "camelCase")]
105pub struct AttributeResponseDto {
106    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
107    pub id: Uuid,
108    #[cfg_attr(feature = "openapi", schema(example = "example"))]
109    pub code: String,
110    #[cfg_attr(feature = "openapi", schema(example = "example"))]
111    pub name: String,
112    pub attribute_type: AttributeType,
113    pub status: CatalogStatus,
114    pub metadata: AuditMetadata,
115}
116
117// =============================================================================
118// List Response DTO
119// =============================================================================
120
121/// Paginated list response for Attribute entities
122///
123/// Used in API responses for list endpoints.
124/// Includes pagination metadata.
125#[derive(Debug, Clone, Serialize)]
126#[cfg_attr(feature = "openapi", derive(ToSchema))]
127#[serde(rename_all = "camelCase")]
128pub struct AttributeListResponseDto {
129    /// List of items
130    pub items: Vec<AttributeResponseDto>,
131    /// Total number of items (across all pages)
132    pub total: u64,
133    /// Current page number (1-indexed)
134    pub page: u32,
135    /// Number of items per page
136    pub per_page: u32,
137    /// Total number of pages
138    pub total_pages: u32,
139    /// Whether there is a next page
140    pub has_next: bool,
141    /// Whether there is a previous page
142    pub has_prev: bool,
143}
144
145impl AttributeListResponseDto {
146    /// Create a new list response from items and pagination info
147    pub fn new(items: Vec<AttributeResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
148        let total_pages = if per_page > 0 {
149            ((total as f64) / (per_page as f64)).ceil() as u32
150        } else {
151            0
152        };
153        Self {
154            items,
155            total,
156            page,
157            per_page,
158            total_pages,
159            has_next: page < total_pages,
160            has_prev: page > 1,
161        }
162    }
163}
164
165/// Summary DTO for list views (compact version)
166#[derive(Debug, Clone, Serialize)]
167#[cfg_attr(feature = "openapi", derive(ToSchema))]
168#[serde(rename_all = "camelCase")]
169pub struct AttributeSummaryDto {
170    pub id: Uuid,
171    pub code: String,
172    pub name: String,
173    pub attribute_type: AttributeType,
174    pub created_at: Option<DateTime<Utc>>,
175}
176
177// =============================================================================
178// Conversions
179// =============================================================================
180
181impl From<Attribute> for AttributeResponseDto {
182    fn from(entity: Attribute) -> Self {
183        Self {
184            id: entity.id,
185            code: entity.code,
186            name: entity.name,
187            attribute_type: entity.attribute_type,
188            status: entity.status,
189            metadata: entity.metadata,
190        }
191    }
192}
193
194impl From<Attribute> for AttributeSummaryDto {
195    fn from(entity: Attribute) -> Self {
196        let created_at = backbone_core::PersistentEntity::created_at(&entity);
197        Self {
198            id: entity.id,
199            code: entity.code,
200            name: entity.name,
201            attribute_type: entity.attribute_type,
202            created_at,
203        }
204    }
205}
206
207impl From<CreateAttributeDto> for Attribute {
208    fn from(dto: CreateAttributeDto) -> Self {
209        Self {
210            id: Uuid::new_v4(),
211            code: dto.code,
212            name: dto.name,
213            attribute_type: dto.attribute_type,
214            status: dto.status,
215            metadata: AuditMetadata::default(),
216        }
217    }
218}
219
220impl From<&Attribute> for AttributeResponseDto {
221    fn from(entity: &Attribute) -> Self {
222        Self {
223            id: entity.id.clone(),
224            code: entity.code.clone(),
225            name: entity.name.clone(),
226            attribute_type: entity.attribute_type.clone(),
227            status: entity.status.clone(),
228            metadata: entity.metadata.clone(),
229        }
230    }
231}
232
233impl backbone_core::FromCreateDto<CreateAttributeDto> for Attribute {
234    fn from_create_dto(dto: CreateAttributeDto) -> backbone_core::ServiceResult<Self> {
235        Ok(Attribute::from(dto))
236    }
237}
238
239impl backbone_core::ApplyUpdateDto<UpdateAttributeDto> for Attribute {
240    fn apply_update(mut self, dto: UpdateAttributeDto) -> backbone_core::ServiceResult<Self> {
241        self.code = dto.code;
242        self.name = dto.name;
243        self.attribute_type = dto.attribute_type;
244        self.status = dto.status;
245        Ok(self)
246    }
247}
248
249// =============================================================================
250// Custom DTOs
251// =============================================================================
252
253// Add custom DTOs specific to Attribute here.
254// This section will be preserved during regeneration.
255// >>> END CUSTOM DTOs
256