dynoxide/actions/
batch_execute_statement.rs1use crate::errors::{DynoxideError, Result};
2use crate::partiql;
3use crate::storage_backend::StorageBackend;
4use crate::types::{AttributeValue, Item};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Default, Deserialize)]
8pub struct BatchExecuteStatementRequest {
9 #[serde(rename = "Statements")]
10 pub statements: Vec<BatchStatementRequest>,
11}
12
13#[derive(Debug, Default, Deserialize)]
14pub struct BatchStatementRequest {
15 #[serde(rename = "Statement")]
16 pub statement: String,
17 #[serde(rename = "Parameters", default)]
18 pub parameters: Option<Vec<AttributeValue>>,
19}
20
21#[derive(Debug, Default, Serialize)]
22pub struct BatchExecuteStatementResponse {
23 #[serde(rename = "Responses")]
24 pub responses: Vec<BatchStatementResponse>,
25}
26
27#[derive(Debug, Default, Serialize)]
28#[non_exhaustive]
29pub struct BatchStatementResponse {
30 #[serde(rename = "Error", skip_serializing_if = "Option::is_none")]
31 pub error: Option<BatchStatementError>,
32 #[serde(rename = "Item", skip_serializing_if = "Option::is_none")]
33 pub item: Option<Item>,
34 #[serde(rename = "TableName", skip_serializing_if = "Option::is_none")]
38 pub table_name: Option<String>,
39}
40
41#[derive(Debug, Default, Serialize)]
42pub struct BatchStatementError {
43 #[serde(rename = "Code")]
44 pub code: String,
45 #[serde(rename = "Message")]
46 pub message: String,
47}
48
49pub async fn execute<S: StorageBackend>(
50 storage: &S,
51 request: BatchExecuteStatementRequest,
52) -> Result<BatchExecuteStatementResponse> {
53 if request.statements.is_empty() {
54 return Err(DynoxideError::ValidationException(
55 "1 validation error detected: Value '[]' at 'statements' failed to satisfy constraint: Member must have length greater than or equal to 1".to_string(),
56 ));
57 }
58
59 if request.statements.len() > 25 {
60 return Err(DynoxideError::ValidationException(
61 "Too many statements in BatchExecuteStatement; limit is 25".to_string(),
62 ));
63 }
64
65 let mut responses = Vec::with_capacity(request.statements.len());
66
67 for stmt_req in &request.statements {
68 let parsed = partiql::parser::parse(&stmt_req.statement);
69
70 let response = match parsed {
71 Err(e) => BatchStatementResponse {
72 error: Some(BatchStatementError {
73 code: "ValidationError".to_string(),
77 message: format!("Statement wasn't well formed, can't be processed: {e}"),
78 }),
79 item: None,
80 table_name: None,
81 },
82 Ok(stmt) => {
83 let table = partiql::parser::table_name(&stmt).map(str::to_string);
86 let params = stmt_req.parameters.as_deref().unwrap_or_default();
87 match partiql::executor::execute(storage, &stmt, params, None).await {
88 Ok(Some(items)) => {
89 BatchStatementResponse {
93 error: None,
94 item: items.into_iter().next(),
95 table_name: table,
96 }
97 }
98 Ok(None) => BatchStatementResponse {
99 error: None,
100 item: None,
101 table_name: table,
102 },
103 Err(e) => BatchStatementResponse {
104 error: Some(BatchStatementError {
105 code: e.short_error_code().to_string(),
106 message: e.to_string(),
107 }),
108 item: None,
109 table_name: None,
110 },
111 }
112 }
113 };
114
115 responses.push(response);
116 }
117
118 Ok(BatchExecuteStatementResponse { responses })
119}