IdentifierPolicy.java
package org.codefilarete.stalactite.dsl.idpolicy;
import java.sql.PreparedStatement;
import java.util.function.Consumer;
import java.util.function.Function;
import org.codefilarete.stalactite.mapping.id.manager.IdentifierInsertionManager;
import org.codefilarete.stalactite.mapping.id.sequence.DatabaseSequenceSettings;
import org.codefilarete.stalactite.mapping.id.sequence.hilo.PooledHiLoSequence;
import org.codefilarete.stalactite.mapping.id.sequence.hilo.PooledHiLoSequenceStorageOptions;
import org.codefilarete.tool.function.Sequence;
/**
* Available identifier policies for entities.
*
* @see IdentifierInsertionManager
*/
@SuppressWarnings("java:S2326" /* Unused generics is necessary to caller signature (mapKey) to make policy identifier type match entity identifier one */)
public interface IdentifierPolicy<ID> {
/**
* Policy for entities that have their id given by the database after insert, such as increment column, implying that generated values can be
* read through {@link PreparedStatement#getGeneratedKeys()}
*
* @return a new policy that will be used to get the identifier value
*/
static <I> GeneratedKeysPolicy<I> databaseAutoIncrement() {
return new GeneratedKeysPolicySupport<>();
}
/**
* Policy for entities that want their id fixed just before insert which value is given by a {@link Sequence}.
* Reader may be interested in {@link PooledHiLoSequence}.
* Sequence data will be stored as specified through {@link PooledHiLoSequenceStorageOptions#DEFAULT}
*
* @return a new policy that will be used to get the identifier value
* @see #pooledHiLoSequence(PooledHiLoSequenceStorageOptions)
*/
static BeforeInsertIdentifierPolicy<Long> pooledHiLoSequence() {
return new PooledHiLoSequenceIdentifierPolicySupport();
}
/**
* Policy for entities that want their id fixed just before insert which value is given by a {@link Sequence}.
* Reader may be interested in {@link PooledHiLoSequence}.
*
* @param sequenceStorageOptions the options about table to store sequence data
* @return a new policy that will be used to get the identifier value
* @see PooledHiLoSequenceStorageOptions#DEFAULT
* @see PooledHiLoSequenceStorageOptions#HIBERNATE_DEFAULT
*/
static BeforeInsertIdentifierPolicy<Long> pooledHiLoSequence(PooledHiLoSequenceStorageOptions sequenceStorageOptions) {
return new PooledHiLoSequenceIdentifierPolicySupport(sequenceStorageOptions);
}
static BeforeInsertIdentifierPolicy<Long> databaseSequence(DatabaseSequenceNamingStrategy namingStrategy) {
return new DatabaseSequenceIdentifierPolicySupport(namingStrategy);
}
static BeforeInsertIdentifierPolicy<Long> databaseSequence(String name) {
return new DatabaseSequenceIdentifierPolicySupport(entityType -> name);
}
static BeforeInsertIdentifierPolicy<Long> databaseSequence(DatabaseSequenceNamingStrategy namingStrategy, DatabaseSequenceSettings databaseSequenceSettings) {
return new DatabaseSequenceIdentifierPolicySupport(namingStrategy, databaseSequenceSettings);
}
static BeforeInsertIdentifierPolicy<Long> databaseSequence(String name, DatabaseSequenceSettings databaseSequenceSettings) {
return new DatabaseSequenceIdentifierPolicySupport(entityType -> name, databaseSequenceSettings);
}
/**
* Policy for entities that want their id fixed just before insert which value is given by a {@link Sequence}.
* Be aware that the given sequence will be shared across all managed entities, meaning that, for instance,
* if it is a long sequence, an integer value can't be found twice in whole entities.
* Reader may be interested in other {@link #pooledHiLoSequence()} methods to avoid such sharing behavior.
*
* @param sequence the {@link Sequence} to ask for identifier value
* @param <I> identifier type
* @return a new policy that will be used to get the identifier value
*/
static <I> BeforeInsertIdentifierPolicy<I> pooledHiLoSequence(Sequence<I> sequence) {
return new BeforeInsertIdentifierPolicySupport<>(sequence);
}
/**
* Policy for entities that have their id already fixed and doesn't require the persistence engine to generate an identifier for them.
* Meanwhile, this policy has a trade-off on persist(..) operation: without knowing how to determine if
* entities are new or not, a database round-trip must be performed to get the ones already present in the database
* and then choose to update them, not insert them. This round-trip may impact performances. That's why it is
* preferable to use {@link #alreadyAssigned(Consumer, Function)} to provide a way to get the state of the entities.
*
* @param <C> entity type
* @param <I> identifier type
* @return a new policy that will be used to know the persistent state of entities
*/
static <C, I> AlreadyAssignedIdentifierPolicy<C, I> alreadyAssigned() {
return IdentifierPolicy.alreadyAssigned(null, null);
}
/**
* Policy for entities that have their id already fixed and doesn't require the persistence engine to generate an identifier for them.
* Meanwhile, this policy requires those instances to be capable of being marked as persisted (after insert to prevent the engine from
* trying to persist again an already persisted instance, for example). A basic implementation can be a boolean switch on entity.
*
* @param markAsPersistedFunction the {@link Consumer} that allows marking the entity as "inserted in database"
* @param isPersistedFunction the {@link Function} that allows knowing if entity was already inserted in database
* @param <C> entity type
* @param <I> identifier type
* @return a new policy that will be used to know the persistent state of entities
*/
static <C, I> AlreadyAssignedIdentifierPolicy<C, I> alreadyAssigned(Consumer<C> markAsPersistedFunction,
Function<C, Boolean> isPersistedFunction) {
return new AlreadyAssignedIdentifierPolicySupport<>(markAsPersistedFunction, isPersistedFunction);
}
}