diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml index b6546847f..9ef680c66 100644 --- a/google-cloud-bigquery/clirr-ignored-differences.xml +++ b/google-cloud-bigquery/clirr-ignored-differences.xml @@ -134,4 +134,9 @@ com/google/cloud/bigquery/DatasetInfo* *setMaxTimeTravelHours(*) + + 7013 + com/google/cloud/bigquery/DatasetInfo* + *setResourceTags(*) + \ No newline at end of file diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Dataset.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Dataset.java index 4fc857785..18606e701 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Dataset.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Dataset.java @@ -170,6 +170,12 @@ public Builder setMaxTimeTravelHours(Long maxTimeTravelHours) { return this; } + @Override + public Builder setResourceTags(Map resourceTags) { + infoBuilder.setResourceTags(resourceTags); + return this; + } + @Override public Dataset build() { return new Dataset(bigquery, infoBuilder); diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/DatasetInfo.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/DatasetInfo.java index f9b7f03e1..90d6c2cd5 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/DatasetInfo.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/DatasetInfo.java @@ -76,6 +76,7 @@ public Dataset apply(DatasetInfo datasetInfo) { private final ExternalDatasetReference externalDatasetReference; private final String storageBillingModel; private final Long maxTimeTravelHours; + private final Annotations resourceTags; /** A builder for {@code DatasetInfo} objects. */ public abstract static class Builder { @@ -184,6 +185,19 @@ public abstract Builder setDefaultEncryptionConfiguration( */ public abstract Builder setDefaultCollation(String defaultCollation); + /** + * Optional. The tags attached to this + * dataset. Tag keys are globally unique. Tag key is expected to be in the namespaced format, + * for example "123456789012/environment" where 123456789012 is the ID of the parent + * organization or project resource for this tag key. Tag value is expected to be the short + * name, for example "Production". + * + * @see Tag + * definitions for more details. + * @param resourceTags resourceTags or {@code null} for none + */ + public abstract Builder setResourceTags(Map resourceTags); + /** Creates a {@code DatasetInfo} object. */ public abstract DatasetInfo build(); } @@ -208,6 +222,7 @@ static final class BuilderImpl extends Builder { private ExternalDatasetReference externalDatasetReference; private String storageBillingModel; private Long maxTimeTravelHours; + private Annotations resourceTags = Annotations.ZERO; BuilderImpl() {} @@ -230,6 +245,7 @@ static final class BuilderImpl extends Builder { this.externalDatasetReference = datasetInfo.externalDatasetReference; this.storageBillingModel = datasetInfo.storageBillingModel; this.maxTimeTravelHours = datasetInfo.maxTimeTravelHours; + this.resourceTags = datasetInfo.resourceTags; } BuilderImpl(com.google.api.services.bigquery.model.Dataset datasetPb) { @@ -270,6 +286,7 @@ public Acl apply(Dataset.Access accessPb) { } this.storageBillingModel = datasetPb.getStorageBillingModel(); this.maxTimeTravelHours = datasetPb.getMaxTimeTravelHours(); + this.resourceTags = Annotations.fromPb(datasetPb.getResourceTags()); } @Override @@ -388,6 +405,12 @@ public Builder setMaxTimeTravelHours(Long maxTimeTravelHours) { return this; } + @Override + public Builder setResourceTags(Map resourceTags) { + this.resourceTags = Annotations.fromUser(resourceTags); + return this; + } + @Override public DatasetInfo build() { return new DatasetInfo(this); @@ -413,6 +436,7 @@ public DatasetInfo build() { externalDatasetReference = builder.externalDatasetReference; storageBillingModel = builder.storageBillingModel; maxTimeTravelHours = builder.maxTimeTravelHours; + resourceTags = builder.resourceTags; } /** Returns the dataset identity. */ @@ -554,6 +578,21 @@ public Long getMaxTimeTravelHours() { return maxTimeTravelHours; } + /** + * Optional. The tags attached to this + * dataset. Tag keys are globally unique. Tag key is expected to be in the namespaced format, for + * example "123456789012/environment" where 123456789012 is the ID of the parent organization or + * project resource for this tag key. Tag value is expected to be the short name, for example + * "Production". + * + * @see Tag + * definitions for more details. + * @return value or {@code null} for none + */ + public Map getResourceTags() { + return resourceTags.userMap(); + } + /** * Returns information about the external metadata storage where the dataset is defined. Filled * out when the dataset type is EXTERNAL. @@ -588,6 +627,7 @@ public String toString() { .add("externalDatasetReference", externalDatasetReference) .add("storageBillingModel", storageBillingModel) .add("maxTimeTravelHours", maxTimeTravelHours) + .add("resourceTags", resourceTags) .toString(); } @@ -675,6 +715,7 @@ public Dataset.Access apply(Acl acl) { if (maxTimeTravelHours != null) { datasetPb.setMaxTimeTravelHours(maxTimeTravelHours); } + datasetPb.setResourceTags(resourceTags.toPb()); return datasetPb; } diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetInfoTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetInfoTest.java index 49a392baf..e999b86e2 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetInfoTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetInfoTest.java @@ -62,6 +62,10 @@ public class DatasetInfoTest { private static final String STORAGE_BILLING_MODEL = "LOGICAL"; private static final Long MAX_TIME_TRAVEL_HOURS_5_DAYS = 120L; private static final Long MAX_TIME_TRAVEL_HOURS_7_DAYS = 168L; + private static final Map RESOURCE_TAGS = + ImmutableMap.of( + "example-key1", "example-value1", + "example-key2", "example-value2"); private static final ExternalDatasetReference EXTERNAL_DATASET_REFERENCE = ExternalDatasetReference.newBuilder() @@ -85,6 +89,7 @@ public class DatasetInfoTest { .setDefaultPartitionExpirationMs(DEFAULT_PARTITION__EXPIRATION) .setStorageBillingModel(STORAGE_BILLING_MODEL) .setMaxTimeTravelHours(MAX_TIME_TRAVEL_HOURS_7_DAYS) + .setResourceTags(RESOURCE_TAGS) .build(); private static final DatasetInfo DATASET_INFO_COMPLETE = DATASET_INFO @@ -183,6 +188,7 @@ public void testBuilder() { assertEquals( MAX_TIME_TRAVEL_HOURS_5_DAYS, DATASET_INFO_WITH_MAX_TIME_TRAVEL_5_DAYS.getMaxTimeTravelHours()); + assertEquals(RESOURCE_TAGS, DATASET_INFO.getResourceTags()); } @Test @@ -272,5 +278,6 @@ private void compareDatasets(DatasetInfo expected, DatasetInfo value) { assertEquals(expected.getExternalDatasetReference(), value.getExternalDatasetReference()); assertEquals(expected.getStorageBillingModel(), value.getStorageBillingModel()); assertEquals(expected.getMaxTimeTravelHours(), value.getMaxTimeTravelHours()); + assertEquals(expected.getResourceTags(), value.getResourceTags()); } } diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetTest.java index e2d7c635c..d138e3cb5 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/DatasetTest.java @@ -68,6 +68,10 @@ public class DatasetTest { private static final Field FIELD = Field.of("FieldName", LegacySQLTypeName.INTEGER); private static final String STORAGE_BILLING_MODEL = "LOGICAL"; private static final Long MAX_TIME_TRAVEL_HOURS = 168L; + private static final Map RESOURCE_TAGS = + ImmutableMap.of( + "example-key1", "example-value1", + "example-key2", "example-value2"); private static final StandardTableDefinition TABLE_DEFINITION = StandardTableDefinition.of(Schema.of(FIELD)); private static final ViewDefinition VIEW_DEFINITION = ViewDefinition.of("QUERY"); @@ -124,6 +128,7 @@ public void testBuilder() { .setLabels(LABELS) .setStorageBillingModel(STORAGE_BILLING_MODEL) .setMaxTimeTravelHours(MAX_TIME_TRAVEL_HOURS) + .setResourceTags(RESOURCE_TAGS) .build(); assertEquals(DATASET_ID, builtDataset.getDatasetId()); assertEquals(ACCESS_RULES, builtDataset.getAcl()); @@ -139,6 +144,7 @@ public void testBuilder() { assertEquals(LABELS, builtDataset.getLabels()); assertEquals(STORAGE_BILLING_MODEL, builtDataset.getStorageBillingModel()); assertEquals(MAX_TIME_TRAVEL_HOURS, builtDataset.getMaxTimeTravelHours()); + assertEquals(RESOURCE_TAGS, builtDataset.getResourceTags()); } @Test @@ -348,6 +354,7 @@ public void testExternalDatasetReference() { .setExternalDatasetReference(EXTERNAL_DATASET_REFERENCE) .setStorageBillingModel(STORAGE_BILLING_MODEL) .setMaxTimeTravelHours(MAX_TIME_TRAVEL_HOURS) + .setResourceTags(RESOURCE_TAGS) .build(); assertEquals( EXTERNAL_DATASET_REFERENCE, @@ -379,5 +386,6 @@ private void compareDatasetInfo(DatasetInfo expected, DatasetInfo value) { assertEquals(expected.getExternalDatasetReference(), value.getExternalDatasetReference()); assertEquals(expected.getStorageBillingModel(), value.getStorageBillingModel()); assertEquals(expected.getMaxTimeTravelHours(), value.getMaxTimeTravelHours()); + assertEquals(expected.getResourceTags(), value.getResourceTags()); } } diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index 0178ac10a..fdd1725f2 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -223,6 +223,10 @@ public class ITBigQueryTest { ImmutableMap.of( "example-label1", "example-value1", "example-label2", "example-value2"); + private static final Map RESOURCE_TAGS = + ImmutableMap.of( + PROJECT_ID + "/example-key1", "example-value1", + PROJECT_ID + "/example-key2", "example-value2"); private static final Field TIMESTAMP_FIELD_SCHEMA = Field.newBuilder("TimestampField", LegacySQLTypeName.TIMESTAMP) .setMode(Field.Mode.NULLABLE) @@ -1278,6 +1282,7 @@ public void testUpdateDataset() { assertThat(dataset.getLabels()).containsExactly("a", "b"); assertThat(dataset.getStorageBillingModel()).isNull(); assertThat(dataset.getMaxTimeTravelHours()).isNull(); + assertThat(dataset.getResourceTags()).isNull(); Map updateLabels = new HashMap<>(); updateLabels.put("x", "y"); @@ -1290,17 +1295,49 @@ public void testUpdateDataset() { .setLabels(updateLabels) .setStorageBillingModel("LOGICAL") .setMaxTimeTravelHours(MAX_TIME_TRAVEL_HOURS) + .setResourceTags(RESOURCE_TAGS) .build()); assertThat(updatedDataset.getDescription()).isEqualTo("Updated Description"); assertThat(updatedDataset.getLabels()).containsExactly("x", "y"); assertThat(updatedDataset.getStorageBillingModel()).isEqualTo("LOGICAL"); assertThat(updatedDataset.getMaxTimeTravelHours()).isEqualTo(MAX_TIME_TRAVEL_HOURS); + assertThat(updatedDataset.getResourceTags()).isEqualTo(RESOURCE_TAGS); updatedDataset = bigquery.update(updatedDataset.toBuilder().setLabels(null).build()); assertThat(updatedDataset.getLabels()).isEmpty(); assertThat(dataset.delete()).isTrue(); } + @Test + public void testUpdateDatasetResourceTags() { + Dataset dataset = + bigquery.create( + DatasetInfo.newBuilder(OTHER_DATASET) + .setDescription("Some Description") + .setLabels(Collections.singletonMap("a", "b")) + .setResourceTags(RESOURCE_TAGS) + .build()); + + final String updatedKey1 = PROJECT_ID + "/updated-key1"; + final String updatedValue1 = "updated-value1"; + final String updatedKey2 = PROJECT_ID + "/updated-key2"; + final String updatedValue2 = "updated-value2"; + + Map updatedResourceTags = + new HashMap<>(ImmutableMap.of(updatedKey1, updatedValue1, updatedKey2, updatedValue2)); + updatedResourceTags.put(PROJECT_ID + "/example-key1", null); + updatedResourceTags.put(PROJECT_ID + "/example-key2", null); + + assertEquals(dataset.getResourceTags(), RESOURCE_TAGS); + + Dataset updatedDataset = + bigquery.update(dataset.toBuilder().setResourceTags(updatedResourceTags).build()); + assertThat(updatedDataset.getResourceTags()) + .containsExactly(updatedKey1, updatedValue1, updatedKey2, updatedValue2); + + assertTrue(dataset.delete()); + } + @Test public void testUpdateDatasetWithSelectedFields() { Dataset dataset = @@ -1767,6 +1804,23 @@ public void testCreateDatasetWithDefaultMaxTimeTravelHours() { RemoteBigQueryHelper.forceDelete(bigquery, timeTravelDataset); } + @Test + public void testCreateDatasetWithSpecificResourceTags() { + String resourceTaggedDataset = RemoteBigQueryHelper.generateDatasetName(); + DatasetInfo info = + DatasetInfo.newBuilder(resourceTaggedDataset) + .setDescription(DESCRIPTION) + .setLabels(LABELS) + .setResourceTags(RESOURCE_TAGS) + .build(); + bigquery.create(info); + + Dataset dataset = bigquery.getDataset(DatasetId.of(resourceTaggedDataset)); + assertEquals(RESOURCE_TAGS, dataset.getResourceTags()); + + RemoteBigQueryHelper.forceDelete(bigquery, resourceTaggedDataset); + } + @Test public void testCreateDatasetWithDefaultCollation() { String collationDataset = RemoteBigQueryHelper.generateDatasetName();