diff --git a/driver-core/src/main/com/mongodb/ServerAddress.java b/driver-core/src/main/com/mongodb/ServerAddress.java index a537cd775a2..f9c31180dd9 100644 --- a/driver-core/src/main/com/mongodb/ServerAddress.java +++ b/driver-core/src/main/com/mongodb/ServerAddress.java @@ -103,7 +103,7 @@ public ServerAddress(@Nullable final String host, final int port) { if (hostToUse.startsWith("[")) { int idx = host.indexOf("]"); if (idx == -1) { - throw new IllegalArgumentException("an IPV6 address must be encosed with '[' and ']'" + throw new IllegalArgumentException("an IPV6 address must be enclosed with '[' and ']'" + " according to RFC 2732."); } diff --git a/driver-core/src/main/com/mongodb/client/model/UnwindOptions.java b/driver-core/src/main/com/mongodb/client/model/UnwindOptions.java index 832d274591e..c15e62e4b09 100644 --- a/driver-core/src/main/com/mongodb/client/model/UnwindOptions.java +++ b/driver-core/src/main/com/mongodb/client/model/UnwindOptions.java @@ -18,6 +18,8 @@ import com.mongodb.lang.Nullable; +import java.util.Objects; + /** * The options for an unwind aggregation pipeline stage * @@ -79,4 +81,24 @@ public String toString() { + ", includeArrayIndex='" + includeArrayIndex + '\'' + '}'; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + UnwindOptions that = (UnwindOptions) o; + return Objects.equals(preserveNullAndEmptyArrays, that.preserveNullAndEmptyArrays) && Objects.equals(includeArrayIndex, that.includeArrayIndex); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(preserveNullAndEmptyArrays); + result = 31 * result + Objects.hashCode(includeArrayIndex); + return result; + } } diff --git a/driver-kotlin-extensions/build.gradle.kts b/driver-kotlin-extensions/build.gradle.kts index 5db6609a6f6..25b437e0fad 100644 --- a/driver-kotlin-extensions/build.gradle.kts +++ b/driver-kotlin-extensions/build.gradle.kts @@ -37,6 +37,8 @@ description = "The MongoDB Kotlin Driver Extensions" ext.set("pomName", "MongoDB Kotlin Driver Extensions") +java { registerFeature("kotlinDrivers") { usingSourceSet(sourceSets["main"]) } } + dependencies { // Align versions of all Kotlin components implementation(platform("org.jetbrains.kotlin:kotlin-bom")) @@ -44,10 +46,16 @@ dependencies { api(project(path = ":driver-core", configuration = "default")) + // Some extensions require higher API like MongoCollection which are defined in the sync & + // coroutine Kotlin driver + "kotlinDriversImplementation"(project(path = ":driver-kotlin-sync", configuration = "default")) + "kotlinDriversImplementation"(project(path = ":driver-kotlin-coroutine", configuration = "default")) + testImplementation("org.jetbrains.kotlin:kotlin-reflect") testImplementation("org.jetbrains.kotlin:kotlin-test-junit") testImplementation("org.assertj:assertj-core:3.24.2") testImplementation("io.github.classgraph:classgraph:4.8.154") + testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } kotlin { explicitApi() } diff --git a/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Accumulators.kt b/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Accumulators.kt new file mode 100644 index 00000000000..2edbd35341d --- /dev/null +++ b/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Accumulators.kt @@ -0,0 +1,503 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * Copyright (C) 2016/2022 Litote + * + * 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. + * + * @custom-license-header + */ +package com.mongodb.kotlin.client.model + +import com.mongodb.client.model.Accumulators +import com.mongodb.client.model.BsonField +import com.mongodb.client.model.QuantileMethod +import kotlin.reflect.KProperty +import org.bson.conversions.Bson + +/** + * Accumulators extension methods to improve Kotlin interop + * + * @since 5.3 + */ +@Suppress("TooManyFunctions") +public object Accumulators { + /** + * Gets a field name for a $group operation representing the sum of the values of the given expression when applied + * to all members of the group. + * + * @param property the data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/sum/ $sum + */ + public fun sum(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.sum(property.path(), expression) + + /** + * Gets a field name for a $group operation representing the average of the values of the given expression when + * applied to all members of the group. + * + * @param property the data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/avg/ $avg + */ + public fun avg(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.avg(property.path(), expression) + + /** + * Returns a combination of a computed field and an accumulator that generates a BSON {@link org.bson.BsonType#ARRAY + * Array} containing computed values from the given {@code inExpression} based on the provided {@code pExpression}, + * which represents an array of percentiles of interest within a group, where each element is a numeric value + * between 0.0 and 1.0 (inclusive). + * + * @param property The data class property computed by the accumulator. + * @param inExpression The input expression. + * @param pExpression The expression representing a percentiles of interest. + * @param method The method to be used for computing the percentiles. + * @param The type of the input expression. + * @param The type of the percentile expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/percentile/ + * $percentile @mongodb.server.release 7.0 + */ + public fun percentile( + property: KProperty<*>, + inExpression: InExpression, + pExpression: PExpression, + method: QuantileMethod + ): BsonField = Accumulators.percentile(property.path(), inExpression, pExpression, method) + + /** + * Returns a combination of a computed field and an accumulator that generates a BSON {@link + * org.bson.BsonType#DOUBLE Double } representing the median value computed from the given {@code inExpression} + * within a group. + * + * @param property The data class property computed by the accumulator. + * @param inExpression The input expression. + * @param method The method to be used for computing the median. + * @param The type of the input expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/median/ + * $median @mongodb.server.release 7.0 + */ + public fun median( + property: KProperty<*>, + inExpression: InExpression, + method: QuantileMethod + ): BsonField = Accumulators.median(property.path(), inExpression, method) + + /** + * Gets a field name for a $group operation representing the value of the given expression when applied to the first + * member of the group. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/first/ $first + */ + public fun first(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.first(property.path(), expression) + + /** + * Returns a combination of a computed field and an accumulator that produces a BSON {@link org.bson.BsonType#ARRAY + * Array} of values of the given {@code inExpression} computed for the first {@code N} elements within a presorted + * group, where {@code N} is the positive integral value of the {@code nExpression}. + * + * @param property The data class property computed by the accumulator. + * @param inExpression The input expression. + * @param nExpression The expression limiting the number of produced values. + * @param The type of the input expression. + * @param The type of the limiting expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/firstN/ + * $firstN @mongodb.server.release 5.2 + */ + public fun firstN( + property: KProperty<*>, + inExpression: InExpression, + nExpression: NExpression + ): BsonField = Accumulators.firstN(property.path(), inExpression, nExpression) + + /** + * Returns a combination of a computed field and an accumulator that produces a value of the given {@code + * outExpression} computed for the top element within a group sorted according to the provided {@code sortBy} + * specification. + * + * @param property The data class property computed by the accumulator. + * @param sortBy The {@linkplain Sorts sort specification}. The syntax is identical to the one expected by {@link + * Aggregates#sort(Bson)}. + * @param outExpression The output expression. + * @param The type of the output expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/top/ + * $top @mongodb.server.release 5.2 + */ + public fun top(property: KProperty<*>, sortBy: Bson, outExpression: OutExpression): BsonField = + Accumulators.top(property.path(), sortBy, outExpression) + + /** + * Returns a combination of a computed field and an accumulator that produces a BSON {@link org.bson.BsonType#ARRAY + * Array} of values of the given {@code outExpression} computed for the top {@code N} elements within a group sorted + * according to the provided {@code sortBy} specification, where {@code N} is the positive integral value of the + * {@code nExpression}. + * + * @param property The data class property computed by the accumulator. + * @param sortBy The {@linkplain Sorts sort specification}. The syntax is identical to the one expected by {@link + * Aggregates#sort(Bson)}. + * @param outExpression The output expression. + * @param nExpression The expression limiting the number of produced values. + * @param The type of the output expression. + * @param The type of the limiting expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/topN/ $topN + * @since 4.7 @mongodb.server.release 5.2 + */ + public fun topN( + property: KProperty<*>, + sortBy: Bson, + outExpression: OutExpression, + nExpression: NExpression + ): BsonField = Accumulators.topN(property.path(), sortBy, outExpression, nExpression) + + /** + * Gets a field name for a $group operation representing the value of the given expression when applied to the last + * member of the group. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/last/ $last + */ + public fun last(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.last(property.path(), expression) + + /** + * Returns a combination of a computed field and an accumulator that produces a BSON {@link org.bson.BsonType#ARRAY + * Array} of values of the given {@code inExpression} computed for the last {@code N} elements within a presorted + * group, where {@code N} is the positive integral value of the {@code nExpression}. + * + * @param property The data class property computed by the accumulator. + * @param inExpression The input expression. + * @param nExpression The expression limiting the number of produced values. + * @param The type of the input expression. + * @param The type of the limiting expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/lastN/ + * $lastN @mongodb.server.release 5.2 + */ + public fun lastN( + property: KProperty<*>, + inExpression: InExpression, + nExpression: NExpression + ): BsonField = Accumulators.lastN(property.path(), inExpression, nExpression) + + /** + * Returns a combination of a computed field and an accumulator that produces a value of the given {@code + * outExpression} computed for the bottom element within a group sorted according to the provided {@code sortBy} + * specification. + * + * @param property The data class property computed by the accumulator. + * @param sortBy The {@linkplain Sorts sort specification}. The syntax is identical to the one expected by {@link + * Aggregates#sort(Bson)}. + * @param outExpression The output expression. + * @param The type of the output expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/bottom/ + * $bottom @mongodb.server.release 5.2 + */ + public fun bottom(property: KProperty<*>, sortBy: Bson, outExpression: OutExpression): BsonField = + Accumulators.bottom(property.path(), sortBy, outExpression) + + /** + * Returns a combination of a computed field and an accumulator that produces a BSON {@link org.bson.BsonType#ARRAY + * Array} of values of the given {@code outExpression} computed for the bottom {@code N} elements within a group + * sorted according to the provided {@code sortBy} specification, where {@code N} is the positive integral value of + * the {@code nExpression}. + * + * @param property The data class property computed by the accumulator. + * @param sortBy The {@linkplain Sorts sort specification}. The syntax is identical to the one expected by {@link + * Aggregates#sort(Bson)}. + * @param outExpression The output expression. + * @param nExpression The expression limiting the number of produced values. + * @param The type of the output expression. + * @param The type of the limiting expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/bottomN/ $bottomN + * @since 4.7 @mongodb.server.release 5.2 + */ + public fun bottomN( + property: KProperty<*>, + sortBy: Bson, + outExpression: OutExpression, + nExpression: NExpression + ): BsonField = Accumulators.bottomN(property.path(), sortBy, outExpression, nExpression) + + /** + * Gets a field name for a $group operation representing the maximum of the values of the given expression when + * applied to all members of the group. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/max/ $max + */ + public fun max(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.max(property.path(), expression) + + /** + * Returns a combination of a computed field and an accumulator that produces a BSON {@link org.bson.BsonType#ARRAY + * Array} of {@code N} largest values of the given {@code inExpression}, where {@code N} is the positive integral + * value of the {@code nExpression}. + * + * @param property The data class property computed by the accumulator. + * @param inExpression The input expression. + * @param nExpression The expression limiting the number of produced values. + * @param The type of the input expression. + * @param The type of the limiting expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/maxN/ $maxN + * @since 4.7 @mongodb.server.release 5.2 + */ + public fun maxN( + property: KProperty<*>, + inExpression: InExpression, + nExpression: NExpression + ): BsonField = Accumulators.maxN(property.path(), inExpression, nExpression) + + /** + * Gets a field name for a $group operation representing the minimum of the values of the given expression when + * applied to all members of the group. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/min/ $min + */ + public fun min(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.min(property.path(), expression) + + /** + * Returns a combination of a computed field and an accumulator that produces a BSON {@link org.bson.BsonType#ARRAY + * Array} of {@code N} smallest values of the given {@code inExpression}, where {@code N} is the positive integral + * value of the {@code nExpression}. + * + * @param property The data class property computed by the accumulator. + * @param inExpression The input expression. + * @param nExpression The expression limiting the number of produced values. + * @param The type of the input expression. + * @param The type of the limiting expression. + * @return The requested {@link BsonField}. @mongodb.driver.manual reference/operator/aggregation/minN/ + * $minN @mongodb.server.release 5.2 + */ + public fun minN( + property: KProperty<*>, + inExpression: InExpression, + nExpression: NExpression + ): BsonField = Accumulators.minN(property.path(), inExpression, nExpression) + + /** + * Gets a field name for a $group operation representing an array of all values that results from applying an + * expression to each document in a group of documents that share the same group by key. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/push/ $push + */ + public fun push(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.push(property.path(), expression) + + /** + * Gets a field name for a $group operation representing all unique values that results from applying the given + * expression to each document in a group of documents that share the same group by key. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/addToSet/ $addToSet + */ + public fun addToSet(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.addToSet(property.path(), expression) + + /** + * Gets a field name for a $group operation representing the result of merging the fields of the documents. If + * documents to merge include the same field name, the field, in the resulting document, has the value from the last + * document merged for the field. + * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/mergeObjects/ $mergeObjects + */ + public fun mergeObjects(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.mergeObjects(property.path(), expression) + + /** + * Gets a field name for a $group operation representing the sample standard deviation of the values of the given + * expression when applied to all members of the group. + * + *

Use if the values encompass the entire population of data you want to represent and do not wish to generalize + * about a larger population.

+ * + * @param property The data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/stdDevPop/ + * $stdDevPop @mongodb.server.release 3.2 + */ + public fun stdDevPop(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.stdDevPop(property.path(), expression) + + /** + * Gets a field name for a $group operation representing the sample standard deviation of the values of the given + * expression when applied to all members of the group. + * + *

Use if the values encompass a sample of a population of data from which to generalize about the + * population.

+ * + * @param property the data class property + * @param expression the expression + * @param the expression type + * @return the field @mongodb.driver.manual reference/operator/aggregation/stdDevSamp/ + * $stdDevSamp @mongodb.server.release 3.2 + */ + public fun stdDevSamp(property: KProperty<*>, expression: TExpression): BsonField = + Accumulators.stdDevSamp(property.path(), expression) + + /** + * Creates an $accumulator pipeline stage + * + * @param property the data class property + * @param initFunction a function used to initialize the state + * @param accumulateFunction a function used to accumulate documents + * @param mergeFunction a function used to merge two internal states, e.g. accumulated on different shards or + * threads. It returns the resulting state of the accumulator. + * @return the $accumulator pipeline stage @mongodb.driver.manual reference/operator/aggregation/accumulator/ + * $accumulator @mongodb.server.release 4.4 + */ + public fun accumulator( + property: KProperty, + initFunction: String, + accumulateFunction: String, + mergeFunction: String + ): BsonField = Accumulators.accumulator(property.path(), initFunction, accumulateFunction, mergeFunction) + + /** + * Creates an $accumulator pipeline stage + * + * @param property the data class property + * @param initFunction a function used to initialize the state + * @param accumulateFunction a function used to accumulate documents + * @param mergeFunction a function used to merge two internal states, e.g. accumulated on different shards or + * threads. It returns the resulting state of the accumulator. + * @param finalizeFunction a function used to finalize the state and return the result (may be null) + * @return the $accumulator pipeline stage @mongodb.driver.manual reference/operator/aggregation/accumulator/ + * $accumulator @mongodb.server.release 4.4 + */ + public fun accumulator( + property: KProperty, + initFunction: String, + accumulateFunction: String, + mergeFunction: String, + finalizeFunction: String? + ): BsonField = + Accumulators.accumulator(property.path(), initFunction, accumulateFunction, mergeFunction, finalizeFunction) + + /** + * Creates an $accumulator pipeline stage + * + * @param property the data class property + * @param initFunction a function used to initialize the state + * @param initArgs init function’s arguments (may be null) + * @param accumulateFunction a function used to accumulate documents + * @param accumulateArgs additional accumulate function’s arguments (may be null). The first argument to the + * function is ‘state’. + * @param mergeFunction a function used to merge two internal states, e.g. accumulated on different shards or + * threads. It returns the resulting state of the accumulator. + * @param finalizeFunction a function used to finalize the state and return the result (may be null) + * @return the $accumulator pipeline stage @mongodb.driver.manual reference/operator/aggregation/accumulator/ + * $accumulator @mongodb.server.release 4.4 + */ + @Suppress("LongParameterList") + public fun accumulator( + property: KProperty, + initFunction: String, + initArgs: List?, + accumulateFunction: String, + accumulateArgs: List?, + mergeFunction: String, + finalizeFunction: String? + ): BsonField = + Accumulators.accumulator( + property.path(), + initFunction, + initArgs, + accumulateFunction, + accumulateArgs, + mergeFunction, + finalizeFunction) + + /** + * Creates an $accumulator pipeline stage + * + * @param property the data class property + * @param initFunction a function used to initialize the state + * @param accumulateFunction a function used to accumulate documents + * @param mergeFunction a function used to merge two internal states, e.g. accumulated on different shards or + * threads. It returns the resulting state of the accumulator. + * @param finalizeFunction a function used to finalize the state and return the result (may be null) + * @param lang a language specifier + * @return the $accumulator pipeline stage @mongodb.driver.manual reference/operator/aggregation/accumulator/ + * $accumulator @mongodb.server.release 4.4 + */ + @Suppress("LongParameterList") + public fun accumulator( + property: KProperty, + initFunction: String, + accumulateFunction: String, + mergeFunction: String, + finalizeFunction: String?, + lang: String + ): BsonField = + Accumulators.accumulator( + property.path(), initFunction, accumulateFunction, mergeFunction, finalizeFunction, lang) + + /** + * Creates an $accumulator pipeline stage + * + * @param property The data class property. + * @param initFunction a function used to initialize the state + * @param initArgs init function’s arguments (may be null) + * @param accumulateFunction a function used to accumulate documents + * @param accumulateArgs additional accumulate function’s arguments (may be null). The first argument to the + * function is ‘state’. + * @param mergeFunction a function used to merge two internal states, e.g. accumulated on different shards or + * threads. It returns the resulting state of the accumulator. + * @param finalizeFunction a function used to finalize the state and return the result (may be null) + * @param lang a language specifier + * @return the $accumulator pipeline stage @mongodb.driver.manual reference/operator/aggregation/accumulator/ + * $accumulator @mongodb.server.release 4.4 + */ + @Suppress("LongParameterList") + public fun accumulator( + property: KProperty, + initFunction: String, + initArgs: List?, + accumulateFunction: String, + accumulateArgs: List?, + mergeFunction: String, + finalizeFunction: String?, + lang: String + ): BsonField = + Accumulators.accumulator( + property.path(), + initFunction, + initArgs, + accumulateFunction, + accumulateArgs, + mergeFunction, + finalizeFunction, + lang) +} diff --git a/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Aggregates.kt b/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Aggregates.kt new file mode 100644 index 00000000000..395ce98d88d --- /dev/null +++ b/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Aggregates.kt @@ -0,0 +1,244 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * Copyright (C) 2016/2022 Litote + * + * 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. + * + * @custom-license-header + */ +package com.mongodb.kotlin.client.model + +import com.mongodb.client.model.Aggregates +import com.mongodb.client.model.GraphLookupOptions +import com.mongodb.client.model.MergeOptions +import com.mongodb.client.model.UnwindOptions +import com.mongodb.client.model.densify.DensifyOptions +import com.mongodb.client.model.densify.DensifyRange +import com.mongodb.kotlin.client.model.Projections.projection +import kotlin.reflect.KProperty +import kotlin.reflect.KProperty1 +import org.bson.conversions.Bson + +/** + * Aggregates extension methods to improve Kotlin interop + * + * @since 5.3 + */ +public object Aggregates { + /** + * Creates a $count pipeline stage using the named field to store the result + * + * @param property the data class field in which to store the count + * @return the $count pipeline stage @mongodb.driver.manual reference/operator/aggregation/count/ $count + */ + public fun count(property: KProperty): Bson = Aggregates.count(property.path()) + + /** + * Creates a $lookup pipeline stage, joining the current collection with the one specified in from using the given + * pipeline. If the first stage in the pipeline is a {@link Aggregates#documents(List) $documents} stage, then the + * {@code from} collection is ignored. + * + * @param from the collection in the same database to perform the join with. + * @param localField the data class field from the local collection to match values against. + * @param foreignField the data class field in the from collection to match values against. + * @param pipeline the pipeline to run on the joined collection. + * @param as the name of the new array field to add to the input documents. + * @return the $lookup pipeline stage @mongodb.driver.manual reference/operator/aggregation/lookup/ + * $lookup @mongodb.server.release 3.6 + */ + public fun lookup( + from: com.mongodb.kotlin.client.MongoCollection, + localField: KProperty1, + foreignField: KProperty1, + newAs: String + ): Bson = Aggregates.lookup(from.namespace.collectionName, localField.path(), foreignField.path(), newAs) + + /** + * Creates a $lookup pipeline stage, joining the current collection with the one specified in from using the given + * pipeline. If the first stage in the pipeline is a {@link Aggregates#documents(List) $documents} stage, then the + * {@code from} collection is ignored. + * + * @param from the collection in the same database to perform the join with. + * @param localField the data class field from the local collection to match values against. + * @param foreignField the data class field in the from collection to match values against. + * @param pipeline the pipeline to run on the joined collection. + * @param as the name of the new array field to add to the input documents. + * @return the $lookup pipeline stage @mongodb.driver.manual reference/operator/aggregation/lookup/ + * $lookup @mongodb.server.release 3.6 + */ + public fun lookup( + from: com.mongodb.kotlin.client.coroutine.MongoCollection, + localField: KProperty1, + foreignField: KProperty1, + newAs: String + ): Bson = Aggregates.lookup(from.namespace.collectionName, localField.path(), foreignField.path(), newAs) + + /** + * Creates a graphLookup pipeline stage for the specified filter + * + * @param the expression type + * @param from the collection to query + * @param startWith the expression to start the graph lookup with + * @param connectFromField the data class from field + * @param connectToField the data class to field + * @param fieldAs name of field in output document + * @param options optional values for the graphLookup + * @return the $graphLookup pipeline stage @mongodb.driver.manual reference/operator/aggregation/graphLookup/ + * $graphLookup @mongodb.server.release 3.4 + */ + @Suppress("LongParameterList") + public fun graphLookup( + from: com.mongodb.kotlin.client.MongoCollection, + startWith: TExpression, + connectFromField: KProperty1, + connectToField: KProperty1, + fieldAs: String, + options: GraphLookupOptions = GraphLookupOptions() + ): Bson = + Aggregates.graphLookup( + from.namespace.collectionName, startWith, connectFromField.path(), connectToField.path(), fieldAs, options) + + /** + * Creates a graphLookup pipeline stage for the specified filter + * + * @param the expression type + * @param from the collection to query + * @param startWith the expression to start the graph lookup with + * @param connectFromField the data class from field + * @param connectToField the data class to field + * @param fieldAs name of field in output document + * @param options optional values for the graphLookup + * @return the $graphLookup pipeline stage @mongodb.driver.manual reference/operator/aggregation/graphLookup/ + * $graphLookup @mongodb.server.release 3.4 + */ + @Suppress("LongParameterList") + public fun graphLookup( + from: com.mongodb.kotlin.client.coroutine.MongoCollection, + startWith: TExpression, + connectFromField: KProperty1, + connectToField: KProperty1, + fieldAs: String, + options: GraphLookupOptions = GraphLookupOptions() + ): Bson = + Aggregates.graphLookup( + from.namespace.collectionName, startWith, connectFromField.path(), connectToField.path(), fieldAs, options) + + /** + * Creates a $unionWith pipeline stage. + * + * @param collection the collection in the same database to perform the union with. + * @param pipeline the pipeline to run on the union. + * @return the $unionWith pipeline stage @mongodb.driver.manual reference/operator/aggregation/unionWith/ + * $unionWith @mongodb.server.release 4.4 + */ + public fun unionWith(collection: com.mongodb.kotlin.client.MongoCollection<*>, pipeline: List): Bson = + Aggregates.unionWith(collection.namespace.collectionName, pipeline) + + /** + * Creates a $unionWith pipeline stage. + * + * @param collection the collection in the same database to perform the union with. + * @param pipeline the pipeline to run on the union. + * @return the $unionWith pipeline stage @mongodb.driver.manual reference/operator/aggregation/unionWith/ + * $unionWith @mongodb.server.release 4.4 + */ + public fun unionWith( + collection: com.mongodb.kotlin.client.coroutine.MongoCollection<*>, + pipeline: List + ): Bson = Aggregates.unionWith(collection.namespace.collectionName, pipeline) + + /** + * Creates a $unwind pipeline stage for the specified field name, which must be prefixed by a {@code '$'} sign. + * + * @param property the data class field name + * @param unwindOptions options for the unwind pipeline stage + * @return the $unwind pipeline stage @mongodb.driver.manual reference/operator/aggregation/unwind/ $unwind + */ + public fun unwind(property: KProperty?>, unwindOptions: UnwindOptions = UnwindOptions()): Bson { + return if (unwindOptions == UnwindOptions()) { + Aggregates.unwind(property.projection) + } else { + Aggregates.unwind(property.projection, unwindOptions) + } + } + + /** + * Creates a $out pipeline stage that writes into the specified collection + * + * @param collection the collection + * @return the $out pipeline stage @mongodb.driver.manual reference/operator/aggregation/out/ $out + */ + public fun out(collection: com.mongodb.kotlin.client.MongoCollection<*>): Bson = + Aggregates.out(collection.namespace.collectionName) + + /** + * Creates a $out pipeline stage that writes into the specified collection + * + * @param collection the collection + * @return the $out pipeline stage @mongodb.driver.manual reference/operator/aggregation/out/ $out + */ + public fun out(collection: com.mongodb.kotlin.client.coroutine.MongoCollection<*>): Bson = + Aggregates.out(collection.namespace.collectionName) + + /** + * Creates a $merge pipeline stage that merges into the specified collection + * + * @param collection the collection to merge into + * @param options the merge options + * @return the $merge pipeline stage @mongodb.driver.manual reference/operator/aggregation/merge/ + * $merge @mongodb.server.release 4.2 + */ + public fun merge( + collection: com.mongodb.kotlin.client.MongoCollection<*>, + options: MergeOptions = MergeOptions() + ): Bson = Aggregates.merge(collection.namespace.collectionName, options) + + /** + * Creates a $merge pipeline stage that merges into the specified collection + * + * @param collection the collection to merge into + * @param options the merge options + * @return the $merge pipeline stage @mongodb.driver.manual reference/operator/aggregation/merge/ + * $merge @mongodb.server.release 4.2 + */ + public fun merge( + collection: com.mongodb.kotlin.client.coroutine.MongoCollection<*>, + options: MergeOptions = MergeOptions() + ): Bson = Aggregates.merge(collection.namespace.collectionName, options) + + /** + * Creates a `$densify` pipeline stage, which adds documents to a sequence of documents where certain values in the + * `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 + */ + public fun densify(property: KProperty, range: DensifyRange): Bson = + Aggregates.densify(property.path(), range) + + /** + * 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 + */ + public fun densify(property: KProperty, range: DensifyRange, options: DensifyOptions): Bson = + Aggregates.densify(property.path(), range, options) +} diff --git a/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/AggregatesTest.kt b/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/AggregatesTest.kt new file mode 100644 index 00000000000..50f369e50ec --- /dev/null +++ b/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/AggregatesTest.kt @@ -0,0 +1,355 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * Copyright (C) 2016/2022 Litote + * + * 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. + * + * @custom-license-header + */ +package com.mongodb.kotlin.client.model + +import com.mongodb.MongoNamespace +import com.mongodb.client.model.Aggregates +import com.mongodb.client.model.Aggregates.project +import com.mongodb.client.model.GraphLookupOptions +import com.mongodb.client.model.MergeOptions +import com.mongodb.client.model.QuantileMethod +import com.mongodb.client.model.UnwindOptions +import com.mongodb.client.model.densify.DensifyOptions +import com.mongodb.client.model.densify.DensifyRange +import com.mongodb.kotlin.client.MongoCollection +import com.mongodb.kotlin.client.model.Accumulators.accumulator +import com.mongodb.kotlin.client.model.Accumulators.addToSet +import com.mongodb.kotlin.client.model.Accumulators.avg +import com.mongodb.kotlin.client.model.Accumulators.bottom +import com.mongodb.kotlin.client.model.Accumulators.bottomN +import com.mongodb.kotlin.client.model.Accumulators.first +import com.mongodb.kotlin.client.model.Accumulators.firstN +import com.mongodb.kotlin.client.model.Accumulators.last +import com.mongodb.kotlin.client.model.Accumulators.lastN +import com.mongodb.kotlin.client.model.Accumulators.max +import com.mongodb.kotlin.client.model.Accumulators.maxN +import com.mongodb.kotlin.client.model.Accumulators.median +import com.mongodb.kotlin.client.model.Accumulators.mergeObjects +import com.mongodb.kotlin.client.model.Accumulators.min +import com.mongodb.kotlin.client.model.Accumulators.minN +import com.mongodb.kotlin.client.model.Accumulators.percentile +import com.mongodb.kotlin.client.model.Accumulators.push +import com.mongodb.kotlin.client.model.Accumulators.stdDevPop +import com.mongodb.kotlin.client.model.Accumulators.stdDevSamp +import com.mongodb.kotlin.client.model.Accumulators.sum +import com.mongodb.kotlin.client.model.Accumulators.top +import com.mongodb.kotlin.client.model.Accumulators.topN +import com.mongodb.kotlin.client.model.Aggregates.count +import com.mongodb.kotlin.client.model.Aggregates.densify +import com.mongodb.kotlin.client.model.Aggregates.graphLookup +import com.mongodb.kotlin.client.model.Aggregates.lookup +import com.mongodb.kotlin.client.model.Aggregates.merge +import com.mongodb.kotlin.client.model.Aggregates.out +import com.mongodb.kotlin.client.model.Aggregates.unionWith +import com.mongodb.kotlin.client.model.Aggregates.unwind +import com.mongodb.kotlin.client.model.Projections.excludeId +import com.mongodb.kotlin.client.model.Projections.projection +import com.mongodb.kotlin.client.model.Sorts.ascending +import kotlin.test.assertEquals +import org.bson.BsonDocument +import org.bson.conversions.Bson +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +class AggregatesTest { + + companion object { + @Mock internal val wrappedEmployee: com.mongodb.client.MongoCollection = mock() + @Mock + internal val wrappedEmployeeCoroutine: com.mongodb.reactivestreams.client.MongoCollection = mock() + @Mock internal val wrappedCustomer: com.mongodb.client.MongoCollection = mock() + @Mock + internal val wrappedCustomerCoroutine: com.mongodb.reactivestreams.client.MongoCollection = mock() + + lateinit var employeeCollection: MongoCollection + lateinit var employeeCollectionCoroutine: com.mongodb.kotlin.client.coroutine.MongoCollection + lateinit var customerCollection: MongoCollection + lateinit var customerCollectionCoroutine: com.mongodb.kotlin.client.coroutine.MongoCollection + + @JvmStatic + @BeforeAll + internal fun setUpMocks() { + employeeCollection = MongoCollection(wrappedEmployee) + employeeCollectionCoroutine = com.mongodb.kotlin.client.coroutine.MongoCollection(wrappedEmployeeCoroutine) + + customerCollection = MongoCollection(wrappedCustomer) + customerCollectionCoroutine = com.mongodb.kotlin.client.coroutine.MongoCollection(wrappedCustomerCoroutine) + + whenever(wrappedEmployee.namespace).doReturn(MongoNamespace("db", Employee::class.simpleName!!)) + whenever(wrappedEmployeeCoroutine.namespace).doReturn(MongoNamespace("db", Employee::class.simpleName!!)) + whenever(wrappedCustomer.namespace).doReturn(MongoNamespace("db", Customer::class.simpleName!!)) + whenever(wrappedCustomerCoroutine.namespace).doReturn(MongoNamespace("db", Customer::class.simpleName!!)) + + employeeCollection.namespace + verify(wrappedEmployee).namespace + assertEquals(Employee::class.simpleName, employeeCollection.namespace.collectionName) + + employeeCollectionCoroutine.namespace + verify(wrappedEmployeeCoroutine).namespace + assertEquals(Employee::class.simpleName, employeeCollectionCoroutine.namespace.collectionName) + + customerCollection.namespace + verify(wrappedCustomer).namespace + assertEquals(Customer::class.simpleName, customerCollection.namespace.collectionName) + + customerCollectionCoroutine.namespace + verify(wrappedCustomerCoroutine).namespace + assertEquals(Customer::class.simpleName, customerCollectionCoroutine.namespace.collectionName) + } + } + + @Test + fun count() { + assertEquals(""" {${'$'}count: "name"}""", count(Person::name)) + } + + @Test + fun lookup() { + assertEquals( + """ {"${'$'}lookup": + {"from": "Customer", "localField": "customerId", "foreignField": "customerId", "as": "invoice"}}""", + lookup(customerCollection, Order::customerId, Customer::customerId, "invoice")) + assertEquals( + Aggregates.lookup("Customer", "customerId", "customerId", "invoice"), + lookup(customerCollection, Order::customerId, Customer::customerId, "invoice")) + + assertEquals( + """ {"${'$'}lookup": + {"from": "Customer", "localField": "customerId", "foreignField": "customerId", "as": "invoice"}}""", + lookup(customerCollectionCoroutine, Order::customerId, Customer::customerId, "invoice")) + assertEquals( + Aggregates.lookup("Customer", "customerId", "customerId", "invoice"), + lookup(customerCollectionCoroutine, Order::customerId, Customer::customerId, "invoice")) + } + + @Test + fun graphLookup() { + assertEquals( + """ {"${'$'}graphLookup": + {"from": "Employee", "startWith": "${'$'}id", "connectFromField": "id", "connectToField": + "reportsTo", "as": "subordinates", "maxDepth": 1}} """, + graphLookup( + from = employeeCollection, + startWith = Employee::id.projection, + connectFromField = Employee::id, + connectToField = Employee::reportsTo, + fieldAs = "subordinates", + options = GraphLookupOptions().maxDepth(1))) + + assertEquals( + """ {"${'$'}graphLookup": + {"from": "Employee", "startWith": "${'$'}id", "connectFromField": "id", "connectToField": + "reportsTo", "as": "subordinates", "maxDepth": 1}} """, + graphLookup( + from = employeeCollectionCoroutine, + startWith = Employee::id.projection, + connectFromField = Employee::id, + connectToField = Employee::reportsTo, + fieldAs = "subordinates", + options = GraphLookupOptions().maxDepth(1))) + } + + @Test + fun unionWith() { + assertEquals( + """ {"${'$'}unionWith": {"coll": "Customer", "pipeline": [{"${'$'}project": {"_id": 0}}]}} """, + unionWith(collection = customerCollection, pipeline = listOf(project(excludeId())))) + + assertEquals( + """ {"${'$'}unionWith": {"coll": "Customer", "pipeline": [{"${'$'}project": {"_id": 0}}]}} """, + unionWith(collection = customerCollectionCoroutine, pipeline = listOf(project(excludeId())))) + } + + @Test + fun unwind() { + assertEquals(UnwindOptions(), UnwindOptions()) + assertEquals(""" {"${'$'}unwind": "${'$'}address"} """, unwind(Person::address)) + + assertEquals( + """ {"${'$'}unwind": + {"path": "${'$'}address", "preserveNullAndEmptyArrays": true, "includeArrayIndex": "idx"}} """, + unwind(Person::address, UnwindOptions().includeArrayIndex("idx").preserveNullAndEmptyArrays(true))) + } + + @Test + fun out() { + assertEquals(""" {"${'$'}out": "Employee"} """, out(employeeCollection)) + assertEquals(""" {"${'$'}out": "Employee"} """, out(employeeCollectionCoroutine)) + } + + @Test + fun merge() { + assertEquals(""" {"${'$'}merge": {"into": "Customer"}} """, merge(customerCollection)) + assertEquals(""" {"${'$'}merge": {"into": "Customer"}} """, merge(customerCollectionCoroutine)) + + assertEquals( + """ {"${'$'}merge": {"into": "Customer", "on": "ssn"}} """, + merge(customerCollection, MergeOptions().uniqueIdentifier("ssn"))) + assertEquals( + """ {"${'$'}merge": {"into": "Customer", "on": "ssn"}} """, + merge(customerCollectionCoroutine, MergeOptions().uniqueIdentifier("ssn"))) + } + + @Test + fun densify() { + assertEquals( + """ {"${'$'}densify": { + "field": "email", + "range": { "bounds": "full", "step": 1 } + }} """, + densify(Customer::email, DensifyRange.fullRangeWithStep(1))) + + assertEquals( + """ {"${'$'}densify": { + "field": "email", + "range": { "bounds": "full", "step": 1 }, + "partitionByFields": ["foo"] + }} """, + densify( + Customer::email, + range = DensifyRange.fullRangeWithStep(1), + options = DensifyOptions.densifyOptions().partitionByFields("foo"))) + } + + @Test + @Suppress("LongMethod") + fun accumulators() { + assertEquals(com.mongodb.client.model.Accumulators.sum("age", 1), sum(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.avg("age", 1), avg(Person::age, 1)) + + assertEquals( + com.mongodb.client.model.Accumulators.percentile("age", 1, 2, QuantileMethod.approximate()), + percentile(Person::age, 1, 2, QuantileMethod.approximate())) + + assertEquals( + com.mongodb.client.model.Accumulators.median("age", 1, QuantileMethod.approximate()), + median(Person::age, 1, QuantileMethod.approximate())) + + assertEquals(com.mongodb.client.model.Accumulators.first("age", 1), first(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.firstN("age", 1, 2), firstN(Person::age, 1, 2)) + + assertEquals( + com.mongodb.client.model.Accumulators.top("age", com.mongodb.client.model.Sorts.ascending("name"), 1), + top(Person::age, ascending(Person::name), 1)) + + assertEquals( + com.mongodb.client.model.Accumulators.topN("age", com.mongodb.client.model.Sorts.ascending("name"), 1, 2), + topN(Person::age, ascending(Person::name), 1, 2)) + + assertEquals(com.mongodb.client.model.Accumulators.last("age", 1), last(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.lastN("age", 1, 2), lastN(Person::age, 1, 2)) + + assertEquals( + com.mongodb.client.model.Accumulators.bottom("age", com.mongodb.client.model.Sorts.ascending("name"), 1), + bottom(Person::age, ascending(Person::name), 1)) + + assertEquals( + com.mongodb.client.model.Accumulators.bottomN( + "age", com.mongodb.client.model.Sorts.ascending("name"), 1, 2), + bottomN(Person::age, ascending(Person::name), 1, 2)) + + assertEquals(com.mongodb.client.model.Accumulators.max("age", 1), max(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.maxN("age", 1, 2), maxN(Person::age, 1, 2)) + + assertEquals(com.mongodb.client.model.Accumulators.min("age", 1), min(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.minN("age", 1, 2), minN(Person::age, 1, 2)) + + assertEquals(com.mongodb.client.model.Accumulators.push("age", 1), push(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.addToSet("age", 1), addToSet(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.mergeObjects("age", 1), mergeObjects(Person::age, 1)) + + assertEquals( + com.mongodb.client.model.Accumulators.accumulator( + "age", "initFunction", "accumulateFunction", "mergeFunction"), + accumulator(Person::age, "initFunction", "accumulateFunction", "mergeFunction")) + + assertEquals( + com.mongodb.client.model.Accumulators.accumulator( + "age", "initFunction", "accumulateFunction", "mergeFunction", "finalizeFunction"), + accumulator(Person::age, "initFunction", "accumulateFunction", "mergeFunction", "finalizeFunction")) + + assertEquals( + com.mongodb.client.model.Accumulators.accumulator( + "age", + "initFunction", + listOf("a", "b"), + "accumulateFunction", + listOf("c", "d"), + "mergeFunction", + "finalizeFunction"), + accumulator( + Person::age, + "initFunction", + listOf("a", "b"), + "accumulateFunction", + listOf("c", "d"), + "mergeFunction", + "finalizeFunction")) + + assertEquals( + com.mongodb.client.model.Accumulators.accumulator( + "age", "initFunction", "accumulateFunction", "mergeFunction", "finalizeFunction", "Kotlin"), + accumulator( + Person::age, "initFunction", "accumulateFunction", "mergeFunction", "finalizeFunction", "Kotlin")) + + assertEquals( + com.mongodb.client.model.Accumulators.accumulator( + "age", + "initFunction", + listOf("a", "b"), + "accumulateFunction", + listOf("c", "d"), + "mergeFunction", + "finalizeFunction", + "Kotlin"), + accumulator( + Person::age, + "initFunction", + listOf("a", "b"), + "accumulateFunction", + listOf("c", "d"), + "mergeFunction", + "finalizeFunction", + "Kotlin")) + + assertEquals(com.mongodb.client.model.Accumulators.stdDevPop("age", 1), stdDevPop(Person::age, 1)) + + assertEquals(com.mongodb.client.model.Accumulators.stdDevSamp("age", 1), stdDevSamp(Person::age, 1)) + } + + data class Person(val name: String, val age: Int, val address: List?, val results: List) + data class Employee(val id: String, val name: String, val reportsTo: String) + data class Order(val id: String, val orderId: String, val customerId: Int, val amount: Int) + data class Customer(val id: String, val customerId: Int, val name: String, val email: String?) + + private fun assertEquals(expected: String, result: Bson) = + assertEquals(BsonDocument.parse(expected), result.toBsonDocument()) +} diff --git a/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/ExtensionsApiTest.kt b/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/ExtensionsApiTest.kt index 4ba9b59a252..e4455f9cfc6 100644 --- a/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/ExtensionsApiTest.kt +++ b/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/ExtensionsApiTest.kt @@ -65,6 +65,24 @@ class ExtensionsApiTest { assertTrue(notImplemented.isEmpty(), "Some possible Sorts were not implemented: $notImplemented") } + @Test + fun shouldHaveAllAggregatesExtensions() { + val kotlinExtensions: Set = getKotlinExtensions("Aggregates") + val javaMethods: Set = getJavaMethods("Aggregates") + + val notImplemented = javaMethods subtract kotlinExtensions + assertTrue(notImplemented.isEmpty(), "Some possible Aggregates were not implemented: $notImplemented") + } + + @Test + fun shouldHaveAllAccumulatorsExtensions() { + val kotlinExtensions: Set = getKotlinExtensions("Accumulators") + val javaMethods: Set = getJavaMethods("Accumulators") + + val notImplemented = javaMethods subtract kotlinExtensions + assertTrue(notImplemented.isEmpty(), "Some possible Accumulators were not implemented: $notImplemented") + } + private fun getKotlinExtensions(className: String): Set { return ClassGraph() .enableClassInfo() diff --git a/driver-sync/src/test/functional/com/mongodb/client/csot/AbstractClientSideOperationsEncryptionTimeoutProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/csot/AbstractClientSideOperationsEncryptionTimeoutProseTest.java index 31f72ca4332..f874ae2042e 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/csot/AbstractClientSideOperationsEncryptionTimeoutProseTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/csot/AbstractClientSideOperationsEncryptionTimeoutProseTest.java @@ -71,7 +71,7 @@ /** * See - * Prose Tests. + * Prose Tests. */ public abstract class AbstractClientSideOperationsEncryptionTimeoutProseTest {