use crate::common;
use aws_sdk_dynamodb::types;
use serde::Serialize;
use serde_dynamo::{Error, Result, to_attribute_value};
use std::collections;
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct SingleReadInput {
pub(crate) consistent_read: Option<bool>,
pub(crate) expression_attribute_names: Option<collections::HashMap<String, String>>,
pub(crate) projection_expression: Option<String>,
pub(crate) table_name: String,
}
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
pub struct SingleReadArgs {
pub consistent_read: Option<bool>,
pub selection: Option<common::selection::SelectionMap>,
pub table_name: String,
}
impl From<SingleReadArgs> for SingleReadInput {
fn from(single_read_args: SingleReadArgs) -> Self {
let (expression_attribute_names, projection_expression) = match single_read_args.selection {
Some(selection) => {
let selection_operation: common::ExpressionInput = selection.into();
(
Some(selection_operation.expression_attribute_names),
Some(selection_operation.expression),
)
}
None => (None, None),
};
Self {
consistent_read: single_read_args.consistent_read,
expression_attribute_names,
projection_expression,
table_name: single_read_args.table_name,
}
}
}
#[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct MultipleReadInput {
pub(crate) consistent_read: Option<bool>,
pub(crate) exclusive_start_key: Option<collections::HashMap<String, types::AttributeValue>>,
pub(crate) expression_attribute_names: Option<collections::HashMap<String, String>>,
pub(crate) expression_attribute_values:
Option<collections::HashMap<String, types::AttributeValue>>,
pub(crate) filter_expression: Option<String>,
pub(crate) index_name: Option<String>,
pub(crate) limit: Option<i32>,
pub(crate) projection_expression: Option<String>,
pub(crate) select: Option<types::Select>,
pub(crate) table_name: String,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct MultipleReadArgs<T> {
pub condition: Option<common::condition::ConditionMap<T>>,
pub consistent_read: Option<bool>,
pub exclusive_start_key: Option<collections::HashMap<String, T>>,
pub index_name: Option<String>,
pub limit: Option<i32>,
pub select: Option<types::Select>,
pub selection: Option<common::selection::SelectionMap>,
pub table_name: String,
}
impl<T: Serialize> TryFrom<MultipleReadArgs<T>> for MultipleReadInput {
type Error = Error;
fn try_from(multiple_read_args: MultipleReadArgs<T>) -> Result<Self> {
let exclusive_start_key = match multiple_read_args.exclusive_start_key {
Some(exclusive_start_key) => {
let mut serialized_exclusive_start_key =
collections::HashMap::with_capacity(exclusive_start_key.len());
for (key, value) in exclusive_start_key {
let value = to_attribute_value(value)?;
serialized_exclusive_start_key.insert(key, value);
}
Some(serialized_exclusive_start_key)
}
None => None,
};
let condition_operation: Option<common::ExpressionInput> = multiple_read_args
.condition
.map(|condition| condition.try_into())
.transpose()?;
let selection_operation: Option<common::ExpressionInput> = multiple_read_args
.selection
.map(|selection| selection.into());
let (
expression_attribute_names,
expression_attribute_values,
filter_expression,
projection_expression,
) = match (condition_operation, selection_operation) {
(Some(mut condition_operation), Some(selection_operation)) => {
condition_operation
.expression_attribute_names
.extend(selection_operation.expression_attribute_names);
(
Some(condition_operation.expression_attribute_names),
Some(condition_operation.expression_attribute_values),
Some(condition_operation.expression),
Some(selection_operation.expression),
)
}
(Some(condition_operation), None) => (
Some(condition_operation.expression_attribute_names),
Some(condition_operation.expression_attribute_values),
Some(condition_operation.expression),
None,
),
(None, Some(selection_operation)) => (
Some(selection_operation.expression_attribute_names),
None,
None,
Some(selection_operation.expression),
),
(None, None) => (None, None, None, None),
};
let operation = Self {
consistent_read: multiple_read_args.consistent_read,
exclusive_start_key,
expression_attribute_names,
expression_attribute_values,
filter_expression,
index_name: multiple_read_args.index_name,
limit: multiple_read_args.limit,
projection_expression,
select: multiple_read_args.select,
table_name: multiple_read_args.table_name,
};
Ok(operation)
}
}
#[macro_export]
macro_rules! get_paginated_output {
($paginator:expr, $output_type:ty) => {{
let mut outputs = Vec::new();
while let Some(page) = $paginator.next().await {
outputs.push(page?);
}
let (items, count, scanned, capacities) = outputs.into_iter().fold(
(Vec::new(), 0, 0, Vec::new()),
|(mut items, count, scanned, mut caps), output| {
if let Some(other_items) = output.items {
items.extend(other_items);
}
if let Some(cap) = output.consumed_capacity {
caps.push(cap);
}
(
items,
count + output.count,
scanned + output.scanned_count,
caps,
)
},
);
let aggregated_capacity = $crate::read::common::aggregate_capacity(capacities);
let output = <$output_type>::builder()
.set_items(Some(items))
.set_count(Some(count))
.set_scanned_count(Some(scanned))
.set_consumed_capacity(Some(aggregated_capacity))
.build();
Ok(output)
}};
}
pub(crate) fn aggregate_capacity(
capacities: Vec<types::ConsumedCapacity>,
) -> types::ConsumedCapacity {
let (cap, read, write, table) = capacities.into_iter().fold(
(0.0, 0.0, 0.0, None),
|(cap, read, write, table), capacity| {
(
cap + capacity.capacity_units.unwrap_or(0.0),
read + capacity.read_capacity_units.unwrap_or(0.0),
write + capacity.write_capacity_units.unwrap_or(0.0),
table.or(capacity.table_name),
)
},
);
types::ConsumedCapacity::builder()
.set_table_name(table)
.set_capacity_units(Some(cap))
.set_read_capacity_units(Some(read))
.set_write_capacity_units(Some(write))
.build()
}
#[macro_export]
macro_rules! apply_single_read_operation {
($builder:expr, $single_read_operation:expr) => {
$builder
.set_consistent_read($single_read_operation.consistent_read)
.set_expression_attribute_names($single_read_operation.expression_attribute_names)
.set_projection_expression($single_read_operation.projection_expression)
.table_name($single_read_operation.table_name)
};
}
#[macro_export]
macro_rules! apply_multiple_read_operation {
($builder:expr, $multiple_read_operation:expr) => {
$builder
.set_consistent_read($multiple_read_operation.consistent_read)
.set_exclusive_start_key($multiple_read_operation.exclusive_start_key)
.set_expression_attribute_names($multiple_read_operation.expression_attribute_names)
.set_expression_attribute_values($multiple_read_operation.expression_attribute_values)
.set_filter_expression($multiple_read_operation.filter_expression)
.set_index_name($multiple_read_operation.index_name)
.set_limit($multiple_read_operation.limit)
.set_projection_expression($multiple_read_operation.projection_expression)
.set_select($multiple_read_operation.select)
.table_name($multiple_read_operation.table_name)
};
}