Skip to content

Commit

Permalink
feature: support parameters on @Aggregation annotation value (query)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsbodden committed Feb 11, 2025
1 parent f7ea19a commit ee74e06
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -590,8 +591,11 @@ private Object executeAggregation(Object[] parameters) {
String indexName = indexer.getIndexName(this.domainType);
SearchOperations<String> ops = modulesOperations.opsForSearch(indexName);

// Handle parameters in the base query
String preparedQuery = prepareQuery(parameters, true);

// build the aggregation
AggregationBuilder aggregation = new AggregationBuilder(value);
AggregationBuilder aggregation = new AggregationBuilder(preparedQuery);

// timeout
if (aggregationTimeout != null) {
Expand Down Expand Up @@ -763,8 +767,8 @@ private String prepareQuery(final Object[] parameters, boolean excludeNullParams
v = parameters[index].toString();
}

String regex = "\\$" + key + "\\b";
preparedQuery = new StringBuilder(preparedQuery.toString().replaceAll(regex, v));
var regex = "(\\$" + Pattern.quote(key) + "(?![a-zA-Z0-9_]))(\\W+|\\*|\\+|$)?";
preparedQuery = new StringBuilder(preparedQuery.toString().replaceAll(regex, v + "$2"));
}
index++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
Expand Down Expand Up @@ -599,8 +600,11 @@ private Object executeAggregation(Object[] parameters) {
String indexName = indexer.getIndexName(this.domainType);
SearchOperations<String> ops = modulesOperations.opsForSearch(indexName);

// Handle parameters in the base query
String preparedQuery = prepareQuery(parameters, true);

// build the aggregation
AggregationBuilder aggregation = new AggregationBuilder(value);
AggregationBuilder aggregation = new AggregationBuilder(preparedQuery);

// timeout
if (aggregationTimeout != null) {
Expand Down Expand Up @@ -773,8 +777,8 @@ private String prepareQuery(final Object[] parameters, boolean excludeNullParams
v = ObjectUtils.asString(parameters[index], mappingConverter);
}

var regex = "(\\$" + key + ")(\\W+|\\*|\\+)(.*)";
preparedQuery = new StringBuilder(preparedQuery.toString().replaceAll(regex, v + "$2$3"));
var regex = "(\\$" + Pattern.quote(key) + "(?![a-zA-Z0-9_]))(\\W+|\\*|\\+|$)?";
preparedQuery = new StringBuilder(preparedQuery.toString().replaceAll(regex, v + "$2"));
}
index++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,21 @@ void testFirstValue() {
.forEach(j -> assertThat(row.getString(expectedData[i][j][0])).isEqualToIgnoringCase(expectedData[i][j][1]));
});
}

@Test
void testAggregationParams() {
String[][] expectedData = { //
{ "Genius", "88.54" }, { "Logitech", "78.98" }, { "Monster", "69.95" }, { "Goliton", "15.69" },
{ "Lenmar", "15.41" }, { "Oceantree(TM)", "12.29" }, { "Oceantree", "11.39" }, { "oooo", "10.11" },
{ "Case Logic", "9.99" }, { "Neewer", "9.71" } //
};
var result = repository.minPricesByBrand("sony");
assertThat(result.getTotalResults()).isEqualTo(27);

IntStream.range(0, expectedData.length - 1).forEach(i -> {
var row = result.getRow(i);
assertThat(row.getString("brand").toLowerCase()).isEqualTo(expectedData[i][0].toLowerCase());
assertThat(row.getString("minPrice")).isEqualTo(expectedData[i][1]);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,22 @@ void testLoadWithDocId() {
.forEach(j -> assertThat(row.getString(expectedData[i][j][0])).isEqualTo(expectedData[i][j][1]));
});
}

@Test
void testAggregationParams() {
String[][] expectedData = { //
{ "Genius", "88.54" }, { "Logitech", "78.98" }, { "Monster", "69.95" }, { "Goliton", "15.69" },
{ "Lenmar", "15.41" }, { "Oceantree(TM)", "12.29" }, { "Oceantree", "11.39" }, { "oooo", "10.11" },
{ "Case Logic", "9.99" }, { "Neewer", "9.71" } //
};
var result = repository.minPricesByBrand("sony");
assertThat(result.getTotalResults()).isEqualTo(27);

IntStream.range(0, expectedData.length - 1).forEach(i -> {
var row = result.getRow(i);
assertThat(row.getString("brand")).isEqualTo(expectedData[i][0].toLowerCase());
assertThat(row.getString("minPrice")).isEqualTo(expectedData[i][1]);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.repository.query.Param;
import redis.clients.jedis.search.aggr.AggregationResult;

import java.util.Map;
Expand Down Expand Up @@ -61,6 +62,33 @@ public interface GameRepository extends RedisDocumentRepository<Game, String> {
//
AggregationResult minPricesContainingSony();


/**
* <pre>
* "FT.AGGREGATE" "com.redis.om.spring.annotations.document.fixtures.GameIdx" "sony"
* "GROUPBY" "1" "@brand"
* "REDUCE" "COUNT" "0"
* "REDUCE" "MIN" "1" "@price" "AS" "minPrice"
* "SORTBY" "2" "@minPrice" "DESC"
* </pre>
*/
@Aggregation( //
value = "$brand", //
groupBy = { //
@GroupBy( //
properties = "@brand", //
reduce = { //
@Reducer(func = ReducerFunction.COUNT), //
@Reducer(func = ReducerFunction.MIN, args = { "@price" }, alias = "minPrice") } //
) //
}, //
sortBy = { //
@SortBy(field = "@minPrice", direction = Direction.DESC), //
}
)
//
AggregationResult minPricesByBrand(@Param("brand") String brand);

/**
* <pre>
* "FT.AGGREGATE" "com.redis.om.spring.annotations.document.fixtures.GameIdx" "sony"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.repository.query.Param;
import redis.clients.jedis.search.aggr.AggregationResult;

import java.util.Map;
Expand Down Expand Up @@ -61,6 +62,32 @@ public interface GameRepository extends RedisEnhancedRepository<Game, String> {
//
AggregationResult minPricesContainingSony();

/**
* <pre>
* "FT.AGGREGATE" "com.redis.om.spring.annotations.document.fixtures.GameIdx" "sony"
* "GROUPBY" "1" "@brand"
* "REDUCE" "COUNT" "0"
* "REDUCE" "MIN" "1" "@price" "AS" "minPrice"
* "SORTBY" "2" "@minPrice" "DESC"
* </pre>
*/
@Aggregation( //
value = "$brand", //
groupBy = { //
@GroupBy( //
properties = "@brand", //
reduce = { //
@Reducer(func = ReducerFunction.COUNT), //
@Reducer(func = ReducerFunction.MIN, args = { "@price" }, alias = "minPrice") } //
) //
}, //
sortBy = { //
@SortBy(field = "@minPrice", direction = Direction.DESC), //
}
)
//
AggregationResult minPricesByBrand(@Param("brand") String brand);

/**
* <pre>
* "FT.AGGREGATE" "com.redis.om.spring.annotations.document.fixtures.GameIdx" "sony"
Expand Down

0 comments on commit ee74e06

Please sign in to comment.