001/*
002 *  Copyright 2019 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.Objects;
020
021import org.apache.commons.lang3.StringUtils;
022import org.apache.solr.client.solrj.util.ClientUtils;
023
024/**
025 * <b>The use of this Query is discouraged. If possible (when from=id), use {@link JoinQuery} instead.</b>
026 * <br>Represents a Solr Join Query
027 */
028public class SolrNativeJoinQuery implements Query
029{
030    /** The "from" field of the join (the query is done on docs which hold this field) */
031    protected String _fromField;
032    /** The "to" field of the join (returned docs hold this field) */
033    protected String _toField;
034    /** The query to apply on joined docs */
035    protected Query _subQuery;
036    
037    /**
038     * <b>The use of this Query is discouraged. If possible (when from=id), use {@link JoinQuery} instead.</b>
039     * <br>Build a solr join query
040     * @param from The "from" field of the join (the query is done on docs which hold this field)
041     * @param to The "to" field of the join (returned docs holds this field)
042     * @param subQuery The sub query (query to apply on joined docs)
043     */
044    public SolrNativeJoinQuery(String from, String to, Query subQuery)
045    {
046        _fromField = from;
047        _toField = to;
048        _subQuery = subQuery;
049    }
050    
051    @Override
052    public String build() throws QuerySyntaxException
053    {
054        StringBuilder sb = new StringBuilder("{!join")
055                .append(" from=").append(_fromField)
056                .append(" to=").append(_toField)
057                .append(" v=\"").append(ClientUtils.escapeQueryChars(_subQuery.build())).append("\"")
058                .append("}");
059        return sb.toString();
060    }
061    
062    public Object buildAsJson() throws QuerySyntaxException
063    {
064        return Map.of("join", Map.of("from", _fromField,
065                                     "to", _toField,
066                                     "query", _subQuery.buildAsJson()));
067    }
068    
069    @Override
070    public String toString(int indent)
071    {
072        final String joinLineIndent = StringUtils.repeat(' ', indent);
073        final int subIndent = indent + 2;
074        final String subLineIndent = StringUtils.repeat(' ', subIndent);
075        final String from = subLineIndent + "[FROM]" + _fromField + "[/FROM]";
076        final String to = subLineIndent + "[TO]" + _toField + "[/TO]";
077        final String subq = subLineIndent + "[Q]" + (_subQuery == null ? String.valueOf(_subQuery) : ("\n" + _subQuery.toString(subIndent + 2) + "\n" + subLineIndent)) + "[/Q]";
078        return joinLineIndent + "[SOLRJOIN]\n" + from + "\n" + to + "\n" + subq + "\n" + joinLineIndent + "[/SOLRJOIN]";
079    }
080
081    @Override
082    public int hashCode()
083    {
084        return Objects.hash(_fromField, _subQuery, _toField);
085    }
086
087    @Override
088    public boolean equals(Object obj)
089    {
090        if (this == obj)
091        {
092            return true;
093        }
094        
095        if (obj == null || getClass() != obj.getClass())
096        {
097            return false;
098        }
099        
100        SolrNativeJoinQuery other = (SolrNativeJoinQuery) obj;
101        return Objects.equals(_fromField, other._fromField) 
102            && Objects.equals(_subQuery, other._subQuery) 
103            && Objects.equals(_toField, other._toField);
104    }
105}