Something went wrong. Try again.
The next MongoDB driver for Kotlin ktmongo.opensavvy.dev
kotlin mongodb multiplatform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102/* * Copyright (c) 2025, 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
import com.github.meanbeanlib.mirror.Executablesimport com.github.meanbeanlib.mirror.SerializableLambdasimport opensavvy.ktmongo.dsl.LowLevelApiimport opensavvy.ktmongo.dsl.path.Fieldimport opensavvy.ktmongo.dsl.path.Pathimport opensavvy.ktmongo.dsl.path.PathSegmentimport opensavvy.ktmongo.dsl.path.divimport org.bson.codecs.pojo.annotations.BsonId
/** * Type-safe representation of a dotted MongoDB field path from Java method references. * * This class is used to type-safely refer to fields from a DTO. For example, if we have the DTO: * ```java * public record Invoice( * @BsonId ObjectId id, * Customer customer * ) { * * public record Customer( * String name, * String address * ) {} * } * ``` * * We can refer to the different fields as: * - `"_id"`: `JavaField.of(Invoice::id)` * - `"customer"`: `JavaField.of(Invoice::customer)` * - `"customer.name"`: `JavaField.of(Invoice::customer).child(Customer::name)` * - `"customer.address"`: `JavaField.of(Invoice::customer).child(Customer::address)` * * Because the generated reference is type-safe, you don't risk typos, and you can navigate from a DTO to * all its usages in all requests using your usual IDE tooling. * * **Important note.** If you're using KtMongo in a mixed Java-Kotlin project, note that this class has a slightly * different mapping algorithm than the Kotlin [Field] implementations, because Kotlin has field references * but Java doesn't, and Kotlin allows the name `_id` but Java doesn't. * In Kotlin code, KtMongo always uses the Kotlin field name as-is, whereas this class will use `_id` if the field * is annotated with `@BsonId`, remove the `"get"` prefix of a getter, etc. For the exact mapping algorithm, see * the implementation. * * @see JavaField.of Builds an instance of this class. */@OptIn(LowLevelApi::class)class JavaField<Root, Type> private constructor( override val path: Path,) : Field<Root, Type> {
/** * Refers to a specific field that is a child of the current field. * * For more information, and for examples, see [JavaField]. */ fun <T> child(accessor: SerializableLambdas.SerializableFunction1<Type, T>): JavaField<Root, T> { return JavaField(path / PathSegment.Field(accessor.name)) }
companion object {
private val SerializableLambdas.SerializableFunction1<*, *>.name: String get() { val getter = Executables.findGetter(this)
return when { getter.annotations.any { it is BsonId } -> "_id" getter.name.startsWith("get") -> getter.name.removePrefix("get").replaceFirstChar { it.lowercase() } getter.name.startsWith("is") -> getter.name.removePrefix("is").replaceFirstChar { it.lowercase() } else -> getter.name } }
/** * Type-safely refers to a MongoDB field based on its Java DTO. * * For more information, and for examples, see [JavaField]. */ @JvmStatic fun <R, T> of(accessor: SerializableLambdas.SerializableFunction1<R, T>): JavaField<R, T> { return JavaField(Path(accessor.name)) } }}