View Javadoc
1   /**
2    *    Copyright 2009-2015 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.jdbc;
17  
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  /**
23   * @author Clinton Begin
24   * @author Jeff Butler
25   * @author Adam Gent
26   */
27  public abstract class AbstractSQL<T> {
28  
29    private static final String AND = ") \nAND (";
30    private static final String OR = ") \nOR (";
31  
32    private SQLStatement sql = new SQLStatement();
33  
34    public abstract T getSelf();
35  
36    public T UPDATE(String table) {
37      sql().statementType = SQLStatement.StatementType.UPDATE;
38      sql().tables.add(table);
39      return getSelf();
40    }
41  
42    public T SET(String sets) {
43      sql().sets.add(sets);
44      return getSelf();
45    }
46  
47    public T INSERT_INTO(String tableName) {
48      sql().statementType = SQLStatement.StatementType.INSERT;
49      sql().tables.add(tableName);
50      return getSelf();
51    }
52  
53    public T VALUES(String columns, String values) {
54      sql().columns.add(columns);
55      sql().values.add(values);
56      return getSelf();
57    }
58  
59    public T SELECT(String columns) {
60      sql().statementType = SQLStatement.StatementType.SELECT;
61      sql().select.add(columns);
62      return getSelf();
63    }
64  
65    public T SELECT_DISTINCT(String columns) {
66      sql().distinct = true;
67      SELECT(columns);
68      return getSelf();
69    }
70  
71    public T DELETE_FROM(String table) {
72      sql().statementType = SQLStatement.StatementType.DELETE;
73      sql().tables.add(table);
74      return getSelf();
75    }
76  
77    public T FROM(String table) {
78      sql().tables.add(table);
79      return getSelf();
80    }
81  
82    public T JOIN(String join) {
83      sql().join.add(join);
84      return getSelf();
85    }
86  
87    public T INNER_JOIN(String join) {
88      sql().innerJoin.add(join);
89      return getSelf();
90    }
91  
92    public T LEFT_OUTER_JOIN(String join) {
93      sql().leftOuterJoin.add(join);
94      return getSelf();
95    }
96  
97    public T RIGHT_OUTER_JOIN(String join) {
98      sql().rightOuterJoin.add(join);
99      return getSelf();
100   }
101 
102   public T OUTER_JOIN(String join) {
103     sql().outerJoin.add(join);
104     return getSelf();
105   }
106 
107   public T WHERE(String conditions) {
108     sql().where.add(conditions);
109     sql().lastList = sql().where;
110     return getSelf();
111   }
112 
113   public T OR() {
114     sql().lastList.add(OR);
115     return getSelf();
116   }
117 
118   public T AND() {
119     sql().lastList.add(AND);
120     return getSelf();
121   }
122 
123   public T GROUP_BY(String columns) {
124     sql().groupBy.add(columns);
125     return getSelf();
126   }
127 
128   public T HAVING(String conditions) {
129     sql().having.add(conditions);
130     sql().lastList = sql().having;
131     return getSelf();
132   }
133 
134   public T ORDER_BY(String columns) {
135     sql().orderBy.add(columns);
136     return getSelf();
137   }
138 
139   private SQLStatement sql() {
140     return sql;
141   }
142 
143   public <A extends Appendable> A usingAppender(A a) {
144     sql().sql(a);
145     return a;
146   }
147 
148   @Override
149   public String toString() {
150     StringBuilder sb = new StringBuilder();
151     sql().sql(sb);
152     return sb.toString();
153   }
154 
155   private static class SafeAppendable {
156     private final Appendable a;
157     private boolean empty = true;
158 
159     public SafeAppendable(Appendable a) {
160       super();
161       this.a = a;
162     }
163 
164     public SafeAppendable append(CharSequence s) {
165       try {
166         if (empty && s.length() > 0) {
167           empty = false;
168         }
169         a.append(s);
170       } catch (IOException e) {
171         throw new RuntimeException(e);
172       }
173       return this;
174     }
175 
176     public boolean isEmpty() {
177       return empty;
178     }
179 
180   }
181 
182   private static class SQLStatement {
183 
184     public enum StatementType {
185       DELETE, INSERT, SELECT, UPDATE
186     }
187 
188     StatementType statementType;
189     List<String> sets = new ArrayList<String>();
190     List<String> select = new ArrayList<String>();
191     List<String> tables = new ArrayList<String>();
192     List<String> join = new ArrayList<String>();
193     List<String> innerJoin = new ArrayList<String>();
194     List<String> outerJoin = new ArrayList<String>();
195     List<String> leftOuterJoin = new ArrayList<String>();
196     List<String> rightOuterJoin = new ArrayList<String>();
197     List<String> where = new ArrayList<String>();
198     List<String> having = new ArrayList<String>();
199     List<String> groupBy = new ArrayList<String>();
200     List<String> orderBy = new ArrayList<String>();
201     List<String> lastList = new ArrayList<String>();
202     List<String> columns = new ArrayList<String>();
203     List<String> values = new ArrayList<String>();
204     boolean distinct;
205 
206     public SQLStatement() {
207         // Prevent Synthetic Access
208     }
209 
210     private void sqlClause(SafeAppendable builder, String keyword, List<String> parts, String open, String close,
211                            String conjunction) {
212       if (!parts.isEmpty()) {
213         if (!builder.isEmpty()) {
214           builder.append("\n");
215         }
216         builder.append(keyword);
217         builder.append(" ");
218         builder.append(open);
219         String last = "________";
220         for (int i = 0, n = parts.size(); i < n; i++) {
221           String part = parts.get(i);
222           if (i > 0 && !part.equals(AND) && !part.equals(OR) && !last.equals(AND) && !last.equals(OR)) {
223             builder.append(conjunction);
224           }
225           builder.append(part);
226           last = part;
227         }
228         builder.append(close);
229       }
230     }
231 
232     private String selectSQL(SafeAppendable builder) {
233       if (distinct) {
234         sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");
235       } else {
236         sqlClause(builder, "SELECT", select, "", "", ", ");
237       }
238 
239       sqlClause(builder, "FROM", tables, "", "", ", ");
240       sqlClause(builder, "JOIN", join, "", "", "\nJOIN ");
241       sqlClause(builder, "INNER JOIN", innerJoin, "", "", "\nINNER JOIN ");
242       sqlClause(builder, "OUTER JOIN", outerJoin, "", "", "\nOUTER JOIN ");
243       sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", "\nLEFT OUTER JOIN ");
244       sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", "\nRIGHT OUTER JOIN ");
245       sqlClause(builder, "WHERE", where, "(", ")", " AND ");
246       sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
247       sqlClause(builder, "HAVING", having, "(", ")", " AND ");
248       sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
249       return builder.toString();
250     }
251 
252     private String insertSQL(SafeAppendable builder) {
253       sqlClause(builder, "INSERT INTO", tables, "", "", "");
254       sqlClause(builder, "", columns, "(", ")", ", ");
255       sqlClause(builder, "VALUES", values, "(", ")", ", ");
256       return builder.toString();
257     }
258 
259     private String deleteSQL(SafeAppendable builder) {
260       sqlClause(builder, "DELETE FROM", tables, "", "", "");
261       sqlClause(builder, "WHERE", where, "(", ")", " AND ");
262       return builder.toString();
263     }
264 
265     private String updateSQL(SafeAppendable builder) {
266 
267       sqlClause(builder, "UPDATE", tables, "", "", "");
268       sqlClause(builder, "SET", sets, "", "", ", ");
269       sqlClause(builder, "WHERE", where, "(", ")", " AND ");
270       return builder.toString();
271     }
272 
273     public String sql(Appendable a) {
274       SafeAppendable builder = new SafeAppendable(a);
275       if (statementType == null) {
276         return null;
277       }
278 
279       String answer;
280 
281       switch (statementType) {
282         case DELETE:
283           answer = deleteSQL(builder);
284           break;
285 
286         case INSERT:
287           answer = insertSQL(builder);
288           break;
289 
290         case SELECT:
291           answer = selectSQL(builder);
292           break;
293 
294         case UPDATE:
295           answer = updateSQL(builder);
296           break;
297 
298         default:
299           answer = null;
300       }
301 
302       return answer;
303     }
304   }
305 }