diff --git a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResponse.java b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResponse.java index 2c9257388b12..787047a7a06d 100644 --- a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResponse.java +++ b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResponse.java @@ -17,7 +17,6 @@ package com.google.gcloud.bigquery; import com.google.common.base.MoreObjects; -import com.google.gcloud.Page; import java.io.Serializable; import java.util.List; @@ -35,7 +34,12 @@ * Thread.sleep(1000); * } * List executionErrors = response.executionErrors(); - * Page> rows = response.rows(); + * QueryResult result = response.result(); + * Iterator> rowIterator = result.iterateAll(); + * while(rowIterator.hasNext()) { + * List row = rowIterator.next(); + * // do something with row + * } * } * * @see Get Query @@ -46,37 +50,29 @@ public class QueryResponse implements Serializable { private static final long serialVersionUID = 3549226764825005655L; + private final QueryResult result; private final String etag; - private final Schema schema; private final JobId job; - private final Long totalRows; - private final Page> rows; - private final Long totalBytesProcessed; private final boolean jobComplete; private final List executionErrors; - private final Boolean cacheHit; static final class Builder { + private QueryResult result; private String etag; - private Schema schema; private JobId job; - private Long totalRows; - private Page> rows; - private Long totalBytesProcessed; private boolean jobComplete; private List executionErrors; - private Boolean cacheHit; private Builder() {} - Builder etag(String etag) { - this.etag = etag; + Builder result(QueryResult result) { + this.result = result; return this; } - Builder schema(Schema schema) { - this.schema = schema; + Builder etag(String etag) { + this.etag = etag; return this; } @@ -85,21 +81,6 @@ Builder job(JobId job) { return this; } - Builder totalRows(Long totalRows) { - this.totalRows = totalRows; - return this; - } - - Builder rows(Page> rows) { - this.rows = rows; - return this; - } - - Builder totalBytesProcessed(Long totalBytesProcessed) { - this.totalBytesProcessed = totalBytesProcessed; - return this; - } - Builder jobComplete(boolean jobComplete) { this.jobComplete = jobComplete; return this; @@ -110,41 +91,32 @@ Builder executionErrors(List executionErrors) { return this; } - Builder cacheHit(Boolean cacheHit) { - this.cacheHit = cacheHit; - return this; - } - QueryResponse build() { return new QueryResponse(this); } } private QueryResponse(Builder builder) { + this.result = builder.result; this.etag = builder.etag; - this.schema = builder.schema; this.job = builder.job; - this.totalRows = builder.totalRows; - this.rows = builder.rows; - this.totalBytesProcessed = builder.totalBytesProcessed; this.jobComplete = builder.jobComplete; this.executionErrors = builder.executionErrors; - this.cacheHit = builder.cacheHit; } /** - * Returns the hash of the {@code QueryResponse} resource or {@code null} if not set. + * Returns the result of the query. Returns {@code null} if {@link #jobComplete()} is {@code + * false}. */ - public String etag() { - return etag; + public QueryResult result() { + return result; } /** - * Returns the schema of the results if the query completed successfully. Returns {@code null} - * otherwise. + * Returns the hash of the {@code QueryResponse} resource or {@code null} if not set. */ - public Schema schema() { - return schema; + public String etag() { + return etag; } /** @@ -156,36 +128,10 @@ public JobId job() { } /** - * Returns the total number of rows in the complete query result set, which can be more than the - * number of rows in the first page of results returned by {@link #rows()}. Returns {@code null} - * if the query did not complete successfully. - */ - public Long totalRows() { - return totalRows; - } - - /** - * Returns the query result as a paginated list of rows, if the query completed successfully. - * Returns {@code null} otherwise. - */ - public Page> rows() { - return rows; - } - - /** - * Returns the total number of bytes processed for the query. If this query was a dry run, this is - * the number of bytes that would be processed if the query were run. Returns {@code null} - * if the query did not complete. - */ - public Long totalBytesProcessed() { - return totalBytesProcessed; - } - - /** - * Returns whether the job running the query has completed or not. If {@link #rows()} and - * {@link #totalRows()} are not {@code null}, this method will always return {@code true}. If this - * method returns {@code false} {@link #totalRows()} and {@link #rows()} return {@code null}. This - * method can be used to check if query execution completed and results are available. + * Returns whether the job running the query has completed or not. If {@link #result()} is not + * {@code null}, this method will always return {@code true}. If this method returns {@code false} + * {@link #result()} returns {@code null}. This method can be used to check if query execution + * completed and results are available. */ public boolean jobComplete() { return jobComplete; @@ -199,25 +145,14 @@ public List executionErrors() { return executionErrors; } - /** - * Returns whether the query result was fetched from the query cache. - * - * @see Query Caching - */ - public Boolean cacheHit() { - return cacheHit; - } - @Override public String toString() { return MoreObjects.toStringHelper(this) + .add("result", result) + .add("etag", etag) .add("job", job) .add("jobComplete", jobComplete) - .add("totalRows", totalRows) - .add("schema", schema) - .add("totalBytesProcessed", totalBytesProcessed) .add("executionErrors", executionErrors) - .add("cacheHit", cacheHit) .toString(); } @@ -236,13 +171,10 @@ public boolean equals(Object obj) { } QueryResponse response = (QueryResponse) obj; return jobComplete == response.jobComplete - && Objects.equals(schema, response.schema) + && Objects.equals(etag, response.etag) + && Objects.equals(result, response.result) && Objects.equals(job, response.job) - && Objects.equals(totalRows, response.totalRows) - && Objects.equals(rows, response.rows) - && Objects.equals(totalBytesProcessed, response.totalBytesProcessed) - && Objects.equals(executionErrors, response.executionErrors) - && Objects.equals(cacheHit, response.cacheHit); + && Objects.equals(executionErrors, response.executionErrors); } static Builder builder() { diff --git a/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResult.java b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResult.java new file mode 100644 index 000000000000..a3253e1fa171 --- /dev/null +++ b/gcloud-java-bigquery/src/main/java/com/google/gcloud/bigquery/QueryResult.java @@ -0,0 +1,171 @@ +/* + * Copyright 2015 Google Inc. All Rights Reserved. + * + * 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.gcloud.bigquery; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.gcloud.PageImpl; + +import java.util.List; +import java.util.Objects; + +public class QueryResult extends PageImpl> { + + private static final long serialVersionUID = -4831062717210349818L; + + private final boolean cacheHit; + private final Schema schema; + private final long totalRows; + private final long totalBytesProcessed; + + interface QueryResultsPageFetcher extends PageImpl.NextPageFetcher> { + @Override + QueryResult nextPage(); + } + + static final class Builder { + + private NextPageFetcher> pageFetcher; + private String cursor; + private Iterable> results; + private boolean cacheHit; + private Schema schema; + private long totalRows; + private long totalBytesProcessed; + + private Builder() {} + + Builder cacheHit(boolean cacheHit) { + this.cacheHit = cacheHit; + return this; + } + + Builder schema(Schema schema) { + this.schema = schema; + return this; + } + + Builder totalBytesProcessed(long totalBytesProcessed) { + this.totalBytesProcessed = totalBytesProcessed; + return this; + } + + Builder totalRows(long totalRows) { + this.totalRows = totalRows; + return this; + } + + Builder pageFetcher(NextPageFetcher> pageFetcher) { + this.pageFetcher = pageFetcher; + return this; + }; + + Builder cursor(String cursor) { + this.cursor = cursor; + return this; + }; + + Builder results(Iterable> results) { + this.results = results; + return this; + }; + + QueryResult build() { + return new QueryResult(this); + } + } + + private QueryResult(Builder builder) { + super(builder.pageFetcher, builder.cursor, builder.results != null ? builder.results + : ImmutableList.>of()); + this.cacheHit = builder.cacheHit; + this.schema = builder.schema; + this.totalBytesProcessed = builder.totalBytesProcessed; + this.totalRows = builder.totalRows; + } + + /** + * Returns whether the query result was fetched from the query cache. + * + * @see Query Caching + */ + public boolean cacheHit() { + return cacheHit; + } + + /** + * Returns the schema of the results. + */ + public Schema schema() { + return schema; + } + + /** + * Returns the total number of bytes processed for the query. If this query was a dry run, this is + * the number of bytes that would be processed if the query were run. + */ + public long totalBytesProcessed() { + return totalBytesProcessed; + } + + /** + * Returns the total number of rows in the complete query result set, which can be more than the + * number of rows in the first page of results returned by {@link #values()}. Returns {@code 0} + * if the query was a dry run. + */ + public long totalRows() { + return totalRows; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("rows", values()) + .add("cacheHit", cacheHit) + .add("schema", schema) + .add("totalBytesProcessed", totalBytesProcessed) + .add("totalRows", totalRows) + .add("cursor", nextPageCursor()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), cacheHit, schema, totalBytesProcessed, totalRows); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + QueryResult response = (QueryResult) obj; + return Objects.equals(nextPageCursor(), response.nextPageCursor()) + && Objects.equals(values(), response.values()) + && Objects.equals(schema, response.schema) + && Objects.equals(totalRows, response.totalRows) + && Objects.equals(totalBytesProcessed, response.totalBytesProcessed) + && Objects.equals(cacheHit, response.cacheHit); + } + + static Builder builder() { + return new Builder(); + } +} diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResponseTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResponseTest.java index 2c00e81a9f63..0d49e6517a49 100644 --- a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResponseTest.java +++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResponseTest.java @@ -17,6 +17,7 @@ package com.google.gcloud.bigquery; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import com.google.common.collect.ImmutableList; @@ -54,43 +55,40 @@ public Page> nextPage() { new BigQueryError("reason2", "location2", "message2", "debugInfo2") ); private static final Boolean CACHE_HIT = false; - private static final QueryResponse QUERY_RESPONSE = QueryResponse.builder() - .etag(ETAG) + private static final QueryResult QUERY_RESULT = QueryResult.builder() .schema(SCHEMA) - .job(JOB_ID) .totalRows(TOTAL_ROWS) - .rows(ROWS) .totalBytesProcessed(TOTAL_BYTES_PROCESSED) + .cursor("cursor") + .pageFetcher(FETCHER) + .results(ImmutableList.>of()) + .cacheHit(CACHE_HIT) + .build(); + private static final QueryResponse QUERY_RESPONSE = QueryResponse.builder() + .etag(ETAG) + .job(JOB_ID) .jobComplete(JOB_COMPLETE) .executionErrors(ERRORS) - .cacheHit(CACHE_HIT) + .result(QUERY_RESULT) .build(); @Test public void testBuilder() { assertEquals(ETAG, QUERY_RESPONSE.etag()); - assertEquals(SCHEMA, QUERY_RESPONSE.schema()); + assertEquals(QUERY_RESULT, QUERY_RESPONSE.result()); assertEquals(JOB_ID, QUERY_RESPONSE.job()); - assertEquals(TOTAL_ROWS, QUERY_RESPONSE.totalRows()); - assertEquals(ROWS, QUERY_RESPONSE.rows()); - assertEquals(TOTAL_BYTES_PROCESSED, (Long) QUERY_RESPONSE.totalBytesProcessed()); assertEquals(JOB_COMPLETE, QUERY_RESPONSE.jobComplete()); assertEquals(ERRORS, QUERY_RESPONSE.executionErrors()); - assertEquals(CACHE_HIT, QUERY_RESPONSE.cacheHit()); } @Test public void testBuilderIncomplete() { QueryResponse queryResponse = QueryResponse.builder().jobComplete(false).build(); assertNull(queryResponse.etag()); - assertNull(queryResponse.schema()); + assertNull(queryResponse.result()); assertNull(queryResponse.job()); - assertNull(queryResponse.totalRows()); - assertNull(queryResponse.rows()); - assertNull(queryResponse.totalBytesProcessed()); - assertEquals(false, queryResponse.jobComplete()); + assertFalse(queryResponse.jobComplete()); assertNull(queryResponse.executionErrors()); - assertNull(queryResponse.cacheHit()); } @Test @@ -101,13 +99,9 @@ public void testEquals() { private void compareQueryResponse(QueryResponse expected, QueryResponse value) { assertEquals(expected, value); assertEquals(expected.etag(), value.etag()); - assertEquals(expected.schema(), value.schema()); + assertEquals(expected.result(), value.result()); assertEquals(expected.job(), value.job()); - assertEquals(expected.totalRows(), value.totalRows()); - assertEquals(expected.rows(), value.rows()); - assertEquals(expected.totalBytesProcessed(), value.totalBytesProcessed()); assertEquals(expected.jobComplete(), value.jobComplete()); assertEquals(expected.executionErrors(), value.executionErrors()); - assertEquals(expected.cacheHit(), value.cacheHit()); } } diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResultTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResultTest.java new file mode 100644 index 000000000000..52b66768e131 --- /dev/null +++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/QueryResultTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2015 Google Inc. All Rights Reserved. + * + * 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.gcloud.bigquery; + +import com.google.common.collect.ImmutableList; +import com.google.gcloud.Page; +import com.google.gcloud.PageImpl; + +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class QueryResultTest { + + private static final String CURSOR = "cursor"; + private static final Field FIELD_SCHEMA1 = + Field.builder("StringField", Field.Type.string()) + .mode(Field.Mode.NULLABLE) + .description("FieldDescription1") + .build(); + private static final Schema SCHEMA = Schema.of(FIELD_SCHEMA1); + private static final long TOTAL_ROWS = 42L; + private static final PageImpl.NextPageFetcher> FETCHER = + new PageImpl.NextPageFetcher>() { + @Override + public Page> nextPage() { + return null; + } + }; + private static final long TOTAL_BYTES_PROCESSED = 4200L; + private static final boolean CACHE_HIT = false; + private static final QueryResult QUERY_RESULT = QueryResult.builder() + .schema(SCHEMA) + .totalRows(TOTAL_ROWS) + .totalBytesProcessed(TOTAL_BYTES_PROCESSED) + .cursor(CURSOR) + .pageFetcher(FETCHER) + .results(ImmutableList.>of()) + .cacheHit(CACHE_HIT) + .build(); + private static final QueryResult QUERY_RESULT_INCOMPLETE = QueryResult.builder() + .totalBytesProcessed(TOTAL_BYTES_PROCESSED) + .build(); + + @Test + public void testBuilder() { + assertEquals(SCHEMA, QUERY_RESULT.schema()); + assertEquals(TOTAL_ROWS, QUERY_RESULT.totalRows()); + assertEquals(TOTAL_BYTES_PROCESSED, QUERY_RESULT.totalBytesProcessed()); + assertEquals(CACHE_HIT, QUERY_RESULT.cacheHit()); + assertEquals(CURSOR, QUERY_RESULT.nextPageCursor()); + assertEquals(null, QUERY_RESULT.nextPage()); + assertEquals(null, QUERY_RESULT_INCOMPLETE.schema()); + assertEquals(0L, QUERY_RESULT_INCOMPLETE.totalRows()); + assertEquals(TOTAL_BYTES_PROCESSED, QUERY_RESULT_INCOMPLETE.totalBytesProcessed()); + assertEquals(false, QUERY_RESULT_INCOMPLETE.cacheHit()); + assertEquals(null, QUERY_RESULT_INCOMPLETE.nextPageCursor()); + assertEquals(null, QUERY_RESULT_INCOMPLETE.nextPage()); + } + + @Test + public void testEquals() { + compareQueryResult(QUERY_RESULT, QUERY_RESULT); + compareQueryResult(QUERY_RESULT_INCOMPLETE, QUERY_RESULT_INCOMPLETE); + } + + private void compareQueryResult(QueryResult expected, QueryResult value) { + assertEquals(expected, value); + assertEquals(expected.nextPage(), value.nextPage()); + assertEquals(expected.nextPageCursor(), value.nextPageCursor()); + assertEquals(expected.values(), value.values()); + assertEquals(expected.schema(), value.schema()); + assertEquals(expected.totalRows(), value.totalRows()); + assertEquals(expected.totalBytesProcessed(), value.totalBytesProcessed()); + assertEquals(expected.cacheHit(), value.cacheHit()); + } +} diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java index 20092395565a..b14d4f2920c0 100644 --- a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java +++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/SerializationTest.java @@ -193,11 +193,19 @@ public class SerializationTest { .maxResults(42L) .maxWaitTime(10L) .build(); + private static final QueryResult QUERY_RESULT = QueryResult.builder() + .schema(TABLE_SCHEMA) + .totalRows(1L) + .totalBytesProcessed(42L) + .cursor("cursor") + .pageFetcher(null) + .results(ImmutableList.>of()) + .build(); private static final QueryResponse QUERY_RESPONSE = QueryResponse.builder() .etag(ETAG) - .schema(TABLE_SCHEMA) .job(JOB_ID) - .totalRows(1L) + .jobComplete(true) + .result(QUERY_RESULT) .build(); @Test