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

Commit 617fd11

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

4 files changed

Lines changed: 238 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)