add --has-more-records and allow adding more records dynamically in Guile v_0 v0.10
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu, 07 Feb 2019 00:55:54 +0100
branchv_0
changeset 16 2dcc22b7a424
parent 15 051e58022783
child 17 c9f86c734d40
add --has-more-records and allow adding more records dynamically in Guile
src/CLIParser.h
src/Configuration.h
src/GuileHandler.h
--- a/src/CLIParser.h	Tue Feb 05 20:40:32 2019 +0100
+++ b/src/CLIParser.h	Thu Feb 07 00:55:54 2019 +0100
@@ -66,6 +66,7 @@
 	static const string_t OPTION_WHERE;
 	static const string_t OPTION_DROP;
 	static const string_t OPTION_DEFINE;
+	static const string_t OPTION_HAS_MORE_RECORDS;
 
 	Configuration parse(const std::vector<string_t>& arguments) {
 		Configuration c;
@@ -79,6 +80,7 @@
 				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_HAS_MORE_RECORDS) currentRelation.guileHasMoreRecords = 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;
@@ -121,6 +123,7 @@
 const string_t CLIParser::OPTION_WHERE = L"--where";
 const string_t CLIParser::OPTION_DROP = L"--drop";
 const string_t CLIParser::OPTION_DEFINE = L"--define";
+const string_t CLIParser::OPTION_HAS_MORE_RECORDS = L"--has-more-records";
 
 }
 }
--- a/src/Configuration.h	Tue Feb 05 20:40:32 2019 +0100
+++ b/src/Configuration.h	Thu Feb 07 00:55:54 2019 +0100
@@ -49,6 +49,7 @@
 	relpipe::writer::string_t guileAfterRecords;
 	relpipe::writer::string_t guileForEach;
 	relpipe::writer::string_t guileWhere;
+	relpipe::writer::string_t guileHasMoreRecords;
 
 	/**
 	 * If true, Guile code will be executed, but no output will be generated.
@@ -90,6 +91,8 @@
 	std::vector<DefinitionRecipe> definitions;
 
 	// TODO: --create t2 3 a integer b boolean '…guile…' – allow creating new relations? Or allow calling startRelation() and attribute() from Guile?
+	// TODO: --has-more-relations '…guile…' – called after all relations … ?
+	// TODO: --dynamic-output-attributes '…guile…' – used instead or together with --output-attribute
 
 	virtual ~Configuration() {
 	}
--- a/src/GuileHandler.h	Tue Feb 05 20:40:32 2019 +0100
+++ b/src/GuileHandler.h	Thu Feb 07 00:55:54 2019 +0100
@@ -187,6 +187,17 @@
 		}
 	}
 
+	/**
+	 * Read from the Guile variables and write to relational output stream.
+	 */
+	void writeCurrentRecord() {
+		for (auto attribute : currentWriterMetadata) writeGuileValueToAttribute(attribute);
+	}
+
+	void writeMoreRecords() {
+		while (scm_to_bool(evalGuileCode(currentRelationConfiguration->guileHasMoreRecords, SCM_BOOL_F))) writeCurrentRecord();
+	}
+
 public:
 
 	GuileHandler(writer::RelationalWriter* relationalWriter, Configuration& configuration, const vector<string_t>& arguments) : relationalWriter(relationalWriter), configuration(configuration) {
@@ -195,6 +206,7 @@
 	void startRelation(string_t name, vector<AttributeMetadata> attributes) override {
 		if (currentRelationConfiguration) {
 			evalGuileCode(currentRelationConfiguration->guileAfterRecords);
+			writeMoreRecords();
 			for (DefinitionRecipe definition : currentRelationConfiguration->definitions) undefineGuileVariable(definition.name);
 		}
 		for (auto attribute : currentReaderMetadata) undefineGuileVariable(attribute.getAttributeName());
@@ -240,8 +252,9 @@
 			if (currentAttributeIndex > 0 && currentAttributeIndex % currentReaderMetadata.size() == 0) {
 				evalGuileCode(currentRelationConfiguration->guileForEach);
 				includeCurrentRecord = scm_to_bool(evalGuileCode(currentRelationConfiguration->guileWhere, SCM_BOOL_T));
-				if (includeCurrentRecord && !currentRelationConfiguration->drop) for (auto attribute : currentWriterMetadata) writeGuileValueToAttribute(attribute);
+				if (includeCurrentRecord && !currentRelationConfiguration->drop) writeCurrentRecord();
 				includeCurrentRecord = false;
+				writeMoreRecords();
 			}
 
 			currentAttributeIndex = currentAttributeIndex % currentReaderMetadata.size();
@@ -251,7 +264,10 @@
 	}
 
 	void endOfPipe() {
-		if (currentRelationConfiguration) evalGuileCode(currentRelationConfiguration->guileAfterRecords);
+		if (currentRelationConfiguration) {
+			evalGuileCode(currentRelationConfiguration->guileAfterRecords);
+			writeMoreRecords();
+		}
 	}
 
 };