diff -r d5e80f15d1f7 -r 6ee7a9e311e9 src/GuileHandler.h --- a/src/GuileHandler.h Tue May 07 01:03:21 2019 +0200 +++ b/src/GuileHandler.h Sun May 26 19:46:47 2019 +0200 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include "Configuration.h" +#include "GuileException.h" namespace relpipe { namespace tr { @@ -59,6 +61,7 @@ RelationConfiguration* currentRelationConfiguration = nullptr; vector currentReaderMetadata; vector currentWriterMetadata; + std::map currenVariablesMapping; integer_t currentAttributeIndex = 0; boolean_t includeCurrentRecord = false; @@ -70,13 +73,51 @@ }); } + void generateVariableMappings() { + currenVariablesMapping.clear(); + for (AttributeMetadata m : currentReaderMetadata) currenVariablesMapping[m.getAttributeName()] = L""; + for (writer::AttributeMetadata m : currentWriterMetadata) currenVariablesMapping[m.attributeName] = L""; + + for (std::pair m : currenVariablesMapping) { + currenVariablesMapping[m.first] = escapeAwkVariableName(m.first); + } + } + /** * @param attributeName name from relational pipe * @return variable name in Guile */ string_t a2v(const string_t& attributeName) { - // TODO: escape spaces and special characters - return L"$" + attributeName; + if (currenVariablesMapping.find(attributeName) != currenVariablesMapping.end()) return currenVariablesMapping[attributeName]; + else throw GuileException(L"Unable to find value in currenVariablesMapping"); + } + + template bool containsValue(std::map map, V value) { // TODO: common function (Guile, AWK) + for (std::pair p : map) if (p.second == value) return true; + return false; + } + + string_t escapeAwkVariableName(const string_t& attributeName, bool addPrefix = true) { + std::wregex badCharacters(L"\\s"); + string_t name = std::regex_replace(attributeName, badCharacters, L"-"); + + if (addPrefix) name = L"$" + name; // $ = standard attribute-variable prefix + + if (containsValue(currenVariablesMapping, name)) return escapeAwkVariableName(L"$" + name, false); // $ = different prefix added to distinguish two attributes with ambiguous names + else return name; + + } + + void debugVariableMapping(const string_t& relationName) { + relationalWriter->startRelation(relationName + L".variableMapping",{ + {L"attribute", writer::TypeId::STRING}, + {L"variable", writer::TypeId::STRING}, + }, true); + + for (std::pair m : currenVariablesMapping) { + relationalWriter->writeAttribute(m.first); + relationalWriter->writeAttribute(m.second); + } } SCM toGuileSymbol(const string_t& name) { @@ -233,6 +274,10 @@ add(currentReaderMetadata, currentWriterMetadata); } + generateVariableMappings(); + + if (currentRelationConfiguration->debugVariableMapping) debugVariableMapping(name); + if (!currentRelationConfiguration || !currentRelationConfiguration->drop) relationalWriter->startRelation(name, currentWriterMetadata, true); if (currentRelationConfiguration) {