Skip to content

DATATMONGO-2077 - Enhance SpEL aggregation support. #639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
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 @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<version>2.2.0.DATAMONGO-2077-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<version>2.2.0.DATAMONGO-2077-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-mongodb-cross-store/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<version>2.2.0.DATAMONGO-2077-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -50,7 +50,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<version>2.2.0.DATAMONGO-2077-SNAPSHOT</version>
</dependency>

<!-- reactive -->
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<version>2.2.0.DATAMONGO-2077-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>2.2.0.BUILD-SNAPSHOT</version>
<version>2.2.0.DATAMONGO-2077-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("strLenBytes", singleArgumentAggregationMethodReference().forOperator("$strLenBytes"));
map.put("strLenCP", singleArgumentAggregationMethodReference().forOperator("$strLenCP"));
map.put("substrCP", arrayArgumentAggregationMethodReference().forOperator("$substrCP"));
map.put("trim", mapArgumentAggregationMethodReference().forOperator("$trim").mappingParametersTo("input", "chars"));
map.put("ltrim",
mapArgumentAggregationMethodReference().forOperator("$ltrim").mappingParametersTo("input", "chars"));
map.put("rtrim",
mapArgumentAggregationMethodReference().forOperator("$rtrim").mappingParametersTo("input", "chars"));

// TEXT SEARCH OPERATORS
map.put("meta", singleArgumentAggregationMethodReference().forOperator("$meta"));
Expand All @@ -116,6 +121,9 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("zip", mapArgumentAggregationMethodReference().forOperator("$zip").mappingParametersTo("inputs",
"useLongestLength", "defaults"));
map.put("in", arrayArgumentAggregationMethodReference().forOperator("$in"));
map.put("arrayToObject", singleArgumentAggregationMethodReference().forOperator("$arrayToObject"));
map.put("indexOfArray", arrayArgumentAggregationMethodReference().forOperator("$indexOfArray"));
map.put("range", arrayArgumentAggregationMethodReference().forOperator("$range"));

// VARIABLE OPERATORS
map.put("map", mapArgumentAggregationMethodReference().forOperator("$map") //
Expand All @@ -138,6 +146,15 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("millisecond", singleArgumentAggregationMethodReference().forOperator("$millisecond"));
map.put("dateToString", mapArgumentAggregationMethodReference().forOperator("$dateToString") //
.mappingParametersTo("format", "date"));
map.put("dateFromString", mapArgumentAggregationMethodReference().forOperator("$dateFromString") //
.mappingParametersTo("dateString", "format", "timezone", "onError", "onNull"));
map.put("dateFromParts", mapArgumentAggregationMethodReference().forOperator("$dateFromParts")
.mappingParametersTo("year", "month", "day", "hour", "minute", "second", "milliseconds", "timezone"));
map.put("isoDateFromParts",
mapArgumentAggregationMethodReference().forOperator("$dateFromParts").mappingParametersTo("isoWeekYear",
"isoWeek", "isoDayOfWeek", "hour", "minute", "second", "milliseconds", "timezone"));
map.put("dateToParts", mapArgumentAggregationMethodReference().forOperator("$dateToParts") //
.mappingParametersTo("date", "timezone", "iso8601"));
map.put("isoDayOfWeek", singleArgumentAggregationMethodReference().forOperator("$isoDayOfWeek"));
map.put("isoWeek", singleArgumentAggregationMethodReference().forOperator("$isoWeek"));
map.put("isoWeekYear", singleArgumentAggregationMethodReference().forOperator("$isoWeekYear"));
Expand All @@ -162,6 +179,24 @@ public class MethodReferenceNode extends ExpressionNode {
// TYPE OPERATORS
map.put("type", singleArgumentAggregationMethodReference().forOperator("$type"));

// OBJECT OPERATORS
map.put("objectToArray", singleArgumentAggregationMethodReference().forOperator("$objectToArray"));
map.put("mergeObjects", arrayArgumentAggregationMethodReference().forOperator("$mergeObjects"));

// CONVERT OPERATORS
map.put("convert", mapArgumentAggregationMethodReference().forOperator("$convert") //
.mappingParametersTo("input", "to", "onError", "onNull"));
map.put("toBool", singleArgumentAggregationMethodReference().forOperator("$toBool"));
map.put("toDate", singleArgumentAggregationMethodReference().forOperator("$toDate"));
map.put("toDecimal", singleArgumentAggregationMethodReference().forOperator("$toDecimal"));
map.put("toDouble", singleArgumentAggregationMethodReference().forOperator("$toDouble"));
map.put("toInt", singleArgumentAggregationMethodReference().forOperator("$toInt"));
map.put("toLong", singleArgumentAggregationMethodReference().forOperator("$toLong"));
map.put("toObjectId", singleArgumentAggregationMethodReference().forOperator("$toObjectId"));
map.put("toString", singleArgumentAggregationMethodReference().forOperator("$toString"));



FUNCTIONS = Collections.unmodifiableMap(map);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,216 @@ public void shouldRenderMethodRefereneType() {
assertThat(transform("type(a)"), is(Document.parse("{ \"$type\" : \"$a\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderArrayToObjectWithFieldReference() {
assertThat(transform("arrayToObject(field)"), is(Document.parse("{ \"$arrayToObject\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderArrayToObjectWithArray() {

assertThat(transform("arrayToObject(new String[]{'key', 'value'})"),
is(Document.parse("{ \"$arrayToObject\" : [\"key\", \"value\"]}")));
}

@Test // DATAMONGO-2077
public void shouldRenderObjectToArrayWithFieldReference() {
assertThat(transform("objectToArray(field)"), is(Document.parse("{ \"$objectToArray\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderMergeObjects() {

assertThat(transform("mergeObjects(field1, $$ROOT)"),
is(Document.parse("{ \"$mergeObjects\" : [\"$field1\", \"$$ROOT\"]}")));
}

@Test // DATAMONGO-2077
public void shouldRenderTrimWithoutChars() {
assertThat(transform("trim(field)"), is(Document.parse("{ \"$trim\" : {\"input\" : \"$field\"}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderTrimWithChars() {

assertThat(transform("trim(field, 'ie')"),
is(Document.parse("{ \"$trim\" : {\"input\" : \"$field\", \"chars\" : \"ie\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderTrimWithCharsFromFieldReference() {

assertThat(transform("trim(field1, field2)"),
is(Document.parse("{ \"$trim\" : {\"input\" : \"$field1\", \"chars\" : \"$field2\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderLtrimWithoutChars() {
assertThat(transform("ltrim(field)"), is(Document.parse("{ \"$ltrim\" : {\"input\" : \"$field\"}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderLtrimWithChars() {

assertThat(transform("ltrim(field, 'ie')"),
is(Document.parse("{ \"$ltrim\" : {\"input\" : \"$field\", \"chars\" : \"ie\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderLtrimWithCharsFromFieldReference() {

assertThat(transform("ltrim(field1, field2)"),
is(Document.parse("{ \"$ltrim\" : {\"input\" : \"$field1\", \"chars\" : \"$field2\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderRtrimWithoutChars() {
assertThat(transform("rtrim(field)"), is(Document.parse("{ \"$rtrim\" : {\"input\" : \"$field\"}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderRtrimWithChars() {

assertThat(transform("rtrim(field, 'ie')"),
is(Document.parse("{ \"$rtrim\" : {\"input\" : \"$field\", \"chars\" : \"ie\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderRtrimWithCharsFromFieldReference() {

assertThat(transform("rtrim(field1, field2)"),
is(Document.parse("{ \"$rtrim\" : {\"input\" : \"$field1\", \"chars\" : \"$field2\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderConvertWithoutOptionalParameters() {

assertThat(transform("convert(field, 'string')"),
is(Document.parse("{ \"$convert\" : {\"input\" : \"$field\", \"to\" : \"string\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderConvertWithOnError() {

assertThat(transform("convert(field, 'int', 'Not an integer.')"), is(Document
.parse("{ \"$convert\" : {\"input\" : \"$field\", \"to\" : \"int\", \"onError\" : \"Not an integer.\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderConvertWithOnErrorOnNull() {

assertThat(transform("convert(field, 'int', 'Not an integer.', -1)"), is(Document.parse(
"{ \"$convert\" : {\"input\" : \"$field\", \"to\" : \"int\", \"onError\" : \"Not an integer.\", \"onNull\" : -1 }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToBool() {
assertThat(transform("toBool(field)"), is(Document.parse("{ \"$toBool\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToDate() {
assertThat(transform("toDate(field)"), is(Document.parse("{ \"$toDate\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToDecimal() {
assertThat(transform("toDecimal(field)"), is(Document.parse("{ \"$toDecimal\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToDouble() {
assertThat(transform("toDouble(field)"), is(Document.parse("{ \"$toDouble\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToInt() {
assertThat(transform("toInt(field)"), is(Document.parse("{ \"$toInt\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToLong() {
assertThat(transform("toLong(field)"), is(Document.parse("{ \"$toLong\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToObjectId() {
assertThat(transform("toObjectId(field)"), is(Document.parse("{ \"$toObjectId\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderToString() {
assertThat(transform("toString(field)"), is(Document.parse("{ \"$toString\" : \"$field\"}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateFromStringWithoutOptionalParameters() {

assertThat(transform("dateFromString(field)"),
is(Document.parse("{ \"$dateFromString\" : {\"dateString\" : \"$field\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateFromStringWithFormat() {

assertThat(transform("dateFromString(field, 'DD-MM-YYYY')"),
is(Document.parse("{ \"$dateFromString\" : {\"dateString\" : \"$field\", \"format\" : \"DD-MM-YYYY\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateFromStringWithFormatAndTimezone() {

assertThat(transform("dateFromString(field, 'DD-MM-YYYY', 'UTC')"), is(Document.parse(
"{ \"$dateFromString\" : {\"dateString\" : \"$field\", \"format\" : \"DD-MM-YYYY\", \"timezone\" : \"UTC\" }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateFromStringWithFormatTimezoneAndOnError() {

assertThat(transform("dateFromString(field, 'DD-MM-YYYY', 'UTC', -1)"), is(Document.parse(
"{ \"$dateFromString\" : {\"dateString\" : \"$field\", \"format\" : \"DD-MM-YYYY\", \"timezone\" : \"UTC\", \"onError\" : -1 }}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateFromStringWithFormatTimezoneOnErrorAndOnNull() {

assertThat(transform("dateFromString(field, 'DD-MM-YYYY', 'UTC', -1, -2)"), is(Document.parse(
"{ \"$dateFromString\" : {\"dateString\" : \"$field\", \"format\" : \"DD-MM-YYYY\", \"timezone\" : \"UTC\", \"onError\" : -1, \"onNull\" : -2}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateFromParts() {

assertThat(transform("dateFromParts(y, m, d, h, mm, s, ms, 'UTC')"), is(Document.parse(
"{ \"$dateFromParts\" : {\"year\" : \"$y\", \"month\" : \"$m\", \"day\" : \"$d\", \"hour\" : \"$h\", \"minute\" : \"$mm\", \"second\" : \"$s\", \"milliseconds\" : \"$ms\", \"timezone\" : \"UTC\"}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderIsoDateFromParts() {

assertThat(transform("isoDateFromParts(y, m, d, h, mm, s, ms, 'UTC')"), is(Document.parse(
"{ \"$dateFromParts\" : {\"isoWeekYear\" : \"$y\", \"isoWeek\" : \"$m\", \"isoDayOfWeek\" : \"$d\", \"hour\" : \"$h\", \"minute\" : \"$mm\", \"second\" : \"$s\", \"milliseconds\" : \"$ms\", \"timezone\" : \"UTC\"}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderDateToParts() {

assertThat(transform("dateToParts(field, 'UTC', false)"), is(
Document.parse("{ \"$dateToParts\" : {\"date\" : \"$field\", \"timezone\" : \"UTC\", \"iso8601\" : false}}")));
}

@Test // DATAMONGO-2077
public void shouldRenderIndexOfArray() {

assertThat(transform("indexOfArray(field, 2)"), is(Document.parse("{ \"$indexOfArray\" : [\"$field\", 2 ]}")));
}

@Test // DATAMONGO-2077
public void shouldRenderRange() {

assertThat(transform("range(0, 10, 2)"), is(Document.parse("{ \"$range\" : [0, 10, 2 ]}")));
}

private Object transform(String expression, Object... params) {
Object result = transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
return result == null ? null : (!(result instanceof org.bson.Document) ? result.toString() : result);
Expand Down