Browse Source

DATAMONGO-840 - Improve support for nested field references in SpEL expressions within Projections.

We now correctly add a compound expression that represents a field reference to the previous operation arguments if necessary.

Original pull request: #118.
pull/118/merge
Thomas Darimont 12 years ago committed by Oliver Gierke
parent
commit
88c968ad36
  1. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformer.java
  2. 40
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java
  3. 74
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/Invoice.java
  4. 46
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/LineItem.java
  5. 70
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/Order.java
  6. 23
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformer.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2014 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.
@ -495,7 +495,7 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer { @@ -495,7 +495,7 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
if (currentNode.hasfirstChildNotOfType(Indexer.class)) {
// we have a property path expression like: foo.bar -> render as reference
return context.getFieldReference().toString();
return context.addToPreviousOrReturn(context.getFieldReference().toString());
}
return context.addToPreviousOrReturn(currentNode.getValue());

40
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationTests.java

@ -782,6 +782,46 @@ public class AggregationTests { @@ -782,6 +782,46 @@ public class AggregationTests {
assertThat(String.valueOf(firstItem.get("_id")), is("u1"));
}
/**
* @see DATAMONGO-840
*/
@Test
public void shouldAggregateOrderDataToAnInvoice() {
mongoTemplate.dropCollection(Order.class);
double taxRate = 0.19;
LineItem product1 = new LineItem("1", "p1", 1.23);
LineItem product2 = new LineItem("2", "p2", 0.87, 2);
LineItem product3 = new LineItem("3", "p3", 5.33);
Order order = new Order("o4711", "c42", new Date()).addItem(product1).addItem(product2).addItem(product3);
mongoTemplate.save(order);
AggregationResults<Invoice> results = mongoTemplate.aggregate(newAggregation(Order.class, //
match(where("id").is(order.getId())), unwind("items"), //
project("id", "customerId", "items") //
.andExpression("items.price * items.quantity").as("lineTotal"), //
group("id") //
.sum("lineTotal").as("netAmount") //
.addToSet("items").as("items"), //
project("id", "items", "netAmount") //
.and("orderId").previousOperation() //
.andExpression("netAmount * [0]", taxRate).as("taxAmount") //
.andExpression("netAmount * (1 + [0])", taxRate).as("totalAmount") //
), Invoice.class);
Invoice invoice = results.getUniqueMappedResult();
assertThat(invoice, is(notNullValue()));
assertThat(invoice.getOrderId(), is(order.getId()));
assertThat(invoice.getNetAmount(), is(closeTo(8.3, 000001)));
assertThat(invoice.getTaxAmount(), is(closeTo(1.577, 000001)));
assertThat(invoice.getTotalAmount(), is(closeTo(9.877, 000001)));
}
private void assertLikeStats(LikeStats like, String id, long count) {
assertThat(like, is(notNullValue()));

74
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/Invoice.java

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
/*
* Copyright 2014 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
*
* http://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.mongodb.core.aggregation;
import java.util.List;
/**
* @author Thomas Darimont
*/
public class Invoice {
String orderId;
double taxAmount;
double netAmount;
double totalAmount;
List<LineItem> items;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public double getTaxAmount() {
return taxAmount;
}
public void setTaxAmount(double taxAmount) {
this.taxAmount = taxAmount;
}
public double getNetAmount() {
return netAmount;
}
public void setNetAmount(double netAmount) {
this.netAmount = netAmount;
}
public double getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(double totalAmount) {
this.totalAmount = totalAmount;
}
public List<LineItem> getItems() {
return items;
}
public void setItems(List<LineItem> items) {
this.items = items;
}
}

46
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/LineItem.java

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
/*
* Copyright 2014 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
*
* http://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.mongodb.core.aggregation;
/**
* @author Thomas Darimont
*/
public class LineItem {
final String id;
final String caption;
final double price;
int quantity = 1;
@SuppressWarnings("unused")
private LineItem() {
this(null, null, 0.0, 0);
}
public LineItem(String id, String caption, double price) {
this.id = id;
this.caption = caption;
this.price = price;
}
public LineItem(String id, String caption, double price, int quantity) {
this(id, caption, price);
this.quantity = quantity;
}
}

70
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/Order.java

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
/*
* Copyright 2014 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
*
* http://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.mongodb.core.aggregation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* @author Thomas Darimont
*/
public class Order {
final String id;
final String customerId;
final Date orderDate;
final List<LineItem> items;
public Order(String id, String customerId, Date orderDate) {
this(id, customerId, orderDate, new ArrayList<LineItem>());
}
public Order(String id, String customerId, Date orderDate, List<LineItem> items) {
this.id = id;
this.customerId = customerId;
this.orderDate = orderDate;
this.items = items;
}
public Order addItem(LineItem item) {
List<LineItem> newItems = new ArrayList<LineItem>(items != null ? items : Collections.<LineItem> emptyList());
newItems.add(item);
return new Order(id, customerId, orderDate, newItems);
}
public String getId() {
return id;
}
public String getCustomerId() {
return customerId;
}
public Date getOrderDate() {
return orderDate;
}
public List<LineItem> getItems() {
return items;
}
}

23
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2014 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.
@ -21,6 +21,7 @@ import static org.junit.Assert.*; @@ -21,6 +21,7 @@ import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.data.mongodb.core.Person;
/**
* Unit tests for {@link SpelExpressionTransformer}.
@ -174,6 +175,26 @@ public class SpelExpressionTransformerUnitTests { @@ -174,6 +175,26 @@ public class SpelExpressionTransformerUnitTests {
is("{ \"$multiply\" : [ { \"$add\" : [ 1 , 42 , 1.2345]} , 23]}"));
}
/**
* @see DATAMONGO-840
*/
@Test
public void shouldRenderCompoundExpressionsWithIndexerAndFieldReference() {
Person person = new Person();
person.setAge(10);
assertThat(transform("[0].age + a.c", person), is("{ \"$add\" : [ 10 , \"$a.c\"]}"));
}
/**
* @see DATAMONGO-840
*/
@Test
public void shouldRenderCompoundExpressionsWithOnlyFieldReferences() {
assertThat(transform("a.b + a.c"), is("{ \"$add\" : [ \"$a.b\" , \"$a.c\"]}"));
}
@Test
public void shouldRenderStringFunctions() {

Loading…
Cancel
Save