/**
* SQL-DK
* Copyright © 2013 František Kučera (frantovo.cz)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package info.globalcode.sql.dk;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author Ing. František Kučera (frantovo.cz)
*/
public class CLIParser {
public static final String TYPE_NAME_SEPARATOR = ":";
private final Map<String, Integer> types;
public CLIParser() {
Map<String, Integer> m = new HashMap<>();
m.put("int", Types.INTEGER);
m.put("string", Types.VARCHAR);
m.put("boolean", Types.BOOLEAN);
/**
* TODO: more types
*/
types = Collections.unmodifiableMap(m);
}
public CLIOptions parseOptions(String[] args) throws CLIParserException {
CLIOptions options = new CLIOptions();
List<Integer> numberedTypes = new ArrayList<>();
Map<String, Integer> namedTypes = new HashMap<>();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
switch (arg) {
case Tokens.TYPES:
String typesString = fetchNext(args, ++i);
for (String oneType : typesString.split(",")) {
int sepatratorIndex = oneType.indexOf(TYPE_NAME_SEPARATOR);
if (sepatratorIndex == -1) {
numberedTypes.add(getType(oneType));
} else {
String namePart = oneType.substring(0, sepatratorIndex).trim();
String typePart = oneType.substring(sepatratorIndex + TYPE_NAME_SEPARATOR.length(), oneType.length());
namedTypes.put(namePart, getType(typePart));
}
}
break;
case Tokens.NAME_PREFIX:
options.setNamePrefix(fetchNext(args, ++i));
break;
case Tokens.DB:
options.setDatabaseName(fetchNext(args, ++i));
break;
case Tokens.SQL:
options.setSql(fetchNext(args, ++i));
options.setCommandType(CLIOptions.COMMAND_TYPE.QUERY);
break;
case Tokens.SQL_UPDATE:
case Tokens.SQL_INSERT:
options.setSql(fetchNext(args, ++i));
options.setCommandType(CLIOptions.COMMAND_TYPE.UPDATE);
break;
case Tokens.BATCH:
options.setBatch(true);
break;
case Tokens.DATA: // --data is the last option
for (i++; i < args.length; i++) {
arg = args[i];
if (arg.startsWith(options.getNamePrefix())) { // Named parameters:
String paramName = arg.substring(options.getNamePrefix().length());
String paramValue = fetchNext(args, ++i);
options.addNamedParameter(new NamedParameter(paramName, paramValue, namedTypes.get(paramName)));
} else { // Numbered parameters:
Parameter parameter;
if (numberedTypes.isEmpty()) {
parameter = new Parameter(arg, null);
} else {
int paramIndex = options.getNumberedParameters().size();
int paramType;
try {
paramType = numberedTypes.get(paramIndex);
} catch (IndexOutOfBoundsException e) {
throw new CLIParserException("Missing type for parameter #" + paramIndex, e);
} catch (NullPointerException e) {
throw new CLIParserException("Invalid type definition for parameter #" + paramIndex, e);
}
parameter = new Parameter(arg, paramType);
}
options.addNumberedParameter(parameter);
}
}
break;
case Tokens.FORMATTER:
options.setFormatterName(fetchNext(args, ++i));
break;
case Tokens.INFO_HELP:
options.addShowInfo(CLIOptions.INFO_TYPE.HELP);
break;
case Tokens.INFO_FORMATTERS:
options.addShowInfo(CLIOptions.INFO_TYPE.FORMATTERS);
break;
case Tokens.INFO_LICENSE:
options.addShowInfo(CLIOptions.INFO_TYPE.LICENSE);
break;
case Tokens.INFO_TYPES:
options.addShowInfo(CLIOptions.INFO_TYPE.TYPES);
break;
case Tokens.INFO_VERSION:
options.addShowInfo(CLIOptions.INFO_TYPE.VERSION);
break;
case Tokens.INFO_DATABASES:
options.addShowInfo(CLIOptions.INFO_TYPE.DATABASES);
break;
case Tokens.INFO_CONNECTION:
options.addShowInfo(CLIOptions.INFO_TYPE.CONNECTION);
options.setDatabaseNameToTest(fetchNext(args, ++i));
break;
default:
throw new CLIParserException("Unknown option: " + arg);
}
}
return options;
}
private String fetchNext(String[] args, int index) throws CLIParserException {
if (index < args.length) {
return args[index];
} else {
throw new CLIParserException("Expecting value for option: " + args[index - 1]);
}
}
public static class Tokens {
public static final String DB = "--db";
public static final String SQL = "--sql";
public static final String SQL_UPDATE = "--sql-update";
public static final String SQL_INSERT = "--sql-insert";
public static final String BATCH = "--batch";
public static final String DATA = "--data";
public static final String NAME_PREFIX = "--name-prefix";
public static final String TYPES = "--types";
public static final String FORMATTER = "--formatter";
public static final String INFO_HELP = "--help";
public static final String INFO_VERSION = "--version";
public static final String INFO_LICENSE = "--license";
public static final String INFO_FORMATTERS = "--list-formatters";
public static final String INFO_TYPES = "--list-types";
public static final String INFO_DATABASES = "--list-databases";
public static final String INFO_CONNECTION = "--test-connection";
private Tokens() {
}
}
private int getType(String typeString) throws CLIParserException {
Integer type = types.get(typeString.trim());
if (type == null) {
throw new CLIParserException("Unsupported type: " + typeString);
} else {
return type;
}
}
}