Skip to content
This repository was archived by the owner on May 8, 2026. It is now read-only.

Commit 026f512

Browse files
committed
feat: Add GcRuleBuilder for safe GC rule construction
1 parent 01720b6 commit 026f512

4 files changed

Lines changed: 234 additions & 0 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2026 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.admin.v2.models;
17+
18+
import com.google.bigtable.admin.v2.GcRule;
19+
import com.google.protobuf.util.Durations;
20+
import org.threeten.bp.Duration;
21+
22+
/**
23+
* Factory for creating safe GcRule protos.
24+
*
25+
* <p>Use this class to construct GcRules instead of the raw proto builder to avoid
26+
* common pitfalls with "oneof" fields (e.g. accidentally overwriting max age with max versions).
27+
*/
28+
public final class GcRuleBuilder {
29+
private GcRuleBuilder() {} // Static utility
30+
31+
// Entry points for composite rules
32+
33+
/** Starts building an Intersection (AND) rule. */
34+
public static IntersectionRuleBuilder intersection() {
35+
return new IntersectionRuleBuilder();
36+
}
37+
38+
/** Starts building a Union (OR) rule. */
39+
public static UnionRuleBuilder union() {
40+
return new UnionRuleBuilder();
41+
}
42+
43+
// Entry points for simple rules (return the Proto directly)
44+
45+
/** Creates a Max Age rule. */
46+
public static GcRule maxAge(Duration age) {
47+
long seconds = age.getSeconds();
48+
int nanos = age.getNano();
49+
return GcRule.newBuilder()
50+
.setMaxAge(Durations.fromNanos(seconds * 1_000_000_000L + nanos))
51+
.build();
52+
}
53+
54+
/** Creates a Max Versions rule. */
55+
public static GcRule maxVersions(int versions) {
56+
return GcRule.newBuilder().setMaxNumVersions(versions).build();
57+
}
58+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2026 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.admin.v2.models;
17+
18+
import com.google.bigtable.admin.v2.GcRule;
19+
import com.google.bigtable.admin.v2.GcRule.Intersection;
20+
21+
/**
22+
* Builder for creating an Intersection (AND) GC Rule.
23+
*
24+
* <p>This class ensures type safety when constructing composite rules, preventing
25+
* the misuse of the standard builder's ambiguous setters.
26+
*/
27+
public final class IntersectionRuleBuilder {
28+
private final Intersection.Builder intersectionBuilder = Intersection.newBuilder();
29+
30+
/** Adds a rule to the intersection. */
31+
public IntersectionRuleBuilder add(GcRule rule) {
32+
intersectionBuilder.addRules(rule);
33+
return this;
34+
}
35+
36+
/** Builds the final GcRule proto. */
37+
public GcRule build() {
38+
return GcRule.newBuilder().setIntersection(intersectionBuilder).build();
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2026 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.admin.v2.models;
17+
18+
import com.google.bigtable.admin.v2.GcRule;
19+
import com.google.bigtable.admin.v2.GcRule.Union;
20+
21+
/**
22+
* Builder for creating a Union (OR) GC Rule.
23+
*
24+
* <p>This class ensures type safety when constructing composite rules, preventing
25+
* the misuse of the standard builder's ambiguous setters.
26+
*/
27+
public final class UnionRuleBuilder {
28+
private final Union.Builder unionBuilder = Union.newBuilder();
29+
30+
/** Adds a rule to the union. */
31+
public UnionRuleBuilder add(GcRule rule) {
32+
unionBuilder.addRules(rule);
33+
return this;
34+
}
35+
36+
/** Builds the final GcRule proto. */
37+
public GcRule build() {
38+
return GcRule.newBuilder().setUnion(unionBuilder).build();
39+
}
40+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2026 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.admin.v2.models;
17+
18+
import static com.google.common.truth.Truth.assertThat;
19+
20+
import com.google.bigtable.admin.v2.GcRule;
21+
import com.google.protobuf.util.Durations;
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.junit.runners.JUnit4;
25+
import org.threeten.bp.Duration;
26+
27+
@RunWith(JUnit4.class)
28+
public class GcRuleBuilderTest {
29+
30+
@Test
31+
public void maxAge_createsCorrectProto() {
32+
GcRule rule = GcRuleBuilder.maxAge(Duration.ofHours(1));
33+
34+
assertThat(rule.hasMaxAge()).isTrue();
35+
assertThat(rule.getMaxAge()).isEqualTo(Durations.fromHours(1));
36+
}
37+
38+
@Test
39+
public void maxVersions_createsCorrectProto() {
40+
GcRule rule = GcRuleBuilder.maxVersions(5);
41+
42+
assertThat(rule.hasMaxNumVersions()).isTrue();
43+
assertThat(rule.getMaxNumVersions()).isEqualTo(5);
44+
}
45+
46+
@Test
47+
public void intersection_buildsNestedRules() {
48+
// Expected Proto structure
49+
GcRule expected = GcRule.newBuilder()
50+
.setIntersection(GcRule.Intersection.newBuilder()
51+
.addRules(GcRule.newBuilder().setMaxNumVersions(1).build())
52+
.addRules(GcRule.newBuilder().setMaxAge(Durations.fromHours(2)).build()))
53+
.build();
54+
55+
// Using the new Builder
56+
GcRule actual = GcRuleBuilder.intersection()
57+
.add(GcRuleBuilder.maxVersions(1))
58+
.add(GcRuleBuilder.maxAge(Duration.ofHours(2)))
59+
.build();
60+
61+
assertThat(actual).isEqualTo(expected);
62+
}
63+
64+
@Test
65+
public void union_buildsNestedRules() {
66+
// Expected Proto structure
67+
GcRule expected = GcRule.newBuilder()
68+
.setUnion(GcRule.Union.newBuilder()
69+
.addRules(GcRule.newBuilder().setMaxNumVersions(10).build())
70+
.addRules(GcRule.newBuilder().setMaxAge(Durations.fromDays(5)).build()))
71+
.build();
72+
73+
// Using the new Builder
74+
GcRule actual = GcRuleBuilder.union()
75+
.add(GcRuleBuilder.maxVersions(10))
76+
.add(GcRuleBuilder.maxAge(Duration.ofDays(5)))
77+
.build();
78+
79+
assertThat(actual).isEqualTo(expected);
80+
}
81+
82+
@Test
83+
public void nestedComplexRules_workCorrectly() {
84+
// Union of (Version(1) OR Intersection(Age(1h) AND Version(5)))
85+
GcRule actual = GcRuleBuilder.union()
86+
.add(GcRuleBuilder.maxVersions(1))
87+
.add(GcRuleBuilder.intersection()
88+
.add(GcRuleBuilder.maxAge(Duration.ofHours(1)))
89+
.add(GcRuleBuilder.maxVersions(5))
90+
.build())
91+
.build();
92+
93+
assertThat(actual.getUnion().getRulesCount()).isEqualTo(2);
94+
assertThat(actual.getUnion().getRules(1).getIntersection().getRulesCount()).isEqualTo(2);
95+
}
96+
}

0 commit comments

Comments
 (0)