/* * Copyright (C) 2010 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xcmis.search.model; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.xcmis.search.QueryObjectModelVisitor; import org.xcmis.search.VisitException; import org.xcmis.search.Visitors; import org.xcmis.search.model.column.Column; import org.xcmis.search.model.constraint.Constraint; import org.xcmis.search.model.ordering.Ordering; import org.xcmis.search.model.source.Source; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * @author <a href="mailto:Sergey.Kabashnyuk@exoplatform.org">Sergey Kabashnyuk</a> * @version $Id: Query.java 34360 2009-07-22 23:58:59Z ksm $ * */ public class Query implements QueryElement, Serializable { private static final long serialVersionUID = 1L; private final List<Column> columns; private final Constraint constraint; private final Limit limits; private final List<Ordering> orderings; private final Source source; /** * Object hash code. */ private final int hcode; /** * Create a new query that uses the supplied source. * * @param source * the source */ public Query(Source source) { this(source, null, Collections.<Ordering> emptyList(), Collections.<Column> emptyList(), Limit.NONE); } /** * Create a new query that uses the supplied source, constraint, orderings, * columns and limits. * * @param source * the source * @param constraint * the constraint (or composite constraint), or null or empty if * there are no constraints * @param orderings * the specifications of how the results are to be ordered, or null * if the order is to be implementation determined * @param columns * the columns to be included in the results, or null or empty if * there are no explicit columns and the actual result columns are * to be implementation determiend * @param limit * the limit for the results, or null if all of the results are to * be included * @param isDistinct * true if duplicates are to be removed from the results * @throws IllegalArgumentException * if the source is null */ public Query(Source source, Constraint constraint, List<Ordering> orderings, List<Column> columns, Limit limit) { Validate.notNull(source, "The source argument may not be null"); this.source = source; this.constraint = constraint; this.orderings = orderings != null ? orderings : Collections.<Ordering> emptyList(); this.limits = limit != null ? limit : Limit.NONE;; this.columns = columns != null ? columns : Collections.<Column> emptyList(); this.hcode = new HashCodeBuilder().append(this.source).append(this.constraint).append(this.columns).append(this.limits) .append(this.orderings).toHashCode(); } /** * @see org.xcmis.search.model.QueryElement#accept(org.xcmis.search.QueryObjectModelVisitor) */ public void accept(QueryObjectModelVisitor visitor) throws VisitException { visitor.visit(this); } /** * Create a copy of this query, but that returns results that include the * columns specified by this query as well as the supplied columns. * * @param columns * the additional columns that should be included in the the * results; may not be null * @return the copy of the query returning the supplied result columns; never * null */ public Query adding(Column... columns) { List<Column> newColumns = null; if (this.columns != null) { newColumns = new ArrayList<Column>(this.columns); for (Column column : columns) { newColumns.add(column); } } else { newColumns = Arrays.asList(columns); } return new Query(source, constraint, getOrderings(), newColumns, getLimits()); } /** * Create a copy of this query, but that returns results that are ordered by * the {@link #getOrderings() orderings} of this column as well as those * supplied. * * @param orderings * the additional orderings of the result rows; may no be null * @return the copy of the query returning the supplied result columns; never * null */ public Query adding(Ordering... orderings) { List<Ordering> newOrderings = null; if (this.getOrderings() != null) { newOrderings = new ArrayList<Ordering>(getOrderings()); for (Ordering ordering : orderings) { newOrderings.add(ordering); } } else { newOrderings = Arrays.asList(orderings); } return new Query(source, constraint, newOrderings, columns, getLimits()); } /** * Create a copy of this query, but one that uses the supplied constraint. * * @param constraint * the constraint that should be used; never null * @return the copy of the query that uses the supplied constraint; never * null */ public Query constrainedBy(Constraint constraint) { return new Query(source, constraint, getOrderings(), columns, getLimits()); } /** * Create a copy of this query, but one in which there are no duplicate rows * in the results. * * @return the copy of the query with no duplicate result rows; never null */ public Query distinct() { return new Query(source, constraint, getOrderings(), columns, getLimits()); } /** * {@inheritDoc} * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } if (obj.getClass() != getClass()) { return false; } Query rhs = (Query)obj; return new EqualsBuilder().append(source, rhs.source).append(constraint, rhs.constraint).append(columns, rhs.columns).append(limits, rhs.limits).isEquals(); } /** * Return the columns defining the query results. If there are no columns, * then the columns are implementation determined. * * @return the list of columns; never null */ public final List<Column> getColumns() { return columns; } /** * Get the constraints, if there are any. * * @return the constraint; may be null */ public final Constraint getConstraint() { return constraint; } /** * Get the limits associated with this query. * * @return the limits; never null but possibly {@link Limit#isUnlimited() * unlimited} */ public final Limit getLimits() { return limits; } /** * Return the orderings for this query. * * @return the list of orderings; never null */ public final List<Ordering> getOrderings() { return orderings; } /** * Get the source for the results. * * @return the query source; never null */ public final Source getSource() { return source; } /** * Create a copy of this query, but one whose results should be ordered by * the supplied orderings. * * @param orderings * the result ordering specification that should be used; never * null * @return the copy of the query that uses the supplied ordering; never null */ public Query orderedBy(List<Ordering> orderings) { return new Query(source, constraint, orderings, columns, getLimits()); } /** * Create a copy of this query, but that returns results with the supplied * columns. * * @param columns * the columns of the results; may not be null * @return the copy of the query returning the supplied result columns; never * null */ public Query returning(List<Column> columns) { return new Query(source, constraint, getOrderings(), columns, getLimits()); } /** * Create a copy of this query, but one that uses the supplied limit on the * number of result rows. * * @param rowLimit * the limit that should be used; must be a positive number * @return the copy of the query that uses the supplied limit; never null */ public Query withLimit(int rowLimit) { return new Query(source, constraint, getOrderings(), columns, getLimits().withRowLimit(rowLimit)); } /** * Create a copy of this query, but one that uses the supplied offset. * * @param offset * the limit that should be used; may not be negative * @return the copy of the query that uses the supplied offset; never null */ public Query withOffset(int offset) { return new Query(source, constraint, getOrderings(), columns, getLimits().withOffset(offset)); } /** * {@inheritDoc} * * @see java.lang.Object#toString() */ @Override public String toString() { return Visitors.readable(this); } /** * {@inheritDoc} * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return hcode; } }