# HG changeset patch # User František Kučera # Date 1532809780 -7200 # Node ID 70af169464664806765fa76ab8eb5653fc3e581f # Parent dc2121dec8561bbdacc08732c5e966d2204a1716 StdInCommand: generate relational data from STDIN (and also CLI arguments) diff -r dc2121dec856 -r 70af16946466 StdInCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/StdInCommand.h Sat Jul 28 22:29:40 2018 +0200 @@ -0,0 +1,89 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "Command.h" +#include "CLI.h" +#include "RelpipeCLIException.h" + +namespace relpipe { +namespace in { +namespace cli { + +/** + * TODO: consider code merge with ArgumentsCommand + */ +class StdInCommand : public Command { +private: + wstring_convert> convertor; // TODO: support also other encodings. + + /** + * Reads next value from arguments and (if no arguments left) from input + * @param input + * @param arguments + * @param i current index in the arguments vector + * @param required if true, exception is thrown when no data found + * @return + */ + relpipe::writer::string_t readNext(std::istream& input, const std::vector& arguments, size_t& i, relpipe::writer::boolean_t required) { + using namespace relpipe::writer; + using namespace relpipe::cli; + + if (i < arguments.size()) { + return arguments[i++]; + } else { + std::stringstream value; + + while (true) { + char ch; + input.get(ch); + if (ch == 0 || input.eof() || input.fail()) break; + else value << ch; + } + + return convertor.from_bytes(value.str()); + } + } + + +public: + + void process(std::istream& input, std::ostream& output, const relpipe::writer::string_t& command, const std::vector& arguments) override { + using namespace relpipe::writer; + + size_t i = 0; + string_t relationName = readNext(input, arguments, i, true); + integer_t attributeCount = std::stoul(readNext(input, arguments, i, true)); // TODO: use integer data type's method? + boolean_t writeHeader = true; // TODO: add option for header omitting + + std::shared_ptr writer(Factory::create(output)); + + std::vector> attributes(attributeCount); + + for (size_t j = 0; j < attributeCount; j++) { + string_t attributeName = readNext(input, arguments, i, true); + TypeId attributeType = writer->toTypeId(readNext(input, arguments, i, true)); + attributes[j] = {attributeName, attributeType}; + } + + writer->startRelation(relationName, attributes, writeHeader); + + while (true) { + string_t value = readNext(input, arguments, i, false); + if (value.empty() && (input.eof() || input.fail())) break; + else writer->writeAttribute(value); + } + } +}; + +} +} +} diff -r dc2121dec856 -r 70af16946466 nbproject/configurations.xml --- a/nbproject/configurations.xml Sat Jul 28 15:42:42 2018 +0200 +++ b/nbproject/configurations.xml Sat Jul 28 22:29:40 2018 +0200 @@ -9,6 +9,7 @@ Command.h DemoCommand.h RelpipeCLIException.h + StdInCommand.h + + @@ -105,6 +108,8 @@ + + diff -r dc2121dec856 -r 70af16946466 relpipe-in-cli.cpp --- a/relpipe-in-cli.cpp Sat Jul 28 15:42:42 2018 +0200 +++ b/relpipe-in-cli.cpp Sat Jul 28 22:29:40 2018 +0200 @@ -11,14 +11,18 @@ #include "Command.h" #include "ArgumentsCommand.h" #include "DemoCommand.h" +#include "StdInCommand.h" using namespace relpipe::cli; using namespace relpipe::in::cli; using namespace relpipe::writer; Command* findCommand(string_t commandName) { + // TODO: better command names + // TODO: help command if (commandName == L"demo") return new DemoCommand(); else if (commandName == L"generate") return new ArgumentsCommand(); + else if (commandName == L"generate-from-stdin") return new StdInCommand(); else throw RelpipeCLIException(L"Unknown command: " + commandName, CLI::EXIT_CODE_UNKNOWN_COMMAND); }