--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CLIParser.h Sun Feb 03 01:44:07 2019 +0100
@@ -0,0 +1,111 @@
+/**
+ * Relational pipes
+ * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * 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/>.
+ */
+#pragma once
+
+#include <vector>
+
+#include <relpipe/writer/typedefs.h>
+#include <relpipe/cli/CLI.h>
+#include <relpipe/cli/RelpipeCLIException.h>
+
+#include "Configuration.h"
+
+namespace relpipe {
+namespace tr {
+namespace guile {
+
+class CLIParser {
+private:
+
+ // TODO: move common methods/classes to relpipe-lib-cli
+
+ string_t readNext(std::vector<string_t> arguments, int& i) {
+ if (i < arguments.size()) return arguments[i++];
+ 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();
+ }
+ }
+
+ bool parseBoolean(const string_t& value, const string_t& optionName) {
+ if (value == L"true") return true;
+ else if (value == L"false") return false;
+ else throw relpipe::cli::RelpipeCLIException(L"Unable to parse boolean value of option: " + optionName + L" (expecting true or false)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
+public:
+
+ static const string_t OPTION_RELATION;
+ 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_WHERE;
+ static const string_t OPTION_DROP;
+ 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_BEFORE_RECORDS) currentRelation.guileBeforeRecords = readNext(arguments, i);
+ else if (option == OPTION_AFTER_RECORDS) currentRelation.guileAfterRecords = readNext(arguments, i);
+ else if (option == OPTION_FOR_EACH) currentRelation.guileForEach = readNext(arguments, i);
+ else if (option == OPTION_WHERE) currentRelation.guileWhere = readNext(arguments, i);
+ else if (option == OPTION_DROP) currentRelation.drop = parseBoolean(readNext(arguments, i), option);
+ else if (option == OPTION_RELATION) {
+ addRelation(c, currentRelation); // previous relation
+ currentRelation.relation = readNext(arguments, i);
+ } else if (option == OPTION_DEFINE) {
+ DefinitionRecipe definition;
+ definition.name = readNext(arguments, i);
+ definition.type = readNext(arguments, i);
+ definition.value = readNext(arguments, i);
+ currentRelation.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;
+ }
+
+ virtual ~CLIParser() {
+ }
+};
+
+const string_t CLIParser::OPTION_RELATION = L"--relation";
+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_WHERE = L"--where";
+const string_t CLIParser::OPTION_DROP = L"--drop";
+const string_t CLIParser::OPTION_DEFINE = L"--define";
+
+}
+}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Configuration.h Sun Feb 03 01:44:07 2019 +0100
@@ -0,0 +1,76 @@
+/**
+ * Relational pipes
+ * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * 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/>.
+ */
+#pragma once
+
+#include <vector>
+#include <tuple>
+
+#include <relpipe/writer/AttributeMetadata.h>
+#include <relpipe/writer/typedefs.h>
+
+namespace relpipe {
+namespace tr {
+namespace guile {
+
+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 guileBeforeRecords;
+ relpipe::writer::string_t guileAfterRecords;
+ relpipe::writer::string_t guileForEach;
+ relpipe::writer::string_t guileWhere;
+ /**
+ * If true, Guile code will be executed, but no output will be generated.
+ */
+ bool drop = false;
+ /**
+ *
+ */
+ std::vector<DefinitionRecipe> definitions;
+ /**
+ * If empty, output relation will have same metadata as the input relation.
+ */
+ std::vector<relpipe::writer::AttributeMetadata> writerMetadata;
+};
+
+class Configuration {
+public:
+ vector<RelationConfiguration> relationConfigurations;
+
+ virtual ~Configuration() {
+ }
+};
+
+}
+}
+}
\ No newline at end of file
--- a/src/GuileHandler.h Sun Jan 27 17:57:03 2019 +0100
+++ b/src/GuileHandler.h Sun Feb 03 01:44:07 2019 +0100
@@ -38,6 +38,8 @@
#include <relpipe/cli/RelpipeCLIException.h>
+#include "Configuration.h"
+
namespace relpipe {
namespace tr {
namespace guile {
@@ -51,6 +53,7 @@
private:
std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings or use always UTF-8 between C++ and Guile
+ Configuration configuration;
shared_ptr<writer::RelationalWriter> relationalWriter;
wregex relationNameRegEx;
@@ -143,15 +146,16 @@
public:
- GuileHandler(ostream& output, const vector<string_t>& arguments) {
+ GuileHandler(ostream& output, Configuration& configuration, const vector<string_t>& arguments) : configuration(configuration) {
relationalWriter.reset(writer::Factory::create(output));
- // TODO: options and parser
- if (arguments.size() == 2) {
- relationNameRegEx = wregex(arguments[0]);
- guileCodeWhereCondition = arguments[1];
+ // FIXME: remove and work directly with configuration in startRelation() and attribute()
+ // i.e. support multiple relationConfigurations
+ if (configuration.relationConfigurations.size() == 1) {
+ relationNameRegEx = wregex(configuration.relationConfigurations[0].relation);
+ guileCodeWhereCondition = configuration.relationConfigurations[0].guileWhere;
} else {
- throw cli::RelpipeCLIException(L"Usage: relpipe-tr-guile <relationNameRegExp> <whereConditionGuileCode>", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND);
+ throw cli::RelpipeCLIException(L"FIXME: only single relationConfiguration is currently supported", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND);
}
}
--- a/src/relpipe-tr-guile.cpp Sun Jan 27 17:57:03 2019 +0100
+++ b/src/relpipe-tr-guile.cpp Sun Feb 03 01:44:07 2019 +0100
@@ -33,6 +33,7 @@
#include <relpipe/writer/TypeId.h>
#include "GuileHandler.h"
+#include "CLIParser.h"
using namespace relpipe::cli;
using namespace relpipe::reader;
@@ -46,8 +47,10 @@
int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
try {
+ CLIParser cliParser;
+ Configuration configuration = cliParser.parse(cli.arguments());
std::shared_ptr<RelationalReader> reader(Factory::create(std::cin));
- GuileHandler handler(std::cout, cli.arguments());
+ GuileHandler handler(std::cout, configuration, cli.arguments());
reader->addHandler(&handler);
reader->process();
@@ -68,5 +71,5 @@
int main(int argc, char**argv) {
scm_boot_guile(argc, argv, relpipeMain, nullptr);
- return 999; // never reached – see exit(resultCode) above
+ return 222; // never reached – see exit(resultCode) above
}