Skip to main content

dynoxide/actions/
describe_table.rs

1use crate::actions::{TableDescription, build_table_description};
2use crate::errors::{DynoxideError, Result};
3use crate::storage_backend::StorageBackend;
4use serde::{Deserialize, Serialize};
5
6/// Internal deserialization struct for detecting missing TableName.
7#[derive(Debug, Default, Deserialize)]
8struct DescribeTableRequestRaw {
9    #[serde(rename = "TableName", default)]
10    table_name: Option<String>,
11}
12
13#[derive(Debug, Default)]
14pub struct DescribeTableRequest {
15    pub table_name: String,
16}
17
18impl<'de> serde::Deserialize<'de> for DescribeTableRequest {
19    fn deserialize<D: serde::Deserializer<'de>>(
20        deserializer: D,
21    ) -> std::result::Result<Self, D::Error> {
22        let raw = DescribeTableRequestRaw::deserialize(deserializer)?;
23
24        if raw.table_name.is_none() {
25            return Err(serde::de::Error::custom(
26                "VALIDATION:The parameter 'TableName' is required but was not present in the request",
27            ));
28        }
29        let table_name = raw.table_name.unwrap();
30
31        // Length check (before pattern, matching DynamoDB ordering)
32        if table_name.len() < 3 || table_name.len() > 255 {
33            return Err(serde::de::Error::custom(
34                "VALIDATION:TableName must be at least 3 characters long and at most 255 characters long",
35            ));
36        }
37
38        // Pattern check
39        if !table_name
40            .chars()
41            .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '.')
42        {
43            return Err(serde::de::Error::custom(format!(
44                "VALIDATION:1 validation error detected: \
45                 Value '{}' at 'tableName' failed to satisfy constraint: \
46                 Member must satisfy regular expression pattern: [a-zA-Z0-9_.-]+",
47                table_name
48            )));
49        }
50
51        Ok(DescribeTableRequest { table_name })
52    }
53}
54
55#[derive(Debug, Default, Serialize)]
56pub struct DescribeTableResponse {
57    #[serde(rename = "Table")]
58    pub table: TableDescription,
59}
60
61pub async fn execute<S: StorageBackend>(
62    storage: &S,
63    request: DescribeTableRequest,
64) -> Result<DescribeTableResponse> {
65    // Validate table name format before checking existence (DynamoDB validates input first)
66    crate::validation::validate_table_name(&request.table_name)?;
67
68    let meta = storage
69        .get_table_metadata(&request.table_name)
70        .await?
71        .ok_or_else(|| {
72            DynoxideError::ResourceNotFoundException(format!(
73                "Requested resource not found: Table: {} not found",
74                request.table_name
75            ))
76        })?;
77
78    // Get actual item count and size
79    let item_count = storage.count_items(&request.table_name).await.ok();
80    let table_size_bytes = item_count.map(|_| 0i64); // Approximate; real size tracking is deferred
81
82    let desc = build_table_description(&meta, item_count, table_size_bytes);
83
84    Ok(DescribeTableResponse { table: desc })
85}