001/*
002 *  Copyright 2022 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.Objects;
019
020/**
021 * Base class for all range-based queries.
022 * @param <T> the value type.
023 */
024public abstract class AbstractRangeQuery<T> implements Query
025{
026    private String _fieldName;
027    private T _lower;
028    private T _upper;
029    private boolean _includeLower;
030    private boolean _includeUpper;
031
032    /**
033     * Build a range query.
034     * @param fieldName The field path.
035     * @param lowerBound The lower end of the range.
036     * @param upperBound The upper end of the range.
037     * @param includeLower Whether to include the lower end or not.
038     * @param includeUpper Whether to include the upper end or not.
039     */
040    public AbstractRangeQuery(String fieldName, T lowerBound, T upperBound, boolean includeLower, boolean includeUpper)
041    {
042        _fieldName = fieldName;
043        _lower = lowerBound;
044        _upper = upperBound;
045        _includeLower = includeLower;
046        _includeUpper = includeUpper;
047    }
048    
049    /**
050     * Returns the Solr field name.
051     * @return the field name
052     */
053    public String getFieldName()
054    {
055        return _fieldName;
056    }
057    
058    /**
059     * Returns true if the query should include the lower bound.
060     * @return true if the query should include the lower bound.
061     */
062    public boolean includeLowerBound()
063    {
064        return _includeLower;
065    }
066    
067    /**
068     * Returns true if the query should include the upper bound.
069     * @return true if the query should include the upper bound.
070     */
071    public boolean includeUpperBound()
072    {
073        return _includeUpper;
074    }
075    
076    /**
077     * Returns the lower bound of the range.
078     * @return the lower bound of the range.
079     */
080    public T getLowerBound()
081    {
082        return _lower;
083    }
084    
085    /**
086     * Returns the upper bound of the range.
087     * @return the upper bound of the range.
088     */
089    public T getUpperBound()
090    {
091        return _upper;
092    }
093    
094    /**
095     * Computes the lower bound for Solr client
096     * @param value the typed value
097     * @return the value, adapted for Solr
098     */
099    public String lowerBoundForQuery(T value)
100    {
101        return value.toString();
102    }
103    
104    /**
105     * Computes the upper bound for Solr client
106     * @param value the typed value
107     * @return the value, adapted for Solr
108     */
109    public String upperBoundForQuery(T value)
110    {
111        return value.toString();
112    }
113    
114    public String build() throws QuerySyntaxException
115    {
116        StringBuilder query = new StringBuilder();
117        
118        query.append(getFieldName())
119             .append(includeLowerBound() ? '[' : '{')
120             .append(lowerBoundForQuery(getLowerBound())).append(" TO ").append(upperBoundForQuery(getUpperBound()))
121             .append(includeUpperBound() ? ']' : '}');
122        
123        return query.toString();
124    }
125
126    @Override
127    public int hashCode()
128    {
129        return Objects.hash(_fieldName, _lower, _upper, _includeLower, _includeUpper);
130    }
131
132    @Override
133    public boolean equals(Object obj)
134    {
135        if (this == obj)
136        {
137            return true;
138        }
139        
140        if (obj == null || getClass() != obj.getClass())
141        {
142            return false;
143        }
144        
145        AbstractRangeQuery other = (AbstractRangeQuery) obj;
146        return Objects.equals(_fieldName, other._fieldName)
147                && Objects.equals(_lower, other._lower)
148                && Objects.equals(_upper, other._upper)
149                && Objects.equals(_includeLower, other._includeLower)
150                && Objects.equals(_includeUpper, other._includeUpper);
151    }
152}