All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.algolia.search.model.indexing.Partial.kt Maven / Gradle / Ivy

package com.algolia.search.model.indexing

import com.algolia.search.endpoint.EndpointIndexing
import com.algolia.search.helper.toAttribute
import com.algolia.search.model.Attribute
import com.algolia.search.serialize.internal.Key
import com.algolia.search.serialize.internal.asJsonInput
import com.algolia.search.serialize.internal.asJsonOutput
import com.algolia.search.serialize.internal.jsonPrimitiveOrNull
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.put

/**
 * An object used to define a partial update operation with the [EndpointIndexing.partialUpdateObject] method.
 */
public sealed class Partial {

    /**
     * The attribute on which the partial update will be applied.
     */
    public abstract val attribute: Attribute

    internal abstract val value: JsonElement

    /**
     * Add or update the value of an attribute.
     * Several convenience constructors are available for each value type.
     */
    public data class Update internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: String) : this(attribute, JsonPrimitive(value))

        public constructor(attribute: Attribute, value: Boolean) : this(attribute, JsonPrimitive(value))

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))

        public constructor(attribute: Attribute, value: JsonArray) : this(attribute, value as JsonElement)

        public constructor(attribute: Attribute, value: JsonObject) : this(attribute, value as JsonElement)
    }

    /**
     * Increment a numeric based value for an attribute.
     */
    public data class Increment internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    /**
     * Increment a numeric integer attribute only if the provided value matches the current value, and otherwise ignore
     * the whole object update. For example, if you pass an `IncrementFrom` value of 2 for the `version` attribute, but
     * the current value of the attribute is 1, the engine ignores the update. If the object doesn't exist, the engine
     * only creates it if you pass an `IncrementFrom` value of 0.
     */
    public data class IncrementFrom internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    /**
     * Increment a numeric integer attribute only if the provided value is greater than the current value, and otherwise
     * ignore the whole object update. For example, if you pass an `IncrementSet` value of 2 for the `version`
     * attribute, and the current value of the attribute is 1, the engine updates the object. If the object doesn't
     * exist yet, the engine only creates it if you pass an `IncrementSet` value that's greater than 0.
     */
    public data class IncrementSet internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    /**
     * Decrement a numeric based value for an attribute.
     */
    public data class Decrement internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    /**
     * Append a number or string element to an array-based value for an attribute.
     */
    public data class Add internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: String) : this(attribute, JsonPrimitive(value))

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    /**
     * Remove all matching number or string elements from an array-based value for an attribute
     */
    public data class Remove internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: String) : this(attribute, JsonPrimitive(value))

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    /**
     * Add a number or string element to an array-based value for an attribute only if it’s not already present
     */
    public data class AddUnique internal constructor(
        override val attribute: Attribute,
        override val value: JsonElement
    ) : Partial() {

        public constructor(attribute: Attribute, value: String) : this(attribute, JsonPrimitive(value))

        public constructor(attribute: Attribute, value: Number) : this(attribute, JsonPrimitive(value))
    }

    @OptIn(ExperimentalSerializationApi::class)
    @Serializer(Partial::class)
    public companion object : KSerializer {

        override fun serialize(encoder: Encoder, value: Partial) {
            val key = when (value) {
                is Update -> null
                is Increment -> Key.Increment
                is IncrementFrom -> Key.IncrementFrom
                is IncrementSet -> Key.IncrementSet
                is Decrement -> Key.Decrement
                is Add -> Key.Add
                is Remove -> Key.Remove
                is AddUnique -> Key.AddUnique
            }
            val json = buildJsonObject {
                put(
                    value.attribute.raw,
                    key?.let {
                        buildJsonObject {
                            put(Key._Operation, key)
                            put(Key.Value, value.value)
                        }
                    } ?: value.value
                )
            }
            encoder.asJsonOutput().encodeJsonElement(json)
        }

        override fun deserialize(decoder: Decoder): Partial {
            val element = decoder.asJsonInput().jsonObject
            val key = element.keys.first()
            val attribute = key.toAttribute()
            val value = element.getValue(key)
            val hasOperation = (value is JsonObject && value.jsonObject.containsKey(Key._Operation))
            val operation = if (hasOperation) value.jsonObject[Key._Operation]?.jsonPrimitiveOrNull?.content else null
            val jsonElement = if (hasOperation) value.jsonObject.getValue((Key.Value)) else value

            return when (operation) {
                null -> Update(attribute, jsonElement)
                Key.Increment -> Increment(attribute, jsonElement)
                Key.IncrementFrom -> IncrementFrom(attribute, jsonElement)
                Key.IncrementSet -> IncrementSet(attribute, jsonElement)
                Key.Decrement -> Decrement(attribute, jsonElement)
                Key.Add -> Add(attribute, jsonElement)
                Key.Remove -> Remove(attribute, jsonElement)
                Key.AddUnique -> AddUnique(attribute, jsonElement)
                else -> throw Exception("Unknown operation $operation")
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy