io.evitadb.api.EvitaContract Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of evita_api Show documentation
Show all versions of evita_api Show documentation
Module contains external API of the evitaDB.
The newest version!
/*
*
* _ _ ____ ____
* _____ _(_) |_ __ _| _ \| __ )
* / _ \ \ / / | __/ _` | | | | _ \
* | __/\ V /| | || (_| | |_| | |_) |
* \___| \_/ |_|\__\__,_|____/|____/
*
* Copyright (c) 2023-2024
*
* 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;
import io.evitadb.api.SessionTraits.SessionFlags;
import io.evitadb.api.TransactionContract.CommitBehavior;
import io.evitadb.api.exception.CatalogAlreadyPresentException;
import io.evitadb.api.exception.InstanceTerminatedException;
import io.evitadb.api.exception.TransactionException;
import io.evitadb.api.requestResponse.schema.CatalogSchemaEditor.CatalogSchemaBuilder;
import io.evitadb.api.requestResponse.schema.SealedCatalogSchema;
import io.evitadb.api.requestResponse.schema.mutation.TopLevelCatalogSchemaMutation;
import io.evitadb.exception.EvitaInternalError;
import io.evitadb.exception.EvitaInvalidUsageException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Evita is a specialized database with easy-to-use API for e-commerce systems. Purpose of this research is creating a fast
* and scalable engine that handles all complex tasks that e-commerce systems has to deal with on a daily basis. Evita should
* operate as a fast secondary lookup / search index used by application frontends. We aim for order of magnitude better
* latency (10x faster or better) for common e-commerce tasks than other solutions based on SQL or NoSQL databases on the
* same hardware specification. Evita should not be used for storing and handling primary data, and we don't aim for ACID
* properties nor data corruption guarantees. Evita "index" must be treated as something that could be dropped any time and
* built up from scratch easily again.
*
* This interface represents the main entrance to the evitaDB contents.
* Evita contract is thread safe.
*
* @author Jan Novotný ([email protected]), FG Forrest a.s. (c) 2021
*/
@ThreadSafe
public interface EvitaContract extends AutoCloseable {
/**
* Returns true if the Evita instance is active and ready to serve requests - i.e. method {@link #close()} has not
* been called yet.
*
* @return true if the Evita instance is active
*/
boolean isActive();
/**
* Creates {@link EvitaSessionContract} for querying the database.
*
* Remember to {@link #close()} or {@link #terminateSession(EvitaSessionContract)} when your work with Evita is finished.
* EvitaSession is not thread safe!
*
* @param catalogName - unique name of the catalog, refers to {@link CatalogContract#getName()}
* @return new instance of EvitaSession
* @see #close()
* @see #createSession(SessionTraits) for complete configuration options.
*/
@Nonnull
default EvitaSessionContract createReadOnlySession(@Nonnull String catalogName) {
return createSession(new SessionTraits(catalogName));
}
/**
* Creates {@link EvitaSessionContract} for querying and altering the database.
*
* Remember to {@link #close()} or {@link #terminateSession(EvitaSessionContract)} when your work with Evita is finished.
* EvitaSession is not thread safe!
*
* @param catalogName - unique name of the catalog, refers to {@link CatalogContract#getName()}
* @return new instance of EvitaSession
* @see #close()
* @see #createSession(SessionTraits) for complete configuration options.
*/
@Nonnull
default EvitaSessionContract createReadWriteSession(@Nonnull String catalogName) {
return createSession(new SessionTraits(catalogName, SessionFlags.READ_WRITE));
}
/**
* Creates {@link EvitaSessionContract} for querying the database. This is the most versatile method for initializing a new
* session allowing to pass all configurable options in `traits` argument.
*
* Remember to {@link #close()} or {@link #terminateSession(EvitaSessionContract)} when your work with Evita is finished.
* EvitaSession is not thread safe!
*
* @return new instance of EvitaSession
* @see #close()
*/
@Nonnull
EvitaSessionContract createSession(@Nonnull SessionTraits traits);
/**
* Method returns active session by its unique id or NULL if such session is not found.
*/
@Nonnull
Optional getSessionById(@Nonnull UUID uuid);
/**
* Terminates existing {@link EvitaSessionContract}. When this method is called no additional calls to this EvitaSession
* is accepted and all will terminate with {@link InstanceTerminatedException}.
*/
void terminateSession(@Nonnull EvitaSessionContract session);
/**
* Returns complete listing of all catalogs known to the Evita instance.
*/
@Nonnull
Set getCatalogNames();
/**
* Creates new catalog of particular name if it doesn't exist. The schema of the catalog (should it was created or
* not) is returned to the response.
*
* @param catalogName name of the catalog
* @return new instance of {@link SealedCatalogSchema} connected with the catalog
*/
@Nonnull
CatalogSchemaBuilder defineCatalog(@Nonnull String catalogName);
/**
* Renames existing catalog to a new name. The `newCatalogName` must not clash with any existing catalog name,
* otherwise exception is thrown. If you need to rename catalog to a name of existing catalog use
* the {@link #replaceCatalog(String, String)} method instead.
*
* In case exception occurs the original catalog (`catalogName`) is guaranteed to be untouched,
* and the `newCatalogName` will not be present.
*
* @param catalogName name of the catalog that will be renamed
* @param newCatalogName new name of the catalog
* @throws CatalogAlreadyPresentException when another catalog with `newCatalogName` already exists
*/
void renameCatalog(@Nonnull String catalogName, @Nonnull String newCatalogName)
throws CatalogAlreadyPresentException;
/**
* Replaces existing catalog of particular with the contents of the another catalog. When this method is
* successfully finished, the catalog `catalogNameToBeReplacedWith` will be known under the name of the
* `catalogNameToBeReplaced` and the original contents of the `catalogNameToBeReplaced` will be purged entirely.
*
* In case exception occurs, the original catalog (`catalogNameToBeReplaced`) is guaranteed to be untouched, the
* state of `catalogNameToBeReplacedWith` is however unknown and should be treated as damaged.
*
* @param catalogNameToBeReplacedWith name of the catalog that will become the successor of the original catalog (old name)
* @param catalogNameToBeReplaced name of the catalog that will be replaced and dropped (new name)
*/
void replaceCatalog(@Nonnull String catalogNameToBeReplacedWith, @Nonnull String catalogNameToBeReplaced);
/**
* Deletes catalog with name `catalogName` along with its contents on disk.
*
* @param catalogName name of the removed catalog
* @return true if catalog was found in Evita and its contents were successfully removed
*/
boolean deleteCatalogIfExists(@Nonnull String catalogName);
/**
* Applies catalog mutation affecting entire catalog.
* The reason why we use mutations for this is to be able to include those operations to the WAL that is
* synchronized to replicas.
*/
void update(@Nonnull TopLevelCatalogSchemaMutation... catalogMutations);
/**
* Executes querying logic in the newly created Evita session. Session is safely closed at the end of this method
* and result is returned.
*
* Query logic is intended to be read-only. For read-write logic use {@link #updateCatalog(String, Function, SessionFlags[]))} or
* open a transaction manually in the logic itself.
*/
T queryCatalog(
@Nonnull String catalogName,
@Nonnull Function queryLogic,
@Nullable SessionFlags... flags
);
/**
* Executes querying logic in the newly created Evita session. Session is safely closed at the end of this method
* and result is returned.
*
* Query logic is intended to be read-only. For read-write logic use {@link #updateCatalog(String, Consumer, SessionFlags[]))} or
* open a transaction manually in the logic itself.
*/
void queryCatalog(
@Nonnull String catalogName,
@Nonnull Consumer queryLogic,
@Nullable SessionFlags... flags
);
/**
* Executes querying logic in the newly created Evita session. Session is safely closed at the end of this method
* and result is returned.
*
* Query logic is intended to be read-only. For read-write logic use {@link #updateCatalog(String, Function, SessionFlags[]))} or
* open a transaction manually in the logic itself.
*
* This is asynchronous variant of {@link #queryCatalog(String, Function, SessionFlags...)} that immediately returns
* a future that is completed when the query finishes.
*
* @return future that is completed when the query finishes
*/
@Nonnull
CompletableFuture queryCatalogAsync(
@Nonnull String catalogName,
@Nonnull Function queryLogic,
@Nullable SessionFlags... flags
);
/**
* Executes catalog read-write logic in the newly Evita session. When logic finishes without exception, changes are
* committed to the index, otherwise changes are roll-backed and no data is affected. Changes made by the updating
* logic are visible only within update function. Other threads outside the logic function work with non-changed
* data until transaction is committed to the index.
*
* Current version limitation:
* Only single updater can execute in parallel (i.e. updates are expected to be invoked by single thread in serial way).
*
* @param catalogName name of the catalog
* @param updater application logic that reads and writes data
* @param flags optional flags that can be passed to the session and affect its behavior
*/
default T updateCatalog(@Nonnull String catalogName, @Nonnull Function updater, @Nullable SessionFlags... flags) {
return updateCatalog(catalogName, updater, CommitBehavior.defaultBehaviour(), flags);
}
/**
* Overloaded method {@link #updateCatalog(String, Function, SessionFlags[])} that returns no result.
*
* @see #updateCatalog(String, Function, SessionFlags[])
*/
default void updateCatalog(@Nonnull String catalogName, @Nonnull Consumer updater, @Nullable SessionFlags... flags) {
updateCatalog(catalogName, updater, CommitBehavior.defaultBehaviour(), flags);
}
/**
* Executes catalog read-write logic in the newly Evita session. When logic finishes without exception, changes are
* committed to the index, otherwise changes are roll-backed and no data is affected. Changes made by the updating
* logic are visible only within update function. Other threads outside the logic function work with non-changed
* data until transaction is committed to the index.
*
* This method blocks indefinitely until the transaction reaches the processing stage defined by
* the `commitBehaviour` argument. If you want to have waiting under the control, use
* {@link #updateCatalogAsync(String, Function, CommitBehavior, SessionFlags...)} alternative.
*
* @param catalogName name of the catalog
* @param updater application logic that reads and writes data
* @param commitBehaviour defines when the transaction is considered to be finished
* @param flags optional flags that can be passed to the session and affect its behavior
* @return result of the updater function
*/
default T updateCatalog(
@Nonnull String catalogName,
@Nonnull Function updater,
@Nonnull CommitBehavior commitBehaviour,
@Nullable SessionFlags... flags
) {
try {
return updateCatalogAsync(catalogName, updater, commitBehaviour, flags).join();
} catch (EvitaInvalidUsageException | EvitaInternalError e) {
throw e;
} catch (Exception e) {
if (e.getCause() instanceof EvitaInvalidUsageException invalidUsageException) {
throw invalidUsageException;
} else if (e.getCause() instanceof EvitaInternalError internalError) {
throw internalError;
} else {
throw new TransactionException("The transaction was rolled back.", e.getCause());
}
}
}
/**
* Executes catalog read-write logic in the newly Evita session. When logic finishes without exception, changes are
* committed to the index, otherwise changes are roll-backed and no data is affected. Changes made by the updating
* logic are visible only within update function. Other threads outside the logic function work with non-changed
* data until transaction is committed to the index.
*
* Method returns future that is completed when the transaction reaches the processing stage defined by
* the `commitBehaviour` argument.
*
* @param catalogName name of the catalog
* @param updater application logic that reads and writes data
* @param commitBehaviour defines when the transaction is considered to be finished
* @param flags optional flags that can be passed to the session and affect its behavior
* @return future that is completed when the transaction reaches the processing stage defined by the `commitBehaviour`
*/
@Nonnull
CompletableFuture updateCatalogAsync(
@Nonnull String catalogName,
@Nonnull Function updater,
@Nonnull CommitBehavior commitBehaviour,
@Nullable SessionFlags... flags
);
/**
* Overloaded method {@link #updateCatalog(String, Function, SessionFlags[])} that returns no result. This method
* blocks indefinitely until the transaction reaches the processing stage defined by the `commitBehaviour` argument.
* If you want to have waiting under the control, use {@link #updateCatalogAsync(String, Consumer, CommitBehavior, SessionFlags...)}
* alternative.
*
* @see #updateCatalog(String, Function, CommitBehavior, SessionFlags[])
*/
default void updateCatalog(
@Nonnull String catalogName,
@Nonnull Consumer updater,
@Nonnull CommitBehavior commitBehaviour,
@Nullable SessionFlags... flags
) {
try {
updateCatalogAsync(catalogName, updater, commitBehaviour, flags).join();
} catch (EvitaInvalidUsageException | EvitaInternalError e) {
throw e;
} catch (Exception e) {
if (e.getCause() instanceof EvitaInvalidUsageException invalidUsageException) {
throw invalidUsageException;
} else if (e.getCause() instanceof EvitaInternalError internalError) {
throw internalError;
} else {
throw new TransactionException("The transaction was rolled back.", e.getCause());
}
}
}
/**
* Overloaded method {@link #updateCatalogAsync(String, Function, CommitBehavior, SessionFlags...)} that returns
* future that is completed when the transaction reaches the processing stage defined by the `commitBehaviour`
* argument.
*
* @return future that is completed when the transaction reaches the processing stage defined by the `commitBehaviour`
* argument. Long represents catalog version where the transaction changes will be visible.
* @throws TransactionException when transaction fails
* @see #updateCatalog(String, Function, CommitBehavior, SessionFlags[])
*/
@Nonnull
CompletableFuture updateCatalogAsync(
@Nonnull String catalogName,
@Nonnull Consumer updater,
@Nonnull CommitBehavior commitBehaviour,
@Nullable SessionFlags... flags
)
throws TransactionException;
/**
* Returns management service that allows to execute various management tasks on the Evita instance and retrieve
* global evitaDB information. These operations might require special permissions for execution and are not used
* daily and therefore are segregated into special management class.
*
* @return management service
*/
@Nonnull
EvitaManagementContract management();
}