/* 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; /** * Common base class for <code>"CASE ... END"</code> clauses * * @author James Ahlborn */ public abstract class BaseCaseStatement<ThisType extends BaseCaseStatement<ThisType>> extends Expression implements Verifiable<ThisType> { /** SqlObject which can outputs "ELSE NULL" */ private static final ElseObject NULL_ELSE = new ElseObject(null); /** the initial column operand for the CASE statement, if any */ private SqlObject _operand; /** the when clauses for this CASE statement (the last object may be an ElseObject) */ private SqlObjectList<BaseWhenObject> _whens = SqlObjectList.create(" "); protected BaseCaseStatement(SqlObject operand) { _operand = operand; } @Override public boolean isEmpty() { return _whens.isEmpty(); } /** * Adds a "WHEN" clause to the "CASE" statement. * <p> * All {@code Object} -> {@code SqlObject} conversions handled by * {@link Converter#toColumnSqlObject(Object)}. * * @param test the custom condition to test for this "WHEN" clause * @param result the result to output if this "WHEN" clause is selected */ public ThisType addCustomWhen(Object test, Object result) { _whens.addObject(new WhenObject(Converter.toColumnSqlObject(test), result)); return getThisType(); } /** * Adds an "ELSE" clause to the "CASE" statement. Should be called at most * once after all necessary calls to addWhen have been done. * <p> * {@code Object} -> {@code SqlObject} conversions handled by * {@link Converter#toColumnSqlObject(Object)}. * * @param result the result to output if no other "WHEN" clause is selected */ public ThisType addElse(Object result) { _whens.addObject(new ElseObject(result)); return getThisType(); } /** * Adds an "ELSE NULL" clause to the "CASE" statement. Should be called at * most once after all necessary calls to addWhen have been done. */ public ThisType addElseNull() { _whens.addObject(NULL_ELSE); return getThisType(); } public final ThisType validate() throws ValidationException { doValidate(); return getThisType(); } public void validate(ValidationContext vContext) throws ValidationException { if(_whens.size() > 1) { // make sure that at most one else clause exists and that it is at the // end int okayIdx = _whens.size() - 1; for(ListIterator<BaseWhenObject> iter = _whens.listIterator(); iter.hasNext(); ) { int idx = iter.nextIndex(); BaseWhenObject obj = iter.next(); if((obj instanceof ElseObject) && (idx != okayIdx)) { throw new ValidationException("Else clause at invalid index " + idx); } } } } @Override protected void collectSchemaObjects(ValidationContext vContext) { vContext.addVerifiable(this); if(_operand != null) { _operand.collectSchemaObjects(vContext); } _whens.collectSchemaObjects(vContext); } @Override public void appendTo(AppendableExt app) throws IOException { if(!isEmpty()) { app.append("(CASE "); if(_operand != null) { app.append(_operand).append(" "); } app.append(_whens).append(" END)"); } } /** @return the handle to this object as the subclass type */ @SuppressWarnings("unchecked") protected final ThisType getThisType() { return (ThisType)this; } /** * Utility class to output the result part of a "WHEN" clause for a "CASE" * clause. */ private static abstract class BaseWhenObject extends SqlObject { private SqlObject _result; protected BaseWhenObject(Object result) { _result = Converter.toColumnSqlObject(result); } @Override protected void collectSchemaObjects(ValidationContext vContext) { _result.collectSchemaObjects(vContext); } protected void appendResult(AppendableExt app) throws IOException { app.append(_result); } } /** * Utility class to output the "WHEN" clause for a "CASE" clause. */ private static class WhenObject extends BaseWhenObject { private SqlObject _test; private WhenObject(SqlObject test, Object result) { super(result); _test = test; } @Override protected void collectSchemaObjects(ValidationContext vContext) { super.collectSchemaObjects(vContext); _test.collectSchemaObjects(vContext); } @Override public void appendTo(AppendableExt app) throws IOException { app.append("WHEN ").append(_test).append(" THEN "); appendResult(app); } } /** * Utility class to output the "ELSE" clause for a "CASE" clause. */ private static class ElseObject extends BaseWhenObject { private ElseObject(Object result) { super(result); } @Override public void appendTo(AppendableExt app) throws IOException { app.append("ELSE "); appendResult(app); } } }