diff --git a/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Filters.kt b/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Filters.kt index 3faef6a8458..4e1f68fda33 100644 --- a/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Filters.kt +++ b/driver-kotlin-extensions/src/main/kotlin/com/mongodb/kotlin/client/model/Filters.kt @@ -24,11 +24,12 @@ import com.mongodb.client.model.Filters import com.mongodb.client.model.TextSearchOptions import com.mongodb.client.model.geojson.Geometry import com.mongodb.client.model.geojson.Point +import org.bson.BsonDocument +import org.bson.BsonType +import org.bson.conversions.Bson import java.util.regex.Pattern import kotlin.internal.OnlyInputTypes import kotlin.reflect.KProperty -import org.bson.BsonType -import org.bson.conversions.Bson /** * Filters extension methods to improve Kotlin interop @@ -288,7 +289,7 @@ public object Filters { * @param filters the list of filters to and together * @return the filter */ - public fun and(filters: Iterable): Bson = Filters.and(filters) + public fun and(filters: Iterable): Bson = combineFilters(Filters::and, filters) /** * Creates a filter that performs a logical AND of the provided list of filters. Note that this will only generate @@ -309,7 +310,7 @@ public object Filters { * @param filters the list of filters to and together * @return the filter */ - public fun or(filters: Iterable): Bson = Filters.or(filters) + public fun or(filters: Iterable): Bson = combineFilters(Filters::or, filters) /** * Creates a filter that preforms a logical OR of the provided list of filters. @@ -352,7 +353,9 @@ public object Filters { * * @return the filter */ - @JvmSynthetic @JvmName("existsExt") public fun KProperty.exists(): Bson = Filters.exists(path()) + @JvmSynthetic + @JvmName("existsExt") + public fun KProperty.exists(): Bson = Filters.exists(path()) /** * Creates a filter that matches all documents that contain the given property. @@ -1216,4 +1219,18 @@ public object Filters { * @return the filter */ public fun jsonSchema(schema: Bson): Bson = Filters.jsonSchema(schema) + + private fun combineFilters( + combine: (List) -> Bson, + filters: Iterable + ): Bson = filters + .filterNotNull() + .filterNot { bson -> bson is Map<*, *> && bson.isEmpty() } + .let { list -> + when (list.size) { + 0 -> BsonDocument() + 1 -> list.first() + else -> combine(list) + } + } } diff --git a/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/FiltersTest.kt b/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/FiltersTest.kt index da15d6ee5af..fc2f48ccb7f 100644 --- a/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/FiltersTest.kt +++ b/driver-kotlin-extensions/src/test/kotlin/com/mongodb/kotlin/client/model/FiltersTest.kt @@ -159,11 +159,18 @@ class FiltersTest { @Test fun testOrSupport() { val expected = BsonDocument.parse("""{${'$'}or: [{"name": "Ada"}, {"age": 20 }]}""") + val bson = or(eq(Person::name, person.name), eq(Person::age, person.age)) assertEquals(expected, bson.document) val kmongoDsl = or(Person::name eq person.name, Person::age eq person.age) assertEquals(expected, kmongoDsl.document) + + val bsonWithNull = or(eq(Person::name, person.name), eq(Person::age, person.age), null) + assertEquals(expected, bsonWithNull.document) + + val kmongoDslWithNull = or(Person::name eq person.name, Person::age eq person.age, null) + assertEquals(expected, kmongoDslWithNull.document) } @Test @@ -186,11 +193,18 @@ class FiltersTest { @Test fun testAndSupport() { val expected = BsonDocument.parse("""{${'$'}and: [{"name": "Ada"}, {"age": 20 }]}""") + val bson = and(eq(Person::name, person.name), eq(Person::age, person.age)) assertEquals(expected, bson.document) val kmongoDsl = and(Person::name.eq(person.name), Person::age.eq(person.age)) assertEquals(expected, kmongoDsl.document) + + val bsonWithNull = and(eq(Person::name, person.name), eq(Person::age, person.age), null) + assertEquals(expected, bsonWithNull.document) + + val kmongoDslWithNull = and(Person::name.eq(person.name), Person::age.eq(person.age), null) + assertEquals(expected, kmongoDslWithNull.document) } @Test