/*
Copyright (c) 2011 James Ahlborn
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
*/
package com.healthmarketscience.sqlbuilder;
import java.io.IOException;
import java.util.List;
import com.healthmarketscience.common.util.AppendableExt;
import com.healthmarketscience.sqlbuilder.dbspec.Column;
import com.healthmarketscience.sqlbuilder.dbspec.Constraint;
import com.healthmarketscience.sqlbuilder.dbspec.ForeignKeyConstraint;
/**
* Outputs a table or column constraint clause (depending on the current
* context) <code>[ CONSTRAINT <name> ] <type> [ (<col1> ...) ]</code>.
*
* @author James Ahlborn
*/
public class ConstraintClause extends SqlObject
{
/**
* Enum representing the types of constraints supported for a column or
* table.
*/
public enum Type
{
NOT_NULL("NOT NULL"),
UNIQUE("UNIQUE"),
PRIMARY_KEY("PRIMARY KEY"),
FOREIGN_KEY("FOREIGN KEY", "REFERENCES");
private final String _tableTypeStr;
private final String _colTypeStr;
private Type(String colTypeStr) {
this(colTypeStr, colTypeStr);
}
private Type(String tableTypeStr, String colTypeStr) {
_tableTypeStr = tableTypeStr;
_colTypeStr = colTypeStr;
}
public String toString(boolean forTable) {
return (forTable ? _tableTypeStr : _colTypeStr);
}
}
protected final Type _type;
protected final SqlObject _name;
protected SqlObjectList<SqlObject> _columns = SqlObjectList.create();
public ConstraintClause(Constraint constraint) {
this(getType(constraint.getType()), constraint, constraint.getColumns());
}
public ConstraintClause(Type type, Object name) {
this(type, name, null);
}
protected ConstraintClause(Type type, Object name, List<?> columns) {
_type = type;
_name = Converter.toCustomConstraintSqlObject(name);
_columns.addObjects(Converter.CUSTOM_COLUMN_TO_OBJ, columns);
}
/**
* Adds a column to the constraint definition.
*/
public ConstraintClause addColumns(Column... columns) {
return addCustomColumns((Object[])columns);
}
/**
* Adds a custom column to the constraint definition.
* <p>
* {@code Object} -> {@code SqlObject} conversions handled by
* {@link Converter#CUSTOM_COLUMN_TO_OBJ}.
*/
public ConstraintClause addCustomColumns(Object... columnStrs) {
_columns.addObjects(Converter.CUSTOM_COLUMN_TO_OBJ, columnStrs);
return this;
}
@Override
protected void collectSchemaObjects(ValidationContext vContext) {
if(_name != null) {
_name.collectSchemaObjects(vContext);
}
_columns.collectSchemaObjects(vContext);
}
@Override
public void appendTo(AppendableExt app) throws IOException {
if(_name != null) {
app.append(_name);
}
boolean forTable = SqlContext.getContext(app).getUseTableConstraints();
app.append(_type.toString(forTable));
if(forTable && !_columns.isEmpty()) {
app.append(" (").append(_columns).append(")");
}
}
/**
* Returns the appropriate {@link Type} for the given
* {@link Constraint#Type}.
*/
private static Type getType(Constraint.Type consType) {
switch(consType) {
case NOT_NULL:
return Type.NOT_NULL;
case UNIQUE:
return Type.UNIQUE;
case PRIMARY_KEY:
return Type.PRIMARY_KEY;
case FOREIGN_KEY:
return Type.FOREIGN_KEY;
default:
throw new RuntimeException("Unexpected constraint type " + consType);
}
}
/**
* Returns the appropriately configured ConstraintClause (or
* ForeignKeyConstraintClause) for the given Constraint.
*/
public static ConstraintClause from(Constraint cons) {
if(cons.getType() == Constraint.Type.FOREIGN_KEY) {
return new ForeignKeyConstraintClause((ForeignKeyConstraint)cons);
}
return new ConstraintClause(cons);
}
/**
* Convenience method for generating an unnamed not null constraint.
*/
public static ConstraintClause notNull() {
return notNull(null);
}
/**
* Convenience method for generating a not null constraint with the given
* name.
* @param name name of the constraint, may be {@code null}
*/
public static ConstraintClause notNull(Object name) {
return new ConstraintClause(Type.NOT_NULL, name);
}
/**
* Convenience method for generating an unnamed unique constraint.
*/
public static ConstraintClause unique() {
return unique(null);
}
/**
* Convenience method for generating a unique constraint with the given
* name.
* @param name name of the constraint, may be {@code null}
*/
public static ConstraintClause unique(Object name) {
return new ConstraintClause(Type.UNIQUE, name);
}
/**
* Convenience method for generating an unnamed primary key constraint.
*/
public static ConstraintClause primaryKey() {
return primaryKey(null);
}
/**
* Convenience method for generating a primary key constraint with the given
* name.
* @param name name of the constraint, may be {@code null}
*/
public static ConstraintClause primaryKey(Object name) {
return new ConstraintClause(Type.PRIMARY_KEY, name);
}
/**
* Convenience method for generating an unnamed foreign key constraint.
*/
public static ForeignKeyConstraintClause foreignKey(Object refTableStr) {
return foreignKey(null, refTableStr);
}
/**
* Convenience method for generating a foreign key constraint with the given
* name.
* @param name name of the constraint, may be {@code null}
* @param refTableStr the table referenced by this constraint
*/
public static ForeignKeyConstraintClause foreignKey(Object name,
Object refTableStr) {
return new ForeignKeyConstraintClause(name, refTableStr);
}
/**
* Wrapper around the constraint name which generates the appropriate
* constraint clause prefix.
*/
static class Prefix extends SqlObject
{
private SqlObject _name;
Prefix(SqlObject name) {
_name = name;
}
@Override
protected void collectSchemaObjects(ValidationContext vContext) {
_name.collectSchemaObjects(vContext);
}
@Override
public void appendTo(AppendableExt app) throws IOException {
app.append("CONSTRAINT ").append(_name).append(" ");
}
}
}