001/*
002 *  Copyright 2018 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.web.frontoffice.search.metamodel.context;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.List;
021import java.util.Optional;
022import java.util.function.Function;
023
024import org.ametys.cms.search.query.AndQuery;
025import org.ametys.cms.search.query.OrQuery;
026import org.ametys.cms.search.query.Query;
027import org.ametys.core.util.LambdaUtils;
028import org.ametys.web.frontoffice.search.instance.model.ContextLang;
029import org.ametys.web.frontoffice.search.instance.model.SearchContext.ContextLangAndCurrentLang;
030import org.ametys.web.frontoffice.search.instance.model.SearchContext.LangQueryProducer;
031import org.ametys.web.frontoffice.search.metamodel.Returnable;
032
033/**
034 * A wrapper of {@link Query queries} about a search context.
035 * <br>Use {@link #getQuery} by {@link Returnable}s in order to choose
036 * the part for each Context the {@link Returnable} cares about (by passing an {@link Optional#empty() empty optional} or a {@link Function joiner}/{@link LangQueryProducer producer})
037 * and transform it to a {@link Query}.
038 */
039public class ContextQueriesWrapper
040{
041    private Query _siteQuery;
042    private Query _sitemapQuery;
043    private ContextLangAndCurrentLang _contextLangAndCurrentLang;
044    private Query _tagQuery;
045    
046    /**
047     * Creates a wrapper of Context Queries (site, sitemap, lang, tag).
048     * @param siteQuery The site query
049     * @param sitemapQuery The sitemap query
050     * @param contextLangAndCurrentLang The wrapper of {@link ContextLang} and the current lang
051     * @param tagQuery The tag query
052     */
053    public ContextQueriesWrapper(Query siteQuery, Query sitemapQuery, ContextLangAndCurrentLang contextLangAndCurrentLang, Query tagQuery)
054    {
055        _siteQuery = siteQuery;
056        _sitemapQuery = sitemapQuery;
057        _contextLangAndCurrentLang = contextLangAndCurrentLang;
058        _tagQuery = tagQuery;
059    }
060    
061    /**
062     * Get the site query
063     * @return the site query
064     */
065    public Optional<Query> getSiteQuery()
066    {
067        return Optional.ofNullable(_siteQuery);
068    }
069    
070    /**
071     * Get the sitemap query
072     * @return the sitemap query
073     */
074    public Optional<Query> getSitemapQuery()
075    {
076        return Optional.ofNullable(_sitemapQuery);
077    }
078    
079    /**
080     * Get the context lang and current lang
081     * @return the context lang and current lang
082     */
083    public Optional<ContextLangAndCurrentLang> getContextLangAndCurrentLang()
084    {
085        return Optional.ofNullable(_contextLangAndCurrentLang);
086    }
087    
088    /**
089     * Get the tag query
090     * @return the tag query
091     */
092    public Optional<Query> getTagQuery()
093    {
094        return Optional.ofNullable(_tagQuery);
095    }
096    
097    /**
098     * Gets the query corresponding to the given contexts (as a collection of {@link ContextQueriesWrapper})
099     * <br>By passing an {@link Optional#empty() empty optional} or a {@link Function joiner}/{@link LangQueryProducer producer}, you are able to choose the part
100     * of the contexts you want to ignore/take account in the generated query.
101     * 
102     * @param contextQueriesWrappers The wrappers of {@link ContextQueriesWrapper context queries}
103     * @param siteQueryJoiner The joiner for the site query
104     * @param sitemapQueryJoiner The joiner for the sitemap query
105     * @param langQueryProducer The producer of the lang query
106     * @param tagQueryJoiner The joiner for the tag query
107     * @return the query corresponding to the given contexts
108     */
109    public static Query getQuery(
110            Collection<ContextQueriesWrapper> contextQueriesWrappers,
111            Optional<Function<Query, Query>> siteQueryJoiner,
112            Optional<Function<Query, Query>> sitemapQueryJoiner,
113            Optional<LangQueryProducer> langQueryProducer,
114            Optional<Function<Query, Query>> tagQueryJoiner)
115    {
116        return contextQueriesWrappers.stream()
117                    .map(LambdaUtils.wrap(cqw -> cqw._getQuery(siteQueryJoiner, sitemapQueryJoiner, langQueryProducer, tagQueryJoiner)))
118                    .collect(OrQuery.collector());
119    }
120    
121    private Query _getQuery(
122            Optional<Function<Query, Query>> siteQueryJoiner,
123            Optional<Function<Query, Query>> sitemapQueryJoiner,
124            Optional<LangQueryProducer> langQueryProducer,
125            Optional<Function<Query, Query>> tagQueryJoiner)
126        throws Exception
127    {
128        List<Query> queries = new ArrayList<>();
129        
130        if (_siteQuery != null && siteQueryJoiner.isPresent())
131        {
132            queries.add(siteQueryJoiner.get().apply(_siteQuery));
133        }
134        if (_sitemapQuery != null && sitemapQueryJoiner.isPresent())
135        {
136            queries.add(sitemapQueryJoiner.get().apply(_sitemapQuery));
137        }
138        if (_contextLangAndCurrentLang != null && langQueryProducer.isPresent())
139        {
140            queries.add(langQueryProducer.get().produce(_contextLangAndCurrentLang));
141        }
142        if (_tagQuery != null && tagQueryJoiner.isPresent())
143        {
144            queries.add(tagQueryJoiner.get().apply(_tagQuery));
145        }
146        
147        return new AndQuery(queries);
148    }
149}