dynoxide/actions/
delete_table.rs1use crate::actions::vector_lifecycle::VectorIndexLifecycle;
2use crate::actions::{TableDescription, build_table_description};
3use crate::errors::{DynoxideError, Result};
4use crate::storage_backend::StorageBackend;
5use crate::types::{GlobalSecondaryIndex, LocalSecondaryIndex};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Default, Deserialize)]
10struct DeleteTableRequestRaw {
11 #[serde(rename = "TableName", default)]
12 table_name: Option<String>,
13}
14
15#[derive(Debug, Default)]
16pub struct DeleteTableRequest {
17 pub table_name: String,
18}
19
20impl<'de> serde::Deserialize<'de> for DeleteTableRequest {
21 fn deserialize<D: serde::Deserializer<'de>>(
22 deserializer: D,
23 ) -> std::result::Result<Self, D::Error> {
24 let raw = DeleteTableRequestRaw::deserialize(deserializer)?;
25
26 if raw.table_name.is_none() {
27 return Err(serde::de::Error::custom(
28 "VALIDATION:The parameter 'TableName' is required but was not present in the request",
29 ));
30 }
31 let table_name = raw.table_name.unwrap();
32
33 if table_name.len() < 3 || table_name.len() > 255 {
35 return Err(serde::de::Error::custom(
36 "VALIDATION:TableName must be at least 3 characters long and at most 255 characters long",
37 ));
38 }
39
40 if !table_name
42 .chars()
43 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
44 {
45 return Err(serde::de::Error::custom(format!(
46 "VALIDATION:1 validation error detected: \
47 Value '{}' at 'tableName' failed to satisfy constraint: \
48 Member must satisfy regular expression pattern: [a-zA-Z0-9_.-]+",
49 table_name
50 )));
51 }
52
53 Ok(DeleteTableRequest { table_name })
54 }
55}
56
57#[derive(Debug, Default, Serialize)]
58pub struct DeleteTableResponse {
59 #[serde(rename = "TableDescription")]
60 pub table_description: TableDescription,
61}
62
63pub async fn execute<S: StorageBackend>(
64 storage: &S,
65 request: DeleteTableRequest,
66 lifecycle: &VectorIndexLifecycle,
67) -> Result<DeleteTableResponse> {
68 crate::validation::validate_table_name(&request.table_name)?;
70
71 let meta = storage
73 .get_table_metadata(&request.table_name)
74 .await?
75 .ok_or_else(|| {
76 DynoxideError::ResourceNotFoundException(format!(
77 "Requested resource not found: Table: {} not found",
78 request.table_name
79 ))
80 })?;
81
82 if meta.deletion_protection_enabled {
84 return Err(DynoxideError::ValidationException(
85 "Resource cannot be deleted as it is currently protected against deletion. \
86 Disable deletion protection first."
87 .to_string(),
88 ));
89 }
90
91 let vector_indexes: Vec<crate::types::VectorIndex> = meta
105 .vector_index_definitions
106 .as_ref()
107 .and_then(|json| serde_json::from_str(json).ok())
108 .unwrap_or_default();
109 let vector_phases = lifecycle.phases_of(
110 storage,
111 &request.table_name,
112 vector_indexes.iter().map(|v| v.index_name.as_str()),
113 );
114 if vector_phases.any_creating() {
115 return Err(DynoxideError::ResourceInUseException(
116 "Attempt to change a resource which is still in use: Cannot delete table while \
117 indexes are being created, updated, or deleted."
118 .to_string(),
119 ));
120 }
121
122 lifecycle.forget_table(&request.table_name);
127
128 if let Some(ref gsi_json) = meta.gsi_definitions
130 && let Ok(gsis) = serde_json::from_str::<Vec<GlobalSecondaryIndex>>(gsi_json)
131 {
132 for gsi in &gsis {
133 storage
134 .drop_gsi_table(&request.table_name, &gsi.index_name)
135 .await?;
136 }
137 }
138
139 if let Some(ref lsi_json) = meta.lsi_definitions
141 && let Ok(lsis) = serde_json::from_str::<Vec<LocalSecondaryIndex>>(lsi_json)
142 {
143 for lsi in &lsis {
144 storage
145 .drop_lsi_table(&request.table_name, &lsi.index_name)
146 .await?;
147 }
148 }
149
150 for vix in &vector_indexes {
153 storage
154 .drop_vector_table(&request.table_name, &vix.index_name)
155 .await?;
156 }
157
158 storage.drop_data_table(&request.table_name).await?;
160
161 storage.delete_table_metadata(&request.table_name).await?;
163
164 let mut desc = build_table_description(&meta, Some(0), Some(0), &vector_phases);
167 desc.table_status = "DELETING".to_string();
168
169 Ok(DeleteTableResponse {
170 table_description: desc,
171 })
172}