001/** 002 * Copyright 2014 Tampere University of Technology, Pori Department 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package core.tut.pori.dao; 017 018import java.util.ArrayList; 019import java.util.Iterator; 020import java.util.List; 021 022import org.springframework.jdbc.core.JdbcTemplate; 023 024import core.tut.pori.dao.clause.SQLClause; 025import core.tut.pori.dao.clause.SQLClause.SQLType; 026import core.tut.pori.dao.clause.UpdateClause; 027import core.tut.pori.dao.clause.WhereClause; 028import core.tut.pori.datatypes.IntPrimitiveList; 029import core.tut.pori.http.parameters.Limits; 030 031/** 032 * Helper class, which can be used to build an SQL UPDATE clause. 033 * 034 */ 035public class SQLUpdateBuilder { 036 private Limits _limits = null; 037 private String _tableName = null; 038 private ArrayList<UpdateClause> _updateClauses = new ArrayList<>(); 039 private ArrayList<WhereClause> _whereClauses = null; 040 041 /** 042 * 043 * @param table 044 */ 045 public SQLUpdateBuilder(String table){ 046 _tableName = table; 047 } 048 049 /** 050 * clear the currently set list of where clauses 051 */ 052 public void clearWhereClauses(){ 053 _whereClauses = null; 054 } 055 056 /** 057 * 058 * @return number of added where clauses 059 */ 060 public int getWhereClauseCount() { 061 return (_whereClauses == null ? 0 : _whereClauses.size()); 062 } 063 064 /** 065 * @param startItem the startItem to set, negative value disables limit 066 */ 067 public void setStartItem(int startItem) { 068 if(_limits == null){ 069 _limits = new Limits(startItem, Limits.DEFAULT_MAX_ITEMS); 070 }else{ 071 _limits.setTypeLimits(startItem, _limits.getEndItem(), null); 072 } 073 } 074 075 /** 076 * @param maxItems the maxItems to set, negative value disables limit 077 */ 078 public void setMaxItems(int maxItems) { 079 if(_limits == null){ 080 _limits = new Limits(0, maxItems-1); 081 }else{ 082 _limits.setTypeLimits(_limits.getStartItem(), maxItems-1, null); 083 } 084 } 085 086 /** 087 * 088 * @param limits if null, this is a no-op 089 */ 090 public void setLimits(Limits limits){ 091 _limits = limits; 092 } 093 094 /** 095 * 096 * @return number of added update clauses 097 */ 098 public int getUpdateClauseCount() { 099 return _updateClauses.size(); 100 } 101 102 /** 103 * null clause will be silently ignored 104 * 105 * @param clause 106 */ 107 public void addUpdateClause(UpdateClause clause){ 108 if(clause != null){ 109 _updateClauses.add(clause); 110 } 111 } 112 113 /** 114 * clear the list of update clauses if any 115 */ 116 public void clearUpdateClauses(){ 117 _updateClauses.clear(); 118 } 119 120 /** 121 * 122 * @param clause 123 */ 124 public void addWhereClause(WhereClause clause){ 125 if(_whereClauses == null){ 126 _whereClauses = new ArrayList<>(); 127 } 128 _whereClauses.add(clause); 129 } 130 131 /** 132 * execute the statement on the given template 133 * @param template 134 * @return number of rows affected 135 */ 136 public int execute(JdbcTemplate template){ 137 return template.update(toSQLString(), getValues(), getValueTypes()); 138 } 139 140 /** 141 * execute the statement on the given template 142 * @param template 143 * @param type 144 * @return number of rows affected 145 */ 146 public int execute(JdbcTemplate template, String type){ 147 return template.update(toSQLString(type), getValues(), getValueTypes()); 148 } 149 150 /** 151 * 152 * @return array of parameter values 153 */ 154 public Object[] getValues(){ 155 List<Object> objects = new ArrayList<>(); 156 for(Iterator<? extends SQLClause> iter = _updateClauses.iterator();iter.hasNext();){ 157 SQLClause c = iter.next(); 158 Object[] o = c.getValues(); 159 if(o != null){ 160 for(int i=0;i<o.length;++i){ 161 objects.add(o[i]); 162 } 163 } 164 } 165 166 if(_whereClauses != null){ 167 for(Iterator<? extends SQLClause> iter = _whereClauses.iterator();iter.hasNext();){ 168 SQLClause c = iter.next(); 169 Object[] o = c.getValues(); 170 if(o != null){ 171 for(int i=0;i<o.length;++i){ 172 objects.add(o[i]); 173 } 174 } 175 } 176 } 177 178 if(objects.isEmpty()){ 179 return null; 180 }else{ 181 return objects.toArray(); 182 } 183 } 184 185 /** 186 * 187 * @return array of parameter types 188 */ 189 public int[] getValueTypes(){ 190 IntPrimitiveList list = new IntPrimitiveList(); 191 for(Iterator<? extends SQLClause> iter = _updateClauses.iterator();iter.hasNext();){ 192 SQLClause c = iter.next(); 193 SQLType[] t = c.getValueTypes(); 194 if(t != null){ 195 for(int i=0;i<t.length;++i){ 196 list.add(t[i].toInt()); 197 } 198 } 199 } 200 201 if(_whereClauses != null){ 202 for(Iterator<? extends SQLClause> iter = _whereClauses.iterator();iter.hasNext();){ 203 SQLClause c = iter.next(); 204 SQLType[] t = c.getValueTypes(); 205 if(t != null){ 206 for(int i=0;i<t.length;++i){ 207 list.add(t[i].toInt()); 208 } 209 } 210 } 211 } 212 213 return list.toArray(); 214 } 215 216 /** 217 * 218 * @return the query as a SQL string 219 */ 220 public String toSQLString(){ 221 return toSQLString(null); 222 } 223 224 /** 225 * 226 * @param type 227 * @return the query as an SQL string using the given type of typed parameters (e.g. Limits). See {@link core.tut.pori.http.parameters.Limits} 228 */ 229 public String toSQLString(String type){ 230 StringBuilder sql = new StringBuilder("UPDATE "); 231 sql.append(_tableName); 232 sql.append(" SET "); 233 234 /* update clauses */ 235 Iterator<UpdateClause> iter = _updateClauses.iterator(); 236 iter.next().toSQLString(sql); // let it throw out-of-bounds if there are no update clauses 237 while(iter.hasNext()){ 238 sql.append(','); 239 iter.next().toSQLString(sql); 240 } 241 242 /* create where clauses */ 243 if(_whereClauses != null){ 244 sql.append(" WHERE "); 245 Iterator<WhereClause> witer = _whereClauses.iterator(); 246 witer.next().toSQLString(sql); 247 while(witer.hasNext()){ 248 WhereClause clause = witer.next(); 249 sql.append(clause.getClauseType().toClauseString()); 250 clause.toSQLString(sql); 251 } 252 } 253 254 /* create limit */ 255 if(_limits != null){ 256 sql.append(" LIMIT "); 257 sql.append(_limits.getStartItem(type)); 258 sql.append(','); 259 sql.append(_limits.getMaxItems()); 260 } 261 262 return sql.toString(); 263 } 264}