Further improvements to codegeneration the defaultcpp config is now called the PgLab

config as it is very specific to the PgLab codebase.

More hard programmed templates moved out of codebuilder to the language config.
This commit is contained in:
eelke 2018-09-19 09:55:43 +02:00
parent 0ba632afd1
commit 0c3bb27e58
10 changed files with 143 additions and 91 deletions

View file

@ -3,45 +3,30 @@
#include "Pgsql_Result.h"
#include "IndentationConfig.h"
#include "LanguageConfig.h"
#include "ResultLoopTemplate.h"
#include "StructureTemplate.h"
#include "util.h"
#include <QTextStream>
void CodeBuilder::GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result, QString structname)
{
// %1 query string
// %2 struct_name
// %3 list of field assignments
QString exec_query_template = "Pgsql::Result result = conn.query(%1);";
QString loop_start_template = R"__(Pgsql::Result result = conn.query(/%queryliteral%/);
for (auto row: result) {
Pgsql::Col col(row);
/%structname%/ v;
/%assignfields%/
})__";
// %field_name%
// %column_name%
// %column_index%
QString assign_result_field_template = "col >> v./%fieldname%/";
QString loop_template = m_configuration->resultLoopTemplate()->m_loopTemplate;;
QString query_string_literal = ConvertToMultiLineCString(query);
ColumnDataList columnData = createColumnDataList(result);
auto get_var_func = [&] (QTextStream &out, QString var) {
if (var == "structname") out << structname;
//else if (var == "assign_fields") GenFieldAssignments(out);
else if (var == "queryliteral") out << query;
else if (var == "assignfields") genFieldRetrieval(out, columnData);
};
// [optional] Gen declaration of result structure
GenReturnStructDefinition(q, result, structname);
GenReturnStructDefinition(q, columnData, structname);
// assume we have connection? What name???
FormatToStream(q, loop_start_template, get_var_func);
FormatToStream(q, loop_template, get_var_func);
// gen code for creating and executing statement
// - bind parameters
@ -51,27 +36,30 @@ for (auto row: result) {
}
void CodeBuilder::GenReturnStructDefinition(QTextStream &q, const Pgsql::Result &result, QString structname) const
void CodeBuilder::GenReturnStructDefinition(QTextStream &q, const ColumnDataList &columns, QString structname) const
{
std::shared_ptr<const StructureTemplate> templ = m_configuration->structureTemplate();
QString field_format = templ->m_fieldTemplate;
int field_indent_levels = templ->m_fieldIndentation;
QString field_indent_string = m_configuration->indentationConfig()->getIndentString(field_indent_levels);
auto struct_callback = [&] (QTextStream &out, QString var) {
if (var == "structname") out << structname;
else if (var == "structfields") genStructFields(out, columns);
};
// Make struct start
//q << QString(templ->m_startTemplate).arg(struct_name);
FormatToStream(q, templ->m_startTemplate, struct_callback);
// Process fields
for (int column = 0; column < result.cols(); ++column) {
QString res_col_name = result.getColName(column);
Oid type_oid = result.type(column);
FormatToStream(q, templ->m_structTemplate, struct_callback);
}
void CodeBuilder::genStructFields(QTextStream &q, const ColumnDataList &columns) const
{
std::shared_ptr<const StructureTemplate> templ = m_configuration->structureTemplate();
QString field_format = templ->m_fieldTemplate;
const int field_indent_levels = templ->m_fieldIndentation;
QString field_indent_string = m_configuration->indentationConfig()->getIndentString(field_indent_levels);
for (auto col : columns) {
QString field_name = col.varName;
Oid type_oid = col.oid;
q << field_indent_string;
genFieldDeclaration(q, field_format, res_col_name, type_oid);
genFieldDeclaration(q, field_format, field_name, type_oid);
q << "\n";
// Unfortunatly there is no easy reliable way to determine if a column can contain null values
// For simple result columns we can have a look at the original column and if that has a NOT NULL constraint
@ -85,10 +73,6 @@ void CodeBuilder::GenReturnStructDefinition(QTextStream &q, const Pgsql::Result
// - boolean flags
// - null pointer (useful for languages where this has no cost, other cases boolean flags will be more performant)
}
// Finish struct
//q << QString(templ->m_endTemplate).arg(struct_name);
FormatToStream(q, templ->m_endTemplate, struct_callback);
}
QString CodeBuilder::columnNameToVariableName(QString column_name) const
@ -101,18 +85,26 @@ QString CodeBuilder::getTypeName(Oid dbtype) const
return m_configuration->getTypeName(dbtype);
}
void CodeBuilder::genFieldDeclaration(QTextStream &q, const QString &format, const QString &column_name, Oid column_type) const
void CodeBuilder::genFieldRetrieval(QTextStream &q, const ColumnDataList &columns) const
{
QString assign_result_field_template = m_configuration->resultLoopTemplate()->m_retrieveValueTemplate;
for (auto col : columns) {
FormatToStream(q, assign_result_field_template, [&col] (QTextStream &out, QString var) {
if (var == "varname") out << col.varName;
});
}
}
void CodeBuilder::genFieldDeclaration(QTextStream &q, const QString &format, const QString &field_name, Oid column_type) const
{
QString field_name = columnNameToVariableName(column_name);
QString type_name = getTypeName(column_type);
//q << QString(format).arg(field_name).arg(type_name);
FormatToStream(q, format, [&] (QTextStream &out, QString var) {
if (var == "typename") out << type_name;
else if (var == "varname") out << field_name;
});
}
CodeBuilder::ColumnDataList CodeBuilder::createColumnDataList(const Pgsql::Result &result)
CodeBuilder::ColumnDataList CodeBuilder::createColumnDataList(const Pgsql::Result &result) const
{
ColumnDataList list;
list.reserve(static_cast<size_t>(result.cols()));