Skip to content

Adding support for Select in ScanEnhancedRequest #5451

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

Closed
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"category": "DynamoDB Enhanced Client",
"contributor": "shetsa-amzn",
"type": "feature",
"description": "Adding support for Select in ScanEnhancedRequest"
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public ScanRequest generateRequest(TableSchema<T> tableSchema,
.exclusiveStartKey(this.request.exclusiveStartKey())
.consistentRead(this.request.consistentRead())
.returnConsumedCapacity(this.request.returnConsumedCapacity())
.select(this.request.select())
.expressionAttributeValues(expressionValues)
.expressionAttributeNames(expressionNames)
.projectionExpression(projectionExpressionAsString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
import software.amazon.awssdk.services.dynamodb.model.Select;
import software.amazon.awssdk.utils.Validate;

/**
Expand All @@ -48,6 +49,7 @@ public final class ScanEnhancedRequest {
private final Integer limit;
private final Boolean consistentRead;
private final Expression filterExpression;
private final Select select;
private final List<NestedAttributeName> attributesToProject;
private final Integer segment;
private final Integer totalSegments;
Expand All @@ -60,6 +62,7 @@ private ScanEnhancedRequest(Builder builder) {
this.totalSegments = builder.totalSegments;
this.consistentRead = builder.consistentRead;
this.filterExpression = builder.filterExpression;
this.select = builder.select;
this.returnConsumedCapacity = builder.returnConsumedCapacity;
this.attributesToProject = builder.attributesToProject != null
? Collections.unmodifiableList(builder.attributesToProject)
Expand All @@ -83,6 +86,7 @@ public Builder toBuilder() {
.totalSegments(totalSegments)
.consistentRead(consistentRead)
.filterExpression(filterExpression)
.select(select)
.returnConsumedCapacity(returnConsumedCapacity)
.addNestedAttributesToProject(attributesToProject);
}
Expand Down Expand Up @@ -129,6 +133,24 @@ public Expression filterExpression() {
return filterExpression;
}

/**
* Returns the value of select, or null if it doesn't exist.
* @return
*/
public Select select() {
return select;
}

/**
* Returns the value of select as a string, or null if it doesn't exist.
* @return
*/
public String selectAsString() {
return String.valueOf(select);
}

/**

/**
* Returns the list of projected attributes on this request object, or an null if no projection is specified.
* Nested attributes are represented using the '.' separator. Example : foo.bar is represented as "foo.bar" which is
Expand Down Expand Up @@ -204,6 +226,11 @@ public boolean equals(Object o) {
? !returnConsumedCapacity.equals(scan.returnConsumedCapacity) : scan.returnConsumedCapacity != null) {
return false;
}

if (select != null ? ! select.equals(scan.select) : scan.select != null) {
return false;
}

return filterExpression != null ? filterExpression.equals(scan.filterExpression) : scan.filterExpression == null;
}

Expand All @@ -215,6 +242,7 @@ public int hashCode() {
result = 31 * result + (totalSegments != null ? totalSegments.hashCode() : 0);
result = 31 * result + (consistentRead != null ? consistentRead.hashCode() : 0);
result = 31 * result + (filterExpression != null ? filterExpression.hashCode() : 0);
result = 31 * result + (select != null ? select.hashCode() : 0);
result = 31 * result + (attributesToProject != null ? attributesToProject.hashCode() : 0);
result = 31 * result + (returnConsumedCapacity != null ? returnConsumedCapacity.hashCode() : 0);
return result;
Expand All @@ -229,6 +257,7 @@ public static final class Builder {
private Integer limit;
private Boolean consistentRead;
private Expression filterExpression;
private Select select;
private List<NestedAttributeName> attributesToProject;
private Integer segment;
private Integer totalSegments;
Expand Down Expand Up @@ -335,6 +364,18 @@ public Builder filterExpression(Expression filterExpression) {
return this;
}

/**
* Determines the attributes to be returned in the result. See {@link Select} for examples and constraints.
* By default, all attributes are returned.
* @param select
* @return a builder of this type
*/
public Builder select(Select select) {
this.select = select;
return this;
}


/**
* <p>
* Sets a collection of the attribute names to be retrieved from the database. These attributes can include
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@
import software.amazon.awssdk.enhanced.dynamodb.Expression;
import software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument;
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.InnerAttributeRecord;
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.NestedTestRecord;
import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema;
import software.amazon.awssdk.enhanced.dynamodb.model.Page;
import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.Select;

public class BasicScanTest extends LocalDynamoDbSyncTestBase {
private static class Record {
Expand Down Expand Up @@ -645,4 +647,98 @@ public void scanAllRecordsWithNestedProjectionNameEmptyNameMap() {
Page<NestedTestRecord> next = resultsAttributeToProject.next();
});
}

@Test
public void scanAllRecordsWithSelect_specific_attr() {
insertRecords();
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":min_value", numberValue(3));
expressionValues.put(":max_value", numberValue(5));
Expression expression = Expression.builder()
.expression("#sort >= :min_value AND #sort <= :max_value")
.expressionValues(expressionValues)
.putExpressionName("#sort", "sort")
.build();

Iterator<Page<Record>> results =
mappedTable.scan(
ScanEnhancedRequest.builder()
.attributesToProject("sort")
.select(Select.SPECIFIC_ATTRIBUTES)
.filterExpression(expression)
.build()
).iterator();

assertThat(results.hasNext(), is(true));
Page<Record> page = results.next();
assertThat(results.hasNext(), is(false));

assertThat(page.items(), hasSize(3));

Record record = page.items().get(0);

assertThat(record.id, is(nullValue()));
assertThat(record.sort, is(3));
}

@Test
public void scanAllRecordsWithSelect_All_Attr() {
insertRecords();
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":min_value", numberValue(3));
expressionValues.put(":max_value", numberValue(5));
Expression expression = Expression.builder()
.expression("#sort >= :min_value AND #sort <= :max_value")
.expressionValues(expressionValues)
.putExpressionName("#sort", "sort")
.build();

Iterator<Page<Record>> results =
mappedTable.scan(
ScanEnhancedRequest.builder()
.select(Select.ALL_ATTRIBUTES)
.filterExpression(expression)
.build()
).iterator();

assertThat(results.hasNext(), is(true));
Page<Record> page = results.next();
assertThat(results.hasNext(), is(false));

assertThat(page.items(), hasSize(3));

Record record = page.items().get(0);

assertThat(record.id, is("id-value"));
assertThat(record.sort, is(3));
}

@Test
public void scanAllRecordsWithSelect_Count() {
insertRecords();
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":min_value", numberValue(3));
expressionValues.put(":max_value", numberValue(5));
Expression expression = Expression.builder()
.expression("#sort >= :min_value AND #sort <= :max_value")
.expressionValues(expressionValues)
.putExpressionName("#sort", "sort")
.build();

Iterator<Page<Record>> results =
mappedTable.scan(
ScanEnhancedRequest.builder()
.select(Select.COUNT)
.filterExpression(expression)
.build()
).iterator();

assertThat(results.hasNext(), is(true));
Page<Record> page = results.next();
assertThat(results.hasNext(), is(false));

assertThat(page.count(), is(3));

assertThat(page.items().size(), is(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isEmptyString;
import static org.hamcrest.Matchers.nullValue;
import static software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider.defaultProvider;
import static software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.numberValue;
Expand Down Expand Up @@ -58,6 +59,7 @@
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.Select;

public class BasicScanTest extends LocalDynamoDbSyncTestBase {
private DynamoDbClient lowLevelClient;
Expand Down Expand Up @@ -668,4 +670,57 @@ public void scanAllRecordsWithNestedProjectionNameEmptyNameMap() {
Page<EnhancedDocument> next = resultsAttributeToProject.next();
});
}

@Test
public void scanAllRecordsDefaultSettings_select() {
insertDocuments();

Iterator<Page<EnhancedDocument>> results =
docMappedtable.scan(b -> b.select(Select.ALL_ATTRIBUTES)).iterator();

assertThat(results.hasNext(), is(true));
Page<EnhancedDocument> page = results.next();
assertThat(results.hasNext(), is(false));

assertThat(page.items().size(), is(DOCUMENTS.size()));

EnhancedDocument firstRecord = page.items().get(0);
assertThat(firstRecord.getString("id"), is("id-value"));
assertThat(firstRecord.getNumber("sort").intValue(), is(0));
assertThat(firstRecord.getNumber("value").intValue(), is(0));
}

@Test
public void scanAllRecordsDefaultSettings_select_specific_attr() {
insertDocuments();

Iterator<Page<EnhancedDocument>> results =
docMappedtable.scan(b -> b.attributesToProject("sort").select(Select.SPECIFIC_ATTRIBUTES)).iterator();

assertThat(results.hasNext(), is(true));
Page<EnhancedDocument> page = results.next();
assertThat(results.hasNext(), is(false));

assertThat(page.items().size(), is(DOCUMENTS.size()));

EnhancedDocument firstRecord = page.items().get(0);
assertThat(firstRecord.getString("id"), is(nullValue()));
assertThat(firstRecord.getNumber("sort").intValue(), is(0));
}


@Test
public void scanAllRecordsDefaultSettings_select_count() {
insertDocuments();

Iterator<Page<EnhancedDocument>> results =
docMappedtable.scan(b -> b.select(Select.COUNT)).iterator();

assertThat(results.hasNext(), is(true));
Page<EnhancedDocument> page = results.next();
assertThat(results.hasNext(), is(false));

assertThat(page.count(), is(DOCUMENTS.size()));
assertThat(page.items().size(), is(0));
}
}
Loading