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..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,20 +48,28 @@
* 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 {
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 +86,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 +99,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 +111,27 @@ 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 paramName} and the String typed value {@code
+ * value}.
+ */
+ public Builder setStringViewParameter(String paramName, @Nullable String value) {
+ Preconditions.checkNotNull(paramName, "paramName 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;
}
/**
@@ -372,7 +402,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..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
@@ -869,4 +869,73 @@ public void builderValidatesAllParamsAreSet() {
assertThat(e.getMessage())
.contains("Attempting to build BoundStatement without binding parameter: bytesParam");
}
+
+ @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 statementWithNullStringViewParameter() {
+ Value nullStringVal = Value.newBuilder().setType(stringType()).build();
+
+ 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 setStringViewParametersNullChecks() {
+ BoundStatement.Builder builder = boundStatementBuilder();
+
+ 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 43da147274f7..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,6 +128,17 @@ static BoundStatement toBoundStatement(
throw new IllegalArgumentException("Unexpected query param type in param: " + value);
}
}
+ 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();
}