diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index d5500ef44..52eaa54d8 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/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index a37ac497e..9583d638c 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -16,6 +16,7 @@ branchProtectionRules: - 'Kokoro - Test: Integration' - cla/google - OwlBot Post Processor + - javadoc - pattern: 1.127.12-sp isAdminEnforced: true requiredApprovingReviewCount: 1 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index fa10a2473..4959517d4 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/.gitignore b/.gitignore index 1c7a7e78f..c94c87d10 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ __pycache__ .new-list.txt .org-list.txt SimpleBenchmarkApp/src/main/java/com/google/cloud/App.java -.flattened-pom.xml \ No newline at end of file +.flattened-pom.xml +# Local Test files +*ITLocalTest.java \ No newline at end of file diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 32989051e..a73256ab8 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 4cd11b173..3c833f4b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## [2.31.2](https://github.com/googleapis/java-bigquery/compare/v2.31.1...v2.31.2) (2023-09-05) + + +### Bug Fixes + +* Hide TableReference data struct ([#2855](https://github.com/googleapis/java-bigquery/issues/2855)) ([2cbded6](https://github.com/googleapis/java-bigquery/commit/2cbded6600af1de8ec15b04a2496733ad2b50c47)) +* SearchStats IndexUnusedReasons null bug ([#2825](https://github.com/googleapis/java-bigquery/issues/2825)) ([309ea60](https://github.com/googleapis/java-bigquery/commit/309ea607a9ff50e59dc4e1069c689c1da9605ed5)) + +## [2.31.1](https://github.com/googleapis/java-bigquery/compare/v2.31.0...v2.31.1) (2023-08-09) + + +### Dependencies + +* Update dependency com.google.api.grpc:proto-google-cloud-bigqueryconnection-v1 to v2.25.0 ([#2845](https://github.com/googleapis/java-bigquery/issues/2845)) ([d940f8d](https://github.com/googleapis/java-bigquery/commit/d940f8d7f119d75aaa80eb60babd5406fca76c69)) +* Update dependency com.google.cloud:google-cloud-datacatalog-bom to v1.29.0 ([#2846](https://github.com/googleapis/java-bigquery/issues/2846)) ([87a0a10](https://github.com/googleapis/java-bigquery/commit/87a0a10d806fdcbf4bdb1ee1478b9ee6aeb7b287)) +* Update dependency com.google.cloud:google-cloud-shared-dependencies to v3.14.0 ([#2834](https://github.com/googleapis/java-bigquery/issues/2834)) ([79fe14c](https://github.com/googleapis/java-bigquery/commit/79fe14c08836b40bf84775a526cba32f63dd8227)) +* Update dependency org.graalvm.buildtools:junit-platform-native to v0.9.24 ([#2839](https://github.com/googleapis/java-bigquery/issues/2839)) ([ae752bc](https://github.com/googleapis/java-bigquery/commit/ae752bc36c516e1a4172bc0c9cfa7ed6bbcbe0e7)) +* Update dependency org.graalvm.buildtools:native-maven-plugin to v0.9.24 ([#2840](https://github.com/googleapis/java-bigquery/issues/2840)) ([1ae6cb9](https://github.com/googleapis/java-bigquery/commit/1ae6cb9b20152e00db9a559ff143faca581bf8b1)) +* Update github/codeql-action action to v2.21.1 ([#2824](https://github.com/googleapis/java-bigquery/issues/2824)) ([9978971](https://github.com/googleapis/java-bigquery/commit/997897166ba121256b7fa6f4c63f83daebdc6a54)) +* Update jmh.version to v1.37 ([#2836](https://github.com/googleapis/java-bigquery/issues/2836)) ([4b3a3c2](https://github.com/googleapis/java-bigquery/commit/4b3a3c22985c76f7e861341dc76e96abc970eaec)) + ## [2.31.0](https://github.com/googleapis/java-bigquery/compare/v2.30.1...v2.31.0) (2023-07-25) diff --git a/README.md b/README.md index 1d99e65b8..1665fb7d1 100644 --- a/README.md +++ b/README.md @@ -53,20 +53,20 @@ If you are using Maven without the BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.21.0') +implementation platform('com.google.cloud:libraries-bom:26.22.0') 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.0' +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.0" +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.0 +[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 49f85f3fb..479eecb8a 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -6,12 +6,12 @@ google-cloud-bigquery-parent com.google.cloud - 2.31.0 + 2.31.3-SNAPSHOT UTF-8 - 1.36 + 1.37 benchmark diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml index 500ce3f58..eaeeded13 100644 --- a/google-cloud-bigquery/clirr-ignored-differences.xml +++ b/google-cloud-bigquery/clirr-ignored-differences.xml @@ -94,4 +94,19 @@ com/google/cloud/bigquery/TableInfo* *TableConstraints(*) + + 7013 + com/google/cloud/bigquery/IndexUnusedReason* + *BaseTableId(*) + + + 7002 + 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 4805f519d..d1441f1a7 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.0 + 2.31.3-SNAPSHOT jar BigQuery https://github.com/googleapis/java-bigquery @@ -11,7 +11,7 @@ com.google.cloud google-cloud-bigquery-parent - 2.31.0 + 2.31.3-SNAPSHOT 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 5f9fea892..3ed4b8928 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 bd209952e..44583e0c8 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 000000000..ecfe54c50 --- /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 58c012a60..ea68075f7 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/main/java/com/google/cloud/bigquery/IndexUnusedReason.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/IndexUnusedReason.java index 06a88b068..bb4f0c3c3 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/IndexUnusedReason.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/IndexUnusedReason.java @@ -16,7 +16,6 @@ package com.google.cloud.bigquery; -import com.google.api.services.bigquery.model.TableReference; import com.google.auto.value.AutoValue; import java.io.Serializable; import javax.annotation.Nullable; @@ -52,9 +51,9 @@ public abstract static class Builder { /** * Specifies the base table involved in the reason that no search index was used. * - * @param tableReference tableReference or {@code null} for none + * @param baseTable baseTable or {@code null} for none */ - public abstract Builder setBaseTable(TableReference tableReference); + public abstract Builder setBaseTableId(TableId baseTable); /** Creates a @code IndexUnusedReason} object. */ public abstract IndexUnusedReason build(); @@ -96,7 +95,7 @@ public static Builder newBuilder() { * @return value or {@code null} for none */ @Nullable - public abstract TableReference getBaseTable(); + public abstract TableId getBaseTableId(); com.google.api.services.bigquery.model.IndexUnusedReason toPb() { com.google.api.services.bigquery.model.IndexUnusedReason indexUnusedReason = @@ -110,8 +109,8 @@ com.google.api.services.bigquery.model.IndexUnusedReason toPb() { if (getMessage() != null) { indexUnusedReason.setMessage(indexUnusedReason.getMessage()); } - if (getBaseTable() != null) { - indexUnusedReason.setBaseTable(indexUnusedReason.getBaseTable()); + if (getBaseTableId() != null) { + indexUnusedReason.setBaseTable(getBaseTableId().toPb()); } return indexUnusedReason; } @@ -129,7 +128,7 @@ static IndexUnusedReason fromPb( builder.setMessage(indexUnusedReason.getMessage()); } if (indexUnusedReason.getBaseTable() != null) { - builder.setBaseTable(indexUnusedReason.getBaseTable()); + builder.setBaseTableId(TableId.fromPb(indexUnusedReason.getBaseTable())); } return builder.build(); } diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/SearchStats.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/SearchStats.java index 73b812383..237b83ca7 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/SearchStats.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/SearchStats.java @@ -68,7 +68,7 @@ SearchStatistics toPb() { searchStatistics.setIndexUsageMode(getIndexUsageMode()); } if (getIndexUnusedReasons() != null) { - searchStatistics.setIndexUnusedReason( + searchStatistics.setIndexUnusedReasons( getIndexUnusedReasons().stream() .map(IndexUnusedReason::toPb) .collect(Collectors.toList())); @@ -81,9 +81,9 @@ static SearchStats fromPb(SearchStatistics searchStatistics) { if (searchStatistics.getIndexUsageMode() != null) { builder.setIndexUsageMode(searchStatistics.getIndexUsageMode()); } - if (searchStatistics.getIndexUnusedReason() != null) { + if (searchStatistics.getIndexUnusedReasons() != null) { builder.setIndexUnusedReasons( - searchStatistics.getIndexUnusedReason().stream() + searchStatistics.getIndexUnusedReasons().stream() .map(IndexUnusedReason::fromPb) .collect(Collectors.toList())); } 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 453701e3a..c91cbc2f3 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 d1c97a694..b244cf260 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 000000000..6d241948b --- /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 e4ec47b47..90cb69061 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 8c5742e57..cf180f9a3 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)); @@ -5090,7 +5093,7 @@ public void testQueryJobWithLabels() throws InterruptedException, TimeoutExcepti } @Test - public void testQueryJobWithSearchReturnsSearchStatistics() throws InterruptedException { + public void testQueryJobWithSearchReturnsSearchStatisticsUnused() throws InterruptedException { String tableName = "test_query_job_table"; String query = "SELECT * FROM " @@ -5109,6 +5112,10 @@ public void testQueryJobWithSearchReturnsSearchStatistics() throws InterruptedEx JobStatistics.QueryStatistics stats = remoteJob.getStatistics(); assertNotNull(stats.getSearchStats()); assertEquals(stats.getSearchStats().getIndexUsageMode(), "UNUSED"); + assertNotNull(stats.getSearchStats().getIndexUnusedReasons()); + assertNotNull( + stats.getSearchStats().getIndexUnusedReasons().get(0).getCode(), + "INDEX_CONFIG_NOT_AVAILABLE"); } finally { bigquery.delete(destinationTable); } diff --git a/pom.xml b/pom.xml index 0dbceabc2..c7af98af7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-bigquery-parent pom - 2.31.0 + 2.31.3-SNAPSHOT BigQuery Parent https://github.com/googleapis/java-bigquery @@ -54,8 +54,8 @@ UTF-8 github google-cloud-bigquery-parent - v2-rev20230520-2.0.0 - 3.13.1 + v2-rev20230812-2.0.0 + 3.15.0 12.0.1 @@ -73,7 +73,7 @@ com.google.cloud google-cloud-bigquerystorage-bom - 2.41.0 + 2.42.0 pom import @@ -97,7 +97,7 @@ com.google.cloud google-cloud-datacatalog-bom - 1.28.0 + 1.30.0 pom import @@ -111,7 +111,7 @@ com.google.cloud google-cloud-bigquery - 2.31.0 + 2.31.3-SNAPSHOT @@ -155,19 +155,19 @@ com.google.cloud google-cloud-storage - 2.25.0 + 2.26.0 test com.google.cloud google-cloud-bigqueryconnection - 2.24.0 + 2.26.0 test com.google.api.grpc proto-google-cloud-bigqueryconnection-v1 - 2.24.0 + 2.26.0 test diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 1f70566b0..e307f5c09 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -69,7 +69,7 @@ com.google.cloud google-cloud-bigqueryconnection - 2.24.0 + 2.26.0 test diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml index cb48b02c3..7f18e0025 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.23 + 0.9.26 test @@ -121,7 +121,7 @@ org.graalvm.buildtools native-maven-plugin - 0.9.23 + 0.9.26 true com.example.bigquery.NativeImageBigquerySample diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 0c1b73ba3..6d3190ee2 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -44,7 +44,7 @@ com.google.cloud google-cloud-bigquery - 2.31.0 + 2.31.3-SNAPSHOT @@ -67,7 +67,7 @@ com.google.cloud google-cloud-bigqueryconnection - 2.24.0 + 2.26.0 test diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 8e218a2ba..e9e85bf7e 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -85,7 +85,7 @@ com.google.cloud google-cloud-bigqueryconnection - 2.24.0 + 2.26.0 test diff --git a/versions.txt b/versions.txt index ed5fb17ab..49aa7879b 100644 --- a/versions.txt +++ b/versions.txt @@ -1,4 +1,4 @@ # Format: # module:released-version:current-version -google-cloud-bigquery:2.31.0:2.31.0 \ No newline at end of file +google-cloud-bigquery:2.31.2:2.31.3-SNAPSHOT \ No newline at end of file