src/CutHandler.h
branchv_0
changeset 10 9ec1290b4a9d
parent 9 f06781a5071b
child 11 9d528c98912d
--- a/src/CutHandler.h	Wed Dec 12 23:45:46 2018 +0100
+++ b/src/CutHandler.h	Thu Dec 13 01:28:55 2018 +0100
@@ -49,13 +49,11 @@
 	shared_ptr<writer::RelationalWriter> relationalWriter;
 
 	wregex relationNameRegEx;
-	wregex attributeNameRegEx;
-	wregex searchRegEx;
+	vector<wregex> attributeNameRegExes;
 
-	vector<boolean_t> currentSearchableAttributes;
+	vector<integer_t> currentAttributeMapping;
 	vector<string_t> currentRecord;
 	integer_t currentAttributeIndex = 0;
-	boolean_t includeCurrentRecord = false;
 	boolean_t filterCurrentRelation = false;
 
 public:
@@ -63,51 +61,52 @@
 	GrepHandler(ostream& output, const vector<string_t>& arguments) {
 		relationalWriter.reset(writer::Factory::create(output));
 
-		if (arguments.size() == 3) {
+		if (arguments.size() >= 2) {
 			relationNameRegEx = wregex(arguments[0]);
-			attributeNameRegEx = wregex(arguments[1]);
-			searchRegEx = wregex(arguments[2]);
+			for (int i = 1; i < arguments.size(); i++) attributeNameRegExes.push_back(wregex(arguments[i]));
 		} else {
-			throw cli::RelpipeCLIException(L"Usage: relpipe-tr-cut <relationNameRegExp> <attributeNameRegExp> <searchRegExp>", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND);
+			throw cli::RelpipeCLIException(L"Usage: relpipe-tr-cut <relationNameRegExp> <attributeNameRegExp> [<otherAttributeNameRegExp> ...]", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND);
 		}
 	}
 
 	void startRelation(string_t name, vector<AttributeMetadata> attributes) override {
 		// TODO: move to a reusable method (or use same metadata on both reader and writer side?)
-		vector<writer::AttributeMetadata> writerMetadata;
+		vector<writer::AttributeMetadata> allWriterMetadata;
 		for (AttributeMetadata readerMetadata : attributes) {
-			writerMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())});
+			allWriterMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())});
 		}
 
+		vector<writer::AttributeMetadata> writerMetadata;
 
-		currentRecord.resize(attributes.size());
-		currentSearchableAttributes.resize(attributes.size(), false);
 		filterCurrentRelation = regex_match(name, relationNameRegEx);
 		if (filterCurrentRelation) {
-			for (int i = 0; i < currentSearchableAttributes.size(); i++) {
-				currentSearchableAttributes[i] = regex_match(attributes[i].getAttributeName(), attributeNameRegEx);
+			currentAttributeMapping.clear();
+			for (wregex attributeNameRegEx : attributeNameRegExes) {
+				for (int i = 0; i < allWriterMetadata.size(); i++) {
+					if (regex_match(allWriterMetadata[i].attributeName, attributeNameRegEx)) currentAttributeMapping.push_back(i);
+				}
 			}
+
+			if (currentAttributeMapping.empty()) throw cli::RelpipeCLIException(L"No attribute matches. Relation must have at least one attribute.", cli::CLI::EXIT_CODE_BAD_SYNTAX); // TODO: review exit code
+			for (integer_t i : currentAttributeMapping) writerMetadata.push_back(allWriterMetadata[i]);
+		} else {
+			writerMetadata = allWriterMetadata;
 		}
 
+		currentRecord.resize(allWriterMetadata.size());
 		relationalWriter->startRelation(name, writerMetadata, true);
 	}
 
 	void attribute(const string_t& value) override {
 		if (filterCurrentRelation) {
 			currentRecord[currentAttributeIndex] = value;
-
-			if (currentSearchableAttributes[currentAttributeIndex]) {
-				includeCurrentRecord |= regex_search(value, searchRegEx);
-			}
-
 			currentAttributeIndex++;
 
-			if (currentAttributeIndex > 0 && currentAttributeIndex % currentSearchableAttributes.size() == 0) {
-				if (includeCurrentRecord) for (string_t v : currentRecord) relationalWriter->writeAttribute(v);
-				includeCurrentRecord = false;
+			if (currentAttributeIndex > 0 && currentAttributeIndex % currentRecord.size() == 0) {
+				for (integer_t i : currentAttributeMapping) relationalWriter->writeAttribute(currentRecord[i]);
 			}
 
-			currentAttributeIndex = currentAttributeIndex % currentSearchableAttributes.size();
+			currentAttributeIndex = currentAttributeIndex % currentRecord.size();
 		} else {
 			relationalWriter->writeAttribute(value);
 		}