commonMain.expr.UpdateOperators.kt Maven / Gradle / Ivy
/*
* 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.expr
import opensavvy.ktmongo.dsl.DangerousMongoApi
import opensavvy.ktmongo.dsl.KtMongoDsl
import opensavvy.ktmongo.dsl.LowLevelApi
import opensavvy.ktmongo.dsl.expr.common.CompoundExpression
import opensavvy.ktmongo.dsl.path.*
import kotlin.reflect.KProperty1
/**
* DSL for MongoDB operators that are used to update existing values (does *not* include aggregation operators).
*
* ### Example
*
* This expression type is available on multiple operations, most commonly `update`:
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* )
*
* collection.update(
* filter = {
* User::name eq "Bob"
* },
* update = {
* User::age set 18
* }
* )
* ```
*
* ### Operators
*
* On regular fields:
* - [`$inc`][inc]
* - [`$rename`][renameTo]
* - [`$set`][set]
* - [`$setOnInsert`][UpsertOperators.setOnInsert] (only for [upserts][UpsertOperators])
* - [`$unset`][unset]
*
* On arrays:
* - [`$`][selected]
* - [`$[]`][all]
*
* 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/)
*
* @see FilterExpression Filters
*/
@KtMongoDsl
interface UpdateOperators : CompoundExpression, FieldDsl {
// region $set
/**
* Replaces the value of a field with the specified [value].
*
* ### Example
*
* ```kotlin
* class User(
* val name: String?,
* val age: Int,
* )
*
* collection.filter {
* User::name eq "foo"
* }.updateMany {
* User::age set 18
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/set/)
*
* @see UpsertOperators.setOnInsert Only set if a new document is created.
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> Field.set(value: V)
/**
* Replaces the value of a field with the specified [value].
*
* ### Example
*
* ```kotlin
* class User(
* val name: String?,
* val age: Int,
* )
*
* collection.filter {
* User::name eq "foo"
* }.updateMany {
* User::age set 18
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/set/)
*
* @see UpsertOperators.setOnInsert Only set if a new document is created.
*/
@OptIn(LowLevelApi::class, DangerousMongoApi::class)
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> KProperty1.set(value: V) {
this.field.set(value)
}
// endregion
// region $inc
/**
* Increments a field by the specified [amount].
*
* [amount] may be negative, in which case the field is decremented.
*
* If the field doesn't exist (either the document doesn't have it, or the operation is an upsert and a new document is created),
* the field is created with an initial value of [amount].
*
* Use of this operator with a field with a `null` value will generate an error.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* )
*
* // It's the new year!
* collection.updateMany {
* User::age inc 1
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/inc/)
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V : Number> Field.inc(amount: V)
/**
* Increments a field by the specified [amount].
*
* [amount] may be negative, in which case the field is decremented.
*
* If the field doesn't exist (either the document doesn't have it, or the operation is an upsert and a new document is created),
* the field is created with an initial value of [amount].
*
* Use of this operator with a field with a `null` value will generate an error.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* )
*
* // It's the new year!
* collection.updateMany {
* User::age inc 1
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/inc/)
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V : Number> KProperty1.inc(amount: V) {
this.field.inc(amount)
}
// endregion
// region $unset
/**
* Deletes a field.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* val alive: Boolean,
* )
*
* collection.filter {
* User::name eq "Luke Skywalker"
* }.updateOne {
* User::age.unset()
* User::alive set false
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/unset/)
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
fun <@kotlin.internal.OnlyInputTypes V> Field.unset()
/**
* Deletes a field.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* val alive: Boolean,
* )
*
* collection.filter {
* User::name eq "Luke Skywalker"
* }.updateOne {
* User::age.unset()
* User::alive set false
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/unset/)
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
fun <@kotlin.internal.OnlyInputTypes V> KProperty1.unset() {
this.field.unset()
}
// endregion
// region $rename
/**
* Renames a field.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* val ageOld: Int,
* )
*
* collection.updateMany {
* User::ageOld renameTo User::age
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/rename/)
*/
@OptIn(LowLevelApi::class, DangerousMongoApi::class)
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> Field.renameTo(newName: Field)
/**
* Renames a field.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* val ageOld: Int,
* )
*
* collection.updateMany {
* User::ageOld renameTo User::age
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/rename/)
*/
@OptIn(LowLevelApi::class, DangerousMongoApi::class)
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> KProperty1.renameTo(newName: Field) {
this.field.renameTo(newName)
}
/**
* Renames a field.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* val ageOld: Int,
* )
*
* collection.updateMany {
* User::ageOld renameTo User::age
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/rename/)
*/
@OptIn(LowLevelApi::class, DangerousMongoApi::class)
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> Field.renameTo(newName: KProperty1) {
this.renameTo(newName.field)
}
/**
* Renames a field.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val age: Int,
* val ageOld: Int,
* )
*
* collection.updateMany {
* User::ageOld renameTo User::age
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/rename/)
*/
@OptIn(LowLevelApi::class, DangerousMongoApi::class)
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> KProperty1.renameTo(newName: KProperty1) {
this.renameTo(newName.field)
}
// endregion
// region Positional operator: $
/**
* The positional operator: update an array item selected in the filter.
*
* When we use [any][FilterOperators.any] or [anyValue][FilterOperators.anyValue]
* in a filter to select an item, we can use this operator to update whichever item was selected.
*
* Do not use this operator in an `upsert`.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val pets: List,
* )
*
* class Pet(
* val name: String,
* val age: Int,
* )
*
* users.updateMany(
* filter = {
* User::pets.any / Pet::name eq "Bobby"
* },
* update = {
* User::pets.selected / Pet::age inc 1
* }
* )
* ```
*
* This example finds all users who have a pet named "Bobby", and increases its age by 1.
* Note that if the users have other pets, they are not impacted.
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/positional/)
*/
@OptIn(LowLevelApi::class)
val Field>.selected: Field
get() = FieldImpl(path / PathSegment.Positional)
/**
* The positional operator: update an array item selected in the filter.
*
* When we use [any][FilterOperators.any] or [anyValue][FilterOperators.anyValue]
* in a filter to select an item, we can use this operator to update whichever item was selected.
*
* Do not use this operator in an `upsert`.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val pets: List,
* )
*
* class Pet(
* val name: String,
* val age: Int,
* )
*
* users.updateMany(
* filter = {
* User::pets.any / Pet::name eq "Bobby"
* },
* update = {
* User::pets.selected / Pet::age inc 1
* }
* )
* ```
*
* This example finds all users who have a pet named "Bobby", and increases its age by 1.
* Note that if the users have other pets, they are not impacted.
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/positional/)
*/
val KProperty1>.selected: Field
get() = this.field.selected
// endregion
// region All positional operator: $[]
/**
* The all positional operator: selects all elements of an array.
*
* This operator is used to declare an update that applies to all items of an array.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val pets: List,
* )
*
* class Pet(
* val name: String,
* val age: Int,
* )
*
* users.updateMany {
* User::pets.all / Pet::age inc 1
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/positional-all/)
*/
@OptIn(LowLevelApi::class)
val Field>.all: Field
get() = FieldImpl(path / PathSegment.AllPositional)
/**
* The all positional operator: selects all elements of an array.
*
* This operator is used to declare an update that applies to all items of an array.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String,
* val pets: List,
* )
*
* class Pet(
* val name: String,
* val age: Int,
* )
*
* users.updateMany {
* User::pets.all / Pet::age inc 1
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/positional-all/)
*/
val KProperty1>.all: Field
get() = this.field.all
// endregion
}
/**
* 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 {
// region $setOnInsert
/**
* If an upsert operation results in an insert of a document,
* then this operator assigns the specified [value] to the field.
* If the update operation does not result in an insert, this operator does nothing.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String?,
* val age: Int,
* )
*
* collection.filter {
* User::name eq "foo"
* }.upsertOne {
* User::age setOnInsert 18
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/setOnInsert/)
*
* @see set Always set the value.
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> Field.setOnInsert(value: V)
/**
* If an upsert operation results in an insert of a document,
* then this operator assigns the specified [value] to the field.
* If the update operation does not result in an insert, this operator does nothing.
*
* ### Example
*
* ```kotlin
* class User(
* val name: String?,
* val age: Int,
* )
*
* collection.filter {
* User::name eq "foo"
* }.upsertOne {
* User::age setOnInsert 18
* }
* ```
*
* ### External resources
*
* - [Official documentation](https://www.mongodb.com/docs/manual/reference/operator/update/setOnInsert/)
*
* @see set Always set the value.
*/
@Suppress("INVISIBLE_REFERENCE")
@KtMongoDsl
infix fun <@kotlin.internal.OnlyInputTypes V> KProperty1.setOnInsert(value: V) {
this.field.setOnInsert(value)
}
// endregion
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy