001/* 
002 * JKNIV, whinstone one contract to access your database.
003 * 
004 * Copyright (C) 2017, the original author or authors.
005 *
006 * This library is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 2.1 of the License.
010 * 
011 * This library is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with this library; if not, write to the Free Software Foundation, Inc., 
018 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
019 */
020package net.sf.jkniv.whinstone.couchdb.commands;
021
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030import net.sf.jkniv.sqlegance.RepositoryException;
031import net.sf.jkniv.sqlegance.Sql;
032import net.sf.jkniv.sqlegance.SqlContext;
033import net.sf.jkniv.whinstone.couchdb.HttpBuilder;
034
035/**
036 * 
037 * FIXME design CouchDb 
038 * http://docs.couchdb.org/en/2.0.0/api/ddoc/common.html
039 *  PUT /{db}/_design/{ddoc}
040 *
041 *  The PUT method creates a new named design document, or creates a new revision of the existing design document.
042 *
043 *  The design documents have some agreement upon their fields and structure. Currently it is the following:
044 *
045 *      language (string): Defines Query Server key to process design document functions
046 *      options (object): View’s default options
047 *      filters (object): Filter functions definition
048 *      lists (object): List functions definition
049 *      rewrites (array or string): Rewrite rules definition
050 *      shows (object): Show functions definition
051 *      updates (object): Update functions definition
052 *      validate_doc_update (string): Validate document update function source
053 *      views (object): View functions definition.
054 *
055 *  Note, that for filters, lists, shows and updates fields objects are mapping of function name to string function source code. 
056 *  For views mapping is the same except that values are objects with map and reduce (optional) keys which also contains 
057 *  functions source code.
058 *
059 *
060 * @author Alisson Gomes
061 * @since 0.6.0
062 */
063public class CouchDbSynchViewDesign
064{
065    private final static Logger LOG = LoggerFactory.getLogger(CouchDbSynchViewDesign.class);
066    private final SqlContext    sqlContext;
067    private final HttpBuilder   httpBuilder;
068    
069    public CouchDbSynchViewDesign(final HttpBuilder httpBuilder, final SqlContext sqlContext)
070    {
071        this.sqlContext = sqlContext;
072        this.httpBuilder = httpBuilder;
073    }
074    
075    public void update()
076    {
077        Map<String, List<Sql>> queries = sqlContext.getPackageStartWith("_design");
078        for (String packet : queries.keySet())
079        {
080            List<Sql> sqls = queries.get(packet);
081            DesignViewCommand command = new DesignViewCommand(httpBuilder, packet);
082            Map<String, ViewFunction> views = new HashMap<String, ViewFunction>();
083            for (Sql sql : sqls)
084            {
085                String name = null;
086                boolean map = true;
087                if(sql.getName().startsWith("index#"))
088                    continue;
089                else if (sql.getName().startsWith("map#"))
090                    name = sql.getName().substring(4);
091                else if (sql.getName().startsWith("reduce#"))
092                {
093                    name = sql.getName().substring(7);
094                    map = false;
095                }
096                else 
097                    throw new RepositoryException("Cannot build " + packet
098                            + " view from docs. The queries must be start with 'map#' | 'reduce#' | 'index#' name");
099                
100                ViewFunction view = views.get(name);
101                if (view == null)
102                {
103                    view = new ViewFunction(name);
104                    views.put(name, view);
105                }
106                if (map)
107                    view.setMap(sql.getSql());
108                else
109                    view.setReduce(sql.getSql());
110            }
111            command.add(views.values());
112            command.execute();
113            //LOG.info("Updating view _design with view [{}]", sql.getName());
114        }
115        LOG.info("Host [{}] had [{}] views design updated", httpBuilder.getHostContext(), queries.size());
116    }
117}