commonMain.io.realm.kotlin.mongodb.ext.FunctionsExt.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of library-sync-jvm Show documentation
Show all versions of library-sync-jvm Show documentation
Sync Library code for Realm Kotlin. This artifact is not supposed to be consumed directly, but through 'io.realm.kotlin:gradle-plugin:1.5.2' instead.
The newest version!
/*
* Copyright 2023 Realm Inc.
*
* 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 io.realm.kotlin.mongodb.ext
import io.realm.kotlin.annotations.ExperimentalRealmSerializerApi
import io.realm.kotlin.mongodb.AppConfiguration
import io.realm.kotlin.mongodb.Functions
import io.realm.kotlin.mongodb.exceptions.AppException
import io.realm.kotlin.mongodb.exceptions.FunctionExecutionException
import io.realm.kotlin.mongodb.exceptions.ServiceException
import io.realm.kotlin.mongodb.internal.BsonEncoder
import io.realm.kotlin.mongodb.internal.FunctionsImpl
import io.realm.kotlin.mongodb.internal.serializerOrRealmBuiltInSerializer
import kotlinx.serialization.KSerializer
import org.mongodb.kbson.BsonArray
import org.mongodb.kbson.BsonDocument
import org.mongodb.kbson.BsonValue
import org.mongodb.kbson.ExperimentalKBsonSerializerApi
import org.mongodb.kbson.serialization.Bson
import org.mongodb.kbson.serialization.EJson
/**
* Invokes an Atlas function.
*
* Since the serialization engine [does not support third-party libraries yet](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/formats.md), there are some
* limitations in what types can be used as arguments and return types:
*
* - Primitives, Bson, MutableRealmInt, RealmUUID, ObjectId, RealmInstant, RealmAny, Array, Collection, and Map are valid argument types.
* - Results can only be deserialized to Bson, MutableRealmInt, RealmUUID, ObjectId, RealmInstant, RealmAny and primitive types
*
* The Bson implementations for arrays or maps are [BsonArray] and [BsonDocument], and they can be
* used as valid return types.
*
* @param name name of the function to call.
* @param args arguments to the function.
* @param T the function return value type.
* @return result of the function call.
*
* @throws FunctionExecutionException if the function failed in some way.
* @throws ServiceException for other failures that can happen when communicating with App Services.
* See [AppException] for details.
*/
public suspend inline fun Functions.call(
name: String,
vararg args: Any?
): T = with(this as FunctionsImpl) {
val serializedEjsonArgs = Bson.toJson(BsonEncoder.encodeToBsonValue(args.toList()))
val encodedResult = callInternal(name, serializedEjsonArgs)
BsonEncoder.decodeFromBsonValue(
resultClass = T::class,
bsonValue = Bson(encodedResult)
) as T
}
/**
* Invokes an Atlas function using the EJson encoder defined in [AppConfiguration.ejson].
*
* **Note** This method supports full document serialization. The call arguments are defined with the builder
* [CallBuilder]. This same builder also allows to bind manually any argument or the return type to
* a specific serializer. Arguments and the return value will be encoded and decoded with [AppConfiguration.ejson].
*
* ```
* val dog: Dog = user.functions.call("RetrieveDog") {
* add("a parameter")
* add(1.5, FloatSerializer) // sets the serializer for this particular argument
* returnValueSerializer = DogSerializer // sets the serializer for the return type
* }
* ```
*
* We cannot use a generic because:
* - There is no serializer available for Any.
* - any [KClass.serializer() is marked as Internal](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/serializer.html)
*
* @param name name of the function to call.
* @param callBuilderBlock code block that sets the call arguments and serializers.
* @param T the function return value type.
* @return result of the function call.
*/
@ExperimentalRealmSerializerApi
@OptIn(ExperimentalKBsonSerializerApi::class)
public suspend inline fun Functions.call(
name: String,
callBuilderBlock: CallBuilder.() -> Unit
): T = with(this as FunctionsImpl) {
CallBuilder(app.configuration.ejson)
.apply(callBuilderBlock)
.run {
val serializedEjsonArgs = Bson.toJson(arguments)
val encodedResult = callInternal(name, serializedEjsonArgs)
val returnValueSerializer =
returnValueSerializer
?: ejson.serializersModule.serializerOrRealmBuiltInSerializer()
ejson.decodeFromString(returnValueSerializer, encodedResult)
}
}
/**
* Builder used to construct a call defining serializers for the different arguments and return value.
*/
@ExperimentalRealmSerializerApi
@OptIn(ExperimentalKBsonSerializerApi::class)
public class CallBuilder
@PublishedApi
internal constructor(
@PublishedApi
internal val ejson: EJson,
) {
/**
* Contains all given arguments transformed as [BsonValue]. The encoding is done on each [add] call
* as in that context we have type information from the reified type.
*
* Usually we would store the arguments in a `List` and would serialize just before invoking
* the call, but that would require to do a runtime look up of the argument serializers an operation
* that unfortunately is internal to kserializer and not stable cross all platforms.
*/
@PublishedApi
internal val arguments: BsonArray = BsonArray()
/**
* Serializer that would be used to deserialize the returned value, null by default.
*
* If null, the return value will be deserialized using the embedded type serializer. Note that
* Realm collection types must be set as they don't have an embedded serializer, for example:
*
* ```kotlin
* CallBuilder> {
* returnValueSerializer = RealmListKSerializer(String.serializer())
* }
* ```
*/
public var returnValueSerializer: KSerializer? = null
/**
* Adds an argument with the default serializer for its type to the function call.
*
* @param T argument type.
* @param argument value.
*/
public inline fun add(argument: T) {
add(argument, ejson.serializersModule.serializerOrRealmBuiltInSerializer())
}
/**
* Adds an argument with a user defined serializer to the function call.
*
* @param T argument type.
* @param argument value.
* @param serializer argument serializer.
*/
public inline fun add(argument: T, serializer: KSerializer) {
arguments.add(ejson.encodeToBsonValue(serializer, argument))
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy