Gen code for query #78

Merged
eelke merged 11 commits from gen-code-for-query into master 2018-09-23 08:38:07 +00:00
10 changed files with 143 additions and 91 deletions
Showing only changes of commit 0c3bb27e58 - Show all commits

View file

@ -42,7 +42,7 @@ void CodeGenerator::generateCode()
QString buffer; QString buffer;
QTextStream stream(&buffer); QTextStream stream(&buffer);
CodeBuilder builder; CodeBuilder builder;
builder.setLanguageConfig(getDefaultCppLanguageConfig()); builder.setLanguageConfig(getPglabCppLanguageConfig());
builder.GenCodeForExecutingQuery(stream, m_query, *m_dbres, struct_name); builder.GenCodeForExecutingQuery(stream, m_query, *m_dbres, struct_name);
stream.flush(); stream.flush();
ui->generatedCodeEditor->setPlainText(buffer); ui->generatedCodeEditor->setPlainText(buffer);

View file

@ -3,45 +3,30 @@
#include "Pgsql_Result.h" #include "Pgsql_Result.h"
#include "IndentationConfig.h" #include "IndentationConfig.h"
#include "LanguageConfig.h" #include "LanguageConfig.h"
#include "ResultLoopTemplate.h"
#include "StructureTemplate.h" #include "StructureTemplate.h"
#include "util.h" #include "util.h"
#include <QTextStream> #include <QTextStream>
void CodeBuilder::GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result, QString structname) void CodeBuilder::GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result, QString structname)
{ {
// %1 query string QString loop_template = m_configuration->resultLoopTemplate()->m_loopTemplate;;
// %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 query_string_literal = ConvertToMultiLineCString(query); QString query_string_literal = ConvertToMultiLineCString(query);
ColumnDataList columnData = createColumnDataList(result); ColumnDataList columnData = createColumnDataList(result);
auto get_var_func = [&] (QTextStream &out, QString var) { auto get_var_func = [&] (QTextStream &out, QString var) {
if (var == "structname") out << structname; if (var == "structname") out << structname;
//else if (var == "assign_fields") GenFieldAssignments(out);
else if (var == "queryliteral") out << query; else if (var == "queryliteral") out << query;
else if (var == "assignfields") genFieldRetrieval(out, columnData);
}; };
// [optional] Gen declaration of result structure // [optional] Gen declaration of result structure
GenReturnStructDefinition(q, result, structname); GenReturnStructDefinition(q, columnData, structname);
// assume we have connection? What name??? // 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 // gen code for creating and executing statement
// - bind parameters // - 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(); 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) { auto struct_callback = [&] (QTextStream &out, QString var) {
if (var == "structname") out << structname; 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; q << field_indent_string;
genFieldDeclaration(q, field_format, res_col_name, type_oid); genFieldDeclaration(q, field_format, field_name, type_oid);
q << "\n"; q << "\n";
// Unfortunatly there is no easy reliable way to determine if a column can contain null values // 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 // 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 // - boolean flags
// - null pointer (useful for languages where this has no cost, other cases boolean flags will be more performant) // - 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 QString CodeBuilder::columnNameToVariableName(QString column_name) const
@ -101,18 +85,26 @@ QString CodeBuilder::getTypeName(Oid dbtype) const
return m_configuration->getTypeName(dbtype); 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); QString type_name = getTypeName(column_type);
//q << QString(format).arg(field_name).arg(type_name);
FormatToStream(q, format, [&] (QTextStream &out, QString var) { FormatToStream(q, format, [&] (QTextStream &out, QString var) {
if (var == "typename") out << type_name; if (var == "typename") out << type_name;
else if (var == "varname") out << field_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; ColumnDataList list;
list.reserve(static_cast<size_t>(result.cols())); list.reserve(static_cast<size_t>(result.cols()));

View file

@ -10,12 +10,22 @@ class QTextStream;
class CodeBuilder { class CodeBuilder {
public: public:
class ColumnData {
public:
Oid oid;
QString columnName;
QString varName; ///< either field of the struct or in loop local var name
};
using ColumnDataList = std::vector<ColumnData>;
ColumnDataList createColumnDataList(const Pgsql::Result &result) const;
void setLanguageConfig(std::shared_ptr<const LanguageConfig> config){ void setLanguageConfig(std::shared_ptr<const LanguageConfig> config){
m_configuration = config; m_configuration = config;
} }
void GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result, QString structname); void GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result, QString structname);
void GenReturnStructDefinition(QTextStream &q, const Pgsql::Result &result, QString structname) const; void GenReturnStructDefinition(QTextStream &q, const ColumnDataList &columns, QString structname) const;
// Generating code for performing query and going through the result // Generating code for performing query and going through the result
// - Code for executing the query // - Code for executing the query
@ -25,21 +35,13 @@ public:
QString columnNameToVariableName(QString column_name) const; QString columnNameToVariableName(QString column_name) const;
QString getTypeName(Oid dbtype) const; QString getTypeName(Oid dbtype) const;
private: private:
class ColumnData {
public:
Oid oid;
QString columnName;
QString varName; ///< either field of the struct or in loop local var name
};
using ColumnDataList = std::vector<ColumnData>;
std::shared_ptr<const LanguageConfig> m_configuration; std::shared_ptr<const LanguageConfig> m_configuration;
void genStructFields(QTextStream &q, const ColumnDataList &columns) const;
void genFieldRetrieval(QTextStream &q, const ColumnDataList &columns) const;
void genFieldDeclaration(QTextStream &q, const QString &format, const QString &field_name, Oid column_type) const;
void GenFieldAssignments(QTextStream &q, const Pgsql::Result &result);
void genFieldDeclaration(QTextStream &q, const QString &format, const QString &column_name, Oid column_type) const;
ColumnDataList createColumnDataList(const Pgsql::Result &result);
}; };
#endif // CODEBUILDER_H #endif // CODEBUILDER_H

View file

@ -2,13 +2,14 @@
#include "IndentationConfig.h" #include "IndentationConfig.h"
#include "LanguageConfig.h" #include "LanguageConfig.h"
#include "NameManglingRules.h" #include "NameManglingRules.h"
#include "ResultLoopTemplate.h"
#include "StructureTemplate.h" #include "StructureTemplate.h"
#include "TypeMappings.h" #include "TypeMappings.h"
#include "Pgsql_oids.h" #include "Pgsql_oids.h"
using namespace Pgsql; using namespace Pgsql;
std::shared_ptr<const TypeMappings> GetDefaultCppTypeMappings() std::shared_ptr<const TypeMappings> GetPglabCppTypeMappings()
{ {
auto tm = std::make_shared<TypeMappings>(); auto tm = std::make_shared<TypeMappings>();
*tm = { *tm = {
@ -28,40 +29,57 @@ std::shared_ptr<const TypeMappings> GetDefaultCppTypeMappings()
return tm; return tm;
} }
std::shared_ptr<StructureTemplate> buildPglabStructureTemplate()
{
auto t = std::make_shared<StructureTemplate>();
t->m_structTemplate =
R"__(class /%structname%/ {
public:
/%structfields%/
};
using /%structname%/Lst = std::vector</%structname%/>;
)__";
std::shared_ptr<LanguageConfig> buildDefaultCppLanguageConfig() t->m_fieldTemplate = "/%typename%/ /%varname%/;";
//st_templ->m_fieldSeparator;
return t;
}
std::shared_ptr<ResultLoopTemplate> buildPglabResultLoopTemplate()
{
auto t = std::make_shared<ResultLoopTemplate>();
t->m_loopTemplate =
R"__(Pgsql::Result result = conn.query(/%queryliteral%/);
/%structname%/Lst lst;
for (auto row: result) {
Pgsql::Col col(row);
/%structname%/ v;
col
/%assignfields%/;
lst.push_back(v);
}
)__";
t->m_retrieveValueTemplate = " >> v./%varname%/";
return t;
}
std::shared_ptr<LanguageConfig> buildPglabCppLanguageConfig()
{ {
auto config = std::make_shared<LanguageConfig>(); auto config = std::make_shared<LanguageConfig>();
config->setTypeMappings(GetDefaultCppTypeMappings()); config->setTypeMappings(GetPglabCppTypeMappings());
config->setNameManglingRules(std::make_shared<NameManglingRules>()); config->setNameManglingRules(std::make_shared<NameManglingRules>());
config->setStructureTemplate(buildPglabStructureTemplate());
auto st_templ = std::make_shared<StructureTemplate>();
st_templ->m_startTemplate = "class /%structname%/ {\npublic:\n";
st_templ->m_endTemplate = "};\n"; // };
st_templ->m_fieldTemplate = "/%typename%/ /%varname%/;";
//st_templ->m_fieldSeparator;
config->setStructureTemplate(st_templ);
config->setIndentationConfig(std::make_shared<IndentationConfig>()); config->setIndentationConfig(std::make_shared<IndentationConfig>());
config->setResultLoopTemplate(buildPglabResultLoopTemplate());
return config; return config;
} }
std::shared_ptr<const LanguageConfig> getDefaultCppLanguageConfig()
{ std::shared_ptr<const LanguageConfig> getPglabCppLanguageConfig()
static auto config = buildDefaultCppLanguageConfig(); {
return config; static auto config = buildPglabCppLanguageConfig();
}
std::shared_ptr<const LanguageConfig> buildPgLabCppLanguageConfig()
{
auto cfg = buildDefaultCppLanguageConfig();
return cfg;
}
std::shared_ptr<const LanguageConfig> getPgLabCppLanguageConfig()
{
static auto config = buildPgLabCppLanguageConfig();
return config; return config;
} }

View file

@ -5,7 +5,7 @@
class LanguageConfig; class LanguageConfig;
std::shared_ptr<const LanguageConfig> getDefaultCppLanguageConfig(); //std::shared_ptr<const LanguageConfig> getDefaultCppLanguageConfig();
std::shared_ptr<const LanguageConfig> getPgLabCppLanguageConfig(); std::shared_ptr<const LanguageConfig> getPglabCppLanguageConfig();
#endif // DEFAULTCONFIGS_H #endif // DEFAULTCONFIGS_H

View file

@ -48,3 +48,13 @@ void LanguageConfig::setIndentationConfig(std::shared_ptr<const IndentationConfi
{ {
m_indentationConfig = indentation_config; m_indentationConfig = indentation_config;
} }
std::shared_ptr<const ResultLoopTemplate> LanguageConfig::resultLoopTemplate() const
{
return m_resultLoopTemplate;
}
void LanguageConfig::setResultLoopTemplate(std::shared_ptr<const ResultLoopTemplate> result_loop_template)
{
m_resultLoopTemplate = result_loop_template;
}

View file

@ -8,6 +8,7 @@ class NameManglingRules;
class TypeMappings; class TypeMappings;
class StructureTemplate; class StructureTemplate;
class IndentationConfig; class IndentationConfig;
class ResultLoopTemplate;
/** /**
* *
*/ */
@ -25,6 +26,8 @@ public:
void setStructureTemplate(std::shared_ptr<const StructureTemplate> structure_template); void setStructureTemplate(std::shared_ptr<const StructureTemplate> structure_template);
std::shared_ptr<const IndentationConfig> indentationConfig() const; std::shared_ptr<const IndentationConfig> indentationConfig() const;
void setIndentationConfig(std::shared_ptr<const IndentationConfig> indentation_config); void setIndentationConfig(std::shared_ptr<const IndentationConfig> indentation_config);
std::shared_ptr<const ResultLoopTemplate> resultLoopTemplate() const;
void setResultLoopTemplate(std::shared_ptr<const ResultLoopTemplate> result_loop_template);
private: private:
/** Default template for declaring a variable of the correct type. /** Default template for declaring a variable of the correct type.
* exmaple: "{$type} {$varname};" * exmaple: "{$type} {$varname};"
@ -34,13 +37,12 @@ private:
std::shared_ptr<const TypeMappings> m_typeMappings; std::shared_ptr<const TypeMappings> m_typeMappings;
std::shared_ptr<const StructureTemplate> m_structureTemplate; std::shared_ptr<const StructureTemplate> m_structureTemplate;
std::shared_ptr<const IndentationConfig> m_indentationConfig; std::shared_ptr<const IndentationConfig> m_indentationConfig;
std::shared_ptr<const ResultLoopTemplate> m_resultLoopTemplate;
enum class VariableStrategy { enum class VariableStrategy {
UseLocalVariables, UseLocalVariables,
DeclareClass DeclareClass
}; };
}; };
#endif // LANGUAGECONFIG_H #endif // LANGUAGECONFIG_H

View file

@ -0,0 +1,26 @@
#ifndef RESULTLOOPTEMPLATE_H
#define RESULTLOOPTEMPLATE_H
#include <QString>
class ResultLoopTemplate {
public:
/**
* @brief m_loopTemplate
*
* Excepted template fields
* - structname: The typename of the struct/class
* - queryliteral: The query
* - assignfields: Replaced with the field assignment
*/
QString m_loopTemplate;
/**
* @brief m_retrieveValueTemplate
*
* Excepted template fields
* - varname: the name of the field of the struct or normal variable
*/
QString m_retrieveValueTemplate;
};
#endif // RESULTLOOPTEMPLATE_H

View file

@ -6,8 +6,9 @@
class StructureTemplate { class StructureTemplate {
public: public:
QString m_startTemplate; // class /$structname/ {\npublic:\n // QString m_startTemplate; // class /$structname/ {\npublic:\n
QString m_endTemplate; // }; // QString m_endTemplate; // };
QString m_structTemplate;
QString m_fieldTemplate; // /$typename/ /$varname/; QString m_fieldTemplate; // /$typename/ /$varname/;
QString m_fieldSeparator; // use when you need something between fields but not after the last field QString m_fieldSeparator; // use when you need something between fields but not after the last field
int m_fieldIndentation = 1; int m_fieldIndentation = 1;

View file

@ -104,7 +104,8 @@ codebuilder/DefaultConfigs.h \
codebuilder/TypeMappings.h \ codebuilder/TypeMappings.h \
codebuilder/IndentationConfig.h \ codebuilder/IndentationConfig.h \
codebuilder/StructureTemplate.h \ codebuilder/StructureTemplate.h \
FormatToStream.h FormatToStream.h \
codebuilder/ResultLoopTemplate.h
unix { unix {
target.path = /usr/lib target.path = /usr/lib