Skip to content

Commit 2e0c44c

Browse files
SiyaoIsHidingabsurdfarce
authored andcommitted
JAVA-3143: Extend driver vector support to arbitrary subtypes and fix handling of variable length types (OSS C* 5.0)
patch by Jane He; reviewed by Bret McGuire and João Reis reference: #1952
1 parent 342e2dc commit 2e0c44c

File tree

30 files changed

+1002
-232
lines changed

30 files changed

+1002
-232
lines changed

core/revapi.json

Lines changed: 297 additions & 0 deletions
Large diffs are not rendered by default.

core/src/main/java/com/datastax/oss/driver/api/core/data/CqlVector.java

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@
1818
package com.datastax.oss.driver.api.core.data;
1919

2020
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
21+
import com.datastax.oss.driver.internal.core.type.codec.ParseUtils;
2122
import com.datastax.oss.driver.shaded.guava.common.base.Preconditions;
2223
import com.datastax.oss.driver.shaded.guava.common.base.Predicates;
23-
import com.datastax.oss.driver.shaded.guava.common.base.Splitter;
2424
import com.datastax.oss.driver.shaded.guava.common.collect.Iterables;
25-
import com.datastax.oss.driver.shaded.guava.common.collect.Streams;
2625
import edu.umd.cs.findbugs.annotations.NonNull;
2726
import java.io.IOException;
2827
import java.io.InvalidObjectException;
@@ -35,7 +34,6 @@
3534
import java.util.Iterator;
3635
import java.util.List;
3736
import java.util.Objects;
38-
import java.util.stream.Collectors;
3937
import java.util.stream.Stream;
4038

4139
/**
@@ -52,15 +50,15 @@
5250
* where possible we've tried to make the API of this class similar to the equivalent methods on
5351
* {@link List}.
5452
*/
55-
public class CqlVector<T extends Number> implements Iterable<T>, Serializable {
53+
public class CqlVector<T> implements Iterable<T>, Serializable {
5654

5755
/**
5856
* Create a new CqlVector containing the specified values.
5957
*
6058
* @param vals the collection of values to wrap.
6159
* @return a CqlVector wrapping those values
6260
*/
63-
public static <V extends Number> CqlVector<V> newInstance(V... vals) {
61+
public static <V> CqlVector<V> newInstance(V... vals) {
6462

6563
// Note that Array.asList() guarantees the return of an array which implements RandomAccess
6664
return new CqlVector(Arrays.asList(vals));
@@ -73,29 +71,64 @@ public static <V extends Number> CqlVector<V> newInstance(V... vals) {
7371
* @param list the collection of values to wrap.
7472
* @return a CqlVector wrapping those values
7573
*/
76-
public static <V extends Number> CqlVector<V> newInstance(List<V> list) {
74+
public static <V> CqlVector<V> newInstance(List<V> list) {
7775
Preconditions.checkArgument(list != null, "Input list should not be null");
7876
return new CqlVector(list);
7977
}
8078

8179
/**
82-
* Create a new CqlVector instance from the specified string representation. Note that this method
83-
* is intended to mirror {@link #toString()}; passing this method the output from a <code>toString
84-
* </code> call on some CqlVector should return a CqlVector that is equal to the origin instance.
80+
* Create a new CqlVector instance from the specified string representation.
8581
*
8682
* @param str a String representation of a CqlVector
8783
* @param subtypeCodec
8884
* @return a new CqlVector built from the String representation
8985
*/
90-
public static <V extends Number> CqlVector<V> from(
91-
@NonNull String str, @NonNull TypeCodec<V> subtypeCodec) {
86+
public static <V> CqlVector<V> from(@NonNull String str, @NonNull TypeCodec<V> subtypeCodec) {
9287
Preconditions.checkArgument(str != null, "Cannot create CqlVector from null string");
9388
Preconditions.checkArgument(!str.isEmpty(), "Cannot create CqlVector from empty string");
94-
ArrayList<V> vals =
95-
Streams.stream(Splitter.on(", ").split(str.substring(1, str.length() - 1)))
96-
.map(subtypeCodec::parse)
97-
.collect(Collectors.toCollection(ArrayList::new));
98-
return new CqlVector(vals);
89+
if (str.equalsIgnoreCase("NULL")) return null;
90+
91+
int idx = ParseUtils.skipSpaces(str, 0);
92+
if (str.charAt(idx++) != '[')
93+
throw new IllegalArgumentException(
94+
String.format(
95+
"Cannot parse vector value from \"%s\", at character %d expecting '[' but got '%c'",
96+
str, idx, str.charAt(idx)));
97+
98+
idx = ParseUtils.skipSpaces(str, idx);
99+
100+
if (str.charAt(idx) == ']') {
101+
return new CqlVector<>(new ArrayList<>());
102+
}
103+
104+
List<V> list = new ArrayList<>();
105+
while (idx < str.length()) {
106+
int n;
107+
try {
108+
n = ParseUtils.skipCQLValue(str, idx);
109+
} catch (IllegalArgumentException e) {
110+
throw new IllegalArgumentException(
111+
String.format(
112+
"Cannot parse vector value from \"%s\", invalid CQL value at character %d",
113+
str, idx),
114+
e);
115+
}
116+
117+
list.add(subtypeCodec.parse(str.substring(idx, n)));
118+
idx = n;
119+
120+
idx = ParseUtils.skipSpaces(str, idx);
121+
if (str.charAt(idx) == ']') return new CqlVector<>(list);
122+
if (str.charAt(idx++) != ',')
123+
throw new IllegalArgumentException(
124+
String.format(
125+
"Cannot parse vector value from \"%s\", at character %d expecting ',' but got '%c'",
126+
str, idx, str.charAt(idx)));
127+
128+
idx = ParseUtils.skipSpaces(str, idx);
129+
}
130+
throw new IllegalArgumentException(
131+
String.format("Malformed vector value \"%s\", missing closing ']'", str));
99132
}
100133

101134
private final List<T> list;
@@ -194,6 +227,11 @@ public int hashCode() {
194227
return Objects.hash(list);
195228
}
196229

230+
/**
231+
* The string representation of the vector. Elements, like strings, may not be properly quoted.
232+
*
233+
* @return the string representation
234+
*/
197235
@Override
198236
public String toString() {
199237
return Iterables.toString(this.list);
@@ -205,7 +243,7 @@ public String toString() {
205243
*
206244
* @param <T> inner type of CqlVector, assume Number is always Serializable.
207245
*/
208-
private static class SerializationProxy<T extends Number> implements Serializable {
246+
private static class SerializationProxy<T> implements Serializable {
209247

210248
private static final long serialVersionUID = 1;
211249

core/src/main/java/com/datastax/oss/driver/api/core/data/GettableById.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ default CqlDuration getCqlDuration(@NonNull CqlIdentifier id) {
531531
* @throws IllegalArgumentException if the id is invalid.
532532
*/
533533
@Nullable
534-
default <ElementT extends Number> CqlVector<ElementT> getVector(
534+
default <ElementT> CqlVector<ElementT> getVector(
535535
@NonNull CqlIdentifier id, @NonNull Class<ElementT> elementsClass) {
536536
return getVector(firstIndexOf(id), elementsClass);
537537
}

core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByIndex.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,7 @@ default CqlDuration getCqlDuration(int i) {
446446
* @throws IndexOutOfBoundsException if the index is invalid.
447447
*/
448448
@Nullable
449-
default <ElementT extends Number> CqlVector<ElementT> getVector(
450-
int i, @NonNull Class<ElementT> elementsClass) {
449+
default <ElementT> CqlVector<ElementT> getVector(int i, @NonNull Class<ElementT> elementsClass) {
451450
return get(i, GenericType.vectorOf(elementsClass));
452451
}
453452

core/src/main/java/com/datastax/oss/driver/api/core/data/GettableByName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ default CqlDuration getCqlDuration(@NonNull String name) {
527527
* @throws IllegalArgumentException if the name is invalid.
528528
*/
529529
@Nullable
530-
default <ElementT extends Number> CqlVector<ElementT> getVector(
530+
default <ElementT> CqlVector<ElementT> getVector(
531531
@NonNull String name, @NonNull Class<ElementT> elementsClass) {
532532
return getVector(firstIndexOf(name), elementsClass);
533533
}

core/src/main/java/com/datastax/oss/driver/api/core/data/SettableById.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ default SelfT setCqlDuration(@NonNull CqlIdentifier id, @Nullable CqlDuration v)
573573
*/
574574
@NonNull
575575
@CheckReturnValue
576-
default <ElementT extends Number> SelfT setVector(
576+
default <ElementT> SelfT setVector(
577577
@NonNull CqlIdentifier id,
578578
@Nullable CqlVector<ElementT> v,
579579
@NonNull Class<ElementT> elementsClass) {

core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByIndex.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ default SelfT setCqlDuration(int i, @Nullable CqlDuration v) {
425425
*/
426426
@NonNull
427427
@CheckReturnValue
428-
default <ElementT extends Number> SelfT setVector(
428+
default <ElementT> SelfT setVector(
429429
int i, @Nullable CqlVector<ElementT> v, @NonNull Class<ElementT> elementsClass) {
430430
return set(i, v, GenericType.vectorOf(elementsClass));
431431
}

core/src/main/java/com/datastax/oss/driver/api/core/data/SettableByName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ default SelfT setCqlDuration(@NonNull String name, @Nullable CqlDuration v) {
572572
*/
573573
@NonNull
574574
@CheckReturnValue
575-
default <ElementT extends Number> SelfT setVector(
575+
default <ElementT> SelfT setVector(
576576
@NonNull String name,
577577
@Nullable CqlVector<ElementT> v,
578578
@NonNull Class<ElementT> elementsClass) {

core/src/main/java/com/datastax/oss/driver/api/core/type/DataTypes.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,10 @@
2727
import com.datastax.oss.driver.internal.core.type.DefaultTupleType;
2828
import com.datastax.oss.driver.internal.core.type.DefaultVectorType;
2929
import com.datastax.oss.driver.internal.core.type.PrimitiveType;
30-
import com.datastax.oss.driver.shaded.guava.common.base.Splitter;
3130
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList;
3231
import com.datastax.oss.protocol.internal.ProtocolConstants;
3332
import edu.umd.cs.findbugs.annotations.NonNull;
3433
import java.util.Arrays;
35-
import java.util.List;
3634

3735
/** Constants and factory methods to obtain data type instances. */
3836
public class DataTypes {
@@ -59,7 +57,6 @@ public class DataTypes {
5957
public static final DataType DURATION = new PrimitiveType(ProtocolConstants.DataType.DURATION);
6058

6159
private static final DataTypeClassNameParser classNameParser = new DataTypeClassNameParser();
62-
private static final Splitter paramSplitter = Splitter.on(',').trimResults();
6360

6461
@NonNull
6562
public static DataType custom(@NonNull String className) {
@@ -68,20 +65,8 @@ public static DataType custom(@NonNull String className) {
6865
if (className.equals("org.apache.cassandra.db.marshal.DurationType")) return DURATION;
6966

7067
/* Vector support is currently implemented as a custom type but is also parameterized */
71-
if (className.startsWith(DefaultVectorType.VECTOR_CLASS_NAME)) {
72-
List<String> params =
73-
paramSplitter.splitToList(
74-
className.substring(
75-
DefaultVectorType.VECTOR_CLASS_NAME.length() + 1, className.length() - 1));
76-
DataType subType = classNameParser.parse(params.get(0), AttachmentPoint.NONE);
77-
int dimensions = Integer.parseInt(params.get(1));
78-
if (dimensions <= 0) {
79-
throw new IllegalArgumentException(
80-
String.format(
81-
"Request to create vector of size %d, size must be positive", dimensions));
82-
}
83-
return new DefaultVectorType(subType, dimensions);
84-
}
68+
if (className.startsWith(DefaultVectorType.VECTOR_CLASS_NAME))
69+
return classNameParser.parse(className, AttachmentPoint.NONE);
8570
return new DefaultCustomType(className);
8671
}
8772

core/src/main/java/com/datastax/oss/driver/api/core/type/codec/TypeCodec.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import edu.umd.cs.findbugs.annotations.NonNull;
2929
import edu.umd.cs.findbugs.annotations.Nullable;
3030
import java.nio.ByteBuffer;
31+
import java.util.Optional;
3132

3233
/**
3334
* Manages the two-way conversion between a CQL type and a Java type.
@@ -234,4 +235,9 @@ default boolean accepts(@NonNull DataType cqlType) {
234235
*/
235236
@Nullable
236237
JavaTypeT parse(@Nullable String value);
238+
239+
@NonNull
240+
default Optional<Integer> serializedSize() {
241+
return Optional.empty();
242+
}
237243
}

0 commit comments

Comments
 (0)