|
27 | 27 | import org.springframework.data.cassandra.core.query.Update.AddToOp.Mode;
|
28 | 28 | import org.springframework.lang.Nullable;
|
29 | 29 | import org.springframework.util.Assert;
|
| 30 | +import org.springframework.util.ObjectUtils; |
30 | 31 | import org.springframework.util.StringUtils;
|
31 | 32 |
|
32 | 33 | import com.datastax.oss.driver.api.core.CqlIdentifier;
|
33 | 34 |
|
34 | 35 | /**
|
35 |
| - * Update object representing a set of update operations. {@link Update} objects can be created in a fluent |
36 |
| - * style. Each construction operation creates a new immutable {@link Update} object. |
| 36 | + * Update object representing a set of update operations. {@link Update} objects can be created in a fluent style. Each |
| 37 | + * construction operation creates a new immutable {@link Update} object. |
37 | 38 | *
|
38 | 39 | * <pre class="code">
|
39 | 40 | * Update update = Update.empty().set("foo", "bar").addTo("baz").prependAll(listOfValues);
|
@@ -68,7 +69,7 @@ public static Update of(Iterable<AssignmentOp> assignmentOps) {
|
68 | 69 |
|
69 | 70 | Assert.notNull(assignmentOps, "Update operations must not be null");
|
70 | 71 |
|
71 |
| - List<AssignmentOp> updateOperations = new ArrayList<>(); |
| 72 | + List<AssignmentOp> updateOperations = new ArrayList<>(assignmentOps instanceof Collection<?> c ? c.size() : 16); |
72 | 73 |
|
73 | 74 | assignmentOps.forEach(updateOperations::add);
|
74 | 75 |
|
@@ -220,50 +221,24 @@ public Collection<AssignmentOp> getUpdateOperations() {
|
220 | 221 |
|
221 | 222 | private Update add(AssignmentOp assignmentOp) {
|
222 | 223 |
|
223 |
| - List<AssignmentOp> list = new ArrayList<>(this.updateOperations.size() + 1); |
| 224 | + List<AssignmentOp> list = new ArrayList<>(this.updateOperations.size() + 1); |
224 | 225 |
|
225 |
| - for (AssignmentOp existing : this.updateOperations) { |
226 |
| - if (!conflicts(existing, assignmentOp)) { |
227 |
| - list.add(existing); |
228 |
| - } |
229 |
| - } |
230 |
| - |
231 |
| - list.add(assignmentOp); |
232 |
| - |
233 |
| - return new Update(list); |
234 |
| - } |
235 |
| - |
236 |
| - /** |
237 |
| - * Determine whether two assignment operations conflict and should not co-exist in a single {@link Update}. |
238 |
| - * Conflicts are defined as whole-column operations on the same column or element-level operations targeting |
239 |
| - * the same element (same map key or same list index) on the same column. In case of conflict, last-wins semantics |
240 |
| - * apply and the incoming operation replaces the existing one. |
241 |
| - */ |
242 |
| - private static boolean conflicts(AssignmentOp existing, AssignmentOp incoming) { |
243 |
| - |
244 |
| - if (!existing.getColumnName().equals(incoming.getColumnName())) { |
245 |
| - return false; |
246 |
| - } |
247 |
| - |
248 |
| - if (existing instanceof SetAtKeyOp e && incoming instanceof SetAtKeyOp i) { |
249 |
| - return equalsNullSafe(e.getKey(), i.getKey()); |
| 226 | + for (AssignmentOp existing : this.updateOperations) { |
| 227 | + if (!assignmentOp.overrides(existing)) { |
| 228 | + list.add(existing); |
| 229 | + } |
250 | 230 | }
|
251 | 231 |
|
252 |
| - if (existing instanceof SetAtIndexOp e && incoming instanceof SetAtIndexOp i) { |
253 |
| - return e.getIndex() == i.getIndex(); |
254 |
| - } |
| 232 | + list.add(assignmentOp); |
255 | 233 |
|
256 |
| - return true; |
| 234 | + return new Update(list); |
257 | 235 | }
|
258 | 236 |
|
259 |
| - private static boolean equalsNullSafe(@Nullable Object a, @Nullable Object b) { |
260 |
| - return a == b || (a != null && a.equals(b)); |
261 |
| - } |
262 | 237 |
|
263 | 238 | @Override
|
264 |
| - public String toString() { |
265 |
| - return StringUtils.collectionToDelimitedString(updateOperations, ", "); |
266 |
| - } |
| 239 | + public String toString() { |
| 240 | + return StringUtils.collectionToDelimitedString(updateOperations, ", "); |
| 241 | + } |
267 | 242 |
|
268 | 243 | /**
|
269 | 244 | * Builder to add a single element/multiple elements to a collection associated with a {@link ColumnName}.
|
@@ -574,6 +549,15 @@ public ColumnName getColumnName() {
|
574 | 549 | public CqlIdentifier toCqlIdentifier() {
|
575 | 550 | return this.columnName.getCqlIdentifier().orElseGet(() -> CqlIdentifier.fromCql(this.columnName.toCql()));
|
576 | 551 | }
|
| 552 | + |
| 553 | + /** |
| 554 | + * Determine whether the {@code other} assignment overrides this assignment. |
| 555 | + * |
| 556 | + * @since 4.5.3 |
| 557 | + */ |
| 558 | + boolean overrides(AssignmentOp other) { |
| 559 | + return ObjectUtils.nullSafeEquals(this.columnName, other.columnName); |
| 560 | + } |
577 | 561 | }
|
578 | 562 |
|
579 | 563 | /**
|
@@ -680,6 +664,20 @@ public int getIndex() {
|
680 | 664 | return index;
|
681 | 665 | }
|
682 | 666 |
|
| 667 | + @Override |
| 668 | + boolean overrides(AssignmentOp other) { |
| 669 | + |
| 670 | + if (super.overrides(other)) { |
| 671 | + if (other instanceof SetAtIndexOp i) { |
| 672 | + return getIndex() == i.getIndex(); |
| 673 | + } else { |
| 674 | + return true; |
| 675 | + } |
| 676 | + } |
| 677 | + |
| 678 | + return false; |
| 679 | + } |
| 680 | + |
683 | 681 | @Override
|
684 | 682 | public String toString() {
|
685 | 683 | return String.format("%s[%d] = %s", getColumnName(), index, serializeToCqlSafely(getValue()));
|
@@ -713,6 +711,20 @@ public Object getValue() {
|
713 | 711 | return value;
|
714 | 712 | }
|
715 | 713 |
|
| 714 | + @Override |
| 715 | + boolean overrides(AssignmentOp other) { |
| 716 | + |
| 717 | + if (super.overrides(other)) { |
| 718 | + if (other instanceof SetAtKeyOp i) { |
| 719 | + return ObjectUtils.nullSafeEquals(getKey(), i.getKey()); |
| 720 | + } else { |
| 721 | + return true; |
| 722 | + } |
| 723 | + } |
| 724 | + |
| 725 | + return false; |
| 726 | + } |
| 727 | + |
716 | 728 | @Override
|
717 | 729 | public String toString() {
|
718 | 730 | return String.format("%s[%s] = %s", getColumnName(), serializeToCqlSafely(key), serializeToCqlSafely(getValue()));
|
@@ -762,6 +774,11 @@ public Object getValue() {
|
762 | 774 | return value;
|
763 | 775 | }
|
764 | 776 |
|
| 777 | + @Override |
| 778 | + boolean overrides(AssignmentOp other) { |
| 779 | + return false; |
| 780 | + } |
| 781 | + |
765 | 782 | @Override
|
766 | 783 | public String toString() {
|
767 | 784 | return String.format("%s = %s - %s", getColumnName(), getColumnName(), serializeToCqlSafely(getValue()));
|
|
0 commit comments