From 198cc70178d22b6118f258a8e43c991f028eeba5 Mon Sep 17 00:00:00 2001 From: anweshadas Date: Thu, 9 Jul 2026 00:43:43 +0000 Subject: [PATCH 1/4] feat: Add view_parameters support in BoundStatement and Test Proxy We need to add support for `view_parameters` in the Java Bigtable client library and the Java Test Proxy to unblock Centigrate testing. Note that the backend Bigtable server currently only supports String typed view parameters. 1. In the Java client library (`BoundStatement.java`): - Update `BoundStatement` and its `Builder` to support storing `view_parameters`. - Implement runtime type validation in `setViewParameter` to check `value.getKindCase() == Value.KindCase.STRING_VALUE`, throwing an `IllegalArgumentException` if a non-String value is passed. - Update `BoundStatement.toProto()` to populate the `view_parameters` field in the `ExecuteQueryRequest` proto. 2. In the Java Test Proxy (`BoundStatementDeserializer.java`): - Update it to extract `view_parameters` from the incoming gRPC `ExecuteQueryRequest` and bind them to the `BoundStatement` before execution (naturally inheriting runtime type validation via delegation). 3. In `BoundStatementTest.java`: - Add unit test verifying `view_parameters` binding and proto conversion. - Add unit test `setViewParameterRejectsNonStringValues` verifying that passing non-String values (int64, bool, unset values, and array values) throws an `IllegalArgumentException`. Note: `bigtable.proto` in `google-cloud-java` already includes `view_parameters` in `ExecuteQueryRequest`. TAG=agy CONV=11853e8d-5cf0-4c6b-8917-b8d6dbac0814 Change-Id: Ie9fb8c3c19d077a99cb3164365752ff7273cbf51 --- .../data/v2/models/sql/BoundStatement.java | 41 ++++++++- .../v2/models/sql/BoundStatementTest.java | 86 +++++++++++++++++++ .../testproxy/BoundStatementDeserializer.java | 1 + 3 files changed, 125 insertions(+), 3 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index 82c1084afd7e..e31af9d365f7 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -58,10 +58,15 @@ public class BoundStatement { private final PreparedStatementImpl preparedStatement; private final Map params; + private final Map viewParameters; - private BoundStatement(PreparedStatementImpl preparedStatement, Map params) { + private BoundStatement( + PreparedStatementImpl preparedStatement, + Map params, + Map viewParameters) { this.preparedStatement = preparedStatement; this.params = params; + this.viewParameters = viewParameters; } /** @@ -78,6 +83,7 @@ public static class Builder { private final PreparedStatementImpl preparedStatement; private final Map> paramTypes; private final Map params; + private final Map viewParameters; /** * Creates a builder from a {@link PreparedStatement} @@ -90,6 +96,7 @@ public Builder(PreparedStatementImpl preparedStatement, Map> this.preparedStatement = preparedStatement; this.paramTypes = paramTypes; this.params = new HashMap<>(); + this.viewParameters = new HashMap<>(); } /** Builds a {@link BoundStatement} from the builder */ @@ -101,7 +108,34 @@ public BoundStatement build() { "Attempting to build BoundStatement without binding parameter: " + paramName); } } - return new BoundStatement(preparedStatement, ImmutableMap.copyOf(params)); + return new BoundStatement( + preparedStatement, + ImmutableMap.copyOf(params), + ImmutableMap.copyOf(viewParameters)); + } + + /** + * Sets a view parameter with the name {@code name} and the Value {@code value}. + */ + public Builder setViewParameter(String name, Value value) { + Preconditions.checkNotNull(name, "name cannot be null"); + Preconditions.checkNotNull(value, "value cannot be null"); + Preconditions.checkArgument( + value.getKindCase() == Value.KindCase.STRING_VALUE, + "Currently only String typed view parameters are supported"); + viewParameters.put(name, value); + return this; + } + + /** + * Sets view parameters from a map. + */ + public Builder setViewParameters(Map viewParameters) { + Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); + for (Map.Entry entry : viewParameters.entrySet()) { + setViewParameter(entry.getKey(), entry.getValue()); + } + return this; } /** @@ -372,7 +406,8 @@ public ExecuteQueryRequest toProto( requestContext.getProjectId(), requestContext.getInstanceId())) .setAppProfileId(requestContext.getAppProfileId()) .setPreparedQuery(preparedQuery) - .putAllParams(params); + .putAllParams(params) + .putAllViewParameters(viewParameters); if (resumeToken != null) { requestBuilder.setResumeToken(resumeToken); diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index 71f46610a203..759535395ca9 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -869,4 +869,90 @@ public void builderValidatesAllParamsAreSet() { assertThat(e.getMessage()) .contains("Attempting to build BoundStatement without binding parameter: bytesParam"); } + + @Test + public void statementWithViewParameters() { + Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); + Value locationVal = Value.newBuilder().setType(stringType()).setStringValue("us-east1").build(); + HashMap viewParams = new HashMap<>(); + viewParams.put("user_id", stringVal); + viewParams.put("location", locationVal); + + BoundStatement s = boundStatementBuilder() + .setViewParameters(viewParams) + .build(); + + assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) + .isEqualTo( + ExecuteQueryRequest.newBuilder() + .setPreparedQuery(EXPECTED_PREPARED_QUERY) + .setInstanceName(EXPECTED_INSTANCE_NAME) + .setAppProfileId(EXPECTED_APP_PROFILE) + .putViewParameters("user_id", stringVal) + .putViewParameters("location", locationVal) + .build()); + } + + @Test + public void setViewParameterRejectsNonStringValues() { + BoundStatement.Builder builder = boundStatementBuilder(); + Value intVal = Value.newBuilder().setType(int64Type()).setIntValue(42).build(); + Value boolVal = Value.newBuilder().setType(boolType()).setBoolValue(true).build(); + Value unsetVal = Value.newBuilder().setType(stringType()).build(); + Value arrayVal = arrayValue(stringValue("foo"), stringValue("bar")); + + IllegalArgumentException eInt = + assertThrows( + IllegalArgumentException.class, + () -> builder.setViewParameter("age", intVal)); + assertThat(eInt.getMessage()) + .contains("Currently only String typed view parameters are supported"); + + IllegalArgumentException eBool = + assertThrows( + IllegalArgumentException.class, + () -> builder.setViewParameter("active", boolVal)); + assertThat(eBool.getMessage()) + .contains("Currently only String typed view parameters are supported"); + + IllegalArgumentException eUnset = + assertThrows( + IllegalArgumentException.class, + () -> builder.setViewParameter("unset", unsetVal)); + assertThat(eUnset.getMessage()) + .contains("Currently only String typed view parameters are supported"); + + IllegalArgumentException eArray = + assertThrows( + IllegalArgumentException.class, + () -> builder.setViewParameter("tags", arrayVal)); + assertThat(eArray.getMessage()) + .contains("Currently only String typed view parameters are supported"); + + HashMap viewParams = new HashMap<>(); + viewParams.put( + "user_id", Value.newBuilder().setType(stringType()).setStringValue("alice").build()); + viewParams.put("age", intVal); + + IllegalArgumentException eMap = + assertThrows( + IllegalArgumentException.class, + () -> builder.setViewParameters(viewParams)); + assertThat(eMap.getMessage()) + .contains("Currently only String typed view parameters are supported"); + + // Empty map should succeed without error + builder.setViewParameters(Collections.emptyMap()); + + // Null checks + assertThrows( + NullPointerException.class, + () -> builder.setViewParameter(null, stringValue("alice"))); + assertThrows( + NullPointerException.class, + () -> builder.setViewParameter("user_id", null)); + assertThrows( + NullPointerException.class, + () -> builder.setViewParameters(null)); + } } diff --git a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java index 43da147274f7..56b40d0d5957 100644 --- a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java +++ b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java @@ -128,6 +128,7 @@ static BoundStatement toBoundStatement( throw new IllegalArgumentException("Unexpected query param type in param: " + value); } } + boundStatementBuilder.setViewParameters(request.getRequest().getViewParametersMap()); return boundStatementBuilder.build(); } From 79b16eb492e59c0521e65b024677941c0ef1a4f4 Mon Sep 17 00:00:00 2001 From: anweshadas Date: Fri, 17 Jul 2026 17:45:16 +0000 Subject: [PATCH 2/4] style: apply google-java-format to BoundStatement and BoundStatementTest Change-Id: I9fd4b13273004223d84cdb4df1678a26e851d412 --- .../data/v2/models/sql/BoundStatement.java | 12 ++----- .../v2/models/sql/BoundStatementTest.java | 32 ++++++------------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index e31af9d365f7..3234326a6285 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -109,14 +109,10 @@ public BoundStatement build() { } } return new BoundStatement( - preparedStatement, - ImmutableMap.copyOf(params), - ImmutableMap.copyOf(viewParameters)); + preparedStatement, ImmutableMap.copyOf(params), ImmutableMap.copyOf(viewParameters)); } - /** - * Sets a view parameter with the name {@code name} and the Value {@code value}. - */ + /** Sets a view parameter with the name {@code name} and the Value {@code value}. */ public Builder setViewParameter(String name, Value value) { Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkNotNull(value, "value cannot be null"); @@ -127,9 +123,7 @@ public Builder setViewParameter(String name, Value value) { return this; } - /** - * Sets view parameters from a map. - */ + /** Sets view parameters from a map. */ public Builder setViewParameters(Map viewParameters) { Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); for (Map.Entry entry : viewParameters.entrySet()) { diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index 759535395ca9..47ecc59e5fea 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -878,9 +878,7 @@ public void statementWithViewParameters() { viewParams.put("user_id", stringVal); viewParams.put("location", locationVal); - BoundStatement s = boundStatementBuilder() - .setViewParameters(viewParams) - .build(); + BoundStatement s = boundStatementBuilder().setViewParameters(viewParams).build(); assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) .isEqualTo( @@ -902,30 +900,25 @@ public void setViewParameterRejectsNonStringValues() { Value arrayVal = arrayValue(stringValue("foo"), stringValue("bar")); IllegalArgumentException eInt = - assertThrows( - IllegalArgumentException.class, - () -> builder.setViewParameter("age", intVal)); + assertThrows(IllegalArgumentException.class, () -> builder.setViewParameter("age", intVal)); assertThat(eInt.getMessage()) .contains("Currently only String typed view parameters are supported"); IllegalArgumentException eBool = assertThrows( - IllegalArgumentException.class, - () -> builder.setViewParameter("active", boolVal)); + IllegalArgumentException.class, () -> builder.setViewParameter("active", boolVal)); assertThat(eBool.getMessage()) .contains("Currently only String typed view parameters are supported"); IllegalArgumentException eUnset = assertThrows( - IllegalArgumentException.class, - () -> builder.setViewParameter("unset", unsetVal)); + IllegalArgumentException.class, () -> builder.setViewParameter("unset", unsetVal)); assertThat(eUnset.getMessage()) .contains("Currently only String typed view parameters are supported"); IllegalArgumentException eArray = assertThrows( - IllegalArgumentException.class, - () -> builder.setViewParameter("tags", arrayVal)); + IllegalArgumentException.class, () -> builder.setViewParameter("tags", arrayVal)); assertThat(eArray.getMessage()) .contains("Currently only String typed view parameters are supported"); @@ -935,9 +928,7 @@ public void setViewParameterRejectsNonStringValues() { viewParams.put("age", intVal); IllegalArgumentException eMap = - assertThrows( - IllegalArgumentException.class, - () -> builder.setViewParameters(viewParams)); + assertThrows(IllegalArgumentException.class, () -> builder.setViewParameters(viewParams)); assertThat(eMap.getMessage()) .contains("Currently only String typed view parameters are supported"); @@ -946,13 +937,8 @@ public void setViewParameterRejectsNonStringValues() { // Null checks assertThrows( - NullPointerException.class, - () -> builder.setViewParameter(null, stringValue("alice"))); - assertThrows( - NullPointerException.class, - () -> builder.setViewParameter("user_id", null)); - assertThrows( - NullPointerException.class, - () -> builder.setViewParameters(null)); + NullPointerException.class, () -> builder.setViewParameter(null, stringValue("alice"))); + assertThrows(NullPointerException.class, () -> builder.setViewParameter("user_id", null)); + assertThrows(NullPointerException.class, () -> builder.setViewParameters(null)); } } From 1a170fcfe8e81054af20cbe86e5fc5583609e641 Mon Sep 17 00:00:00 2001 From: anweshadas Date: Fri, 17 Jul 2026 20:14:49 +0000 Subject: [PATCH 3/4] refactor(bigtable): add setStringViewParameter(s) to BoundStatement.Builder Change-Id: I2183f39fa9b6197648c84f40eabab770096d6953 --- .../data/v2/models/sql/BoundStatement.java | 36 ++++++++++++- .../v2/models/sql/BoundStatementTest.java | 54 +++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index 3234326a6285..280c242714c0 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -112,7 +112,33 @@ public BoundStatement build() { preparedStatement, ImmutableMap.copyOf(params), ImmutableMap.copyOf(viewParameters)); } - /** Sets a view parameter with the name {@code name} and the Value {@code value}. */ + /** + * Sets a view parameter with the name {@code paramName} and the String typed value {@code + * value}. + */ + public Builder setStringViewParameter(String paramName, @Nullable String value) { + Preconditions.checkNotNull(paramName, "paramName cannot be null"); + Preconditions.checkNotNull(value, "value cannot be null"); + viewParameters.put(paramName, stringParamOf(value)); + return this; + } + + /** Sets String typed view parameters from a map. */ + public Builder setStringViewParameters(Map viewParameters) { + Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); + for (Map.Entry entry : viewParameters.entrySet()) { + setStringViewParameter(entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * Sets a view parameter with the name {@code name} and the Value {@code value}. + * + *

This is considered an internal implementation detail and should not be used by + * applications. + */ + @InternalApi("For internal use only") public Builder setViewParameter(String name, Value value) { Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkNotNull(value, "value cannot be null"); @@ -123,7 +149,13 @@ public Builder setViewParameter(String name, Value value) { return this; } - /** Sets view parameters from a map. */ + /** + * Sets view parameters from a map. + * + *

This is considered an internal implementation detail and should not be used by + * applications. + */ + @InternalApi("For internal use only") public Builder setViewParameters(Map viewParameters) { Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); for (Map.Entry entry : viewParameters.entrySet()) { diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index 47ecc59e5fea..d9e08ae16b0a 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -891,6 +891,60 @@ public void statementWithViewParameters() { .build()); } + @Test + public void statementWithStringViewParameters() { + Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); + Value locationVal = Value.newBuilder().setType(stringType()).setStringValue("us-east1").build(); + + BoundStatement s = + boundStatementBuilder() + .setStringViewParameter("user_id", "alice") + .setStringViewParameter("location", "us-east1") + .build(); + + assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) + .isEqualTo( + ExecuteQueryRequest.newBuilder() + .setPreparedQuery(EXPECTED_PREPARED_QUERY) + .setInstanceName(EXPECTED_INSTANCE_NAME) + .setAppProfileId(EXPECTED_APP_PROFILE) + .putViewParameters("user_id", stringVal) + .putViewParameters("location", locationVal) + .build()); + } + + @Test + public void statementWithStringViewParametersMap() { + Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); + Value locationVal = Value.newBuilder().setType(stringType()).setStringValue("us-east1").build(); + + HashMap viewParams = new HashMap<>(); + viewParams.put("user_id", "alice"); + viewParams.put("location", "us-east1"); + + BoundStatement s = boundStatementBuilder().setStringViewParameters(viewParams).build(); + + assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) + .isEqualTo( + ExecuteQueryRequest.newBuilder() + .setPreparedQuery(EXPECTED_PREPARED_QUERY) + .setInstanceName(EXPECTED_INSTANCE_NAME) + .setAppProfileId(EXPECTED_APP_PROFILE) + .putViewParameters("user_id", stringVal) + .putViewParameters("location", locationVal) + .build()); + } + + @Test + public void setStringViewParametersNullChecks() { + BoundStatement.Builder builder = boundStatementBuilder(); + + assertThrows(NullPointerException.class, () -> builder.setStringViewParameter(null, "alice")); + assertThrows( + NullPointerException.class, () -> builder.setStringViewParameter("user_id", (String) null)); + assertThrows(NullPointerException.class, () -> builder.setStringViewParameters(null)); + } + @Test public void setViewParameterRejectsNonStringValues() { BoundStatement.Builder builder = boundStatementBuilder(); From c4c9e923c362f972743c2b575b2e69e8809d6bdf Mon Sep 17 00:00:00 2001 From: anweshadas Date: Fri, 17 Jul 2026 20:25:17 +0000 Subject: [PATCH 4/4] refactor(bigtable): address PR comments on view parameters API Change-Id: Ib5c71c01b359ac43e9ac68716020d6ab821ae7bd --- .../data/v2/models/sql/BoundStatement.java | 38 +------- .../v2/models/sql/BoundStatementTest.java | 89 ++++--------------- .../testproxy/BoundStatementDeserializer.java | 12 ++- 3 files changed, 31 insertions(+), 108 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index 280c242714c0..05e4e96f5fda 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -48,11 +48,14 @@ * paramName, Type value) for the appropriate type. For example: * *

{@code
- * BoundStatementt boundStatement = preparedStatement.bind()
+ * BoundStatement boundStatement = preparedStatement.bind()
  *     .setBytesParam("qualifier", ByteString.copyFromUtf8("test"))
  *     .setBytesParam("key", ByteString.copyFromUtf8("testKey"))
  *     .build();
  * }
+ * + *

View parameters can also be specified on the statement using {@link + * Builder#setStringViewParameter(String, String)} or {@link Builder#setStringViewParameters(Map)}. */ public class BoundStatement { @@ -118,7 +121,6 @@ public BoundStatement build() { */ public Builder setStringViewParameter(String paramName, @Nullable String value) { Preconditions.checkNotNull(paramName, "paramName cannot be null"); - Preconditions.checkNotNull(value, "value cannot be null"); viewParameters.put(paramName, stringParamOf(value)); return this; } @@ -132,38 +134,6 @@ public Builder setStringViewParameters(Map viewParameters) { return this; } - /** - * Sets a view parameter with the name {@code name} and the Value {@code value}. - * - *

This is considered an internal implementation detail and should not be used by - * applications. - */ - @InternalApi("For internal use only") - public Builder setViewParameter(String name, Value value) { - Preconditions.checkNotNull(name, "name cannot be null"); - Preconditions.checkNotNull(value, "value cannot be null"); - Preconditions.checkArgument( - value.getKindCase() == Value.KindCase.STRING_VALUE, - "Currently only String typed view parameters are supported"); - viewParameters.put(name, value); - return this; - } - - /** - * Sets view parameters from a map. - * - *

This is considered an internal implementation detail and should not be used by - * applications. - */ - @InternalApi("For internal use only") - public Builder setViewParameters(Map viewParameters) { - Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); - for (Map.Entry entry : viewParameters.entrySet()) { - setViewParameter(entry.getKey(), entry.getValue()); - } - return this; - } - /** * Sets a query parameter with the name {@code paramName} and the String typed value {@code * value} diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index d9e08ae16b0a..51e1cd591ac5 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -870,27 +870,6 @@ public void builderValidatesAllParamsAreSet() { .contains("Attempting to build BoundStatement without binding parameter: bytesParam"); } - @Test - public void statementWithViewParameters() { - Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); - Value locationVal = Value.newBuilder().setType(stringType()).setStringValue("us-east1").build(); - HashMap viewParams = new HashMap<>(); - viewParams.put("user_id", stringVal); - viewParams.put("location", locationVal); - - BoundStatement s = boundStatementBuilder().setViewParameters(viewParams).build(); - - assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) - .isEqualTo( - ExecuteQueryRequest.newBuilder() - .setPreparedQuery(EXPECTED_PREPARED_QUERY) - .setInstanceName(EXPECTED_INSTANCE_NAME) - .setAppProfileId(EXPECTED_APP_PROFILE) - .putViewParameters("user_id", stringVal) - .putViewParameters("location", locationVal) - .build()); - } - @Test public void statementWithStringViewParameters() { Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); @@ -936,63 +915,27 @@ public void statementWithStringViewParametersMap() { } @Test - public void setStringViewParametersNullChecks() { - BoundStatement.Builder builder = boundStatementBuilder(); + public void statementWithNullStringViewParameter() { + Value nullStringVal = Value.newBuilder().setType(stringType()).build(); - assertThrows(NullPointerException.class, () -> builder.setStringViewParameter(null, "alice")); - assertThrows( - NullPointerException.class, () -> builder.setStringViewParameter("user_id", (String) null)); - assertThrows(NullPointerException.class, () -> builder.setStringViewParameters(null)); + BoundStatement s = + boundStatementBuilder().setStringViewParameter("user_id", (String) null).build(); + + assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) + .isEqualTo( + ExecuteQueryRequest.newBuilder() + .setPreparedQuery(EXPECTED_PREPARED_QUERY) + .setInstanceName(EXPECTED_INSTANCE_NAME) + .setAppProfileId(EXPECTED_APP_PROFILE) + .putViewParameters("user_id", nullStringVal) + .build()); } @Test - public void setViewParameterRejectsNonStringValues() { + public void setStringViewParametersNullChecks() { BoundStatement.Builder builder = boundStatementBuilder(); - Value intVal = Value.newBuilder().setType(int64Type()).setIntValue(42).build(); - Value boolVal = Value.newBuilder().setType(boolType()).setBoolValue(true).build(); - Value unsetVal = Value.newBuilder().setType(stringType()).build(); - Value arrayVal = arrayValue(stringValue("foo"), stringValue("bar")); - - IllegalArgumentException eInt = - assertThrows(IllegalArgumentException.class, () -> builder.setViewParameter("age", intVal)); - assertThat(eInt.getMessage()) - .contains("Currently only String typed view parameters are supported"); - - IllegalArgumentException eBool = - assertThrows( - IllegalArgumentException.class, () -> builder.setViewParameter("active", boolVal)); - assertThat(eBool.getMessage()) - .contains("Currently only String typed view parameters are supported"); - - IllegalArgumentException eUnset = - assertThrows( - IllegalArgumentException.class, () -> builder.setViewParameter("unset", unsetVal)); - assertThat(eUnset.getMessage()) - .contains("Currently only String typed view parameters are supported"); - - IllegalArgumentException eArray = - assertThrows( - IllegalArgumentException.class, () -> builder.setViewParameter("tags", arrayVal)); - assertThat(eArray.getMessage()) - .contains("Currently only String typed view parameters are supported"); - - HashMap viewParams = new HashMap<>(); - viewParams.put( - "user_id", Value.newBuilder().setType(stringType()).setStringValue("alice").build()); - viewParams.put("age", intVal); - IllegalArgumentException eMap = - assertThrows(IllegalArgumentException.class, () -> builder.setViewParameters(viewParams)); - assertThat(eMap.getMessage()) - .contains("Currently only String typed view parameters are supported"); - - // Empty map should succeed without error - builder.setViewParameters(Collections.emptyMap()); - - // Null checks - assertThrows( - NullPointerException.class, () -> builder.setViewParameter(null, stringValue("alice"))); - assertThrows(NullPointerException.class, () -> builder.setViewParameter("user_id", null)); - assertThrows(NullPointerException.class, () -> builder.setViewParameters(null)); + assertThrows(NullPointerException.class, () -> builder.setStringViewParameter(null, "alice")); + assertThrows(NullPointerException.class, () -> builder.setStringViewParameters(null)); } } diff --git a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java index 56b40d0d5957..76513fa0bd8f 100644 --- a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java +++ b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java @@ -128,7 +128,17 @@ static BoundStatement toBoundStatement( throw new IllegalArgumentException("Unexpected query param type in param: " + value); } } - boundStatementBuilder.setViewParameters(request.getRequest().getViewParametersMap()); + for (Map.Entry entry : request.getRequest().getViewParametersMap().entrySet()) { + String name = entry.getKey(); + Value value = entry.getValue(); + if (value.getKindCase().equals(KindCase.KIND_NOT_SET)) { + boundStatementBuilder.setStringViewParameter(name, null); + } else if (value.getKindCase().equals(KindCase.STRING_VALUE)) { + boundStatementBuilder.setStringViewParameter(name, value.getStringValue()); + } else { + throw new IllegalArgumentException("Unexpected view parameter type in param: " + value); + } + } return boundStatementBuilder.build(); }