alien_core/resources/
storage.rs1use crate::error::{ErrorData, Result};
2use crate::resource::{ResourceDefinition, ResourceOutputsDefinition, ResourceRef};
3use crate::ResourceType;
4use alien_error::AlienError;
5use bon::Builder;
6use serde::{Deserialize, Serialize};
7use std::any::Any;
8use std::fmt::Debug;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
13#[serde(rename_all = "camelCase", deny_unknown_fields)]
14pub struct LifecycleRule {
15 pub days: u32,
17 #[serde(default)]
19 pub prefix: Option<String>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
24#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
25#[serde(rename_all = "camelCase", deny_unknown_fields)]
26#[builder(start_fn = new)]
27pub struct Storage {
28 #[builder(start_fn)]
31 pub id: String,
32
33 #[serde(default)]
36 #[builder(default)]
37 pub public_read: bool,
38
39 #[serde(default)]
42 #[builder(default)]
43 pub versioning: bool,
44
45 #[serde(default)]
48 #[builder(default)]
49 pub lifecycle_rules: Vec<LifecycleRule>,
50}
51
52impl Storage {
53 pub const RESOURCE_TYPE: ResourceType = ResourceType::from_static("storage");
55
56 pub fn id(&self) -> &str {
58 &self.id
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
64#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
65#[serde(rename_all = "camelCase")]
66pub struct StorageOutputs {
67 pub bucket_name: String,
69 }
71
72#[typetag::serde(name = "storage")]
73impl ResourceOutputsDefinition for StorageOutputs {
74 fn resource_type() -> ResourceType {
75 Storage::RESOURCE_TYPE.clone()
76 }
77
78 fn as_any(&self) -> &dyn Any {
79 self
80 }
81
82 fn box_clone(&self) -> Box<dyn ResourceOutputsDefinition> {
83 Box::new(self.clone())
84 }
85
86 fn outputs_eq(&self, other: &dyn ResourceOutputsDefinition) -> bool {
87 other.as_any().downcast_ref::<StorageOutputs>() == Some(self)
88 }
89}
90
91#[typetag::serde(name = "storage")]
93impl ResourceDefinition for Storage {
94 fn resource_type() -> ResourceType {
95 Self::RESOURCE_TYPE.clone()
96 }
97
98 fn get_resource_type(&self) -> ResourceType {
99 Self::resource_type()
100 }
101
102 fn id(&self) -> &str {
103 &self.id
104 }
105
106 fn get_dependencies(&self) -> Vec<ResourceRef> {
107 Vec::new()
108 }
109
110 fn validate_update(&self, new_config: &dyn ResourceDefinition) -> Result<()> {
111 let new_storage = new_config
113 .as_any()
114 .downcast_ref::<Storage>()
115 .ok_or_else(|| {
116 AlienError::new(ErrorData::UnexpectedResourceType {
117 resource_id: self.id.clone(),
118 expected: Self::RESOURCE_TYPE,
119 actual: new_config.get_resource_type(),
120 })
121 })?;
122
123 if self.id != new_storage.id {
124 return Err(AlienError::new(ErrorData::InvalidResourceUpdate {
125 resource_id: self.id.clone(),
126 reason: "the 'id' field is immutable".to_string(),
127 }));
128 }
129 Ok(())
131 }
132
133 fn as_any(&self) -> &dyn Any {
134 self
135 }
136
137 fn as_any_mut(&mut self) -> &mut dyn Any {
138 self
139 }
140
141 fn box_clone(&self) -> Box<dyn ResourceDefinition> {
142 Box::new(self.clone())
143 }
144
145 fn resource_eq(&self, other: &dyn ResourceDefinition) -> bool {
146 other.as_any().downcast_ref::<Storage>() == Some(self)
147 }
148}