
org.fastnate.generator.context.GeneratedIdProperty Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fastnate-generator Show documentation
Show all versions of fastnate-generator Show documentation
The Fastnate Offline SQL Generator
The newest version!
package org.fastnate.generator.context;
import java.io.IOException;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.fastnate.generator.statements.ColumnExpression;
import org.fastnate.generator.statements.PrimitiveColumnExpression;
import org.fastnate.generator.statements.StatementsWriter;
import org.fastnate.generator.statements.TableStatement;
import org.fastnate.util.ClassUtil;
import lombok.Getter;
/**
* Describes an {@link Id} property of an {@link EntityClass}.
*
* @author Tobias Liefke
* @param
* The type of the container class
* @param
* The type of the property
*/
@Getter
public class GeneratedIdProperty extends PrimitiveProperty {
/** Shortcut for the inverse of {@link GeneratorContext#isWriteRelativeIds()}. */
private final boolean absoluteIds;
/** Indicates that the ID is never "null", because we have a primitive ID value. */
private final boolean primitive;
/** The entity class that contains our property. */
private final EntityClass entityClass;
/** The type of the numbers. */
private final Class type;
/** Marker for the ID of an entity which needs to be referenced by its unique properties. */
private final T unknownIdMarker;
/** The generator used for generating new values of this property. */
private final IdGenerator generator;
/**
* Creates a new instance of {@link GeneratedIdProperty}.
*
* @param entityClass
* the entity class
* @param attribute
* the accessor of the id attribute
* @param column
* the column annotation
*/
public GeneratedIdProperty(final EntityClass entityClass, final AttributeAccessor attribute,
final Column column) {
super(entityClass.getContext(), entityClass.getTable(), attribute, column,
entityClass.getContext().isWriteRelativeIds()
|| !entityClass.getContext().getDialect().isSettingIdentityAllowed());
this.entityClass = entityClass;
this.absoluteIds = !getColumn().isAutoGenerated();
this.type = (Class) attribute.getType();
this.unknownIdMarker = ClassUtil.convertNumber(-1, this.type);
this.primitive = this.type.isPrimitive();
this.generator = entityClass.getContext().getGenerator(attribute.getAnnotation(GeneratedValue.class),
getTable(), getColumn());
}
@Override
public void addInsertExpression(final TableStatement statement, final E entity) {
ensureIsNew(entity);
if (this.absoluteIds) {
// If we generate explict IDs, lets do that now
final T id = this.generator.createNextValue(this.type);
setValue(entity, id);
statement.setColumnValue(getColumn(), PrimitiveColumnExpression.create(id, getDialect()));
} else if (!this.generator.isPostIncrement()) {
final T id = this.generator.createNextValue(this.type);
setValue(entity, id);
this.generator.addNextValue(statement, getColumn(), id);
}
}
@Override
public void createPreInsertStatements(final StatementsWriter writer, final E entity) throws IOException {
if (!this.absoluteIds) {
this.generator.createPreInsertStatements(writer);
}
}
private void ensureIsNew(final E entity) {
if (!isNew(entity)) {
throw new IllegalArgumentException("Tried to create entity twice: " + entity);
}
}
/**
* Creates the reference of an entity in SQL using its (relative or absolute) id.
*
* @param entity
* the entity
* @param whereExpression
* indicates that the reference is used in a "where" statement
* @return the expression for the ID of that entity or {@code null} if the entity was not written up to now
* @throws IllegalArgumentException
* if the entity is a {@link #isReference(Object) reference} without any id
*/
@Override
public ColumnExpression getExpression(final E entity, final boolean whereExpression) {
final Number targetId = getValue(entity);
if (targetId == null) {
return null;
}
if (targetId == this.unknownIdMarker) {
throw new IllegalArgumentException("Entity must be referenced by an unique property: " + entity);
}
if (targetId.longValue() < 0) {
return PrimitiveColumnExpression.create(-1 - 1 - targetId.longValue(), getDialect());
}
if (this.absoluteIds) {
return PrimitiveColumnExpression.create(targetId, getDialect());
}
return this.generator.getExpression(getTable(), getColumn(), targetId, whereExpression);
}
/**
* Indicates that the given entity needs to be written.
*
* @param entity
* the entity to check
* @return {@code true} if the id of the given entity is not set up to now
*/
public boolean isNew(final E entity) {
final Number id = getValue(entity);
return id == null || this.primitive && id.longValue() == 0;
}
/**
* Indicates that the given entity was not written before, but exists already in the database.
*
* @param entity
* the entity to check
* @return {@code true} if the entity was {@link #markReference(Object) marked as reference}
*/
public boolean isReference(final E entity) {
final Number id = getValue(entity);
return id != null && id.longValue() < 0;
}
/**
* Marks an entity as reference, where we don't know the ID database.
*
* A reference is not written during SQL generation, because it exists already in the database when the script is
* executed. As we don't know the ID during build time we have to reference it using some unique properties.
*
* @param entity
* the entity to mark
*/
public void markReference(final E entity) {
if (isNew(entity)) {
setValue(entity, this.unknownIdMarker);
}
}
/**
* Marks an entity as reference, where we know the id in the database.
*
* A reference is not written during SQL generation, because it exists already in the database when the script is
* executed.
*
* @param entity
* the entity to mark
* @param id
* the id of the entity in the database
*/
public void markReference(final E entity, final T id) {
if (isNew(entity)) {
setValue(entity, ClassUtil.convertNumber(Long.valueOf(-1 - 1 - id.longValue()), this.type));
}
}
/**
* Called after the insert statement was written, to update any nessecary state in the context.
*
* @param entity
* the current entity
*/
public void postInsert(final E entity) {
if (!this.absoluteIds && this.generator.isPostIncrement()) {
// We have an identity column -> the database increments the ID after the insert
setValue(entity, this.generator.createNextValue(this.type));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy