001/* 
002 * JKNIV, SQLegance keeping queries maintainable.
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.sqlegance.params;
021
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026import java.util.regex.Matcher;
027import java.util.regex.Pattern;
028
029public class ParamParserDollarMark extends AbstractParamParser
030{
031    private static final Pattern PATTERN_PARAMS = Pattern.compile(REGEX_DOLLAR_MARK, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
032    private static final ParamParser INSTANCE = new ParamParserDollarMark();
033    
034    private ParamParserDollarMark()
035    {
036    }
037
038    public static ParamParser getInstance()
039    {
040        return INSTANCE;
041    }
042    
043    @Override
044    Pattern getPatternParams()
045    {
046        return PATTERN_PARAMS;
047    }
048
049    @Override
050    public String[] find(String query)
051    {
052        return parserDollar(query).toArray(new String[0]);
053    }
054    
055    @Override
056    public ParamMarkType getType()
057    {
058        return ParamMarkType.DOLLAR;
059    }
060    
061    /**
062     * Is {@code $}
063     */
064    @Override
065    public String getPlaceholder()
066    {
067        return "$";
068    }
069    
070    private List<String> parserDollar(final String sentence)
071    {
072        List<String> params = new ArrayList<String>();
073        Matcher matcherDollar = PATTERN_PARAMS.matcher(sentence);
074        int i = 0;
075        while (matcherDollar.find())
076        {
077            if (matcherDollar.group().startsWith("'"))
078            {
079                continue;
080            }
081            else if (matcherDollar.group().startsWith(":in:"))
082            {
083                params.add(i++, sentence.subSequence(matcherDollar.start() + 1, matcherDollar.end()).toString());
084                continue;
085            }
086            //System.out.printf("group[%s] [%s]\n", matcherTwoDots.group(), sentence.subSequence(matcherTwoDots.start() + 1, matcherTwoDots.end()).toString());
087            params.add(i++, sentence.subSequence(matcherDollar.start() + 1, matcherDollar.end()).toString());
088        }
089        return params;
090    }   
091    
092    
093    @Override
094    public String replaceForPlaceholder(String query, Object params)
095    {
096        return replaceForPlaceholderWithNumber(query, params);
097    }
098    
099    @Override
100    public String replaceForPlaceholderWithNumber(String query, Object params)
101    {
102        StringBuffer sb = new StringBuffer(query);
103        Matcher matcherTwoDots = getPatternParams().matcher(query);
104        Map<String, String> mapForINClauseParams = new HashMap<String, String>();
105        int startIndex = 0;
106        int endIndex = 0;
107        int index = 1;
108        while (matcherTwoDots.find())
109        {
110            String match = matcherTwoDots.group();
111            if (match.startsWith("'"))
112                continue;
113            if (match.startsWith(":in:"))
114            {
115                String paramName = match.substring(4, match.length());
116                Object[] paramsAsArray = getParamsClauseIN(params, paramName);
117                if (paramsAsArray != null 
118                        && paramsAsArray.length > 0 && !mapForINClauseParams.containsKey(match))
119                {
120                    StringBuilder tmp = new StringBuilder();
121                    for(int i=0; i<paramsAsArray.length; i++)
122                        tmp.append( i>0? "," : "")
123                           .append("\\"+getPlaceholder()+index++);
124                    
125                    mapForINClauseParams.put(match, tmp.toString());
126                }
127            }
128            else
129            {
130                startIndex = matcherTwoDots.start();
131                endIndex = matcherTwoDots.end();
132                sb.replace(startIndex, endIndex, padspace(endIndex - startIndex, index++));
133            }
134        }
135        if (!mapForINClauseParams.isEmpty())
136        {
137            String newSql = sb.toString();
138            for(String key : mapForINClauseParams.keySet())
139                newSql = newSql.replaceAll(key, mapForINClauseParams.get(key));
140            
141            sb = new StringBuffer(newSql);
142        }
143        return sb.toString();
144    }    
145
146}