001/*
002 *  Copyright 2017 Anyware Services
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 */
016package org.ametys.cms.search.query;
017
018import java.util.Arrays;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.List;
022import java.util.stream.Collectors;
023
024import org.apache.commons.lang3.StringUtils;
025
026/**
027 * Represents a search {@link Query} corresponding to the logical "and" between several other queries.
028 */
029public class AndQuery implements Query
030{
031    
032    /** The list of queries. The queries on this list are distinct. */
033    protected List<Query> _queries;
034    /** If a query is empty should just ignore it, or return an empty AndQuery */
035    protected boolean _ignoreEmptyQueries;
036    
037    /**
038     * Build an AndQuery object.
039     * @param queries the queries.
040     */
041    public AndQuery(Query... queries)
042    {
043        this(true, queries);
044    }
045    
046    /**
047     * Build an AndQuery object.
048     * @param ignoreEmptyQueries If a query is empty should just ignore it, or return an empty AndQuery
049     * @param queries the queries.
050     */
051    public AndQuery(boolean ignoreEmptyQueries, Query... queries)
052    {
053        this(ignoreEmptyQueries, Arrays.asList(queries));
054    }
055    
056    /**
057     * Build an AndQuery object.
058     * @param queries the queries as a Collection.
059     */
060    public AndQuery(Collection<Query> queries)
061    {
062        this(true, queries);
063    }
064    
065    /**
066     * Build an AndQuery object.
067     * @param ignoreEmptyQueries If a query is empty should just ignore it, or return an empty AndQuery
068     * @param queries the queries as a Collection.
069     */
070    public AndQuery(boolean ignoreEmptyQueries, Collection<Query> queries)
071    {
072        _queries = queries.stream().distinct().collect(Collectors.toList());
073        _ignoreEmptyQueries = ignoreEmptyQueries;
074    }
075    
076    /**
077     * Get the list of queries in this "and".
078     * @return the list of queries.
079     */
080    public List<Query> getQueries()
081    {
082        return Collections.unmodifiableList(_queries);
083    }
084    
085    @Override
086    public String build() throws QuerySyntaxException
087    {
088        boolean isFirst = true;
089        StringBuilder sb = new StringBuilder();
090        
091        if (_queries.size() > 1)
092        {
093            sb.append('(');
094        }
095        
096        for (Query subQuery : _queries)
097        {
098            if (subQuery != null)
099            {
100                String exprAsString = subQuery.build();
101                if (StringUtils.isNotBlank(exprAsString))
102                {
103                    if (!isFirst)
104                    {
105                        sb.append(" AND ");
106                    }
107                    sb.append(exprAsString);
108                    isFirst = false;
109                }    
110                else if (!_ignoreEmptyQueries)
111                {
112                    return "";
113                }
114            }
115        }
116        
117        if (isFirst)
118        {
119            return "";
120        }
121        else
122        {
123            if (_queries.size() > 1)
124            {
125                sb.append(')');
126            }
127            return sb.toString();
128        }
129    }
130
131    @Override
132    public int hashCode()
133    {
134        final int prime = 31;
135        int result = 1;
136        result = prime * result + (_ignoreEmptyQueries ? 1231 : 1237);
137        result = prime * result + ((_queries == null) ? 0 : _queries.hashCode());
138        return result;
139    }
140
141    @Override
142    public boolean equals(Object obj)
143    {
144        if (this == obj)
145        {
146            return true;
147        }
148        if (obj == null)
149        {
150            return false;
151        }
152        if (getClass() != obj.getClass())
153        {
154            return false;
155        }
156        AndQuery other = (AndQuery) obj;
157        if (_ignoreEmptyQueries != other._ignoreEmptyQueries)
158        {
159            return false;
160        }
161        if (_queries == null)
162        {
163            if (other._queries != null)
164            {
165                return false;
166            }
167        }
168        else if (!_queries.equals(other._queries))
169        {
170            return false;
171        }
172        return true;
173    }
174}