pgLab/pglablib/codebuilder/CodeBuilder.cpp
eelke 0c3bb27e58 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.
2018-09-19 09:55:43 +02:00

118 lines
4.2 KiB
C++

#include "CodeBuilder.h"
#include "FormatToStream.h"
#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)
{
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 == "queryliteral") out << query;
else if (var == "assignfields") genFieldRetrieval(out, columnData);
};
// [optional] Gen declaration of result structure
GenReturnStructDefinition(q, columnData, structname);
// assume we have connection? What name???
FormatToStream(q, loop_template, get_var_func);
// gen code for creating and executing statement
// - bind parameters
// Gen code for iterating through result and filling the result struct/or local variables
}
void CodeBuilder::GenReturnStructDefinition(QTextStream &q, const ColumnDataList &columns, QString structname) const
{
std::shared_ptr<const StructureTemplate> templ = m_configuration->structureTemplate();
auto struct_callback = [&] (QTextStream &out, QString var) {
if (var == "structname") out << structname;
else if (var == "structfields") genStructFields(out, columns);
};
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, 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
// then we can assume NOT NULL for the result if there are no LEFT/RIGHT JOINS or other constructs that can introduce NULL
// values
// Any way at generation time we might want to be able to specify the null handle
// - exception/error return
// - magic value
// - boost::optional
// - boolean flags
// - null pointer (useful for languages where this has no cost, other cases boolean flags will be more performant)
}
}
QString CodeBuilder::columnNameToVariableName(QString column_name) const
{
return m_configuration->columnNameToFieldName(column_name);
}
QString CodeBuilder::getTypeName(Oid dbtype) const
{
return m_configuration->getTypeName(dbtype);
}
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 type_name = getTypeName(column_type);
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) const
{
ColumnDataList list;
list.reserve(static_cast<size_t>(result.cols()));
for (int column = 0; column < result.cols(); ++column) {
Oid type_oid = result.type(column);
QString column_name = result.getColName(column);
QString field_name = columnNameToVariableName(column_name);
list.push_back({type_oid, column_name, field_name});
}
return list;
}