add --define for passing parameters from the outside environment v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 03 Feb 2019 21:53:10 +0100
branchv_0
changeset 11 9603e64324bc
parent 10 f7f9a2553128
child 12 7977c1bdba1f
add --define for passing parameters from the outside environment
src/Configuration.h
src/GuileHandler.h
--- a/src/Configuration.h	Sun Feb 03 19:52:37 2019 +0100
+++ b/src/Configuration.h	Sun Feb 03 21:53:10 2019 +0100
@@ -54,7 +54,8 @@
 	 */
 	bool drop = false;
 	/**
-	 * 
+	 * Variable definitions for this relation.
+	 * Can be used as a safe way for passing parameters from the outside environment.
 	 */
 	std::vector<DefinitionRecipe> definitions;
 	/**
@@ -67,6 +68,11 @@
 public:
 	vector<RelationConfiguration> relationConfigurations;
 
+	// TODO: --define – global definitions (for all relations)?
+	// TODO: --relation … --drop – will execute --for-each, but no output will be generated for this relation
+	// TODO: --relation … --output-attribute 'name' 'type' – output relation will have different attributes than the input relation
+	// TODO: --create t2 3 a integer b boolean '…guile…' – allow creating new relations? Or allow calling startRelation() and attribute() from Guile?
+
 	virtual ~Configuration() {
 	}
 };
--- a/src/GuileHandler.h	Sun Feb 03 19:52:37 2019 +0100
+++ b/src/GuileHandler.h	Sun Feb 03 21:53:10 2019 +0100
@@ -114,6 +114,39 @@
 		scm_define(toGuileSymbol(name), toGuileValue(value, typeInfo, type));
 	}
 
+	/**
+	 * TODO: use a common method
+	 */
+	bool parseBoolean(const 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);
+	}
+
+	void defineGuileVariable(const DefinitionRecipe& definition) {
+		switch (relationalWriter->toTypeId(definition.type)) {
+			case writer::TypeId::BOOLEAN:
+			{
+				boolean_t value = parseBoolean(definition.value);
+				defineGuileVariable(definition.name, &value, typeid (value), TypeId::BOOLEAN);
+				break;
+			}
+			case writer::TypeId::INTEGER:
+			{
+				integer_t value = stoul(definition.value);
+				defineGuileVariable(definition.name, &value, typeid (value), TypeId::INTEGER);
+				break;
+			}
+			case writer::TypeId::STRING:
+			{
+				defineGuileVariable(definition.name, &definition.value, typeid (definition.value), TypeId::STRING);
+				break;
+			}
+			default:
+				throw cli::RelpipeCLIException(L"Unsupported type in defineGuileVariable(): " + definition.type, cli::CLI::EXIT_CODE_UNEXPECTED_ERROR);
+		}
+	}
+
 	void undefineGuileVariable(const string_t& name) {
 		scm_define(toGuileSymbol(name), scm_make_undefined_variable()); // undefined != (define n)
 		// TODO: or use: scm_variable_unset_x() ?
@@ -152,7 +185,10 @@
 	}
 
 	void startRelation(string_t name, vector<AttributeMetadata> attributes) override {
-		if (currentRelationConfiguration) evalGuileCode(currentRelationConfiguration->guileAfterRecords);
+		if (currentRelationConfiguration) {
+			evalGuileCode(currentRelationConfiguration->guileAfterRecords);
+			for (DefinitionRecipe definition : currentRelationConfiguration->definitions) undefineGuileVariable(definition.name);
+		}
 		for (auto attribute : currentReaderMetadata) undefineGuileVariable(attribute.getAttributeName());
 		currentReaderMetadata = attributes;
 		// TODO: move to a reusable method (or use same metadata on both reader and writer side?)
@@ -166,6 +202,7 @@
 		for (int i = 0; i < configuration.relationConfigurations.size(); i++) {
 			if (regex_match(name, wregex(configuration.relationConfigurations[i].relation))) {
 				currentRelationConfiguration = &configuration.relationConfigurations[i];
+				for (DefinitionRecipe definition : currentRelationConfiguration->definitions) defineGuileVariable(definition);
 				break; // it there are multiple matches, only the first configuration is used
 			}
 		}