44 using namespace relpipe::reader; |
46 using namespace relpipe::reader; |
45 using namespace relpipe::reader::handlers; |
47 using namespace relpipe::reader::handlers; |
46 |
48 |
47 class GuileHandler : public RelationalReaderStringHadler { |
49 class GuileHandler : public RelationalReaderStringHadler { |
48 private: |
50 private: |
|
51 std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings. |
|
52 |
49 shared_ptr<writer::RelationalWriter> relationalWriter; |
53 shared_ptr<writer::RelationalWriter> relationalWriter; |
50 |
54 |
51 wregex relationNameRegEx; |
55 wregex relationNameRegEx; |
52 |
56 |
53 vector<AttributeMetadata> currentMetadata; |
57 vector<AttributeMetadata> currentMetadata; |
54 vector<string_t> currentRecord; |
58 vector<string_t> currentRecord; |
55 integer_t currentAttributeIndex = 0; |
59 integer_t currentAttributeIndex = 0; |
56 boolean_t includeCurrentRecord = false; |
60 boolean_t includeCurrentRecord = false; |
57 boolean_t filterCurrentRelation = false; |
61 boolean_t filterCurrentRelation = false; |
|
62 string_t guileCode; |
|
63 |
|
64 SCM toGuileSymbol(const string_t& name) { |
|
65 return scm_string_to_symbol(scm_from_locale_string(convertor.to_bytes(name).c_str())); |
|
66 } |
|
67 |
|
68 SCM toGuileString(const string_t& value) { |
|
69 return scm_from_locale_string(convertor.to_bytes(value).c_str()); |
|
70 } |
|
71 |
|
72 SCM toGuileInteger(const string_t& value) { |
|
73 return scm_from_uint64(stoul(value)); |
|
74 } |
|
75 |
|
76 SCM toGuileBoolean(const string_t& value) { |
|
77 return value == L"true" ? SCM_BOOL_T : SCM_BOOL_F; |
|
78 } |
|
79 |
|
80 void defineGuileVariable(const string_t& name, TypeId type, const string_t& value) { |
|
81 // TODO: RelationalReaderValueHadler? |
|
82 switch (type) { |
|
83 case TypeId::BOOLEAN: |
|
84 scm_define(toGuileSymbol(name), toGuileBoolean(value)); |
|
85 break; |
|
86 case TypeId::INTEGER: |
|
87 scm_define(toGuileSymbol(name), toGuileInteger(value)); |
|
88 break; |
|
89 case TypeId::STRING: |
|
90 scm_define(toGuileSymbol(name), toGuileString(value)); |
|
91 break; |
|
92 default: |
|
93 throw cli::RelpipeCLIException(L"Unsupported type in defineGuileVariable()", cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); |
|
94 } |
|
95 } |
|
96 |
|
97 void undefineGuileVariable(const string_t& name, TypeId type, const string_t& value) { |
|
98 scm_define(toGuileSymbol(name), scm_make_undefined_variable()); // undefined != (define n) |
|
99 } |
58 |
100 |
59 public: |
101 public: |
60 |
102 |
61 GuileHandler(ostream& output, const vector<string_t>& arguments) { |
103 GuileHandler(ostream& output, const vector<string_t>& arguments) { |
62 relationalWriter.reset(writer::Factory::create(output)); |
104 relationalWriter.reset(writer::Factory::create(output)); |
63 |
105 |
64 // TODO: options and parser |
106 // TODO: options and parser |
65 if (arguments.size() == 1) { |
107 if (arguments.size() == 2) { |
66 relationNameRegEx = wregex(arguments[0]); |
108 relationNameRegEx = wregex(arguments[0]); |
|
109 guileCode = arguments[1]; |
67 } else { |
110 } else { |
68 throw cli::RelpipeCLIException(L"Usage: relpipe-tr-guile <relationNameRegExp>", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND); |
111 throw cli::RelpipeCLIException(L"Usage: relpipe-tr-guile <relationNameRegExp>", cli::CLI::EXIT_CODE_UNKNOWN_COMMAND); |
69 } |
112 } |
70 } |
113 } |
71 |
114 |
72 void startRelation(string_t name, vector<AttributeMetadata> attributes) override { |
115 void startRelation(string_t name, vector<AttributeMetadata> attributes) override { |
73 currentMetadata = attributes; |
116 currentMetadata = attributes; |
74 // TODO: move to a reusable method (or use same metadata on both reader and writer side?) |
117 // TODO: move to a reusable method (or use same metadata on both reader and writer side?) |
75 vector<writer::AttributeMetadata> writerMetadata; |
118 vector<writer::AttributeMetadata> writerMetadata; |
76 for (AttributeMetadata readerMetadata : attributes) { |
119 for (AttributeMetadata readerMetadata : attributes) { |
|
120 |
77 writerMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())}); |
121 writerMetadata.push_back({readerMetadata.getAttributeName(), relationalWriter->toTypeId(readerMetadata.getTypeName())}); |
78 } |
122 } |
79 |
123 |
80 currentRecord.resize(attributes.size()); |
124 currentRecord.resize(attributes.size()); |
81 filterCurrentRelation = regex_match(name, relationNameRegEx); |
125 filterCurrentRelation = regex_match(name, relationNameRegEx); |
82 |
126 |
83 relationalWriter->startRelation(name, writerMetadata, true); |
127 relationalWriter->startRelation(name, writerMetadata, true); |
84 } |
128 } |
87 if (filterCurrentRelation) { |
131 if (filterCurrentRelation) { |
88 // TODO: evaluate condition and updates in Guile |
132 // TODO: evaluate condition and updates in Guile |
89 currentRecord[currentAttributeIndex] = value; |
133 currentRecord[currentAttributeIndex] = value; |
90 includeCurrentRecord = false; |
134 includeCurrentRecord = false; |
91 |
135 |
|
136 // TODO: remove, just a demo code |
|
137 defineGuileVariable(L"hello", TypeId::STRING, L"world"); |
|
138 defineGuileVariable(L"a", TypeId::INTEGER, L"123"); |
|
139 defineGuileVariable(L"b", TypeId::INTEGER, L"456"); |
|
140 defineGuileVariable(L"tr", TypeId::BOOLEAN, L"true"); |
|
141 defineGuileVariable(L"fa", TypeId::BOOLEAN, L"false"); |
|
142 |
|
143 //integer_t guileResult = scm_to_uint64(scm_eval_string(toGuileString(guileCode))); |
|
144 //std::wcerr << "result from Guile: " << guileResult << std::endl; |
|
145 |
|
146 includeCurrentRecord = scm_to_bool(scm_eval_string(toGuileString(guileCode))); |
|
147 //scm_shell(0, nullptr); |
|
148 // -------- |
|
149 |
|
150 |
92 currentAttributeIndex++; |
151 currentAttributeIndex++; |
93 |
152 |
94 if (currentAttributeIndex > 0 && currentAttributeIndex % currentMetadata.size() == 0) { |
153 if (currentAttributeIndex > 0 && currentAttributeIndex % currentMetadata.size() == 0) { |
95 if (includeCurrentRecord) for (string_t v : currentRecord) relationalWriter->writeAttribute(v); |
154 if (includeCurrentRecord) for (string_t v : currentRecord) relationalWriter->writeAttribute(v); |
96 includeCurrentRecord = false; |
155 includeCurrentRecord = false; |
97 } |
156 } |
98 |
157 |
99 currentAttributeIndex = currentAttributeIndex % currentMetadata.size(); |
158 currentAttributeIndex = currentAttributeIndex % currentMetadata.size(); |
100 } else { |
159 } else { |
|
160 |
101 relationalWriter->writeAttribute(value); |
161 relationalWriter->writeAttribute(value); |
102 } |
162 } |
103 } |
163 } |
104 |
164 |
105 void endOfPipe() { |
165 void endOfPipe() { |