Skip to content

Commit 191d15c

Browse files
feat: Add support for MergeToCell API (#2258)
* feat: Add support for MergeToCell API * feat: Add support for MergeToCell API * fix build * fix build * fix format * fix build * fix build * fix build * fix format * fix test * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * Update WriteAggregate.java * Update WriteAggregate.java * Update WriteAggregate.java * Update WriteAggregate.java --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent e37ec06 commit 191d15c

File tree

13 files changed

+262
-4
lines changed

13 files changed

+262
-4
lines changed

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/ChangeStreamMutation.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ Builder addToCell(@Nonnull String familyName, Value qualifier, Value timestamp,
182182
return this;
183183
}
184184

185+
Builder mergeToCell(@Nonnull String familyName, Value qualifier, Value timestamp, Value input) {
186+
this.entriesBuilder().add(MergeToCell.create(familyName, qualifier, timestamp, input));
187+
return this;
188+
}
189+
185190
abstract ChangeStreamMutation build();
186191
}
187192

@@ -210,6 +215,13 @@ public RowMutation toRowMutation(@Nonnull String tableId) {
210215
addToCell.getQualifier(),
211216
addToCell.getTimestamp(),
212217
addToCell.getInput());
218+
} else if (entry instanceof MergeToCell) {
219+
MergeToCell mergeToCell = (MergeToCell) entry;
220+
rowMutation.mergeToCell(
221+
mergeToCell.getFamily(),
222+
mergeToCell.getQualifier(),
223+
mergeToCell.getTimestamp(),
224+
mergeToCell.getInput());
213225
} else {
214226
throw new IllegalArgumentException("Unexpected Entry type.");
215227
}
@@ -242,6 +254,13 @@ public RowMutationEntry toRowMutationEntry() {
242254
addToCell.getQualifier(),
243255
addToCell.getTimestamp(),
244256
addToCell.getInput());
257+
} else if (entry instanceof MergeToCell) {
258+
MergeToCell mergeToCell = (MergeToCell) entry;
259+
rowMutationEntry.mergeToCell(
260+
mergeToCell.getFamily(),
261+
mergeToCell.getQualifier(),
262+
mergeToCell.getTimestamp(),
263+
mergeToCell.getInput());
245264
} else {
246265
throw new IllegalArgumentException("Unexpected Entry type.");
247266
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/ChangeStreamRecordAdapter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ void addToCell(
141141
@Nonnull Value timestamp,
142142
@Nonnull Value value);
143143

144+
void mergeToCell(
145+
@Nonnull String familyName,
146+
@Nonnull Value qualifier,
147+
@Nonnull Value timestamp,
148+
@Nonnull Value value);
149+
144150
/**
145151
* Called to start a SetCell.
146152
*

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/DefaultChangeStreamRecordAdapter.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ public void addToCell(
142142
this.changeStreamMutationBuilder.addToCell(familyName, qualifier, timestamp, input);
143143
}
144144

145+
@Override
146+
public void mergeToCell(
147+
@Nonnull String familyName,
148+
@Nonnull Value qualifier,
149+
@Nonnull Value timestamp,
150+
@Nonnull Value input) {
151+
this.changeStreamMutationBuilder.mergeToCell(familyName, qualifier, timestamp, input);
152+
}
153+
145154
/** {@inheritDoc} */
146155
@Override
147156
public void startCell(String family, ByteString qualifier, long timestampMicros) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.cloud.bigtable.data.v2.models;
17+
18+
import com.google.api.core.InternalApi;
19+
import com.google.auto.value.AutoValue;
20+
import java.io.Serializable;
21+
import javax.annotation.Nonnull;
22+
23+
/** Representation of an MergeToCell mod in a data change. */
24+
@InternalApi("Intended for use by the BigtableIO in apache/beam only.")
25+
@AutoValue
26+
public abstract class MergeToCell implements Entry, Serializable {
27+
public static MergeToCell create(
28+
@Nonnull String family,
29+
@Nonnull Value qualifier,
30+
@Nonnull Value timestamp,
31+
@Nonnull Value input) {
32+
return new AutoValue_MergeToCell(family, qualifier, timestamp, input);
33+
}
34+
35+
@Nonnull
36+
public abstract String getFamily();
37+
38+
@Nonnull
39+
public abstract Value getQualifier();
40+
41+
@Nonnull
42+
public abstract Value getTimestamp();
43+
44+
@Nonnull
45+
public abstract Value getInput();
46+
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/Mutation.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.bigtable.v2.Mutation.DeleteFromColumn;
2222
import com.google.bigtable.v2.Mutation.DeleteFromFamily;
2323
import com.google.bigtable.v2.Mutation.DeleteFromRow;
24+
import com.google.bigtable.v2.Mutation.MergeToCell;
2425
import com.google.bigtable.v2.Mutation.SetCell;
2526
import com.google.cloud.bigtable.data.v2.models.Range.TimestampRange;
2627
import com.google.common.base.Preconditions;
@@ -308,6 +309,24 @@ public Mutation addToCell(
308309
return this;
309310
}
310311

312+
@Override
313+
public Mutation mergeToCell(
314+
@Nonnull String familyName,
315+
@Nonnull Value qualifier,
316+
@Nonnull Value timestamp,
317+
@Nonnull Value value) {
318+
com.google.bigtable.v2.Mutation.Builder builder = com.google.bigtable.v2.Mutation.newBuilder();
319+
MergeToCell.Builder mergeToCellBuilder = builder.getMergeToCellBuilder();
320+
mergeToCellBuilder.setFamilyName(familyName);
321+
322+
qualifier.buildTo(mergeToCellBuilder.getColumnQualifierBuilder());
323+
timestamp.buildTo(mergeToCellBuilder.getTimestampBuilder());
324+
value.buildTo(mergeToCellBuilder.getInputBuilder());
325+
326+
addMutation(builder.build());
327+
return this;
328+
}
329+
311330
private void addMutation(com.google.bigtable.v2.Mutation mutation) {
312331
Preconditions.checkState(numMutations + 1 <= MAX_MUTATIONS, "Too many mutations per row");
313332
Preconditions.checkState(

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/MutationApi.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ default T addToCell(
138138
return addToCell(familyName, ByteString.copyFromUtf8(qualifier), timestamp, value);
139139
}
140140

141+
/**
142+
* Merges a ByteString accumulator value to a cell in an aggregate column family.
143+
*
144+
* <p>This is a convenience override that converts Strings to ByteStrings.
145+
*
146+
* <p>Note: The timestamp values are in microseconds but must match the granularity of the
147+
* table(defaults to `MILLIS`). Therefore, the given value must be a multiple of 1000 (millisecond
148+
* granularity). For example: `1571902339435000`.
149+
*/
150+
default T mergeToCell(
151+
@Nonnull String familyName, @Nonnull String qualifier, long timestamp, ByteString value) {
152+
return mergeToCell(familyName, ByteString.copyFromUtf8(qualifier), timestamp, value);
153+
}
154+
141155
/**
142156
* Adds an int64 value to an aggregate cell. The column family must be an aggregate family and
143157
* have an "int64" input type or this mutation will be rejected.
@@ -155,6 +169,22 @@ default T addToCell(
155169
Value.IntValue.create(input));
156170
}
157171

172+
/**
173+
* Merges a ByteString accumulator value to a cell in an aggregate column family.
174+
*
175+
* <p>Note: The timestamp values are in microseconds but must match the granularity of the
176+
* table(defaults to `MILLIS`). Therefore, the given value must be a multiple of 1000 (millisecond
177+
* granularity). For example: `1571902339435000`.
178+
*/
179+
default T mergeToCell(
180+
@Nonnull String familyName, @Nonnull ByteString qualifier, long timestamp, ByteString input) {
181+
return mergeToCell(
182+
familyName,
183+
Value.RawValue.create(qualifier),
184+
Value.RawTimestamp.create(timestamp),
185+
Value.RawValue.create(input));
186+
}
187+
158188
/**
159189
* Adds a {@link Value} to an aggregate cell. The column family must be an aggregate family and
160190
* have an input type matching the type of {@link Value} or this mutation will be rejected.
@@ -168,4 +198,18 @@ T addToCell(
168198
@Nonnull Value qualifier,
169199
@Nonnull Value timestamp,
170200
@Nonnull Value input);
201+
202+
/**
203+
* Merges a {@link Value} accumulator to an aggregate cell. The column family must be an aggregate
204+
* family or this mutation will be rejected.
205+
*
206+
* <p>Note: The timestamp values are in microseconds but must match the granularity of the
207+
* table(defaults to `MILLIS`). Therefore, the given value must be a multiple of 1000 (millisecond
208+
* granularity). For example: `1571902339435000`.
209+
*/
210+
T mergeToCell(
211+
@Nonnull String familyName,
212+
@Nonnull Value qualifier,
213+
@Nonnull Value timestamp,
214+
@Nonnull Value input);
171215
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/RowMutation.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,16 @@ public RowMutation addToCell(
237237
return this;
238238
}
239239

240+
@Override
241+
public RowMutation mergeToCell(
242+
@Nonnull String familyName,
243+
@Nonnull Value qualifier,
244+
@Nonnull Value timestamp,
245+
@Nonnull Value input) {
246+
mutation.mergeToCell(familyName, qualifier, timestamp, input);
247+
return this;
248+
}
249+
240250
@InternalApi
241251
public MutateRowRequest toProto(RequestContext requestContext) {
242252
MutateRowRequest.Builder builder = MutateRowRequest.newBuilder();

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/RowMutationEntry.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ public RowMutationEntry addToCell(
190190
return this;
191191
}
192192

193+
@Override
194+
public RowMutationEntry mergeToCell(
195+
@Nonnull String familyName,
196+
@Nonnull Value qualifier,
197+
@Nonnull Value timestamp,
198+
@Nonnull Value input) {
199+
mutation.mergeToCell(familyName, qualifier, timestamp, input);
200+
return this;
201+
}
202+
193203
@InternalApi
194204
public MutateRowsRequest.Entry toProto() {
195205
Preconditions.checkArgument(

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/changestream/ChangeStreamStateMachine.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,16 @@ State handleDataChange(ReadChangeStreamResponse.DataChange dataChange) {
485485
Value.fromProto(mod.getAddToCell().getColumnQualifier()),
486486
Value.fromProto(mod.getAddToCell().getTimestamp()),
487487
Value.fromProto(mod.getAddToCell().getInput()));
488+
continue;
489+
}
490+
// Case 5: MergeToCell
491+
if (mod.hasMergeToCell()) {
492+
builder.mergeToCell(
493+
mod.getMergeToCell().getFamilyName(),
494+
Value.fromProto(mod.getMergeToCell().getColumnQualifier()),
495+
Value.fromProto(mod.getMergeToCell().getTimestamp()),
496+
Value.fromProto(mod.getMergeToCell().getInput()));
497+
continue;
488498
}
489499
throw new IllegalStateException(
490500
"Received unknown mod type. You may need to upgrade your Bigtable client.");

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/ChangeStreamMutationTest.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public void userInitiatedMutationTest() throws IOException, ClassNotFoundExcepti
6767
Value.rawValue(ByteString.copyFromUtf8("col1")),
6868
Value.rawTimestamp(1000),
6969
Value.intValue(1234))
70+
.mergeToCell(
71+
"agg-family",
72+
Value.rawValue(ByteString.copyFromUtf8("col2")),
73+
Value.rawTimestamp(1000),
74+
Value.rawValue(ByteString.copyFrom(Longs.toByteArray(1234L))))
7075
.setToken("fake-token")
7176
.setEstimatedLowWatermark(FAKE_LOW_WATERMARK)
7277
.build();
@@ -150,6 +155,11 @@ public void toRowMutationTest() {
150155
Value.rawValue(ByteString.copyFromUtf8("qual1")),
151156
Value.rawTimestamp(1000),
152157
Value.intValue(1234))
158+
.mergeToCell(
159+
"agg-family",
160+
Value.rawValue(ByteString.copyFromUtf8("qual2")),
161+
Value.rawTimestamp(1000),
162+
Value.rawValue(ByteString.copyFrom(Longs.toByteArray(1234L))))
153163
.setToken("fake-token")
154164
.setEstimatedLowWatermark(FAKE_LOW_WATERMARK)
155165
.build();
@@ -161,7 +171,7 @@ public void toRowMutationTest() {
161171
NameUtil.formatTableName(
162172
REQUEST_CONTEXT.getProjectId(), REQUEST_CONTEXT.getInstanceId(), TABLE_ID);
163173
assertThat(mutateRowRequest.getTableName()).isEqualTo(tableName);
164-
assertThat(mutateRowRequest.getMutationsList()).hasSize(4);
174+
assertThat(mutateRowRequest.getMutationsList()).hasSize(5);
165175
assertThat(mutateRowRequest.getMutations(0).getSetCell().getValue())
166176
.isEqualTo(ByteString.copyFromUtf8("fake-value"));
167177
assertThat(mutateRowRequest.getMutations(1).getDeleteFromFamily().getFamilyName())
@@ -178,6 +188,14 @@ public void toRowMutationTest() {
178188
.setTimestamp(Value.rawTimestamp(1000).toProto())
179189
.setInput(Value.intValue(1234).toProto())
180190
.build());
191+
assertThat(mutateRowRequest.getMutations(4).getMergeToCell())
192+
.isEqualTo(
193+
Mutation.MergeToCell.newBuilder()
194+
.setFamilyName("agg-family")
195+
.setColumnQualifier(Value.rawValue(ByteString.copyFromUtf8("qual2")).toProto())
196+
.setTimestamp(Value.rawTimestamp(1000).toProto())
197+
.setInput(Value.rawValue(ByteString.copyFrom(Longs.toByteArray(1234L))).toProto())
198+
.build());
181199
}
182200

183201
@Test
@@ -220,6 +238,11 @@ public void toRowMutationEntryTest() {
220238
Value.rawValue(ByteString.copyFromUtf8("qual1")),
221239
Value.rawTimestamp(1000),
222240
Value.intValue(1234))
241+
.mergeToCell(
242+
"agg-family",
243+
Value.rawValue(ByteString.copyFromUtf8("qual2")),
244+
Value.rawTimestamp(1000),
245+
Value.rawValue(ByteString.copyFrom(Longs.toByteArray(1234L))))
223246
.setToken("fake-token")
224247
.setEstimatedLowWatermark(FAKE_LOW_WATERMARK)
225248
.build();
@@ -228,7 +251,7 @@ public void toRowMutationEntryTest() {
228251
RowMutationEntry rowMutationEntry = changeStreamMutation.toRowMutationEntry();
229252
MutateRowsRequest.Entry mutateRowsRequestEntry = rowMutationEntry.toProto();
230253
assertThat(mutateRowsRequestEntry.getRowKey()).isEqualTo(ByteString.copyFromUtf8("key"));
231-
assertThat(mutateRowsRequestEntry.getMutationsList()).hasSize(4);
254+
assertThat(mutateRowsRequestEntry.getMutationsList()).hasSize(5);
232255
assertThat(mutateRowsRequestEntry.getMutations(0).getSetCell().getValue())
233256
.isEqualTo(ByteString.copyFromUtf8("fake-value"));
234257
assertThat(mutateRowsRequestEntry.getMutations(1).getDeleteFromFamily().getFamilyName())
@@ -245,6 +268,14 @@ public void toRowMutationEntryTest() {
245268
.setTimestamp(Value.rawTimestamp(1000).toProto())
246269
.setInput(Value.intValue(1234).toProto())
247270
.build());
271+
assertThat(mutateRowsRequestEntry.getMutations(4).getMergeToCell())
272+
.isEqualTo(
273+
Mutation.MergeToCell.newBuilder()
274+
.setFamilyName("agg-family")
275+
.setColumnQualifier(Value.rawValue(ByteString.copyFromUtf8("qual2")).toProto())
276+
.setTimestamp(Value.rawTimestamp(1000).toProto())
277+
.setInput(Value.rawValue(ByteString.copyFrom(Longs.toByteArray(1234L))).toProto())
278+
.build());
248279
}
249280

250281
@Test

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/MutationTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.bigtable.v2.Mutation.DeleteFromColumn;
2222
import com.google.bigtable.v2.Mutation.DeleteFromFamily;
2323
import com.google.bigtable.v2.Mutation.DeleteFromRow;
24+
import com.google.bigtable.v2.Mutation.MergeToCell;
2425
import com.google.cloud.bigtable.data.v2.models.Range.TimestampRange;
2526
import com.google.common.primitives.Longs;
2627
import com.google.protobuf.ByteString;
@@ -195,6 +196,21 @@ public void addToCellTest() {
195196
assertThat(actual).containsExactly(builder.build());
196197
}
197198

199+
@Test
200+
public void mergeToCellTest() {
201+
mutation.mergeToCell("cf1", "q", 10000, ByteString.copyFrom(Longs.toByteArray(1234L)));
202+
List<com.google.bigtable.v2.Mutation> actual = mutation.getMutations();
203+
204+
com.google.bigtable.v2.Mutation.Builder builder = com.google.bigtable.v2.Mutation.newBuilder();
205+
MergeToCell.Builder mergeToCellBuilder = builder.getMergeToCellBuilder();
206+
mergeToCellBuilder.setFamilyName("cf1");
207+
mergeToCellBuilder.getColumnQualifierBuilder().setRawValue(ByteString.copyFromUtf8("q"));
208+
mergeToCellBuilder.getTimestampBuilder().setRawTimestampMicros(10000);
209+
mergeToCellBuilder.getInputBuilder().setRawValue(ByteString.copyFrom(Longs.toByteArray(1234L)));
210+
211+
assertThat(actual).containsExactly(builder.build());
212+
}
213+
198214
@Test
199215
public void serializationTest() throws IOException, ClassNotFoundException {
200216
Mutation expected = Mutation.create().setCell("cf", "q", "val");
@@ -281,7 +297,8 @@ public void fromProtoTest() {
281297
ByteString.copyFromUtf8("fake-value"))
282298
.deleteCells("fake-family", ByteString.copyFromUtf8("fake-qualifier"))
283299
.deleteFamily("fake-family2")
284-
.addToCell("agg-family", "qual1", 1000, 1234);
300+
.addToCell("agg-family", "qual1", 1000, 1234)
301+
.mergeToCell("agg-family", "qual2", 1000, ByteString.copyFrom(Longs.toByteArray(1234L)));
285302

286303
List<com.google.bigtable.v2.Mutation> protoMutation = mutation.getMutations();
287304

0 commit comments

Comments
 (0)