src/YAMLCommand.h
branchv_0
changeset 3 64f8f8792470
parent 2 d68192f0e960
child 4 c176766462c5
equal deleted inserted replaced
2:d68192f0e960 3:64f8f8792470
    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 }