/* Copyright (c) 2008 Health Market Science, Inc. 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 You can contact Health Market Science at info@healthmarketscience.com or at the following address: Health Market Science 2700 Horizon Drive Suite 200 King of Prussia, PA 19406 */ package com.healthmarketscience.sqlbuilder; import java.io.IOException; import java.util.ListIterator; import com.healthmarketscience.common.util.AppendableExt; import com.healthmarketscience.sqlbuilder.dbspec.Column; import com.healthmarketscience.sqlbuilder.dbspec.Constraint; import com.healthmarketscience.sqlbuilder.dbspec.Table; /** * Query which generates a CREATE TABLE statement. * * @author James Ahlborn */ public class CreateTableQuery extends BaseCreateQuery<CreateTableQuery> { /** column level constraints * @deprecated use {@link ConstraintClause} instead */ @Deprecated public enum ColumnConstraint { NOT_NULL("NOT NULL"), UNIQUE("UNIQUE"), PRIMARY_KEY("PRIMARY KEY"); private final String _constraintClause; private ColumnConstraint(String constraintClause) { _constraintClause = constraintClause; } @Override public String toString() { return _constraintClause; } } protected SqlObjectList<SqlObject> _constraints = SqlObjectList.create(); public CreateTableQuery(Table table) { this(table, false); } /** * {@code Column} -> {@code SqlObject} conversions handled by * {@link Converter#TYPED_COLUMN_TO_OBJ}. * * @param table the table to create * @param includeColumns iff <code>true</code>, all the columns and * constraints of this table will be added to the * query */ public CreateTableQuery(Table table, boolean includeColumns) { this((Object)table); if(includeColumns) { // add all the columns for this table _columns.addObjects(Converter.TYPED_COLUMN_TO_OBJ, table.getColumns()); // add all the constraints for this table _constraints.addObjects(Converter.CUSTOM_TO_CONSTRAINTCLAUSE, table.getConstraints()); } } /** * {@code Object} -> {@code SqlObject} conversions handled by * {@link Converter#toCustomTableSqlObject(Object)}. */ public CreateTableQuery(Object tableStr) { super(Converter.toCustomTableSqlObject(tableStr)); } /** * @return a DropQuery for the object which would be created by this create * query. */ @Override public DropQuery getDropQuery() { return new DropQuery(DropQuery.Type.TABLE, _object); } /** * Adds the given Objects as column descriptions, should look like * <code>"<column> <type> [<constraint> ... ]"</code>. * <p> * {@code Object} -> {@code SqlObject} conversions handled by * {@link Converter#TYPED_COLUMN_TO_OBJ}. */ @Override public CreateTableQuery addCustomColumns(Object... typedColumnStrs) { _columns.addObjects(Converter.TYPED_COLUMN_TO_OBJ, typedColumnStrs); return this; } /** * Adds column description for the given Column along with the given column * constraint. * @deprecated use {@link ConstraintClause} instead of ColumnConstraint */ @Deprecated public CreateTableQuery addColumn(Column column, ColumnConstraint constraint) { return addCustomColumn(column, constraint); } /** * Adds given Object as column description along with the given column * constraint. * <p> * {@code Object} -> {@code SqlObject} conversions handled by * {@link Converter#TYPED_COLUMN_TO_OBJ}. * @deprecated use {@link ConstraintClause} instead of ColumnConstraint */ @Deprecated public CreateTableQuery addCustomColumn(Object columnStr, ColumnConstraint constraint) { SqlObject column = Converter.TYPED_COLUMN_TO_OBJ.convert(columnStr); if(column instanceof TypedColumnObject) { ((TypedColumnObject)column).addConstraint(constraint); } else { column = new ConstrainedColumn(column, constraint); } _columns.addObject(column); return this; } /** Sets the constraint on a previously added column * @deprecated use {@link ConstraintClause} instead of ColumnConstraint */ @Deprecated public CreateTableQuery setColumnConstraint(Column column, ColumnConstraint constraint) { return addColumnConstraint(column, (Object)constraint); } /** * Adds the constraint on a previously added column * <p> * {@code Object} -> {@code SqlObject} constraint conversions handled by * {@link Converter#toCustomConstraintClause}. */ public CreateTableQuery addColumnConstraint(Column column, Object constraint) { for(ListIterator<SqlObject> iter = _columns.listIterator(); iter.hasNext(); ) { SqlObject tmpCol = iter.next(); if((tmpCol instanceof TypedColumnObject) && (((TypedColumnObject)tmpCol)._column == column)) { // add constraint ((TypedColumnObject)tmpCol).addConstraint(constraint); break; } } return this; } /** * Sets the given value as the column default value on a previously added * column * <p> * {@code Object} -> {@code SqlObject} value conversions handled by * {@link Converter#toValueSqlObject}. */ public CreateTableQuery setColumnDefaultValue(Column column, Object defaultValue) { for(ListIterator<SqlObject> iter = _columns.listIterator(); iter.hasNext(); ) { SqlObject tmpCol = iter.next(); if((tmpCol instanceof TypedColumnObject) && (((TypedColumnObject)tmpCol)._column == column)) { // add constraint ((TypedColumnObject)tmpCol).setDefaultValue(defaultValue); break; } } return this; } /** * Adds the given Constraints as table constraints. */ public CreateTableQuery addConstraints(Constraint... constraints) { return addCustomConstraints((Object[])constraints); } /** * Adds the given Objects as table constraints, should look like * <code>"<constraint>"</code>. * <p> * {@code Object} -> {@code SqlObject} conversions handled by * {@link Converter#CUSTOM_TO_CONSTRAINTCLAUSE}. */ public CreateTableQuery addCustomConstraints(Object... constraintStrs) { _constraints.addObjects(Converter.CUSTOM_TO_CONSTRAINTCLAUSE, constraintStrs); return this; } @Override protected void collectSchemaObjects(ValidationContext vContext) { super.collectSchemaObjects(vContext); _constraints.collectSchemaObjects(vContext); } @Override public void validate(ValidationContext vContext) throws ValidationException { // validate super super.validate(vContext); // we'd better have some columns if(_columns.isEmpty()) { throw new ValidationException("Table has no columns"); } } @Override protected void appendTo(AppendableExt app, SqlContext newContext) throws IOException { newContext.setUseTableAliases(false); app.append("CREATE TABLE ").append(_object) .append(" (").append(_columns); if(!_constraints.isEmpty()) { app.append(",").append(_constraints); } app.append(")"); appendTableSpace(app); } /** * Wrapper around a column that adds a constraint specification. */ private static class ConstrainedColumn extends SqlObject { private SqlObject _column; private Object _constraint; private ConstrainedColumn(SqlObject column, Object constraint) { _column = column; _constraint = constraint; } @Override protected void collectSchemaObjects(ValidationContext vContext) { _column.collectSchemaObjects(vContext); } @Override public void appendTo(AppendableExt app) throws IOException { app.append(_column).append(" ").append(_constraint); } } }