48 |
48 |
49 const yaml_event_type_t getType() const { |
49 const yaml_event_type_t getType() const { |
50 return event.type; |
50 return event.type; |
51 } |
51 } |
52 |
52 |
|
53 const relpipe::writer::string_t getTypeName() const { |
|
54 return findTypeName(event.type); |
|
55 } |
|
56 |
|
57 /** Just for debugging and error handling */ |
|
58 static const relpipe::writer::string_t findTypeName(const yaml_event_type_t eventType) { |
|
59 if (eventType == YAML_NO_EVENT) return L"NO"; |
|
60 else if (eventType == YAML_STREAM_START_EVENT) return L"STREAM_START"; |
|
61 else if (eventType == YAML_STREAM_END_EVENT) return L"STREAM_END"; |
|
62 else if (eventType == YAML_DOCUMENT_START_EVENT) return L"DOCUMENT_START"; |
|
63 else if (eventType == YAML_DOCUMENT_END_EVENT) return L"DOCUMENT_END"; |
|
64 else if (eventType == YAML_ALIAS_EVENT) return L"ALIAS"; |
|
65 else if (eventType == YAML_SCALAR_EVENT) return L"SCALAR"; |
|
66 else if (eventType == YAML_SEQUENCE_START_EVENT) return L"SEQUENCE_START"; |
|
67 else if (eventType == YAML_SEQUENCE_END_EVENT) return L"SEQUENCE_END"; |
|
68 else if (eventType == YAML_MAPPING_START_EVENT) return L"MAPPING_START"; |
|
69 else if (eventType == YAML_MAPPING_END_EVENT) return L"MAPPING_END"; |
|
70 else return L"UNKNOWN"; |
|
71 } |
|
72 |
53 const yaml_event_t* getEvent() const { |
73 const yaml_event_t* getEvent() const { |
54 return &event; |
74 return &event; |
55 } |
75 } |
56 |
76 |
57 YAMLEvent(const YAMLEvent&) = delete; |
77 YAMLEvent(const YAMLEvent&) = delete; |
92 int result = yaml_parser_parse(&yamlParser, &event); |
112 int result = yaml_parser_parse(&yamlParser, &event); |
93 return result == 1 && event.type != yaml_event_type_e::YAML_NO_EVENT ? new YAMLEvent(event) : nullptr; // 1 = OK in yaml.h; YAML_NO_EVENT = end |
113 return result == 1 && event.type != yaml_event_type_e::YAML_NO_EVENT ? new YAMLEvent(event) : nullptr; // 1 = OK in yaml.h; YAML_NO_EVENT = end |
94 } |
114 } |
95 }; |
115 }; |
96 |
116 |
|
117 using YAMLEvent_p = std::shared_ptr<YAMLEvent>; |
|
118 |
97 YAMLParser parser; |
119 YAMLParser parser; |
98 |
120 std::shared_ptr<relpipe::writer::RelationalWriter> writer; |
99 using YAMLEvent_p = std::shared_ptr<YAMLEvent>; |
121 |
100 |
122 relpipe::writer::string_t relationName; |
101 enum class State { |
123 std::vector<relpipe::writer::string_t> record; |
102 START, |
124 std::vector<relpipe::writer::AttributeMetadata> attributesMetadata; |
103 RELATIONS, |
125 |
104 ATTRIBUTE, |
126 relpipe::writer::string_t y2s(const yaml_char_t* value) { |
105 RECORDS |
|
106 }; |
|
107 |
|
108 State state; |
|
109 |
|
110 relpipe::writer::string_t y2s(yaml_char_t* value) { |
|
111 return value ? convertor.from_bytes((const char*) value) : L""; |
127 return value ? convertor.from_bytes((const char*) value) : L""; |
112 } |
128 } |
113 |
129 |
114 relpipe::writer::string_t findValue(std::vector<relpipe::writer::string_t> record, relpipe::writer::string_t key) { |
130 relpipe::writer::string_t fetchScalarValue(YAMLEvent_p event) { |
115 if (record.size() % 2) relpipe::writer::RelpipeWriterException(L"Invalid count of values in the record vector"); |
131 if (event->getType() == YAML_SCALAR_EVENT) return y2s(event->getEvent()->data.scalar.value); |
116 for (size_t i = 0; i < record.size(); i += 2) { |
132 else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected SCALAR but got: " + event->getTypeName()); |
117 if (record[i] == key) return record[i + 1]; |
133 } |
118 } |
134 |
119 return L""; |
135 void consumeEvent(const yaml_event_type_t expectedEventType, relpipe::writer::string_t expectedScalarValue = L"") { |
120 } |
136 YAMLEvent_p event = YAMLEvent_p(parser.next()); |
|
137 if (!event) throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: missing event: " + YAMLEvent::findTypeName(expectedEventType)); |
|
138 if (event->getType() != expectedEventType) throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected event: " + YAMLEvent::findTypeName(expectedEventType) + L", but got: " + event->getTypeName()); |
|
139 if (expectedEventType == YAML_SCALAR_EVENT && expectedScalarValue.size() && expectedScalarValue != fetchScalarValue(event)) throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected scalar value: " + expectedScalarValue + L", but got " + fetchScalarValue(event)); |
|
140 } |
|
141 |
|
142 relpipe::writer::string_t consumeScalarEvent() { |
|
143 YAMLEvent_p event = YAMLEvent_p(parser.next()); |
|
144 if (event && event->getType() == YAML_SCALAR_EVENT) return fetchScalarValue(event); |
|
145 else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected SCALAR, but got: " + event->getTypeName()); |
|
146 } |
|
147 |
|
148 void processRelation() { |
|
149 YAMLEvent_p event = YAMLEvent_p(parser.next()); |
|
150 if (event->getType() == YAML_MAPPING_START_EVENT) processRelationWithMetadata(); |
|
151 else if (event->getType() == YAML_SEQUENCE_START_EVENT)processRelationWithoutMetadata(); |
|
152 else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected MAPPING or SEQUENCE, but got: " + event->getTypeName()); |
|
153 } |
|
154 |
|
155 void processRelationWithMetadata() { |
|
156 consumeEvent(YAML_SCALAR_EVENT, L"attribute-metadata"); |
|
157 consumeEvent(YAML_SEQUENCE_START_EVENT); |
|
158 |
|
159 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event && event->getType() != YAML_SEQUENCE_END_EVENT; event = YAMLEvent_p(parser.next())) { |
|
160 if (event->getType() != YAML_MAPPING_START_EVENT) throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected MAPPING (attribute-metadata), but got: " + event->getTypeName()); |
|
161 relpipe::writer::string_t name; |
|
162 relpipe::writer::string_t type = L"string"; |
|
163 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event && event->getType() != YAML_MAPPING_END_EVENT; event = YAMLEvent_p(parser.next())) { |
|
164 auto key = fetchScalarValue(event); |
|
165 auto value = consumeScalarEvent(); |
|
166 if (key == L"name") name = value; |
|
167 else if (key == L"type") type = value; |
|
168 else; // unsupported metadata, later there might be something useful |
|
169 } |
|
170 attributesMetadata.push_back({name, writer->toTypeId(type)}); |
|
171 } |
|
172 |
|
173 writer->startRelation(relationName, attributesMetadata, true); |
|
174 |
|
175 YAMLEvent_p event = YAMLEvent_p(parser.next()); |
|
176 if (event->getType() == YAML_SCALAR_EVENT && fetchScalarValue(event) == L"record") { |
|
177 consumeEvent(YAML_SEQUENCE_START_EVENT); |
|
178 processRecords(); |
|
179 consumeEvent(YAML_MAPPING_END_EVENT); |
|
180 } else if (event->getType() == YAML_MAPPING_END_EVENT) { |
|
181 // empty relation, no records |
|
182 } else { |
|
183 relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected 'record' or MAPPING_END, but got: " + event->getTypeName()); |
|
184 } |
|
185 } |
|
186 |
|
187 void processRelationWithoutMetadata() { |
|
188 // First record: |
|
189 consumeEvent(YAML_MAPPING_START_EVENT); |
|
190 record.clear(); |
|
191 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event && event->getType() != YAML_MAPPING_END_EVENT; event = YAMLEvent_p(parser.next())) { |
|
192 auto name = fetchScalarValue(event); |
|
193 auto value = consumeScalarEvent(); |
|
194 attributesMetadata.push_back({name, relpipe::writer::TypeId::STRING}); |
|
195 record.push_back(value); |
|
196 } |
|
197 writer->startRelation(relationName, attributesMetadata, true); |
|
198 for (auto value : record) writer->writeAttribute(value); |
|
199 |
|
200 // Following records: |
|
201 processRecords(); |
|
202 } |
|
203 |
|
204 void processRecords() { |
|
205 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event && event->getType() != YAML_SEQUENCE_END_EVENT; event = YAMLEvent_p(parser.next())) { |
|
206 if (event->getType() != YAML_MAPPING_START_EVENT) throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: expected MAPPING (record), but got: " + event->getTypeName()); |
|
207 record.clear(); |
|
208 record.resize(attributesMetadata.size()); |
|
209 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event && event->getType() != YAML_MAPPING_END_EVENT; event = YAMLEvent_p(parser.next())) { |
|
210 auto name = fetchScalarValue(event); |
|
211 auto value = consumeScalarEvent(); |
|
212 for (int i = 0; i < attributesMetadata.size(); i++) { |
|
213 if (name == attributesMetadata[i].attributeName) { |
|
214 record[i] = value; |
|
215 break; |
|
216 } |
|
217 } |
|
218 } |
|
219 for (auto value : record) writer->writeAttribute(value); |
|
220 } |
|
221 } |
|
222 |
121 |
223 |
122 public: |
224 public: |
123 |
225 |
124 YAMLCommand() { |
226 YAMLCommand() { |
125 } |
227 } |
127 virtual ~YAMLCommand() { |
229 virtual ~YAMLCommand() { |
128 } |
230 } |
129 |
231 |
130 void process(std::istream& input, std::shared_ptr<relpipe::writer::RelationalWriter> writer) { |
232 void process(std::istream& input, std::shared_ptr<relpipe::writer::RelationalWriter> writer) { |
131 parser.setInput(&input); |
233 parser.setInput(&input); |
132 |
234 this->writer = writer; |
133 relpipe::writer::string_t relationName; |
235 |
134 std::vector<relpipe::writer::string_t> record; |
236 consumeEvent(YAML_STREAM_START_EVENT); |
135 std::vector<relpipe::writer::AttributeMetadata> attributesMetadata; |
237 consumeEvent(YAML_DOCUMENT_START_EVENT); |
136 |
238 consumeEvent(YAML_MAPPING_START_EVENT); |
137 state = State::START; |
239 |
138 |
240 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event && event->getType() != YAML_MAPPING_END_EVENT; event = YAMLEvent_p(parser.next())) { |
139 for (YAMLEvent_p event = YAMLEvent_p(parser.next()); event; event = YAMLEvent_p(parser.next())) { |
241 relationName = fetchScalarValue(event); |
140 if (event->getType() == YAML_NO_EVENT) { |
242 attributesMetadata.clear(); |
141 throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: YAML_NO_EVENT"); |
243 processRelation(); |
142 } else if (event->getType() == YAML_STREAM_START_EVENT) { |
244 } |
143 } else if (event->getType() == YAML_STREAM_END_EVENT) { |
245 |
144 } else if (event->getType() == YAML_DOCUMENT_START_EVENT) { |
246 consumeEvent(YAML_DOCUMENT_END_EVENT); |
145 } else if (event->getType() == YAML_DOCUMENT_END_EVENT) { |
247 consumeEvent(YAML_STREAM_END_EVENT); |
146 } else if (event->getType() == YAML_ALIAS_EVENT) { |
|
147 } else if (event->getType() == YAML_SCALAR_EVENT) { |
|
148 relpipe::writer::string_t scalarValue = y2s(event->getEvent()->data.scalar.value); |
|
149 if (state == State::RELATIONS) relationName = scalarValue; |
|
150 else if (state == State::ATTRIBUTE) record.push_back(scalarValue); |
|
151 else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_SCALAR_EVENT"); |
|
152 } else if (event->getType() == YAML_SEQUENCE_START_EVENT) { |
|
153 if (state == State::RELATIONS) state = State::RECORDS; |
|
154 else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_SEQUENCE_START_EVENT"); |
|
155 } else if (event->getType() == YAML_SEQUENCE_END_EVENT) { |
|
156 if (state == State::RECORDS) { |
|
157 state = State::RELATIONS; |
|
158 relationName.clear(); |
|
159 attributesMetadata.clear(); |
|
160 } else { |
|
161 throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_SEQUENCE_END_EVENT"); |
|
162 } |
|
163 } else if (event->getType() == YAML_MAPPING_START_EVENT) { |
|
164 if (state == State::START) state = State::RELATIONS; |
|
165 else if (state == State::RECORDS) state = State::ATTRIBUTE; |
|
166 else if (state == State::RELATIONS) throw relpipe::writer::RelpipeWriterException(L"Not yet implemented"); // TODO: there might be also a map in the relation value (not only a sequence) that would contain metadata (i.e. data types + support for relation containing no records) |
|
167 else throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_MAPPING_START_EVENT"); |
|
168 } else if (event->getType() == YAML_MAPPING_END_EVENT) { |
|
169 if (state == State::ATTRIBUTE) { |
|
170 if (attributesMetadata.size() == 0) { |
|
171 if (record.size() % 2) relpipe::writer::RelpipeWriterException(L"Invalid count of values in the record vector"); |
|
172 for (size_t i = 0; i < record.size(); i += 2) attributesMetadata.push_back(relpipe::writer::AttributeMetadata{record[i], relpipe::writer::TypeId::STRING}); |
|
173 writer->startRelation(relationName, attributesMetadata, true); |
|
174 } |
|
175 for (auto m : attributesMetadata) writer->writeAttribute(findValue(record, m.attributeName)); |
|
176 record.clear(); |
|
177 state = State::RECORDS; |
|
178 } else if (state == State::RELATIONS) { |
|
179 break; // map of the relations ends (root) |
|
180 } else { |
|
181 throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unexpected YAML_MAPPING_END_EVENT"); |
|
182 } |
|
183 } else { |
|
184 throw relpipe::writer::RelpipeWriterException(L"Invalid YAML structure: unknown event: " + std::to_wstring(event->getType())); |
|
185 } |
|
186 } |
|
187 } |
248 } |
188 }; |
249 }; |
189 |
250 |
190 } |
251 } |
191 } |
252 } |