Browse Source

Configure relaxed/strict field lookup when creating `AggregationOperationContext`.

Closes #4714
Original pull request: #4720
pull/4759/head
Christoph Strobl 2 years ago committed by Mark Paluch
parent
commit
f5b7a389b2
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOperationRenderer.java
  2. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java
  3. 2
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DocumentEnhancingOperation.java
  4. 18
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java
  5. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/InheritingExposedFieldsAggregationOperationContext.java
  6. 7
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/VariableOperators.java
  7. 45
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationOperationRendererUnitTests.java

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AggregationOperationRenderer.java

@ -50,6 +50,7 @@ class AggregationOperationRenderer { @@ -50,6 +50,7 @@ class AggregationOperationRenderer {
List<Document> operationDocuments = new ArrayList<Document>(operations.size());
AggregationOperationContext contextToUse = rootContext;
boolean relaxed = rootContext instanceof RelaxedTypeBasedAggregationOperationContext;
for (AggregationOperation operation : operations) {
@ -60,12 +61,13 @@ class AggregationOperationRenderer { @@ -60,12 +61,13 @@ class AggregationOperationRenderer {
ExposedFields fields = exposedFieldsOperation.getFields();
if (operation instanceof InheritsFieldsAggregationOperation || exposedFieldsOperation.inheritsFields()) {
contextToUse = new InheritingExposedFieldsAggregationOperationContext(fields, contextToUse);
contextToUse = new InheritingExposedFieldsAggregationOperationContext(fields, contextToUse, relaxed);
} else {
contextToUse = fields.exposesNoFields() ? DEFAULT_CONTEXT
: new ExposedFieldsAggregationOperationContext(fields, contextToUse);
: new ExposedFieldsAggregationOperationContext(fields, contextToUse, relaxed);
}
}
}
return operationDocuments;

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java

@ -688,7 +688,7 @@ public class ArrayOperators { @@ -688,7 +688,7 @@ public class ArrayOperators {
Document filterExpression = new Document();
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context);
exposedFields, context, false);
filterExpression.putAll(context.getMappedObject(new Document("input", getMappedInput(context))));
filterExpression.put("as", as.getTarget());

2
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DocumentEnhancingOperation.java

@ -50,7 +50,7 @@ abstract class DocumentEnhancingOperation implements InheritsFieldsAggregationOp @@ -50,7 +50,7 @@ abstract class DocumentEnhancingOperation implements InheritsFieldsAggregationOp
public Document toDocument(AggregationOperationContext context) {
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context);
exposedFields, context, false);
if (valueMap.size() == 1) {
return context.getMappedObject(

18
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java

@ -37,6 +37,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -37,6 +37,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
private final ExposedFields exposedFields;
private final AggregationOperationContext rootContext;
private final boolean relaxedFieldLookup;
/**
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}. Uses the given
@ -46,13 +47,14 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -46,13 +47,14 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
* @param rootContext must not be {@literal null}.
*/
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields,
AggregationOperationContext rootContext) {
AggregationOperationContext rootContext, boolean relaxedFieldLookup) {
Assert.notNull(exposedFields, "ExposedFields must not be null");
Assert.notNull(rootContext, "RootContext must not be null");
this.exposedFields = exposedFields;
this.rootContext = rootContext;
this.relaxedFieldLookup = relaxedFieldLookup;
}
@Override
@ -87,7 +89,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -87,7 +89,7 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
* @param name must not be {@literal null}.
* @return
*/
private FieldReference getReference(@Nullable Field field, String name) {
protected FieldReference getReference(@Nullable Field field, String name) {
Assert.notNull(name, "Name must not be null");
@ -96,12 +98,10 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -96,12 +98,10 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
return exposedField;
}
if (rootContext instanceof RelaxedTypeBasedAggregationOperationContext) {
if(relaxedFieldLookup) {
if (field != null) {
return new DirectFieldReference(new ExposedField(field, true));
}
return new DirectFieldReference(new ExposedField(name, true));
}
@ -156,4 +156,12 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -156,4 +156,12 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
public CodecRegistry getCodecRegistry() {
return getRootContext().getCodecRegistry();
}
@Override
public AggregationOperationContext continueOnMissingFieldReference() {
if(relaxedFieldLookup) {
return this;
}
return new ExposedFieldsAggregationOperationContext(exposedFields, rootContext, true);
}
}

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

@ -38,9 +38,9 @@ class InheritingExposedFieldsAggregationOperationContext extends ExposedFieldsAg @@ -38,9 +38,9 @@ class InheritingExposedFieldsAggregationOperationContext extends ExposedFieldsAg
* @param previousContext must not be {@literal null}.
*/
public InheritingExposedFieldsAggregationOperationContext(ExposedFields exposedFields,
AggregationOperationContext previousContext) {
AggregationOperationContext previousContext, boolean continueOnMissingFieldReference) {
super(exposedFields, previousContext);
super(exposedFields, previousContext, continueOnMissingFieldReference);
this.previousContext = previousContext;
}

7
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/VariableOperators.java

@ -171,7 +171,7 @@ public class VariableOperators { @@ -171,7 +171,7 @@ public class VariableOperators {
Document map = new Document();
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context);
exposedFields, context, false);
Document input;
if (sourceArray instanceof Field field) {
@ -308,8 +308,6 @@ public class VariableOperators { @@ -308,8 +308,6 @@ public class VariableOperators {
Document letExpression = new Document();
Document mappedVars = new Document();
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context);
for (ExpressionVariable var : this.vars) {
mappedVars.putAll(getMappedVariable(var, context));
@ -317,6 +315,9 @@ public class VariableOperators { @@ -317,6 +315,9 @@ public class VariableOperators {
letExpression.put("vars", mappedVars);
if (expression != null) {
InheritingExposedFieldsAggregationOperationContext operationContext = new InheritingExposedFieldsAggregationOperationContext(
exposedFields, context, false);
letExpression.put("in", getMappedIn(operationContext));
}

45
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/AggregationOperationRendererUnitTests.java

@ -15,15 +15,26 @@ @@ -15,15 +15,26 @@
*/
package org.springframework.data.mongodb.core.aggregation;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.data.domain.Sort.Direction.DESC;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.project;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.sort;
import java.util.List;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation.InheritsFieldsAggregationOperation;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.test.util.MongoTestMappingContext;
/**
* @author Christoph Strobl
@ -115,4 +126,34 @@ public class AggregationOperationRendererUnitTests { @@ -115,4 +126,34 @@ public class AggregationOperationRendererUnitTests {
.extracting("previousContext").isSameAs(captor.getAllValues().get(1));
}
record TestRecord(@Id String field1, String field2, LayerOne layerOne) {
record LayerOne(List<LayerTwo> layerTwo) {
}
record LayerTwo(LayerThree layerThree) {
}
record LayerThree(int fieldA, int fieldB)
{}
}
@Test
void xxx() {
MongoTestMappingContext ctx = new MongoTestMappingContext(cfg -> {
cfg.initialEntitySet(TestRecord.class);
});
MappingMongoConverter mongoConverter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, ctx);
Aggregation agg = Aggregation.newAggregation(
Aggregation.unwind("layerOne.layerTwo"),
project().and("layerOne.layerTwo.layerThree").as("layerOne.layerThree"),
sort(DESC, "layerOne.layerThree.fieldA")
);
AggregationOperationRenderer.toDocument(agg.getPipeline().getOperations(), new RelaxedTypeBasedAggregationOperationContext(TestRecord.class, ctx, new QueryMapper(mongoConverter)));
}
}

Loading…
Cancel
Save