54 std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings or use always UTF-8 between C++ and Guile |
54 std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings or use always UTF-8 between C++ and Guile |
55 |
55 |
56 Configuration configuration; |
56 Configuration configuration; |
57 writer::RelationalWriter* relationalWriter; |
57 writer::RelationalWriter* relationalWriter; |
58 |
58 |
59 wregex relationNameRegEx; |
59 RelationConfiguration* currentRelationConfiguration = nullptr; |
60 |
|
61 vector<AttributeMetadata> currentReaderMetadata; |
60 vector<AttributeMetadata> currentReaderMetadata; |
62 vector<writer::AttributeMetadata> currentWriterMetadata; |
61 vector<writer::AttributeMetadata> currentWriterMetadata; |
63 vector<string_t> currentRecord; |
62 vector<string_t> currentRecord; |
64 integer_t currentAttributeIndex = 0; |
63 integer_t currentAttributeIndex = 0; |
65 boolean_t includeCurrentRecord = false; |
64 boolean_t includeCurrentRecord = false; |
66 boolean_t filterCurrentRelation = false; |
|
67 string_t guileCodeWhereCondition; |
|
68 |
65 |
69 /** |
66 /** |
70 * @param attributeName name from relational pipe |
67 * @param attributeName name from relational pipe |
71 * @return variable name in Guile |
68 * @return variable name in Guile |
72 */ |
69 */ |
145 } |
142 } |
146 |
143 |
147 public: |
144 public: |
148 |
145 |
149 GuileHandler(writer::RelationalWriter* relationalWriter, Configuration& configuration, const vector<string_t>& arguments) : relationalWriter(relationalWriter), configuration(configuration) { |
146 GuileHandler(writer::RelationalWriter* relationalWriter, Configuration& configuration, const vector<string_t>& arguments) : relationalWriter(relationalWriter), configuration(configuration) { |
150 |
|
151 // FIXME: remove and work directly with configuration in startRelation() and attribute() |
|
152 // i.e. support multiple relationConfigurations |
|
153 if (configuration.relationConfigurations.size() == 1) { |
|
154 relationNameRegEx = wregex(configuration.relationConfigurations[0].relation); |
|
155 guileCodeWhereCondition = configuration.relationConfigurations[0].guileWhere; |
|
156 } else { |
|
157 throw cli::RelpipeCLIException(L"FIXME: only single relationConfiguration is currently supported", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND); |
|
158 } |
|
159 } |
147 } |
160 |
148 |
161 void startRelation(string_t name, vector<AttributeMetadata> attributes) override { |
149 void startRelation(string_t name, vector<AttributeMetadata> attributes) override { |
162 for (auto attribute : currentReaderMetadata) undefineGuileVariable(attribute.getAttributeName()); |
150 for (auto attribute : currentReaderMetadata) undefineGuileVariable(attribute.getAttributeName()); |
163 currentReaderMetadata = attributes; |
151 currentReaderMetadata = attributes; |
164 // TODO: move to a reusable method (or use same metadata on both reader and writer side?) |
152 // TODO: move to a reusable method (or use same metadata on both reader and writer side?) |
165 // TODO: allow structural changes during transformation |
153 // TODO: allow structural changes during transformation |
166 // TODO: clear Guile variables for attributes from previous relation |
|
167 currentWriterMetadata.clear(); |
154 currentWriterMetadata.clear(); |
168 for (AttributeMetadata readerMetadata : attributes) { |
155 for (AttributeMetadata readerMetadata : attributes) { |
169 currentWriterMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())}); |
156 currentWriterMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())}); |
170 } |
157 } |
171 |
158 |
172 currentRecord.resize(attributes.size()); |
159 currentRecord.resize(attributes.size()); |
173 filterCurrentRelation = regex_match(name, relationNameRegEx); |
160 |
|
161 for (int i = 0; i < configuration.relationConfigurations.size(); i++) { |
|
162 if (regex_match(name, wregex(configuration.relationConfigurations[i].relation))) { |
|
163 currentRelationConfiguration = &configuration.relationConfigurations[i]; |
|
164 break; // it there are multiple matches, only the first configuration is used |
|
165 } |
|
166 } |
174 |
167 |
175 relationalWriter->startRelation(name, currentWriterMetadata, true); |
168 relationalWriter->startRelation(name, currentWriterMetadata, true); |
176 } |
169 } |
177 |
170 |
178 void attribute(const void* value, const std::type_info& type) override { |
171 void attribute(const void* value, const std::type_info& type) override { |
179 if (filterCurrentRelation) { |
172 if (currentRelationConfiguration) { |
180 defineGuileVariable(a2v(currentReaderMetadata[currentAttributeIndex].getAttributeName()), value, type, currentReaderMetadata[currentAttributeIndex].getTypeId()); |
173 defineGuileVariable(a2v(currentReaderMetadata[currentAttributeIndex].getAttributeName()), value, type, currentReaderMetadata[currentAttributeIndex].getTypeId()); |
181 |
174 |
182 currentAttributeIndex++; |
175 currentAttributeIndex++; |
183 |
176 |
184 // TODO: > 0 ?: |
177 // TODO: > 0 ?: |
185 if (currentAttributeIndex > 0 && currentAttributeIndex % currentReaderMetadata.size() == 0) { |
178 if (currentAttributeIndex > 0 && currentAttributeIndex % currentReaderMetadata.size() == 0) { |
186 includeCurrentRecord = scm_to_bool(evalGuileCode(guileCodeWhereCondition)); |
179 includeCurrentRecord = scm_to_bool(evalGuileCode(currentRelationConfiguration->guileWhere)); |
187 if (includeCurrentRecord) for (auto attribute : currentWriterMetadata) writeGuileValueToAttribute(attribute); |
180 if (includeCurrentRecord) for (auto attribute : currentWriterMetadata) writeGuileValueToAttribute(attribute); |
188 includeCurrentRecord = false; |
181 includeCurrentRecord = false; |
189 } |
182 } |
190 |
183 |
191 currentAttributeIndex = currentAttributeIndex % currentReaderMetadata.size(); |
184 currentAttributeIndex = currentAttributeIndex % currentReaderMetadata.size(); |