001package com.hfg.sql;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.List;
006import java.util.regex.Matcher;
007import java.util.regex.Pattern;
008
009import com.hfg.util.StringBuilderPlus;
010import com.hfg.util.StringUtil;
011import com.hfg.util.collection.CollectionUtil;
012
013//------------------------------------------------------------------------------
014/**
015 Grouping of SQL where clauses - either AND or OR.
016 <div>
017 @author J. Alex Taylor, hairyfatguy.com
018 </div>
019 */
020//------------------------------------------------------------------------------
021// com.hfg XML/HTML Coding Library
022//
023// This library is free software; you can redistribute it and/or
024// modify it under the terms of the GNU Lesser General Public
025// License as published by the Free Software Foundation; either
026// version 2.1 of the License, or (at your option) any later version.
027//
028// This library is distributed in the hope that it will be useful,
029// but WITHOUT ANY WARRANTY; without even the implied warranty of
030// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
031// Lesser General Public License for more details.
032//
033// You should have received a copy of the GNU Lesser General Public
034// License along with this library; if not, write to the Free Software
035// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
036//
037// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
038// jataylor@hairyfatguy.com
039//------------------------------------------------------------------------------
040
041public abstract class WhereClauseGroup
042{
043   public enum Type
044   {
045      AND(3),
046      OR(4);
047
048      private String mPadding;
049
050      private Type(int inPadding)
051      {
052         mPadding = StringUtil.polyChar(' ', inPadding);
053      }
054
055      public String getPadding()
056      {
057         return mPadding;
058      }
059   }
060
061   private Type mType;
062   private List<Object> mWhereClauses;
063
064   private static final Pattern CLAUSE_INTERIOR_REGEXP = Pattern.compile("([^\\)])\n\\s+");
065
066   //###########################################################################
067   // CONSTRUCTORS
068   //###########################################################################
069
070   //---------------------------------------------------------------------------
071   protected WhereClauseGroup(Type inValue)
072   {
073      mType = inValue;
074   }
075
076   //###########################################################################
077   // PUBLIC METHODS
078   //###########################################################################
079
080   //---------------------------------------------------------------------------
081   public Type getType()
082   {
083      return mType;
084   }
085
086   //---------------------------------------------------------------------------
087   public String toSQL()
088   {
089      StringBuilderPlus buffer = new StringBuilderPlus().setDelimiter("\n" + mType.getPadding() + mType + " ");
090      if (CollectionUtil.hasValues(mWhereClauses))
091      {
092         Type type = null;
093         for (Object clause : mWhereClauses)
094         {
095            if (null == type)
096            {
097               if (clause instanceof WhereClauseGroup)
098               {
099                  type = ((WhereClauseGroup)clause).getType();
100               }
101               else
102               {
103                  type = Type.AND;
104               }
105            }
106
107            if (clause instanceof WhereClauseGroup
108                  && (! ((WhereClauseGroup)clause).getType().equals(type)
109                      || (mWhereClauses.size() > 1
110                          && ! ((WhereClauseGroup)clause).getType().equals(getType()))))
111            {
112               // Remove any line returns we placed in the interior of a grouped clause
113               int index = 0;
114               StringBuilder clauseSql = new StringBuilder(((WhereClauseGroup) clause).toSQL());
115               Matcher m = CLAUSE_INTERIOR_REGEXP.matcher(clauseSql);
116               while (m.find(index))
117               {
118                  clauseSql.replace(m.start() + 1, m.end(), " ");
119                  index = m.start() + 1;
120               }
121
122               buffer.delimitedAppend("(" + clauseSql + ")");
123            }
124            else
125            {
126               buffer.delimitedAppend(clause);
127            }
128         }
129      }
130
131      return buffer.toString();
132   }
133
134   //---------------------------------------------------------------------------
135   @Override
136   public String toString()
137   {
138      return toSQL();
139   }
140
141   //---------------------------------------------------------------------------
142   public WhereClauseGroup add(WhereClause inValue)
143   {
144      if (null == mWhereClauses)
145      {
146         mWhereClauses = new ArrayList<>(4);
147      }
148
149      mWhereClauses.add(inValue);
150
151      return this;
152   }
153
154   //---------------------------------------------------------------------------
155   public WhereClauseGroup add(WhereClauseGroup inValue)
156   {
157      if (null == mWhereClauses)
158      {
159         mWhereClauses = new ArrayList<>(4);
160      }
161
162      mWhereClauses.add(inValue);
163
164      return this;
165   }
166
167   //---------------------------------------------------------------------------
168   public WhereClauseGroup addAll(Collection<WhereClause> inValues)
169   {
170      if (CollectionUtil.hasValues(inValues))
171      {
172         if (null == mWhereClauses)
173         {
174            mWhereClauses = new ArrayList<>(inValues.size());
175         }
176
177         mWhereClauses.addAll(inValues);
178      }
179
180      return this;
181   }
182
183   //---------------------------------------------------------------------------
184   public WhereClauseGroup addAllGroups(Collection<WhereClauseGroup> inValues)
185   {
186      if (CollectionUtil.hasValues(inValues))
187      {
188         if (null == mWhereClauses)
189         {
190            mWhereClauses = new ArrayList<>(inValues.size());
191         }
192
193         mWhereClauses.addAll(inValues);
194      }
195
196      return this;
197   }
198}