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 } |