bigquery: Add support for removing an expiration
Prior to this change, calls to Update did not support removing a table's
expiration, even though the REST API supports such an operation.
Because the TableUpdateMetadata ExpirationTime field is a time.Time
value, rather than a pointer to a time.Time, we cannot pass in nil to
indicate the expiration time should be removed. Instead, this change
uses a sentinel value, the zero value time.Time minus one second, and
advises callers to use the NeverExpire variable added in this commit.
Fixes #1196.
Change-Id: Ib2cae9bc7744da75e86c62f8d476e78b6e8d6e73
Reviewed-on: https://code-review.googlesource.com/c/34631
Reviewed-by: Jean de Klerk <deklerk@google.com>
diff --git a/bigquery/table.go b/bigquery/table.go
index b7553e7..52d1af0 100644
--- a/bigquery/table.go
+++ b/bigquery/table.go
@@ -69,8 +69,9 @@
// Clustering specifies the data clustering configuration for the table.
Clustering *Clustering
- // The time when this table expires. If not set, the table will persist
- // indefinitely. Expired tables will be deleted and their storage reclaimed.
+ // The time when this table expires. If set, this table will expire at the
+ // specified time. Expired tables will be deleted and their storage
+ // reclaimed. The zero value is ignored.
ExpirationTime time.Time
// User-provided labels.
@@ -278,7 +279,7 @@
// Create creates a table in the BigQuery service.
// Pass in a TableMetadata value to configure the table.
// If tm.View.Query is non-empty, the created table will be of type VIEW.
-// Expiration can only be set during table creation.
+// If no ExpirationTime is specified, the table will never expire.
// After table creation, a view can be modified only if its table was initially created
// with a view.
func (t *Table) Create(ctx context.Context, tm *TableMetadata) (err error) {
@@ -443,6 +444,10 @@
return newRowIterator(ctx, t, pf)
}
+// NeverExpire is a sentinel value used with TableMetadataToUpdate's
+// ExpirationTime to indicate that a table should never expire.
+var NeverExpire = time.Time{}.Add(-1)
+
// Update modifies specific Table metadata fields.
func (t *Table) Update(ctx context.Context, tm TableMetadataToUpdate, etag string) (md *TableMetadata, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Table.Update")
@@ -485,7 +490,9 @@
if tm.EncryptionConfig != nil {
t.EncryptionConfiguration = tm.EncryptionConfig.toBQ()
}
- if !tm.ExpirationTime.IsZero() {
+ if tm.ExpirationTime == NeverExpire {
+ t.NullFields = append(t.NullFields, "ExpirationTime")
+ } else if !tm.ExpirationTime.IsZero() {
t.ExpirationTime = tm.ExpirationTime.UnixNano() / 1e6
forceSend("ExpirationTime")
}
@@ -530,7 +537,8 @@
// all mutable fields of EncryptionConfig are populated.
EncryptionConfig *EncryptionConfig
- // The time when this table expires.
+ // The time when this table expires. To remove a table's expiration,
+ // set ExpirationTime to NeverExpire. The zero value is ignored.
ExpirationTime time.Time
// The query to use for a view.
diff --git a/bigquery/table_test.go b/bigquery/table_test.go
index 0c4d926..84e2e8f 100644
--- a/bigquery/table_test.go
+++ b/bigquery/table_test.go
@@ -298,6 +298,12 @@
NullFields: []string{"Labels.D"},
},
},
+ {
+ tm: TableMetadataToUpdate{ExpirationTime: NeverExpire},
+ want: &bq.Table{
+ NullFields: []string{"ExpirationTime"},
+ },
+ },
} {
got := test.tm.toBQ()
if !testutil.Equal(got, test.want) {