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
72impl ResourceOutputsDefinition for StorageOutputs {
73 fn get_resource_type(&self) -> ResourceType {
74 Storage::RESOURCE_TYPE.clone()
75 }
76
77 fn as_any(&self) -> &dyn Any {
78 self
79 }
80
81 fn box_clone(&self) -> Box<dyn ResourceOutputsDefinition> {
82 Box::new(self.clone())
83 }
84
85 fn outputs_eq(&self, other: &dyn ResourceOutputsDefinition) -> bool {
86 other.as_any().downcast_ref::<StorageOutputs>() == Some(self)
87 }
88
89 fn to_json_value(&self) -> serde_json::Result<serde_json::Value> {
90 serde_json::to_value(self)
91 }
92}
93
94impl ResourceDefinition for Storage {
96 fn get_resource_type(&self) -> ResourceType {
97 Self::RESOURCE_TYPE
98 }
99
100 fn id(&self) -> &str {
101 &self.id
102 }
103
104 fn get_dependencies(&self) -> Vec<ResourceRef> {
105 Vec::new()
106 }
107
108 fn validate_update(&self, new_config: &dyn ResourceDefinition) -> Result<()> {
109 let new_storage = new_config
111 .as_any()
112 .downcast_ref::<Storage>()
113 .ok_or_else(|| {
114 AlienError::new(ErrorData::UnexpectedResourceType {
115 resource_id: self.id.clone(),
116 expected: Self::RESOURCE_TYPE,
117 actual: new_config.get_resource_type(),
118 })
119 })?;
120
121 if self.id != new_storage.id {
122 return Err(AlienError::new(ErrorData::InvalidResourceUpdate {
123 resource_id: self.id.clone(),
124 reason: "the 'id' field is immutable".to_string(),
125 }));
126 }
127 Ok(())
129 }
130
131 fn as_any(&self) -> &dyn Any {
132 self
133 }
134
135 fn as_any_mut(&mut self) -> &mut dyn Any {
136 self
137 }
138
139 fn box_clone(&self) -> Box<dyn ResourceDefinition> {
140 Box::new(self.clone())
141 }
142
143 fn resource_eq(&self, other: &dyn ResourceDefinition) -> bool {
144 other.as_any().downcast_ref::<Storage>() == Some(self)
145 }
146
147 fn to_json_value(&self) -> serde_json::Result<serde_json::Value> {
148 serde_json::to_value(self)
149 }
150}