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.dialect;
021
022import net.sf.jkniv.sqlegance.dialect.AnsiDialect;
023import net.sf.jkniv.sqlegance.dialect.SqlFeatureFactory;
024import net.sf.jkniv.sqlegance.dialect.SqlFeatureSupport;
025import net.sf.jkniv.sqlegance.params.ParamMarkType;
026import net.sf.jkniv.whinstone.params.ParameterException;
027
028/**
029 * Dialect to CouchDB
030 * 
031 * <p>
032 * Limit clause:
033 *  <pre>
034 *  {
035 *    "selector": {
036 *      "year": {"$gt": 2010}
037 *    },
038 *    "fields": ["_id", "_rev", "year", "title"],
039 *    "sort": [{"year": "asc"}],
040 *    "limit": 2,
041 *    "skip": 0
042 *  }
043 *  </pre>
044 * 
045 * <ul>
046 *  <li>Supports limits? true</li>
047 *  <li>Supports limit off set? true</li>
048 *  <li>Supports rownum? false</li>
049 * </ul>
050 *
051 * @author Alisson Gomes 
052 * @since 0.6.0
053 * @see <a href="https://docs.couchdb.org/en/2.1.2/api/database/find.html">Find Pagination</a>
054 */
055public class CouchDbDialect2o0 extends AnsiDialect
056{
057    public CouchDbDialect2o0()
058    {
059        super();
060        addFeature(SqlFeatureFactory.newInstance(SqlFeatureSupport.LIMIT, true));
061        addFeature(SqlFeatureFactory.newInstance(SqlFeatureSupport.LIMIT_OFF_SET, true));
062        addFeature(SqlFeatureFactory.newInstance(SqlFeatureSupport.BOOKMARK_QUERY, false));//couchdb 2.0 doesn't support bookmark
063        addFeature(SqlFeatureFactory.newInstance(SqlFeatureSupport.CONN_HOLDABILITY, false));
064        addFeature(SqlFeatureFactory.newInstance(SqlFeatureSupport.PAGING_ROUNDTRIP, false));
065    }
066    
067    @Override
068    public String buildQueryPaging(final String sqlText, int offset, int max)
069    {
070        String bodyWithLimitAndSkip = sqlText;
071        int offsetLimit = sqlText.indexOf("\"limit\"");
072        if (offsetLimit > -1)
073            throw new ParameterException("Query [" + sqlText
074                    + "] has a \"limit\" property defined, cannot use auto paging Queryable for this query.");
075        
076        int offsetBracket = sqlText.lastIndexOf("}");
077        if (offsetBracket >= 0)
078            bodyWithLimitAndSkip = sqlText.substring(0, offsetBracket) 
079                                    + "\n,\"limit\": " + max + ", \"skip\": " + offset + " }";
080        return bodyWithLimitAndSkip;        
081    }
082
083    @Override
084    public String buildQueryPaging(final String sqlText, int offset, int max, String bookmark)
085    {
086        String bodyWithLimitAndSkip = sqlText;
087        int offsetLimit = sqlText.indexOf("\"limit\"");
088        if (offsetLimit > -1)
089            throw new ParameterException("Query [" + sqlText
090                    + "] has a \"limit\" property defined, cannot use auto paging Queryable for this query.");
091        
092        int offsetBracket = sqlText.lastIndexOf("}");
093        if (offsetBracket >= 0)
094            bodyWithLimitAndSkip = sqlText.substring(0, offsetBracket) 
095                                    + "\n,\"limit\": " + max + ", \"skip\": " + offset + 
096                                    (bookmark != null ? ", \"bookmark\": \"" + bookmark + "\"": "")
097                                    + " }";
098        return bodyWithLimitAndSkip;        
099    }
100
101    @Override
102    public boolean supportsParmMark(ParamMarkType paramParse)
103    {
104        return paramParse != ParamMarkType.DOLLAR;
105    }
106
107    @Override
108    public String buildQueryCount(String sqlText)
109    {
110        return sqlText;
111    }
112}