26 #include <regex> |
26 #include <regex> |
27 #include <cassert> |
27 #include <cassert> |
28 |
28 |
29 #include <relpipe/reader/typedefs.h> |
29 #include <relpipe/reader/typedefs.h> |
30 #include <relpipe/reader/TypeId.h> |
30 #include <relpipe/reader/TypeId.h> |
31 #include <relpipe/reader/handlers/RelationalReaderValueHandler.h> |
31 #include <relpipe/reader/RelpipeReaderException.h> |
|
32 #include <relpipe/reader/handlers/RelationalReaderStringHandler.h> |
32 #include <relpipe/reader/handlers/AttributeMetadata.h> |
33 #include <relpipe/reader/handlers/AttributeMetadata.h> |
33 |
|
34 #include "RecfileWriter.h" |
|
35 |
34 |
36 namespace relpipe { |
35 namespace relpipe { |
37 namespace out { |
36 namespace out { |
38 namespace recfile { |
37 namespace recfile { |
39 |
38 |
40 using namespace relpipe::reader; |
39 using namespace relpipe::reader; |
41 |
40 |
42 class RecfileHandler : public handlers::RelationalReaderValueHadler { |
41 class RecfileHandler : public handlers::RelationalReaderStringHadler { |
43 private: |
42 private: |
44 shared_ptr<RecfileWriter> recfileWriter; |
43 std::ostream& output; |
45 std::vector<TypeId> columnTypes; |
44 wstring_convert<codecvt_utf8<wchar_t>> convertor; // XML output will be always in UTF-8 |
46 std::vector<string_t> columnTypeCodes; |
45 std::vector<TypeId> attributeTypes; |
47 std::vector<string_t> columnNames; |
46 std::vector<string_t> attributeTypeCodes; |
|
47 std::vector<string_t> attributeNames; |
48 integer_t valueCount = 0; |
48 integer_t valueCount = 0; |
49 integer_t columnCount = 0; |
49 integer_t attributeCount = 0; |
50 integer_t relationCount = 0; |
50 integer_t relationCount = 0; |
|
51 |
|
52 void writeRelationName(const string_t& name) { |
|
53 // FIXME: escaping/filtering |
|
54 output << "%rec: " << convertor.to_bytes(name) << std::endl; |
|
55 } |
|
56 |
|
57 const std::string toRecfileType(const TypeId& type) { |
|
58 switch (type) { |
|
59 case TypeId::BOOLEAN: return "bool"; |
|
60 case TypeId::INTEGER: return "int"; |
|
61 case TypeId::STRING: return ""; // TODO: string type? |
|
62 default: throw RelpipeReaderException(L"Unsupported type – unable to convert to a Recfile type"); |
|
63 } |
|
64 } |
|
65 |
|
66 void writeAttributeMetadata(const handlers::AttributeMetadata& attribute) { |
|
67 // FIXME: escaping/filtering |
|
68 // FIXME: translate to recfile types |
|
69 output << "%type: " << convertor.to_bytes(attribute.getAttributeName()) << " " << toRecfileType(attribute.getTypeId()) << std::endl; |
|
70 } |
|
71 |
|
72 void writeSeparator() { |
|
73 output << std::endl; |
|
74 } |
|
75 |
|
76 void writeAttribute(const string_t& name, const TypeId& type, const string_t& value) { |
|
77 // FIXME: escaping/filtering |
|
78 output << convertor.to_bytes(name) << ": "; |
|
79 |
|
80 for (char ch : convertor.to_bytes(value)) { |
|
81 output << ch; |
|
82 if (ch == '\n') output << "+ "; |
|
83 } |
|
84 |
|
85 output << std::endl; |
|
86 } |
51 |
87 |
52 public: |
88 public: |
53 |
89 |
54 RecfileHandler(std::ostream& output) : recfileWriter(new RecfileWriter(output)) { |
90 RecfileHandler(std::ostream& output) : output(output) { |
55 } |
91 } |
56 |
92 |
57 void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override { |
93 void startRelation(string_t name, std::vector<handlers::AttributeMetadata> attributes) override { |
58 valueCount = 0; |
94 valueCount = 0; |
59 columnCount = 0; |
95 attributeCount = 0; |
60 |
96 |
61 if (relationCount == 0) { |
97 if (relationCount) writeSeparator(); |
62 recfileWriter->writeStartSequence(); // root |
98 |
63 } else { |
99 relationCount++; |
64 recfileWriter->writeEndSequence(); |
100 writeRelationName(name); |
65 recfileWriter->writeEndSequence(); |
101 |
|
102 attributeCount = attributes.size(); |
|
103 attributeTypes.resize(attributeCount); |
|
104 attributeTypeCodes.resize(attributeCount); |
|
105 attributeNames.resize(attributeCount); |
|
106 for (int i = 0; i < attributes.size(); i++) { |
|
107 attributeNames[i] = attributes[i].getAttributeName(); |
|
108 attributeTypes[i] = attributes[i].getTypeId(); |
|
109 attributeTypeCodes[i] = attributes[i].getTypeName(); |
|
110 writeAttributeMetadata(attributes[i]); |
66 } |
111 } |
67 relationCount++; |
|
68 recfileWriter->writeStartSequence(); // relation |
|
69 |
|
70 recfileWriter->writeString(name); |
|
71 |
|
72 |
|
73 recfileWriter->writeStartSequence(); // relation metadata |
|
74 columnCount = attributes.size(); |
|
75 columnTypes.resize(columnCount); |
|
76 columnTypeCodes.resize(columnCount); |
|
77 columnNames.resize(columnCount); |
|
78 for (int i = 0; i < attributes.size(); i++) { |
|
79 columnNames[i] = attributes[i].getAttributeName(); |
|
80 columnTypes[i] = attributes[i].getTypeId(); |
|
81 columnTypeCodes[i] = attributes[i].getTypeName(); |
|
82 |
|
83 recfileWriter->writeStartSequence(); // attribute-metadata |
|
84 recfileWriter->writeString(columnNames[i]); |
|
85 recfileWriter->writeString(columnTypeCodes[i]); |
|
86 recfileWriter->writeEndSequence(); |
|
87 } |
|
88 recfileWriter->writeEndSequence(); |
|
89 |
|
90 } |
112 } |
91 |
113 |
92 void attribute(const void* value, const std::type_info& type) override { |
114 void attribute(const string_t& value) override { |
93 integer_t i = valueCount % columnCount; |
115 integer_t i = valueCount % attributeCount; |
94 |
116 if (i == 0) writeSeparator(); |
95 if (i == 0 && valueCount) recfileWriter->writeEndSequence(); |
|
96 if (i == 0) recfileWriter->writeStartSequence(); |
|
97 |
|
98 valueCount++; |
117 valueCount++; |
99 |
118 writeAttribute(attributeNames[i], attributeTypes[i], value); |
100 switch (columnTypes[i]) { |
|
101 case TypeId::BOOLEAN: |
|
102 { |
|
103 assert(type == typeid (boolean_t)); |
|
104 auto* typedValue = static_cast<const boolean_t*> (value); |
|
105 recfileWriter->writeBoolean(*typedValue); |
|
106 break; |
|
107 } |
|
108 case TypeId::INTEGER: |
|
109 { |
|
110 assert(type == typeid (integer_t)); |
|
111 auto* typedValue = static_cast<const integer_t*> (value); |
|
112 recfileWriter->writeInteger(*typedValue); |
|
113 break; |
|
114 } |
|
115 case TypeId::STRING: |
|
116 { |
|
117 assert(type == typeid (string_t)); |
|
118 auto* typedValue = static_cast<const string_t*> (value); |
|
119 recfileWriter->writeString(*typedValue); |
|
120 break; |
|
121 } |
|
122 default: |
|
123 throw cli::RelpipeCLIException(L"Unsupported type in RecfileHandler.attribute()", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); |
|
124 } |
|
125 |
|
126 } |
119 } |
127 |
120 |
128 void endOfPipe() { |
121 void endOfPipe() { |
129 if (valueCount) recfileWriter->writeEndSequence(); |
122 if (valueCount) writeSeparator(); |
130 if (relationCount) recfileWriter->writeEndSequence(); |
|
131 recfileWriter->writeEndSequence(); |
|
132 } |
123 } |
133 |
124 |
134 }; |
125 }; |
135 |
126 |
136 } |
127 } |