--- a/src/CLIParser.h Sun May 05 23:09:20 2019 +0200
+++ b/src/CLIParser.h Mon May 06 16:00:20 2019 +0200
@@ -29,6 +29,10 @@
namespace tr {
namespace awk {
+/**
+ * This tr-awk CLI options are inspired by tr-guile options.
+ * These configurations are independent and might diverge, but when possible, the should share same option names and same logic for common parts.
+ */
class CLIParser {
private:
@@ -39,17 +43,65 @@
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);
}
+ void addRelation(Configuration& c, RelationConfiguration& currentRelation) {
+ if (currentRelation.relation.size()) {
+ c.relationConfigurations.push_back(currentRelation);
+ currentRelation = RelationConfiguration();
+ }
+ }
+
+ relpipe::writer::TypeId parseTypeId(const string_t& value) {
+ using t = relpipe::writer::TypeId;
+ if (value == L"string") return t::STRING;
+ else if (value == L"integer") return t::INTEGER;
+ else if (value == L"boolean") return t::BOOLEAN;
+ else throw relpipe::cli::RelpipeCLIException(L"Unable to parse TypeId: " + value, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
public:
- static const string_t OPTION_EXPRESSION;
+ static const string_t OPTION_RELATION;
+ static const string_t OPTION_OUTPUT_ATTRIBUTE;
+ static const string_t OPTION_INPUT_ATTRIBUTES_APPEND;
+ static const string_t OPTION_INPUT_ATTRIBUTES_PREPEND;
+ static const string_t OPTION_BEFORE_RECORDS;
+ static const string_t OPTION_AFTER_RECORDS;
+ static const string_t OPTION_FOR_EACH;
+ static const string_t OPTION_DEFINE;
Configuration parse(const std::vector<string_t>& arguments) {
Configuration c;
+ RelationConfiguration currentRelation;
- for (int i = 0; i < arguments.size();) {
- string_t option = readNext(arguments, i);
- if (option == OPTION_EXPRESSION) c.awkExpression = readNext(arguments, i);
- else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ {
+ for (int i = 0; i < arguments.size();) {
+ string_t option = readNext(arguments, i);
+
+ if (option == OPTION_BEFORE_RECORDS) currentRelation.awkBeforeRecords = readNext(arguments, i);
+ else if (option == OPTION_AFTER_RECORDS) currentRelation.awkAfterRecords = readNext(arguments, i);
+ else if (option == OPTION_FOR_EACH) currentRelation.awkForEach = readNext(arguments, i);
+ else if (option == OPTION_INPUT_ATTRIBUTES_APPEND) currentRelation.inputAttributesAppend = true;
+ else if (option == OPTION_INPUT_ATTRIBUTES_PREPEND) currentRelation.inputAttributesPrepend = true;
+ else if (option == OPTION_RELATION) {
+ addRelation(c, currentRelation); // previous relation
+ currentRelation.relation = readNext(arguments, i);
+ } else if (option == OPTION_OUTPUT_ATTRIBUTE) {
+ relpipe::writer::AttributeMetadata attribute;
+ attribute.attributeName = readNext(arguments, i);
+ attribute.typeId = parseTypeId(readNext(arguments, i));
+ currentRelation.writerMetadata.push_back(attribute);
+ } else if (option == OPTION_DEFINE) {
+ DefinitionRecipe definition;
+ definition.name = readNext(arguments, i);
+ definition.type = readNext(arguments, i);
+ definition.value = readNext(arguments, i);
+ if (currentRelation.relation.size()) currentRelation.definitions.push_back(definition);
+ else c.definitions.push_back(definition);
+ } else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+
+ }
+
+ addRelation(c, currentRelation); // last relation
}
return c;
@@ -59,7 +111,14 @@
}
};
-const string_t CLIParser::OPTION_EXPRESSION = L"--expression";
+const string_t CLIParser::OPTION_RELATION = L"--relation";
+const string_t CLIParser::OPTION_OUTPUT_ATTRIBUTE = L"--output-attribute";
+const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_APPEND = L"--input-attributes-append";
+const string_t CLIParser::OPTION_INPUT_ATTRIBUTES_PREPEND = L"--input-attributes-prepend";
+const string_t CLIParser::OPTION_BEFORE_RECORDS = L"--before-records";
+const string_t CLIParser::OPTION_AFTER_RECORDS = L"--after-records";
+const string_t CLIParser::OPTION_FOR_EACH = L"--for-each";
+const string_t CLIParser::OPTION_DEFINE = L"--define";
}
}
--- a/src/Configuration.h Sun May 05 23:09:20 2019 +0200
+++ b/src/Configuration.h Mon May 06 16:00:20 2019 +0200
@@ -24,10 +24,62 @@
namespace tr {
namespace awk {
+class DefinitionRecipe {
+public:
+
+ virtual ~DefinitionRecipe() {
+ }
+
+ relpipe::writer::string_t name;
+ relpipe::writer::string_t type;
+ relpipe::writer::string_t value;
+};
+
+class RelationConfiguration {
+public:
+
+ virtual ~RelationConfiguration() {
+ }
+
+ relpipe::writer::string_t relation;
+ relpipe::writer::string_t awkBeforeRecords;
+ relpipe::writer::string_t awkAfterRecords;
+ relpipe::writer::string_t awkForEach;
+
+ /**
+ * Variable definitions for this relation.
+ * Can be used as a safe way for passing parameters from the outside environment.
+ * See also Configuration::definitions (can be overridden by relation's definitions)
+ */
+ std::vector<DefinitionRecipe> definitions;
+
+ /**
+ * If empty, output relation will have same metadata as the input relation.
+ */
+ std::vector<relpipe::writer::AttributeMetadata> writerMetadata;
+
+ /**
+ * Whether original attributes should be appended to those specified using --output-attribute
+ */
+ bool inputAttributesAppend = false;
+
+ /**
+ * Whether original attributes should be prepended to those specified using --output-attribute
+ */
+ bool inputAttributesPrepend = false;
+};
+
class Configuration {
public:
- relpipe::writer::string_t awkExpression;
+ vector<RelationConfiguration> relationConfigurations;
+
+ /**
+ * Global definitions for all relations.
+ * Can be used as a safe way for passing parameters from the outside environment.
+ * See also RelationConfiguration::definitions
+ */
+ std::vector<DefinitionRecipe> definitions;
virtual ~Configuration() {
}