Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DynamoDB Enhanced Client: Added support for attribute level custom up… #2076

Merged
merged 2 commits into from
Oct 3, 2020

Conversation

bmaizels
Copy link
Contributor

@bmaizels bmaizels commented Oct 1, 2020

…date behaviors

Implements suggestion in #1822

Description

Copied from README.md update:

Changing update behavior of attributes

It is possible to customize the update behavior as applicable to individual attributes when an 'update' operation is
performed (e.g. UpdateItem or an update within TransactWriteItems).

For example, say like you wanted to store a 'created on' timestamp on your record, but only wanted its value to be
written if there is no existing value for the attribute stored in the database then you would use the
WRITE_IF_NOT_EXISTS update behavior. Here is an example using a bean:

@DynamoDbBean
public class Customer extends GenericRecord {
    private String id;
    private Instant createdOn;

    @DynamoDbPartitionKey
    public String getId() { return this.id; }
    public void setId(String id) { this.name = id; }

    @DynamoDbUpdateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)
    public Instant getCreatedOn() { return this.createdOn; }    
    public void setCreatedOn(Instant createdOn) { this.createdOn = createdOn; }
}

Same example using a static table schema:

static final TableSchema<Customer> CUSTOMER_TABLE_SCHEMA =
     TableSchema.builder(Customer.class)
       .newItemSupplier(Customer::new)
       .addAttribute(String.class, a -> a.name("id")
                                         .getter(Customer::getId)
                                         .setter(Customer::setId)
                                         .tags(primaryPartitionKey()))
       .addAttribute(Instant.class, a -> a.name("createdOn")
                                          .getter(Customer::getCreatedOn)
                                          .setter(Customer::setCreatedOn)
                                          .tags(updateBehavior(UpdateBehavior.WRITE_IF_NOT_EXISTS)))
       .build();

@bmaizels bmaizels force-pushed the bmaizels/ddbenhanced-update-behaviors branch 2 times, most recently from b7be963 to ae432b1 Compare October 1, 2020 02:48
@bmaizels bmaizels force-pushed the bmaizels/ddbenhanced-update-behaviors branch from 90714e4 to 7857623 Compare October 1, 2020 21:51
Comment on lines +43 to +46
@DynamoDbUpdateBehavior(WRITE_IF_NOT_EXISTS)
public Instant getCreatedOn() {
return createdOn;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about the use of this. Would you actually use it for "created date" if it doesn't work for putItem (only for updateItem)? Wouldn't this be firstUpdatedDate, which seems kind of useless?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use-case, as it was put to me, was to avoid branching logic and always do a uniform update. It also allows schema evolution so they can update the record and write a value with a new attribute that didn't exist in the schema before only if it hadn't been set before in the database. I imagine it's the same rationale that lead to DDB implementing if_not_exists in their update expressions at all, this is really just a 'plumbing it through' exercise.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's probably more useful at the request level than the schema level, but that's a different feature request, I suppose.

@sonarcloud
Copy link

sonarcloud bot commented Oct 2, 2020

Kudos, SonarCloud Quality Gate passed!

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities (and Security Hotspot 0 Security Hotspots to review)
Code Smell A 1 Code Smell

88.9% 88.9% Coverage
0.0% 0.0% Duplication

warning The version of Java (1.8.0_252) you have used to run this analysis is deprecated and we will stop accepting it from October 2020. Please update to at least Java 11.
Read more here

@takarabt
Copy link

takarabt commented Nov 4, 2020

Hi @bmaizels,

Are you planning to add the possibility to ignore null values when updating a record?

I think this is a very common use case. For example, if I want to change only the description for a given record using the DynamoDBMapper (sdk v1) I could use the object {"id": "123", "description": "My new description"}, Using the same object with the DynamoDB Enhanced client, the attributes which are not included on the object will be overwritten to null.

Basically we need something similar to UPDATE_SKIP_NULL_ATTRIBUTES -> https://aws.amazon.com/blogs/developer/using-the-savebehavior-configuration-for-the-dynamodbmapper/

For more flexibility, it's probably better to add this as a configuration on the client level.

Regards,

@bmaizels
Copy link
Contributor Author

bmaizels commented Nov 4, 2020

@takarabt
Copy link

takarabt commented Nov 5, 2020

@bmaizels yes this is what we used, after investigation I figured out that the problem is related to the usage of primitive type "int" it's set by default to 0 and not to null.

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants