Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion crates/engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,15 @@ impl OperationContext {

/// Dispatch an operation by name.
///
/// `raw_body` is the request text `body` was parsed from. `Scan` reads the
/// member order of its `ExpressionAttributeValues`, `ExclusiveStartKey` and
/// `ScanFilter` from it.
///
/// Returns the JSON response body and sideband metrics for the metrics collector.
pub async fn dispatch(
operation: &str,
body: serde_json::Value,
raw_body: &[u8],
ctx: &OperationContext,
server_addr: &str,
) -> Result<DispatchResult, DynamoDbError> {
Expand Down Expand Up @@ -474,7 +479,7 @@ pub async fn dispatch(
"DeleteItem" => handle_delete_item(body, ctx).await,
"UpdateItem" => handle_update_item(body, ctx).await,
"Query" => handle_query(body, ctx).await,
"Scan" => handle_scan(body, ctx).await,
"Scan" => handle_scan(body, raw_body, ctx).await,
"SearchVectors" => handle_search_vectors(body, ctx).await,
"BatchGetItem" => handle_batch_get_item(body, ctx).await,
"BatchWriteItem" => handle_batch_write_item(body, ctx).await,
Expand Down
27 changes: 17 additions & 10 deletions crates/engine/src/query_key_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,17 +98,23 @@ pub(crate) fn shape_fault_first<T: DeserializeOwned>(
check: DynamoDbError,
) -> DynamoDbError {
match serde_json::from_value::<T>(body.clone()) {
Err(e) => match crate::deserialize_error(e) {
DynamoDbError::SerializationException(msg) if msg.contains(UNKNOWN_TYPE_DESCRIPTOR) => {
check
}
shape @ DynamoDbError::SerializationException(_) => shape,
_ => check,
},
Err(e) => {
let fault = crate::deserialize_error(e);
if is_shape_fault(&fault) { fault } else { check }
}
Ok(_) => check,
}
}

/// Whether `fault`, from [`crate::deserialize_error`], is a fault in the shape
/// of the body (a field of the wrong JSON type), which the service reports
/// ahead of every check, rather than an attribute value the deserializer
/// refuses with a `ValidationException` or an unknown type descriptor; see
/// [`shape_fault_first`].
pub(crate) fn is_shape_fault(fault: &DynamoDbError) -> bool {
matches!(fault, DynamoDbError::SerializationException(msg) if !msg.contains(UNKNOWN_TYPE_DESCRIPTOR))
}

/// The deserializer's text for an AttributeValue whose type descriptor is not
/// one of the service's.
const UNKNOWN_TYPE_DESCRIPTOR: &str = "unknown AttributeValue type descriptor";
Expand Down Expand Up @@ -205,7 +211,8 @@ pub(crate) fn non_empty(body: &Value, field: &str) -> bool {
}

/// The type descriptors an AttributeValue may carry.
const TYPE_DESCRIPTORS: &[&str] = &["S", "N", "B", "SS", "NS", "BS", "M", "L", "NULL", "BOOL"];
pub(crate) const TYPE_DESCRIPTORS: &[&str] =
&["S", "N", "B", "SS", "NS", "BS", "M", "L", "NULL", "BOOL"];

/// The legacy condition maps of `Scan` whose `AttributeValueList` entries
/// [`has_unreadable_attribute_value`] reads.
Expand Down Expand Up @@ -315,7 +322,7 @@ pub fn validate_expression_attribute_value_numbers(

/// Every number inside one attribute value (`N`, `NS` members, and the values
/// nested in `L` and `M`), with Unicode decimal digits folded for the check.
fn validate_value_numbers(value: &AttributeValue) -> Result<(), DynamoDbError> {
pub(crate) fn validate_value_numbers(value: &AttributeValue) -> Result<(), DynamoDbError> {
match value {
AttributeValue::N(n) => validate_number_text(n),
AttributeValue::NS(set) => set.iter().try_for_each(|n| validate_number_text(n)),
Expand All @@ -327,7 +334,7 @@ fn validate_value_numbers(value: &AttributeValue) -> Result<(), DynamoDbError> {

/// One number text against the number rules, with the service's `Query`
/// message for an empty value and the original text echoed for a malformed one.
fn validate_number_text(text: &str) -> Result<(), DynamoDbError> {
pub(crate) fn validate_number_text(text: &str) -> Result<(), DynamoDbError> {
let folded = crate::decimal_digits::fold_decimal_digits(text);
match extenddb_core::validation::number::validate_and_normalize_number(&folded) {
Ok(_) => Ok(()),
Expand Down
Loading
Loading