src/CLIParser.h
branchv_0
changeset 2 362f2689cb87
parent 0 c205f5d06418
child 5 cbc7817a3346
equal deleted inserted replaced
1:eb7134dfdcc5 2:362f2689cb87
    27 
    27 
    28 namespace relpipe {
    28 namespace relpipe {
    29 namespace tr {
    29 namespace tr {
    30 namespace sql {
    30 namespace sql {
    31 
    31 
    32 /**
       
    33  * This tr-sql CLI options are inspired by tr-guile options.
       
    34  * These configurations are independent and might diverge, but when possible, they should share same option names and same logic for common parts.
       
    35  */
       
    36 class CLIParser {
    32 class CLIParser {
    37 private:
    33 private:
    38 
    34 
    39 	// FIXME: move common methods/classes to relpipe-lib-cli or relpipe-lib-helper
    35 	// FIXME: move common methods/classes to relpipe-lib-cli or relpipe-lib-helper
    40 
    36 
    41 	string_t readNext(std::vector<string_t> arguments, int& i) {
    37 	string_t readNext(std::vector<string_t> arguments, int& i) {
    42 		if (i < arguments.size()) return arguments[i++];
    38 		if (i < arguments.size()) return arguments[i++];
    43 		else throw relpipe::cli::RelpipeCLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
    39 		else throw relpipe::cli::RelpipeCLIException(L"Missing CLI argument" + (i > 0 ? (L" after " + arguments[i - 1]) : L""), relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
    44 	}
    40 	}
    45 
    41 
    46 	void addRelation(Configuration& c, RelationConfiguration& currentRelation) {
    42 	void addQuery(Configuration& c, Statement& currentQuery) {
    47 		if (currentRelation.relation.size()) {
    43 		if (currentQuery.sql.size()) {
    48 			c.relationConfigurations.push_back(currentRelation);
    44 			c.statements.push_back(currentQuery);
    49 			currentRelation = RelationConfiguration();
    45 			currentQuery = Statement();
    50 		}
    46 		}
    51 	}
       
    52 
       
    53 	relpipe::writer::TypeId parseTypeId(const string_t& value) {
       
    54 		using t = relpipe::writer::TypeId;
       
    55 		if (value == L"string") return t::STRING;
       
    56 		else if (value == L"integer") return t::INTEGER;
       
    57 		else if (value == L"boolean") return t::BOOLEAN;
       
    58 		else throw relpipe::cli::RelpipeCLIException(L"Unable to parse TypeId: " + value, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
       
    59 	}
    47 	}
    60 
    48 
    61 public:
    49 public:
    62 
    50 
    63 	static const string_t OPTION_RELATION;
    51 	static const string_t OPTION_RELATION;
    64 	static const string_t OPTION_OUTPUT_ATTRIBUTE;
    52 	static const string_t OPTION_PARAMETER;
    65 	static const string_t OPTION_INPUT_ATTRIBUTES_APPEND;
       
    66 	static const string_t OPTION_INPUT_ATTRIBUTES_PREPEND;
       
    67 	static const string_t OPTION_DEBUG_VARIABLE_MAPPING;
       
    68 	static const string_t OPTION_BEFORE_RECORDS;
       
    69 	static const string_t OPTION_AFTER_RECORDS;
       
    70 	static const string_t OPTION_FOR_EACH;
       
    71 	static const string_t OPTION_DROP;
       
    72 	static const string_t OPTION_DEFINE;
       
    73 
    53 
    74 	Configuration parse(const std::vector<string_t>& arguments) {
    54 	Configuration parse(const std::vector<string_t>& arguments) {
    75 		Configuration c;
    55 		Configuration c;
    76 		RelationConfiguration currentRelation;
    56 		Statement currentQuery;
    77 
    57 
    78 		for (int i = 0; i < arguments.size();) {
    58 		for (int i = 0; i < arguments.size();) {
    79 			string_t option = readNext(arguments, i);
    59 			string_t option = readNext(arguments, i);
    80 
    60 
    81 			if (option == OPTION_BEFORE_RECORDS) currentRelation.sqlBeforeRecords = readNext(arguments, i);
    61 			if (option == OPTION_RELATION) {
    82 			else if (option == OPTION_AFTER_RECORDS) currentRelation.sqlAfterRecords = readNext(arguments, i);
    62 				addQuery(c, currentQuery); // previous relation
    83 			else if (option == OPTION_FOR_EACH) currentRelation.sqlForEach = readNext(arguments, i);
    63 				currentQuery.relation = readNext(arguments, i);
    84 			else if (option == OPTION_DROP) currentRelation.drop = true;
    64 				currentQuery.sql = readNext(arguments, i);
    85 			else if (option == OPTION_INPUT_ATTRIBUTES_APPEND) currentRelation.inputAttributesAppend = true;
    65 			} else if (option == OPTION_PARAMETER) {
    86 			else if (option == OPTION_INPUT_ATTRIBUTES_PREPEND) currentRelation.inputAttributesPrepend = true;
    66 				Parameter parameter;
    87 			else if (option == OPTION_DEBUG_VARIABLE_MAPPING) currentRelation.debugVariableMapping = true;
    67 				parameter.value = readNext(arguments, i);
    88 			else if (option == OPTION_RELATION) {
    68 				currentQuery.parameters.push_back(parameter);
    89 				addRelation(c, currentRelation); // previous relation
       
    90 				currentRelation.relation = readNext(arguments, i);
       
    91 			} else if (option == OPTION_OUTPUT_ATTRIBUTE) {
       
    92 				relpipe::writer::AttributeMetadata attribute;
       
    93 				attribute.attributeName = readNext(arguments, i);
       
    94 				attribute.typeId = parseTypeId(readNext(arguments, i));
       
    95 				currentRelation.writerMetadata.push_back(attribute);
       
    96 			} else if (option == OPTION_DEFINE) {
       
    97 				DefinitionRecipe definition;
       
    98 				definition.name = readNext(arguments, i);
       
    99 				definition.type = readNext(arguments, i);
       
   100 				definition.value = readNext(arguments, i);
       
   101 				if (currentRelation.relation.size()) currentRelation.definitions.push_back(definition);
       
   102 				else c.definitions.push_back(definition);
       
   103 			} else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
    69 			} else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
   104 		}
    70 		}
   105 		addRelation(c, currentRelation); // last relation
    71 		addQuery(c, currentQuery); // last relation
   106 
    72 
   107 		return c;
    73 		return c;
   108 	}
    74 	}
   109 
    75 
   110 	virtual ~CLIParser() {
    76 	virtual ~CLIParser() {
   111 	}
    77 	}
   112 };
    78 };
   113 
    79 
       
    80 
       
    81 // relpipe-tr-sql --relation "tabulka" "SELECT * FROM fstab WHERE id = ?" --parameter "123"
       
    82 // TODO: --file db.sqlite --keep-file
       
    83 // TODO: --type string/integer/boolean (default is string)
       
    84 
   114 const string_t CLIParser::OPTION_RELATION = L"--relation";
    85 const string_t CLIParser::OPTION_RELATION = L"--relation";
   115 const string_t CLIParser::OPTION_OUTPUT_ATTRIBUTE = L"--output-attribute";
    86 const string_t CLIParser::OPTION_PARAMETER = L"--parameter";
   116 const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_APPEND = L"--input-attributes-append";
       
   117 const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_PREPEND = L"--input-attributes-prepend";
       
   118 const string_t CLIParser::OPTION_DEBUG_VARIABLE_MAPPING = L"--debug-variable-mapping";
       
   119 const string_t CLIParser::OPTION_BEFORE_RECORDS = L"--before-records";
       
   120 const string_t CLIParser::OPTION_AFTER_RECORDS = L"--after-records";
       
   121 const string_t CLIParser::OPTION_FOR_EACH = L"--for-each";
       
   122 const string_t CLIParser::OPTION_DROP = L"--drop";
       
   123 const string_t CLIParser::OPTION_DEFINE = L"--define";
       
   124 
    87 
   125 }
    88 }
   126 }
    89 }
   127 }
    90 }