package com.goodworkalan.addendum;
import static com.goodworkalan.addendum.Addendum.COLUMN_EXISTS;
import static com.goodworkalan.addendum.Addendum.*;
import com.goodworkalan.addendum.dialect.Column;
import com.goodworkalan.danger.Danger;
/**
* Builds an entity alteration that can change the underlying table name, alter
* properties, add new properties or drop properties.
*
* @author Alan Gutierrez
*/
public class AlterEntity {
/** The addendum builder to return when this builder terminates. */
private final Addendum addendum;
/** The database migration patch. */
private final Patch patch;
/** The entity to alter. */
private final Entity entity;
/**
* Create an alter table builder that alters the given entity.
*
* @param addendum
* The addendum builder to return when this builder terminates.
* @param entity
* The entity to alter.
* @param patch
* The database migration patch.
*/
AlterEntity(Addendum addendum, Entity entity, Patch patch) {
this.addendum = addendum;
this.entity = entity;
this.patch = patch;
}
/**
* Rename the underlying table.
*
* @param tableName
* The new table name.
* @return This alter entity builder to continue construction.
*/
public AlterEntity table(String tableName) {
patch.add(new TableRename(patch.schema.getEntityName(entity.tableName), entity.tableName, tableName));
return this;
}
/**
* Rename the entity independently of the table. This differs from the
* {@link Addendum#rename(String, String) Addendum.rename} method in that it
* <em>will not</em> also rename the underlying table if the underlying
* table has the name name.
*
* @param name
* The new entity name.
* @return This alter entity builder to continue construction.
*/
public AlterEntity name(String name) {
patch.schema.rename(patch.schema.getEntityName(entity.tableName), name);
return this;
}
/**
* Rename the given property. Returns a property rename builder to specify
* the new name.
*
* @param from
* The name of the property.
* @param to
* The name to rename the property to.
* @return A property rename builder.
*/
public AlterEntity rename(String from, String to) {
if (!entity.properties.containsKey(from)) {
throw new Danger(Addendum.class, PROPERTY_MISSING, from);
}
entity.rename(from, to);
Column renamed = entity.getColumn(to);
if (renamed.getName().equals(from)) {
patch.add(new ColumnAlteration(entity.tableName, renamed, to));
}
return this;
}
/**
* Sets the association between the given column name to the given property
* name, replacing the current column name to property name association. If
* the property name is already in use, and is not associated with the given
* column name, an exception is thrown. If the column name is not defined an
* exception is thrown.
* <p>
* This method is useful when first mapping a legacy database with SQL like
* names to Java object fields and bean properties.
*
* @param columnName
* The column name.
* @param propertyName
* The property name.
* @return This alter entity builder to continue construction.
* @exception Addendum
* If the property name is already in use or if the column
* name cannot be found.
*/
public AlterEntity alias(String columnName, String propertyName) {
String existingColumnName = entity.properties.get(propertyName);
if (existingColumnName == null) {
if (!entity.columns.containsKey(columnName)) {
throw new Danger(Addendum.class, COLUMN_MISSING, columnName);
}
entity.properties.remove(entity.getPropertyName(columnName));
entity.properties.put(propertyName, columnName);
} else if (!existingColumnName.equals(columnName)) {
throw new Danger(Addendum.class, PROPERTY_EXISTS, propertyName);
}
return this;
}
/**
* Add a new column to the table with the given name, the given column name,
* and given column type.
*
* @param name
* The property name.
* @param columnName
* The column name.
* @param columnType
* The <code>java.sql.Type</code> column type.
* @return An add column language element to define the column.
*/
public AddProperty add(String name, String columnName, int columnType) {
if (entity.properties.containsKey(name)) {
throw new Danger(Addendum.class, PROPERTY_EXISTS, name);
}
if (entity.columns.containsKey(columnName)) {
throw new Danger(Addendum.class, COLUMN_EXISTS, name);
}
Column column = new Column(name, columnType);
return new AddProperty(this, patch, entity.tableName, name, column);
}
/**
* Add a new column to the table with the given name
* and given column type. The property name is used for the column name.
*
* @param name
* The property name.
* @param columnType
* The <code>java.sql.Type</code> column type.
* @return An add column language element to define the column.
*/
public AddProperty add(String name, int columnType) {
return add(name, name, columnType);
}
/**
* Add a new column to the table with the given name, the given column name,
* and a column type appropriate for the given Java primitive.
*
* @param name
* The property name.
* @param columnName
* The column name.
* @param nativeType
* The native column type.
* @return An add column language element to define the column.
*/
public AddProperty add(String name, String columnName, Class<?> nativeType) {
return add(name, columnName, Column.getColumnType(nativeType));
}
/**
* Add a new column to the table with the given name and a column type
* appropriate for the given Java primitive. The property name is used for
* the column name.
*
* @param name
* The property name.
* @param nativeType
* The native column type.
* @return An add column language element to define the column.
*/
public AddProperty add(String name, Class<?> nativeType) {
return add(name, name, nativeType);
}
/**
* Begin an alter column statement to alter the column with the given name.
*
* @param property
* The name of the property to alter.
* @return An alter column language element to define the column changes.
*/
public AlterProperty alter(String property) {
return new AlterProperty(this, patch, entity, entity.getColumn(property));
}
/**
* Drop the property with the given property name. If the property does not
* exist in the entity, an exception is raised.
*
* @param property
* The property to drop.
* @return This alter entity builder to continue construction.
* @exception Addendum
* If the property does not exist.
*/
public AlterEntity drop(String property) {
patch.add(new ColumnDrop(entity.tableName, property));
return this;
}
/**
* Terminate the builder and return the parent alter table builder.
*
* @return The parent alter table builder to continue construction.
*/
public Addendum end () {
return addendum;
}
}