Skip to content

Commit 3f954e4

Browse files
authored
Adding support for Select in ScanEnhancedRequest (#5519)
1 parent 71e129f commit 3f954e4

File tree

5 files changed

+199
-0
lines changed

5 files changed

+199
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "DynamoDB Enhanced Client",
3+
"contributor": "shetsa-amzn",
4+
"type": "feature",
5+
"description": "Adding support for Select in ScanEnhancedRequest"
6+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/operations/ScanOperation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public ScanRequest generateRequest(TableSchema<T> tableSchema,
8282
.exclusiveStartKey(this.request.exclusiveStartKey())
8383
.consistentRead(this.request.consistentRead())
8484
.returnConsumedCapacity(this.request.returnConsumedCapacity())
85+
.select(this.request.select())
8586
.expressionAttributeValues(expressionValues)
8687
.expressionAttributeNames(expressionNames)
8788
.projectionExpression(projectionExpressionAsString);

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/model/ScanEnhancedRequest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
3333
import software.amazon.awssdk.services.dynamodb.model.ReturnConsumedCapacity;
3434
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
35+
import software.amazon.awssdk.services.dynamodb.model.Select;
3536
import software.amazon.awssdk.utils.Validate;
3637

3738
/**
@@ -48,6 +49,7 @@ public final class ScanEnhancedRequest {
4849
private final Integer limit;
4950
private final Boolean consistentRead;
5051
private final Expression filterExpression;
52+
private final Select select;
5153
private final List<NestedAttributeName> attributesToProject;
5254
private final Integer segment;
5355
private final Integer totalSegments;
@@ -60,6 +62,7 @@ private ScanEnhancedRequest(Builder builder) {
6062
this.totalSegments = builder.totalSegments;
6163
this.consistentRead = builder.consistentRead;
6264
this.filterExpression = builder.filterExpression;
65+
this.select = builder.select;
6366
this.returnConsumedCapacity = builder.returnConsumedCapacity;
6467
this.attributesToProject = builder.attributesToProject != null
6568
? Collections.unmodifiableList(builder.attributesToProject)
@@ -83,6 +86,7 @@ public Builder toBuilder() {
8386
.totalSegments(totalSegments)
8487
.consistentRead(consistentRead)
8588
.filterExpression(filterExpression)
89+
.select(select)
8690
.returnConsumedCapacity(returnConsumedCapacity)
8791
.addNestedAttributesToProject(attributesToProject);
8892
}
@@ -129,6 +133,24 @@ public Expression filterExpression() {
129133
return filterExpression;
130134
}
131135

136+
/**
137+
* Returns the value of select, or null if it doesn't exist.
138+
* @return
139+
*/
140+
public Select select() {
141+
return select;
142+
}
143+
144+
/**
145+
* Returns the value of select as a string, or null if it doesn't exist.
146+
* @return
147+
*/
148+
public String selectAsString() {
149+
return String.valueOf(select);
150+
}
151+
152+
/**
153+
132154
/**
133155
* Returns the list of projected attributes on this request object, or an null if no projection is specified.
134156
* Nested attributes are represented using the '.' separator. Example : foo.bar is represented as "foo.bar" which is
@@ -204,6 +226,11 @@ public boolean equals(Object o) {
204226
? !returnConsumedCapacity.equals(scan.returnConsumedCapacity) : scan.returnConsumedCapacity != null) {
205227
return false;
206228
}
229+
230+
if (select != null ? ! select.equals(scan.select) : scan.select != null) {
231+
return false;
232+
}
233+
207234
return filterExpression != null ? filterExpression.equals(scan.filterExpression) : scan.filterExpression == null;
208235
}
209236

@@ -215,6 +242,7 @@ public int hashCode() {
215242
result = 31 * result + (totalSegments != null ? totalSegments.hashCode() : 0);
216243
result = 31 * result + (consistentRead != null ? consistentRead.hashCode() : 0);
217244
result = 31 * result + (filterExpression != null ? filterExpression.hashCode() : 0);
245+
result = 31 * result + (select != null ? select.hashCode() : 0);
218246
result = 31 * result + (attributesToProject != null ? attributesToProject.hashCode() : 0);
219247
result = 31 * result + (returnConsumedCapacity != null ? returnConsumedCapacity.hashCode() : 0);
220248
return result;
@@ -229,6 +257,7 @@ public static final class Builder {
229257
private Integer limit;
230258
private Boolean consistentRead;
231259
private Expression filterExpression;
260+
private Select select;
232261
private List<NestedAttributeName> attributesToProject;
233262
private Integer segment;
234263
private Integer totalSegments;
@@ -335,6 +364,18 @@ public Builder filterExpression(Expression filterExpression) {
335364
return this;
336365
}
337366

367+
/**
368+
* Determines the attributes to be returned in the result. See {@link Select} for examples and constraints.
369+
* By default, all attributes are returned.
370+
* @param select
371+
* @return a builder of this type
372+
*/
373+
public Builder select(Select select) {
374+
this.select = select;
375+
return this;
376+
}
377+
378+
338379
/**
339380
* <p>
340381
* Sets a collection of the attribute names to be retrieved from the database. These attributes can include

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/BasicScanTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,15 @@
4545
import software.amazon.awssdk.enhanced.dynamodb.Expression;
4646
import software.amazon.awssdk.enhanced.dynamodb.NestedAttributeName;
4747
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
48+
import software.amazon.awssdk.enhanced.dynamodb.document.EnhancedDocument;
4849
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.InnerAttributeRecord;
4950
import software.amazon.awssdk.enhanced.dynamodb.functionaltests.models.NestedTestRecord;
5051
import software.amazon.awssdk.enhanced.dynamodb.mapper.StaticTableSchema;
5152
import software.amazon.awssdk.enhanced.dynamodb.model.Page;
5253
import software.amazon.awssdk.enhanced.dynamodb.model.ScanEnhancedRequest;
5354
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
5455
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
56+
import software.amazon.awssdk.services.dynamodb.model.Select;
5557

5658
public class BasicScanTest extends LocalDynamoDbSyncTestBase {
5759
private static class Record {
@@ -645,4 +647,98 @@ public void scanAllRecordsWithNestedProjectionNameEmptyNameMap() {
645647
Page<NestedTestRecord> next = resultsAttributeToProject.next();
646648
});
647649
}
650+
651+
@Test
652+
public void scanAllRecordsWithSelect_specific_attr() {
653+
insertRecords();
654+
Map<String, AttributeValue> expressionValues = new HashMap<>();
655+
expressionValues.put(":min_value", numberValue(3));
656+
expressionValues.put(":max_value", numberValue(5));
657+
Expression expression = Expression.builder()
658+
.expression("#sort >= :min_value AND #sort <= :max_value")
659+
.expressionValues(expressionValues)
660+
.putExpressionName("#sort", "sort")
661+
.build();
662+
663+
Iterator<Page<Record>> results =
664+
mappedTable.scan(
665+
ScanEnhancedRequest.builder()
666+
.attributesToProject("sort")
667+
.select(Select.SPECIFIC_ATTRIBUTES)
668+
.filterExpression(expression)
669+
.build()
670+
).iterator();
671+
672+
assertThat(results.hasNext(), is(true));
673+
Page<Record> page = results.next();
674+
assertThat(results.hasNext(), is(false));
675+
676+
assertThat(page.items(), hasSize(3));
677+
678+
Record record = page.items().get(0);
679+
680+
assertThat(record.id, is(nullValue()));
681+
assertThat(record.sort, is(3));
682+
}
683+
684+
@Test
685+
public void scanAllRecordsWithSelect_All_Attr() {
686+
insertRecords();
687+
Map<String, AttributeValue> expressionValues = new HashMap<>();
688+
expressionValues.put(":min_value", numberValue(3));
689+
expressionValues.put(":max_value", numberValue(5));
690+
Expression expression = Expression.builder()
691+
.expression("#sort >= :min_value AND #sort <= :max_value")
692+
.expressionValues(expressionValues)
693+
.putExpressionName("#sort", "sort")
694+
.build();
695+
696+
Iterator<Page<Record>> results =
697+
mappedTable.scan(
698+
ScanEnhancedRequest.builder()
699+
.select(Select.ALL_ATTRIBUTES)
700+
.filterExpression(expression)
701+
.build()
702+
).iterator();
703+
704+
assertThat(results.hasNext(), is(true));
705+
Page<Record> page = results.next();
706+
assertThat(results.hasNext(), is(false));
707+
708+
assertThat(page.items(), hasSize(3));
709+
710+
Record record = page.items().get(0);
711+
712+
assertThat(record.id, is("id-value"));
713+
assertThat(record.sort, is(3));
714+
}
715+
716+
@Test
717+
public void scanAllRecordsWithSelect_Count() {
718+
insertRecords();
719+
Map<String, AttributeValue> expressionValues = new HashMap<>();
720+
expressionValues.put(":min_value", numberValue(3));
721+
expressionValues.put(":max_value", numberValue(5));
722+
Expression expression = Expression.builder()
723+
.expression("#sort >= :min_value AND #sort <= :max_value")
724+
.expressionValues(expressionValues)
725+
.putExpressionName("#sort", "sort")
726+
.build();
727+
728+
Iterator<Page<Record>> results =
729+
mappedTable.scan(
730+
ScanEnhancedRequest.builder()
731+
.select(Select.COUNT)
732+
.filterExpression(expression)
733+
.build()
734+
).iterator();
735+
736+
assertThat(results.hasNext(), is(true));
737+
Page<Record> page = results.next();
738+
assertThat(results.hasNext(), is(false));
739+
740+
assertThat(page.count(), is(3));
741+
742+
assertThat(page.items().size(), is(0));
743+
}
648744
}

services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/functionaltests/document/BasicScanTest.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static org.hamcrest.Matchers.empty;
2121
import static org.hamcrest.Matchers.hasSize;
2222
import static org.hamcrest.Matchers.is;
23+
import static org.hamcrest.Matchers.isEmptyString;
2324
import static org.hamcrest.Matchers.nullValue;
2425
import static software.amazon.awssdk.enhanced.dynamodb.AttributeConverterProvider.defaultProvider;
2526
import static software.amazon.awssdk.enhanced.dynamodb.internal.AttributeValues.numberValue;
@@ -58,6 +59,7 @@
5859
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
5960
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
6061
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
62+
import software.amazon.awssdk.services.dynamodb.model.Select;
6163

6264
public class BasicScanTest extends LocalDynamoDbSyncTestBase {
6365
private DynamoDbClient lowLevelClient;
@@ -668,4 +670,57 @@ public void scanAllRecordsWithNestedProjectionNameEmptyNameMap() {
668670
Page<EnhancedDocument> next = resultsAttributeToProject.next();
669671
});
670672
}
673+
674+
@Test
675+
public void scanAllRecordsDefaultSettings_select() {
676+
insertDocuments();
677+
678+
Iterator<Page<EnhancedDocument>> results =
679+
docMappedtable.scan(b -> b.select(Select.ALL_ATTRIBUTES)).iterator();
680+
681+
assertThat(results.hasNext(), is(true));
682+
Page<EnhancedDocument> page = results.next();
683+
assertThat(results.hasNext(), is(false));
684+
685+
assertThat(page.items().size(), is(DOCUMENTS.size()));
686+
687+
EnhancedDocument firstRecord = page.items().get(0);
688+
assertThat(firstRecord.getString("id"), is("id-value"));
689+
assertThat(firstRecord.getNumber("sort").intValue(), is(0));
690+
assertThat(firstRecord.getNumber("value").intValue(), is(0));
691+
}
692+
693+
@Test
694+
public void scanAllRecordsDefaultSettings_select_specific_attr() {
695+
insertDocuments();
696+
697+
Iterator<Page<EnhancedDocument>> results =
698+
docMappedtable.scan(b -> b.attributesToProject("sort").select(Select.SPECIFIC_ATTRIBUTES)).iterator();
699+
700+
assertThat(results.hasNext(), is(true));
701+
Page<EnhancedDocument> page = results.next();
702+
assertThat(results.hasNext(), is(false));
703+
704+
assertThat(page.items().size(), is(DOCUMENTS.size()));
705+
706+
EnhancedDocument firstRecord = page.items().get(0);
707+
assertThat(firstRecord.getString("id"), is(nullValue()));
708+
assertThat(firstRecord.getNumber("sort").intValue(), is(0));
709+
}
710+
711+
712+
@Test
713+
public void scanAllRecordsDefaultSettings_select_count() {
714+
insertDocuments();
715+
716+
Iterator<Page<EnhancedDocument>> results =
717+
docMappedtable.scan(b -> b.select(Select.COUNT)).iterator();
718+
719+
assertThat(results.hasNext(), is(true));
720+
Page<EnhancedDocument> page = results.next();
721+
assertThat(results.hasNext(), is(false));
722+
723+
assertThat(page.count(), is(DOCUMENTS.size()));
724+
assertThat(page.items().size(), is(0));
725+
}
671726
}

0 commit comments

Comments
 (0)