Skip to content

Commit

Permalink
Add query building API for the $fill aggregation pipeline stage (mo…
Browse files Browse the repository at this point in the history
…ngodb#965)

JAVA-4394
  • Loading branch information
stIncMale authored Jul 6, 2022
1 parent bb4f8f2 commit c70c2d2
Show file tree
Hide file tree
Showing 21 changed files with 1,155 additions and 46 deletions.
61 changes: 60 additions & 1 deletion driver-core/src/main/com/mongodb/client/model/Aggregates.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.mongodb.client.model;

import com.mongodb.MongoNamespace;
import com.mongodb.client.model.fill.FillComputation;
import com.mongodb.client.model.fill.FillOptions;
import com.mongodb.client.model.search.SearchOperator;
import com.mongodb.client.model.search.SearchCollector;
import com.mongodb.client.model.search.SearchOptions;
Expand All @@ -26,6 +28,7 @@
import org.bson.BsonDocumentWriter;
import org.bson.BsonInt32;
import org.bson.BsonString;
import org.bson.BsonType;
import org.bson.BsonValue;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.conversions.Bson;
Expand All @@ -35,10 +38,12 @@
import java.util.Objects;

import static com.mongodb.assertions.Assertions.assertTrue;
import static com.mongodb.assertions.Assertions.isTrueArgument;
import static com.mongodb.assertions.Assertions.notNull;
import static com.mongodb.client.model.search.SearchOptions.searchOptions;
import static com.mongodb.internal.Iterables.concat;
import static com.mongodb.internal.client.model.Util.sizeAtLeast;
import static java.util.Arrays.asList;
import static org.bson.assertions.Assertions.notNull;

/**
* Builders for aggregation pipeline stages.
Expand Down Expand Up @@ -656,6 +661,60 @@ public static <TExpression> Bson setWindowFields(@Nullable final TExpression par
return new SetWindowFieldsStage<>(partitionBy, sortBy, output);
}

/**
* Creates a {@code $fill} pipeline stage, which assigns values to fields when they are {@link BsonType#NULL Null} or missing.
*
* @param options The fill options.
* @param output The {@link FillComputation}.
* @param moreOutput More {@link FillComputation}s.
* @return The requested pipeline stage.
* @mongodb.driver.manual reference/operator/aggregation/fill/ $fill
* @mongodb.server.release 5.3
* @since 4.7
*/
public static Bson fill(final FillOptions options, final FillComputation output, final FillComputation... moreOutput) {
return fill(options, concat(notNull("output", output), moreOutput));
}

/**
* Creates a {@code $fill} pipeline stage, which assigns values to fields when they are {@link BsonType#NULL Null} or missing.
*
* @param options The fill options.
* @param output The non-empty {@link FillComputation}s.
* @return The requested pipeline stage.
* @mongodb.driver.manual reference/operator/aggregation/fill/ $fill
* @mongodb.server.release 5.3
* @since 4.7
*/
public static Bson fill(final FillOptions options, final Iterable<? extends FillComputation> output) {
notNull("options", options);
notNull("output", output);
isTrueArgument("output must not be empty", sizeAtLeast(output, 1));
return new Bson() {
@Override
public <TDocument> BsonDocument toBsonDocument(final Class<TDocument> documentClass, final CodecRegistry codecRegistry) {
BsonDocument fillSpecificationDoc = new BsonDocument();
fillSpecificationDoc.putAll(options.toBsonDocument(documentClass, codecRegistry));
BsonDocument outputDoc = new BsonDocument();
for (final FillComputation computation : output) {
BsonDocument computationDoc = computation.toBsonDocument(documentClass, codecRegistry);
assertTrue(computationDoc.size() == 1);
outputDoc.putAll(computationDoc);
}
fillSpecificationDoc.append("output", outputDoc);
return new BsonDocument("$fill", fillSpecificationDoc);
}

@Override
public String toString() {
return "Stage{name='$fill'"
+ ", options=" + options
+ ", output=" + output
+ '}';
}
};
}

/**
* Creates a {@code $search} pipeline stage supported by MongoDB Atlas.
* You may use the {@code $meta: "searchScore"} expression, e.g., via {@link Projections#metaSearchScore(String)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,43 @@ public static WindowedComputation denseRank(final String path) {
return simpleParameterWindowFunction(path, "$denseRank", null, null);
}

/**
* Builds a computation of the last observed non-{@link BsonType#NULL Null} evaluation result of the {@code expression}.
*
* @param path The output field path.
* @param expression The expression.
* @param <TExpression> The expression type.
* @return The constructed windowed computation.
* @mongodb.driver.manual reference/operator/aggregation/locf/ $locf
* @since 4.7
* @mongodb.server.release 5.2
*/
public static <TExpression> WindowedComputation locf(final String path, final TExpression expression) {
notNull("path", path);
notNull("expression", expression);
return simpleParameterWindowFunction(path, "$locf", expression, null);
}

/**
* Builds a computation of a value that is equal to the evaluation result of the {@code expression} when it is non-{@link BsonType#NULL Null},
* or to the linear interpolation of surrounding evaluation results of the {@code expression} when the result is {@link BsonType#NULL Null}.
* <p>
* {@linkplain Aggregates#setWindowFields(Object, Bson, Iterable) Sorting} is required.</p>
*
* @param path The output field path.
* @param expression The expression.
* @param <TExpression> The expression type.
* @return The constructed windowed computation.
* @mongodb.driver.manual reference/operator/aggregation/linearFill/ $linearFill
* @since 4.7
* @mongodb.server.release 5.3
*/
public static <TExpression> WindowedComputation linearFill(final String path, final TExpression expression) {
notNull("path", path);
notNull("expression", expression);
return simpleParameterWindowFunction(path, "$linearFill", expression, null);
}

private static WindowedComputation simpleParameterWindowFunction(final String path, final String functionName,
@Nullable final Object expression,
@Nullable final Window window) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* 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 com.mongodb.client.model.fill;

import com.mongodb.annotations.Evolving;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.WindowedComputations;
import org.bson.Document;
import org.bson.conversions.Bson;

import static com.mongodb.assertions.Assertions.notNull;

/**
* The core part of the {@code $fill} pipeline stage of an aggregation pipeline.
* A pair of an expression/method and a path to a field to be filled with evaluation results of the expression/method.
*
* @see Aggregates#fill(FillOptions, Iterable)
* @see Aggregates#fill(FillOptions, FillComputation, FillComputation...)
* @mongodb.server.release 5.3
* @since 4.7
*/
@Evolving
public interface FillComputation extends Bson {
/**
* Returns a {@link FillComputation} that uses the specified {@code expression}.
*
* @param field The field to fill.
* @param expression The expression.
* @param <TExpression> The {@code expression} type.
* @return The requested {@link FillComputation}.
* @mongodb.driver.manual core/document/#dot-notation Dot notation
*/
static <TExpression> ValueFillComputation value(final String field, TExpression expression) {
return new FillConstructibleBsonElement(notNull("field", field),
new Document("value", (notNull("expression", expression))));
}

/**
* Returns a {@link FillComputation} that uses the {@link WindowedComputations#locf(String, Object) locf} method.
*
* @param field The field to fill.
* @return The requested {@link FillComputation}.
* @mongodb.driver.manual core/document/#dot-notation Dot notation
*/
static LocfFillComputation locf(final String field) {
return new FillConstructibleBsonElement(notNull("field", field),
new Document("method", "locf"));
}

/**
* Returns a {@link FillComputation} that uses the {@link WindowedComputations#linearFill(String, Object) linear} method.
* <p>
* {@linkplain FillOptions#sortBy(Bson) Sorting} is required.</p>
*
* @param field The field to fill.
* @return The requested {@link FillComputation}.
* @mongodb.driver.manual core/document/#dot-notation Dot notation
*/
static LinearFillComputation linear(final String field) {
return new FillConstructibleBsonElement(notNull("field", field),
new Document("method", "linear"));
}

/**
* Creates a {@link FillComputation} from a {@link Bson} in situations when there is no builder method
* that better satisfies your needs.
* This method cannot be used to validate the syntax.
* <p>
* <i>Example</i><br>
* The following code creates two functionally equivalent {@link FillComputation}s,
* though they may not be {@linkplain Object#equals(Object) equal}.
* <pre>{@code
* FillComputation field1 = FillComputation.locf("fieldName");
* FillComputation field2 = FillComputation.of(new Document("fieldName", new Document("method", "locf")));
* }</pre>
*
* @param fill A {@link Bson} representing the required {@link FillComputation}.
* @return The requested {@link FillComputation}.
*/
static FillComputation of(final Bson fill) {
return new FillConstructibleBsonElement(notNull("fill", fill));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* 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 com.mongodb.client.model.fill;

import com.mongodb.internal.client.model.AbstractConstructibleBson;
import org.bson.Document;
import org.bson.conversions.Bson;

import static com.mongodb.assertions.Assertions.notNull;
import static com.mongodb.internal.client.model.Util.sizeAtLeast;

final class FillConstructibleBson extends AbstractConstructibleBson<FillConstructibleBson> implements FillOptions {
static final FillConstructibleBson EMPTY_IMMUTABLE = new FillConstructibleBson(AbstractConstructibleBson.EMPTY_IMMUTABLE);

FillConstructibleBson(final Bson base) {
super(base);
}

private FillConstructibleBson(final Bson base, final Document appended) {
super(base, appended);
}

@Override
protected FillConstructibleBson newSelf(final Bson base, final Document appended) {
return new FillConstructibleBson(base, appended);
}

@Override
public <TExpression> FillOptions partitionBy(final TExpression expression) {
notNull("expression", expression);
return newMutated(doc -> {
doc.remove("partitionByFields");
doc.append("partitionBy", expression);
});
}

@Override
public FillOptions partitionByFields(final Iterable<String> fields) {
notNull("fields", fields);
return newMutated(doc -> {
doc.remove("partitionBy");
if (sizeAtLeast(fields, 1)) {
doc.append("partitionByFields", fields);
} else {
doc.remove("partitionByFields");
}
});
}

@Override
public FillOptions sortBy(final Bson sortBy) {
return newAppended("sortBy", notNull("sortBy", sortBy));
}

@Override
public FillOptions option(final String name, final Object value) {
return newAppended(notNull("name", name), notNull("value", value));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* 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 com.mongodb.client.model.fill;

import com.mongodb.internal.client.model.AbstractConstructibleBsonElement;
import org.bson.conversions.Bson;

final class FillConstructibleBsonElement extends AbstractConstructibleBsonElement<FillConstructibleBsonElement> implements
ValueFillComputation, LocfFillComputation, LinearFillComputation {
FillConstructibleBsonElement(final String name, final Bson value) {
super(name, value);
}

FillConstructibleBsonElement(final Bson baseElement) {
super(baseElement);
}

private FillConstructibleBsonElement(final Bson baseElement, final Bson appendedElementValue) {
super(baseElement, appendedElementValue);
}

@Override
protected FillConstructibleBsonElement newSelf(final Bson baseElement, final Bson appendedElementValue) {
return new FillConstructibleBsonElement(baseElement, appendedElementValue);
}
}
Loading

0 comments on commit c70c2d2

Please sign in to comment.