source: trunk/fmgVen/src/com/fmguler/ven/Criteria.java @ 32

Last change on this file since 32 was 32, checked in by fmguler, 13 years ago

Fixed typed criteria method parameters from Criteria.eq(String attribute, String value) to eq(String attribute, Object value). They accept values of any type, e.g. int, string, date.

Turned off debug messages by default. They can be enabled by setting Ven.setDebug(true).

Updated to Netbeans 7.0.1, which updated build-impl.xml, nothing to do with functionality.

File size: 11.7 KB
Line 
1/*
2 *  fmgVen - A Convention over Configuration Java ORM Tool
3 *  Copyright 2011 Fatih Mehmet Güler
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *  under the License.
17 */
18package com.fmguler.ven;
19
20import com.fmguler.ven.util.Convert;
21import java.util.HashMap;
22import java.util.LinkedList;
23import java.util.Map;
24import java.util.Stack;
25
26/**
27 * Criteria object, used to filter the result of a query according to some criteria.
28 * <p>
29 * Can be used in two modes; as string criteria or typed criteria.
30 * The string criteria is used like;
31 * <pre>
32 * new Criteria().add("and SomeDomainObject.anotherDomainObjects.name like :p1").param("p1", "a%");
33 * </pre>
34 * And the typed criteria is used like;
35 * <pre>
36 * new Criteria().eq(attr,value).like(attr,value).and().gt(attr, value).or().orderAsc(attr).orderDesc(attr).limit(limit, offset);
37 * </pre>
38 *
39 * This criteria object is used to filter SQL results by adding the "Criteria.criteriaToSQL()" output to the where clause.
40 *
41 * @author Fatih Mehmet Güler
42 */
43public class Criteria {
44    private StringBuffer criteriaStringBuffer = new StringBuffer(); //for string criteria
45    private LinkedList criterionList = new LinkedList(); //for typed criteria
46    private Map parameters = new HashMap(); //the parameters used in criteria string
47    private int limit = 20;
48    private int offset = 0;
49    int paramCount = 0;
50
51    //--------------------------------------------------------------------------
52    //String Criteria Methods
53    /**
54     * Add a criteria string
55     */
56    public Criteria add(String criteriaString) {
57        this.criteriaStringBuffer.append(" ").append(criteriaString);
58        return this;
59    }
60
61    /**
62     * Add the parameter used in criteria string
63     */
64    public Criteria param(String parameter, Object value) {
65        this.parameters.put(parameter, value);
66        return this;
67    }
68
69    /**
70     * Converts criteria string to SQL
71     * @return the criteria string as SQL where clause
72     */
73    public String criteriaStringToSQL() {
74        StringBuffer resultBuffer = new StringBuffer();
75        String criteriaString = criteriaStringBuffer.toString();
76        criteriaString = criteriaString.replaceAll("\\(", "\\( ");
77        criteriaString = criteriaString.replaceAll("\\)", " \\)");
78
79        String[] parts = criteriaString.split(" ");
80        for (int i = 0; i < parts.length; i++) {
81            if (!parts[i].startsWith(":") && parts[i].indexOf(".") >= 0) {
82                int lastDot = parts[i].lastIndexOf('.');
83                resultBuffer.append(" ");
84                int u = parts[i].length();
85                resultBuffer.append(Convert.toDB(parts[i].substring(0, lastDot).replace('.', '_')));
86                resultBuffer.append(Convert.toDB(parts[i].substring(lastDot, u)));
87            } else {
88                resultBuffer.append(" ").append(parts[i]);
89            }
90        }
91        return resultBuffer.toString();
92    }
93
94    /**
95     * @return the parameter map
96     */
97    public Map getParameters() {
98        return parameters;
99    }
100
101    //--------------------------------------------------------------------------
102    //Typed Criteria Methods
103    /**
104     * Add a criterion where an attribue equals a value (SQL = operator)
105     */
106    public Criteria eq(String attribute, Object value) {
107        criterionList.add(new Criterion(attribute, Criterion.OP_EQUALS, value));
108        return this;
109    }
110
111    /**
112     * Add a criterion where an attribue is like a value (SQL like operator)
113     */
114    public Criteria like(String attribute, Object value) {
115        criterionList.add(new Criterion(attribute, Criterion.OP_LIKE, value));
116        return this;
117    }
118
119    /**
120     * Add a criterion where an attribue is similar to a value (SQL similar to operator)
121     */
122    public Criteria similarto(String attribute, Object value) {
123        criterionList.add(new Criterion(attribute, Criterion.OP_SIMILAR_TO, value));
124        return this;
125    }
126
127    /**
128     * Add a criterion where an attribue is greater than a value (SQL > operator)
129     */
130    public Criteria gt(String attribute, Object value) {
131        criterionList.add(new Criterion(attribute, Criterion.OP_GREATER_THAN, value));
132        return this;
133    }
134
135    /**
136     * Add a criterion where an attribue is less than a value (SQL < operator)
137     */
138    public Criteria lt(String attribute, Object value) {
139        criterionList.add(new Criterion(attribute, Criterion.OP_LESS_THAN, value));
140        return this;
141    }
142
143    /**
144     * Add a criterion where an attribue is null (SQL is null operator)
145     */
146    public Criteria isNull(String attribute) {
147        criterionList.add(new Criterion(attribute, Criterion.OP_ISNULL, null));
148        return this;
149    }
150
151    /**
152     * Add: order by attribute asc
153     */
154    public Criteria orderAsc(String attribute) {
155        //Not implemented yet.
156        return this;
157    }
158
159    /**
160     * Add: order by attribute desc
161     */
162    public Criteria orderDesc(String attribute) {
163        //Not implemented yet.
164        return this;
165    }
166
167    /**
168     * Add limit and offset to the clause
169     */
170    public Criteria limit(int limit, int offset) {
171        this.limit = limit;
172        this.offset = offset;
173        return this;
174    }
175
176    //--------------------------------------------------------------------------
177    //Connectives
178    /**
179     * Connect previous two criteria with logical and
180     * (as in postfix notation)
181     */
182    public Criteria and() {
183        criterionList.add(new Criterion(Criterion.CONN_AND));
184        return this;
185    }
186
187    /**
188     * Connect previous two criteria with logical or
189     * (as in postfix notation)
190     */
191    public Criteria or() {
192        criterionList.add(new Criterion(Criterion.CONN_OR));
193        return this;
194    }
195
196    /**
197     * Connect previous criterion with logical not
198     * (as in postfix notation)
199     */
200    public Criteria not() {
201        criterionList.add(new Criterion(Criterion.CONN_NOT));
202        return this;
203    }
204
205    /**
206     * Converts typed criteria to SQL
207     * @return the typed criteria as SQL where clause
208     */
209    public String criteriaToSQL() {
210        LinkedList clone = (LinkedList)criterionList.clone();
211        Stack stack = new Stack();
212        while (!clone.isEmpty()) {
213            Criterion criterion = (Criterion)clone.removeFirst();
214            if (!criterion.isConnective()) {
215                String s = "(" + convertOperatorToSQL(criterion) + ")";
216                stack.push(s);
217            } else {
218                String conn = criterion.connective;
219                if (conn.equals(Criterion.CONN_AND)) {
220                    String s1 = (String)stack.pop();
221                    String s2 = (String)stack.pop();
222                    String sr = "(" + s1 + " and " + s2 + ")";
223                    stack.push(sr);
224                } else if (conn.equals(Criterion.CONN_OR)) {
225                        String s1 = (String)stack.pop();
226                        String s2 = (String)stack.pop();
227                        String sr = "(" + s1 + " or " + s2 + ")";
228                        stack.push(sr);
229                    } else if (conn.equals(Criterion.CONN_NOT)) {
230                            String s = (String)stack.pop();
231                            String sr = "not (" + s + ")";
232                            stack.push(sr);
233                        }
234            }
235        }
236
237        if (stack.isEmpty()) return "1=1";
238
239        String result = (String)stack.pop();
240        return result;
241    }
242
243    //convert the attribute-operator-value criterion to SQL
244    private String convertOperatorToSQL(Criterion criterion) {
245        String attribute = convertAttributeToAlias(criterion.attribute);
246        String operator = criterion.operator;
247        Object value = criterion.value;
248        String result = "";
249
250        if (value == null) {
251            //no value e.g. is null operator
252            result = attribute + " " + operator;
253        } else {
254            String paramName = genParamName();
255            parameters.put(paramName, value);
256            result = attribute + " " + operator + " :" + paramName + "";
257        }
258
259        return result;
260    }
261
262    //convert attribute to SQL alias
263    protected String convertAttributeToAlias(String attribute) {
264        //we convert like: x.y.z.t to x_y_z.t
265        StringBuffer resultBuffer = new StringBuffer();
266        int lastDot = attribute.lastIndexOf('.');
267        resultBuffer.append(" ");
268        int u = attribute.length();
269        resultBuffer.append(Convert.toDB(attribute.substring(0, lastDot).replace('.', '_')));
270        resultBuffer.append(Convert.toDB(attribute.substring(lastDot, u)));
271        return resultBuffer.toString();
272    }
273
274    //generate parameter for typed criteria
275    private String genParamName() {
276        return "__p" + paramCount++;
277    }
278
279    //test the criteria object
280    public static void main(String[] args) {
281        Criteria criteria = new Criteria() //criteria object
282                .like("SomeDomainObject.anotherDomainObjects.name", "a%") //attribute like value
283                .eq("SomeDomainObject.name", "sdo1") //attribute equals value
284                .and() //connect previous criteria with and
285                .isNull("SomeDomainObject.description") //attribute is null
286                .or(); //connect previous criteria with and
287
288        //print the resulting where clause SQL
289        System.out.println(criteria.criteriaToSQL());
290
291        //the result is;
292        //(( some_domain_object.description is null) or (( some_domain_object.name = :__p1) and ( some_domain_object_another_domain_objects.name like :__p0)))
293    }
294}
295
296/**
297 * Each criterion used in the criteria.
298 * Used to hold attribute-operator-value triplet.
299 * Used internally.
300 * @author Fatih Mehmet Güler
301 */
302class Criterion {
303    //available logical connectives
304    public static final String CONN_AND = "and";
305    public static final String CONN_OR = "or";
306    public static final String CONN_NOT = "not";
307    //available operators
308    public static final String OP_EQUALS = "=";
309    public static final String OP_LESS_THAN = "<";
310    public static final String OP_GREATER_THAN = ">";
311    public static final String OP_LIKE = "like";
312    public static final String OP_SIMILAR_TO = "similar to";
313    public static final String OP_NOT = "not";
314    public static final String OP_ISNULL = "is null";
315    //attribute-operator-value triplet
316    public String attribute;
317    public String operator;
318    public Object value;
319    //logical connective
320    public String connective = null;
321
322    public Criterion(String attribute, String operator, Object value) {
323        this.attribute = attribute;
324        this.operator = operator;
325        this.value = value;
326    }
327
328    public Criterion(String connective) {
329        this.connective = connective;
330    }
331
332    public boolean isConnective() {
333        return connective != null;
334    }
335
336    /**
337     * @return string representation of this criterion
338     */
339    public String toString() {
340        if (isConnective()) return connective;
341        return attribute + " " + operator + " " + value;
342    }
343}
Note: See TracBrowser for help on using the repository browser.