diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index d5500ef442..52eaa54d82 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-java:latest - digest: sha256:46d2d262cd285c638656c8bde468011b723dc0c7ffd6a5ecc2650fe639c82e8f -# created: 2023-07-24T14:21:17.707234503Z + digest: sha256:88ba8dcc5c2c7792e1c3511381f4ab329002a1c42c512f66ca87ced572dfbf9f +# created: 2023-09-05T18:54:42.225408832Z diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fa10a24734..4959517d49 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -32,7 +32,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 with: persist-credentials: false @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: SARIF file path: results.sarif diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 32989051e7..a73256ab80 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -12,9 +12,9 @@ cachetools==5.3.1 \ --hash=sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590 \ --hash=sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b # via google-auth -certifi==2023.5.7 \ - --hash=sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7 \ - --hash=sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716 +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ @@ -485,6 +485,5 @@ zipp==3.16.1 \ # via importlib-metadata # WARNING: The following packages were not pinned, but pip requires them to be -# pinned when the requirements file includes hashes and the requirement is not -# satisfied by a package already installed. Consider using the --allow-unsafe flag. +# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag. # setuptools diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c833f4b7c..05a148540f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## [2.32.0](https://github.com/googleapis/java-bigquery/compare/v2.31.2...v2.32.0) (2023-09-14) + + +### Features + +* Add support for converting interval fields to threeten PeriodDuration ([#2838](https://github.com/googleapis/java-bigquery/issues/2838)) ([2294c2f](https://github.com/googleapis/java-bigquery/commit/2294c2ffca62a22a66786a9a4c6c9ef1be898e5d)) +* Add support for ExternalDatasetReference ([#2871](https://github.com/googleapis/java-bigquery/issues/2871)) ([bbb86fd](https://github.com/googleapis/java-bigquery/commit/bbb86fd8488ad253f2e9cf3fb08360330bd860a3)) + + +### Dependencies + +* Update actions/checkout action to v4 ([#2862](https://github.com/googleapis/java-bigquery/issues/2862)) ([902e9b9](https://github.com/googleapis/java-bigquery/commit/902e9b97cd548910354297ff6e605df094a03175)) +* Update actions/upload-artifact action to v3.1.3 ([#2867](https://github.com/googleapis/java-bigquery/issues/2867)) ([cbbf0fb](https://github.com/googleapis/java-bigquery/commit/cbbf0fb8a99c0633335d81cd36a7b53dfe9df20b)) +* Update dependency com.google.api.grpc:proto-google-cloud-bigqueryconnection-v1 to v2.26.0 ([#2873](https://github.com/googleapis/java-bigquery/issues/2873)) ([6196625](https://github.com/googleapis/java-bigquery/commit/6196625d614ce80641008ffab3b5bf9720651bb9)) +* Update dependency com.google.cloud:google-cloud-datacatalog-bom to v1.30.0 ([#2874](https://github.com/googleapis/java-bigquery/issues/2874)) ([6cafedf](https://github.com/googleapis/java-bigquery/commit/6cafedf634bc88f41b2b5d3ec1425341b02ac8b6)) +* Update dependency com.google.cloud:google-cloud-shared-dependencies to v3.15.0 ([#2870](https://github.com/googleapis/java-bigquery/issues/2870)) ([f24439b](https://github.com/googleapis/java-bigquery/commit/f24439b7adf1f08cee4b65918b4395861fe88517)) +* Update dependency org.graalvm.buildtools:junit-platform-native to v0.9.26 ([#2868](https://github.com/googleapis/java-bigquery/issues/2868)) ([d01031c](https://github.com/googleapis/java-bigquery/commit/d01031cbc6d50f9aff8c6d49a8d2c54496779451)) +* Update dependency org.graalvm.buildtools:native-maven-plugin to v0.9.26 ([#2869](https://github.com/googleapis/java-bigquery/issues/2869)) ([edd7141](https://github.com/googleapis/java-bigquery/commit/edd714129b65d73f894591c4d40e1a8e79c36b04)) + ## [2.31.2](https://github.com/googleapis/java-bigquery/compare/v2.31.1...v2.31.2) (2023-09-05) diff --git a/README.md b/README.md index aceecda141..d5521d9866 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ If you are using Maven without the BOM, add this to your dependencies: com.google.cloud google-cloud-bigquery - 2.31.0 + 2.31.2 ``` @@ -60,13 +60,13 @@ implementation 'com.google.cloud:google-cloud-bigquery' If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-bigquery:2.31.1' +implementation 'com.google.cloud:google-cloud-bigquery:2.31.2' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.31.1" +libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.31.2" ``` @@ -351,7 +351,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-bigquery/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-bigquery.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.31.1 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.31.2 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles diff --git a/benchmark/pom.xml b/benchmark/pom.xml index dde17cb100..7f06c92456 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -6,7 +6,7 @@ google-cloud-bigquery-parent com.google.cloud - 2.31.2 + 2.32.0 diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml index 41067bd213..eaeeded132 100644 --- a/google-cloud-bigquery/clirr-ignored-differences.xml +++ b/google-cloud-bigquery/clirr-ignored-differences.xml @@ -104,4 +104,9 @@ com/google/cloud/bigquery/IndexUnusedReason* *BaseTable(*) + + 7013 + com/google/cloud/bigquery/DatasetInfo* + *setExternalDatasetReference(*) + \ No newline at end of file diff --git a/google-cloud-bigquery/pom.xml b/google-cloud-bigquery/pom.xml index 5ec3e04a6a..f7fdee1068 100644 --- a/google-cloud-bigquery/pom.xml +++ b/google-cloud-bigquery/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-bigquery - 2.31.2 + 2.32.0 jar BigQuery https://github.com/googleapis/java-bigquery @@ -11,7 +11,7 @@ com.google.cloud google-cloud-bigquery-parent - 2.31.2 + 2.32.0 google-cloud-bigquery 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 5f9fea892f..3ed4b89287 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 @@ -152,6 +152,12 @@ public Builder setDefaultCollation(String defaultCollation) { return this; } + @Override + public Builder setExternalDatasetReference(ExternalDatasetReference externalDatasetReference) { + infoBuilder.setExternalDatasetReference(externalDatasetReference); + 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 bd209952e8..44583e0c85 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 @@ -73,6 +73,7 @@ public Dataset apply(DatasetInfo datasetInfo) { private final EncryptionConfiguration defaultEncryptionConfiguration; private final Long defaultPartitionExpirationMs; private final String defaultCollation; + private final ExternalDatasetReference externalDatasetReference; /** A builder for {@code DatasetInfo} objects. */ public abstract static class Builder { @@ -127,6 +128,13 @@ public abstract static class Builder { public abstract Builder setLabels(Map labels); + /** + * Optional. Information about the external metadata storage where the dataset is defined. + * Filled out when the dataset type is EXTERNAL + */ + public abstract Builder setExternalDatasetReference( + ExternalDatasetReference externalDatasetReference); + /** * The default encryption key for all tables in the dataset. Once this property is set, all * newly-created partitioned tables in the dataset will have encryption key set to this value, @@ -183,6 +191,7 @@ static final class BuilderImpl extends Builder { private EncryptionConfiguration defaultEncryptionConfiguration; private Long defaultPartitionExpirationMs; private String defaultCollation; + private ExternalDatasetReference externalDatasetReference; BuilderImpl() {} @@ -202,6 +211,7 @@ static final class BuilderImpl extends Builder { this.defaultEncryptionConfiguration = datasetInfo.defaultEncryptionConfiguration; this.defaultPartitionExpirationMs = datasetInfo.defaultPartitionExpirationMs; this.defaultCollation = datasetInfo.defaultCollation; + this.externalDatasetReference = datasetInfo.externalDatasetReference; } BuilderImpl(com.google.api.services.bigquery.model.Dataset datasetPb) { @@ -236,6 +246,10 @@ public Acl apply(Dataset.Access accessPb) { } this.defaultPartitionExpirationMs = datasetPb.getDefaultPartitionExpirationMs(); this.defaultCollation = datasetPb.getDefaultCollation(); + if (datasetPb.getExternalDatasetReference() != null) { + this.externalDatasetReference = + ExternalDatasetReference.fromPb(datasetPb.getExternalDatasetReference()); + } } @Override @@ -336,6 +350,12 @@ public Builder setDefaultCollation(String defaultCollation) { return this; } + @Override + public Builder setExternalDatasetReference(ExternalDatasetReference externalDatasetReference) { + this.externalDatasetReference = externalDatasetReference; + return this; + } + @Override public DatasetInfo build() { return new DatasetInfo(this); @@ -358,6 +378,7 @@ public DatasetInfo build() { defaultEncryptionConfiguration = builder.defaultEncryptionConfiguration; defaultPartitionExpirationMs = builder.defaultPartitionExpirationMs; defaultCollation = builder.defaultCollation; + externalDatasetReference = builder.externalDatasetReference; } /** Returns the dataset identity. */ @@ -487,6 +508,14 @@ public String getDefaultCollation() { return defaultCollation; } + /** + * Returns information about the external metadata storage where the dataset is defined. Filled + * out when the dataset type is EXTERNAL. + */ + public ExternalDatasetReference getExternalDatasetReference() { + return externalDatasetReference; + } + /** Returns a builder for the dataset object. */ public Builder toBuilder() { return new BuilderImpl(this); @@ -510,6 +539,7 @@ public String toString() { .add("defaultEncryptionConfiguration", defaultEncryptionConfiguration) .add("defaultPartitionExpirationMs", defaultPartitionExpirationMs) .add("defaultCollation", defaultCollation) + .add("externalDatasetReference", externalDatasetReference) .toString(); } @@ -588,6 +618,9 @@ public Dataset.Access apply(Acl acl) { if (defaultCollation != null) { datasetPb.setDefaultCollation(defaultCollation); } + if (externalDatasetReference != null) { + datasetPb.setExternalDatasetReference(externalDatasetReference.toPb()); + } return datasetPb; } diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalDatasetReference.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalDatasetReference.java new file mode 100644 index 0000000000..ecfe54c50c --- /dev/null +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalDatasetReference.java @@ -0,0 +1,79 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import com.google.auto.value.AutoValue; +import com.google.common.annotations.VisibleForTesting; +import java.io.Serializable; +import javax.annotation.Nullable; + +/** Configures the access a dataset defined in an external metadata storage. */ +@AutoValue +public abstract class ExternalDatasetReference implements Serializable { + + public static ExternalDatasetReference.Builder newBuilder() { + return new AutoValue_ExternalDatasetReference.Builder(); + } + + static ExternalDatasetReference fromPb( + com.google.api.services.bigquery.model.ExternalDatasetReference externalDatasetReference) { + ExternalDatasetReference.Builder builder = newBuilder(); + + if (externalDatasetReference.getConnection() != null) { + builder.setConnection(externalDatasetReference.getConnection()); + } + if (externalDatasetReference.getExternalSource() != null) { + builder.setExternalSource(externalDatasetReference.getExternalSource()); + } + + return builder.build(); + } + + public com.google.api.services.bigquery.model.ExternalDatasetReference toPb() { + com.google.api.services.bigquery.model.ExternalDatasetReference externalDatasetReference = + new com.google.api.services.bigquery.model.ExternalDatasetReference(); + + externalDatasetReference.setConnection(getConnection()); + externalDatasetReference.setExternalSource(getExternalSource()); + return externalDatasetReference; + } + + @Nullable + public abstract String getConnection(); + + @Nullable + public abstract String getExternalSource(); + + /** Returns a builder for an ExternalDatasetReference. */ + @VisibleForTesting + public abstract ExternalDatasetReference.Builder toBuilder(); + + @AutoValue.Builder + public abstract static class Builder { + /** + * The connection id that is used to access the external_source. Format: + * projects/{project_id}/locations/{location_id}/connections/{connection_id} * + */ + public abstract ExternalDatasetReference.Builder setConnection(String connection); + + /** External source that backs this dataset * */ + public abstract ExternalDatasetReference.Builder setExternalSource(String externalSource); + + /** Creates a {@code ExternalDatasetReference} object. */ + public abstract ExternalDatasetReference build(); + } +} diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FieldValue.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FieldValue.java index 58c012a60e..ea68075f7f 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FieldValue.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FieldValue.java @@ -27,10 +27,16 @@ import java.io.Serializable; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.Duration; import java.time.Instant; +import java.time.Period; +import java.time.format.DateTimeParseException; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.threeten.extra.PeriodDuration; /** * Google BigQuery Table Field Value class. Objects of this class represent values of a BigQuery @@ -237,6 +243,28 @@ public List getRepeatedValue() { return (List) value; } + /** + * Returns this field's value as a {@link org.threeten.extra.PeriodDuration}. This method should + * be used if the corresponding field has {@link StandardSQLTypeName#INTERVAL} type, or if it is a + * legal canonical format "[sign]Y-M [sign]D [sign]H:M:S[.F]", e.g. "123-7 -19 0:24:12.000006" or + * ISO 8601. + * + * @throws ClassCastException if the field is not a primitive type + * @throws NullPointerException if {@link #isNull()} returns {@code true} + * @throws IllegalArgumentException if the field cannot be converted to a legal interval + */ + @SuppressWarnings("unchecked") + public PeriodDuration getPeriodDuration() { + checkNotNull(value); + try { + // Try parsing from ISO 8601 + return PeriodDuration.parse(getStringValue()); + } catch (DateTimeParseException dateTimeParseException) { + // Try parsing from canonical interval format + return parseCanonicalInterval(getStringValue()); + } + } + /** * Returns this field's value as a {@link FieldValueList} instance. This method should only be * used if the corresponding field has {@link LegacySQLTypeName#RECORD} type (i.e. {@link @@ -325,4 +353,63 @@ static FieldValue fromPb(Object cellPb, Field recordSchema) { } throw new IllegalArgumentException("Unexpected table cell format"); } + + /** + * Parse interval in canonical format and create instance of {@code PeriodDuration}. + * + *

The parameter {@code interval} should be an interval in the canonical format: "[sign]Y-M + * [sign]D [sign]H:M:S[.F]". More details + * here + * + * @throws IllegalArgumentException if the {@code interval} is not a valid interval + */ + static PeriodDuration parseCanonicalInterval(String interval) throws IllegalArgumentException { + // Pattern is [sign]Y-M [sign]D [sign]H:M:S[.F] + Pattern pattern = + Pattern.compile( + "(?[+-])?(?\\d+)-(?\\d+) (?[-|+])?(?\\d+) (?[-|+])?(?\\d+):(?\\d+):(?\\d+)(\\.(?\\d+))?"); + Matcher matcher = pattern.matcher(interval); + if (!matcher.find()) { + throw new IllegalArgumentException(); + } + String sign1 = matcher.group("sign1"); + String year = matcher.group("year"); + String month = matcher.group("month"); + String sign2 = matcher.group("sign2"); + String day = matcher.group("day"); + String sign3 = matcher.group("sign3"); + String hours = matcher.group("hours"); + String minutes = matcher.group("minutes"); + String seconds = matcher.group("seconds"); + String fraction = matcher.group("fraction"); + + int yearInt = Integer.parseInt(year); + int monthInt = Integer.parseInt(month); + if (Objects.equals(sign1, "-")) { + yearInt *= -1; + monthInt *= -1; + } + + int dayInt = Integer.parseInt(day); + if (Objects.equals(sign2, "-")) { + dayInt *= -1; + } + if (sign3 == null) { + sign3 = ""; + } + + String durationString = + sign3 + + "PT" + + hours + + "H" + + minutes + + "M" + + seconds + + (fraction == null ? "" : "." + fraction) + + "S"; + + return PeriodDuration.of(Period.of(yearInt, monthInt, dayInt), Duration.parse(durationString)); + } } 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 453701e3a8..c91cbc2f30 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 @@ -58,6 +58,12 @@ public class DatasetInfoTest { private static final DatasetId DATASET_ID_COMPLETE = DatasetId.of("project", "dataset"); private static final EncryptionConfiguration DATASET_ENCRYPTION_CONFIGURATION = EncryptionConfiguration.newBuilder().setKmsKeyName("KMS_KEY_1").build(); + + private static final ExternalDatasetReference EXTERNAL_DATASET_REFERENCE = + ExternalDatasetReference.newBuilder() + .setExternalSource("source") + .setConnection("connection") + .build(); private static final DatasetInfo DATASET_INFO = DatasetInfo.newBuilder(DATASET_ID) .setAcl(ACCESS_RULES) @@ -82,6 +88,8 @@ public class DatasetInfoTest { .build(); private static final DatasetInfo DATASET_INFO_COMPLETE_WITH_IAM_MEMBER = DATASET_INFO.toBuilder().setAcl(ACCESS_RULES_IAM_MEMBER).build(); + private static final DatasetInfo DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE = + DATASET_INFO.toBuilder().setExternalDatasetReference(EXTERNAL_DATASET_REFERENCE).build(); @Test public void testToBuilder() { @@ -108,6 +116,28 @@ public void testToBuilderIncomplete() { assertEquals(datasetInfo, datasetInfo.toBuilder().build()); } + @Test + public void testToBuilderWithExternalDatasetReference() { + compareDatasets( + DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE, + DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE.toBuilder().build()); + + ExternalDatasetReference externalDatasetReference = + ExternalDatasetReference.newBuilder() + .setExternalSource("source2") + .setConnection("connection2") + .build(); + DatasetInfo datasetInfo = + DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE + .toBuilder() + .setExternalDatasetReference(externalDatasetReference) + .build(); + assertEquals(externalDatasetReference, datasetInfo.getExternalDatasetReference()); + datasetInfo = + datasetInfo.toBuilder().setExternalDatasetReference(EXTERNAL_DATASET_REFERENCE).build(); + compareDatasets(DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE, datasetInfo); + } + @Test public void testBuilder() { assertNull(DATASET_INFO.getDatasetId().getProject()); @@ -137,6 +167,9 @@ public void testBuilder() { assertEquals(LOCATION, DATASET_INFO_COMPLETE.getLocation()); assertEquals(SELF_LINK, DATASET_INFO_COMPLETE.getSelfLink()); assertEquals(LABELS, DATASET_INFO_COMPLETE.getLabels()); + assertEquals( + EXTERNAL_DATASET_REFERENCE, + DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE.getExternalDatasetReference()); } @Test @@ -156,6 +189,7 @@ public void testOf() { assertNull(datasetInfo.getDefaultEncryptionConfiguration()); assertNull(datasetInfo.getDefaultPartitionExpirationMs()); assertTrue(datasetInfo.getLabels().isEmpty()); + assertNull(datasetInfo.getExternalDatasetReference()); datasetInfo = DatasetInfo.of(DATASET_ID); assertEquals(DATASET_ID, datasetInfo.getDatasetId()); @@ -172,11 +206,15 @@ public void testOf() { assertNull(datasetInfo.getDefaultEncryptionConfiguration()); assertNull(datasetInfo.getDefaultPartitionExpirationMs()); assertTrue(datasetInfo.getLabels().isEmpty()); + assertNull(datasetInfo.getExternalDatasetReference()); } @Test public void testToPbAndFromPb() { compareDatasets(DATASET_INFO_COMPLETE, DatasetInfo.fromPb(DATASET_INFO_COMPLETE.toPb())); + compareDatasets( + DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE, + DatasetInfo.fromPb(DATASET_INFO_COMPLETE_WITH_EXTERNAL_DATASET_REFERENCE.toPb())); DatasetInfo datasetInfo = DatasetInfo.newBuilder("project", "dataset").build(); compareDatasets(datasetInfo, DatasetInfo.fromPb(datasetInfo.toPb())); } @@ -204,5 +242,6 @@ private void compareDatasets(DatasetInfo expected, DatasetInfo value) { expected.getDefaultEncryptionConfiguration(), value.getDefaultEncryptionConfiguration()); assertEquals( expected.getDefaultPartitionExpirationMs(), value.getDefaultPartitionExpirationMs()); + assertEquals(expected.getExternalDatasetReference(), value.getExternalDatasetReference()); } } 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 d1c97a6940..b244cf2606 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 @@ -83,6 +83,11 @@ public class DatasetTest { TableInfo.newBuilder( TableId.of(NEW_PROJECT_ID, "dataset", "table3"), EXTERNAL_TABLE_DEFINITION) .build(); + private static final ExternalDatasetReference EXTERNAL_DATASET_REFERENCE = + ExternalDatasetReference.newBuilder() + .setExternalSource("source") + .setConnection("connection") + .build(); @Rule public MockitoRule rule; @@ -319,6 +324,31 @@ public void testToAndFromPb() { compareDataset(expectedDataset, Dataset.fromPb(bigquery, expectedDataset.toPb())); } + @Test + public void testExternalDatasetReference() { + Dataset datasetWithExternalDatasetReference = + new Dataset.Builder(bigquery, DATASET_ID) + .setAcl(ACCESS_RULES) + .setCreationTime(CREATION_TIME) + .setDefaultTableLifetime(DEFAULT_TABLE_EXPIRATION) + .setDescription(DESCRIPTION) + .setEtag(ETAG) + .setFriendlyName(FRIENDLY_NAME) + .setGeneratedId(GENERATED_ID) + .setLastModified(LAST_MODIFIED) + .setLocation(LOCATION) + .setSelfLink(SELF_LINK) + .setLabels(LABELS) + .setExternalDatasetReference(EXTERNAL_DATASET_REFERENCE) + .build(); + assertEquals( + EXTERNAL_DATASET_REFERENCE, + datasetWithExternalDatasetReference.getExternalDatasetReference()); + compareDataset( + datasetWithExternalDatasetReference, + datasetWithExternalDatasetReference.toBuilder().build()); + } + private void compareDataset(Dataset expected, Dataset value) { assertEquals(expected, value); compareDatasetInfo(expected, value); @@ -338,5 +368,6 @@ private void compareDatasetInfo(DatasetInfo expected, DatasetInfo value) { assertEquals(expected.getCreationTime(), value.getCreationTime()); assertEquals(expected.getDefaultTableLifetime(), value.getDefaultTableLifetime()); assertEquals(expected.getLastModified(), value.getLastModified()); + assertEquals(expected.getExternalDatasetReference(), value.getExternalDatasetReference()); } } diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalDatasetReferenceTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalDatasetReferenceTest.java new file mode 100644 index 0000000000..6d241948b8 --- /dev/null +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalDatasetReferenceTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class ExternalDatasetReferenceTest { + private static final String EXTERNAL_SOURCE = "test_source"; + private static final String CONNECTION = "test_connection"; + private static final ExternalDatasetReference EXTERNAL_DATASET_REFERENCE = + ExternalDatasetReference.newBuilder() + .setExternalSource(EXTERNAL_SOURCE) + .setConnection(CONNECTION) + .build(); + + @Test + public void testToBuilder() { + compareExternalDatasetReference( + EXTERNAL_DATASET_REFERENCE, EXTERNAL_DATASET_REFERENCE.toBuilder().build()); + ExternalDatasetReference externalDatasetReference = + EXTERNAL_DATASET_REFERENCE.toBuilder().setExternalSource("test_source2").build(); + assertEquals("test_source2", externalDatasetReference.getExternalSource()); + } + + @Test + public void testBuilder() { + assertEquals(EXTERNAL_SOURCE, EXTERNAL_DATASET_REFERENCE.getExternalSource()); + assertEquals(CONNECTION, EXTERNAL_DATASET_REFERENCE.getConnection()); + ExternalDatasetReference externalDatasetReference = + ExternalDatasetReference.newBuilder() + .setExternalSource(EXTERNAL_SOURCE) + .setConnection(CONNECTION) + .build(); + assertEquals(EXTERNAL_DATASET_REFERENCE, externalDatasetReference); + } + + @Test + public void testToAndFromPb() { + ExternalDatasetReference externalDatasetReference = + EXTERNAL_DATASET_REFERENCE.toBuilder().build(); + assertTrue( + ExternalDatasetReference.fromPb(externalDatasetReference.toPb()) + instanceof ExternalDatasetReference); + compareExternalDatasetReference( + externalDatasetReference, ExternalDatasetReference.fromPb(externalDatasetReference.toPb())); + } + + private void compareExternalDatasetReference( + ExternalDatasetReference expected, ExternalDatasetReference value) { + assertEquals(expected.getExternalSource(), value.getExternalSource()); + assertEquals(expected.getConnection(), value.getConnection()); + } +} diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java index e4ec47b472..90cb690618 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/FieldValueTest.java @@ -27,8 +27,13 @@ import com.google.common.collect.ImmutableMap; import com.google.common.io.BaseEncoding; import java.math.BigDecimal; +import java.time.Duration; +import java.time.Period; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Map.Entry; import org.junit.Test; +import org.threeten.extra.PeriodDuration; public class FieldValueTest { @@ -43,6 +48,10 @@ public class FieldValueTest { ImmutableMap.of("v", "123456789.123456789"); private static final Map STRING_FIELD = ImmutableMap.of("v", "string"); private static final Map TIMESTAMP_FIELD = ImmutableMap.of("v", "42"); + private static final Map INTERVAL_FIELD_1 = + ImmutableMap.of("v", "P3Y2M1DT12H34M56.789S"); + private static final Map INTERVAL_FIELD_2 = + ImmutableMap.of("v", "3-2 1 12:34:56.789"); private static final Map BYTES_FIELD = ImmutableMap.of("v", BYTES_BASE64); private static final Map NULL_FIELD = ImmutableMap.of("v", Data.nullOf(String.class)); @@ -74,6 +83,17 @@ public void testFromPb() { value = FieldValue.fromPb(TIMESTAMP_FIELD); assertEquals(FieldValue.Attribute.PRIMITIVE, value.getAttribute()); assertEquals(42000000, value.getTimestampValue()); + value = FieldValue.fromPb(INTERVAL_FIELD_1); + assertEquals(FieldValue.Attribute.PRIMITIVE, value.getAttribute()); + PeriodDuration periodDuration = + PeriodDuration.of(Period.of(3, 2, 1), Duration.parse("PT12H34M56.789S")); + assertEquals(periodDuration, value.getPeriodDuration()); + assertEquals("P3Y2M1DT12H34M56.789S", value.getStringValue()); + value = FieldValue.fromPb(INTERVAL_FIELD_2); + assertEquals(FieldValue.Attribute.PRIMITIVE, value.getAttribute()); + periodDuration = PeriodDuration.of(Period.of(3, 2, 1), Duration.parse("PT12H34M56.789S")); + assertEquals(periodDuration, value.getPeriodDuration()); + assertEquals("3-2 1 12:34:56.789", value.getStringValue()); value = FieldValue.fromPb(BYTES_FIELD); assertEquals(FieldValue.Attribute.PRIMITIVE, value.getAttribute()); assertArrayEquals(BYTES, value.getBytesValue()); @@ -146,4 +166,22 @@ public void testEquals() { assertEquals(recordValue, FieldValue.fromPb(RECORD_FIELD)); assertEquals(recordValue.hashCode(), FieldValue.fromPb(RECORD_FIELD).hashCode()); } + + @Test + public void testParseCanonicalInterval() { + Map intervalToPeriodDuration = new LinkedHashMap<>(); + intervalToPeriodDuration.put( + "125-7 -19 -0:24:12.001", PeriodDuration.parse("P125Y7M-19DT0H-24M-12.001S")); + intervalToPeriodDuration.put("-15-6 23 23:14:05", PeriodDuration.parse("P-15Y-6M23DT23H14M5S")); + intervalToPeriodDuration.put( + "06-01 06 01:01:00.123456", PeriodDuration.parse("P6Y1M6DT1H1M0.123456S")); + intervalToPeriodDuration.put("-0-0 -0 -0:0:0", PeriodDuration.parse("P0Y0M0DT0H0M0S")); + intervalToPeriodDuration.put( + "-99999-99999 9999 999:999:999.999999999", + PeriodDuration.parse("P-99999Y-99999M9999DT999H999M999.999999999S")); + for (Entry entry : intervalToPeriodDuration.entrySet()) { + assertEquals(FieldValue.parseCanonicalInterval(entry.getKey()), entry.getValue()); + System.out.println(FieldValue.parseCanonicalInterval(entry.getKey())); + } + } } 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 bb9c233a45..cf180f9a36 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 @@ -1228,8 +1228,11 @@ public void testIntervalType() throws InterruptedException { .build(); TableResult result = bigquery.query(queryJobConfiguration); assertNotNull(result.getJobId()); + PeriodDuration periodDuration = + PeriodDuration.of(Period.of(125, 7, -19), java.time.Duration.parse("PT24M12.000006S")); for (FieldValueList values : result.iterateAll()) { assertEquals("125-7 -19 0:24:12.000006", values.get(0).getValue()); + assertEquals(periodDuration, values.get(0).getPeriodDuration()); } } finally { assertTrue(bigquery.delete(tableId)); diff --git a/pom.xml b/pom.xml index 7628435f20..ed6e9d9646 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-bigquery-parent pom - 2.31.2 + 2.32.0 BigQuery Parent https://github.com/googleapis/java-bigquery @@ -54,8 +54,8 @@ UTF-8 github google-cloud-bigquery-parent - v2-rev20230805-2.0.0 - 3.14.0 + v2-rev20230812-2.0.0 + 3.15.0 12.0.1 @@ -73,7 +73,7 @@ com.google.cloud google-cloud-bigquerystorage-bom - 2.41.1 + 2.42.0 pom import @@ -97,7 +97,7 @@ com.google.cloud google-cloud-datacatalog-bom - 1.29.0 + 1.30.0 pom import @@ -111,7 +111,7 @@ com.google.cloud google-cloud-bigquery - 2.31.2 + 2.32.0 @@ -155,19 +155,19 @@ com.google.cloud google-cloud-storage - 2.26.0 + 2.27.0 test com.google.cloud google-cloud-bigqueryconnection - 2.25.0 + 2.26.0 test com.google.api.grpc proto-google-cloud-bigqueryconnection-v1 - 2.25.0 + 2.26.0 test diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 5c186115b7..0b6b5994bb 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -45,7 +45,7 @@ com.google.cloud google-cloud-bigquery - 2.31.0 + 2.31.2 @@ -63,13 +63,13 @@ com.google.cloud google-cloud-bigtable - 2.25.1 + 2.26.0 test com.google.cloud google-cloud-bigqueryconnection - 2.25.0 + 2.26.0 test diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml index 186ea50ab2..7f18e0025f 100644 --- a/samples/native-image-sample/pom.xml +++ b/samples/native-image-sample/pom.xml @@ -99,7 +99,7 @@ org.graalvm.buildtools junit-platform-native - 0.9.24 + 0.9.26 test @@ -121,7 +121,7 @@ org.graalvm.buildtools native-maven-plugin - 0.9.24 + 0.9.26 true com.example.bigquery.NativeImageBigquerySample diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index c811b89f9c..f602d39b95 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -44,7 +44,7 @@ com.google.cloud google-cloud-bigquery - 2.31.2 + 2.32.0 @@ -61,13 +61,13 @@ com.google.cloud google-cloud-bigtable - 2.25.1 + 2.26.0 test com.google.cloud google-cloud-bigqueryconnection - 2.25.0 + 2.26.0 test diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 080f1e84cf..2e8a7890d2 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -79,13 +79,13 @@ com.google.cloud google-cloud-bigtable - 2.25.1 + 2.26.0 test com.google.cloud google-cloud-bigqueryconnection - 2.25.0 + 2.26.0 test diff --git a/versions.txt b/versions.txt index c9aaacf02c..0b7ba086a6 100644 --- a/versions.txt +++ b/versions.txt @@ -1,4 +1,4 @@ # Format: # module:released-version:current-version -google-cloud-bigquery:2.31.2:2.31.2 \ No newline at end of file +google-cloud-bigquery:2.32.0:2.32.0 \ No newline at end of file