2018-09-09 18:52:32 +02:00
|
|
|
|
#include "CodeBuilder.h"
|
2018-09-18 11:53:19 +02:00
|
|
|
|
#include "FormatToStream.h"
|
2018-09-09 18:52:32 +02:00
|
|
|
|
#include "Pgsql_Result.h"
|
|
|
|
|
|
#include "IndentationConfig.h"
|
|
|
|
|
|
#include "LanguageConfig.h"
|
|
|
|
|
|
#include "StructureTemplate.h"
|
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
|
2018-09-18 11:53:19 +02:00
|
|
|
|
void CodeBuilder::GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result, QString structname)
|
2018-09-09 18:52:32 +02:00
|
|
|
|
{
|
|
|
|
|
|
// %1 query string
|
|
|
|
|
|
// %2 struct_name
|
|
|
|
|
|
// %3 list of field assignments
|
|
|
|
|
|
QString exec_query_template = "Pgsql::Result result = conn.query(%1);";
|
|
|
|
|
|
|
2018-09-18 11:53:19 +02:00
|
|
|
|
QString loop_start_template = R"__(Pgsql::Result result = conn.query(/%queryliteral%/);
|
|
|
|
|
|
for (auto row: result) {
|
|
|
|
|
|
Pgsql::Col col(row);
|
|
|
|
|
|
/%structname%/ v;
|
|
|
|
|
|
/%assignfields%/
|
|
|
|
|
|
})__";
|
2018-09-09 18:52:32 +02:00
|
|
|
|
|
|
|
|
|
|
// %field_name%
|
|
|
|
|
|
// %column_name%
|
|
|
|
|
|
// %column_index%
|
2018-09-18 11:53:19 +02:00
|
|
|
|
QString assign_result_field_template = "col >> v./%fieldname%/";
|
2018-09-09 18:52:32 +02:00
|
|
|
|
QString query_string_literal = ConvertToMultiLineCString(query);
|
|
|
|
|
|
|
2018-09-18 11:53:19 +02:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-09-09 18:52:32 +02:00
|
|
|
|
// [optional] Gen declaration of result structure
|
2018-09-18 11:53:19 +02:00
|
|
|
|
GenReturnStructDefinition(q, result, structname);
|
2018-09-09 18:52:32 +02:00
|
|
|
|
|
|
|
|
|
|
// assume we have connection? What name???
|
2018-09-18 11:53:19 +02:00
|
|
|
|
FormatToStream(q, loop_start_template, get_var_func);
|
2018-09-09 18:52:32 +02:00
|
|
|
|
|
|
|
|
|
|
// gen code for creating and executing statement
|
|
|
|
|
|
// - bind parameters
|
|
|
|
|
|
|
|
|
|
|
|
// Gen code for iterating through result and filling the result struct/or local variables
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-18 11:53:19 +02:00
|
|
|
|
void CodeBuilder::GenReturnStructDefinition(QTextStream &q, const Pgsql::Result &result, QString structname) const
|
2018-09-09 18:52:32 +02:00
|
|
|
|
{
|
|
|
|
|
|
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);
|
2018-09-18 11:53:19 +02:00
|
|
|
|
|
|
|
|
|
|
auto struct_callback = [&] (QTextStream &out, QString var) {
|
|
|
|
|
|
if (var == "structname") out << structname;
|
|
|
|
|
|
};
|
2018-09-09 18:52:32 +02:00
|
|
|
|
// Make struct start
|
2018-09-18 11:53:19 +02:00
|
|
|
|
//q << QString(templ->m_startTemplate).arg(struct_name);
|
|
|
|
|
|
FormatToStream(q, templ->m_startTemplate, struct_callback);
|
2018-09-09 18:52:32 +02:00
|
|
|
|
// Process fields
|
|
|
|
|
|
for (int column = 0; column < result.cols(); ++column) {
|
|
|
|
|
|
QString res_col_name = result.getColName(column);
|
|
|
|
|
|
Oid type_oid = result.type(column);
|
|
|
|
|
|
|
|
|
|
|
|
q << field_indent_string;
|
|
|
|
|
|
genFieldDeclaration(q, field_format, res_col_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)
|
|
|
|
|
|
}
|
|
|
|
|
|
// Finish struct
|
2018-09-18 11:53:19 +02:00
|
|
|
|
|
|
|
|
|
|
//q << QString(templ->m_endTemplate).arg(struct_name);
|
|
|
|
|
|
FormatToStream(q, templ->m_endTemplate, struct_callback);
|
2018-09-09 18:52:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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::genFieldDeclaration(QTextStream &q, const QString &format, const QString &column_name, Oid column_type) const
|
|
|
|
|
|
{
|
|
|
|
|
|
QString field_name = columnNameToVariableName(column_name);
|
|
|
|
|
|
QString type_name = getTypeName(column_type);
|
2018-09-18 11:53:19 +02:00
|
|
|
|
//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;
|
|
|
|
|
|
});
|
2018-09-09 18:52:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-18 11:53:19 +02:00
|
|
|
|
CodeBuilder::ColumnDataList CodeBuilder::createColumnDataList(const Pgsql::Result &result)
|
|
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|