001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Bogdan Stefanescu
018 *     Florent Guillaume
019 */
020
021package org.nuxeo.ecm.core.query.sql.model;
022
023import java.io.Serializable;
024
025import org.nuxeo.ecm.core.api.NuxeoPrincipal;
026
027/**
028 * @author Bogdan Stefanescu
029 * @author Florent Guillaume
030 */
031public class SQLQuery implements ASTNode {
032
033    private static final long serialVersionUID = 6383829486216039408L;
034
035    private String queryString;
036
037    public SelectClause select;
038
039    public final FromClause from;
040
041    public final WhereClause where;
042
043    public OrderByClause orderBy;
044
045    public final GroupByClause groupBy;
046
047    public final HavingClause having;
048
049    public long limit = 0;
050
051    public long offset = 0;
052
053    public SQLQuery() {
054        this(new SelectClause(), new FromClause(), null, null, null, null);
055    }
056
057    public SQLQuery(SelectClause select, FromClause from) {
058        this(select, from, null, null, null, null);
059    }
060
061    public SQLQuery(SelectClause select, FromClause from, WhereClause where) {
062        this(select, from, where, null, null, null);
063    }
064
065    public SQLQuery(SelectClause select, FromClause from, WhereClause where, OrderByClause orderBy) {
066        this(select, from, where, null, null, orderBy);
067    }
068
069    public SQLQuery(SelectClause select, FromClause from, WhereClause where, GroupByClause groupBy,
070            HavingClause having, OrderByClause orderBy) {
071        this.select = select;
072        this.from = from;
073        this.where = where;
074        this.groupBy = groupBy;
075        this.having = having;
076        this.orderBy = orderBy;
077    }
078
079    public SQLQuery(SelectClause select, FromClause from, WhereClause where, GroupByClause groupBy,
080            HavingClause having, OrderByClause orderBy, long limit, long offset) {
081        this.select = select;
082        this.from = from;
083        this.where = where;
084        this.groupBy = groupBy;
085        this.having = having;
086        this.orderBy = orderBy;
087        this.limit = limit;
088        this.offset = offset;
089    }
090
091    /**
092     * Copying constructor. Does not deep-copy the clauses though.
093     */
094    public SQLQuery(SQLQuery other) {
095        select = other.select;
096        from = other.from;
097        where = other.where;
098        orderBy = other.orderBy;
099        groupBy = other.groupBy;
100        having = other.having;
101        limit = other.limit;
102        offset = other.offset;
103    }
104
105    public SQLQuery withPredicate(Predicate predicate) {
106        return new SQLQuery(select, from, new WhereClause(predicate), groupBy, having, orderBy, limit, offset);
107    }
108
109    public SelectClause getSelectClause() {
110        return select;
111    }
112
113    public FromClause getFromClause() {
114        return from;
115    }
116
117    public WhereClause getWhereClause() {
118        return where;
119    }
120
121    public OrderByClause getOrderByClause() {
122        return orderBy;
123    }
124
125    @Override
126    public void accept(IVisitor visitor) {
127        visitor.visitQuery(this);
128    }
129
130    @Override
131    // FIXME: not finished
132    public String toString() {
133        if (queryString != null) {
134            return queryString;
135        }
136        StringBuilder sb = new StringBuilder();
137        sb.append("SELECT ").append(select).append(" FROM ").append(from);
138        if (where != null) {
139            sb.append(" WHERE ").append(where);
140        }
141        if (orderBy != null) {
142            sb.append(" ORDER BY ").append(orderBy);
143        }
144        return sb.toString();
145    }
146
147    public void setLimit(long limit) {
148        this.limit = limit;
149    }
150
151    public void setOffset(long offset) {
152        this.offset = offset;
153    }
154
155    public long getLimit() {
156        return limit;
157    }
158
159    public long getOffset() {
160        return offset;
161    }
162
163    public String getQueryString() {
164        return queryString;
165    }
166
167    public void setQueryString(String queryString) {
168        this.queryString = queryString;
169    }
170
171    @Override
172    public boolean equals(Object obj) {
173        if (this == obj) {
174            return true;
175        }
176        if (obj == null) {
177            return false;
178        }
179        if (getClass() != obj.getClass()) {
180            return false;
181        }
182        SQLQuery other = (SQLQuery) obj;
183        if (select == null) {
184            if (other.select != null) {
185                return false;
186            }
187        } else if (!select.equals(other.select)) {
188            return false;
189        }
190        if (from == null) {
191            if (other.from != null) {
192                return false;
193            }
194        } else if (!from.equals(other.from)) {
195            return false;
196        }
197        if (where == null) {
198            if (other.where != null) {
199                return false;
200            }
201        } else if (!where.equals(other.where)) {
202            return false;
203        }
204        if (orderBy == null) {
205            if (other.orderBy != null) {
206                return false;
207            }
208        } else if (!orderBy.equals(other.orderBy)) {
209            return false;
210        }
211        if (groupBy == null) {
212            if (other.groupBy != null) {
213                return false;
214            }
215        } else if (!groupBy.equals(other.groupBy)) {
216            return false;
217        }
218        if (having == null) {
219            if (other.having != null) {
220                return false;
221            }
222        } else if (!having.equals(other.having)) {
223            return false;
224        }
225        if (limit != other.limit) {
226            return false;
227        }
228        if (offset != other.offset) {
229            return false;
230        }
231        return true;
232    }
233
234    @Override
235    public int hashCode() {
236        final int prime = 31;
237        int result = 1;
238        result = prime * result + (select == null ? 0 : select.hashCode());
239        result = prime * result + (from == null ? 0 : from.hashCode());
240        result = prime * result + (where == null ? 0 : where.hashCode());
241        result = prime * result + (orderBy == null ? 0 : orderBy.hashCode());
242        result = prime * result + (groupBy == null ? 0 : groupBy.hashCode());
243        result = prime * result + (having == null ? 0 : having.hashCode());
244        result = prime * result + (int) (limit ^ (limit >>> 32));
245        result = prime * result + (int) (offset ^ (offset >>> 32));
246        return result;
247    }
248
249    /**
250     * Interface for a class that can transform a {@link SQLQuery} into another.
251     */
252    public interface Transformer {
253
254        Transformer IDENTITY = new IdentityTransformer();
255
256        SQLQuery transform(NuxeoPrincipal principal, SQLQuery query);
257    }
258
259    public static class IdentityTransformer implements Transformer {
260        @Override
261        public SQLQuery transform(NuxeoPrincipal principal, SQLQuery query) {
262            return query;
263        }
264    }
265
266}