add --input-attributes-append and --input-attributes-prepend for adding attributes using --output-attribute instead of replacing whole attribute list v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Tue, 05 Feb 2019 20:40:32 +0100
branchv_0
changeset 15 051e58022783
parent 14 82bd0f57a889
child 16 2dcc22b7a424
add --input-attributes-append and --input-attributes-prepend for adding attributes using --output-attribute instead of replacing whole attribute list
src/CLIParser.h
src/Configuration.h
src/GuileHandler.h
--- a/src/CLIParser.h	Tue Feb 05 12:41:54 2019 +0100
+++ b/src/CLIParser.h	Tue Feb 05 20:40:32 2019 +0100
@@ -58,6 +58,8 @@
 
 	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;
@@ -78,6 +80,8 @@
 				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 = true;
+				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);
@@ -109,6 +113,8 @@
 
 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";
--- a/src/Configuration.h	Tue Feb 05 12:41:54 2019 +0100
+++ b/src/Configuration.h	Tue Feb 05 20:40:32 2019 +0100
@@ -49,24 +49,38 @@
 	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;
+
 	/**
 	 * 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:
+
 	vector<RelationConfiguration> relationConfigurations;
 	/**
 	 * Global definitions for all relations.
--- a/src/GuileHandler.h	Tue Feb 05 12:41:54 2019 +0100
+++ b/src/GuileHandler.h	Tue Feb 05 20:40:32 2019 +0100
@@ -62,6 +62,14 @@
 	integer_t currentAttributeIndex = 0;
 	boolean_t includeCurrentRecord = false;
 
+	void add(vector<AttributeMetadata>& readerAttributes, vector<writer::AttributeMetadata>& writerAttributes) {
+		for (AttributeMetadata readerAttributes : readerAttributes)
+			writerAttributes.push_back({
+				readerAttributes.getAttributeName(),
+				relationalWriter->toTypeId(readerAttributes.getTypeName())
+			});
+	}
+
 	/**
 	 * @param attributeName name from relational pipe
 	 * @return variable name in Guile
@@ -206,9 +214,11 @@
 		// TODO: move to a reusable method (or use same metadata on both reader and writer side?)
 		currentWriterMetadata.clear();
 		if (currentRelationConfiguration && currentRelationConfiguration->writerMetadata.size()) {
-			currentWriterMetadata = currentRelationConfiguration->writerMetadata;
+			if (currentRelationConfiguration->inputAttributesPrepend) add(currentReaderMetadata, currentWriterMetadata);
+			currentWriterMetadata.insert(currentWriterMetadata.end(), currentRelationConfiguration->writerMetadata.begin(), currentRelationConfiguration->writerMetadata.end());
+			if (currentRelationConfiguration->inputAttributesAppend) add(currentReaderMetadata, currentWriterMetadata);
 		} else {
-			for (AttributeMetadata readerMetadata : attributes) currentWriterMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())});
+			add(currentReaderMetadata, currentWriterMetadata);
 		}
 
 		if (!currentRelationConfiguration || !currentRelationConfiguration->drop) relationalWriter->startRelation(name, currentWriterMetadata, true);