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 @@ -11,7 +11,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra-parent</artifactId>
<version>5.0.0-SNAPSHOT</version>
<version>5.0.0-GH-1566-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data for Apache Cassandra</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-cassandra-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra-parent</artifactId>
<version>5.0.0-SNAPSHOT</version>
<version>5.0.0-GH-1566-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
26 changes: 20 additions & 6 deletions spring-data-cassandra/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra-parent</artifactId>
<version>5.0.0-SNAPSHOT</version>
<version>5.0.0-GH-1566-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand All @@ -24,6 +24,12 @@

<dependencies>

<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.0</version>
</dependency>

<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
Expand All @@ -50,6 +56,12 @@
<artifactId>spring-tx</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core-test</artifactId>
<scope>test</scope>
</dependency>

<!-- Spring Data -->
<dependency>
<groupId>${project.groupId}</groupId>
Expand Down Expand Up @@ -198,6 +210,13 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit-assertj</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>edu.umd.cs.mtc</groupId>
<artifactId>multithreadedtc</artifactId>
Expand Down Expand Up @@ -227,11 +246,6 @@
<artifactId>kotlinx-coroutines-reactor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.0</version>
</dependency>

<dependency>
<groupId>io.mockk</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.springframework.data.cassandra.core;

import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
Expand Down Expand Up @@ -423,6 +424,27 @@ <T, R> List<R> doSelect(Query query, Class<?> entityClass, CqlIdentifier tableNa
return doQuery(select.build(), rowMapper);
}

ResultSet doSelectResultSet(Query query, Class<?> entityClass, CqlIdentifier tableName) {

CassandraPersistentEntity<?> entity = getRequiredPersistentEntity(entityClass);

StatementBuilder<Select> select = getStatementFactory().select(query, entity, tableName);
SimpleStatement statement = select.build();

return queryForResultSet(statement);
}

ResultSet queryForResultSet(Statement<?> statement) {

if (PreparedStatementDelegate.canPrepare(isUsePreparedStatements(), statement, log)) {

PreparedStatementHandler statementHandler = createPreparedStatementHandler(statement);
return getCqlOperations().query(statementHandler, statementHandler, resultSet -> resultSet);
}

return getCqlOperations().queryForResultSet(statement);
}

@Override
public <T> @Nullable T selectOne(Query query, Class<T> entityClass) throws DataAccessException {

Expand Down Expand Up @@ -970,6 +992,11 @@ private <T> Function<Row, T> getMapper(EntityProjection<T, ?> projection, CqlIde

Class<T> targetType = projection.getMappedType().getType();

if (Map.class.isAssignableFrom(targetType)) {
ColumnMapRowMapper columnMapRowMapper = new ColumnMapRowMapper();
return row -> (T) columnMapRowMapper.mapRow(row, 0);
}

return row -> {

maybeEmitEvent(() -> new AfterLoadEvent<>(row, targetType, tableName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public interface ExecutableSelectOperation {
*
* @since 5.0
*/
interface UntypedSelect {
interface UntypedSelect extends TerminatingProjections {

/**
* Define the {@link Class result target type} that the Cassandra Row fields should be mapped to.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.springframework.util.ObjectUtils;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.core.cql.Statement;

Expand Down Expand Up @@ -91,6 +93,21 @@ public <T> TerminatingResults<T> map(RowMapper<T> mapper) {
return new TerminatingSelectResultSupport<>(template, statement, mapper);
}

@Override
public long count() {

List<Row> rows = template.select(statement, Row.class);

if (rows.size() == 1) {

Object object = rows.get(0).getObject(0);

return ((Number) object).longValue();
}

return 0;
}

}

static class TypedSelectSupport<T> extends TerminatingSelectResultSupport<T, T> implements TerminatingResults<T> {
Expand All @@ -99,7 +116,9 @@ static class TypedSelectSupport<T> extends TerminatingSelectResultSupport<T, T>

TypedSelectSupport(CassandraTemplate template, Statement<?> statement, Class<T> domainType) {
super(template, statement,
template.getRowMapper(domainType, EntityQueryUtils.getTableName(statement), QueryResultConverter.entity()));
ResultSet.class.isAssignableFrom(domainType) ? null
: template.getRowMapper(domainType, EntityQueryUtils.getTableName(statement),
QueryResultConverter.entity()));

this.domainType = domainType;
}
Expand All @@ -120,9 +139,10 @@ static class TerminatingSelectResultSupport<S, T> implements TerminatingResults<

final Statement<?> statement;

final RowMapper<T> rowMapper;
final @Nullable RowMapper<T> rowMapper;

TerminatingSelectResultSupport(CassandraTemplate template, Statement<?> statement, RowMapper<T> rowMapper) {
TerminatingSelectResultSupport(CassandraTemplate template, Statement<?> statement,
@Nullable RowMapper<T> rowMapper) {
this.template = template;
this.statement = statement;
this.rowMapper = rowMapper;
Expand Down Expand Up @@ -156,6 +176,10 @@ public <R> TerminatingResults<R> map(QueryResultConverter<? super T, ? extends R
@Override
public @Nullable T oneValue() {

if (this.rowMapper == null) {
return (T) this.template.queryForResultSet(this.statement);
}

List<T> result = this.template.getCqlOperations().query(this.statement, this.rowMapper);

if (ObjectUtils.isEmpty(result)) {
Expand Down Expand Up @@ -271,6 +295,10 @@ public boolean exists() {
@Override
public @Nullable T oneValue() {

if (this.returnType.equals(ResultSet.class)) {
return (T) this.template.doSelectResultSet(this.query.limit(2), this.domainType, getTableName());
}

List<T> result = this.template.doSelect(this.query.limit(2), this.domainType, getTableName(), this.returnType,
this.mappingFunction);

Expand All @@ -279,8 +307,8 @@ public boolean exists() {
}

if (result.size() > 1) {
throw new IncorrectResultSizeDataAccessException(
String.format("Query [%s] returned non unique result", this.query), 1);
throw new IncorrectResultSizeDataAccessException(1, result.size());

}

return result.iterator().next();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.convert.QueryMapper;
import org.springframework.data.cassandra.core.convert.UpdateMapper;
Expand Down Expand Up @@ -73,6 +74,7 @@
import org.springframework.util.ClassUtils;

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.data.CqlVector;
import com.datastax.oss.driver.api.core.metadata.schema.ClusteringOrder;
import com.datastax.oss.driver.api.querybuilder.BindMarker;
Expand Down Expand Up @@ -615,7 +617,8 @@ public StatementBuilder<Delete> delete(Object entity, QueryOptions options, Enti
Columns computeColumnsForProjection(EntityProjection<?, ?> projection, Columns columns,
CassandraPersistentEntity<?> domainType, Class<?> returnType) {

if (!columns.isEmpty() || ClassUtils.isAssignable(domainType.getType(), returnType)) {
if (!columns.isEmpty() || ClassUtils.isAssignable(domainType.getType(), returnType)
|| ClassUtils.isAssignable(Map.class, returnType) || ClassUtils.isAssignable(ResultSet.class, returnType)) {
return columns;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public Filter getMappedObject(Filter filter, CassandraPersistentEntity<?> entity
return Filter.from(result);
}

private @Nullable Object getMappedValue(Field field, CriteriaDefinition.Operator operator, Object value) {
protected @Nullable Object getMappedValue(Field field, CriteriaDefinition.Operator operator, Object value) {

if (field.getProperty().isPresent()
&& field.getProperty().filter(it -> converter.getCustomConversions().hasValueConverter(it)).isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ public Query pageRequest(Pageable pageable) {

CassandraPageRequest.validatePageable(pageable);

if (pageable.isUnpaged()) {
return this;
}

CassandraScrollPosition scrollPosition = getScrollPosition();

if (pageable instanceof CassandraPageRequest cpr) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2025 the original author or authors.
*
* 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
*
* https://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 org.springframework.data.cassandra.repository.aot;

import java.util.List;

import org.springframework.data.cassandra.repository.query.ParameterBinding;
import org.springframework.data.domain.Limit;

/**
* AOT query value object along with its parameter bindings.
*
* @author Mark Paluch
* @since 5.0
*/
abstract class AotQuery {

private final List<ParameterBinding> parameterBindings;

AotQuery(List<ParameterBinding> parameterBindings) {
this.parameterBindings = parameterBindings;
}

/**
* @return the list of parameter bindings.
*/
public List<ParameterBinding> getParameterBindings() {
return parameterBindings;
}

/**
* @return the preliminary query limit.
*/
public Limit getLimit() {
return Limit.unlimited();
}

/**
* @return whether the query is limited (e.g. {@code findTop10By}).
*/
public boolean isLimited() {
return getLimit().isLimited();
}

/**
* @return whether the query a delete query.
*/
public boolean isDelete() {
return false;
}

/**
* @return whether the query is a count query.
*/
public boolean isCount() {
return false;
}

/**
* @return whether the query is an exists query.
*/
public boolean isExists() {
return false;
}

}
Loading