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.join;
017
018import java.util.Objects;
019import java.util.Optional;
020
021import org.apache.solr.client.solrj.util.ClientUtils;
022
023import org.ametys.cms.search.query.JoinQuery;
024import org.ametys.cms.search.query.Query;
025import org.ametys.cms.search.query.QuerySyntaxException;
026
027/**
028 * Class representing a join key and its (optional) nested query for creating a {@link JoinQuery}
029 */
030public class JoinKey
031{
032    private String _key;
033    private Optional<String> _joinField;
034    private Optional<Query> _nestedQuery;
035    
036    /**
037     * Creates a JoinKey
038     * @param key The key. Cannot be null
039     */
040    public JoinKey(String key)
041    {
042        this(key, null, null);
043    }
044    
045    /**
046     * Creates a JoinKey
047     * @param key The key. Cannot be null
048     * @param nestedQuery The nested query of the join key. Can be null
049     */
050    public JoinKey(String key, Query nestedQuery)
051    {
052        this(key, null, nestedQuery);
053    }
054    
055    /**
056     * Creates a JoinKey
057     * @param key The key. Cannot be null
058     * @param joinField the field to join on. Can be null in which case "id_dv" will be assumed on Solr side.
059     * @param nestedQuery The nested query of the join key. Can be null
060     */
061    public JoinKey(String key, String joinField, Query nestedQuery)
062    {
063        if (key == null)
064        {
065            throw new IllegalArgumentException("The key of the JoinKey cannot be null");
066        }
067        
068        _key = key;
069        _joinField = Optional.ofNullable(joinField);
070        _nestedQuery = Optional.ofNullable(nestedQuery);
071    }
072    
073    /**
074     * Gets the key of the JoinKey
075     * @return the key of the JoinKey
076     */
077    public String getKey()
078    {
079        return _key;
080    }
081    
082    /**
083     * Returns the join field, if any.
084     * @return the join field, if any.
085     */
086    public Optional<String> getJoinField()
087    {
088        return _joinField;
089    }
090
091    /**
092     * Gets the optional nested query of the join key
093     * @return the optional nested query of the join key
094     */
095    public Optional<Query> getNestedQuery()
096    {
097        return _nestedQuery;
098    }
099    
100    /**
101     * Build the Solr {@link JoinQuery} part representing this {@link JoinKey}.
102     * @param escape if the nested query should be escaped
103     * @return a Solr query part
104     * @throws QuerySyntaxException if the query part can't be built because of a syntax error.
105     */
106    public String build(boolean escape) throws QuerySyntaxException
107    {
108        StringBuilder queryString = new StringBuilder();
109        
110        queryString.append(_key);
111        
112        if (_joinField.isPresent())
113        {
114            queryString.append('%').append(_joinField.get());
115        }
116       
117        if (_nestedQuery.isPresent())
118        {
119            String query = _nestedQuery.get().build();
120            queryString.append('[')
121                       .append(escape ? ClientUtils.escapeQueryChars(query) : query)
122                       .append(']');
123        }
124        
125        return queryString.toString();
126    }
127    
128    @Override
129    public int hashCode()
130    {
131        return Objects.hash(_key, _joinField, _nestedQuery);
132    }
133
134    @Override
135    public boolean equals(Object obj)
136    {
137        if (!(obj instanceof JoinKey other))
138        {
139            return false;
140        }
141        
142        return Objects.equals(_key, other._key)
143            && Objects.equals(_joinField, other._joinField)
144            && Objects.equals(_nestedQuery, other._nestedQuery);
145    }
146    
147    @Override
148    public String toString()
149    {
150        return "JoinKey(key=" + _key + ",joinField=" + _joinField.orElse("<none>") + ",nestedQuery=" + _nestedQuery.map(Query::toString).orElse("<none>") + ")";
151    }
152}