/*
* Copyright 2016. 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.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.Sum;
import org.springframework.util.Assert;
/**
* Gateway to {@literal Set expressions} which perform {@literal set} operation on arrays, treating arrays as sets.
*
* @author Christoph Strobl
* @since 1.10
*/
public class SetOperators {
/**
* Take the array referenced by given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
* @return
*/
public static SetOperatorFactory arrayAsSet(String fieldReference) {
return new SetOperatorFactory(fieldReference);
}
/**
* Take the array resulting from the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetOperatorFactory arrayAsSet(AggregationExpression expression) {
return new SetOperatorFactory(expression);
}
/**
* @author Christoph Strobl
*/
public static class SetOperatorFactory {
private final String fieldReference;
private final AggregationExpression expression;
/**
* Creates new {@link SetOperatorFactory} for given {@literal fieldReference}.
*
* @param fieldReference must not be {@literal null}.
*/
public SetOperatorFactory(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null!");
this.fieldReference = fieldReference;
this.expression = null;
}
/**
* Creates new {@link SetOperatorFactory} for given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
*/
public SetOperatorFactory(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
this.fieldReference = null;
this.expression = expression;
}
/**
* Creates new {@link AggregationExpression} that compares the previously mentioned field to one or more arrays and
* returns {@literal true} if they have the same distinct elements and {@literal false} otherwise.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(String... arrayReferences) {
return createSetEquals().isEqualTo(arrayReferences);
}
/**
* Creates new {@link AggregationExpression} that compares the previously mentioned field to one or more arrays and
* returns {@literal true} if they have the same distinct elements and {@literal false} otherwise.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(AggregationExpression... expressions) {
return createSetEquals().isEqualTo(expressions);
}
private SetEquals createSetEquals() {
return usesFieldRef() ? SetEquals.arrayAsSet(fieldReference) : SetEquals.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in every of those.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetIntersection intersects(String... arrayReferences) {
return createSetIntersection().intersects(arrayReferences);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in every of those.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetIntersection intersects(AggregationExpression... expressions) {
return createSetIntersection().intersects(expressions);
}
private SetIntersection createSetIntersection() {
return usesFieldRef() ? SetIntersection.arrayAsSet(fieldReference) : SetIntersection.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in any of those.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetUnion union(String... arrayReferences) {
return createSetUnion().union(arrayReferences);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and one or more
* arrays and returns an array that contains the elements that appear in any of those.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetUnion union(AggregationExpression... expressions) {
return createSetUnion().union(expressions);
}
private SetUnion createSetUnion() {
return usesFieldRef() ? SetUnion.arrayAsSet(fieldReference) : SetUnion.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and returns an array
* containing the elements that do not exist in the given {@literal arrayReference}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(String arrayReference) {
return createSetDifference().differenceTo(arrayReference);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and returns an array
* containing the elements that do not exist in the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(AggregationExpression expression) {
return createSetDifference().differenceTo(expression);
}
private SetDifference createSetDifference() {
return usesFieldRef() ? SetDifference.arrayAsSet(fieldReference) : SetDifference.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and returns
* {@literal true} if it is a subset of the given {@literal arrayReference}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(String arrayReference) {
return createSetIsSubset().isSubsetOf(arrayReference);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and returns
* {@literal true} if it is a subset of the given {@link AggregationExpression}.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(AggregationExpression expression) {
return createSetIsSubset().isSubsetOf(expression);
}
private SetIsSubset createSetIsSubset() {
return usesFieldRef() ? SetIsSubset.arrayAsSet(fieldReference) : SetIsSubset.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpression} that takes array of the previously mentioned field and returns
* {@literal true} if any of the elements are {@literal true} and {@literal false} otherwise.
*
* @return
*/
public AnyElementTrue anyElementTrue() {
return usesFieldRef() ? AnyElementTrue.arrayAsSet(fieldReference) : AnyElementTrue.arrayAsSet(expression);
}
/**
* Creates new {@link AggregationExpression} that tkes array of the previously mentioned field and returns
* {@literal true} if no elements is {@literal false}.
*
* @return
*/
public AllElementsTrue allElementsTrue() {
return usesFieldRef() ? AllElementsTrue.arrayAsSet(fieldReference) : AllElementsTrue.arrayAsSet(expression);
}
private boolean usesFieldRef() {
return this.fieldReference != null;
}
}
/**
* {@link AggregationExpression} for {@code $setEquals}.
*
* @author Christoph Strobl
*/
public static class SetEquals extends AbstractAggregationExpression {
private SetEquals(List<?> arrays) {
super(arrays);
}
@Override
protected String getMongoMethod() {
return "$setEquals";
}
/**
* Create new {@link SetEquals}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetEquals arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetEquals(asFields(arrayReference));
}
/**
* Create new {@link SetEquals}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetEquals arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetEquals(Collections.singletonList(expression));
}
/**
* Creates new {@link java.util.Set} with all previously added arguments appending the given one.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(String... arrayReferences) {
Assert.notNull(arrayReferences, "ArrayReferences must not be null!");
return new SetEquals(append(Fields.fields(arrayReferences).asList()));
}
/**
* Creates new {@link Sum} with all previously added arguments appending the given one.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(AggregationExpression... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new SetEquals(append(Arrays.asList(expressions)));
}
/**
* Creates new {@link Sum} with all previously added arguments appending the given one.
*
* @param array must not be {@literal null}.
* @return
*/
public SetEquals isEqualTo(Object[] array) {
Assert.notNull(array, "Array must not be null!");
return new SetEquals(append(array));
}
}
/**
* {@link AggregationExpression} for {@code $setIntersection}.
*
* @author Christoph Strobl
*/
public static class SetIntersection extends AbstractAggregationExpression {
private SetIntersection(List<?> arrays) {
super(arrays);
}
@Override
protected String getMongoMethod() {
return "$setIntersection";
}
/**
* Creates new {@link SetIntersection}
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetIntersection arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetIntersection(asFields(arrayReference));
}
/**
* Creates new {@link SetIntersection}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetIntersection arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetIntersection(Collections.singletonList(expression));
}
/**
* Creates new {@link SetIntersection} with all previously added arguments appending the given one.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetIntersection intersects(String... arrayReferences) {
Assert.notNull(arrayReferences, "ArrayReferences must not be null!");
return new SetIntersection(append(asFields(arrayReferences)));
}
/**
* Creates new {@link SetIntersection} with all previously added arguments appending the given one.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetIntersection intersects(AggregationExpression... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new SetIntersection(append(Arrays.asList(expressions)));
}
}
/**
* {@link AggregationExpression} for {@code $setUnion}.
*
* @author Christoph Strobl
*/
public static class SetUnion extends AbstractAggregationExpression {
private SetUnion(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$setUnion";
}
/**
* Creates new {@link SetUnion}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetUnion arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetUnion(asFields(arrayReference));
}
/**
* Creates new {@link SetUnion}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetUnion arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetUnion(Collections.singletonList(expression));
}
/**
* Creates new {@link SetUnion} with all previously added arguments appending the given one.
*
* @param arrayReferences must not be {@literal null}.
* @return
*/
public SetUnion union(String... arrayReferences) {
Assert.notNull(arrayReferences, "ArrayReferences must not be null!");
return new SetUnion(append(asFields(arrayReferences)));
}
/**
* Creates new {@link SetUnion} with all previously added arguments appending the given one.
*
* @param expressions must not be {@literal null}.
* @return
*/
public SetUnion union(AggregationExpression... expressions) {
Assert.notNull(expressions, "Expressions must not be null!");
return new SetUnion(append(Arrays.asList(expressions)));
}
}
/**
* {@link AggregationExpression} for {@code $setDifference}.
*
* @author Christoph Strobl
*/
public static class SetDifference extends AbstractAggregationExpression {
private SetDifference(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$setDifference";
}
/**
* Creates new {@link SetDifference}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetDifference arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetDifference(asFields(arrayReference));
}
/**
* Creates new {@link SetDifference}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetDifference arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetDifference(Collections.singletonList(expression));
}
/**
* Creates new {@link SetDifference} with all previously added arguments appending the given one.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetDifference(append(Fields.field(arrayReference)));
}
/**
* Creates new {@link SetDifference} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetDifference differenceTo(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetDifference(append(expression));
}
}
/**
* {@link AggregationExpression} for {@code $setIsSubset}.
*
* @author Christoph Strobl
*/
public static class SetIsSubset extends AbstractAggregationExpression {
private SetIsSubset(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$setIsSubset";
}
/**
* Creates new {@link SetIsSubset}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static SetIsSubset arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetIsSubset(asFields(arrayReference));
}
/**
* Creates new {@link SetIsSubset}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static SetIsSubset arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetIsSubset(Collections.singletonList(expression));
}
/**
* Creates new {@link SetIsSubset} with all previously added arguments appending the given one.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new SetIsSubset(append(Fields.field(arrayReference)));
}
/**
* Creates new {@link SetIsSubset} with all previously added arguments appending the given one.
*
* @param expression must not be {@literal null}.
* @return
*/
public SetIsSubset isSubsetOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new SetIsSubset(append(expression));
}
}
/**
* {@link AggregationExpression} for {@code $anyElementTrue}.
*
* @author Christoph Strobl
*/
public static class AnyElementTrue extends AbstractAggregationExpression {
private AnyElementTrue(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$anyElementTrue";
}
/**
* Creates new {@link AnyElementTrue}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static AnyElementTrue arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new AnyElementTrue(asFields(arrayReference));
}
/**
* Creates new {@link AnyElementTrue}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static AnyElementTrue arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new AnyElementTrue(Collections.singletonList(expression));
}
public AnyElementTrue anyElementTrue() {
return this;
}
}
/**
* {@link AggregationExpression} for {@code $allElementsTrue}.
*
* @author Christoph Strobl
*/
public static class AllElementsTrue extends AbstractAggregationExpression {
private AllElementsTrue(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$allElementsTrue";
}
/**
* Creates new {@link AllElementsTrue}.
*
* @param arrayReference must not be {@literal null}.
* @return
*/
public static AllElementsTrue arrayAsSet(String arrayReference) {
Assert.notNull(arrayReference, "ArrayReference must not be null!");
return new AllElementsTrue(asFields(arrayReference));
}
/**
* Creates new {@link AllElementsTrue}.
*
* @param expression must not be {@literal null}.
* @return
*/
public static AllElementsTrue arrayAsSet(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null!");
return new AllElementsTrue(Collections.singletonList(expression));
}
public AllElementsTrue allElementsTrue() {
return this;
}
}
}