diff --git a/test/src/commonTest/kotlin/BasicReadWriteTest.kt b/test/src/commonTest/kotlin/BasicReadWriteTest.kt index 295a384b..83dce065 100644 --- a/test/src/commonTest/kotlin/BasicReadWriteTest.kt +++ b/test/src/commonTest/kotlin/BasicReadWriteTest.kt @@ -16,19 +16,20 @@ package opensavvy.ktmongo.sync +import kotlinx.serialization.Serializable import opensavvy.ktmongo.test.testCollection import opensavvy.prepared.runner.kotest.PreparedSpec -import opensavvy.prepared.suite.SuiteDsl -fun SuiteDsl.basicReadWriteTest() = suite("Basic read/write test") { - class User( +class BasicReadWriteTest : PreparedSpec({ + @Serializable + data class User( val name: String, val age: Int, ) val users by testCollection("basic-users") - test("Foo") { + test("Simple write and read") { users().upsertOne( filter = { User::name eq "Foo" @@ -38,9 +39,7 @@ fun SuiteDsl.basicReadWriteTest() = suite("Basic read/write test") { User::age setOnInsert 0 } ) - } -} -class BasicReadWriteTest : PreparedSpec({ - basicReadWriteTest() + check(User("Bad", 0) in users().find().toList()) + } }) -- 2.51.2 From bfd13d5d265eff15f4109d2d15c4859122241986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:21:03 +0100 Subject: [PATCH 02/11] docs(test): Add a contribution guide for tests --- CONTRIBUTING.md | 2 ++ test/README.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 test/README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 97f53be1..6531f07c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,8 @@ If you have a specific change you'd like to submit, be it documentation, bug fix > > The simplest way of contacting us is by creating an issue on this repository, or commenting in an existing issue. Some projects may also have a Discord server, if you prefer reaching us there. +A simple way to contribute is to [submit integration tests](test/README.md) for features that are important to you, to ensure we won't accidentally break them. + ## Issue tracking If you want to contribute, but do not know what to improve, we recommend going through to existing issues. diff --git a/test/README.md b/test/README.md new file mode 100644 index 00000000..45e1c5a4 --- /dev/null +++ b/test/README.md @@ -0,0 +1,52 @@ +# Integration tests + +This folder contains integration tests using the driver. They are run in CI against the last 3 stable versions of MongoDB, so we can ensure new versions don't break anything. + +We highly welcome contributions adding simple scenarii or complex requests that are important to you. This way, we will ensure they continue to work and use them as the basis for future performance or syntax improvements. + +This could be as simple as a request using some strange combination of options, or as complex as massive aggregations that impact each other. + +If you'd like to contribute, but don't know how to, please read our [contribution guide](https://opensavvy.dev/open-source/index.html#contributing-to-open-source-projects). The rest of this document describes how to edit this project but doesn't explain our general workflow regarding contributions. + +## Requirements + +Before starting, use this command to check if you have a valid Docker installation: +```shell +docker run -it hello-world +``` + +You will also need a valid Java installation, use this command to check if you have one: +```shell +java -version +``` + +The tests require a running MongoDB instance. To start one, click here: `MongoDB`. If you're not using IntelliJ, open [docker-compose.yml](../docker/docker-compose.yml) and run the MongoDB service (from the root of the repository): +```shell +cd docker +docker compose up -d +``` + +Finally, run the existing tests before editing anything, to ensure they all pass: `Check`. If you're not using IntelliJ, run (from the root of the repository): +```shell +./gradlew check +``` + +## Add your scenario + +Open the folder [src/commonTest/kotlin](src/commonTest/kotlin) and create a new Kotlin file. Take inspiration from other existing tests, in particular [BasicReadWriteTest](src/commonTest/kotlin/BasicReadWriteTest.kt). + +These tests use the [Prepared test framework](https://opensavvy.gitlab.io/groundwork/prepared/docs/). The most important things to know are: +- Tests are declared in a class that implements `PreparedSpec`. +- `by testCollection("collection-name")` is used to dynamically generate a new collection on each execution (to ensure parallel tests don't impact each other). The name of the collection is printed in the standard output of the test so you can go observe it afterward. +- The `check` function is used to make assertions. Assertions should not be split into multiple lines nor intermediary variables. +- Most functions should have a quick documentation (CTRL Q by default in IntelliJ). + +Once you're done writing your test, execute it with `Check`. If you're not using IntelliJ, run (from the root of the repository): +```shell +./gradlew check +``` + +Each test should automatically print details on which collections it modified. If a test fails, the collections are kept so you can observe them yourself. In IntelliJ, you can open the "Database" tool window which should already be configured to read from the database. Otherwise, you can connect with any other tool using the URL: +```text +mongodb://localhost:27017 +``` -- 2.51.2 From 0e5a7db88c85e421b99aee0cdfcfc3118f0a4149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:22:57 +0100 Subject: [PATCH 03/11] feat(dsl): Create the InsertOne and InsertMany models --- dsl/src/commonMain/kotlin/models/Insert.kt | 68 +++++++++++++++++++ .../kotlin/options/InsertOptions.kt | 33 +++++++++ 2 files changed, 101 insertions(+) create mode 100644 dsl/src/commonMain/kotlin/models/Insert.kt create mode 100644 dsl/src/commonMain/kotlin/options/InsertOptions.kt diff --git a/dsl/src/commonMain/kotlin/models/Insert.kt b/dsl/src/commonMain/kotlin/models/Insert.kt new file mode 100644 index 00000000..8b4bf899 --- /dev/null +++ b/dsl/src/commonMain/kotlin/models/Insert.kt @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, 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.dsl.models + +import opensavvy.ktmongo.bson.BsonContext +import opensavvy.ktmongo.dsl.KtMongoDsl +import opensavvy.ktmongo.dsl.options.InsertManyOptions +import opensavvy.ktmongo.dsl.options.InsertOneOptions +import opensavvy.ktmongo.dsl.tree.ImmutableNode +import opensavvy.ktmongo.dsl.tree.Node + +/** + * Inserting a single element in a collection. + * + * ### Example + * + * ```kotlin + * users.insertOne(User(name = "Bob", age = 18)) + * ``` + * + * @see InsertMany + * @see InsertOneOptions Options + */ +@KtMongoDsl +class InsertOne private constructor( + val context: BsonContext, + val options: InsertOneOptions, + val document: Document, +) : Node by ImmutableNode { + + constructor(context: BsonContext, document: Document) : this(context, InsertOneOptions(context), document) +} + +/** + * Inserting multiple elements in a collection in a single operation. + * + * ### Example + * + * ```kotlin + * users.insertMany(User(name = "Bob", age = 18), User(name = "Fred", age = 19), User(name = "Arthur", age = 22)) + * ``` + * + * @see InsertOne + * @see InsertManyOptions Options + */ +@KtMongoDsl +class InsertMany private constructor( + val context: BsonContext, + val options: InsertManyOptions, + val documents: List, +) : Node by ImmutableNode { + + constructor(context: BsonContext, documents: List) : this(context, InsertManyOptions(context), documents) +} diff --git a/dsl/src/commonMain/kotlin/options/InsertOptions.kt b/dsl/src/commonMain/kotlin/options/InsertOptions.kt new file mode 100644 index 00000000..24835abf --- /dev/null +++ b/dsl/src/commonMain/kotlin/options/InsertOptions.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024, 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.dsl.options + +import opensavvy.ktmongo.bson.BsonContext +import opensavvy.ktmongo.dsl.options.common.Options +import opensavvy.ktmongo.dsl.options.common.OptionsHolder + +/** + * The options for a `collection.insertOne` operation. + */ +class InsertOneOptions(context: BsonContext) : + Options by OptionsHolder(context) + +/** + * The options for a `collection.insertMany` operation. + */ +class InsertManyOptions(context: BsonContext) : + Options by OptionsHolder(context) -- 2.51.2 From 63705c96b75c514178a2df431fea6afad26d63e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:24:25 +0100 Subject: [PATCH 04/11] feat(dsl): Add insertOne and insertMany in bulkWrite --- dsl/src/commonMain/kotlin/models/BulkWrite.kt | 103 +++++++++++++++++- dsl/src/commonMain/kotlin/models/Insert.kt | 2 +- .../jvmMain/kotlin/models/BulkWrite.jvm.kt | 10 +- 3 files changed, 109 insertions(+), 6 deletions(-) diff --git a/dsl/src/commonMain/kotlin/models/BulkWrite.kt b/dsl/src/commonMain/kotlin/models/BulkWrite.kt index 2d666cb6..eec48c16 100644 --- a/dsl/src/commonMain/kotlin/models/BulkWrite.kt +++ b/dsl/src/commonMain/kotlin/models/BulkWrite.kt @@ -24,6 +24,7 @@ import opensavvy.ktmongo.dsl.expr.FilterOperators import opensavvy.ktmongo.dsl.expr.UpdateOperators import opensavvy.ktmongo.dsl.expr.UpsertOperators import opensavvy.ktmongo.dsl.options.BulkWriteOptions +import opensavvy.ktmongo.dsl.options.InsertOneOptions import opensavvy.ktmongo.dsl.options.UpdateOptions import opensavvy.ktmongo.dsl.tree.CompoundNode import opensavvy.ktmongo.dsl.tree.Node @@ -80,7 +81,7 @@ sealed interface AvailableInBulkWrite : Node * @see BulkWriteOptions Options */ @KtMongoDsl -class BulkWrite private constructor( +class BulkWrite private constructor( val context: BsonContext, private val globalFilter: FilterOperators.() -> Unit, val options: BulkWriteOptions, @@ -134,6 +135,104 @@ class BulkWrite private constructor( acceptAll(child.operations.asIterable()) } + /** + * Inserts a [document]. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.bulkWrite { + * insertOne(User(name = "Bob", age = 18)) + * } + * ``` + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertMany Insert multiple documents. + * @see updateOne Update an existing document. + * @see upsertOne Update or insert a document. + */ + @OptIn(DangerousMongoApi::class, LowLevelApi::class) + fun insertOne( + document: Document, + options: InsertOneOptions.() -> Unit = {}, + ) { + val model = InsertOne(context, document) + + model.options.options() + + accept(model) + } + + /** + * Inserts multiple [documents] in a single operation. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.bulkWrite { + * insertMany(listOf(User(name = "Bob", age = 18), User(name = "Alice", age = 17))) + * } + * ``` + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertOne Insert a single document. + * @see updateMany Update multiple documents. + */ + fun insertMany( + documents: Iterable, + options: InsertOneOptions.() -> Unit = {}, + ) { + for (document in documents) { + insertOne(document, options) + } + } + + /** + * Inserts multiple [documents] in a single operation. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.bulkWrite { + * insertMany(User(name = "Bob", age = 18), User(name = "Alice", age = 17)) + * } + * ``` + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertOne Insert a single document. + * @see updateMany Update multiple documents. + */ + fun insertMany( + vararg documents: Document, + options: InsertOneOptions.() -> Unit = {}, + ) { + insertMany(documents.asList(), options) + } + /** * Updates all documents that match [filter] according to [update]. * @@ -205,6 +304,7 @@ class BulkWrite private constructor( * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#updateone-and-updatemany) * * @see updateMany Update multiple documents. + * @see insertOne Create a new document. * @see upsertOne Create a document if none are found. */ @OptIn(DangerousMongoApi::class, LowLevelApi::class) @@ -256,6 +356,7 @@ class BulkWrite private constructor( * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#updateone-and-updatemany) * - [The behavior of upsert functions](https://www.mongodb.com/docs/manual/reference/method/db.collection.update/#insert-a-new-document-if-no-match-exists--upsert-) * + * @see insertOne Always create a new document. * @see updateOne Do nothing if no matching documents are found. */ @OptIn(DangerousMongoApi::class, LowLevelApi::class) diff --git a/dsl/src/commonMain/kotlin/models/Insert.kt b/dsl/src/commonMain/kotlin/models/Insert.kt index 8b4bf899..8ff7a9ef 100644 --- a/dsl/src/commonMain/kotlin/models/Insert.kt +++ b/dsl/src/commonMain/kotlin/models/Insert.kt @@ -40,7 +40,7 @@ class InsertOne private constructor( val context: BsonContext, val options: InsertOneOptions, val document: Document, -) : Node by ImmutableNode { +) : Node by ImmutableNode, AvailableInBulkWrite { constructor(context: BsonContext, document: Document) : this(context, InsertOneOptions(context), document) } diff --git a/dsl/src/jvmMain/kotlin/models/BulkWrite.jvm.kt b/dsl/src/jvmMain/kotlin/models/BulkWrite.jvm.kt index 2832187b..59b524c4 100644 --- a/dsl/src/jvmMain/kotlin/models/BulkWrite.jvm.kt +++ b/dsl/src/jvmMain/kotlin/models/BulkWrite.jvm.kt @@ -16,13 +16,11 @@ package opensavvy.ktmongo.dsl.models -import com.mongodb.client.model.UpdateManyModel -import com.mongodb.client.model.UpdateOneModel -import com.mongodb.client.model.UpdateOptions -import com.mongodb.client.model.WriteModel +import com.mongodb.client.model.* import opensavvy.ktmongo.dsl.LowLevelApi import opensavvy.ktmongo.dsl.expr.common.toBsonDocument +@Suppress("UNCHECKED_CAST") @OptIn(LowLevelApi::class) fun AvailableInBulkWrite.toJava(): WriteModel = when (this) { is UpdateMany<*> -> UpdateManyModel( @@ -42,4 +40,8 @@ fun AvailableInBulkWrite.toJava(): WriteModel = w /* update = */ this.update.toBsonDocument(), /* options = */ UpdateOptions().upsert(true), ) + + is InsertOne<*> -> InsertOneModel( + /* document = */ (this.document as Document)!! + ) } -- 2.51.2 From f201c3f864d31b059254c3e6dd237af340fd4683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:33:13 +0100 Subject: [PATCH 05/11] feat(driver-sync): Add insertOne and insertMany --- .../commonMain/kotlin/FilteredCollection.kt | 6 + .../src/commonMain/kotlin/MongoCollection.kt | 5 +- .../kotlin/operations/InsertOperations.kt | 120 ++++++++++++++++++ .../src/jvmMain/kotlin/JvmMongoCollection.kt | 33 ++++- 4 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 driver-sync/src/commonMain/kotlin/operations/InsertOperations.kt diff --git a/driver-sync/src/commonMain/kotlin/FilteredCollection.kt b/driver-sync/src/commonMain/kotlin/FilteredCollection.kt index 964a20bb..8e300b94 100644 --- a/driver-sync/src/commonMain/kotlin/FilteredCollection.kt +++ b/driver-sync/src/commonMain/kotlin/FilteredCollection.kt @@ -167,6 +167,12 @@ private class FilteredCollection( ) } + override fun insertOne(document: Document, options: InsertOneOptions.() -> Unit) = + upstream.insertOne(document, options) + + override fun insertMany(documents: Iterable, options: InsertManyOptions.() -> Unit) = + upstream.insertMany(documents, options) + @OptIn(LowLevelApi::class) override fun toString(): String { val filter = FilterExpression(context) diff --git a/driver-sync/src/commonMain/kotlin/MongoCollection.kt b/driver-sync/src/commonMain/kotlin/MongoCollection.kt index 05c2e90f..a3b39738 100644 --- a/driver-sync/src/commonMain/kotlin/MongoCollection.kt +++ b/driver-sync/src/commonMain/kotlin/MongoCollection.kt @@ -32,6 +32,8 @@ import opensavvy.ktmongo.sync.operations.* * - [find][FindOperations.find] * - [findOne][FindOperations.findOne] * - [findOneAndUpdate][UpdateOperations.findOneAndUpdate] + * - [insertOne][InsertOperations.insertOne] + * - [insertMany][InsertOperations.insertMany] * - [updateOne][UpdateOperations.updateOne] * - [updateMany][UpdateOperations.updateMany] * - [upsertOne][UpdateOperations.upsertOne] @@ -45,4 +47,5 @@ interface MongoCollection : CountOperations, UpdateOperations, DeleteOperations, - CollectionOperations + CollectionOperations, + InsertOperations diff --git a/driver-sync/src/commonMain/kotlin/operations/InsertOperations.kt b/driver-sync/src/commonMain/kotlin/operations/InsertOperations.kt new file mode 100644 index 00000000..26d6e3f8 --- /dev/null +++ b/driver-sync/src/commonMain/kotlin/operations/InsertOperations.kt @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, 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.sync.operations + +import opensavvy.ktmongo.dsl.options.InsertManyOptions +import opensavvy.ktmongo.dsl.options.InsertOneOptions +import opensavvy.ktmongo.sync.filter + +/** + * Interface grouping MongoDB operations relating to inserting new documents. + */ +interface InsertOperations : BaseOperations { + + /** + * Inserts a [document]. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.insertOne(User(name = "Bob", age = 18)) + * ``` + * + * Note that `insertOne` ignores [filtered collection][opensavvy.ktmongo.sync.MongoCollection.filter]. + * That is, `insertOne` on a filtered collection behaves exactly the same as the same `insertOne` on the underlying + * real collection. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.insertOne/) + * + * @see insertMany Insert multiple documents. + */ + fun insertOne( + document: Document, + options: InsertOneOptions.() -> Unit = {}, + ) + + /** + * Inserts multiple [documents] in a single operation. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.insertMany(users) + * ``` + * + * Note that `insertOne` ignores [filtered collection][opensavvy.ktmongo.sync.MongoCollection.filter]. + * That is, `insertOne` on a filtered collection behaves exactly the same as the same `insertOne` on the underlying + * real collection. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertOne Insert a single document. + */ + fun insertMany( + documents: Iterable, + options: InsertManyOptions.() -> Unit = {}, + ) + + /** + * Inserts multiple [documents] in a single operation. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.insertMany( + * User(name = "Bob", age = 18), + * User(name = "Alice", age = 17) + * ) + * ``` + * + * Note that `insertOne` ignores [filtered collection][opensavvy.ktmongo.sync.MongoCollection.filter]. + * That is, `insertOne` on a filtered collection behaves exactly the same as the same `insertOne` on the underlying + * real collection. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertOne Insert a single document. + */ + fun insertMany( + vararg documents: Document, + options: InsertManyOptions.() -> Unit = {}, + ) { + insertMany(documents.asList(), options) + } + +} diff --git a/driver-sync/src/jvmMain/kotlin/JvmMongoCollection.kt b/driver-sync/src/jvmMain/kotlin/JvmMongoCollection.kt index 9240a031..b61e749e 100644 --- a/driver-sync/src/jvmMain/kotlin/JvmMongoCollection.kt +++ b/driver-sync/src/jvmMain/kotlin/JvmMongoCollection.kt @@ -173,6 +173,33 @@ class JvmMongoCollection internal constructor( ) } + // endregion + // region Insert + + @OptIn(LowLevelApi::class) + override fun insertOne(document: Document, options: InsertOneOptions.() -> Unit) { + val model = InsertOne(context, document) + + model.options.options() + + inner.insertOne( + model.document, + com.mongodb.client.model.InsertOneOptions() + ) + } + + @OptIn(LowLevelApi::class) + override fun insertMany(documents: Iterable, options: InsertManyOptions.() -> Unit) { + val model = InsertMany(context, documents.toList()) + + model.options.options() + + inner.insertMany( + model.documents, + com.mongodb.client.model.InsertManyOptions() + ) + } + // endregion // region Delete @@ -181,7 +208,7 @@ class JvmMongoCollection internal constructor( options: DeleteOneOptions.() -> Unit, filter: FilterOperators.() -> Unit, ) { - val options = DeleteOneOptions(context).apply(options) + DeleteOneOptions(context).apply(options) val filter = FilterExpression(context).apply(filter) inner.deleteOne( @@ -195,7 +222,7 @@ class JvmMongoCollection internal constructor( options: DeleteManyOptions.() -> Unit, filter: FilterOperators.() -> Unit, ) { - val options = DeleteManyOptions(context).apply(options) + DeleteManyOptions(context).apply(options) val filter = FilterExpression(context).apply(filter) inner.deleteOne( @@ -209,7 +236,7 @@ class JvmMongoCollection internal constructor( @OptIn(LowLevelApi::class) override fun drop(options: DropOptions.() -> Unit) { - val options = DropOptions(context).apply(options) + DropOptions(context).apply(options) inner.drop(DropCollectionOptions()) } -- 2.51.2 From 96ed7f098836c9b70ee6627796a369b6d5a79f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:42:07 +0100 Subject: [PATCH 06/11] feat(driver-coroutines): Add insertOne and insertMany --- .../commonMain/kotlin/FilteredCollection.kt | 6 + .../src/commonMain/kotlin/MongoCollection.kt | 5 +- .../kotlin/operations/InsertOperations.kt | 117 ++++++++++++++++++ .../src/jvmMain/kotlin/JvmMongoCollection.kt | 33 ++++- .../commonTest/kotlin/BasicReadWriteTest.kt | 8 +- 5 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 driver-coroutines/src/commonMain/kotlin/operations/InsertOperations.kt diff --git a/driver-coroutines/src/commonMain/kotlin/FilteredCollection.kt b/driver-coroutines/src/commonMain/kotlin/FilteredCollection.kt index 5854da55..ebccf604 100644 --- a/driver-coroutines/src/commonMain/kotlin/FilteredCollection.kt +++ b/driver-coroutines/src/commonMain/kotlin/FilteredCollection.kt @@ -167,6 +167,12 @@ private class FilteredCollection( ) } + override suspend fun insertOne(document: Document, options: InsertOneOptions.() -> Unit) = + upstream.insertOne(document, options) + + override suspend fun insertMany(documents: Iterable, options: InsertManyOptions.() -> Unit) = + upstream.insertMany(documents, options) + @OptIn(LowLevelApi::class) override fun toString(): String { val filter = FilterExpression(context) diff --git a/driver-coroutines/src/commonMain/kotlin/MongoCollection.kt b/driver-coroutines/src/commonMain/kotlin/MongoCollection.kt index 652bd56e..8f5508c0 100644 --- a/driver-coroutines/src/commonMain/kotlin/MongoCollection.kt +++ b/driver-coroutines/src/commonMain/kotlin/MongoCollection.kt @@ -32,6 +32,8 @@ import opensavvy.ktmongo.coroutines.operations.* * - [find][FindOperations.find] * - [findOne][FindOperations.findOne] * - [findOneAndUpdate][UpdateOperations.findOneAndUpdate] + * - [insertOne][InsertOperations.insertOne] + * - [insertMany][InsertOperations.insertMany] * - [updateOne][UpdateOperations.updateOne] * - [updateMany][UpdateOperations.updateMany] * - [upsertOne][UpdateOperations.upsertOne] @@ -45,4 +47,5 @@ interface MongoCollection : CountOperations, UpdateOperations, DeleteOperations, - CollectionOperations + CollectionOperations, + InsertOperations diff --git a/driver-coroutines/src/commonMain/kotlin/operations/InsertOperations.kt b/driver-coroutines/src/commonMain/kotlin/operations/InsertOperations.kt new file mode 100644 index 00000000..b22964fd --- /dev/null +++ b/driver-coroutines/src/commonMain/kotlin/operations/InsertOperations.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024, 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.operations + +import opensavvy.ktmongo.coroutines.filter +import opensavvy.ktmongo.dsl.options.InsertManyOptions +import opensavvy.ktmongo.dsl.options.InsertOneOptions + +interface InsertOperations : BaseOperations { + + /** + * Inserts a [document]. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.insertOne(User(name = "Bob", age = 18)) + * ``` + * + * Note that `insertOne` ignores [filtered collection][opensavvy.ktmongo.coroutines.MongoCollection.filter]. + * That is, `insertOne` on a filtered collection behaves exactly the same as the same `insertOne` on the underlying + * real collection. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.insertOne/) + * + * @see insertMany Insert multiple documents. + */ + suspend fun insertOne( + document: Document, + options: InsertOneOptions.() -> Unit = {}, + ) + + /** + * Inserts multiple [documents] in a single operation. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.insertMany(users) + * ``` + * + * Note that `insertOne` ignores [filtered collection][opensavvy.ktmongo.coroutines.MongoCollection.filter]. + * That is, `insertOne` on a filtered collection behaves exactly the same as the same `insertOne` on the underlying + * real collection. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertOne Insert a single document. + */ + suspend fun insertMany( + documents: Iterable, + options: InsertManyOptions.() -> Unit = {}, + ) + + /** + * Inserts multiple [documents] in a single operation. + * + * ### Example + * + * ```kotlin + * class User( + * val name: String, + * val age: Int, + * ) + * + * collection.insertMany( + * User(name = "Bob", age = 18), + * User(name = "Alice", age = 17) + * ) + * ``` + * + * Note that `insertOne` ignores [filtered collection][opensavvy.ktmongo.coroutines.MongoCollection.filter]. + * That is, `insertOne` on a filtered collection behaves exactly the same as the same `insertOne` on the underlying + * real collection. + * + * ### External resources + * + * - [Official documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.bulkWrite/#insertone) + * + * @see insertOne Insert a single document. + */ + suspend fun insertMany( + vararg documents: Document, + options: InsertManyOptions.() -> Unit = {}, + ) { + insertMany(documents.asList(), options) + } + +} diff --git a/driver-coroutines/src/jvmMain/kotlin/JvmMongoCollection.kt b/driver-coroutines/src/jvmMain/kotlin/JvmMongoCollection.kt index a90aafa0..2a840997 100644 --- a/driver-coroutines/src/jvmMain/kotlin/JvmMongoCollection.kt +++ b/driver-coroutines/src/jvmMain/kotlin/JvmMongoCollection.kt @@ -173,6 +173,33 @@ class JvmMongoCollection internal constructor( ) } + // endregion + // region Insert + + @OptIn(LowLevelApi::class) + override suspend fun insertOne(document: Document, options: InsertOneOptions.() -> Unit) { + val model = InsertOne(context, document) + + model.options.options() + + inner.insertOne( + model.document, + com.mongodb.client.model.InsertOneOptions() + ) + } + + @OptIn(LowLevelApi::class) + override suspend fun insertMany(documents: Iterable, options: InsertManyOptions.() -> Unit) { + val model = InsertMany(context, documents.toList()) + + model.options.options() + + inner.insertMany( + model.documents, + com.mongodb.client.model.InsertManyOptions() + ) + } + // endregion // region Delete @@ -181,7 +208,7 @@ class JvmMongoCollection internal constructor( options: DeleteOneOptions.() -> Unit, filter: FilterOperators.() -> Unit, ) { - val options = DeleteOneOptions(context).apply(options) + DeleteOneOptions(context).apply(options) val filter = FilterExpression(context).apply(filter) inner.deleteOne( @@ -195,7 +222,7 @@ class JvmMongoCollection internal constructor( options: DeleteManyOptions.() -> Unit, filter: FilterOperators.() -> Unit, ) { - val options = DeleteManyOptions(context).apply(options) + DeleteManyOptions(context).apply(options) val filter = FilterExpression(context).apply(filter) inner.deleteOne( @@ -209,7 +236,7 @@ class JvmMongoCollection internal constructor( @OptIn(LowLevelApi::class) override suspend fun drop(options: DropOptions.() -> Unit) { - val options = DropOptions(context).apply(options) + DropOptions(context).apply(options) inner.drop(DropCollectionOptions()) } diff --git a/test/src/commonTest/kotlin/BasicReadWriteTest.kt b/test/src/commonTest/kotlin/BasicReadWriteTest.kt index 83dce065..dd59c8ce 100644 --- a/test/src/commonTest/kotlin/BasicReadWriteTest.kt +++ b/test/src/commonTest/kotlin/BasicReadWriteTest.kt @@ -29,7 +29,13 @@ class BasicReadWriteTest : PreparedSpec({ val users by testCollection("basic-users") - test("Simple write and read") { + test("Simple insert and read") { + users().insertOne(User(name = "Bob", age = 18)) + + check(User("Bob", age = 18) in users().find().toList()) + } + + test("Simple upsert and read") { users().upsertOne( filter = { User::name eq "Foo" -- 2.51.2 From 4c2fc8a00a65929d5dbe83b7395f623b7e1351de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:44:14 +0100 Subject: [PATCH 07/11] style(dsl): Fixed unclosed region --- dsl/src/commonMain/kotlin/expr/FilterOperators.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt index 8b188866..bdd241aa 100644 --- a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt +++ b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt @@ -2071,4 +2071,5 @@ interface FilterOperators : CompoundExpression, FieldDsl { this.field.containsAll(values) } + // endregion } -- 2.51.2 From 11dd10759dfa17935a1cb89a5d0eea05978fc401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:49:12 +0100 Subject: [PATCH 08/11] =?UTF-8?q?feat(dsl):=20Rename=20any=E2=86=92anyValu?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See #11 --- .../kotlin/expr/FilterExpression.kt | 4 ++-- .../commonMain/kotlin/expr/FilterOperators.kt | 24 +++++++++---------- .../kotlin/expr/filter/ArrayFilterTest.kt | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dsl/src/commonMain/kotlin/expr/FilterExpression.kt b/dsl/src/commonMain/kotlin/expr/FilterExpression.kt index f1c9ee92..edaa5d2e 100644 --- a/dsl/src/commonMain/kotlin/expr/FilterExpression.kt +++ b/dsl/src/commonMain/kotlin/expr/FilterExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, OpenSavvy, 4SH and contributors. + * Copyright (c) 2024, 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. @@ -169,7 +169,7 @@ class FilterExpression( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl - override fun Field>.any(block: PredicateOperators.() -> Unit) { + override fun Field>.anyValue(block: PredicateOperators.() -> Unit) { accept(ElementMatchExpressionNode(this.path, PredicateExpression(context).apply(block), context)) } diff --git a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt index bdd241aa..c1dc383c 100644 --- a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt +++ b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt @@ -94,7 +94,7 @@ import kotlin.reflect.KProperty1 * } * ``` * - * To execute an operator on one of the elements of an array, see [any]. + * To execute an operator on one of the elements of an array, see [anyValue]. * * ### Operators * @@ -1683,7 +1683,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * } * ``` * - * This function is a shorthand for `any`: + * This function is a shorthand for [any]: * ```kotlin * collection.find { * User::grades.any / Gradle::name eq 19 @@ -1717,7 +1717,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * } * ``` * - * This function is a shorthand for `any`: + * This function is a shorthand for [any]: * ```kotlin * collection.find { * User::grades.any / Gradle::name eq 19 @@ -1751,7 +1751,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * } * ``` * - * This function is a shorthand for `any`: + * This function is a shorthand for [any]: * ```kotlin * collection.find { * User::grades.any / Gradle::name eq 19 @@ -1785,7 +1785,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * } * ``` * - * This function is a shorthand for `any`: + * This function is a shorthand for [any]: * ```kotlin * collection.find { * User::grades.any / Gradle::name eq 19 @@ -1815,7 +1815,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * ) * * collection.find { - * Student::grades.any { + * Student::grades.anyValue { * gte(8) * lte(10) * } @@ -1850,7 +1850,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { */ @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl - fun Field>.any(block: PredicateOperators.() -> Unit) + fun Field>.anyValue(block: PredicateOperators.() -> Unit) /** * Specify multiple operators on a single array element. @@ -1867,7 +1867,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * ) * * collection.find { - * Student::grades.any { + * Student::grades.anyValue { * gte(8) * lte(10) * } @@ -1901,8 +1901,8 @@ interface FilterOperators : CompoundExpression, FieldDsl { * - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/query/elemMatch/) */ @KtMongoDsl - fun KProperty1>.any(block: PredicateOperators.() -> Unit) { - this.field.any(block) + fun KProperty1>.anyValue(block: PredicateOperators.() -> Unit) { + this.field.anyValue(block) } /** @@ -1952,7 +1952,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * because the pet "Gwen" has a matching birth month. * * If you want to perform operators on the elements directly (not on their fields), use - * [any] instead. + * [anyValue] instead. * * ### External resources * @@ -2009,7 +2009,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * because the pet "Gwen" has a matching birth month. * * If you want to perform operators on the elements directly (not on their fields), use - * [any] instead. + * [anyValue] instead. * * ### External resources * diff --git a/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt b/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt index 0b395441..8fe3755e 100644 --- a/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt +++ b/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt @@ -56,7 +56,7 @@ class ArrayFilterTest : PreparedSpec({ test("Test on a single array element") { filter { - User::grades.any { + User::grades.anyValue { gt(12) lte(15) } -- 2.51.2 From 75cfa6a1eb262882a33919a634951c88af2fc3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 17:56:48 +0100 Subject: [PATCH 09/11] =?UTF-8?q?feat(dsl):=20Rename=20anyObject=E2=86=92a?= =?UTF-8?q?ny?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #11 --- .../commonMain/kotlin/expr/FilterExpression.kt | 2 +- .../commonMain/kotlin/expr/FilterOperators.kt | 16 ++++++++-------- .../kotlin/expr/filter/ArrayFilterTest.kt | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dsl/src/commonMain/kotlin/expr/FilterExpression.kt b/dsl/src/commonMain/kotlin/expr/FilterExpression.kt index edaa5d2e..efc6000f 100644 --- a/dsl/src/commonMain/kotlin/expr/FilterExpression.kt +++ b/dsl/src/commonMain/kotlin/expr/FilterExpression.kt @@ -175,7 +175,7 @@ class FilterExpression( @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl - override fun Field>.anyObject(block: FilterOperators.() -> Unit) { + override fun Field>.any(block: FilterOperators.() -> Unit) { accept(ElementMatchExpressionNode(path, FilterExpression(context).apply(block), context)) } diff --git a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt index c1dc383c..3a323db5 100644 --- a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt +++ b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt @@ -117,7 +117,7 @@ import kotlin.reflect.KProperty1 * - [`$type`][hasType] * * Array query: - * - [`$elemMatch`][anyObject] + * - [`$elemMatch`][any] */ @KtMongoDsl interface FilterOperators : CompoundExpression, FieldDsl { @@ -1842,7 +1842,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * see the [any] property. * * This function only allows specifying operators on array elements directly. - * To specify operators on sub-fields of array elements, see [anyObject]. + * To specify operators on sub-fields of array elements, see [any]. * * ### External resources * @@ -1894,7 +1894,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * see the [any] property. * * This function only allows specifying operators on array elements directly. - * To specify operators on sub-fields of array elements, see [anyObject]. + * To specify operators on sub-fields of array elements, see [any]. * * ### External resources * @@ -1926,7 +1926,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * val currentMonth = 3 * * collection.find { - * Customer::pets.anyObject { + * Customer::pets.any { * Pet::birthMonth gte currentMonth * Pet::birthMonth lte (currentMonth + 1) * } @@ -1960,7 +1960,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { */ @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl - fun Field>.anyObject(block: FilterOperators.() -> Unit) + fun Field>.any(block: FilterOperators.() -> Unit) /** * Specify multiple operators on fields of a single array element. @@ -1983,7 +1983,7 @@ interface FilterOperators : CompoundExpression, FieldDsl { * val currentMonth = 3 * * collection.find { - * Customer::pets.anyObject { + * Customer::pets.any { * Pet::birthMonth gte currentMonth * Pet::birthMonth lte (currentMonth + 1) * } @@ -2017,8 +2017,8 @@ interface FilterOperators : CompoundExpression, FieldDsl { */ @OptIn(LowLevelApi::class, DangerousMongoApi::class) @KtMongoDsl - fun KProperty1>.anyObject(block: FilterOperators.() -> Unit) { - this.field.anyObject(block) + fun KProperty1>.any(block: FilterOperators.() -> Unit) { + this.field.any(block) } // endregion diff --git a/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt b/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt index 8fe3755e..636f9899 100644 --- a/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt +++ b/dsl/src/commonTest/kotlin/expr/filter/ArrayFilterTest.kt @@ -96,7 +96,7 @@ class ArrayFilterTest : PreparedSpec({ test("Test on subfields of a single array element") { filter { - User::pets.anyObject { + User::pets.any { Pet::age gt 15 Pet::age lte 18 } @@ -124,7 +124,7 @@ class ArrayFilterTest : PreparedSpec({ test("Test on a single subfield of a single array element") { filter { - User::pets.anyObject { + User::pets.any { Pet::age { gt(15) lte(18) @@ -147,7 +147,7 @@ class ArrayFilterTest : PreparedSpec({ test("Everything combined") { filter { User::pets / Pet::age gt 3 - User::pets.anyObject { + User::pets.any { Pet::age gte 1 Pet::name eq "Chocolat" } -- 2.51.2 From 4bdd64ee49d3a4547e41a58a209f378fa98a20e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 18:02:50 +0100 Subject: [PATCH 10/11] docs(dsl): Add documentation header on AbstractCompoundExpression Closes #12 --- .../commonMain/kotlin/expr/common/CompoundExpression.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dsl/src/commonMain/kotlin/expr/common/CompoundExpression.kt b/dsl/src/commonMain/kotlin/expr/common/CompoundExpression.kt index 0eb2dbc5..a6d86b45 100644 --- a/dsl/src/commonMain/kotlin/expr/common/CompoundExpression.kt +++ b/dsl/src/commonMain/kotlin/expr/common/CompoundExpression.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, OpenSavvy, 4SH and contributors. + * Copyright (c) 2024, 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. @@ -59,6 +59,11 @@ interface CompoundExpression : Expression, CompoundNode { companion object } +/** + * Abstract utility class to help implement [CompoundExpression]. + * + * Learn more by reading [Expression], [AbstractExpression] and [CompoundExpression]. + */ abstract class AbstractCompoundExpression( context: BsonContext, ) : AbstractExpression(context), CompoundExpression { -- 2.51.2 From a05f5a053ee32514ca78dff04338f9ea1431c107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Wed, 20 Nov 2024 18:10:09 +0100 Subject: [PATCH 11/11] docs(dsl): Link to tracking issues in operator pages Closes #13 --- dsl/src/commonMain/kotlin/expr/FilterOperators.kt | 3 +++ dsl/src/commonMain/kotlin/expr/PredicateOperators.kt | 2 ++ dsl/src/commonMain/kotlin/expr/UpdateOperators.kt | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt index 3a323db5..53b3732c 100644 --- a/dsl/src/commonMain/kotlin/expr/FilterOperators.kt +++ b/dsl/src/commonMain/kotlin/expr/FilterOperators.kt @@ -117,7 +117,10 @@ import kotlin.reflect.KProperty1 * - [`$type`][hasType] * * Array query: + * - [`$all`][containsAll] * - [`$elemMatch`][any] + * + * If you can't find an operator you're searching for, visit the [tracking issue](https://gitlab.com/opensavvy/ktmongo/-/issues/4). */ @KtMongoDsl interface FilterOperators : CompoundExpression, FieldDsl { diff --git a/dsl/src/commonMain/kotlin/expr/PredicateOperators.kt b/dsl/src/commonMain/kotlin/expr/PredicateOperators.kt index d61c41d3..7cf67c33 100644 --- a/dsl/src/commonMain/kotlin/expr/PredicateOperators.kt +++ b/dsl/src/commonMain/kotlin/expr/PredicateOperators.kt @@ -44,6 +44,8 @@ import opensavvy.ktmongo.dsl.path.FieldDsl * 1. By referring to a specific property, we obtain a [PredicateOperators] that we can use * to declare many operators on that property. * + * If you can't find the operator you're searching for, visit the [tracking issue](https://gitlab.com/opensavvy/ktmongo/-/issues/4). + * * ### External resources * * - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/query/) diff --git a/dsl/src/commonMain/kotlin/expr/UpdateOperators.kt b/dsl/src/commonMain/kotlin/expr/UpdateOperators.kt index cef57d8a..5567345d 100644 --- a/dsl/src/commonMain/kotlin/expr/UpdateOperators.kt +++ b/dsl/src/commonMain/kotlin/expr/UpdateOperators.kt @@ -52,12 +52,14 @@ import kotlin.reflect.KProperty1 * - [`$inc`][inc] * - [`$rename`][renameTo] * - [`$set`][set] - * - [`$setOnInsert`][UpsertOperators.setOnInsert] (only for upserts) + * - [`$setOnInsert`][UpsertOperators.setOnInsert] (only for [upserts][UpsertOperators]) * - [`$unset`][unset] * * On arrays: * - [`$[]`][FieldDsl.get] * + * If you can't find the operator you're searching for, visit the [tracking issue](https://gitlab.com/opensavvy/ktmongo/-/issues/5). + * * ### External resources * * - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/) @@ -379,6 +381,8 @@ interface UpdateOperators : CompoundExpression, FieldDsl { * DSL for MongoDB operators that are used to update existing values, creating new documents if none exist (does *not* include aggregation operators). * * This interface is a variant of [UpdateOperators] used in upsert operations. See [UpdateOperators] for more information. + * + * If you can't find the operator you're searching for, visit the [tracking issue](https://gitlab.com/opensavvy/ktmongo/-/issues/5). */ @KtMongoDsl interface UpsertOperators : UpdateOperators {