change CLI interface: options: --relation --print-types --print-relation-name --print-record-count
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bash-completion.sh Thu Sep 24 18:57:20 2020 +0200
@@ -0,0 +1,45 @@
+# 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, version 3 of the License.
+#
+# 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/>.
+
+_relpipe_out_tabular_completion() {
+ local w0 w1 w2 w3
+
+ COMPREPLY=()
+ w0=${COMP_WORDS[COMP_CWORD]}
+ w1=${COMP_WORDS[COMP_CWORD-1]}
+ w2=${COMP_WORDS[COMP_CWORD-2]}
+ w3=${COMP_WORDS[COMP_CWORD-3]}
+
+ BOOLEAN_VALUES=(
+ "true"
+ "false"
+ )
+
+ if [[ "$w1" == "--relation" && "x$w0" == "x" ]]; then COMPREPLY=("'.+'")
+ elif [[ "$w1" == "--print-types" ]]; then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
+ elif [[ "$w1" == "--print-relation-name" ]]; then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
+ elif [[ "$w1" == "--print-record-count" ]]; then COMPREPLY=($(compgen -W "${BOOLEAN_VALUES[*]}" -- "$w0"))
+ else
+ OPTIONS=(
+ "--relation"
+ "--print-types"
+ "--print-relation-name"
+ "--print-record-count"
+ )
+ COMPREPLY=($(compgen -W "${OPTIONS[*]}" -- "$w0"))
+ fi
+}
+
+complete -F _relpipe_out_tabular_completion relpipe-out-tabular
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CLIParser.h Thu Sep 24 18:57:20 2020 +0200
@@ -0,0 +1,103 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 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, version 3 of the License.
+ *
+ * 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 <iostream>
+
+#include <relpipe/reader/typedefs.h>
+#include <relpipe/cli/CLI.h>
+#include <relpipe/cli/RelpipeCLIException.h>
+
+#include "Configuration.h"
+
+namespace relpipe {
+namespace out {
+namespace tabular {
+
+class CLIParser {
+private:
+
+ relpipe::reader::string_t readNext(const std::vector<relpipe::reader::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);
+ } else {
+ // no relation name given → global configuration
+ c.printTypes = currentRelation.printTypes;
+ c.printRelationName = currentRelation.printRelationName;
+ c.printRecordCount = currentRelation.printRecordCount;
+ }
+ currentRelation = RelationConfiguration();
+ }
+
+ /**
+ * TODO: use a common method
+ */
+ bool parseBoolean(const relpipe::reader::string_t& value) {
+ if (value == L"true") return true;
+ else if (value == L"false") return false;
+ else throw relpipe::cli::RelpipeCLIException(L"Unable to parse boolean value: " + value + L" (expecting true or false)", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ }
+
+public:
+
+ static const relpipe::reader::string_t OPTION_RELATION;
+ static const relpipe::reader::string_t OPTION_PRINT_TYPES;
+ static const relpipe::reader::string_t OPTION_PRINT_RELATION_NAME;
+ static const relpipe::reader::string_t OPTION_PRINT_RECORD_COUNT;
+
+ Configuration parse(const std::vector<relpipe::reader::string_t>& arguments) {
+ Configuration c;
+ RelationConfiguration currentRelation;
+
+ for (int i = 0; i < arguments.size();) {
+ relpipe::reader::string_t option = readNext(arguments, i);
+
+ if (option == OPTION_RELATION) {
+ addRelation(c, currentRelation); // previous relation
+ currentRelation.relation = readNext(arguments, i);
+ } else if (option == OPTION_PRINT_TYPES) {
+ currentRelation.printTypes = parseBoolean(readNext(arguments, i));
+ } else if (option == OPTION_PRINT_RELATION_NAME) {
+ currentRelation.printRelationName = parseBoolean(readNext(arguments, i));
+ } else if (option == OPTION_PRINT_RECORD_COUNT) {
+ currentRelation.printRecordCount = parseBoolean(readNext(arguments, i));
+ } 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 relpipe::reader::string_t CLIParser::OPTION_RELATION = L"--relation";
+const relpipe::reader::string_t CLIParser::OPTION_PRINT_TYPES = L"--print-types";
+const relpipe::reader::string_t CLIParser::OPTION_PRINT_RELATION_NAME = L"--print-relation-name";
+const relpipe::reader::string_t CLIParser::OPTION_PRINT_RECORD_COUNT = L"--print-record-count";
+
+}
+}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Configuration.h Thu Sep 24 18:57:20 2020 +0200
@@ -0,0 +1,54 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 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, version 3 of the License.
+ *
+ * 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 <iostream>
+
+#include <relpipe/reader/typedefs.h>
+
+
+namespace relpipe {
+namespace out {
+namespace tabular {
+
+class RelationConfiguration {
+public:
+
+ virtual ~RelationConfiguration() {
+ }
+
+ relpipe::reader::string_t relation;
+ relpipe::reader::boolean_t printTypes = true;
+ relpipe::reader::boolean_t printRecordCount = true;
+ relpipe::reader::boolean_t printRelationName = true;
+};
+
+class Configuration {
+public:
+ relpipe::reader::boolean_t printTypes = true;
+ relpipe::reader::boolean_t printRecordCount = true;
+ relpipe::reader::boolean_t printRelationName = true;
+ std::vector<RelationConfiguration> relationConfigurations;
+
+ virtual ~Configuration() {
+ }
+};
+
+}
+}
+}
\ No newline at end of file
--- a/src/TabularPrefetchingHandler.h Sat Jun 06 01:50:44 2020 +0200
+++ b/src/TabularPrefetchingHandler.h Thu Sep 24 18:57:20 2020 +0200
@@ -29,6 +29,8 @@
#include <relpipe/reader/handlers/RelationalReaderStringHandler.h>
#include <relpipe/reader/handlers/AttributeMetadata.h>
+#include "Configuration.h"
+
namespace relpipe {
namespace out {
namespace tabular {
@@ -52,7 +54,11 @@
const char* INDENT = " "; // table indent from the left
- std::ostream &output;
+ std::ostream& output;
+ Configuration& configuration;
+ RelationConfiguration* currentRelationConfiguration;
+
+#define getConfiguration(option) (currentRelationConfiguration ? currentRelationConfiguration->option : configuration.option)
std::vector<TypeId> columnTypes;
std::vector<string_t> columnTypeCodes;
@@ -146,7 +152,7 @@
for (size_t i = 0; i < columnCount; i++) {
string_t typeCode = columnTypeCodes[i];
string_t columnName = columnNames[i];
- integer_t minWidth = columnName.size() + typeCode.size() + 3; // 3 = " ()" in "columnName (typeCode)"
+ integer_t minWidth = columnName.size() + (getConfiguration(printTypes) ? typeCode.size() + 3 : 0); // 3 = " ()" in "columnName (typeCode)"
columnWidths[i] = max(columnWidths[i], minWidth);
paddings[i] = columnWidths[i] - minWidth;
}
@@ -160,7 +166,7 @@
for (integer_t p = 0; p < paddings[i]; p++) {
output << " ";
}
- output << " (" << convertor.to_bytes(columnTypeCodes[i]) << ")";
+ if (getConfiguration(printTypes)) output << " (" << convertor.to_bytes(columnTypeCodes[i]) << ")";
output << ESC_BORDER << " │" << ESC_RESET;
}
output << std::endl;
@@ -182,21 +188,32 @@
if (columnIndex == (columnCount - 1)) output << std::endl;
}
printHorizontalLine(L"╰", L"┴", L"╯");
- integer_t recordCount = values.size() / columnCount;
- output << ESC_YELLOW << "Record count: " << ESC_RESET << recordCount << std::endl;
+
+ if (getConfiguration(printRecordCount)) {
+ integer_t recordCount = values.size() / columnCount;
+ output << ESC_YELLOW << "Record count: " << ESC_RESET << recordCount << std::endl;
+ }
values.clear();
}
public:
- TabularPrefetchingHandler(std::ostream& output) : output(output) {
+ TabularPrefetchingHandler(std::ostream& output, Configuration& configuration) : output(output), configuration(configuration) {
}
void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override {
if (columnCount) printCachedData();
- output << ESC_RED << convertor.to_bytes(name) << ":" << ESC_RESET << endl;
+ currentRelationConfiguration = nullptr;
+ for (int i = 0; i < configuration.relationConfigurations.size(); i++) {
+ if (std::regex_match(name, std::wregex(configuration.relationConfigurations[i].relation))) {
+ currentRelationConfiguration = &configuration.relationConfigurations[i];
+ break; // it there are multiple matches, only the first configuration is used
+ }
+ }
+
+ if (getConfiguration(printRelationName)) output << ESC_RED << convertor.to_bytes(name) << ":" << ESC_RESET << endl;
columnCount = attributes.size();
columnTypes.resize(columnCount);
columnTypeCodes.resize(columnCount);
@@ -222,6 +239,8 @@
};
+#undef getConfiguration
+
}
}
}
--- a/src/relpipe-out-tabular.cpp Sat Jun 06 01:50:44 2020 +0200
+++ b/src/relpipe-out-tabular.cpp Thu Sep 24 18:57:20 2020 +0200
@@ -24,6 +24,8 @@
#include <relpipe/reader/RelpipeReaderException.h>
#include "TabularPrefetchingHandler.h"
+#include "Configuration.h"
+#include "CLIParser.h"
using namespace relpipe::cli;
using namespace relpipe::reader;
@@ -37,16 +39,10 @@
int resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR;
try {
- // if (cli.arguments().size() > 0) {
-
- // const wstring commandName = cli.arguments()[0];
- // vector<wstring> arguments(cli.arguments().size() - 1);
- // for (int i = 1; i < cli.arguments().size(); i++) {
- // arguments[i - 1] = cli.arguments()[i];
- // }
-
+ CLIParser cliParser;
+ Configuration configuration = cliParser.parse(cli.arguments());
std::shared_ptr<RelationalReader> reader(Factory::create(std::cin));
- TabularPrefetchingHandler handler(std::cout);
+ TabularPrefetchingHandler handler(std::cout, configuration);
reader->addHandler(&handler);
reader->process();