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

io.evitadb.api.requestResponse.data.ReferenceContract Maven / Gradle / Ivy

The 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;

import io.evitadb.api.query.require.EntityFetch;
import io.evitadb.api.query.require.EntityGroupFetch;
import io.evitadb.api.requestResponse.data.mutation.reference.ReferenceKey;
import io.evitadb.api.requestResponse.data.structure.Entity;
import io.evitadb.api.requestResponse.data.structure.EntityReference;
import io.evitadb.api.requestResponse.schema.AttributeSchemaContract;
import io.evitadb.api.requestResponse.schema.Cardinality;
import io.evitadb.api.requestResponse.schema.EvolutionMode;
import io.evitadb.api.requestResponse.schema.ReferenceSchemaContract;
import io.evitadb.dataType.EvitaDataTypes;
import io.evitadb.utils.MemoryMeasuringConstants;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;

/**
 * Contract for classes that allow reading information about references in {@link Entity} instance.
 *
 * @author Jan Novotný ([email protected]), FG Forrest a.s. (c) 2021
 */
public interface ReferenceContract extends AttributesContract, Droppable, Comparable, ContentComparator {

	/**
	 * Method allows to access unique and primary identifier of the ReferenceContract within {@link EntityContract}.
	 */
	@Nonnull
	ReferenceKey getReferenceKey();

	/**
	 * Returns name of the reference. The name always corresponds with {@link #getReferenceSchema()} name.
	 */
	@Nonnull
	default String getReferenceName() {
		return getReferenceKey().referenceName();
	}

	/**
	 * Returns primary key of the referenced (internal or external) entity.
	 */
	default int getReferencedPrimaryKey() {
		return getReferenceKey().primaryKey();
	}

	/**
	 * Returns body of the referenced entity in case its fetching was requested via {@link EntityFetch}
	 * constraint.
	 */
	@Nonnull
	Optional getReferencedEntity();

	/**
	 * Returns referenced entity type - conforming to {@link ReferenceSchemaContract#getReferencedEntityType()}.
	 */
	@Nonnull
	String getReferencedEntityType();

	/**
	 * Returns cardinality of the reference. The name always corresponds with {@link #getReferenceSchema()} cardinality.
	 */
	@Nonnull
	Cardinality getReferenceCardinality();

	/**
	 * Returns reference group. Group is composed of entity type and primary key of the referenced group entity.
	 * Group may or may not be Evita entity.
	 */
	@Nonnull
	Optional getGroup();

	/**
	 * Returns body of the referenced entity in case its fetching was requested via {@link EntityGroupFetch}
	 * constraint.
	 */
	@Nonnull
	Optional getGroupEntity();

	/**
	 * Returns schema that describes this type of reference.
	 * NULL can be returned in case schema hasn't yet known the reference type, but will be automatically created
	 * if {@link EvolutionMode#ADDING_REFERENCES} is allowed. So the NULL will be returned in very rare cases.
	 */
	@Nonnull
	Optional getReferenceSchema();

	/**
	 * Returns schema that describes this type of reference or throws an exception.
	 * NULL can be returned in case schema hasn't yet known the reference type, but will be automatically created
	 * if {@link EvolutionMode#ADDING_REFERENCES} is allowed. So the NULL will be returned in very rare cases.
	 */
	@Nonnull
	ReferenceSchemaContract getReferenceSchemaOrThrow();

	/**
	 * Referenced entity is a business key - we can compare according it.
	 */
	@Override
	default int compareTo(ReferenceContract o) {
		return getReferenceKey().compareTo(o.getReferenceKey());
	}

	/**
	 * Method returns gross estimation of the in-memory size of this instance. The estimation is expected not to be
	 * a precise one. Please use constants from {@link MemoryMeasuringConstants} for size computation.
	 */
	default int estimateSize() {
		return MemoryMeasuringConstants.OBJECT_HEADER_SIZE
			// version
			+ MemoryMeasuringConstants.INT_SIZE +
			// dropped
			+MemoryMeasuringConstants.BYTE_SIZE +
			// referenced entity
			+MemoryMeasuringConstants.REFERENCE_SIZE + getReferenceKey().estimateSize() +
			// group
			+MemoryMeasuringConstants.REFERENCE_SIZE + getGroup().stream().mapToInt(GroupEntityReference::estimateSize).sum() +
			// schema
			+MemoryMeasuringConstants.REFERENCE_SIZE;
	}

	/**
	 * Returns true if reference differs by any "business" related data from other reference.
	 */
	@Override
	default boolean differsFrom(@Nullable ReferenceContract otherReference) {
		if (otherReference == null) return true;
		if (!Objects.equals(getReferenceKey(), otherReference.getReferenceKey())) return true;
		if (getGroup().map(it -> it.differsFrom(otherReference.getGroup().orElse(null))).orElseGet(() -> otherReference.getGroup().isPresent()))
			return true;
		if (dropped() != otherReference.dropped()) return true;
		return AttributesContract.anyAttributeDifferBetween(this, otherReference);
	}

	/**
	 * This class envelopes reference to the reference group. It adds support for versioning and tombstone on top of basic
	 * {@link EntityReference} structure.
	 *
	 * @param referencedEntity reference to {@link Entity#getType()} of the referenced entity. Might be also any {@link String}
	 *                         that identifies type some external resource not maintained by Evita.
	 * @param primaryKey       reference to {@link Entity#getPrimaryKey()} of the referenced entity. Might be also any integer
	 *                         that uniquely identifies some external resource of type {@link #getType()} not maintained by Evita.
	 * @param version          contains version of this object and gets increased with any entity update. Allows to execute
	 *                         optimistic locking i.e. avoiding parallel modifications.
	 * @param dropped          contains TRUE if reference group reference was dropped - i.e. removed. Such reference is not removed (unless
	 *                         tidying process does it), but are lying in reference with tombstone flag. Dropped reference
	 *                         can be overwritten by a new value continuing with the versioning where it was stopped for the last time.
	 */
	record GroupEntityReference(@Nonnull String referencedEntity, int primaryKey, int version, boolean dropped)
		implements EntityReferenceContract, Droppable, Serializable, ContentComparator {
		@Serial private static final long serialVersionUID = 7432447904441796055L;

		@Nonnull
		@Override
		public String getType() {
			return referencedEntity;
		}

		@Nonnull
		@Override
		public Integer getPrimaryKey() {
			return primaryKey;
		}

		@Override
		public boolean dropped() {
			return dropped;
		}

		@Override
		public int version() {
			return version;
		}

		@Override
		public int compareTo(@Nonnull GroupEntityReference o) {
			return compareReferenceContract(o);
		}

		/**
		 * Returns true if reference group differs by any "business" related data from other reference group.
		 */
		@Override
		public boolean differsFrom(@Nullable GroupEntityReference otherReferenceGroup) {
			if (otherReferenceGroup == null) {
				return true;
			}
			if (!Objects.equals(primaryKey, otherReferenceGroup.primaryKey())) {
				return true;
			}
			return dropped != otherReferenceGroup.dropped();
		}

		public int estimateSize() {
			return MemoryMeasuringConstants.OBJECT_HEADER_SIZE +
				// type
				EvitaDataTypes.estimateSize(referencedEntity) +
				// primary key
				MemoryMeasuringConstants.INT_SIZE +
				//version
				MemoryMeasuringConstants.INT_SIZE +
				// dropped
				MemoryMeasuringConstants.BYTE_SIZE;
		}

		@Override
		public String toString() {
			return (dropped ? "❌ " : "") +
				"`" + referencedEntity + "`" + " with key " + getPrimaryKey();
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy