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.time.LocalDateTime;
019import java.time.ZoneId;
020import java.time.ZoneOffset;
021import java.time.ZonedDateTime;
022
023import org.apache.solr.client.solrj.util.ClientUtils;
024
025import org.ametys.core.util.date.AdaptableDate;
026import org.ametys.core.util.date.AdaptableDate.DateTimeInterval;
027
028/**
029 * Represents a {@link Query} testing a datetime field.
030 */
031public class DateTimeQuery extends AbstractDateOperatorQuery
032{
033    /**
034     * Build a DateQuery testing the existence of the field.
035     * @param fieldPath the field path.
036     */
037    public DateTimeQuery(String fieldPath)
038    {
039        this(fieldPath, Operator.EXISTS, (AdaptableDate) null);
040    }
041    
042    /**
043     * Build a DateQuery.
044     * @param fieldPath the field's path
045     * @param value the value.
046     */
047    public DateTimeQuery(String fieldPath, ZonedDateTime value)
048    {
049        this(fieldPath, AdaptableDate.fromDateTime(value.withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime()));
050    }
051    
052    /**
053     * Build a DateQuery.
054     * @param fieldPath the field's path
055     * @param value the value.
056     */
057    public DateTimeQuery(String fieldPath, AdaptableDate value)
058    {
059        this(fieldPath, Operator.EQ, value);
060    }
061    
062    /**
063     * Build a DateQuery.
064     * @param fieldPath the field's path
065     * @param op the operator.
066     * @param value the value.
067     */
068    public DateTimeQuery(String fieldPath, Operator op, ZonedDateTime value)
069    {
070        this(fieldPath, op, AdaptableDate.fromDateTime(value.withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime()));
071    }
072    
073    /**
074     * Build a DateQuery.
075     * @param fieldPath the field's path
076     * @param op the operator.
077     * @param value the value.
078     */
079    public DateTimeQuery(String fieldPath, Operator op, AdaptableDate value)
080    {
081        super(fieldPath + "_dt", op, value);
082    }
083
084    @Override
085    protected void appendDateValue(StringBuilder query, Operator operator, AdaptableDate value)
086    {
087        DateTimeInterval interval = value.resolveDateTime();
088        
089        LocalDateTime min = interval.min();
090        ZonedDateTime minDateTime = min.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC);
091        String minStrValue = minDateTime.format(DATE_FORMATTER);
092        
093        LocalDateTime max = interval.max();
094        ZonedDateTime maxDateTime = max.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC);
095        String maxStrValue = maxDateTime.format(DATE_FORMATTER);
096        
097        if (operator == Operator.EQ || operator == Operator.NE)
098        {
099            if (min.equals(max))
100            {
101                query.append(ClientUtils.escapeQueryChars(minStrValue));
102            }
103            else
104            {
105                query.append('[').append(minStrValue).append(" TO ").append(maxStrValue).append(']');
106            }
107            
108            return;
109        }
110        else if (operator == Operator.GT)
111        {
112            query.append('{').append(minStrValue).append(" TO *]");
113        }
114        else if (operator == Operator.GE)
115        {
116            query.append('[').append(minStrValue).append(" TO *]");
117        }
118        else if (operator == Operator.LT)
119        {
120            query.append("[* TO ").append(maxStrValue).append('}');
121        }
122        else if (operator == Operator.LE)
123        {
124            query.append("[* TO ").append(maxStrValue).append(']');
125        }
126    }
127}