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..311a247d5721 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,25 @@ 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 String value {@code value} */ + public Builder setViewParameter(String name, String value) { + Preconditions.checkNotNull(name, "name cannot be null"); + Preconditions.checkNotNull(value, "value cannot be null"); + viewParameters.put(name, stringParamOf(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 +397,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..891aacabc9da 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 @@ -53,6 +53,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; import org.junit.Test; import org.junit.runner.RunWith; @@ -869,4 +870,53 @@ public void builderValidatesAllParamsAreSet() { assertThat(e.getMessage()) .contains("Attempting to build BoundStatement without binding parameter: bytesParam"); } + + @Test + public void statementWithViewParameters() { + Map viewParams = new HashMap<>(); + viewParams.put("user_id", "alice"); + viewParams.put("role", "admin"); + + 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", + Value.newBuilder().setType(stringType()).setStringValue("alice").build()) + .putViewParameters( + "role", + Value.newBuilder().setType(stringType()).setStringValue("admin").build()) + .build()); + } + + @Test + public void statementWithSingleViewParameter() { + BoundStatement s = boundStatementBuilder().setViewParameter("user_id", "alice").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", + Value.newBuilder().setType(stringType()).setStringValue("alice").build()) + .build()); + } + + @Test + public void statementWithNullViewParameter() { + assertThrows( + NullPointerException.class, () -> boundStatementBuilder().setViewParameter(null, "alice")); + assertThrows( + NullPointerException.class, + () -> boundStatementBuilder().setViewParameter("user_id", null)); + assertThrows(NullPointerException.class, () -> boundStatementBuilder().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..3cbece85f3e7 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,18 @@ static BoundStatement toBoundStatement( throw new IllegalArgumentException("Unexpected query param type in param: " + value); } } + for (Map.Entry entry : request.getRequest().getViewParametersMap().entrySet()) { + Value value = entry.getValue(); + if (value.getKindCase().equals(KindCase.STRING_VALUE)) { + boundStatementBuilder.setViewParameter(entry.getKey(), value.getStringValue()); + } else { + throw new IllegalArgumentException( + "View parameter '" + + entry.getKey() + + "' must be a String, got: " + + value.getKindCase()); + } + } return boundStatementBuilder.build(); }