Browse Source

DATAMONGO-1326 - Add Builder, update javadoc and remove additional interface.

Updated javadoc and formatting. Added tests and removed marker interface.

Original Pull Request: #344
pull/347/head
Christoph Strobl 10 years ago
parent
commit
65b6576cfc
  1. 27
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AdditionalFieldsExposingAggregationOperation.java
  2. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java
  3. 31
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ExposedFieldsAggregationOperationContext.java
  4. 136
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/LookupOperation.java
  5. 59
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/LookupOperationUnitTests.java

27
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/AdditionalFieldsExposingAggregationOperation.java

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
/*
* Copyright 2013 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;
/**
* {@link AggregationOperation} that exposes <b>additional</b> {@link ExposedFields} that can be used for later
* aggregation pipeline {@code AggregationOperation}s, e.g. lookup operation produces a field which has to be added to
* the current ones.
*
* @author Alessio Fachechi
*/
public interface AdditionalFieldsExposingAggregationOperation extends FieldsExposingAggregationOperation {
}

22
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/Aggregation.java

@ -272,10 +272,14 @@ public class Aggregation { @@ -272,10 +272,14 @@ public class Aggregation {
}
/**
* Creates a new {@link LookupOperation} for the given fields.
* Creates a new {@link LookupOperation}.
*
* @param fields must not be {@literal null}.
* @return
* @param from must not be {@literal null}.
* @param localField must not be {@literal null}.
* @param foreignField must not be {@literal null}.
* @param as must not be {@literal null}.
* @return never {@literal null}.
* @since 1.9
*/
public static LookupOperation lookup(String from, String localField, String foreignField, String as) {
return lookup(field(from), field(localField), field(foreignField), field(as));
@ -284,8 +288,12 @@ public class Aggregation { @@ -284,8 +288,12 @@ public class Aggregation {
/**
* Creates a new {@link LookupOperation} for the given {@link Fields}.
*
* @param fields must not be {@literal null}.
* @return
* @param from must not be {@literal null}.
* @param localField must not be {@literal null}.
* @param foreignField must not be {@literal null}.
* @param as must not be {@literal null}.
* @return never {@literal null}.
* @since 1.9
*/
public static LookupOperation lookup(Field from, Field localField, Field foreignField, Field as) {
return new LookupOperation(from, localField, foreignField, as);
@ -352,11 +360,9 @@ public class Aggregation { @@ -352,11 +360,9 @@ public class Aggregation {
operationDocuments.add(operation.toDBObject(context));
if (operation instanceof FieldsExposingAggregationOperation) {
boolean additional = operation instanceof AdditionalFieldsExposingAggregationOperation ? true : false;
FieldsExposingAggregationOperation exposedFieldsOperation = (FieldsExposingAggregationOperation) operation;
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), rootContext,
additional);
context = new ExposedFieldsAggregationOperationContext(exposedFieldsOperation.getFields(), rootContext);
}
}

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

@ -17,9 +17,7 @@ package org.springframework.data.mongodb.core.aggregation; @@ -17,9 +17,7 @@ package org.springframework.data.mongodb.core.aggregation;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.ExposedField;
import org.springframework.data.mongodb.core.aggregation.ExposedFields.FieldReference;
import org.springframework.data.mongodb.core.aggregation.Fields.AggregationField;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.mongodb.DBObject;
@ -29,14 +27,12 @@ import com.mongodb.DBObject; @@ -29,14 +27,12 @@ import com.mongodb.DBObject;
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Alessio Fachechi
* @since 1.4
*/
class ExposedFieldsAggregationOperationContext implements AggregationOperationContext {
private final ExposedFields exposedFields;
private final AggregationOperationContext rootContext;
private final boolean additional;
/**
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}. Uses the given
@ -46,28 +42,13 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -46,28 +42,13 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
* @param rootContext must not be {@literal null}.
*/
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields,
AggregationOperationContext rootContext) {
this(exposedFields, rootContext, false);
}
/**
* Creates a new {@link ExposedFieldsAggregationOperationContext} from the given {@link ExposedFields}. Uses the given
* {@link AggregationOperationContext} to perform a mapping to mongo types if necessary.
*
* @param exposedFields must not be {@literal null}.
* @param rootContext must not be {@literal null}.
* @param additional {@literal true} if the context exposes new fields in addition to the previous ones, e.g. in the
* case of a lookup operation, {@literal false} otherwise.
*/
public ExposedFieldsAggregationOperationContext(ExposedFields exposedFields, AggregationOperationContext rootContext,
boolean additional) {
AggregationOperationContext rootContext) {
Assert.notNull(exposedFields, "ExposedFields must not be null!");
Assert.notNull(rootContext, "RootContext must not be null!");
this.exposedFields = exposedFields;
this.rootContext = rootContext;
this.additional = additional;
}
/*
@ -132,16 +113,6 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo @@ -132,16 +113,6 @@ class ExposedFieldsAggregationOperationContext implements AggregationOperationCo
}
}
if (additional) {
// if no exposed fields found propagate to root context.
if (field != null) {
return rootContext.getReference(field);
} else if (StringUtils.hasText(name)) {
return rootContext.getReference(name);
}
}
throw new IllegalArgumentException(String.format("Invalid reference '%s'!", name));
}
}

136
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/LookupOperation.java

@ -22,19 +22,19 @@ import com.mongodb.BasicDBObject; @@ -22,19 +22,19 @@ import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
/**
* Encapsulates the aggregation framework {@code $lookup}-operation.
* We recommend to use the static factory method {@link Aggregation#lookup(String, String, String, String)} instead of
* creating instances of this class directly.
* Encapsulates the aggregation framework {@code $lookup}-operation. We recommend to use the static factory method
* {@link Aggregation#lookup(String, String, String, String)} instead of creating instances of this class directly.
*
* @author Alessio Fachechi
* @author Christoph Strobl
* @see http://docs.mongodb.org/manual/reference/aggregation/lookup/#stage._S_lookup
* @since 1.9
*/
public class LookupOperation implements AdditionalFieldsExposingAggregationOperation {
public class LookupOperation implements FieldsExposingAggregationOperation {
private ExposedField from;
private ExposedField localField;
private ExposedField foreignField;
private Field from;
private Field localField;
private Field foreignField;
private ExposedField as;
/**
@ -46,24 +46,38 @@ public class LookupOperation implements AdditionalFieldsExposingAggregationOpera @@ -46,24 +46,38 @@ public class LookupOperation implements AdditionalFieldsExposingAggregationOpera
* @param as must not be {@literal null}.
*/
public LookupOperation(Field from, Field localField, Field foreignField, Field as) {
Assert.notNull(from, "From must not be null!");
Assert.notNull(localField, "LocalField must not be null!");
Assert.notNull(foreignField, "ForeignField must not be null!");
Assert.notNull(as, "As must not be null!");
this.from = new ExposedField(from, true);
this.localField = new ExposedField(localField, true);
this.foreignField = new ExposedField(foreignField, true);
this.from = from;
this.localField = localField;
this.foreignField = foreignField;
this.as = new ExposedField(as, true);
}
private LookupOperation() {
// used by builder
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.FieldsExposingAggregationOperation#getFields()
*/
@Override
public ExposedFields getFields() {
return ExposedFields.from(as);
}
/*
* (non-Javadoc)
* @see org.springframework.data.mongodb.core.aggregation.AggregationOperation#toDBObject(org.springframework.data.mongodb.core.aggregation.AggregationOperationContext)
*/
@Override
public DBObject toDBObject(AggregationOperationContext context) {
BasicDBObject lookupObject = new BasicDBObject();
lookupObject.append("from", from.getTarget());
@ -73,4 +87,106 @@ public class LookupOperation implements AdditionalFieldsExposingAggregationOpera @@ -73,4 +87,106 @@ public class LookupOperation implements AdditionalFieldsExposingAggregationOpera
return new BasicDBObject("$lookup", lookupObject);
}
/**
* Get a builder that allows creation of {@link LookupOperation}.
*
* @return
*/
public static FromBuilder newLookup() {
return new LookupOperationBuilder();
}
public static interface FromBuilder {
/**
* @param name
* @return
*/
LocalFieldBuilder from(String name);
}
public static interface LocalFieldBuilder {
/**
* @param name
* @return
*/
ForeignFieldBuilder localField(String name);
}
public static interface ForeignFieldBuilder {
/**
* @param name
* @return
*/
AsBuilder foreignField(String name);
}
public static interface AsBuilder {
/**
* @param name
* @return
*/
LookupOperation as(String name);
}
/**
* Builder for fluent {@link LookupOperation} creation.
*
* @author Christoph Strobl
* @since 1.9
*/
public static final class LookupOperationBuilder
implements FromBuilder, LocalFieldBuilder, ForeignFieldBuilder, AsBuilder {
private LookupOperation lookupOperation;
private LookupOperationBuilder() {
this.lookupOperation = new LookupOperation();
}
/**
* Creates new builder for {@link LookupOperation}.
*
* @return never {@literal null}.
*/
public static FromBuilder newBuilder() {
return new LookupOperationBuilder();
}
@Override
public LocalFieldBuilder from(String name) {
Assert.hasText(name, "'From' must not be null or empty!");
lookupOperation.from = Fields.field(name);
return this;
}
@Override
public LookupOperation as(String name) {
Assert.hasText(name, "'As' must not be null or empty!");
lookupOperation.as = new ExposedField(Fields.field(name), true);
return null;
}
@Override
public AsBuilder foreignField(String name) {
Assert.hasText(name, "'ForeignField' must not be null or empty!");
lookupOperation.foreignField = Fields.field(name);
return this;
}
@Override
public ForeignFieldBuilder localField(String name) {
Assert.hasText(name, "'LocalField' must not be null or empty!");
lookupOperation.localField = Fields.field(name);
return this;
}
}
}

59
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/LookupOperationUnitTests.java

@ -17,23 +17,56 @@ package org.springframework.data.mongodb.core.aggregation; @@ -17,23 +17,56 @@ package org.springframework.data.mongodb.core.aggregation;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.mongodb.test.util.IsBsonObject.*;
import com.mongodb.DBObject;
import org.junit.Test;
import org.springframework.data.mongodb.core.DBObjectTestUtils;
import com.mongodb.DBObject;
/**
* Unit tests for {@link LookupOperation}.
*
* @author Alessio Fachechi
* @author Christoph Strobl
*/
public class LookupOperationUnitTests {
/**
* @see DATAMONGO-1326
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullForFrom() {
new LookupOperation(null, Fields.field("localField"), Fields.field("foreignField"), Fields.field("as"));
}
/**
* @see DATAMONGO-1326
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullLocalFieldField() {
new LookupOperation(Fields.field("from"), null, Fields.field("foreignField"), Fields.field("as"));
}
/**
* @see DATAMONGO-1326
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullFields() {
new LookupOperation((Field) null, (Field) null, (Field) null, (Field) null);
public void rejectsNullForeignField() {
new LookupOperation(Fields.field("from"), Fields.field("localField"), null, Fields.field("as"));
}
/**
* @see DATAMONGO-1326
*/
@Test(expected = IllegalArgumentException.class)
public void rejectsNullForAs() {
new LookupOperation(Fields.field("from"), Fields.field("localField"), Fields.field("foreignField"), null);
}
/**
* @see DATAMONGO-1326
*/
@Test
public void lookupOperationWithValues() {
@ -41,16 +74,28 @@ public class LookupOperationUnitTests { @@ -41,16 +74,28 @@ public class LookupOperationUnitTests {
DBObject lookupClause = extractDbObjectFromLookupOperation(lookupOperation);
assertThat((String) lookupClause.get("from"), is(new String("a")));
assertThat((String) lookupClause.get("localField"), is(new String("b")));
assertThat((String) lookupClause.get("foreignField"), is(new String("c")));
assertThat((String) lookupClause.get("as"), is(new String("d")));
assertThat(lookupClause,
isBsonObject().containing("from", "a") //
.containing("localField", "b") //
.containing("foreignField", "c") //
.containing("as", "d"));
}
/**
* @see DATAMONGO-1326
*/
@Test
public void lookupOperationExposesAsField() {
LookupOperation lookupOperation = Aggregation.lookup("a", "b", "c", "d");
assertThat(lookupOperation.getFields().exposesNoFields(), is(false));
assertThat(lookupOperation.getFields().exposesSingleFieldOnly(), is(true));
assertThat(lookupOperation.getFields().getField("d"), notNullValue());
}
private DBObject extractDbObjectFromLookupOperation(LookupOperation lookupOperation) {
DBObject dbObject = lookupOperation.toDBObject(Aggregation.DEFAULT_CONTEXT);
DBObject lookupClause = DBObjectTestUtils.getAsDBObject(dbObject, "$lookup");
return lookupClause;

Loading…
Cancel
Save