Source code: nectar/data/Query.java
1 /*
2 Copyright (C) 2003 Kai Schutte
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 * Query.java
19 *
20 * Created on March 31, 2003, 7:53 PM
21 */
22
23 package nectar.data;
24
25 import java.util.Collection;
26 import java.util.Vector;
27 import nectar.record.Record;
28 import nectar.record.RecordDescriptor;
29
30 /** Query objects are used to define the criteria for a query to the DataSource. It
31 * is essentially an object oriented analogy to SQL's SELECT statement. With this
32 * analogy, the variables that a Query is defined by could be described as:
33 * SELECT (list of fieldnames) FROM (list of tables) WHERE (dataConditions tree)
34 * (list of postElements).
35 *
36 * @author Kai Schutte skander@skander.com
37 */
38 public class Query {
39 private Vector fields = null;
40 private Vector extraFields = new Vector();
41 private Vector tables = null;
42 private DataConditions dcs = null;
43 private MatchConditions mcs = null;
44 private PostElements pes = null;
45 /** Creates a new empty instance of Query */
46 public Query() {
47 fields = new Vector();
48 tables = new Vector();
49 }
50
51 /** Create a new instance of a Query object based on the criteria determined in the
52 * RecordDescriptor object.
53 * @param rd The RecordDescriptor defining a Record's general criteria.
54 */
55 public Query(RecordDescriptor rd) {
56 fields = new Vector();
57 tables = new Vector();
58 redefine(rd);
59 }
60
61 /** reset this Query object so that it looks like a new object created with the
62 * empty constructor.
63 */
64 public void reset() {
65 fields.clear();
66 extraFields.clear();
67 tables.clear();
68 dcs = null;
69 mcs = null;
70 pes = null;
71 }
72
73 /** reset, then set all values according to the criteria defined in the given
74 * RecordDescriptor.
75 * @param rd The RecordDescriptor defining the query criteria.
76 */
77 public void redefine(RecordDescriptor rd) {
78 reset();
79 String type = rd.getType();
80 addTable(Record.TABLE);
81 addTable(type);
82 addField(Record.FIELD_RECORD_ID);
83 addDataCondition(DataConditions.AND, new OperatorCondition(new FieldElement(Record.TABLE, Record.FIELD_RECORD_ID), OperatorCondition.EQUAL, new FieldElement(type, Record.FIELD_CHILD_ID)));
84 addDataCondition(DataConditions.AND, new OperatorCondition(new FieldElement(Record.TABLE, Record.FIELD_TYPE), OperatorCondition.EQUAL, new ValueElement(type)));
85
86 Long owner = rd.getOwner();
87 if (owner == null) {
88 addDataCondition(DataConditions.AND, new FunctionCondition(FunctionCondition.ISNULL, new FieldElement(Record.TABLE, Record.FIELD_OWNER)));
89 } else if (owner.longValue() >= 0) {
90 addDataCondition(DataConditions.AND, new OperatorCondition(new FieldElement(Record.TABLE, Record.FIELD_OWNER), OperatorCondition.EQUAL, new ValueElement(owner.toString())));
91 }
92
93 Long project = rd.getProject();
94 DataConditions projectDcs = new DataConditions();
95 projectDcs.append(DataConditions.OR, new FunctionCondition(FunctionCondition.ISNULL, new FieldElement(Record.TABLE, Record.FIELD_PROJECT)));
96 projectDcs.append(DataConditions.OR, new OperatorCondition(new FieldElement(Record.TABLE, Record.FIELD_PROJECT), OperatorCondition.EQUAL, new ValueElement(project.toString())));
97 addDataCondition(DataConditions.AND, projectDcs);
98
99 String status = rd.getStatus();
100 if (status != null)
101 addDataCondition(DataConditions.AND, new OperatorCondition(new FieldElement(Record.TABLE, Record.FIELD_STATUS), OperatorCondition.EQUAL, new ValueElement(status)));
102 }
103
104 /** Creates a new Query instance, with a shorthand to set the fields and tables from a Collection of field Strings and a Collection
105 * of table Strings.
106 * @param f Collection of field name strings.
107 * @param t Collection of table name strings.
108 */
109 public Query(Collection f, Collection t) {
110 this.fields = new Vector(f);
111 this.tables = new Vector(t);
112 }
113
114 /** Creates a new instance of Query with field names, table names, DataConditions
115 * and PostElements set.
116 * @param f Collection of field names.
117 * @param t Collection of table names.
118 * @param d DataConditions construct to use in this Query.
119 * @param p PostElements construct to use in this Query.
120 *
121 */
122 public Query(Collection f, Collection t, DataConditions d, PostElements p) {
123 this.fields = new Vector(f);
124 this.tables = new Vector(t);
125 this.dcs = d;
126 this.pes = p;
127 }
128
129 /** create a deep copy of this Query. As Query objects in their entirety may be
130 * rather complex, this method may put a pretty heavy load on the system if used
131 * frequently.
132 * @return a deep/recursive copy of this instance.
133 */
134 public Object clone() {
135 Query clone = new Query();
136 clone.fields = new Vector(this.fields);
137 clone.tables = new Vector(this.tables);
138 if (dcs != null)
139 clone.dcs = (DataConditions)dcs.clone();
140 if (pes != null)
141 clone.pes = (PostElements)pes.clone();
142 if (mcs != null)
143 clone.mcs = (MatchConditions)mcs.clone();
144 clone.extraFields = new Vector(this.extraFields);
145 return clone;
146 }
147
148 /** get the Collection of field names defined in this query.
149 * @return the Collection of field name Strings.
150 */
151 public Collection getFields() { return fields; }
152
153 /** Set the Collection of field names for this Query.
154 *
155 * Calling <CODE>setFields(null)</CODE> is equivalent to
156 * <CODE>clearFields()</CODE>.
157 * @param fields Collection of field name strings.
158 */
159 public void setFields(Collection fields) {
160 if (fields == null)
161 this.fields.clear();
162 else
163 this.fields = new Vector(fields);
164 }
165
166 /** Clears the internal list of field names. */
167 public void clearFields() {
168 this.fields.clear();
169 }
170 /** append a field name to this Query.
171 * @param field the name of the field to add.
172 */
173 public void addField(String field) {
174 fields.add(field);
175 }
176 /** Returns a collection of extra field names. Extra field names are ones with have
177 * not been specified through setFields() or addField() but are necessary for this
178 * Query to work correctly. For example, adding a MatchCondition to a query will
179 * add an extra field to contain the score of a match.
180 * @return the Collection of extra field names.
181 */
182 public Collection getExtraFields() { return extraFields; }
183
184 /** Return the collection of table name strings used in this Query.
185 * @return the collection of tables for this Query.
186 */
187 public Collection getTables() { return tables; }
188 /** Set the list of tables this Query uses.
189 *
190 * Calling <CODE>getTables(null)</CODE> is equivalent to
191 * <CODE>clearTables()</CODE>.
192 * @param tables the Collection of table names.
193 */
194 public void setTables(Collection tables) {
195 if (tables == null)
196 this.tables.clear();
197 else
198 this.tables = new Vector(tables);
199 }
200
201 /** Clears the internal list of table names. */
202 public void clearTables() {
203 this.tables.clear();
204 }
205
206 /** add's a table name to the internal list in this Query.
207 * @param table Add a table name to this Query.
208 */
209 public void addTable(String table) {
210 if (tables == null)
211 tables = new Vector();
212 tables.add(table);
213 }
214
215 /** returns the DataConditions for this Query.
216 * @return the dataConditions.
217 */
218 public DataConditions getDataConditions() { return dcs; }
219 /** Sets the DataConditions for this Query.
220 * @param dcs the DataConditions.
221 */
222 public void setDataConditions(DataConditions dcs) { this.dcs = dcs; }
223
224 /** remove all data conditions from this Query. */
225 public void clearDataConditions() {
226 this.dcs = null;
227 }
228
229
230 /** Append a DataCondition to the top level DataConditions object in this Query.
231 * @param operator AND/OR/NOT -- see {@link DataConditions}.
232 * @param dc The DataCondition to add.
233 */
234 public void addDataCondition(byte operator, DataCondition dc) {
235 if (dcs == null) dcs = new DataConditions(dc);
236 else dcs.append(operator, dc);
237 }
238 /** Append a DataConditions to the top level DataConditions object in this Query.
239 * @param operator AND/OR/NOT -- see {@link DataConditions}.
240 * @param dc The DataConditions to add.
241 */
242 public void addDataCondition(byte operator, DataConditions dc) {
243 if (dcs == null) dcs = new DataConditions(dc);
244 else dcs.append(operator, dc);
245 }
246
247 /** Set the MatchConditions object for this Query.
248 * @param mcs the MatchConditions for this Query.
249 */
250 public void setMatchConditions(MatchConditions mcs) {
251 this.mcs = mcs;
252 extraFields.add(mcs.getReturnField());
253 }
254
255 /** Returns the MatchConditions defined in this Query.
256 * @return the matchConditions object or null if it's undefined.
257 */
258 public MatchConditions getMatchConditions() {
259 return mcs;
260 }
261
262 /** Returns the PostElements object for this Query.
263 * @return the PostElements object or null if undefined.
264 */
265 public PostElements getPostElements() { return pes; }
266 /** Sets the PostElements object for this Query.
267 * @param pes The PostElements object to set.
268 */
269 public void setPostElements(PostElements pes) { this.pes = pes; }
270 /** Append a PostElement to this Query's PostElements object.
271 * @param pe the PostElement to add.
272 */
273 public void addPostElement(PostElement pe) {
274 if (pes == null) { pes = new PostElements(); }
275 pes.set(pe);
276 }
277 }