57 writer::RelationalWriter* relationalWriter; |
59 writer::RelationalWriter* relationalWriter; |
58 |
60 |
59 RelationConfiguration* currentRelationConfiguration = nullptr; |
61 RelationConfiguration* currentRelationConfiguration = nullptr; |
60 vector<AttributeMetadata> currentReaderMetadata; |
62 vector<AttributeMetadata> currentReaderMetadata; |
61 vector<writer::AttributeMetadata> currentWriterMetadata; |
63 vector<writer::AttributeMetadata> currentWriterMetadata; |
|
64 std::map<string_t, string_t> currenVariablesMapping; |
62 integer_t currentAttributeIndex = 0; |
65 integer_t currentAttributeIndex = 0; |
63 boolean_t includeCurrentRecord = false; |
66 boolean_t includeCurrentRecord = false; |
64 |
67 |
65 void add(vector<AttributeMetadata>& readerAttributes, vector<writer::AttributeMetadata>& writerAttributes) { |
68 void add(vector<AttributeMetadata>& readerAttributes, vector<writer::AttributeMetadata>& writerAttributes) { |
66 for (AttributeMetadata readerAttributes : readerAttributes) |
69 for (AttributeMetadata readerAttributes : readerAttributes) |
68 readerAttributes.getAttributeName(), |
71 readerAttributes.getAttributeName(), |
69 relationalWriter->toTypeId(readerAttributes.getTypeName()) |
72 relationalWriter->toTypeId(readerAttributes.getTypeName()) |
70 }); |
73 }); |
71 } |
74 } |
72 |
75 |
|
76 void generateVariableMappings() { |
|
77 currenVariablesMapping.clear(); |
|
78 for (AttributeMetadata m : currentReaderMetadata) currenVariablesMapping[m.getAttributeName()] = L""; |
|
79 for (writer::AttributeMetadata m : currentWriterMetadata) currenVariablesMapping[m.attributeName] = L""; |
|
80 |
|
81 for (std::pair<string_t, string_t> m : currenVariablesMapping) { |
|
82 currenVariablesMapping[m.first] = escapeAwkVariableName(m.first); |
|
83 } |
|
84 } |
|
85 |
73 /** |
86 /** |
74 * @param attributeName name from relational pipe |
87 * @param attributeName name from relational pipe |
75 * @return variable name in Guile |
88 * @return variable name in Guile |
76 */ |
89 */ |
77 string_t a2v(const string_t& attributeName) { |
90 string_t a2v(const string_t& attributeName) { |
78 // TODO: escape spaces and special characters |
91 if (currenVariablesMapping.find(attributeName) != currenVariablesMapping.end()) return currenVariablesMapping[attributeName]; |
79 return L"$" + attributeName; |
92 else throw GuileException(L"Unable to find value in currenVariablesMapping"); |
|
93 } |
|
94 |
|
95 template <typename K, typename V> bool containsValue(std::map<K, V> map, V value) { // TODO: common function (Guile, AWK) |
|
96 for (std::pair<K, V> p : map) if (p.second == value) return true; |
|
97 return false; |
|
98 } |
|
99 |
|
100 string_t escapeAwkVariableName(const string_t& attributeName, bool addPrefix = true) { |
|
101 std::wregex badCharacters(L"\\s"); |
|
102 string_t name = std::regex_replace(attributeName, badCharacters, L"-"); |
|
103 |
|
104 if (addPrefix) name = L"$" + name; // $ = standard attribute-variable prefix |
|
105 |
|
106 if (containsValue(currenVariablesMapping, name)) return escapeAwkVariableName(L"$" + name, false); // $ = different prefix added to distinguish two attributes with ambiguous names |
|
107 else return name; |
|
108 |
|
109 } |
|
110 |
|
111 void debugVariableMapping(const string_t& relationName) { |
|
112 relationalWriter->startRelation(relationName + L".variableMapping",{ |
|
113 {L"attribute", writer::TypeId::STRING}, |
|
114 {L"variable", writer::TypeId::STRING}, |
|
115 }, true); |
|
116 |
|
117 for (std::pair<string_t, string_t> m : currenVariablesMapping) { |
|
118 relationalWriter->writeAttribute(m.first); |
|
119 relationalWriter->writeAttribute(m.second); |
|
120 } |
80 } |
121 } |
81 |
122 |
82 SCM toGuileSymbol(const string_t& name) { |
123 SCM toGuileSymbol(const string_t& name) { |
83 return scm_string_to_symbol(scm_from_locale_string(convertor.to_bytes(name).c_str())); |
124 return scm_string_to_symbol(scm_from_locale_string(convertor.to_bytes(name).c_str())); |
84 } |
125 } |
231 if (currentRelationConfiguration->inputAttributesAppend) add(currentReaderMetadata, currentWriterMetadata); |
272 if (currentRelationConfiguration->inputAttributesAppend) add(currentReaderMetadata, currentWriterMetadata); |
232 } else { |
273 } else { |
233 add(currentReaderMetadata, currentWriterMetadata); |
274 add(currentReaderMetadata, currentWriterMetadata); |
234 } |
275 } |
235 |
276 |
|
277 generateVariableMappings(); |
|
278 |
|
279 if (currentRelationConfiguration->debugVariableMapping) debugVariableMapping(name); |
|
280 |
236 if (!currentRelationConfiguration || !currentRelationConfiguration->drop) relationalWriter->startRelation(name, currentWriterMetadata, true); |
281 if (!currentRelationConfiguration || !currentRelationConfiguration->drop) relationalWriter->startRelation(name, currentWriterMetadata, true); |
237 |
282 |
238 if (currentRelationConfiguration) { |
283 if (currentRelationConfiguration) { |
239 // TODO: better variable name, object, function? |
284 // TODO: better variable name, object, function? |
240 defineGuileVariable(L"relpipe-relation-name", &name, typeid (name), TypeId::STRING); |
285 defineGuileVariable(L"relpipe-relation-name", &name, typeid (name), TypeId::STRING); |