Skip to content

Commit d783292

Browse files
feat: add support for table snapshot (#1320)
* feat: add table snapshot support Allows users to generate a persistent copy of an existing table as it were at a given point in time within the same project. * feat: add support for table snapshot * add comment on operationType * lint update and remove extraneous update table snapshot IT * add cleanup for restoredTable * update base on comments * update based on comments
1 parent 9bd442a commit d783292

File tree

6 files changed

+301
-4
lines changed

6 files changed

+301
-4
lines changed

google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/CopyJobConfiguration.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public final class CopyJobConfiguration extends JobConfiguration {
3838

3939
private final List<TableId> sourceTables;
4040
private final TableId destinationTable;
41+
private final String operationType;
4142
private final JobInfo.CreateDisposition createDisposition;
4243
private final JobInfo.WriteDisposition writeDisposition;
4344
private final EncryptionConfiguration destinationEncryptionConfiguration;
@@ -49,6 +50,7 @@ public static final class Builder
4950

5051
private List<TableId> sourceTables;
5152
private TableId destinationTable;
53+
private String operationType;
5254
private JobInfo.CreateDisposition createDisposition;
5355
private JobInfo.WriteDisposition writeDisposition;
5456
private EncryptionConfiguration destinationEncryptionConfiguration;
@@ -63,6 +65,7 @@ private Builder(CopyJobConfiguration jobConfiguration) {
6365
this();
6466
this.sourceTables = jobConfiguration.sourceTables;
6567
this.destinationTable = jobConfiguration.destinationTable;
68+
this.operationType = jobConfiguration.operationType;
6669
this.createDisposition = jobConfiguration.createDisposition;
6770
this.writeDisposition = jobConfiguration.writeDisposition;
6871
this.destinationEncryptionConfiguration = jobConfiguration.destinationEncryptionConfiguration;
@@ -74,6 +77,9 @@ private Builder(com.google.api.services.bigquery.model.JobConfiguration configur
7477
this();
7578
JobConfigurationTableCopy copyConfigurationPb = configurationPb.getCopy();
7679
this.destinationTable = TableId.fromPb(copyConfigurationPb.getDestinationTable());
80+
if (copyConfigurationPb.getOperationType() != null) {
81+
this.operationType = copyConfigurationPb.getOperationType();
82+
}
7783
if (copyConfigurationPb.getSourceTables() != null) {
7884
this.sourceTables =
7985
Lists.transform(copyConfigurationPb.getSourceTables(), TableId.FROM_PB_FUNCTION);
@@ -114,6 +120,15 @@ public Builder setDestinationTable(TableId destinationTable) {
114120
return this;
115121
}
116122

123+
/**
124+
* Sets the supported operation types (COPY, SNAPSHOT or RESTORE) in table copy job. More info:
125+
* https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#operationtype
126+
*/
127+
public Builder setOperationType(String operationType) {
128+
this.operationType = operationType;
129+
return this;
130+
}
131+
117132
public Builder setDestinationEncryptionConfiguration(
118133
EncryptionConfiguration encryptionConfiguration) {
119134
this.destinationEncryptionConfiguration = encryptionConfiguration;
@@ -178,6 +193,7 @@ private CopyJobConfiguration(Builder builder) {
178193
super(builder);
179194
this.sourceTables = checkNotNull(builder.sourceTables);
180195
this.destinationTable = checkNotNull(builder.destinationTable);
196+
this.operationType = builder.operationType;
181197
this.createDisposition = builder.createDisposition;
182198
this.writeDisposition = builder.writeDisposition;
183199
this.destinationEncryptionConfiguration = builder.destinationEncryptionConfiguration;
@@ -195,6 +211,11 @@ public TableId getDestinationTable() {
195211
return destinationTable;
196212
}
197213

214+
/** Returns the table copy job type */
215+
public String getOperationType() {
216+
return operationType;
217+
}
218+
198219
public EncryptionConfiguration getDestinationEncryptionConfiguration() {
199220
return destinationEncryptionConfiguration;
200221
}
@@ -241,6 +262,7 @@ ToStringHelper toStringHelper() {
241262
return super.toStringHelper()
242263
.add("sourceTables", sourceTables)
243264
.add("destinationTable", destinationTable)
265+
.add("operationType", operationType)
244266
.add("destinationEncryptionConfiguration", destinationEncryptionConfiguration)
245267
.add("createDisposition", createDisposition)
246268
.add("writeDisposition", writeDisposition)
@@ -260,6 +282,7 @@ public int hashCode() {
260282
baseHashCode(),
261283
sourceTables,
262284
destinationTable,
285+
operationType,
263286
createDisposition,
264287
writeDisposition,
265288
labels,
@@ -293,11 +316,12 @@ com.google.api.services.bigquery.model.JobConfiguration toPb() {
293316
com.google.api.services.bigquery.model.JobConfiguration jobConfiguration =
294317
new com.google.api.services.bigquery.model.JobConfiguration();
295318
configurationPb.setDestinationTable(destinationTable.toPb());
296-
if (sourceTables.size() == 1) {
297-
configurationPb.setSourceTable(sourceTables.get(0).toPb());
298-
} else {
319+
if (sourceTables != null) {
299320
configurationPb.setSourceTables(Lists.transform(sourceTables, TableId.TO_PB_FUNCTION));
300321
}
322+
if (operationType != null) {
323+
configurationPb.setOperationType(operationType);
324+
}
301325
if (createDisposition != null) {
302326
configurationPb.setCreateDisposition(createDisposition.toString());
303327
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2021 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+
* http://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.bigquery;
18+
19+
import com.google.api.client.util.DateTime;
20+
import com.google.api.core.BetaApi;
21+
import com.google.api.services.bigquery.model.Table;
22+
import com.google.auto.value.AutoValue;
23+
import com.google.common.annotations.VisibleForTesting;
24+
import javax.annotation.Nullable;
25+
26+
@AutoValue
27+
@BetaApi
28+
public abstract class SnapshotTableDefinition extends TableDefinition {
29+
30+
private static final long serialVersionUID = 2113445776046717526L;
31+
32+
@AutoValue.Builder
33+
public abstract static class Builder
34+
extends TableDefinition.Builder<SnapshotTableDefinition, Builder> {
35+
36+
/** Reference describing the ID of the table that was snapshot. * */
37+
public abstract Builder setBaseTableId(TableId baseTableId);
38+
39+
/**
40+
* The time at which the base table was snapshot. This value is reported in the JSON response
41+
* using RFC3339 format. *
42+
*/
43+
public abstract Builder setSnapshotTime(String dateTime);
44+
45+
public abstract Builder setTimePartitioning(TimePartitioning timePartitioning);
46+
47+
public abstract Builder setRangePartitioning(RangePartitioning rangePartitioning);
48+
49+
public abstract Builder setClustering(Clustering clustering);
50+
51+
/** Creates a {@code SnapshotTableDefinition} object. */
52+
public abstract SnapshotTableDefinition build();
53+
}
54+
55+
@Nullable
56+
public abstract TableId getBaseTableId();
57+
58+
@Nullable
59+
public abstract String getSnapshotTime();
60+
61+
@Nullable
62+
public abstract TimePartitioning getTimePartitioning();
63+
64+
@Nullable
65+
public abstract RangePartitioning getRangePartitioning();
66+
67+
@Nullable
68+
public abstract Clustering getClustering();
69+
70+
/** Returns a builder for a snapshot table definition. */
71+
public static SnapshotTableDefinition.Builder newBuilder() {
72+
return new AutoValue_SnapshotTableDefinition.Builder().setType(Type.SNAPSHOT);
73+
}
74+
75+
@VisibleForTesting
76+
public abstract SnapshotTableDefinition.Builder toBuilder();
77+
78+
@Override
79+
Table toPb() {
80+
Table tablePb = super.toPb();
81+
com.google.api.services.bigquery.model.SnapshotDefinition snapshotDefinition =
82+
new com.google.api.services.bigquery.model.SnapshotDefinition();
83+
snapshotDefinition.setBaseTableReference(getBaseTableId().toPb());
84+
snapshotDefinition.setSnapshotTime(DateTime.parseRfc3339(getSnapshotTime()));
85+
tablePb.setSnapshotDefinition(snapshotDefinition);
86+
if (getTimePartitioning() != null) {
87+
tablePb.setTimePartitioning(getTimePartitioning().toPb());
88+
}
89+
if (getRangePartitioning() != null) {
90+
tablePb.setRangePartitioning(getRangePartitioning().toPb());
91+
}
92+
if (getClustering() != null) {
93+
tablePb.setClustering(getClustering().toPb());
94+
}
95+
return tablePb;
96+
}
97+
98+
static SnapshotTableDefinition fromPb(Table tablePb) {
99+
Builder builder = newBuilder().table(tablePb);
100+
com.google.api.services.bigquery.model.SnapshotDefinition snapshotDefinition =
101+
tablePb.getSnapshotDefinition();
102+
if (snapshotDefinition != null) {
103+
if (snapshotDefinition.getBaseTableReference() != null) {
104+
builder.setBaseTableId(TableId.fromPb(snapshotDefinition.getBaseTableReference()));
105+
}
106+
if (snapshotDefinition.getSnapshotTime() != null) {
107+
builder.setSnapshotTime(snapshotDefinition.getSnapshotTime().toStringRfc3339());
108+
}
109+
}
110+
return builder.build();
111+
}
112+
}

google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableDefinition.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public Type apply(String constant) {
8383
*/
8484
public static final Type MODEL = type.createAndRegister("MODEL");
8585

86+
public static final Type SNAPSHOT = type.createAndRegister("SNAPSHOT");
87+
8688
private Type(String constant) {
8789
super(constant);
8890
}
@@ -165,6 +167,8 @@ static <T extends TableDefinition> T fromPb(Table tablePb) {
165167
return (T) ExternalTableDefinition.fromPb(tablePb);
166168
case "MODEL":
167169
return (T) ModelTableDefinition.fromPb(tablePb);
170+
case "SNAPSHOT":
171+
return (T) SnapshotTableDefinition.fromPb(tablePb);
168172
default:
169173
// never reached
170174
throw new IllegalArgumentException("Format " + tablePb.getType() + " is not supported");

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/CopyJobConfigurationTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ public void testToPbAndFromPb() {
113113
assertNull(COPY_JOB_CONFIGURATION.toPb().getExtract());
114114
assertNull(COPY_JOB_CONFIGURATION.toPb().getLoad());
115115
assertNull(COPY_JOB_CONFIGURATION.toPb().getQuery());
116-
assertNull(COPY_JOB_CONFIGURATION.toPb().getCopy().getSourceTables());
116+
assertNull(COPY_JOB_CONFIGURATION.toPb().getCopy().getSourceTable());
117+
assertNotNull(COPY_JOB_CONFIGURATION.toPb().getCopy().getSourceTables());
117118
assertNull(COPY_JOB_CONFIGURATION_MULTIPLE_TABLES.toPb().getCopy().getSourceTable());
118119
assertNotNull(COPY_JOB_CONFIGURATION.getLabels());
119120
assertNotNull(COPY_JOB_CONFIGURATION_MULTIPLE_TABLES.getLabels());
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2021 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+
* http://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.bigquery;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertTrue;
21+
22+
import org.junit.Test;
23+
24+
public class SnapshotTableDefinitionTest {
25+
26+
private static final TableId BASE_TABLE_ID = TableId.of("DATASET_NAME", "BASE_TABLE_NAME");
27+
private static final String SNAPSHOT_TIME = "2021-05-19T11:32:26.553Z";
28+
private static final SnapshotTableDefinition SNAPSHOTTABLE_DEFINITION =
29+
SnapshotTableDefinition.newBuilder()
30+
.setBaseTableId(BASE_TABLE_ID)
31+
.setSnapshotTime(SNAPSHOT_TIME)
32+
.build();
33+
34+
@Test
35+
public void testToBuilder() {
36+
compareSnapshotTableDefinition(
37+
SNAPSHOTTABLE_DEFINITION, SNAPSHOTTABLE_DEFINITION.toBuilder().build());
38+
SnapshotTableDefinition snapshotTableDefinition =
39+
SNAPSHOTTABLE_DEFINITION.toBuilder().setSnapshotTime("2021-05-20T11:32:26.553Z").build();
40+
assertEquals("2021-05-20T11:32:26.553Z", snapshotTableDefinition.getSnapshotTime());
41+
}
42+
43+
@Test
44+
public void testBuilder() {
45+
assertEquals(TableDefinition.Type.SNAPSHOT, SNAPSHOTTABLE_DEFINITION.getType());
46+
assertEquals(BASE_TABLE_ID, SNAPSHOTTABLE_DEFINITION.getBaseTableId());
47+
assertEquals(SNAPSHOT_TIME, SNAPSHOTTABLE_DEFINITION.getSnapshotTime());
48+
SnapshotTableDefinition snapshotTableDefinition =
49+
SnapshotTableDefinition.newBuilder()
50+
.setBaseTableId(BASE_TABLE_ID)
51+
.setSnapshotTime(SNAPSHOT_TIME)
52+
.build();
53+
assertEquals(SNAPSHOTTABLE_DEFINITION, snapshotTableDefinition);
54+
}
55+
56+
@Test
57+
public void testToAndFromPb() {
58+
SnapshotTableDefinition snapshotTableDefinition = SNAPSHOTTABLE_DEFINITION.toBuilder().build();
59+
assertTrue(
60+
TableDefinition.fromPb(snapshotTableDefinition.toPb()) instanceof SnapshotTableDefinition);
61+
compareSnapshotTableDefinition(
62+
snapshotTableDefinition,
63+
TableDefinition.<SnapshotTableDefinition>fromPb(snapshotTableDefinition.toPb()));
64+
}
65+
66+
private void compareSnapshotTableDefinition(
67+
SnapshotTableDefinition expected, SnapshotTableDefinition value) {
68+
assertEquals(expected, value);
69+
assertEquals(expected.getBaseTableId(), value.getBaseTableId());
70+
assertEquals(expected.getSnapshotTime(), value.getSnapshotTime());
71+
}
72+
}

0 commit comments

Comments
 (0)