001/*
002 *  Copyright 2023 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.Map;
019import java.util.Optional;
020
021import org.apache.commons.lang.StringUtils;
022import org.apache.solr.client.solrj.util.ClientUtils;
023
024/**
025 * A fuzzy query is meant to search for approximatively matching terms.<br>
026 * It works by wrapping another query. Only queries translating to Solr's BooleanQuery or TermQuery may be "fuzzied" this way.
027 * Furthermore, it obvisouly only makes sense for text queries, even it'd technically work for dates, numbers, ... 
028 */
029public class FuzzyQuery extends AbstractWrapperQuery
030{
031    /**
032     * Build a fuzzy query.
033     * @param query the wrapped {@link Query}.
034     */
035    public FuzzyQuery(Query query)
036    {
037        super(query);
038    }
039    
040    public String build() throws QuerySyntaxException
041    {
042        String build = getSubQuery().build();
043        if (StringUtils.isBlank(build))
044        {
045            build = new MatchAllQuery().build();
046        }
047        
048        StringBuilder sb = new StringBuilder()
049                .append("{!fuzzy v=\"")
050                .append(ClientUtils.escapeQueryChars(build))
051                .append("\"}");
052        return sb.toString();
053    }
054    
055    public Optional<Object> buildAsJson() throws QuerySyntaxException
056    {
057        Optional<Object> json = getSubQuery().buildAsJson();
058        if (json.isPresent() && json.get() instanceof String jsonStr && StringUtils.isBlank(jsonStr))
059        {
060            json = new MatchAllQuery().buildAsJson();
061        }
062        
063        return json.map(q -> Map.of("fuzzy", Map.of("query", q)));
064    }
065}