Skip to content

Commit 7d7b9a9

Browse files
authored
feat(bigtable): Add schema bundle support (#2619)
* feat(bigtable): Add schema bundle support * minor fix * fix format * add tests * add tests * handled file * added files * fix format * fix files * fix comment * fix * fix test * fix test * fix test * fix more tests * fix more tests * fix more tests * fix more tests * fix more tests * use separate tables for tests * use separate tables for tests * use separate tables for tests * update according to PR * update according to PR * update according to PR * Update UpdateSchemaBundleRequest.java * fix build
1 parent b5acca6 commit 7d7b9a9

15 files changed

+1675
-0
lines changed

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClient.java

Lines changed: 342 additions & 0 deletions
Large diffs are not rendered by default.

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/internal/NameUtil.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public class NameUtil {
3838
private static final Pattern AUTHORIZED_VIEW_PATTERN =
3939
Pattern.compile("projects/([^/]+)/instances/([^/]+)/tables/([^/]+)/authorizedViews/([^/]+)");
4040

41+
private static final Pattern SCHEMA_BUNDLE_PATTERN =
42+
Pattern.compile("projects/([^/]+)/instances/([^/]+)/tables/([^/]+)/schemaBundles/([^/]+)");
43+
4144
public static String formatProjectName(String projectId) {
4245
return "projects/" + projectId;
4346
}
@@ -74,6 +77,11 @@ public static String formatAuthorizedViewName(
7477
return formatTableName(projectId, instanceId, tableId) + "/authorizedViews/" + viewId;
7578
}
7679

80+
public static String formatSchemaBundleName(
81+
String projectId, String instanceId, String tableId, String bundleId) {
82+
return formatTableName(projectId, instanceId, tableId) + "/schemaBundles/" + bundleId;
83+
}
84+
7785
public static String extractTableIdFromTableName(String fullTableName) {
7886
Matcher matcher = TABLE_PATTERN.matcher(fullTableName);
7987
if (!matcher.matches()) {
@@ -99,6 +107,14 @@ public static String extractAuthorizedViewIdFromAuthorizedViewName(
99107
return matcher.group(4);
100108
}
101109

110+
public static String extractSchemaBundleIdFromSchemaBundleName(String fullSchemaBundleName) {
111+
Matcher matcher = SCHEMA_BUNDLE_PATTERN.matcher(fullSchemaBundleName);
112+
if (!matcher.matches()) {
113+
throw new IllegalArgumentException("Invalid schema bundle name: " + fullSchemaBundleName);
114+
}
115+
return matcher.group(4);
116+
}
117+
102118
public static String extractZoneIdFromLocationName(String fullLocationName) {
103119
Matcher matcher = LOCATION_PATTERN.matcher(fullLocationName);
104120
if (!matcher.matches()) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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+
17+
package com.google.cloud.bigtable.admin.v2.models;
18+
19+
import com.google.api.core.InternalApi;
20+
import com.google.bigtable.admin.v2.ProtoSchema;
21+
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
22+
import com.google.common.base.Objects;
23+
import com.google.common.base.Preconditions;
24+
import com.google.protobuf.ByteString;
25+
import java.io.IOException;
26+
import java.nio.file.Files;
27+
import java.nio.file.Paths;
28+
import javax.annotation.Nonnull;
29+
30+
/**
31+
* Parameters for creating a new Cloud Bigtable {@link SchemaBundle}, which represents subsets of a
32+
* particular table.
33+
*
34+
* <p>Sample code:
35+
*
36+
* <pre>{@code
37+
* CreateSchemaBundleRequest request =
38+
* CreateSchemaBundleRequest.of("my-table", "my-new-schema-bundle")
39+
* .setProtoSchemaFile("proto_file.pb");
40+
* }</pre>
41+
*
42+
* @see SchemaBundle for more details.
43+
*/
44+
public final class CreateSchemaBundleRequest {
45+
private final String tableId;
46+
private final com.google.bigtable.admin.v2.CreateSchemaBundleRequest.Builder requestBuilder =
47+
com.google.bigtable.admin.v2.CreateSchemaBundleRequest.newBuilder();
48+
49+
public static CreateSchemaBundleRequest of(
50+
@Nonnull String tableId, @Nonnull String schemaBundleId) {
51+
return new CreateSchemaBundleRequest(tableId, schemaBundleId);
52+
}
53+
54+
private CreateSchemaBundleRequest(@Nonnull String tableId, @Nonnull String schemaBundleId) {
55+
Preconditions.checkNotNull(tableId, "tableId must be set");
56+
Preconditions.checkNotNull(schemaBundleId, "schemaBundleId must be set");
57+
58+
this.tableId = tableId;
59+
requestBuilder.setSchemaBundleId(schemaBundleId);
60+
}
61+
62+
/** Sets the proto schema for this schema bundle. */
63+
public CreateSchemaBundleRequest setProtoSchemaFile(@Nonnull String protoSchemaFile)
64+
throws IOException {
65+
Preconditions.checkNotNull(protoSchemaFile, "protoSchemaFile must be set");
66+
byte[] content = Files.readAllBytes(Paths.get(protoSchemaFile));
67+
return setProtoSchema(ByteString.copyFrom(content));
68+
}
69+
70+
/** Sets the proto schema for this schema bundle. */
71+
public CreateSchemaBundleRequest setProtoSchema(@Nonnull ByteString protoSchema)
72+
throws IOException {
73+
Preconditions.checkNotNull(protoSchema, "protoSchema must be set");
74+
requestBuilder.setSchemaBundle(
75+
com.google.bigtable.admin.v2.SchemaBundle.newBuilder()
76+
.setProtoSchema(ProtoSchema.newBuilder().setProtoDescriptors(protoSchema)));
77+
return this;
78+
}
79+
80+
@Override
81+
public boolean equals(Object o) {
82+
if (this == o) {
83+
return true;
84+
}
85+
if (o == null || getClass() != o.getClass()) {
86+
return false;
87+
}
88+
CreateSchemaBundleRequest that = (CreateSchemaBundleRequest) o;
89+
return Objects.equal(requestBuilder.build(), that.requestBuilder.build())
90+
&& Objects.equal(tableId, that.tableId);
91+
}
92+
93+
@Override
94+
public int hashCode() {
95+
return Objects.hashCode(requestBuilder.build(), tableId);
96+
}
97+
98+
/**
99+
* Creates the request protobuf. This method is considered an internal implementation detail and
100+
* not meant to be used by applications.
101+
*/
102+
@InternalApi
103+
public com.google.bigtable.admin.v2.CreateSchemaBundleRequest toProto(
104+
@Nonnull String projectId, @Nonnull String instanceId) {
105+
return requestBuilder
106+
.setParent(NameUtil.formatTableName(projectId, instanceId, tableId))
107+
.build();
108+
}
109+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
17+
package com.google.cloud.bigtable.admin.v2.models;
18+
19+
import com.google.api.core.InternalApi;
20+
import com.google.bigtable.admin.v2.SchemaBundleName;
21+
import com.google.common.base.Objects;
22+
import com.google.common.base.Preconditions;
23+
import javax.annotation.Nonnull;
24+
25+
/**
26+
* A class that wraps the {@link com.google.bigtable.admin.v2.SchemaBundle} protocol buffer object.
27+
*/
28+
public final class SchemaBundle {
29+
private final com.google.bigtable.admin.v2.SchemaBundle proto;
30+
private final SchemaBundleName schemaBundleName;
31+
32+
/**
33+
* Wraps the protobuf. This method is considered an internal implementation detail and not meant
34+
* to be used by applications.
35+
*/
36+
@InternalApi
37+
public static SchemaBundle fromProto(@Nonnull com.google.bigtable.admin.v2.SchemaBundle proto) {
38+
return new SchemaBundle(proto);
39+
}
40+
41+
private SchemaBundle(@Nonnull com.google.bigtable.admin.v2.SchemaBundle proto) {
42+
Preconditions.checkNotNull(proto);
43+
Preconditions.checkArgument(!proto.getName().isEmpty(), "SchemaBundle must have a name");
44+
Preconditions.checkArgument(
45+
proto.hasProtoSchema(), "Schemabundle must have a proto_schema field");
46+
this.proto = proto;
47+
this.schemaBundleName = SchemaBundleName.parse(proto.getName());
48+
}
49+
50+
/** Gets the schema bundle's id. */
51+
public String getId() {
52+
//noinspection ConstantConditions
53+
return schemaBundleName.getSchemaBundle();
54+
}
55+
56+
/** Gets the id of the table that owns this schema bundle. */
57+
public String getTableId() {
58+
//noinspection ConstantConditions
59+
return schemaBundleName.getTable();
60+
}
61+
62+
/** Gets the proto schema of this schema bundle. */
63+
public com.google.protobuf.ByteString getProtoSchema() {
64+
if (proto.hasProtoSchema()) {
65+
return proto.getProtoSchema().getProtoDescriptors();
66+
}
67+
throw new IllegalStateException("This SchemaBundle doesn't have a valid type specified");
68+
}
69+
70+
/**
71+
* Creates the request protobuf. This method is considered an internal implementation detail and
72+
* not meant to be used by applications.
73+
*/
74+
@InternalApi
75+
public com.google.bigtable.admin.v2.SchemaBundle toProto() {
76+
return proto;
77+
}
78+
79+
@Override
80+
public boolean equals(Object o) {
81+
if (this == o) {
82+
return true;
83+
}
84+
if (o == null || getClass() != o.getClass()) {
85+
return false;
86+
}
87+
SchemaBundle that = (SchemaBundle) o;
88+
return Objects.equal(proto, that.proto);
89+
}
90+
91+
@Override
92+
public int hashCode() {
93+
return Objects.hashCode(proto);
94+
}
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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+
17+
package com.google.cloud.bigtable.admin.v2.models;
18+
19+
import com.google.api.core.InternalApi;
20+
import com.google.bigtable.admin.v2.ProtoSchema;
21+
import com.google.cloud.bigtable.admin.v2.internal.NameUtil;
22+
import com.google.common.base.Objects;
23+
import com.google.common.base.Preconditions;
24+
import com.google.protobuf.ByteString;
25+
import com.google.protobuf.FieldMask;
26+
import com.google.protobuf.util.FieldMaskUtil;
27+
import java.io.IOException;
28+
import java.nio.file.Files;
29+
import java.nio.file.Paths;
30+
import javax.annotation.Nonnull;
31+
32+
/**
33+
* Parameters for updating an existing Cloud Bigtable {@link SchemaBundle}.
34+
*
35+
* <p>Sample code:
36+
*
37+
* <pre>{@code
38+
* SchemaBundle existingSchemaBundle = client.getSchemaBundle("my-table", "my-schema-bundle");
39+
* UpdateSchemaBundleRequest request =
40+
* UpdateSchemaBundleRequest.of(existingSchemaBundle).setProtoSchemaFile("file.pb");
41+
* }</pre>
42+
*
43+
* @see SchemaBundle for more details.
44+
*/
45+
public final class UpdateSchemaBundleRequest {
46+
private final com.google.bigtable.admin.v2.UpdateSchemaBundleRequest.Builder requestBuilder;
47+
private final String tableId;
48+
private final String schemaBundleId;
49+
50+
/** Builds a new update request using an existing schema bundle. */
51+
public static UpdateSchemaBundleRequest of(@Nonnull SchemaBundle schemaBundle) {
52+
return new UpdateSchemaBundleRequest(
53+
schemaBundle.getTableId(),
54+
schemaBundle.getId(),
55+
com.google.bigtable.admin.v2.UpdateSchemaBundleRequest.newBuilder()
56+
.setSchemaBundle(schemaBundle.toProto()));
57+
}
58+
59+
/** Builds a new update schema bundle request. */
60+
public static UpdateSchemaBundleRequest of(
61+
@Nonnull String tableId, @Nonnull String schemaBundleId) {
62+
return new UpdateSchemaBundleRequest(
63+
tableId,
64+
schemaBundleId,
65+
com.google.bigtable.admin.v2.UpdateSchemaBundleRequest.newBuilder());
66+
}
67+
68+
private UpdateSchemaBundleRequest(
69+
@Nonnull String tableId,
70+
@Nonnull String schemaBundleId,
71+
@Nonnull com.google.bigtable.admin.v2.UpdateSchemaBundleRequest.Builder requestBuilder) {
72+
Preconditions.checkNotNull(tableId, "tableId must be set");
73+
Preconditions.checkNotNull(schemaBundleId, "schemaBundleId must be set");
74+
Preconditions.checkNotNull(requestBuilder, "proto builder must be set");
75+
76+
this.tableId = tableId;
77+
this.schemaBundleId = schemaBundleId;
78+
this.requestBuilder = requestBuilder;
79+
}
80+
81+
/** Sets the proto schema for this schema bundle. */
82+
public UpdateSchemaBundleRequest setProtoSchemaFile(@Nonnull String protoSchemaFile)
83+
throws IOException {
84+
Preconditions.checkNotNull(protoSchemaFile, "protoSchemaFile must be set");
85+
byte[] content = Files.readAllBytes(Paths.get(protoSchemaFile));
86+
return setProtoSchema(ByteString.copyFrom(content));
87+
}
88+
89+
/** Sets the proto schema for this schema bundle. */
90+
public UpdateSchemaBundleRequest setProtoSchema(@Nonnull ByteString protoSchema)
91+
throws IOException {
92+
Preconditions.checkNotNull(protoSchema, "protoSchema must be set");
93+
requestBuilder.setSchemaBundle(
94+
com.google.bigtable.admin.v2.SchemaBundle.newBuilder()
95+
.setProtoSchema(ProtoSchema.newBuilder().setProtoDescriptors(protoSchema)));
96+
updateFieldMask(com.google.bigtable.admin.v2.SchemaBundle.PROTO_SCHEMA_FIELD_NUMBER);
97+
return this;
98+
}
99+
100+
/**
101+
* Configures if safety warnings should be disabled. If set, then non backwards compatible changes
102+
* are allowed.
103+
*/
104+
@SuppressWarnings("WeakerAccess")
105+
public UpdateSchemaBundleRequest setIgnoreWarnings(boolean value) {
106+
requestBuilder.setIgnoreWarnings(value);
107+
return this;
108+
}
109+
110+
private void updateFieldMask(int fieldNumber) {
111+
FieldMask newMask =
112+
FieldMaskUtil.fromFieldNumbers(
113+
com.google.bigtable.admin.v2.SchemaBundle.class, fieldNumber);
114+
requestBuilder.setUpdateMask(FieldMaskUtil.union(requestBuilder.getUpdateMask(), newMask));
115+
}
116+
117+
@Override
118+
public boolean equals(Object o) {
119+
if (this == o) {
120+
return true;
121+
}
122+
if (o == null || getClass() != o.getClass()) {
123+
return false;
124+
}
125+
UpdateSchemaBundleRequest that = (UpdateSchemaBundleRequest) o;
126+
return Objects.equal(requestBuilder.build(), that.requestBuilder.build())
127+
&& Objects.equal(tableId, that.tableId)
128+
&& Objects.equal(schemaBundleId, that.schemaBundleId);
129+
}
130+
131+
@Override
132+
public int hashCode() {
133+
return Objects.hashCode(requestBuilder.build(), tableId, schemaBundleId);
134+
}
135+
136+
/**
137+
* Creates the request protobuf. This method is considered an internal implementation detail and
138+
* not meant to be used by applications.
139+
*/
140+
@InternalApi
141+
public com.google.bigtable.admin.v2.UpdateSchemaBundleRequest toProto(
142+
@Nonnull String projectId, @Nonnull String instanceId) {
143+
requestBuilder
144+
.getSchemaBundleBuilder()
145+
.setName(NameUtil.formatSchemaBundleName(projectId, instanceId, tableId, schemaBundleId));
146+
return requestBuilder.build();
147+
}
148+
}

0 commit comments

Comments
 (0)