This is an automated email from the ASF dual-hosted git repository.
kturner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push:
new 9c3497bfdc Constructed API methods for creating Mutations from
key/value pairs (#5702)
9c3497bfdc is described below
commit 9c3497bfdc620308a89594c164ca2563b7483a72
Author: Imirie Billey <[email protected]>
AuthorDate: Thu Jul 17 12:33:42 2025 -0400
Constructed API methods for creating Mutations from key/value pairs (#5702)
Closes #1056
---
.../org/apache/accumulo/core/data/Mutation.java | 22 +++++
.../apache/accumulo/core/data/MutationTest.java | 107 +++++++++++++++++++++
2 files changed, 129 insertions(+)
diff --git a/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
b/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
index b8c6c22feb..9be3143480 100644
--- a/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
+++ b/core/src/main/java/org/apache/accumulo/core/data/Mutation.java
@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import org.apache.accumulo.core.dataImpl.thrift.TMutation;
import org.apache.accumulo.core.security.ColumnVisibility;
@@ -777,6 +778,16 @@ public class Mutation implements Writable {
QualifierOptions family(CharSequence colFam);
QualifierOptions family(Text colFam);
+
+ /**
+ * Sets the column family, column qualifier, and column visibility of a
mutation. All other
+ * fields in the key are ignored.
+ *
+ * @param key key
+ * @return a TimestampOptions object, advancing the method chain
+ * @since 4.0.0
+ */
+ TimestampOptions keyColumns(Key key);
}
/**
@@ -962,6 +973,17 @@ public class Mutation implements Writable {
return family(colFam.getBytes(), colFam.getLength());
}
+ @Override
+ public TimestampOptions keyColumns(Key key) {
+ Objects.requireNonNull(key, "key cannot be null");
+
+ byte[] colFam = key.getColumnFamilyData().toArray();
+ byte[] colQual = key.getColumnQualifierData().toArray();
+ byte[] colVis = key.getColumnVisibilityData().toArray();
+
+ return this.family(colFam).qualifier(colQual).visibility(colVis);
+ }
+
/**
* Sets the column qualifier of a mutation.
*
diff --git a/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
b/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
index fd2363d3d4..2d7289a20a 100644
--- a/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/data/MutationTest.java
@@ -948,4 +948,111 @@ public class MutationTest {
assertEquals(expected, m.prettyPrint());
}
+
+ /**
+ * Test that the mutation is correctly updated to be added when a valid Key
is passed through
+ * {@link Mutation.FamilyOptions#keyColumns(Key)}, and a valid Value is
passed through
+ * {@link Mutation.TimestampOptions#put(Value)}.
+ */
+ @Test
+ public void testAddingKeyColumns() {
+ Mutation m = new Mutation(new Text("r1"));
+ Key k = new Key(nt("r1"), nt("cf1"), nt("cq1"), new
ColumnVisibility("cv1"), 1L);
+ m.at().keyColumns(k).timestamp(k.getTimestamp()).put(nv("v1"));
+
+ Key k2 = new Key(nt("r1"), nt("cf2"), nt("cq2"), new
ColumnVisibility("cv2"), 2L);
+ m.at().keyColumns(k2).put(nv("v2"));
+
+ assertEquals(2, m.size());
+
+ List<ColumnUpdate> updates = m.getUpdates();
+
+ assertEquals(2, m.size());
+ assertEquals(2, updates.size());
+
+ verifyColumnUpdate(updates.get(0), "cf1", "cq1", "cv1", 1L, true, false,
"v1");
+ verifyColumnUpdate(updates.get(1), "cf2", "cq2", "cv2", 2L, false, false,
"v2");
+ }
+
+ /**
+ * Test that the mutation is correctly updated to be deleted when a valid
Key is passed through
+ * {@link Mutation.TimestampOptions#delete()}.
+ */
+ @Test
+ public void testDeletingKeyColumns() {
+ Mutation m = new Mutation(new Text("r1"));
+ Key k = new Key(nt("r1"), nt("cf1"), nt("cq1"), new
ColumnVisibility("cv1"), 1L);
+ m.at().keyColumns(k).timestamp(k.getTimestamp()).put(nv("v1"));
+ m.at().keyColumns(k).delete();
+
+ Key k2 = new Key(nt("r1"), nt("cf2"), nt("cq2"), new
ColumnVisibility("cv2"), 2L);
+ m.at().keyColumns(k2).delete();
+
+ assertEquals(3, m.size());
+
+ List<ColumnUpdate> updates = m.getUpdates();
+
+ assertEquals(3, m.size());
+ assertEquals(3, updates.size());
+
+ verifyColumnUpdate(updates.get(0), "cf1", "cq1", "cv1", 1L, true, false,
"v1");
+ verifyColumnUpdate(updates.get(1), "cf1", "cq1", "cv1", 1L, false, true,
"");
+ verifyColumnUpdate(updates.get(2), "cf2", "cq2", "cv2", 2L, false, true,
"");
+ }
+
+ /**
+ * Test that mutations are correctly added back through after being
previously deleted.
+ */
+ @Test
+ public void testAddingDeletedKeyColumnsBack() {
+ Mutation m = new Mutation(new Text("r1"));
+ Key k = new Key(nt("r1"), nt("cf1"), nt("cq1"), new
ColumnVisibility("cv1"), 1L);
+ m.at().keyColumns(k).timestamp(k.getTimestamp()).put(nv("v1"));
+ m.at().keyColumns(k).delete();
+ m.at().keyColumns(k).timestamp(k.getTimestamp()).put(nv("v1"));
+
+ Key k2 = new Key(nt("r1"), nt("cf2"), nt("cq2"), new
ColumnVisibility("cv2"), 2L);
+ m.at().keyColumns(k2).delete();
+ m.at().keyColumns(k2).put(nv("v1"));
+
+ assertEquals(5, m.size());
+
+ List<ColumnUpdate> updates = m.getUpdates();
+
+ assertEquals(5, m.size());
+ assertEquals(5, updates.size());
+
+ verifyColumnUpdate(updates.get(0), "cf1", "cq1", "cv1", 1L, true, false,
"v1");
+ verifyColumnUpdate(updates.get(1), "cf1", "cq1", "cv1", 1L, false, true,
"");
+ verifyColumnUpdate(updates.get(2), "cf1", "cq1", "cv1", 1L, true, false,
"v1");
+ verifyColumnUpdate(updates.get(3), "cf2", "cq2", "cv2", 2L, false, true,
"");
+ verifyColumnUpdate(updates.get(4), "cf2", "cq2", "cv2", 2L, false, false,
"v1");
+ }
+
+ /**
+ * Test that a NullPointerException is thrown when passing a null Key through
+ * {@link Mutation.FamilyOptions#keyColumns(Key)}.
+ */
+ @Test
+ public void testKeyColumnsAddingNullKey() {
+ Mutation m = new Mutation(new Text("r1"));
+ Key k = null;
+ Value v = nv("v1");
+
+ assertThrows(NullPointerException.class, () ->
m.at().keyColumns(k).put(v));
+ }
+
+ /**
+ * Test that a NullPointerException is thrown when passing a null Value
through
+ * {@link Mutation.TimestampOptions#put(Value)}.
+ */
+ @Test
+ public void testKeyColumnsAddingNullValue() {
+ Mutation m = new Mutation(new Text("r1"));
+ Key k = new Key(nt("r1"), nt("cf1"), nt("cq1"), new
ColumnVisibility("cv1"), 1L);
+ Value v = null;
+
+ assertThrows(NullPointerException.class, () ->
m.at().keyColumns(k).put(v));
+ }
+
}