Skip to content

Commit

Permalink
JAVA-1799: Use CqlIdentifier for simple statement named values
Browse files Browse the repository at this point in the history
  • Loading branch information
olim7t committed Apr 12, 2018
1 parent cd3bbd5 commit 4cc5e6b
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 22 deletions.
1 change: 1 addition & 0 deletions changelog/README.md
Expand Up @@ -4,6 +4,7 @@

### 4.0.0-alpha4 (in progress)

- [improvement] JAVA-1799: Use CqlIdentifier for simple statement named values
- [new feature] JAVA-1515: Add query builder
- [improvement] JAVA-1773: Make DriverConfigProfile enumerable
- [improvement] JAVA-1787: Use standalone shaded Guava artifact
Expand Down
Expand Up @@ -19,6 +19,7 @@
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.DefaultProtocolVersion;
import com.datastax.oss.driver.api.core.session.Request;
import com.datastax.oss.driver.internal.core.CqlIdentifiers;
import com.datastax.oss.driver.internal.core.cql.DefaultSimpleStatement;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -100,7 +101,7 @@ static SimpleStatement newInstance(String cqlQuery, Map<String, Object> namedVal
return new DefaultSimpleStatement(
cqlQuery,
Collections.emptyList(),
namedValues,
CqlIdentifiers.wrapKeys(namedValues),
null,
null,
null,
Expand Down Expand Up @@ -148,7 +149,7 @@ static SimpleStatementBuilder builder(SimpleStatement template) {
* method. However custom implementations may choose to be mutable and return the same instance.
*
* @see #setPositionalValues(List)
* @see #setNamedValues(Map)
* @see #setNamedValuesWithIds(Map)
*/
SimpleStatement setQuery(String newQuery);

Expand Down Expand Up @@ -176,9 +177,9 @@ default SimpleStatement setKeyspace(String newKeyspaceName) {
/**
* Sets the positional values to bind to anonymous placeholders.
*
* <p>You can use either positional or named values, but not both. Therefore if this method
* returns a non-empty list, then {@link #getNamedValues()} must return an empty map, otherwise a
* runtime error will be thrown.
* <p>You can use either positional or named values, but not both. Therefore if you call this
* method but {@link #getNamedValues()} returns a non-empty map, an {@link
* IllegalArgumentException} will be thrown.
*
* <p>The driver's built-in implementation is immutable, and returns a new instance from this
* method. However custom implementations may choose to be mutable and return the same instance.
Expand All @@ -187,21 +188,29 @@ default SimpleStatement setKeyspace(String newKeyspaceName) {
*/
SimpleStatement setPositionalValues(List<Object> newPositionalValues);

Map<String, Object> getNamedValues();
Map<CqlIdentifier, Object> getNamedValues();

/**
* Sets the named values to bind to named placeholders.
*
* <p>Names must be stripped of the leading column.
*
* <p>You can use either positional or named values, but not both. Therefore if this method
* returns a non-empty map, then {@link #getPositionalValues()} must return an empty list,
* otherwise a runtime error will be thrown.
* <p>You can use either positional or named values, but not both. Therefore if you call this
* method but {@link #getPositionalValues()} returns a non-empty list, an {@link
* IllegalArgumentException} will be thrown.
*
* <p>The driver's built-in implementation is immutable, and returns a new instance from this
* method. However custom implementations may choose to be mutable and return the same instance.
*
* @see #setQuery(String)
*/
SimpleStatement setNamedValues(Map<String, Object> newNamedValues);
SimpleStatement setNamedValuesWithIds(Map<CqlIdentifier, Object> newNamedValues);

/**
* Shortcut for {@link #setNamedValuesWithIds(Map)} with raw strings as value names. The keys are
* converted on the fly with {@link CqlIdentifier#fromCql(String)}.
*/
default SimpleStatement setNamedValues(Map<String, Object> newNamedValues) {
return setNamedValuesWithIds(CqlIdentifiers.wrapKeys(newNamedValues));
}
}
Expand Up @@ -30,7 +30,7 @@ public class SimpleStatementBuilder
private String query;
private CqlIdentifier keyspace;
private ImmutableList.Builder<Object> positionalValuesBuilder;
private ImmutableMap.Builder<String, Object> namedValuesBuilder;
private ImmutableMap.Builder<CqlIdentifier, Object> namedValuesBuilder;

public SimpleStatementBuilder(String query) {
this.query = query;
Expand All @@ -49,7 +49,7 @@ public SimpleStatementBuilder(SimpleStatement template) {
}
if (!template.getNamedValues().isEmpty()) {
this.namedValuesBuilder =
ImmutableMap.<String, Object>builder().putAll(template.getNamedValues());
ImmutableMap.<CqlIdentifier, Object>builder().putAll(template.getNamedValues());
}
}

Expand Down Expand Up @@ -110,8 +110,8 @@ public SimpleStatementBuilder clearPositionalValues() {
return this;
}

/** @see SimpleStatement#setNamedValues(Map) */
public SimpleStatementBuilder addNamedValue(String name, Object value) {
/** @see SimpleStatement#setNamedValuesWithIds(Map) */
public SimpleStatementBuilder addNamedValue(CqlIdentifier name, Object value) {
if (positionalValuesBuilder != null) {
throw new IllegalArgumentException(
"Can't have both positional and named values in a statement.");
Expand All @@ -123,7 +123,15 @@ public SimpleStatementBuilder addNamedValue(String name, Object value) {
return this;
}

/** @see SimpleStatement#setNamedValues(Map) */
/**
* Shortcut for {@link #addNamedValue(CqlIdentifier, Object)
* addNamedValue(CqlIdentifier.fromCql(name), value)}.
*/
public SimpleStatementBuilder addNamedValue(String name, Object value) {
return addNamedValue(CqlIdentifier.fromCql(name), value);
}

/** @see SimpleStatement#setNamedValuesWithIds(Map) */
public SimpleStatementBuilder clearNamedValues() {
namedValuesBuilder = null;
return this;
Expand Down
@@ -0,0 +1,31 @@
/*
* Copyright DataStax, Inc.
*
* 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.datastax.oss.driver.internal.core;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
import java.util.Map;

public class CqlIdentifiers {

public static <V> Map<CqlIdentifier, V> wrapKeys(Map<String, V> in) {
ImmutableMap.Builder<CqlIdentifier, V> out = ImmutableMap.builder();
for (Map.Entry<String, V> entry : in.entrySet()) {
out.put(CqlIdentifier.fromCql(entry.getKey()), entry.getValue());
}
return out.build();
}
}
Expand Up @@ -223,13 +223,16 @@ public static List<ByteBuffer> encode(
}

public static Map<String, ByteBuffer> encode(
Map<String, Object> values, CodecRegistry codecRegistry, ProtocolVersion protocolVersion) {
Map<CqlIdentifier, Object> values,
CodecRegistry codecRegistry,
ProtocolVersion protocolVersion) {
if (values.isEmpty()) {
return Collections.emptyMap();
} else {
ImmutableMap.Builder<String, ByteBuffer> encodedValues = ImmutableMap.builder();
for (Map.Entry<String, Object> entry : values.entrySet()) {
encodedValues.put(entry.getKey(), encode(entry.getValue(), codecRegistry, protocolVersion));
for (Map.Entry<CqlIdentifier, Object> entry : values.entrySet()) {
encodedValues.put(
entry.getKey().asInternal(), encode(entry.getValue(), codecRegistry, protocolVersion));
}
return encodedValues.build();
}
Expand Down
Expand Up @@ -29,7 +29,7 @@ public class DefaultSimpleStatement implements SimpleStatement {

private final String query;
private final List<Object> positionalValues;
private final Map<String, Object> namedValues;
private final Map<CqlIdentifier, Object> namedValues;
private final String configProfileName;
private final DriverConfigProfile configProfile;
private final CqlIdentifier keyspace;
Expand All @@ -47,7 +47,7 @@ public class DefaultSimpleStatement implements SimpleStatement {
public DefaultSimpleStatement(
String query,
List<Object> positionalValues,
Map<String, Object> namedValues,
Map<CqlIdentifier, Object> namedValues,
String configProfileName,
DriverConfigProfile configProfile,
CqlIdentifier keyspace,
Expand Down Expand Up @@ -127,12 +127,12 @@ public SimpleStatement setPositionalValues(List<Object> newPositionalValues) {
}

@Override
public Map<String, Object> getNamedValues() {
public Map<CqlIdentifier, Object> getNamedValues() {
return namedValues;
}

@Override
public SimpleStatement setNamedValues(Map<String, Object> newNamedValues) {
public SimpleStatement setNamedValuesWithIds(Map<CqlIdentifier, Object> newNamedValues) {
return new DefaultSimpleStatement(
query,
positionalValues,
Expand Down
Expand Up @@ -17,6 +17,7 @@

import static org.assertj.core.api.Assertions.assertThat;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException;
import com.datastax.oss.driver.api.testinfra.ccm.CcmRule;
Expand Down Expand Up @@ -270,4 +271,14 @@ public void should_fail_when_mixing_positional_and_named_values() {
.addNamedValue(":k", KEY)
.build();
}

@Test
public void should_use_positional_value_with_case_sensitive_id() {
SimpleStatement statement =
SimpleStatement.builder("SELECT count(*) FROM test2 WHERE k=:\"theKey\"")
.addNamedValue(CqlIdentifier.fromCql("\"theKey\""), 0)
.build();
Row row = cluster.session().execute(statement).one();
assertThat(row.getLong(0)).isEqualTo(0);
}
}

0 comments on commit 4cc5e6b

Please sign in to comment.