Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
<cassandra-driver.version>4.19.0</cassandra-driver.version>
<dist.id>spring-data-cassandra</dist.id>
<multithreadedtc.version>1.01</multithreadedtc.version>
<springdata.commons>4.1.0-SNAPSHOT</springdata.commons>
<springdata.commons>4.1.0-GH-3400-SNAPSHOT</springdata.commons>
</properties>

<dependencyManagement>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
import java.util.Set;

import org.springframework.data.cassandra.core.mapping.CassandraPersistentEntity;
import org.springframework.data.cassandra.core.mapping.CassandraPersistentProperty;
import org.springframework.data.cassandra.core.query.Filter;
import org.springframework.data.cassandra.core.query.Update;
import org.springframework.data.core.TypeInformation;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.util.Assert;

import com.datastax.oss.driver.api.core.type.DataType;
Expand Down Expand Up @@ -81,10 +81,10 @@ public Update getMappedObject(Update update, CassandraPersistentEntity<?> entity

Field field = createPropertyField(entity, assignmentOp.getColumnName());

field.getProperty().filter(it -> it.getOrdinal() != null).ifPresent(it -> {
if (field.hasProperty(CassandraPersistentProperty::hasOrdinal)) {
throw new IllegalArgumentException(
String.format("Cannot reference tuple value elements, property [%s]", field.getMappedKey()));
});
}

mapped.add(getMappedUpdateOperation(assignmentOp, field));
}
Expand Down Expand Up @@ -128,8 +128,9 @@ private AssignmentOp getMappedUpdateOperation(Field field, SetOp updateOp) {
Assert.state(op.getValue() != null,
() -> String.format("SetAtKeyOp for %s attempts to set null", field.getProperty()));

Optional<? extends TypeInformation<?>> typeInformation = field.getProperty()
.map(PersistentProperty::getTypeInformation);
Optional<? extends TypeInformation<?>> typeInformation = field.hasProperty()
? Optional.of(field.getProperty().getTypeInformation())
: Optional.empty();

Optional<TypeInformation<?>> keyType = typeInformation.map(TypeInformation::getComponentType);
Optional<TypeInformation<?>> valueType = typeInformation.map(TypeInformation::getMapValueType);
Expand Down Expand Up @@ -161,9 +162,9 @@ private AssignmentOp getMappedUpdateOperation(Field field, SetOp updateOp) {

if (collection.isEmpty()) {

int protocolCode = field.getProperty()
.map(property -> getConverter().getColumnTypeResolver().resolve(property).getDataType())
.map(DataType::getProtocolCode).orElse(ProtocolConstants.DataType.LIST);
int protocolCode = field.hasProperty()
? getConverter().getColumnTypeResolver().resolve(field.getProperty()).getDataType().getProtocolCode()
: ProtocolConstants.DataType.LIST;

if (protocolCode == ProtocolConstants.DataType.SET) {
return new SetOp(field.getMappedKey(), Collections.emptySet());
Expand All @@ -184,7 +185,7 @@ private AssignmentOp getMappedUpdateOperation(Field field, RemoveOp updateOp) {
ColumnType descriptor = getColumnType(field, value, ColumnTypeTransformer.AS_IS);
boolean mapLike = false;

if (field.getProperty().isPresent() && field.getProperty().get().isMapLike()) {
if (field.hasProperty(CassandraPersistentProperty::isMapLike)) {

descriptor = getColumnType(field, value, value instanceof Collection ? ColumnTypeTransformer.ENCLOSING_MAP_KEY_SET
: ColumnTypeTransformer.MAP_KEY_TYPE);
Expand All @@ -207,9 +208,9 @@ private AssignmentOp getMappedUpdateOperation(Field field, AddToOp updateOp) {
ColumnType descriptor = getColumnType(field, value, ColumnTypeTransformer.AS_IS);
Collection<Object> mappedValue = (Collection) getConverter().convertToColumnType(value, descriptor);

if (field.getProperty().isPresent()) {
if (field.hasProperty()) {

DataType dataType = getConverter().getColumnTypeResolver().resolve(field.getProperty().get()).getDataType();
DataType dataType = getConverter().getColumnTypeResolver().resolve(field.getProperty()).getDataType();

if (dataType instanceof SetType && !(mappedValue instanceof Set)) {
Collection<Object> collection = new HashSet<>();
Expand All @@ -229,8 +230,9 @@ private AssignmentOp getMappedUpdateOperation(Field field, AddToOp updateOp) {

private AssignmentOp getMappedUpdateOperation(Field field, AddToMapOp updateOp) {

Optional<? extends TypeInformation<?>> typeInformation = field.getProperty()
.map(PersistentProperty::getTypeInformation);
Optional<? extends TypeInformation<?>> typeInformation = field.hasProperty()
? Optional.of(field.getProperty().getTypeInformation())
: Optional.empty();

Optional<TypeInformation<?>> keyType = typeInformation.map(TypeInformation::getComponentType);
Optional<TypeInformation<?>> valueType = typeInformation.map(TypeInformation::getMapValueType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ private CqlIdentifier determineColumnName() {
}

String overriddenName = null;
boolean forceQuote = false;

Column column = findAnnotation(Column.class);

Expand Down Expand Up @@ -209,6 +208,7 @@ protected Association<CassandraPersistentProperty> createAssociation() {

@Override
public boolean isMapLike() {
// TODO: Super isMap?
return ClassUtils.isAssignable(Map.class, getType());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import java.util.Optional;

import org.jspecify.annotations.Nullable;

import org.springframework.data.core.PropertyPath;
import org.springframework.data.core.TypedPropertyPath;
import org.springframework.util.Assert;

import com.datastax.oss.driver.api.core.CqlIdentifier;
Expand All @@ -36,6 +39,28 @@
*/
public abstract class ColumnName {

/**
* Create a {@link ColumnName} given a {@link TypedPropertyPath property}.
*
* @param property must not be {@literal null}.
* @return the {@link ColumnName} for {@link PropertyPath}
* @since 5.1
*/
public static <T, P> ColumnName from(TypedPropertyPath<T, P> property) {
return from((PropertyPath) TypedPropertyPath.of(property));
}

/**
* Create a {@link ColumnName} given a {@link PropertyPath property}.
*
* @param propertyPath must not be {@literal null}.
* @return the {@link ColumnName} for {@link PropertyPath}
* @since 5.1
*/
public static ColumnName from(PropertyPath propertyPath) {
return new PropertyPathColumnName(propertyPath);
}

/**
* Create a {@link ColumnName} given {@link CqlIdentifier}. The resulting instance uses CQL identifier rules to
* identify column names (quoting, case-sensitivity).
Expand All @@ -45,9 +70,6 @@ public abstract class ColumnName {
* @see CqlIdentifier
*/
public static ColumnName from(CqlIdentifier cqlIdentifier) {

Assert.notNull(cqlIdentifier, "Column name must not be null");

return new CqlIdentifierColumnName(cqlIdentifier);
}

Expand All @@ -56,26 +78,79 @@ public static ColumnName from(CqlIdentifier cqlIdentifier) {
* column names (case-sensitivity).
*
* @param columnName must not be {@literal null} or empty.
* @return the {@link ColumnName} for {@link CqlIdentifier}
* @return the {@link ColumnName} for {@code columnName}
*/
public static ColumnName from(String columnName) {

Assert.hasText(columnName, "Column name must not be null or empty");

return new StringColumnName(columnName);
}

/**
* @return the optional column name.
*/
public abstract Optional<String> getColumnName();
public Optional<String> getColumnName() {
return Optional.empty();
}

/**
* Indicates whether a column name is available.
*
* @return {@literal true} if a (string or {@link CqlIdentifier}) column name is available; {@literal false}
* otherwise.
* @since 5.1
*/
public boolean hasColumnName() {
return getColumnName().isPresent();
}

/**
* @return the optional {@link PropertyPath}.
*/
public @Nullable PropertyPath getPropertyPath() {
return null;
}

/**
* Indicates whether a {@link PropertyPath} is available.
*
* @return {@literal true} if a {@link PropertyPath} is available; {@literal false} otherwise.
* @since 5.1
*/
public boolean hasPropertyPath() {
return getPropertyPath() != null;
}

/**
* Returns the required {@link PropertyPath} or throws an {@link IllegalStateException} if not available.
*
* @return the required {@link PropertyPath}.
* @throws IllegalStateException if no {@link PropertyPath} is available.
* @since 5.1
*/
public PropertyPath getRequiredPropertyPath() {

PropertyPath propertyPath = getPropertyPath();

if (propertyPath == null) {
throw new IllegalStateException("No PropertyPath available");
}

return propertyPath;
}

/**
* @return the optional {@link CqlIdentifier}.
*/
public abstract Optional<CqlIdentifier> getCqlIdentifier();
public Optional<CqlIdentifier> getCqlIdentifier() {
return Optional.empty();
}

CqlIdentifier getRequiredCqlIdentifier() {
/**
* Returns the required {@link CqlIdentifier} or constructs one from available information.
*
* @return the required {@link CqlIdentifier}.
* @since 5.1
*/
public CqlIdentifier getRequiredCqlIdentifier() {
return getCqlIdentifier().or(() -> getColumnName().map(CqlIdentifier::fromCql))
.orElseGet(() -> CqlIdentifier.fromCql(toCql()));
}
Expand Down Expand Up @@ -110,6 +185,54 @@ public int hashCode() {
return hashValue;
}

/**
* {@link PropertyPath}-based column name representation.
*
* @author Mark Paluch
*/
static class PropertyPathColumnName extends ColumnName {

private final PropertyPath propertyPath;

PropertyPathColumnName(PropertyPath propertyPath) {

Assert.notNull(propertyPath, "Property path must not be null");

this.propertyPath = propertyPath;
}

@Override
public Optional<String> getColumnName() {
return Optional.of(toCql());
}

@Override
public PropertyPath getPropertyPath() {
return propertyPath;
}

@Override
public boolean equals(@Nullable Object obj) {
return super.equals(obj)
&& (obj instanceof PropertyPathColumnName that && this.propertyPath.equals(that.propertyPath));
}

@Override
public String toCql() {
return this.propertyPath.toDotPath();
}

@Override
public String toString() {

if (this.propertyPath.hasNext()) {
return this.propertyPath.toString();
}

return this.propertyPath.toDotPath();
}
}

/**
* {@link String}-based column name representation. Preserves letter casing.
*
Expand All @@ -120,6 +243,9 @@ static class StringColumnName extends ColumnName {
private final String columnName;

StringColumnName(String columnName) {

Assert.hasText(columnName, "Column name must not be null or empty");

this.columnName = columnName;
}

Expand All @@ -128,11 +254,6 @@ public Optional<String> getColumnName() {
return Optional.of(columnName);
}

@Override
public Optional<CqlIdentifier> getCqlIdentifier() {
return Optional.empty();
}

@Override
public String toCql() {
return this.columnName;
Expand All @@ -154,12 +275,10 @@ static class CqlIdentifierColumnName extends ColumnName {
private final CqlIdentifier cqlIdentifier;

CqlIdentifierColumnName(CqlIdentifier cqlIdentifier) {
this.cqlIdentifier = cqlIdentifier;
}

@Override
public Optional<String> getColumnName() {
return Optional.empty();
Assert.notNull(cqlIdentifier, "Column name must not be null");

this.cqlIdentifier = cqlIdentifier;
}

@Override
Expand Down
Loading
Loading