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

io.evitadb.api.requestResponse.data.mutation.attribute.ApplyDeltaAttributeMutation Maven / Gradle / Ivy

There is a newer version: 2024.10.0
Show newest version
/*
 *
 *                         _ _        ____  ____
 *               _____   _(_) |_ __ _|  _ \| __ )
 *              / _ \ \ / / | __/ _` | | | |  _ \
 *             |  __/\ V /| | || (_| | |_| | |_) |
 *              \___| \_/ |_|\__\__,_|____/|____/
 *
 *   Copyright (c) 2023
 *
 *   Licensed under the Business Source License, Version 1.1 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   https://github.com/FgForrest/evitaDB/blob/master/LICENSE
 *
 *   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.evitadb.api.requestResponse.data.mutation.attribute;

import io.evitadb.api.exception.InvalidMutationException;
import io.evitadb.api.requestResponse.data.AttributesContract.AttributeKey;
import io.evitadb.api.requestResponse.data.AttributesContract.AttributeValue;
import io.evitadb.api.requestResponse.schema.EntitySchemaContract;
import io.evitadb.dataType.NumberRange;
import io.evitadb.utils.Assert;
import lombok.EqualsAndHashCode;
import lombok.Getter;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serial;
import java.math.BigDecimal;
import java.util.Locale;

/**
 * Increments or decrements existing numeric value by specified delta (negative number produces decremental of
 * existing number, positive one incrementation).
 *
 * Allows to specify the number range that is tolerated for the value after delta application has been finished to
 * verify for example that number of items on stock doesn't go below zero.
 *
 * @author Jan Novotný ([email protected]), FG Forrest a.s. (c) 2021
 */
@EqualsAndHashCode(callSuper = true)
public class ApplyDeltaAttributeMutation extends AttributeSchemaEvolvingMutation {
	@Serial private static final long serialVersionUID = -107926476337012921L;
	/**
	 * Delta value that should be applied to the existing attribute.
	 * Delta is added to the existing number, negative delta decreases it, positive delta increases it.
	 */
	@Getter private final T delta;
	/**
	 * Required number inclusive range that needs to be valid for the attribute value after the delta has been applied.
	 * Might be NULL if no check is necessary. When the value is outside the requested range mutation is not applied
	 * and exception is thrown that eventually results in transaction rollback.
	 */
	@Nullable
	@Getter private final NumberRange requiredRangeAfterApplication;

	public ApplyDeltaAttributeMutation(@Nonnull AttributeKey attributeKey, @Nonnull T delta) {
		super(attributeKey);
		this.delta = delta;
		this.requiredRangeAfterApplication = null;
	}

	public ApplyDeltaAttributeMutation(@Nonnull String attributeName, @Nonnull T delta) {
		super(new AttributeKey(attributeName));
		this.delta = delta;
		this.requiredRangeAfterApplication = null;
	}

	public ApplyDeltaAttributeMutation(@Nonnull String attributeName, @Nullable Locale locale, @Nonnull T delta) {
		super(new AttributeKey(attributeName, locale));
		this.delta = delta;
		this.requiredRangeAfterApplication = null;
	}

	public ApplyDeltaAttributeMutation(@Nonnull AttributeKey attributeKey, @Nonnull T delta, @Nullable NumberRange requiredRangeAfterApplication) {
		super(attributeKey);
		this.delta = delta;
		this.requiredRangeAfterApplication = requiredRangeAfterApplication;
	}

	public ApplyDeltaAttributeMutation(@Nonnull String attributeName, @Nonnull T delta, @Nullable NumberRange requiredRangeAfterApplication) {
		super(new AttributeKey(attributeName));
		this.delta = delta;
		this.requiredRangeAfterApplication = requiredRangeAfterApplication;
	}

	public ApplyDeltaAttributeMutation(@Nonnull String attributeName, @Nullable Locale locale, @Nonnull T delta, @Nullable NumberRange requiredRangeAfterApplication) {
		super(new AttributeKey(attributeName, locale));
		this.delta = delta;
		this.requiredRangeAfterApplication = requiredRangeAfterApplication;
	}

	@Override
	@Nonnull
	public T getAttributeValue() {
		return delta;
	}

	@Nonnull
	@Override
	public AttributeValue mutateLocal(@Nonnull EntitySchemaContract entitySchema, @Nullable AttributeValue existingAttributeValue) {
		Assert.isTrue(
			existingAttributeValue != null && existingAttributeValue.exists() && existingAttributeValue.value() != null,
			"Cannot apply delta to attribute " + attributeKey.attributeName() + " when it doesn't exist!"
		);
		Assert.isTrue(
				existingAttributeValue.value() instanceof Number,
				"Cannot apply delta to attribute " + attributeKey.attributeName() + " when its value is " +
						existingAttributeValue.value().getClass().getName()
		);
		final Number existingValue = (Number) existingAttributeValue.value();
		final T newValue;
		if (existingValue instanceof BigDecimal) {
			//noinspection unchecked
			newValue = (T) ((BigDecimal) existingValue).add((BigDecimal) delta);
		} else if (existingValue instanceof Byte) {
			//noinspection unchecked
			newValue = (T) (Byte.valueOf((byte)((byte) existingValue + (byte) delta)));
		} else if (existingValue instanceof Short) {
			//noinspection unchecked
			newValue = (T) (Short.valueOf((short) ((short)existingValue + (short)delta)));
		} else if (existingValue instanceof Integer) {
			//noinspection unchecked
			newValue = (T) (Integer.valueOf(((int)existingValue + (int)delta)));
		} else if (existingValue instanceof Long) {
			//noinspection unchecked
			newValue = (T) (Long.valueOf(((long)existingValue + (long)delta)));
		} else {
			// this should never ever happen
			throw new InvalidMutationException("Unknown Evita data type: " + existingValue.getClass());
		}
		if (requiredRangeAfterApplication != null) {
			Assert.isTrue(
				requiredRangeAfterApplication.isWithin(newValue),
				() -> new InvalidMutationException(
					"Applying delta " + delta + " on " + existingValue + " produced result " + newValue +
						" which is out of specified range " + requiredRangeAfterApplication + "!"
				)
			);
		}
		return new AttributeValue(existingAttributeValue.version() + 1, attributeKey, newValue);
	}

	@Override
	public long getPriority() {
		return PRIORITY_UPSERT;
	}

	@Override
	public String toString() {
		return "apply delta " + delta + " to attribute `" + attributeKey + "`";
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy