src/TabularPrefetchingHandler.h
branchv_0
changeset 40 59f3cb26bfe7
parent 39 f33464965693
child 41 e1339b8e838e
equal deleted inserted replaced
39:f33464965693 40:59f3cb26bfe7
    38 
    38 
    39 using namespace relpipe::reader;
    39 using namespace relpipe::reader;
    40 
    40 
    41 class TabularPrefetchingHandler : public handlers::RelationalReaderStringHandler {
    41 class TabularPrefetchingHandler : public handlers::RelationalReaderStringHandler {
    42 private:
    42 private:
    43 	
    43 
    44 	class ColorScheme {
    44 	class ColorScheme {
    45 	};
    45 	public:
    46 	
    46 		const char* ESC_BRIGHT = "\u001b[1m";
       
    47 		const char* ESC_RED = "\u001b[31m";
       
    48 		const char* ESC_GREEN = "\u001b[32m";
       
    49 		const char* ESC_BLUE = "\u001b[34m";
       
    50 		const char* ESC_YELLOW = "\u001b[33m";
       
    51 		const char* ESC_AMBER = "\u001b[38;5;166m";
       
    52 		const char* ESC_CYAN = "\u001b[36m";
       
    53 		const char* ESC_RESET = "\u001b[0m";
       
    54 		const char* ESC_EMPTY = "";
       
    55 
       
    56 		const char* header = ESC_BRIGHT;
       
    57 		const char* border = ESC_GREEN;
       
    58 		const char* value = ESC_CYAN;
       
    59 		const char* relation = ESC_RED;
       
    60 		const char* replacement = ESC_RED;
       
    61 		const char* count = ESC_YELLOW;
       
    62 		const char* reset = ESC_RESET;
       
    63 	} cs;
       
    64 
    47 	std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings.
    65 	std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings.
    48 	const char* ESC_BRIGHT = "\u001b[1m";
    66 
    49 	const char* ESC_RED = "\u001b[31m";
       
    50 	const char* ESC_GREEN = "\u001b[32m";
       
    51 	const char* ESC_YELLOW = "\u001b[33m";
       
    52 	const char* ESC_CYAN = "\u001b[36m";
       
    53 	const char* ESC_RESET = "\u001b[0m";
       
    54 
       
    55 	const char* ESC_HEADER = ESC_BRIGHT;
       
    56 	const char* ESC_BORDER = ESC_GREEN;
       
    57 	const char* ESC_VALUE = ESC_CYAN;
       
    58 	const char* ESC_RELATION = ESC_RED;
       
    59 	const char* ESC_REPLACEMENT = ESC_RED;
       
    60 	const char* ESC_COUNT = ESC_YELLOW;
       
    61 
    67 
    62 	const char* INDENT = " "; // table indent from the left
    68 	const char* INDENT = " "; // table indent from the left
    63 
    69 
    64 	std::ostream& output;
    70 	std::ostream& output;
    65 	Configuration& configuration;
    71 	Configuration& configuration;
    73 	std::vector<integer_t> columnWidths;
    79 	std::vector<integer_t> columnWidths;
    74 	std::vector<string_t> values; // all values are saved here and processed at the end of the relation
    80 	std::vector<string_t> values; // all values are saved here and processed at the end of the relation
    75 	integer_t columnCount = 0;
    81 	integer_t columnCount = 0;
    76 
    82 
    77 	const string_t colorizeReplacement(const string_t &replacement, const char* valueColor) {
    83 	const string_t colorizeReplacement(const string_t &replacement, const char* valueColor) {
    78 		return convertor.from_bytes(ESC_RESET) + convertor.from_bytes(ESC_REPLACEMENT) + replacement + convertor.from_bytes(ESC_RESET) + convertor.from_bytes(valueColor);
    84 		return convertor.from_bytes(cs.reset) + convertor.from_bytes(cs.replacement) + replacement + convertor.from_bytes(cs.reset) + convertor.from_bytes(valueColor);
    79 	}
    85 	}
    80 
    86 
    81 	/**
    87 	/**
    82 	 * Sanitizes whitespace that could broke table layout.
    88 	 * Sanitizes whitespace that could broke table layout.
    83 	 * 
    89 	 * 
   111 					break;
   117 					break;
   112 				default: result << ch;
   118 				default: result << ch;
   113 			}
   119 			}
   114 		}
   120 		}
   115 
   121 
   116 		result << convertor.from_bytes(ESC_RESET);
   122 		result << convertor.from_bytes(cs.reset);
   117 
   123 
   118 		return result.str();
   124 		return result.str();
   119 	}
   125 	}
   120 
   126 
   121 	/**
   127 	/**
   144 		}
   150 		}
   145 		return width;
   151 		return width;
   146 	}
   152 	}
   147 
   153 
   148 	void printHorizontalLine(const string_t& left, const string_t& middle, const string_t& right, const string_t& bar) {
   154 	void printHorizontalLine(const string_t& left, const string_t& middle, const string_t& right, const string_t& bar) {
   149 		output << INDENT << ESC_BORDER;
   155 		output << INDENT << cs.border;
   150 		output << convertor.to_bytes(left);
   156 		output << convertor.to_bytes(left);
   151 		for (size_t c = 0; c < columnCount; c++) {
   157 		for (size_t c = 0; c < columnCount; c++) {
   152 			integer_t width = columnWidths[c];
   158 			integer_t width = columnWidths[c];
   153 			for (integer_t w = 0; w < (width + 2); w++) output << convertor.to_bytes(bar); // 2 = left and right padding of the value
   159 			for (integer_t w = 0; w < (width + 2); w++) output << convertor.to_bytes(bar); // 2 = left and right padding of the value
   154 			if (c < (columnCount - 1)) output << convertor.to_bytes(middle);
   160 			if (c < (columnCount - 1)) output << convertor.to_bytes(middle);
   155 		}
   161 		}
   156 		output << convertor.to_bytes(right);
   162 		output << convertor.to_bytes(right);
   157 		output << ESC_RESET << std::endl;
   163 		output << cs.reset << std::endl;
   158 
   164 
   159 	}
   165 	}
   160 
   166 
   161 	void printCachedData() {
   167 	void printCachedData() {
   162 		// Compute column widths and paddings:
   168 		// Compute column widths and paddings:
   183 		else if (configuration.tableStyle == Configuration::TableStyle::HorizontalOnly) verticalSeparator = " ";
   189 		else if (configuration.tableStyle == Configuration::TableStyle::HorizontalOnly) verticalSeparator = " ";
   184 		else if (configuration.tableStyle == Configuration::TableStyle::Ascii) verticalSeparator = "|";
   190 		else if (configuration.tableStyle == Configuration::TableStyle::Ascii) verticalSeparator = "|";
   185 		else throw RelpipeReaderException(L"Unsupported TableStyle: " + std::to_wstring((int) configuration.tableStyle));
   191 		else throw RelpipeReaderException(L"Unsupported TableStyle: " + std::to_wstring((int) configuration.tableStyle));
   186 
   192 
   187 		// Print column headers:
   193 		// Print column headers:
   188 		output << INDENT << ESC_BORDER << verticalSeparator << ESC_RESET;
   194 		output << INDENT << cs.border << verticalSeparator << cs.reset;
   189 		for (size_t i = 0; i < columnCount; i++) {
   195 		for (size_t i = 0; i < columnCount; i++) {
   190 			output << " " << convertor.to_bytes(formatValue(columnNames[i], ESC_HEADER));
   196 			output << " " << convertor.to_bytes(formatValue(columnNames[i], cs.header));
   191 			for (integer_t p = 0; p < paddings[i]; p++) {
   197 			for (integer_t p = 0; p < paddings[i]; p++) {
   192 				output << " ";
   198 				output << " ";
   193 			}
   199 			}
   194 			if (getConfiguration(writeTypes)) output << " (" << convertor.to_bytes(columnTypeCodes[i]) << ")";
   200 			if (getConfiguration(writeTypes)) output << " (" << convertor.to_bytes(columnTypeCodes[i]) << ")";
   195 			output << ESC_BORDER << " " << verticalSeparator << ESC_RESET;
   201 			output << cs.border << " " << verticalSeparator << cs.reset;
   196 		}
   202 		}
   197 		output << std::endl;
   203 		output << std::endl;
   198 		if (configuration.tableStyle == Configuration::TableStyle::Rounded) printHorizontalLine(L"├", L"┼", L"┤", L"─");
   204 		if (configuration.tableStyle == Configuration::TableStyle::Rounded) printHorizontalLine(L"├", L"┼", L"┤", L"─");
   199 		else if (configuration.tableStyle == Configuration::TableStyle::Sharp) printHorizontalLine(L"├", L"┼", L"┤", L"─");
   205 		else if (configuration.tableStyle == Configuration::TableStyle::Sharp) printHorizontalLine(L"├", L"┼", L"┤", L"─");
   200 		else if (configuration.tableStyle == Configuration::TableStyle::SharpDouble) printHorizontalLine(L"╠", L"╬", L"╣", L"═");
   206 		else if (configuration.tableStyle == Configuration::TableStyle::SharpDouble) printHorizontalLine(L"╠", L"╬", L"╣", L"═");
   203 		else throw RelpipeReaderException(L"Unsupported TableStyle: " + std::to_wstring((int) configuration.tableStyle));
   209 		else throw RelpipeReaderException(L"Unsupported TableStyle: " + std::to_wstring((int) configuration.tableStyle));
   204 
   210 
   205 		// Print particular rows:
   211 		// Print particular rows:
   206 		for (size_t i = 0; i < values.size(); i++) {
   212 		for (size_t i = 0; i < values.size(); i++) {
   207 			integer_t columnIndex = i % columnCount;
   213 			integer_t columnIndex = i % columnCount;
   208 			if (columnIndex == 0) output << INDENT << ESC_BORDER << verticalSeparator << ESC_RESET;
   214 			if (columnIndex == 0) output << INDENT << cs.border << verticalSeparator << cs.reset;
   209 			string_t stringValue = values[i];
   215 			string_t stringValue = values[i];
   210 			integer_t padding = columnWidths[columnIndex] - computeWidth(stringValue);
   216 			integer_t padding = columnWidths[columnIndex] - computeWidth(stringValue);
   211 			boolean_t alignRight = columnTypes[columnIndex] == TypeId::BOOLEAN || columnTypes[columnIndex] == TypeId::INTEGER;
   217 			boolean_t alignRight = columnTypes[columnIndex] == TypeId::BOOLEAN || columnTypes[columnIndex] == TypeId::INTEGER;
   212 
   218 
   213 			if (alignRight) for (integer_t p = 0; p < padding; p++) output << " ";
   219 			if (alignRight) for (integer_t p = 0; p < padding; p++) output << " ";
   214 			output << " " << convertor.to_bytes(formatValue(stringValue, ESC_VALUE));
   220 			output << " " << convertor.to_bytes(formatValue(stringValue, cs.value));
   215 			if (!alignRight) for (integer_t p = 0; p < padding; p++) output << " ";
   221 			if (!alignRight) for (integer_t p = 0; p < padding; p++) output << " ";
   216 
   222 
   217 			output << ESC_BORDER << " " << verticalSeparator << ESC_RESET;
   223 			output << cs.border << " " << verticalSeparator << cs.reset;
   218 			if (columnIndex == (columnCount - 1)) output << std::endl;
   224 			if (columnIndex == (columnCount - 1)) output << std::endl;
   219 		}
   225 		}
   220 		if (configuration.tableStyle == Configuration::TableStyle::Rounded) printHorizontalLine(L"╰", L"┴", L"╯", L"─");
   226 		if (configuration.tableStyle == Configuration::TableStyle::Rounded) printHorizontalLine(L"╰", L"┴", L"╯", L"─");
   221 		else if (configuration.tableStyle == Configuration::TableStyle::Sharp) printHorizontalLine(L"└", L"┴", L"┘", L"─");
   227 		else if (configuration.tableStyle == Configuration::TableStyle::Sharp) printHorizontalLine(L"└", L"┴", L"┘", L"─");
   222 		else if (configuration.tableStyle == Configuration::TableStyle::SharpDouble) printHorizontalLine(L"╚", L"╩", L"╝", L"═");
   228 		else if (configuration.tableStyle == Configuration::TableStyle::SharpDouble) printHorizontalLine(L"╚", L"╩", L"╝", L"═");
   224 		else if (configuration.tableStyle == Configuration::TableStyle::Ascii) printHorizontalLine(L"+", L"+", L"+", L"-");
   230 		else if (configuration.tableStyle == Configuration::TableStyle::Ascii) printHorizontalLine(L"+", L"+", L"+", L"-");
   225 		else throw RelpipeReaderException(L"Unsupported TableStyle: " + std::to_wstring((int) configuration.tableStyle));
   231 		else throw RelpipeReaderException(L"Unsupported TableStyle: " + std::to_wstring((int) configuration.tableStyle));
   226 
   232 
   227 		if (getConfiguration(writeRecordCount)) {
   233 		if (getConfiguration(writeRecordCount)) {
   228 			integer_t recordCount = values.size() / columnCount;
   234 			integer_t recordCount = values.size() / columnCount;
   229 			output << ESC_COUNT << "Record count: " << ESC_RESET << recordCount << std::endl;
   235 			output << cs.count << "Record count: " << cs.reset << recordCount << std::endl;
   230 		}
   236 		}
   231 
   237 
   232 		values.clear();
   238 		values.clear();
   233 	}
   239 	}
   234 
   240 
   246 				currentRelationConfiguration = &configuration.relationConfigurations[i];
   252 				currentRelationConfiguration = &configuration.relationConfigurations[i];
   247 				break; // it there are multiple matches, only the first configuration is used
   253 				break; // it there are multiple matches, only the first configuration is used
   248 			}
   254 			}
   249 		}
   255 		}
   250 
   256 
   251 		if (getConfiguration(writeRelationName)) output << ESC_RELATION << convertor.to_bytes(name) << ":" << ESC_RESET << endl;
   257 		if (configuration.colorScheme == Configuration::ColorScheme::Greenish) {
       
   258 			cs = ColorScheme();
       
   259 		} else if (configuration.colorScheme == Configuration::ColorScheme::Amberish) {
       
   260 			cs = ColorScheme();
       
   261 			cs.border = cs.ESC_YELLOW;
       
   262 			cs.value = cs.ESC_AMBER;
       
   263 		} else if (configuration.colorScheme == Configuration::ColorScheme::Monochrome) {
       
   264 			cs = ColorScheme();
       
   265 			cs.border = cs.ESC_EMPTY;
       
   266 			cs.count = cs.ESC_EMPTY;
       
   267 			cs.header = cs.ESC_EMPTY;
       
   268 			cs.relation = cs.ESC_EMPTY;
       
   269 			cs.replacement = cs.ESC_EMPTY;
       
   270 			cs.reset = cs.ESC_EMPTY;
       
   271 			cs.value = cs.ESC_EMPTY;
       
   272 		} else if (configuration.colorScheme == Configuration::ColorScheme::Midnight) {
       
   273 			cs = ColorScheme();
       
   274 			cs.relation = cs.ESC_CYAN;
       
   275 			cs.count = cs.ESC_CYAN;
       
   276 			cs.border = cs.ESC_BLUE;
       
   277 			cs.value = cs.ESC_EMPTY;
       
   278 		} else {
       
   279 			throw RelpipeReaderException(L"Unsupported ColorScheme: " + std::to_wstring((int) configuration.colorScheme));
       
   280 		}
       
   281 
       
   282 		if (getConfiguration(writeRelationName)) output << cs.relation << convertor.to_bytes(name) << ":" << cs.reset << endl;
   252 		columnCount = attributes.size();
   283 		columnCount = attributes.size();
   253 		columnTypes.resize(columnCount);
   284 		columnTypes.resize(columnCount);
   254 		columnTypeCodes.resize(columnCount);
   285 		columnTypeCodes.resize(columnCount);
   255 		columnNames.resize(columnCount);
   286 		columnNames.resize(columnCount);
   256 		columnWidths.resize(columnCount, 0);
   287 		columnWidths.resize(columnCount, 0);