use super::*;
use aws_sdk_dynamodb::types::{
TransactWriteItem,
builders::{ConditionCheckBuilder, DeleteBuilder, PutBuilder, UpdateBuilder},
};
#[must_use = "builder does nothing until .build() is called"]
pub struct TransactPutRequest<TD: TableDefinition, T = (), C: ConditionState = NoCondition> {
builder: PutBuilder,
_marker: PhantomData<(TD, T, C)>,
}
impl<TD: TableDefinition, T, C: ConditionState> TransactPutRequest<TD, T, C> {
pub fn new(item: Item<TD>) -> Self {
let table_name = TD::table_name();
tracing::debug!(table_name, "TransactPut");
Self {
builder: PutBuilder::default()
.table_name(table_name)
.set_item(Some(item.into_inner())),
_marker: PhantomData,
}
}
pub fn into_inner(self) -> PutBuilder {
self.builder
}
pub fn build(self) -> TransactWriteItem {
TransactWriteItem::builder()
.put(self.builder.build().expect("mandatory attributes set"))
.build()
}
}
impl<TD: TableDefinition, T> TransactPutRequest<TD, T, NoCondition> {
pub fn condition(
mut self,
condition: Condition<'_>,
) -> TransactPutRequest<TD, T, AlreadyHasCondition> {
tracing::debug!(%condition, "TransactPut condition");
self.builder = condition.apply(self.builder);
TransactPutRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD>> TransactPutRequest<TD, T, NoCondition> {
pub fn exists(mut self) -> TransactPutRequest<TD, T, AlreadyHasCondition> {
self.builder = T::exists().apply(self.builder);
TransactPutRequest {
builder: self.builder,
_marker: PhantomData,
}
}
pub fn not_exists(mut self) -> TransactPutRequest<TD, T, AlreadyHasCondition> {
self.builder = T::not_exists().apply(self.builder);
TransactPutRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
#[must_use = "builder does nothing until .build() is called"]
pub struct TransactDeleteRequest<TD: TableDefinition, T = (), C: ConditionState = NoCondition> {
builder: DeleteBuilder,
_marker: PhantomData<(TD, T, C)>,
}
impl<TD: TableDefinition, T, C: ConditionState> TransactDeleteRequest<TD, T, C> {
pub fn new(key: Key<TD>) -> Self {
let table_name = TD::table_name();
tracing::debug!(table_name, key = ?key, "TransactDelete");
Self {
builder: DeleteBuilder::default()
.table_name(table_name)
.set_key(Some(key.into_inner())),
_marker: PhantomData,
}
}
pub fn into_inner(self) -> DeleteBuilder {
self.builder
}
pub fn build(self) -> TransactWriteItem {
TransactWriteItem::builder()
.delete(self.builder.build().expect("mandatory attributes set"))
.build()
}
}
impl<TD: TableDefinition, T> TransactDeleteRequest<TD, T, NoCondition> {
pub fn condition(
mut self,
condition: Condition<'_>,
) -> TransactDeleteRequest<TD, T, AlreadyHasCondition> {
tracing::debug!(%condition, "TransactDelete condition");
self.builder = condition.apply(self.builder);
TransactDeleteRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD>> TransactDeleteRequest<TD, T, NoCondition> {
pub fn exists(self) -> TransactDeleteRequest<TD, T, AlreadyHasCondition> {
self.condition(T::exists())
}
}
#[must_use = "builder does nothing until .build() is called"]
pub struct TransactUpdateRequest<TD: TableDefinition, T = (), C: ConditionState = NoCondition> {
builder: UpdateBuilder,
_marker: PhantomData<(TD, T, C)>,
}
impl<TD: TableDefinition, T, C: ConditionState> TransactUpdateRequest<TD, T, C> {
pub fn new(key: Key<TD>, update: Update<'_>) -> Self {
let table_name = TD::table_name();
tracing::debug!(table_name, key = ?key, %update, "TransactUpdate");
Self {
builder: update.apply(
UpdateBuilder::default()
.table_name(table_name)
.set_key(Some(key.into_inner())),
),
_marker: PhantomData,
}
}
pub fn into_inner(self) -> UpdateBuilder {
self.builder
}
pub fn build(self) -> TransactWriteItem {
TransactWriteItem::builder()
.update(
self.builder
.build()
.expect("Update expression is always set"),
)
.build()
}
}
impl<TD: TableDefinition, T> TransactUpdateRequest<TD, T, NoCondition> {
pub fn condition(
mut self,
condition: Condition<'_>,
) -> TransactUpdateRequest<TD, T, AlreadyHasCondition> {
tracing::debug!(%condition, "TransactUpdate condition");
self.builder = condition.apply(self.builder);
TransactUpdateRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD>> TransactUpdateRequest<TD, T, NoCondition> {
pub fn exists(mut self) -> TransactUpdateRequest<TD, T, AlreadyHasCondition> {
self.builder = T::exists().apply(self.builder);
TransactUpdateRequest {
builder: self.builder,
_marker: PhantomData,
}
}
pub fn not_exists(mut self) -> TransactUpdateRequest<TD, T, AlreadyHasCondition> {
self.builder = T::not_exists().apply(self.builder);
TransactUpdateRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
#[must_use = "builder does nothing until .build() is called"]
pub struct TransactConditionCheckRequest<TD: TableDefinition, T = ()> {
builder: ConditionCheckBuilder,
_marker: PhantomData<(TD, T)>,
}
impl<TD: TableDefinition, T> TransactConditionCheckRequest<TD, T> {
pub fn new(key: Key<TD>, condition: Condition<'_>) -> Self {
let table_name = TD::table_name();
tracing::debug!(table_name, key = ?key, %condition, "TransactConditionCheck");
Self {
builder: condition.apply(
ConditionCheckBuilder::default()
.table_name(table_name)
.set_key(Some(key.into_inner())),
),
_marker: PhantomData,
}
}
pub fn into_inner(self) -> ConditionCheckBuilder {
self.builder
}
pub fn build(self) -> TransactWriteItem {
TransactWriteItem::builder()
.condition_check(self.builder.build().expect("mandatory attributes set"))
.build()
}
}
pub trait DynamoDBItemTransactOp<TD: TableDefinition>: DynamoDBItemOp<TD> {
fn transact_put(&self) -> TransactPutRequest<TD, Self>
where
Self: Serialize,
{
TransactPutRequest::new(self.to_item())
}
fn transact_delete(&self) -> TransactDeleteRequest<TD, Self> {
TransactDeleteRequest::new(self.get_key())
}
fn transact_delete_by_id(key_id: Self::KeyId<'_>) -> TransactDeleteRequest<TD, Self> {
TransactDeleteRequest::new(Self::get_key_from_id(key_id))
}
fn transact_update(&self, update: Update<'_>) -> TransactUpdateRequest<TD, Self> {
TransactUpdateRequest::new(self.get_key(), update)
}
fn transact_update_by_id(
key_id: Self::KeyId<'_>,
update: Update<'_>,
) -> TransactUpdateRequest<TD, Self> {
TransactUpdateRequest::new(Self::get_key_from_id(key_id), update)
}
fn transact_condition(
&self,
condition: Condition<'_>,
) -> TransactConditionCheckRequest<TD, Self> {
TransactConditionCheckRequest::new(self.get_key(), condition)
}
fn transact_condition_by_id(
key_id: Self::KeyId<'_>,
condition: Condition<'_>,
) -> TransactConditionCheckRequest<TD, Self> {
TransactConditionCheckRequest::new(Self::get_key_from_id(key_id), condition)
}
}
impl<TD: TableDefinition, DBI: DynamoDBItemOp<TD>> DynamoDBItemTransactOp<TD> for DBI {}