From 2fb721cfb772a8da3a651cd03c82e591bd8a1050 Mon Sep 17 00:00:00 2001 From: Jens Suhr Date: Wed, 29 Jan 2025 15:44:34 +0100 Subject: [PATCH 1/2] JAVA-5775 Filter null values in Filters.and / Filters.or --- .../com/mongodb/kotlin/client/model/Filters.kt | 4 ++-- .../com/mongodb/kotlin/client/model/FiltersTest.kt | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) 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..638d8c9625f 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 @@ -288,7 +288,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 = Filters.and(filters.filterNotNull()) /** * Creates a filter that performs a logical AND of the provided list of filters. Note that this will only generate @@ -309,7 +309,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 = Filters.or(filters.filterNotNull()) /** * Creates a filter that preforms a logical OR of the provided list of filters. 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 From 4d2ab1b092eb6bf55b8702835b57a557355e9044 Mon Sep 17 00:00:00 2001 From: Jens Suhr Date: Wed, 29 Jan 2025 16:36:06 +0100 Subject: [PATCH 2/2] JAVA-5775 Combine and/or filters like KMongo does --- .../mongodb/kotlin/client/model/Filters.kt | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) 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 638d8c9625f..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.filterNotNull()) + 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.filterNotNull()) + 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) + } + } }