|
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