diff --git a/driver-coroutines/build.gradle.kts b/driver-coroutines/build.gradle.kts index 9f5f9435..453026bb 100644 --- a/driver-coroutines/build.gradle.kts +++ b/driver-coroutines/build.gradle.kts @@ -23,6 +23,7 @@ kotlin { jvm() sourceSets.commonMain.dependencies { + api(projects.driverApi) api(projects.dsl) api(projects.driverSharedOfficial) api(libs.kotlinx.coroutines) @@ -37,6 +38,10 @@ kotlin { implementation(libsCommon.kotest.assertions) implementation(libsCommon.kotlin.test) } + + compilerOptions { + freeCompilerArgs.add("-Xexpect-actual-classes") + } } library { diff --git a/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoClient.kt b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoClient.kt new file mode 100644 index 00000000..c7b4ae67 --- /dev/null +++ b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoClient.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2026, OpenSavvy and contributors. + * + * 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 opensavvy.ktmongo.coroutines + +import opensavvy.ktmongo.api.MongoClient + +/** + * Entry-point to the KtMongo Coroutines driver. + * + * The Coroutine client provides a coroutine-aware API which internally uses the + * [official Kotlin driver](https://www.mongodb.com/docs/drivers/kotlin/coroutine/current/). + * + * ### Organizing data + * + * Accessing MongoDB data happens in three steps: + * - [CoroutineMongoClient]: represents the connection to the MongoDB application, handles + * the lifecycle and the configuration. + * - [CoroutineMongoDatabase] (accessed with [CoroutineMongoClient.database]): each database groups data together. + * This allows deploying multiple applications (or the same application multiple times) + * without name collisions. + * - [CoroutineMongoCollection] (accessed with [CoroutineMongoDatabase.collection]): each collection stores data together. + * Documents in a collection may have a different structure. + * + * ### Example + * + * ```kotlin + * @Serializable + * class User( + * val _id: ObjectId, + * val name: String, + * val age: Int, + * ) + * + * fun main() = runBlocking { + * val client: CoroutineMongoClient = // TODO + * + * val database = client.database("my-app") + * val users = database.collection("users") + * + * println("The database contains ${users.count()} users.") + * } + * ``` + */ +interface CoroutineMongoClient : MongoClient { + + /** + * Obtains the underlying MongoDB client from the official Kotlin driver. + */ + fun asOfficial(): com.mongodb.kotlin.client.coroutine.MongoClient + + override fun database(name: String): CoroutineMongoDatabase +} diff --git a/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoCollection.kt b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoCollection.kt new file mode 100644 index 00000000..a2fda928 --- /dev/null +++ b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoCollection.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2026, OpenSavvy and contributors. + * + * 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 opensavvy.ktmongo.coroutines + +import opensavvy.ktmongo.api.MongoCollection +import opensavvy.ktmongo.api.MongoDatabase +import opensavvy.ktmongo.bson.official.BsonFactory + +/** + * A collection stores related documents together. + * + * The Coroutine client provides a coroutine-aware API which internally uses the + * [official Kotlin driver](https://www.mongodb.com/docs/drivers/kotlin/coroutine/current/). + * + * Usually, all documents in a collection have the same shape (the same fields). + * However, heterogeneous structure can be achieved by using: + * - Kotlin collections, like [List] and [Set], the embed an arbitrary number of items. + * - Polymorphism, for example with `sealed class`, to have different fields based on a discriminator. + * + * To avoid name collisions, collections are grouped into [databases][MongoDatabase]. + * + * To obtain a collection, see [MongoDatabase.collection]. + * + * ### Size limit + * + * A MongoDB document cannot exceed 16 MiB. + * + * You can measure the size of a document with [opensavvy.ktmongo.bson.BsonDocument.toByteArray] + * followed by [ByteArray.size]. + * + * The maximum nesting is 100 levels. + * Each document or array adds a level. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/core/databases-and-collections/) + * - [Size limits](https://www.mongodb.com/docs/manual/reference/limits/#bson-documents) + */ +interface CoroutineMongoCollection : MongoCollection { + + /** + * Obtains the underlying MongoDB collection from the official Kotlin driver. + */ + fun asOfficial(): com.mongodb.kotlin.client.coroutine.MongoCollection + + override val factory: BsonFactory + +} diff --git a/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoDatabase.kt b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoDatabase.kt new file mode 100644 index 00000000..943960b9 --- /dev/null +++ b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoDatabase.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026, OpenSavvy and contributors. + * + * 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 opensavvy.ktmongo.coroutines + +import opensavvy.ktmongo.api.MongoClient +import opensavvy.ktmongo.api.MongoDatabase +import opensavvy.ktmongo.dsl.LowLevelApi +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +/** + * A grouping of collections with the same theme. + * + * The Coroutine client provides a coroutine-aware API which internally uses the + * [official Kotlin driver](https://www.mongodb.com/docs/drivers/kotlin/coroutine/current/). + * + * ### What is a database? + * + * [Collections][MongoCollection] are grouped into databases to avoid name collisions. + * Databases are similar to Kotlin packages. + * If multiple applications are deployed in the same MongoDB instance in their own database, + * they can use the same collection names (e.g. `users`) without conflicts. + * + * Each database has a [name] that must be unique within a MongoDB deployment. + * + * ### Access + * + * To obtain a database, see [MongoClient.database]. + * + * To obtain a collection, see [collection]. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/core/databases-and-collections/) + */ +interface CoroutineMongoDatabase : MongoDatabase { + + /** + * Obtains the underlying MongoDB database from the official Kotlin driver. + */ + fun asOfficial(): com.mongodb.kotlin.client.coroutine.MongoDatabase + + @LowLevelApi + override fun collection(name: String, type: KType): CoroutineMongoCollection + + /** + * Creates a [MongoCollection] object. + * + * This method is purely a client-side operation, it does nothing in the MongoDB server. + * In MongoDB, databases and collections are created implicitly on the first insert. + * + * For an example, see [MongoClient]. + */ + @OptIn(LowLevelApi::class) + @Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION") + final inline fun collection(name: String): CoroutineMongoCollection = + collection(name, type = typeOf()) + +} diff --git a/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoIterable.kt b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoIterable.kt new file mode 100644 index 00000000..7a48b5d2 --- /dev/null +++ b/driver-coroutines/src/jvmMain/kotlin/CoroutineMongoIterable.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, OpenSavvy and contributors. + * + * 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 opensavvy.ktmongo.coroutines + +import com.mongodb.kotlin.client.coroutine.FindFlow +import opensavvy.ktmongo.api.MongoIterable + +/** + * Streaming-capable iterable cursor to read data from the database. + * + * The Coroutine client provides a coroutine-aware API which internally uses the + * [official Kotlin driver](https://www.mongodb.com/docs/drivers/kotlin/coroutine/current/). + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/core/cursors/) + */ +interface CoroutineMongoIterable : MongoIterable { + + /** + * Obtains the underlying MongoDB flow from the official Kotlin driver. + */ + fun asOfficial(): FindFlow + +}