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     * Gets the query corresponding to the given contexts (as a collection of {@link ContextQueriesWrapper})
063     * <br>By passing an {@link Optional#empty() empty optional} or a {@link Function joiner}/{@link LangQueryProducer producer}, you are able to choose the part
064     * of the contexts you want to ignore/take account in the generated query.
065     * 
066     * @param contextQueriesWrappers The wrappers of {@link ContextQueriesWrapper context queries}
067     * @param siteQueryJoiner The joiner for the site query
068     * @param sitemapQueryJoiner The joiner for the sitemap query
069     * @param langQueryProducer The producer of the lang query
070     * @param tagQueryJoiner The joiner for the tag query
071     * @return the query corresponding to the given contexts
072     */
073    public static Query getQuery(
074            Collection<ContextQueriesWrapper> contextQueriesWrappers,
075            Optional<Function<Query, Query>> siteQueryJoiner,
076            Optional<Function<Query, Query>> sitemapQueryJoiner,
077            Optional<LangQueryProducer> langQueryProducer,
078            Optional<Function<Query, Query>> tagQueryJoiner)
079    {
080        return contextQueriesWrappers.stream()
081                    .map(LambdaUtils.wrap(cqw -> cqw._getQuery(siteQueryJoiner, sitemapQueryJoiner, langQueryProducer, tagQueryJoiner)))
082                    .collect(OrQuery.collector());
083    }
084    
085    private Query _getQuery(
086            Optional<Function<Query, Query>> siteQueryJoiner,
087            Optional<Function<Query, Query>> sitemapQueryJoiner,
088            Optional<LangQueryProducer> langQueryProducer,
089            Optional<Function<Query, Query>> tagQueryJoiner)
090        throws Exception
091    {
092        List<Query> queries = new ArrayList<>();
093        
094        if (_siteQuery != null && siteQueryJoiner.isPresent())
095        {
096            queries.add(siteQueryJoiner.get().apply(_siteQuery));
097        }
098        if (_sitemapQuery != null && sitemapQueryJoiner.isPresent())
099        {
100            queries.add(sitemapQueryJoiner.get().apply(_sitemapQuery));
101        }
102        if (_contextLangAndCurrentLang != null && langQueryProducer.isPresent())
103        {
104            queries.add(langQueryProducer.get().produce(_contextLangAndCurrentLang));
105        }
106        if (_tagQuery != null && tagQueryJoiner.isPresent())
107        {
108            queries.add(tagQueryJoiner.get().apply(_tagQuery));
109        }
110        
111        return new AndQuery(queries);
112    }
113}