src/StreamRelationalWriter.h
author František Kučera <franta-hg@frantovo.cz>
Sun, 22 Jul 2018 17:19:25 +0200
branchv_0
changeset 16 3613617d3076
parent 15 8fd6c4d44071
child 17 f2cccaa9dd38
permissions -rw-r--r--
writeAttribute() with raw pointer and type_info

#pragma once

#include <string>
#include <iostream>
#include <vector>

#include "../include/typedefs.h"
#include "../include/RelationalWriter.h"
#include "../include/TypeId.h"
#include "format.h"
#include "DataTypeWriterBase.h"
#include "types/BooleanDataTypeWriter.h"
#include "types/IntegerDataTypeWriter.h"
#include "types/StringDataTypeWriter.h"

namespace relpipe {
namespace writer {

class StreamRelationalWriter : public RelationalWriter {
private:
	std::ostream &output;
	types::BooleanDataTypeWriter booleanWriter;
	types::IntegerDataTypeWriter integerWriter;
	types::StringDataTypeWriter stringWriter;
	vector<DataTypeWriterBase*> writers = {&booleanWriter, &integerWriter, &stringWriter};

	/**
	 * count of columns in the current table
	 */
	integer_t columnCount;
	/**
	 * number of column (0 = first) that will be written; after writing, the number is increased and prepared for next one
	 */
	integer_t currentColumn;

	/**
	 * types of columns in the current table
	 */
	vector<TypeId> columnTypes;

	void writeString(const string_t &stringValue, const TypeId typeId) {
		for (DataTypeWriterBase* writer : writers) if (writer->supports(typeId)) return writer->writeString(output, stringValue);
		throw RelpipeWriterException(L"Unsupported data type: " + static_cast<integer_t> (typeId));
	}

	void writeRaw(const void* value, const type_info& typeInfo, const TypeId typeId) {
		for (DataTypeWriterBase* writer : writers) if (writer->supports(typeId)) return writer->writeRaw(output, value, typeInfo);
		throw RelpipeWriterException(L"Unsupported data type: " + static_cast<integer_t> (typeId));
	}

public:

	StreamRelationalWriter(std::ostream &output) :
	output(output) {
	}

	TypeId toTypeId(const string_t typeCode) override {
		for (DataTypeWriterBase* writer : writers) if (writer->supports(typeCode)) return writer->getTypeId();
		throw RelpipeWriterException(L"Unsupported data type: " + typeCode);
	}

	string_t toTypeCode(const TypeId typeId) override {
		for (DataTypeWriterBase* writer : writers) if (writer->supports(typeId)) return writer->getTypeCode();
		throw RelpipeWriterException(L"Unsupported data type: " + static_cast<integer_t> (typeId));
	}

	void startRelation(string_t name, std::vector<std::pair<string_t, TypeId> > attributes, boolean_t writeHeader) override {
		string_t tableName = name;
		columnCount = attributes.size();
		currentColumn = 0;

		// Write table name and column count:
		integerWriter.writeValue(output, DATA_PART_START);
		stringWriter.writeValue(output, tableName);
		integerWriter.writeValue(output, columnCount);

		columnTypes.clear();
		columnTypes.resize(columnCount);

		// Write column names:
		for (size_t c = 0; c < columnCount; c++) {
			wstring columnName = attributes[c].first;
			stringWriter.writeValue(output, columnName);
		}

		// Write column types:
		for (size_t c = 0; c < columnCount; c++) {
			TypeId typeId = attributes[c].second;
			integerWriter.writeValue(output, static_cast<integer_t> (typeId));
			columnTypes[c] = typeId;
		}

	}

	void writeRecord(std::vector<string_t> attributes) override {
		// FIXME: check vector size
		// FIXME: check currentColumn == 0
		for (size_t c = 0; c < columnCount; c++) {
			// TODO: do not support multiple rows in a single method call
			if (c % columnCount == 0) {
				integerWriter.writeValue(output, DATA_PART_ROW);
			}

			wstring stringValue = attributes[c];
			TypeId typeId = columnTypes[c % columnCount];
			writeString(stringValue, typeId);
		}
	}

	void writeAttribute(const void* value, const std::type_info& type) override {
		if (currentColumn == 0) integerWriter.writeValue(output, DATA_PART_ROW);
		writeRaw(value, type, columnTypes[currentColumn]);
		if (++currentColumn == columnCount) currentColumn = 0;
	}

};

}
}