KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jodd > db > orm > sqlgen > DbDynamicSqlTemplate


1 // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
2

3 package jodd.db.orm.sqlgen;
4
5 import jodd.bean.BeanUtil;
6 import jodd.db.orm.DbEntityDescriptor;
7 import jodd.db.orm.DbOrm;
8 import jodd.db.orm.DbOrmException;
9 import jodd.introspector.DefaultIntrospector;
10 import jodd.util.StringUtil;
11
12 import java.lang.reflect.Field JavaDoc;
13
14 /**
15  * Enhanced {@link DbSqlTemplate}. Gives some more macros for dynamic queries.
16  *
17  * <p>
18  * Macro references follows this rules:
19  * <ul>
20  * <li>objref : objref.ID=:className.propertyName (only non-null)</li>
21  * <li>+objref : objref.ID=:className.propertyName (including non-null)</li>*
22  * <li>alias.objref : alias.ID=:className.propertyName</li>
23  * <li>.objref : ID=:className.propertyName</li>
24  * </ul>
25  */

26 public class DbDynamicSqlTemplate extends DbSqlTemplate {
27
28     public DbDynamicSqlTemplate(String JavaDoc template) {
29         this(template, DbOrm.getInstance());
30     }
31
32     public DbDynamicSqlTemplate(String JavaDoc template, DbOrm dbOrm) {
33         super(template, dbOrm);
34     }
35
36     // ---------------------------------------------------------------- overrides
37

38     /**
39      * @see DbSqlTemplate#use(String, Object)
40      */

41     public DbDynamicSqlTemplate use(String JavaDoc name, Object JavaDoc value) {
42         super.use(name, value);
43         return this;
44     }
45
46     /**
47      * @see DbSqlTemplate#columnAliases
48      */

49     public DbDynamicSqlTemplate columnAliases(boolean aliases) {
50         super.columnAliases(aliases);
51         return this;
52     }
53
54     /**
55      * @see DbSqlTemplate#setColumnAliasesType(jodd.db.orm.sqlgen.DbSqlTemplate.ColumnAliasType)
56      */

57     public DbDynamicSqlTemplate setColumnAliasesType(ColumnAliasType aliasesType) {
58         super.setColumnAliasesType(aliasesType);
59         return this;
60     }
61
62     /**
63      * @see DbSqlTemplate#escape(boolean)
64      */

65     public DbDynamicSqlTemplate escape(boolean escape) {
66         super.escape(escape);
67         return this;
68     }
69
70     // ---------------------------------------------------------------- where
71

72
73     /**
74      * Parses where conditions based on specified object reference. When just object reference
75      * is specified, each generated column will have table name as prefix. Example:<br>
76      * <code>#W{where foo}</code> may generate: '<code>where foo.ID=:foo.id</code>'.<br>
77      * If specified object reference is existing table reference, columns will be prefixed
78      * with table references instead of table names.
79      *
80      * <p>
81      * By adding a table ref prefix to object reference, generated columns names will contain
82      * this table ref (i.e. alias):<br>
83      * <code>#W{where b.foo}</code> may generate: '<code>where b.ID=:foo.id</code>'.<br>
84      * Note that existance of table alias is <b>NOT</b> checked, because it is regular not to use
85      * table macros, if one doesn't want so. When alias is missing, but a 'dot' exists:<br>
86      * <code>#W{where .foo}</code> may generate: '<code>where ID=:foo.id</code>'.<br>
87      *
88      * <p>
89      * If reference starts with '!' sign, finder mode is turned on. Note that there is no sence
90      * to have a finder for columns including non-null ones.
91      *
92      * <p>
93      * Optionally, macro can have an word in front of values list, that specifies
94      * an optional sql keyword that will be inserted only if there is at least one
95      * generated condition.
96      */

97     public String JavaDoc parseWhere(String JavaDoc template) {
98         StringBuilder JavaDoc result = new StringBuilder JavaDoc(template.length());
99         while (true) {
100             String JavaDoc allConditions = nextRegion(result, template, "$W{", "}");
101             if (allConditions == null) {
102                 break;
103             }
104             String JavaDoc prefix = null; // get prefix word
105
int spaceNdx = allConditions.indexOf(' ');
106             if (spaceNdx != -1) {
107                 prefix = allConditions.substring(0, spaceNdx);
108                 allConditions = allConditions.substring(spaceNdx + 1).trim();
109             }
110             
111             String JavaDoc[] conds = StringUtil.split(allConditions, ",");
112             int count = 0;
113             for (String JavaDoc condition: conds) {
114                 condition = condition.trim();
115
116                 boolean useFinders = false;
117                 if (condition.startsWith("!") == true) {
118                     condition = condition.substring(1);
119                     useFinders = true;
120                 }
121
122                 String JavaDoc tableAlias; // get optional table alias, will never be null
123
int dotNdx = condition.indexOf('.');
124                 if (dotNdx != -1) {
125                     tableAlias = condition.substring(0, dotNdx);
126                     condition = condition.substring(dotNdx + 1);
127                 } else {
128 // if (tablesRefs.get(condition) != null) {
129
// tableAlias = condition;
130
// }
131
tableAlias = condition;
132                 }
133
134                 Object JavaDoc data = null;
135                 if (references != null) {
136                     data = references.get(condition);
137                 }
138                 if (data == null) {
139                     throw new DbOrmException("Unable to find object reference '" + condition + "'.");
140                 }
141                 if (useFinders == false) {
142                     count = where(result, prefix, data, tableAlias, count);
143                 } else {
144                     count = whereWithFinders(result, prefix, data, tableAlias, count);
145                 }
146             }
147         }
148         return result.toString();
149     }
150
151     public static String JavaDoc[][] operators = new String JavaDoc[][] {
152             new String JavaDoc[] {"Like", " like "},
153             new String JavaDoc[] {"Greater", ">"},
154             new String JavaDoc[] {"Less", "<"},
155             new String JavaDoc[] {"GreaterEqual", ">="},
156             new String JavaDoc[] {"LessEqual", "<="},
157             new String JavaDoc[] {"Not", "<>"},
158     };
159
160     protected int where(StringBuilder JavaDoc result, String JavaDoc prefix, Object JavaDoc object, String JavaDoc tableAlias, int count) {
161         Class JavaDoc type = object.getClass();
162         DbEntityDescriptor ded = dbOrm.lookup(type);
163
164         String JavaDoc className = StringUtil.uncapitalize(type.getSimpleName());
165         String JavaDoc[] allProperties = ded.getProperties();
166         String JavaDoc[] allColumns = ded.getColumns();
167
168         for (int i = 0; i < allProperties.length; i++) {
169             String JavaDoc property = allProperties[i];
170
171             Object JavaDoc value = BeanUtil.getDeclaredProperty(object, property);
172             if (value == null) {
173                 continue;
174             }
175
176             // generate
177
String JavaDoc propertyName = className + '.' + property;
178             parameters.put(propertyName, value);
179             if ((count == 0) && (prefix != null)) {
180                 result.append(prefix).append(' ');
181             } else {
182                 result.append(" and ");
183             }
184             count++;
185             if (tableAlias.length() != 0) {
186                 result.append(tableAlias).append('.');
187             }
188             result.append(allColumns[i]).append('=').append(':').append(propertyName);
189         }
190         return count;
191     }
192
193
194     protected int whereWithFinders(StringBuilder JavaDoc result, String JavaDoc prefix, Object JavaDoc object, String JavaDoc tableAlias, int count) {
195         Class JavaDoc type = object.getClass();
196         DbEntityDescriptor ded = dbOrm.lookup(type);
197         String JavaDoc className = StringUtil.uncapitalize(type.getSimpleName());
198
199         Field JavaDoc[] allFields = DefaultIntrospector.lookup(type).getAllFields(true);
200
201         for (Field JavaDoc field : allFields) {
202
203             String JavaDoc operator = "=";
204             String JavaDoc lookupFieldName = field.getName();
205             for (String JavaDoc[] op : operators) {
206                 if (lookupFieldName.endsWith(op[0])) {
207                     lookupFieldName = lookupFieldName.substring(0, lookupFieldName.length() - op[0].length());
208                     operator = op[1];
209                     break;
210                 }
211             }
212
213             // value
214
Object JavaDoc value = BeanUtil.getDeclaredProperty(object, field.getName());
215             if (value == null) {
216                 continue;
217             }
218
219             // column name
220
String JavaDoc columnName = ded.getColumnName(lookupFieldName);
221             if (columnName == null) {
222                 continue;
223             }
224
225             // generate
226
String JavaDoc propertyName = className + '.' + field.getName();
227             parameters.put(propertyName, value);
228             if ((count == 0) && (prefix != null)) {
229                 result.append(prefix).append(' ');
230             } else {
231                 result.append(" and ");
232             }
233             count++;
234             if (tableAlias.length() != 0) {
235                 result.append(tableAlias).append('.');
236             }
237             result.append(columnName).append(operator).append(':').append(propertyName);
238         }
239         return count;
240     }
241
242     // ---------------------------------------------------------------- values
243

244
245     /**
246      * Returns comma-separated list of columns for specified object reference.
247      * If reference starts with "+" all columns will be returned.
248      */

249     public String JavaDoc parseValues(String JavaDoc template) {
250         StringBuilder JavaDoc result = new StringBuilder JavaDoc(template.length());
251         while (true) {
252             String JavaDoc valueRef = nextRegion(result, template, "$V{", "}");
253             if (valueRef == null) {
254                 break;
255             }
256
257             boolean allProperties = false;
258             if (valueRef.startsWith("+")) {
259                 allProperties = true;
260                 valueRef = valueRef.substring(1);
261             }
262
263             Object JavaDoc data = null;
264             if (references != null) {
265                 data = references.get(valueRef);
266             }
267             if (data == null) {
268                 throw new DbOrmException("Unable to find object reference '" + valueRef + "'.");
269             }
270
271             Class JavaDoc type = data.getClass();
272             String JavaDoc className = StringUtil.uncapitalize(type.getSimpleName());
273             DbEntityDescriptor ded = dbOrm.lookup(type);
274             String JavaDoc[] properties = ded.getProperties();
275             int size = 0;
276             for (String JavaDoc property : properties) {
277                 Object JavaDoc value = BeanUtil.getDeclaredProperty(data, property);
278                 if ((allProperties == false) && (value == null)) {
279                     continue;
280                 }
281                 if (size > 0) {
282                     result.append(',').append(' ');
283                 }
284                 size++;
285                 result.append(':');
286                 String JavaDoc propertyName = className + '.' + property;
287                 result.append(propertyName);
288                 parameters.put(propertyName, value);
289             }
290         }
291         return result.toString();
292     }
293
294
295     // ---------------------------------------------------------------- update
296

297     /**
298      * Generates comma-separated assignment pairs for specified object reference.
299      * If reference starts with "+" all columns will be returned.
300      */

301     public String JavaDoc parseUpdate(String JavaDoc template) {
302         StringBuilder JavaDoc result = new StringBuilder JavaDoc(template.length());
303         while (true) {
304             String JavaDoc valueRef = nextRegion(result, template, "$U{", "}");
305             if (valueRef == null) {
306                 break;
307             }
308             boolean allProperties = false;
309             if (valueRef.startsWith("+")) {
310                 allProperties = true;
311                 valueRef = valueRef.substring(1);
312             }
313
314             String JavaDoc tableRef = null;
315             int dotNdx = valueRef.indexOf('.');
316             if (dotNdx != -1) {
317                 tableRef = valueRef.substring(0, dotNdx);
318                 valueRef = valueRef.substring(dotNdx + 1);
319             }
320
321             Object JavaDoc data = null;
322             if (references != null) {
323                 data = references.get(valueRef);
324             }
325             if (data == null) {
326                 throw new DbOrmException("Unable to find object reference '" + valueRef + "'.");
327             }
328
329             Class JavaDoc type = data.getClass();
330             String JavaDoc className = StringUtil.uncapitalize(type.getSimpleName());
331             DbEntityDescriptor ded = dbOrm.lookup(type);
332             String JavaDoc[] properties = ded.getProperties();
333             String JavaDoc[] columns = ded.getColumns();
334             int size = 0;
335             for (int i = 0; i < properties.length; i++) {
336                 String JavaDoc property = properties[i];
337                 Object JavaDoc value = BeanUtil.getDeclaredProperty(data, property);
338                 if ((allProperties == false) && (value == null)) {
339                     continue;
340                 }
341                 if (size > 0) {
342                     result.append(',').append(' ');
343                 }
344                 size++;
345                 if (tableRef != null) {
346                     if (tableRef.length() != 0) {
347                         result.append(tableRef).append('.');
348                     }
349                 }
350                 result.append(columns[i]).append('=');
351                 result.append(':');
352                 String JavaDoc propertyName = className + '.' + property;
353                 result.append(propertyName);
354                 parameters.put(propertyName, value);
355             }
356         }
357         return result.toString();
358     }
359     
360
361
362     // ---------------------------------------------------------------- interface
363

364     public String JavaDoc generateQuery() {
365         return parseUpdate(parseValues(parseWhere(super.generateQuery())));
366     }
367
368 }
369
Popular Tags