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}