use std::future::{Future, IntoFuture};
use std::pin::Pin;
use super::*;
use aws_sdk_dynamodb::operation::update_item::builders::UpdateItemFluentBuilder;
#[must_use = "builder does nothing until awaited or executed"]
pub struct UpdateItemRequest<
TD: TableDefinition,
T = (),
O: OutputFormat = Raw,
R: ReturnValue = ReturnNothing,
C: ConditionState = NoCondition,
> {
builder: UpdateItemFluentBuilder,
_marker: PhantomData<(TD, T, O, R, C)>,
}
impl<TD: TableDefinition, T, O: OutputFormat, R: ReturnValue, C: ConditionState>
UpdateItemRequest<TD, T, O, R, C>
{
pub fn into_inner(self) -> UpdateItemFluentBuilder {
self.builder
}
}
impl<TD: TableDefinition> UpdateItemRequest<TD> {
pub fn new(client: aws_sdk_dynamodb::Client, key: Key<TD>, update: Update<'_>) -> Self {
Self::_new(client, key, update)
}
}
impl<TD: TableDefinition, T, O: OutputFormat, R: ReturnValue, C: ConditionState>
UpdateItemRequest<TD, T, O, R, C>
{
pub(super) fn _new(client: aws_sdk_dynamodb::Client, key: Key<TD>, update: Update<'_>) -> Self {
let table_name = TD::table_name();
tracing::debug!(table_name, ?key, %update, "UpdateItem");
Self {
builder: update.apply(
client
.update_item()
.table_name(table_name)
.set_key(Some(key.into_inner())),
),
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T, O: OutputFormat, C: ConditionState>
UpdateItemRequest<TD, T, O, ReturnNothing, C>
{
pub fn return_old(self) -> UpdateItemRequest<TD, T, O, Return<Old>, C> {
tracing::debug!("UpdateItem return_old");
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
pub fn return_new(self) -> UpdateItemRequest<TD, T, O, Return<New>, C> {
tracing::debug!("UpdateItem return_new");
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T, O: OutputFormat, C: ConditionState>
UpdateItemRequest<TD, T, O, Return<New>, C>
{
pub fn return_old(self) -> UpdateItemRequest<TD, T, O, Return<Old>, C> {
tracing::debug!("UpdateItem return_old");
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
pub fn return_none(self) -> UpdateItemRequest<TD, T, O, ReturnNothing, C> {
tracing::debug!("UpdateItem return_none");
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T, O: OutputFormat, C: ConditionState>
UpdateItemRequest<TD, T, O, Return<Old>, C>
{
pub fn return_new(self) -> UpdateItemRequest<TD, T, O, Return<New>, C> {
tracing::debug!("UpdateItem return_new");
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
pub fn return_none(self) -> UpdateItemRequest<TD, T, O, ReturnNothing, C> {
tracing::debug!("UpdateItem return_none");
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T, O: OutputFormat, R: ReturnValue>
UpdateItemRequest<TD, T, O, R, NoCondition>
{
pub fn condition(
mut self,
condition: Condition<'_>,
) -> UpdateItemRequest<TD, T, O, R, AlreadyHasCondition> {
tracing::debug!(%condition, "UpdateItem condition");
self.builder = condition.apply(self.builder);
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD>, O: OutputFormat, R: ReturnValue>
UpdateItemRequest<TD, T, O, R, NoCondition>
{
pub fn exists(self) -> UpdateItemRequest<TD, T, O, R, AlreadyHasCondition> {
self.condition(T::exists())
}
pub fn not_exists(self) -> UpdateItemRequest<TD, T, O, R, AlreadyHasCondition> {
self.condition(T::not_exists())
}
}
impl<TD: TableDefinition, T, R: ReturnValue, C: ConditionState>
UpdateItemRequest<TD, T, Typed, R, C>
{
pub fn raw(self) -> UpdateItemRequest<TD, T, Raw, R, C> {
UpdateItemRequest {
builder: self.builder,
_marker: PhantomData,
}
}
}
impl<TD: TableDefinition, T, O: OutputFormat, C: ConditionState>
UpdateItemRequest<TD, T, O, ReturnNothing, C>
{
#[tracing::instrument(level = "debug", skip(self), name = "update_execute")]
pub fn execute(self) -> impl Future<Output = Result<()>> + Send + 'static {
let builder = self.builder;
async move {
builder.return_values(SDKReturnValue::None).send().await?;
Ok(())
}
}
}
impl<TD: TableDefinition, T, O: OutputFormat, C: ConditionState> IntoFuture
for UpdateItemRequest<TD, T, O, ReturnNothing, C>
{
type Output = Result<()>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.execute())
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD> + DeserializeOwned, C: ConditionState>
UpdateItemRequest<TD, T, Typed, Return<Old>, C>
{
#[tracing::instrument(level = "debug", skip(self), name = "update_execute_old")]
pub fn execute(self) -> impl Future<Output = Result<Option<T>>> + Send + 'static {
let builder = self.builder;
async move {
let out = builder.return_values(Old::return_value()).send().await?;
out.attributes
.map(Item::from_dynamodb_response)
.map(T::try_from_item)
.transpose()
}
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD> + DeserializeOwned, C: ConditionState> IntoFuture
for UpdateItemRequest<TD, T, Typed, Return<Old>, C>
{
type Output = Result<Option<T>>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.execute())
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD> + DeserializeOwned, C: ConditionState>
UpdateItemRequest<TD, T, Typed, Return<New>, C>
{
#[tracing::instrument(level = "debug", skip(self), name = "update_execute_new")]
pub fn execute(self) -> impl Future<Output = Result<T>> + Send + 'static {
let builder = self.builder;
async move {
let out = builder.return_values(New::return_value()).send().await?;
out.attributes
.map(Item::from_dynamodb_response)
.map(T::try_from_item)
.expect("asked to return something")
}
}
}
impl<TD: TableDefinition, T: DynamoDBItem<TD> + DeserializeOwned, C: ConditionState> IntoFuture
for UpdateItemRequest<TD, T, Typed, Return<New>, C>
{
type Output = Result<T>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.execute())
}
}
impl<TD: TableDefinition, T, C: ConditionState> UpdateItemRequest<TD, T, Raw, Return<Old>, C> {
#[tracing::instrument(level = "debug", skip(self), name = "update_execute_old_raw")]
pub fn execute(self) -> impl Future<Output = Result<Option<Item<TD>>>> + Send + 'static {
let builder = self.builder;
async move {
let out = builder.return_values(Old::return_value()).send().await?;
Ok(out.attributes.map(Item::from_dynamodb_response))
}
}
}
impl<TD: TableDefinition, T, C: ConditionState> IntoFuture
for UpdateItemRequest<TD, T, Raw, Return<Old>, C>
{
type Output = Result<Option<Item<TD>>>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.execute())
}
}
impl<TD: TableDefinition, T, C: ConditionState> UpdateItemRequest<TD, T, Raw, Return<New>, C> {
#[tracing::instrument(level = "debug", skip(self), name = "update_execute_new_raw")]
pub fn execute(self) -> impl Future<Output = Result<Item<TD>>> + Send + 'static {
let builder = self.builder;
async move {
let out = builder.return_values(New::return_value()).send().await?;
Ok(out
.attributes
.map(Item::from_dynamodb_response)
.expect("asked to return something"))
}
}
}
impl<TD: TableDefinition, T, C: ConditionState> IntoFuture
for UpdateItemRequest<TD, T, Raw, Return<New>, C>
{
type Output = Result<Item<TD>>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(self.execute())
}
}