Skip to content

Commit

Permalink
Add query building API for the $densify aggregation pipeline stage (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
stIncMale authored Jul 12, 2022
1 parent b68b580 commit ac15365
Show file tree
Hide file tree
Showing 20 changed files with 1,079 additions and 16 deletions.
57 changes: 57 additions & 0 deletions 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.densify.DensifyOptions;
import com.mongodb.client.model.densify.DensifyRange;
import com.mongodb.client.model.fill.FillComputation;
import com.mongodb.client.model.fill.FillOptions;
import com.mongodb.client.model.search.SearchOperator;
Expand All @@ -38,6 +40,7 @@
import java.util.Objects;

import static com.mongodb.assertions.Assertions.assertTrue;
import static com.mongodb.client.model.densify.DensifyOptions.densifyOptions;
import static com.mongodb.assertions.Assertions.isTrueArgument;
import static com.mongodb.assertions.Assertions.notNull;
import static com.mongodb.client.model.search.SearchOptions.searchOptions;
Expand Down Expand Up @@ -661,6 +664,60 @@ public static <TExpression> Bson setWindowFields(@Nullable final TExpression par
return new SetWindowFieldsStage<>(partitionBy, sortBy, output);
}

/**
* Creates a {@code $densify} pipeline stage, which adds documents to a sequence of documents
* where certain values in the {@code field} are missing.
*
* @param field The field to densify.
* @param range The range.
* @return The requested pipeline stage.
* @mongodb.driver.manual reference/operator/aggregation/densify/ $densify
* @mongodb.driver.manual core/document/#dot-notation Dot notation
* @mongodb.server.release 5.1
* @since 4.7
*/
public static Bson densify(final String field, final DensifyRange range) {
return densify(notNull("field", field), notNull("range", range), densifyOptions());
}

/**
* Creates a {@code $densify} pipeline stage, which adds documents to a sequence of documents
* where certain values in the {@code field} are missing.
*
* @param field The field to densify.
* @param range The range.
* @param options The densify options.
* Specifying {@link DensifyOptions#densifyOptions()} is equivalent to calling {@link #densify(String, DensifyRange)}.
* @return The requested pipeline stage.
* @mongodb.driver.manual reference/operator/aggregation/densify/ $densify
* @mongodb.driver.manual core/document/#dot-notation Dot notation
* @mongodb.server.release 5.1
* @since 4.7
*/
public static Bson densify(final String field, final DensifyRange range, final DensifyOptions options) {
notNull("field", field);
notNull("range", range);
notNull("options", options);
return new Bson() {
@Override
public <TDocument> BsonDocument toBsonDocument(final Class<TDocument> documentClass, final CodecRegistry codecRegistry) {
BsonDocument densifySpecificationDoc = new BsonDocument("field", new BsonString(field));
densifySpecificationDoc.append("range", range.toBsonDocument(documentClass, codecRegistry));
densifySpecificationDoc.putAll(options.toBsonDocument(documentClass, codecRegistry));
return new BsonDocument("$densify", densifySpecificationDoc);
}

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

/**
* Creates a {@code $fill} pipeline stage, which assigns values to fields when they are {@link BsonType#NULL Null} or missing.
*
Expand Down
35 changes: 23 additions & 12 deletions driver-core/src/main/com/mongodb/client/model/MongoTimeUnit.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,48 +15,53 @@
*/
package com.mongodb.client.model;

import org.bson.conversions.Bson;
import com.mongodb.client.model.densify.DensifyRange;

/**
* Units for specifying time-based bounds for {@linkplain Window windows} and output units for some time-based
* {@linkplain WindowedComputation windowed computations}.
* Units for specifying time-based values.
*
* @see Windows
* @see WindowedComputations
* @see DensifyRange
* @mongodb.server.release 5.0
* @since 4.3
*/
public enum MongoTimeUnit {
/**
* YEAR
* {@linkplain #value() "year"}
*/
YEAR("year", false),
/**
* QUARTER
* {@linkplain #value() "quarter"}
*/
QUARTER("quarter", false),
/**
* MONTH
* {@linkplain #value() "month"}
*/
MONTH("month", false),
/**
* WEEK
* {@linkplain #value() "week"}
*/
WEEK("week", true),
/**
* DAY
* {@linkplain #value() "day"}
*/
DAY("day", true),
/**
* HOUR
* {@linkplain #value() "hour"}
*/
HOUR("hour", true),
/**
* MINUTE
* {@linkplain #value() "minute"}
*/
MINUTE("minute", true),
/**
* SECOND
* {@linkplain #value() "second"}
*/
SECOND("second", true),
/**
* MILLISECOND
* {@linkplain #value() "millisecond"}
*/
MILLISECOND("millisecond", true);

Expand All @@ -68,7 +73,13 @@ public enum MongoTimeUnit {
this.fixed = fixed;
}

String value() {
/**
* Returns a {@link String} representation of the unit, which may be useful when using methods like
* {@link Windows#of(Bson)}, {@link DensifyRange#of(Bson)}.
*
* @return A {@link String} representation of the unit.
*/
public String value() {
return value;
}

Expand Down
2 changes: 1 addition & 1 deletion driver-core/src/main/com/mongodb/client/model/Windows.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public final class Windows {
* Window pastWeek1 = Windows.timeRange(-1, MongoTimeUnit.WEEK, Windows.Bound.CURRENT);
* Window pastWeek2 = Windows.of(
* new Document("range", Arrays.asList(-1, "current"))
* .append("unit", "week"));
* .append("unit", MongoTimeUnit.WEEK.value()));
* }</pre>
*
* @param window A {@link Bson} representing the required window.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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,
* WITHOUNumber 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.densify;

import com.mongodb.annotations.Evolving;
import com.mongodb.client.model.MongoTimeUnit;

import java.time.Instant;

/**
* @see DensifyRange#fullRangeWithStep(long, MongoTimeUnit)
* @see DensifyRange#partitionRangeWithStep(long, MongoTimeUnit)
* @see DensifyRange#rangeWithStep(Instant, Instant, long, MongoTimeUnit)
* @mongodb.server.release 5.1
* @since 4.7
*/
@Evolving
public interface DateDensifyRange extends DensifyRange {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.densify;

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 DensifyConstructibleBson extends AbstractConstructibleBson<DensifyConstructibleBson> implements
NumberDensifyRange, DateDensifyRange,
DensifyOptions {
static final DensifyConstructibleBson EMPTY_IMMUTABLE = new DensifyConstructibleBson(AbstractConstructibleBson.EMPTY_IMMUTABLE);

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

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

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

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

@Override
public DensifyOptions 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,87 @@
/*
* 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.densify;

import com.mongodb.annotations.Evolving;
import com.mongodb.client.model.Aggregates;
import com.mongodb.lang.Nullable;
import org.bson.conversions.Bson;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;

/**
* Represents optional fields of the {@code $densify} pipeline stage of an aggregation pipeline.
*
* @see Aggregates#densify(String, DensifyRange, DensifyOptions)
* @see Aggregates#densify(String, DensifyRange)
* @mongodb.server.release 5.1
* @since 4.7
*/
@Evolving
public interface DensifyOptions extends Bson {
/**
* Creates a new {@link DensifyOptions} with the specified {@code fields} to partition by.
*
* @param fields The fields to partition by.
* If no fields are specified, then the whole sequence is considered to be a single partition.
* @return A new {@link DensifyOptions}.
* @mongodb.driver.manual core/document/#dot-notation Dot notation
*/
default DensifyOptions partitionByFields(@Nullable final String... fields) {
return partitionByFields(fields == null ? emptyList() : asList(fields));
}

/**
* Creates a new {@link DensifyOptions} with the specified {@code fields} to partition by.
*
* @param fields The fields to partition by.
* If no fields are specified, then the whole sequence is considered to be a single partition.
* @return A new {@link DensifyOptions}.
* @mongodb.driver.manual core/document/#dot-notation Dot notation
*/
DensifyOptions partitionByFields(Iterable<String> fields);

/**
* Creates a new {@link DensifyOptions} with the specified option 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 DensifyOptions} objects,
* though they may not be {@linkplain Object#equals(Object) equal}.
* <pre>{@code
* DensifyOptions options1 = DensifyOptions.densifyOptions()
* .partitionByFields("fieldName");
* DensifyOptions options2 = DensifyOptions.densifyOptions()
* .option("partitionByFields", Collections.singleton("fieldName"));
* }</pre>
*
* @param name The option name.
* @param value The option value.
* @return A new {@link DensifyOptions}.
*/
DensifyOptions option(String name, Object value);

/**
* Returns {@link DensifyOptions} that represents server defaults.
*
* @return {@link DensifyOptions} that represents server defaults.
*/
static DensifyOptions densifyOptions() {
return DensifyConstructibleBson.EMPTY_IMMUTABLE;
}
}
Loading

0 comments on commit ac15365

Please sign in to comment.