Skip to content

Commit 82582f8

Browse files
committed
Merge PR #6725: Replace nested Stream.concat with direct iteration
2 parents 327cca3 + e40e293 commit 82582f8

File tree

2 files changed

+75
-31
lines changed

2 files changed

+75
-31
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "Amazon DynamoDB Enhanced Client",
4+
"contributor": "",
5+
"description": "Improved performance of UpdateExpression conversion by replacing Stream.concat chains and String.format with direct iteration and StringJoiner."
6+
}

services-custom/dynamodb-enhanced/src/main/java/software/amazon/awssdk/enhanced/dynamodb/internal/update/UpdateExpressionConverter.java

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
import java.util.ArrayList;
1919
import java.util.Collections;
20+
import java.util.HashMap;
2021
import java.util.List;
2122
import java.util.Map;
23+
import java.util.StringJoiner;
2224
import java.util.stream.Collectors;
2325
import java.util.stream.Stream;
2426
import software.amazon.awssdk.annotations.SdkInternalApi;
@@ -113,53 +115,89 @@ public static List<String> findAttributeNames(UpdateExpression updateExpression)
113115
private static List<String> groupExpressions(UpdateExpression expression) {
114116
List<String> groupExpressions = new ArrayList<>();
115117
if (!expression.setActions().isEmpty()) {
116-
groupExpressions.add(SET + expression.setActions().stream()
117-
.map(a -> String.format("%s = %s", a.path(), a.value()))
118-
.collect(Collectors.joining(ACTION_SEPARATOR)));
118+
StringJoiner joiner = new StringJoiner(ACTION_SEPARATOR, SET, "");
119+
expression.setActions().forEach(a -> joiner.add(a.path() + " = " + a.value()));
120+
groupExpressions.add(joiner.toString());
119121
}
120122
if (!expression.removeActions().isEmpty()) {
121-
groupExpressions.add(REMOVE + expression.removeActions().stream()
122-
.map(RemoveAction::path)
123-
.collect(Collectors.joining(ACTION_SEPARATOR)));
123+
StringJoiner joiner = new StringJoiner(ACTION_SEPARATOR, REMOVE, "");
124+
expression.removeActions().forEach(a -> joiner.add(a.path()));
125+
groupExpressions.add(joiner.toString());
124126
}
125127
if (!expression.deleteActions().isEmpty()) {
126-
groupExpressions.add(DELETE + expression.deleteActions().stream()
127-
.map(a -> String.format("%s %s", a.path(), a.value()))
128-
.collect(Collectors.joining(ACTION_SEPARATOR)));
128+
StringJoiner joiner = new StringJoiner(ACTION_SEPARATOR, DELETE, "");
129+
expression.deleteActions().forEach(a -> joiner.add(a.path() + " " + a.value()));
130+
groupExpressions.add(joiner.toString());
129131
}
130132
if (!expression.addActions().isEmpty()) {
131-
groupExpressions.add(ADD + expression.addActions().stream()
132-
.map(a -> String.format("%s %s", a.path(), a.value()))
133-
.collect(Collectors.joining(ACTION_SEPARATOR)));
133+
StringJoiner joiner = new StringJoiner(ACTION_SEPARATOR, ADD, "");
134+
expression.addActions().forEach(a -> joiner.add(a.path() + " " + a.value()));
135+
groupExpressions.add(joiner.toString());
134136
}
135137
return groupExpressions;
136138
}
137139

138-
private static Stream<Map<String, String>> streamOfExpressionNames(UpdateExpression expression) {
139-
return Stream.concat(expression.setActions().stream().map(SetAction::expressionNames),
140-
Stream.concat(expression.removeActions().stream().map(RemoveAction::expressionNames),
141-
Stream.concat(expression.deleteActions().stream()
142-
.map(DeleteAction::expressionNames),
143-
expression.addActions().stream()
144-
.map(AddAction::expressionNames))));
140+
private static Map<String, AttributeValue> mergeExpressionValues(UpdateExpression expression) {
141+
Map<String, AttributeValue> merged = new HashMap<>();
142+
143+
for (SetAction action : expression.setActions()) {
144+
mergeValuesInto(merged, action.expressionValues());
145+
}
146+
for (DeleteAction action : expression.deleteActions()) {
147+
mergeValuesInto(merged, action.expressionValues());
148+
}
149+
for (AddAction action : expression.addActions()) {
150+
mergeValuesInto(merged, action.expressionValues());
151+
}
152+
153+
return merged.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(merged);
145154
}
146155

147-
private static Map<String, AttributeValue> mergeExpressionValues(UpdateExpression expression) {
148-
return streamOfExpressionValues(expression)
149-
.reduce(Expression::joinValues)
150-
.orElseGet(Collections::emptyMap);
156+
private static Map<String, String> mergeExpressionNames(UpdateExpression expression) {
157+
Map<String, String> merged = new HashMap<>();
158+
159+
for (SetAction action : expression.setActions()) {
160+
mergeNamesInto(merged, action.expressionNames());
161+
}
162+
for (RemoveAction action : expression.removeActions()) {
163+
mergeNamesInto(merged, action.expressionNames());
164+
}
165+
for (DeleteAction action : expression.deleteActions()) {
166+
mergeNamesInto(merged, action.expressionNames());
167+
}
168+
for (AddAction action : expression.addActions()) {
169+
mergeNamesInto(merged, action.expressionNames());
170+
}
171+
172+
return merged.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(merged);
151173
}
152174

153-
private static Stream<Map<String, AttributeValue>> streamOfExpressionValues(UpdateExpression expression) {
154-
return Stream.concat(expression.setActions().stream().map(SetAction::expressionValues),
155-
Stream.concat(expression.deleteActions().stream().map(DeleteAction::expressionValues),
156-
expression.addActions().stream().map(AddAction::expressionValues)));
175+
private static void mergeNamesInto(Map<String, String> target, Map<String, String> source) {
176+
if (source == null || source.isEmpty()) {
177+
return;
178+
}
179+
source.forEach((key, value) -> {
180+
String oldValue = target.put(key, value);
181+
if (oldValue != null && !oldValue.equals(value)) {
182+
throw new IllegalArgumentException(
183+
String.format("Attempt to coalesce two expressions with conflicting expression names. "
184+
+ "Expression name key = '%s'", key));
185+
}
186+
});
157187
}
158188

159-
private static Map<String, String> mergeExpressionNames(UpdateExpression expression) {
160-
return streamOfExpressionNames(expression)
161-
.reduce(Expression::joinNames)
162-
.orElseGet(Collections::emptyMap);
189+
private static void mergeValuesInto(Map<String, AttributeValue> target, Map<String, AttributeValue> source) {
190+
if (source == null || source.isEmpty()) {
191+
return;
192+
}
193+
source.forEach((key, value) -> {
194+
AttributeValue oldValue = target.put(key, value);
195+
if (oldValue != null && !oldValue.equals(value)) {
196+
throw new IllegalArgumentException(
197+
String.format("Attempt to coalesce two expressions with conflicting expression values. "
198+
+ "Expression value key = '%s'", key));
199+
}
200+
});
163201
}
164202

165203
private static List<String> listPathsWithoutTokens(UpdateExpression expression) {

0 commit comments

Comments
 (0)