From 229250a5baf350284cabee4c0010b859b2b2bb2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 12 Sep 2026 20:08:48 +0200 Subject: [PATCH] feat(driver-sync): Implement MongoCollection.unsafeCast() --- .../kotlin/BlockingMongoCollection.kt | 3 + .../kotlin/SyncFilteredMongoCollectionImpl.kt | 4 ++ .../src/jvmMain/kotlin/SyncMongoCollection.kt | 55 +++++++++++++++++++ .../jvmMain/kotlin/SyncMongoCollectionImpl.kt | 5 ++ 4 files changed, 67 insertions(+) diff --git a/driver-sync-api-adapter/src/commonMain/kotlin/BlockingMongoCollection.kt b/driver-sync-api-adapter/src/commonMain/kotlin/BlockingMongoCollection.kt index ac1c18ed..082bef1c 100644 --- a/driver-sync-api-adapter/src/commonMain/kotlin/BlockingMongoCollection.kt +++ b/driver-sync-api-adapter/src/commonMain/kotlin/BlockingMongoCollection.kt @@ -170,6 +170,9 @@ class BlockingMongoCollection( BlockingUpsertResult(inner.upsertOneWithPipeline(options, filter, update)) } + override fun unsafeCast(type: KType): BlockingMongoCollection = + BlockingMongoCollection(inner.unsafeCast(type)) + override fun toString(): String = inner.toString() } diff --git a/driver-sync/src/jvmMain/kotlin/SyncFilteredMongoCollectionImpl.kt b/driver-sync/src/jvmMain/kotlin/SyncFilteredMongoCollectionImpl.kt index 53210b48..a4d27ade 100644 --- a/driver-sync/src/jvmMain/kotlin/SyncFilteredMongoCollectionImpl.kt +++ b/driver-sync/src/jvmMain/kotlin/SyncFilteredMongoCollectionImpl.kt @@ -90,6 +90,10 @@ private class SyncFilteredMongoCollectionImpl( override val context: BsonContext get() = upstream.context + @Suppress("UNCHECKED_CAST") + override fun unsafeCast(type: KType): SyncMongoCollection = + SyncFilteredMongoCollectionImpl(upstream.unsafeCast(type), globalFilter as FilterQuery.() -> Unit) + override fun create(options: CreateCollectionOptions.() -> Unit) = error("It is not possible to call 'create' on the filtered collection $this:\nA filtered collection is a driver-side view, it cannot exist in the database itself.") diff --git a/driver-sync/src/jvmMain/kotlin/SyncMongoCollection.kt b/driver-sync/src/jvmMain/kotlin/SyncMongoCollection.kt index c643d769..4f8ac969 100644 --- a/driver-sync/src/jvmMain/kotlin/SyncMongoCollection.kt +++ b/driver-sync/src/jvmMain/kotlin/SyncMongoCollection.kt @@ -28,6 +28,8 @@ import opensavvy.ktmongo.dsl.query.UpdateWithPipelineQuery import opensavvy.ktmongo.dsl.query.UpsertQuery import opensavvy.ktmongo.sync.api.MongoCollection import opensavvy.ktmongo.sync.api.operations.UpdateOperations +import kotlin.reflect.KType +import kotlin.reflect.typeOf /** * A collection stores related documents together. @@ -99,4 +101,57 @@ interface SyncMongoCollection : MongoCollection { override fun find(): SyncMongoFindIterable override fun find(options: FindOptions.() -> Unit, filter: FilterQuery.() -> Unit): SyncMongoFindIterable + + /** + * Overwrites the represented type of this value. + * + * This method can be useful to bypass type checks. + * + * ### Example + * + * If we know there are some documents that have the wrong format, we can use `unsafeCast` to find them + * without needing to add their fields to the production DTO. + * + * ```kotlin + * class User( + * val _id: ObjectId, + * val name: String, + * ) + * + * users.unsafeCast() // Treat all data as arbitrary BSON documents + * .find { BsonDocument.get("oldField") ne null } + * .forEach { + * println(it["oldField"]?.decodeString()) + * } + * ``` + */ + override fun unsafeCast(type: KType): SyncMongoCollection + + /** + * Overwrites the represented type of this value. + * + * This method can be useful to bypass type checks. + * + * ### Example + * + * If we know there are some documents that have the wrong format, we can use `unsafeCast` to find them + * without needing to add their fields to the production DTO. + * + * ```kotlin + * class User( + * val _id: ObjectId, + * val name: String, + * ) + * + * users.unsafeCast() // Treat all data as arbitrary BSON documents + * .find { BsonDocument.get("oldField") ne null } + * .forEach { + * println(it["oldField"]?.decodeString()) + * } + * ``` + */ + @Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION") + final inline fun unsafeCast(): SyncMongoCollection = + unsafeCast(typeOf()) + } diff --git a/driver-sync/src/jvmMain/kotlin/SyncMongoCollectionImpl.kt b/driver-sync/src/jvmMain/kotlin/SyncMongoCollectionImpl.kt index f1d68fb6..595ec8a0 100644 --- a/driver-sync/src/jvmMain/kotlin/SyncMongoCollectionImpl.kt +++ b/driver-sync/src/jvmMain/kotlin/SyncMongoCollectionImpl.kt @@ -47,6 +47,7 @@ import opensavvy.ktmongo.official.toJava import opensavvy.ktmongo.official.toKtMongo import opensavvy.ktmongo.sync.api.operations.UpdateOperations import java.util.concurrent.TimeUnit +import kotlin.reflect.KClass import kotlin.reflect.KType import kotlin.reflect.typeOf import com.mongodb.client.model.ReplaceOptions as MongoReplaceOptions @@ -82,6 +83,10 @@ private class SyncMongoCollectionImpl( @LowLevelApi override val context: BsonContext = CoroutineBsonContext() + @Suppress("UNCHECKED_CAST") + override fun unsafeCast(type: KType): SyncMongoCollection = + SyncMongoCollectionImpl(inner.withDocumentClass((type.classifier as KClass).java), factory, propertyNameStrategy, objectIdGenerator, type, innerDatabase) + // region Count override fun count(): Long = -- 2.51.2