1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.graph.query.model;
25
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import net.jcip.annotations.Immutable;
34 import org.modeshape.common.i18n.I18n;
35 import org.modeshape.common.util.CheckArg;
36 import org.modeshape.common.util.HashCode;
37 import org.modeshape.common.util.ObjectUtil;
38 import org.modeshape.graph.GraphI18n;
39
40
41
42
43
44
45
46
47
48 @Immutable
49 public class SetQuery implements QueryCommand {
50 private static final long serialVersionUID = 1L;
51
52 public enum Operation implements Readable {
53 UNION("UNION"),
54 INTERSECT("INTERSECT"),
55 EXCEPT("EXCEPT");
56
57 private static final Map<String, Operation> OPERATIONS_BY_SYMBOL;
58 static {
59 Map<String, Operation> opsBySymbol = new HashMap<String, Operation>();
60 for (Operation op : Operation.values()) {
61 opsBySymbol.put(op.getSymbol(), op);
62 }
63 OPERATIONS_BY_SYMBOL = Collections.unmodifiableMap(opsBySymbol);
64 }
65
66 private final String symbol;
67
68 private Operation( String symbol ) {
69 this.symbol = symbol;
70 }
71
72
73
74
75 public String getSymbol() {
76 return symbol;
77 }
78
79
80
81
82
83
84 @Override
85 public String toString() {
86 return symbol;
87 }
88
89 public static Operation forSymbol( String symbol ) {
90 CheckArg.isNotNull(symbol, "symbol");
91 return OPERATIONS_BY_SYMBOL.get(symbol.toUpperCase());
92 }
93
94
95
96
97
98
99 public String getString() {
100 return getSymbol();
101 }
102 }
103
104 protected static boolean unionableColumns( List<? extends Column> left,
105 List<? extends Column> right ) {
106
107 if (left.size() != right.size()) return false;
108
109 Iterator<? extends Column> leftIter = left.iterator();
110 Iterator<? extends Column> rightIter = right.iterator();
111 while (leftIter.hasNext() && rightIter.hasNext()) {
112 Column leftColumn = leftIter.next();
113 Column rightColumn = rightIter.next();
114 if (leftColumn == null || rightColumn == null) return false;
115 }
116 return leftIter.hasNext() == rightIter.hasNext();
117 }
118
119 private final List<? extends Ordering> orderings;
120 private final Limit limits;
121 private final QueryCommand left;
122 private final QueryCommand right;
123 private final Operation operation;
124 private final boolean all;
125 private final int hc;
126
127
128
129
130
131
132
133
134
135
136 public SetQuery( QueryCommand left,
137 Operation operation,
138 QueryCommand right,
139 boolean all ) {
140 CheckArg.isNotNull(left, "left");
141 CheckArg.isNotNull(right, "right");
142 CheckArg.isNotNull(operation, "operation");
143 if (!unionableColumns(left.columns(), right.columns())) {
144 I18n msg = GraphI18n.leftAndRightQueriesInSetQueryMustHaveUnionableColumns;
145 throw new IllegalArgumentException(msg.text(left.columns(), right.columns()));
146 }
147 this.left = left;
148 this.right = right;
149 this.operation = operation;
150 this.all = all;
151 this.orderings = Collections.<Ordering>emptyList();
152 this.limits = Limit.NONE;
153 this.hc = HashCode.compute(this.left, this.right, this.operation);
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167 public SetQuery( QueryCommand left,
168 Operation operation,
169 QueryCommand right,
170 boolean all,
171 List<? extends Ordering> orderings,
172 Limit limit ) {
173 CheckArg.isNotNull(left, "left");
174 CheckArg.isNotNull(right, "right");
175 CheckArg.isNotNull(operation, "operation");
176 if (!unionableColumns(left.columns(), right.columns())) {
177 I18n msg = GraphI18n.leftAndRightQueriesInSetQueryMustHaveUnionableColumns;
178 throw new IllegalArgumentException(msg.text(left.columns(), right.columns()));
179 }
180 this.left = left;
181 this.right = right;
182 this.operation = operation;
183 this.all = all;
184 this.orderings = orderings != null ? orderings : Collections.<Ordering>emptyList();
185 this.limits = limit != null ? limit : Limit.NONE;
186 this.hc = HashCode.compute(this.left, this.right, this.operation);
187 }
188
189
190
191
192
193
194 public List<? extends Column> columns() {
195 return left.columns();
196 }
197
198
199
200
201
202
203 public Limit limits() {
204 return limits;
205 }
206
207
208
209
210
211
212 public List<? extends Ordering> orderings() {
213 return orderings;
214 }
215
216
217
218
219
220
221 public QueryCommand left() {
222 return left;
223 }
224
225
226
227
228
229
230 public QueryCommand right() {
231 return right;
232 }
233
234
235
236
237
238
239 public final Operation operation() {
240 return operation;
241 }
242
243
244
245
246
247
248 public final boolean isAll() {
249 return all;
250 }
251
252
253
254
255
256
257 @Override
258 public String toString() {
259 return Visitors.readable(this);
260 }
261
262
263
264
265
266
267 @Override
268 public int hashCode() {
269 return hc;
270 }
271
272
273
274
275
276
277 @Override
278 public boolean equals( Object obj ) {
279 if (obj == this) return true;
280 if (obj instanceof SetQuery) {
281 SetQuery that = (SetQuery)obj;
282 if (this.hc != that.hc) return false;
283 if (this.operation != that.operation) return false;
284 if (!this.left.equals(that.left)) return false;
285 if (!this.right.equals(that.right)) return false;
286 if (!ObjectUtil.isEqualWithNulls(this.limits(), that.limits())) return false;
287 if (!ObjectUtil.isEqualWithNulls(this.orderings(), that.orderings())) return false;
288 return true;
289 }
290 return false;
291 }
292
293
294
295
296
297
298 public void accept( Visitor visitor ) {
299 visitor.visit(this);
300 }
301
302 public SetQuery withLimit( int rowLimit ) {
303 if (limits().rowLimit() == rowLimit) return this;
304 return new SetQuery(left, operation, right, all, orderings(), limits().withRowLimit(rowLimit));
305 }
306
307 public SetQuery withOffset( int offset ) {
308 if (limits().offset() == offset) return this;
309 return new SetQuery(left, operation, right, all, orderings(), limits().withOffset(offset));
310 }
311
312 public SetQuery adding( Ordering... orderings ) {
313 List<Ordering> newOrderings = null;
314 if (this.orderings() != null) {
315 newOrderings = new ArrayList<Ordering>(orderings());
316 for (Ordering ordering : orderings) {
317 newOrderings.add(ordering);
318 }
319 } else {
320 newOrderings = Arrays.asList(orderings);
321 }
322 return new SetQuery(left, operation, right, all, newOrderings, limits());
323 }
324 }