diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index be3b9bde4..9786771c4 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-java:latest - digest: sha256:7062473f423f339256346ddbee3d81fb1de6b784fabc2a4d959d7df2c720e375 + digest: sha256:3c950ed12391ebaffd1ee66d0374766a1c50144ebe6a7a0042300b2e6bb5856b diff --git a/.github/workflows/approve-readme.yaml b/.github/workflows/approve-readme.yaml index c51324279..1bb182327 100644 --- a/.github/workflows/approve-readme.yaml +++ b/.github/workflows/approve-readme.yaml @@ -1,3 +1,18 @@ +# Copyright 2022 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. +# Github action job to test core java library features on +# downstream client libraries before they are released. on: pull_request: name: auto-merge-readme diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index 59c7cadde..18e23230d 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -1,3 +1,18 @@ +# Copyright 2022 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. +# Github action job to test core java library features on +# downstream client libraries before they are released. on: pull_request: name: auto-release @@ -16,13 +31,13 @@ jobs: return; } - // only approve PRs like "chore: release " - if ( !context.payload.pull_request.title.startsWith("chore: release") ) { + // only approve PRs like "chore(main): release " + if ( !context.payload.pull_request.title.startsWith("chore(main): release") ) { return; } // only approve PRs with pom.xml and versions.txt changes - const filesPromise = github.pulls.listFiles.endpoint({ + const filesPromise = github.rest.pulls.listFiles.endpoint({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.payload.pull_request.number, @@ -54,7 +69,7 @@ jobs: return; } - const promise = github.pulls.list.endpoint({ + const promise = github.rest.pulls.list.endpoint({ owner: context.repo.owner, repo: context.repo.repo, state: 'open' @@ -71,7 +86,7 @@ jobs: } // approve release PR - await github.pulls.createReview({ + await github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, body: 'Rubber stamped release!', @@ -80,7 +95,7 @@ jobs: }); // attach kokoro:force-run and automerge labels - await github.issues.addLabels({ + await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 05de1f60d..6b5e56aaa 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,3 +1,18 @@ +# Copyright 2022 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. +# Github action job to test core java library features on +# downstream client libraries before they are released. on: push: branches: diff --git a/.github/workflows/samples.yaml b/.github/workflows/samples.yaml index c46230a78..d5d964df1 100644 --- a/.github/workflows/samples.yaml +++ b/.github/workflows/samples.yaml @@ -1,3 +1,18 @@ +# Copyright 2022 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. +# Github action job to test core java library features on +# downstream client libraries before they are released. on: pull_request: name: samples diff --git a/.kokoro/build.bat b/.kokoro/build.bat index 05826ad93..cc602c9eb 100644 --- a/.kokoro/build.bat +++ b/.kokoro/build.bat @@ -1,3 +1,18 @@ :: See documentation in type-shell-output.bat +# Copyright 2022 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. +# Github action job to test core java library features on +# downstream client libraries before they are released. "C:\Program Files\Git\bin\bash.exe" %~dp0build.sh diff --git a/.kokoro/nightly/java11-integration.cfg b/.kokoro/nightly/java11-integration.cfg new file mode 100644 index 000000000..58049cc38 --- /dev/null +++ b/.kokoro/nightly/java11-integration.cfg @@ -0,0 +1,37 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-public-resources/java11014" +} + +env_vars: { + key: "JOB_TYPE" + value: "integration" +} +# TODO: remove this after we've migrated all tests and scripts +env_vars: { + key: "GCLOUD_PROJECT" + value: "gcloud-devel" +} + +env_vars: { + key: "GOOGLE_CLOUD_PROJECT" + value: "gcloud-devel" +} + +env_vars: { + key: "ENABLE_FLAKYBOT" + value: "true" +} + +env_vars: { + key: "GOOGLE_APPLICATION_CREDENTIALS" + value: "secret_manager/java-it-service-account" +} + +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "java-it-service-account" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 20c9d3e50..8e9adc217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [2.9.0](https://github.com/googleapis/java-bigquery/compare/v2.8.0...v2.9.0) (2022-02-11) + + +### Features + +* add Interval type support ([#1844](https://github.com/googleapis/java-bigquery/issues/1844)) ([fd3751a](https://github.com/googleapis/java-bigquery/commit/fd3751a44be8f6401ea4b13684f862177ee9e976)) + + +### Documentation + +* **sample:** Add sample for native image support in Bigquery ([#1829](https://github.com/googleapis/java-bigquery/issues/1829)) ([7bb6c79](https://github.com/googleapis/java-bigquery/commit/7bb6c79e4839f183dda021ddf81a3961efd752d6)) + + +### Dependencies + +* update actions/github-script action to v6 ([#1847](https://github.com/googleapis/java-bigquery/issues/1847)) ([7ffe963](https://github.com/googleapis/java-bigquery/commit/7ffe963043ae8b243f1e351a5fffd992f3fcbbb5)) +* update dependency com.google.cloud:google-cloud-bigtable to v2.5.3 ([#1840](https://github.com/googleapis/java-bigquery/issues/1840)) ([88fc05f](https://github.com/googleapis/java-bigquery/commit/88fc05f3233e4e3a9cdfa73eff9856e4fd6fb1c7)) +* update dependency com.google.cloud:google-cloud-storage to v2.4.0 ([#1828](https://github.com/googleapis/java-bigquery/issues/1828)) ([d628fff](https://github.com/googleapis/java-bigquery/commit/d628fff9b899e13c75aaf26d42bfc553c48a3c4e)) +* update dependency com.google.cloud:google-cloud-storage to v2.4.1 ([#1839](https://github.com/googleapis/java-bigquery/issues/1839)) ([e8ebd5c](https://github.com/googleapis/java-bigquery/commit/e8ebd5c2ed29f26aa004e1bdf59ab2e7afb2963c)) +* update dependency com.google.cloud:native-image-support to v0.12.0 ([#1832](https://github.com/googleapis/java-bigquery/issues/1832)) ([1d27b30](https://github.com/googleapis/java-bigquery/commit/1d27b309e2fa6cdc99fc08234390a065d7ca1098)) +* update dependency com.google.cloud:native-image-support to v0.12.1 ([#1841](https://github.com/googleapis/java-bigquery/issues/1841)) ([15918a1](https://github.com/googleapis/java-bigquery/commit/15918a1fa006734ee265ccc569facb8958a1d0bb)) +* update dependency com.google.cloud:native-image-support to v0.12.2 ([#1843](https://github.com/googleapis/java-bigquery/issues/1843)) ([56e6acf](https://github.com/googleapis/java-bigquery/commit/56e6acf4def66c4c298fa7bb6b38025db9faee68)) +* update dependency com.google.cloud:native-image-support to v0.12.3 ([#1845](https://github.com/googleapis/java-bigquery/issues/1845)) ([b64b441](https://github.com/googleapis/java-bigquery/commit/b64b441bf4d0e79434e556f1fdb9ec0083d5baec)) +* update dependency com.google.oauth-client:google-oauth-client-java6 to v1.33.1 ([#1835](https://github.com/googleapis/java-bigquery/issues/1835)) ([7680714](https://github.com/googleapis/java-bigquery/commit/7680714f4a2d0da798ec3ea613701251cba859ff)) +* update dependency com.google.oauth-client:google-oauth-client-jetty to v1.33.1 ([#1836](https://github.com/googleapis/java-bigquery/issues/1836)) ([950f3cd](https://github.com/googleapis/java-bigquery/commit/950f3cdb3be2571f0519848aa167e67949e06f1e)) + ## [2.8.0](https://github.com/googleapis/java-bigquery/compare/v2.7.1...v2.8.0) (2022-02-02) diff --git a/README.md b/README.md index 0b3f49656..82c393b42 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ See https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/The-Google com.google.cloud libraries-bom - 24.2.0 + 24.3.0 pom import @@ -44,7 +44,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-bigquery - 2.7.1 + 2.8.0 ``` @@ -52,20 +52,20 @@ If you are using Maven without 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:24.2.0') +implementation platform('com.google.cloud:libraries-bom:24.3.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.7.1' +implementation 'com.google.cloud:google-cloud-bigquery:2.8.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.7.1" +libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.8.0" ``` ## Authentication @@ -111,6 +111,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-bigquery/tree | Sample | Source Code | Try it | | --------------------------- | --------------------------------- | ------ | +| Native Image Bigquery Sample | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/native-image-sample/src/main/java/com/example/bigquery/NativeImageBigquerySample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/native-image-sample/src/main/java/com/example/bigquery/NativeImageBigquerySample.java) | | Add Column Load Append | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/AddColumnLoadAppend.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/AddColumnLoadAppend.java) | | Add Empty Column | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/AddEmptyColumn.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/AddEmptyColumn.java) | | Auth Drive Scope | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/AuthDriveScope.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/AuthDriveScope.java) | diff --git a/benchmark/pom.xml b/benchmark/pom.xml index c20b9eb51..8472c7ebb 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -6,7 +6,7 @@ google-cloud-bigquery-parent com.google.cloud - 2.8.0 + 2.9.0 diff --git a/google-cloud-bigquery/pom.xml b/google-cloud-bigquery/pom.xml index 5eee1ea2f..123f95281 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.8.0 + 2.9.0 jar BigQuery https://github.com/googleapis/java-bigquery @@ -11,7 +11,7 @@ com.google.cloud google-cloud-bigquery-parent - 2.8.0 + 2.9.0 google-cloud-bigquery @@ -85,6 +85,10 @@ com.google.code.gson gson + + org.threeten + threeten-extra + diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LegacySQLTypeName.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LegacySQLTypeName.java index 1c2a3d884..944df2fb0 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LegacySQLTypeName.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LegacySQLTypeName.java @@ -96,6 +96,9 @@ public LegacySQLTypeName apply(String constant) { /** Represents JSON data */ public static final LegacySQLTypeName JSON = type.createAndRegister("JSON").setStandardType(StandardSQLTypeName.JSON); + /** Represents duration or amount of time. */ + public static final LegacySQLTypeName INTERVAL = + type.createAndRegister("INTERVAL").setStandardType(StandardSQLTypeName.INTERVAL); private static Map standardToLegacyMap = new HashMap<>(); diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java index f7f7e384f..227597bb1 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryParameterValue.java @@ -43,6 +43,7 @@ import org.threeten.bp.format.DateTimeFormatter; import org.threeten.bp.format.DateTimeFormatterBuilder; import org.threeten.bp.format.DateTimeParseException; +import org.threeten.extra.PeriodDuration; /** * A value for a QueryParameter along with its type. @@ -63,6 +64,7 @@ *
  • BigDecimal: StandardSQLTypeName.NUMERIC *
  • BigNumeric: StandardSQLTypeName.BIGNUMERIC *
  • JSON: StandardSQLTypeName.JSON + *
  • INTERVAL: StandardSQLTypeName.INTERVAL * * *

    No other types are supported through that entry point. The other types can be created by @@ -308,12 +310,26 @@ public static QueryParameterValue time(String value) { /** * Creates a {@code QueryParameterValue} object with a type of DATETIME. Must be in the format - * "yyyy-MM-dd HH:mm:ss.SSSSSS", e.g. ""2014-08-19 12:41:35.220000". + * "yyyy-MM-dd HH:mm:ss.SSSSSS", e.g. "2014-08-19 12:41:35.220000". */ public static QueryParameterValue dateTime(String value) { return of(value, StandardSQLTypeName.DATETIME); } + /** + * Creates a {@code QueryParameterValue} object with a type of INTERVAL. Must be in the canonical + * format "[sign]Y-M [sign]D [sign]H:M:S[.F]", e.g. "123-7 -19 0:24:12.000006" or ISO 8601 + * duration format, e.g. "P123Y7M-19DT0H24M12.000006S" + */ + public static QueryParameterValue interval(String value) { + return of(value, StandardSQLTypeName.INTERVAL); + } + + /** Creates a {@code QueryParameterValue} object with a type of INTERVAL. */ + public static QueryParameterValue interval(PeriodDuration value) { + return of(value, StandardSQLTypeName.INTERVAL); + } + /** * Creates a {@code QueryParameterValue} object with a type of ARRAY, and an array element type * based on the given class. @@ -408,6 +424,8 @@ private static String valueToStringOrNull(T value, StandardSQLTypeName type) return value.toString(); case JSON: if (value instanceof String || value instanceof JsonObject) return value.toString(); + case INTERVAL: + if (value instanceof String || value instanceof PeriodDuration) return value.toString(); break; case STRUCT: throw new IllegalArgumentException("Cannot convert STRUCT to String value"); diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTypeName.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTypeName.java index 57152a2a6..1081fc5d6 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTypeName.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTypeName.java @@ -57,6 +57,8 @@ public enum StandardSQLTypeName { DATETIME, /** Represents a set of geographic points, represented as a Well Known Text (WKT) string. */ GEOGRAPHY, - /** Represents JSON data */ - JSON + /** Represents JSON data. */ + JSON, + /** Represents duration or amount of time. */ + INTERVAL } diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java index 679b6ec5c..6b5368003 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryParameterValueTest.java @@ -27,6 +27,7 @@ import com.google.gson.JsonObject; import java.math.BigDecimal; import java.text.ParseException; +import java.time.Period; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -38,6 +39,7 @@ import org.threeten.bp.format.DateTimeFormatter; import org.threeten.bp.format.DateTimeFormatterBuilder; import org.threeten.bp.jdk8.Jdk8Methods; +import org.threeten.extra.PeriodDuration; public class QueryParameterValueTest { @@ -212,6 +214,24 @@ public void testJson() { assertThat(value1.getArrayType()).isNull(); } + @Test + public void testInterval() { + QueryParameterValue value = QueryParameterValue.interval("123-7 -19 0:24:12.000006"); + QueryParameterValue value1 = QueryParameterValue.interval("P123Y7M-19DT0H24M12.000006S"); + QueryParameterValue value2 = + QueryParameterValue.interval( + PeriodDuration.of(Period.of(1, 2, 25), java.time.Duration.ofHours(8))); + assertThat(value.getValue()).isEqualTo("123-7 -19 0:24:12.000006"); + assertThat(value1.getValue()).isEqualTo("P123Y7M-19DT0H24M12.000006S"); + assertThat(value2.getValue()).isEqualTo("P1Y2M25DT8H"); + assertThat(value.getType()).isEqualTo(StandardSQLTypeName.INTERVAL); + assertThat(value1.getType()).isEqualTo(StandardSQLTypeName.INTERVAL); + assertThat(value2.getType()).isEqualTo(StandardSQLTypeName.INTERVAL); + assertThat(value.getArrayType()).isNull(); + assertThat(value1.getArrayType()).isNull(); + assertThat(value2.getArrayType()).isNull(); + } + @Test public void testBytes() { QueryParameterValue value = QueryParameterValue.bytes(new byte[] {1, 3}); 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 b8051122f..282bef986 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 @@ -130,6 +130,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.time.Instant; +import java.time.Period; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -151,6 +152,7 @@ import org.junit.Test; import org.junit.rules.Timeout; import org.threeten.bp.Duration; +import org.threeten.extra.PeriodDuration; public class ITBigQueryTest { @@ -816,6 +818,77 @@ public void testJsonType() throws InterruptedException { } } + @Test + public void testIntervalType() throws InterruptedException { + String tableName = "test_create_table_intervaltype"; + TableId tableId = TableId.of(DATASET, tableName); + Schema schema = Schema.of(Field.of("intervalField", StandardSQLTypeName.INTERVAL)); + StandardTableDefinition standardTableDefinition = StandardTableDefinition.of(schema); + try { + // Create a table with a JSON column + Table createdTable = bigquery.create(TableInfo.of(tableId, standardTableDefinition)); + assertNotNull(createdTable); + + // Insert 3 rows of Interval data into the Interval column + Map intervalRow1 = + Collections.singletonMap("intervalField", "123-7 -19 0:24:12.000006"); + Map intervalRow2 = + Collections.singletonMap("intervalField", "P123Y7M-19DT0H24M12.000006S"); + + InsertAllRequest request = + InsertAllRequest.newBuilder(tableId).addRow(intervalRow1).addRow(intervalRow2).build(); + InsertAllResponse response = bigquery.insertAll(request); + assertFalse(response.hasErrors()); + assertEquals(0, response.getInsertErrors().size()); + + // Insert another Interval row parsed from a String with Interval positional query parameter + String dml = "INSERT INTO " + tableId.getTable() + " (intervalField) VALUES(?)"; + // Parsing from ISO 8610 format String + QueryParameterValue intervalParameter = + QueryParameterValue.interval("P125Y7M-19DT0H24M12.000006S"); + QueryJobConfiguration dmlQueryJobConfiguration = + QueryJobConfiguration.newBuilder(dml) + .setDefaultDataset(DatasetId.of(DATASET)) + .setUseLegacySql(false) + .addPositionalParameter(intervalParameter) + .build(); + bigquery.query(dmlQueryJobConfiguration); + Page rows = bigquery.listTableData(tableId); + assertEquals(3, Iterables.size(rows.getValues())); + + // Parsing from threeten-extra PeriodDuration + QueryParameterValue intervalParameter1 = + QueryParameterValue.interval( + PeriodDuration.of(Period.of(1, 2, 25), java.time.Duration.ofHours(8))); + QueryJobConfiguration dmlQueryJobConfiguration1 = + QueryJobConfiguration.newBuilder(dml) + .setDefaultDataset(DatasetId.of(DATASET)) + .setUseLegacySql(false) + .addPositionalParameter(intervalParameter1) + .build(); + bigquery.query(dmlQueryJobConfiguration1); + Page rows1 = bigquery.listTableData(tableId); + assertEquals(4, Iterables.size(rows1.getValues())); + + // Query the Interval column with Interval positional query parameter + String sql = "SELECT intervalField FROM " + tableId.getTable() + " WHERE intervalField = ? "; + QueryParameterValue intervalParameter2 = + QueryParameterValue.interval("P125Y7M-19DT0H24M12.000006S"); + QueryJobConfiguration queryJobConfiguration = + QueryJobConfiguration.newBuilder(sql) + .setDefaultDataset(DatasetId.of(DATASET)) + .setUseLegacySql(false) + .addPositionalParameter(intervalParameter2) + .build(); + TableResult result = bigquery.query(queryJobConfiguration); + for (FieldValueList values : result.iterateAll()) { + assertEquals("125-7 -19 0:24:12.000006", values.get(0).getValue()); + } + } finally { + assertTrue(bigquery.delete(tableId)); + } + } + @Test public void testCreateTableWithConstraints() { String tableName = "test_create_table_with_constraints"; diff --git a/pom.xml b/pom.xml index 07ad8b6b7..4048b0b99 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-bigquery-parent pom - 2.8.0 + 2.9.0 BigQuery Parent https://github.com/googleapis/java-bigquery @@ -14,7 +14,7 @@ com.google.cloud google-cloud-shared-config - 1.2.6 + 1.2.7 @@ -70,7 +70,7 @@ com.google.cloud google-cloud-datacatalog-bom - 1.6.2 + 1.6.3 pom import @@ -84,7 +84,7 @@ com.google.cloud google-cloud-bigquery - 2.8.0 + 2.9.0 @@ -93,12 +93,20 @@ ${google-api-services-bigquery.version} + com.google.code.gson gson 2.8.9 + + + org.threeten + threeten-extra + 1.7.0 + + junit @@ -127,7 +135,7 @@ com.google.cloud google-cloud-storage - 2.3.0 + 2.4.1 test @@ -149,7 +157,7 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 3.1.2 + 3.2.1 @@ -176,7 +184,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.3.1 + 3.3.2 html diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 9cb96538f..4b3ba9df9 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -45,31 +45,31 @@ com.google.cloud google-cloud-bigquery - 2.7.1 + 2.8.0 com.google.oauth-client google-oauth-client-java6 - 1.33.0 + 1.33.1 com.google.oauth-client google-oauth-client-jetty - 1.33.0 + 1.33.1 com.google.cloud google-cloud-bigtable - 2.5.2 + 2.5.3 test com.google.cloud google-cloud-bigqueryconnection - 2.1.8 + 2.1.9 test diff --git a/samples/native-image-sample/README.md b/samples/native-image-sample/README.md new file mode 100644 index 000000000..e4e4b52ee --- /dev/null +++ b/samples/native-image-sample/README.md @@ -0,0 +1,47 @@ +# BigQuery Sample Application with Native Image + +The BigQuery sample application demonstrates some common operations with [Google Cloud BigQuery](https://cloud.google.com/bigquery) and is compatible with Native Image compilation. + +## Setup Instructions + +1. Follow the [GCP Project Authentication and Native Image Setup Instructions](../../README.md). + +2. [Enable the BigQuery APIs](https://console.cloud.google.com/apis/api/bigquery.googleapis.com). + +### Run with Native Image Support + +Navigate to this directory in a new terminal. + +1. Compile the application using the Native Image Compiler. This step may take a few minutes. + + ``` + mvn package -P native -DskipTests + ``` + +2. Run the application: + + ``` + ./target/native-image-sample + ``` + +3. The application will create a sample BigQuery dataset in your GCP project called `nativeimage_test_dataset` and perform some simple operations like creating a table, inserting data, and running a query. + + If you would like to delete the BigQuery dataset later, you can manage your BigQuery resources through [Google Cloud Console](https://console.cloud.google.com/bigquery) to clean up BigQuery resources under your project. + + When you run the application, you'll see output like this in the terminal: + + ``` + Created new table: nativeimage_test_table_2351b0891d2f48af9309bd289c3bad13 + Successfully inserted test row. + Queried the following records: + User id: TestUser-2f39e3ec-d81a-483f-9ec0-b9bd54155710 | age: 40 + Deleted table: nativeimage_test_table_2351b0891d2f48af9309bd289c3bad13 + ``` + +### Sample Integration test with Native Image Support + +In order to run the sample integration test, call the following command: + +``` +mvn test -Pnative +``` \ No newline at end of file diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml new file mode 100644 index 000000000..6e3fced6b --- /dev/null +++ b/samples/native-image-sample/pom.xml @@ -0,0 +1,161 @@ + + + + 4.0.0 + com.example.bigquery + native-image-sample + Native Image Sample + + + com.google.cloud.samples + shared-configuration + 1.2.0 + + + + 1.8 + 1.8 + UTF-8 + + + + + + com.google.cloud + libraries-bom + 24.3.0 + pom + import + + + + + + + com.google.cloud + google-cloud-bigquery + + + + + junit + junit + 4.13.2 + test + + + com.google.truth + truth + 1.1.3 + test + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.example.bigquery.NativeImageBigquerySample + + + + + + + + + + + + native + + + + com.google.cloud + native-image-support + 0.12.3 + + + org.junit.vintage + junit-vintage-engine + 5.8.2 + test + + + org.graalvm.buildtools + junit-platform-native + 0.9.9 + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + 2.22.2 + + + **/*IT + + + + + org.graalvm.buildtools + native-maven-plugin + 0.9.9 + true + + com.example.bigquery.NativeImageBigquerySample + + + --no-fallback + --no-server + + + + + build-native + + build + test + + package + + + test-native + + test + + test + + + + + + + + diff --git a/samples/native-image-sample/src/main/java/com/example/bigquery/NativeImageBigquerySample.java b/samples/native-image-sample/src/main/java/com/example/bigquery/NativeImageBigquerySample.java new file mode 100644 index 000000000..e7f1b35c5 --- /dev/null +++ b/samples/native-image-sample/src/main/java/com/example/bigquery/NativeImageBigquerySample.java @@ -0,0 +1,170 @@ +/* + * Copyright 2022 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.example.bigquery; + +import com.google.api.gax.paging.Page; +import com.google.cloud.bigquery.BigQuery; +import com.google.cloud.bigquery.BigQueryError; +import com.google.cloud.bigquery.BigQueryOptions; +import com.google.cloud.bigquery.Dataset; +import com.google.cloud.bigquery.DatasetInfo; +import com.google.cloud.bigquery.Field; +import com.google.cloud.bigquery.FieldValueList; +import com.google.cloud.bigquery.InsertAllRequest; +import com.google.cloud.bigquery.InsertAllResponse; +import com.google.cloud.bigquery.QueryJobConfiguration; +import com.google.cloud.bigquery.Schema; +import com.google.cloud.bigquery.StandardSQLTypeName; +import com.google.cloud.bigquery.StandardTableDefinition; +import com.google.cloud.bigquery.Table; +import com.google.cloud.bigquery.TableDefinition; +import com.google.cloud.bigquery.TableId; +import com.google.cloud.bigquery.TableInfo; +import com.google.cloud.bigquery.TableResult; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Sample application demonstrating BigQuery operations. + * + *

    Note: This application will create a BigQuery dataset in your GCP project. You can delete this + * by viewing BigQuery in Cloud Console https://console.cloud.google.com/bigquery or by uncommenting + * the call to `deleteDataset(..)` made in main(). + */ +public class NativeImageBigquerySample { + + private static final String DATASET_ID = "nativeimage_test_dataset"; + + private static final String TABLE_ID = "nativeimage_test_table"; + + private static final Schema TABLE_SCHEMA = + Schema.of( + Field.of("id", StandardSQLTypeName.STRING), Field.of("age", StandardSQLTypeName.INT64)); + + /** Entrypoint to the application. */ + public static void main(String[] args) throws InterruptedException { + BigQuery bigQuery = BigQueryOptions.getDefaultInstance().getService(); + + if (!hasDataset(bigQuery, DATASET_ID)) { + createDataset(bigQuery, DATASET_ID); + } + + String tableName = TABLE_ID + "_" + UUID.randomUUID().toString().replace("-", ""); + createTable(bigQuery, DATASET_ID, tableName, TABLE_SCHEMA); + String testId = "TestUser-" + UUID.randomUUID().toString(); + int testAge = 40; + insertTestRecord(bigQuery, DATASET_ID, tableName, testId, testAge); + queryTable(bigQuery, DATASET_ID, tableName); + + // Clean up resources. + deleteTable(bigQuery, DATASET_ID, tableName); + + // Uncomment this to delete the created dataset. + // deleteDataset(bigQuery, DATASET_ID); + } + + static String queryTable(BigQuery bigQuery, String datasetName, String tableName) + throws InterruptedException { + String fullyQualifiedTable = datasetName + "." + tableName; + String query = "SELECT * FROM " + fullyQualifiedTable; + + QueryJobConfiguration queryConfig = QueryJobConfiguration.newBuilder(query).build(); + TableResult results = bigQuery.query(queryConfig); + + String result = ""; + System.out.println("Queried the following records: "); + for (FieldValueList row : results.iterateAll()) { + String rowStatement = + String.format( + "User id: %s | age: %d\n", + row.get("id").getStringValue(), row.get("age").getLongValue()); + result += rowStatement; + System.out.println(row); + } + return result; + } + + static void insertTestRecord( + BigQuery bigQuery, String datasetName, String tableName, String id, int age) { + + Map rowContent = new HashMap<>(); + rowContent.put("id", id); + rowContent.put("age", age); + + InsertAllRequest request = + InsertAllRequest.newBuilder(datasetName, tableName).addRow(rowContent).build(); + + InsertAllResponse response = bigQuery.insertAll(request); + + if (response.hasErrors()) { + System.out.println("Insert resulted in errors:"); + for (Map.Entry> entry : response.getInsertErrors().entrySet()) { + System.out.println("Response error: \n" + entry.getValue()); + } + } else { + System.out.println("Successfully inserted test row."); + } + } + + static void createTable(BigQuery bigQuery, String datasetName, String tableName, Schema schema) { + + TableId tableId = TableId.of(datasetName, tableName); + TableDefinition tableDefinition = StandardTableDefinition.of(schema); + TableInfo tableInfo = TableInfo.newBuilder(tableId, tableDefinition).build(); + bigQuery.create(tableInfo); + System.out.println("Created new table: " + tableName); + } + + static boolean hasTable(BigQuery bigQuery, String datasetName, String tableName) { + + Page tables = bigQuery.listTables(datasetName); + for (Table table : tables.iterateAll()) { + if (tableName.equals(table.getTableId().getTable())) { + return true; + } + } + return false; + } + + static void createDataset(BigQuery bigQuery, String datasetName) { + DatasetInfo datasetInfo = DatasetInfo.newBuilder(datasetName).build(); + Dataset newDataset = bigQuery.create(datasetInfo); + System.out.println("Created new dataset: " + newDataset.getDatasetId().getDataset()); + } + + static boolean hasDataset(BigQuery bigQuery, String datasetName) { + Page datasets = bigQuery.listDatasets(); + for (Dataset dataset : datasets.iterateAll()) { + if (datasetName.equals(dataset.getDatasetId().getDataset())) { + return true; + } + } + return false; + } + + static void deleteTable(BigQuery bigQuery, String datasetName, String tableName) { + bigQuery.getTable(datasetName, tableName).delete(); + System.out.println("Deleted table: " + tableName); + } + + static void deleteDataset(BigQuery bigQuery, String datasetName) { + bigQuery.getDataset(datasetName).delete(); + System.out.println("Deleting dataset " + datasetName); + } +} diff --git a/samples/native-image-sample/src/test/java/com/example/bigquery/NativeImageBigquerySampleIT.java b/samples/native-image-sample/src/test/java/com/example/bigquery/NativeImageBigquerySampleIT.java new file mode 100644 index 000000000..a65bc5aa8 --- /dev/null +++ b/samples/native-image-sample/src/test/java/com/example/bigquery/NativeImageBigquerySampleIT.java @@ -0,0 +1,67 @@ +/* + * Copyright 2022 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.example.bigquery; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.bigquery.BigQuery; +import com.google.cloud.bigquery.BigQueryOptions; +import com.google.cloud.bigquery.Field; +import com.google.cloud.bigquery.Schema; +import com.google.cloud.bigquery.StandardSQLTypeName; +import java.util.UUID; +import org.junit.Before; +import org.junit.Test; + +/** Tests for {@link NativeImageBigquerySample} */ +public class NativeImageBigquerySampleIT { + + private static final String DATASET_ID = "nativeimage_it_dataset"; + + private static final String TABLE_ID = "nativeimage_it_table"; + + private static final Schema TABLE_SCHEMA = + Schema.of( + Field.of("id", StandardSQLTypeName.STRING), Field.of("age", StandardSQLTypeName.INT64)); + + private BigQuery bigQuery; + + private String tableName; + + @Before + public void setUp() { + bigQuery = BigQueryOptions.getDefaultInstance().getService(); + tableName = TABLE_ID + "_" + UUID.randomUUID().toString().replace("-", ""); + if (!NativeImageBigquerySample.hasDataset(bigQuery, DATASET_ID)) { + NativeImageBigquerySample.createDataset(bigQuery, DATASET_ID); + } + NativeImageBigquerySample.createTable(bigQuery, DATASET_ID, tableName, TABLE_SCHEMA); + } + + @Test + public void testQueryTable() throws InterruptedException { + String testId = "TestUser-" + UUID.randomUUID(); + NativeImageBigquerySample.insertTestRecord(bigQuery, DATASET_ID, tableName, testId, 40); + + String result = NativeImageBigquerySample.queryTable(bigQuery, DATASET_ID, tableName); + + assertThat(result).isEqualTo("User id: " + testId + " | age: 40\n"); + + // Clean up + NativeImageBigquerySample.deleteTable(bigQuery, DATASET_ID, tableName); + } +} diff --git a/samples/pom.xml b/samples/pom.xml index 4e9299af4..a02b0b6c4 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -47,6 +47,7 @@ install-without-bom snapshot snippets + native-image-sample diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 143ca6acd..312c27457 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -44,30 +44,30 @@ com.google.cloud google-cloud-bigquery - 2.8.0 + 2.9.0 com.google.oauth-client google-oauth-client-java6 - 1.33.0 + 1.33.1 com.google.oauth-client google-oauth-client-jetty - 1.33.0 + 1.33.1 com.google.cloud google-cloud-bigtable - 2.5.2 + 2.5.3 test com.google.cloud google-cloud-bigqueryconnection - 2.1.8 + 2.1.9 test diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 1be592b87..8a7caea9d 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -47,7 +47,7 @@ com.google.cloud libraries-bom - 24.2.0 + 24.3.0 pom import @@ -66,12 +66,12 @@ com.google.oauth-client google-oauth-client-java6 - 1.33.0 + 1.33.1 com.google.oauth-client google-oauth-client-jetty - 1.33.0 + 1.33.1 @@ -79,13 +79,13 @@ com.google.cloud google-cloud-bigtable - 2.5.2 + 2.5.3 test com.google.cloud google-cloud-bigqueryconnection - 2.1.8 + 2.1.9 test diff --git a/versions.txt b/versions.txt index 9e9df81f2..8dc052a16 100644 --- a/versions.txt +++ b/versions.txt @@ -1,4 +1,4 @@ # Format: # module:released-version:current-version -google-cloud-bigquery:2.8.0:2.8.0 \ No newline at end of file +google-cloud-bigquery:2.9.0:2.9.0 \ No newline at end of file