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;
QTextStream stream(&buffer);
CodeBuilder builder;
builder.setLanguageConfig(getDefaultCppLanguageConfig());
builder.setLanguageConfig(getPglabCppLanguageConfig());
builder.GenCodeForExecutingQuery(stream, m_query, *m_dbres, struct_name);
stream.flush();
ui->generatedCodeEditor->setPlainText(buffer);

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()));

View file

@ -10,12 +10,22 @@ class QTextStream;
class CodeBuilder {
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){
m_configuration = config;
}
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
// - Code for executing the query
@ -25,21 +35,13 @@ public:
QString columnNameToVariableName(QString column_name) const;
QString getTypeName(Oid dbtype) const;
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;
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

View file

@ -2,13 +2,14 @@
#include "IndentationConfig.h"
#include "LanguageConfig.h"
#include "NameManglingRules.h"
#include "ResultLoopTemplate.h"
#include "StructureTemplate.h"
#include "TypeMappings.h"
#include "Pgsql_oids.h"
using namespace Pgsql;
std::shared_ptr<const TypeMappings> GetDefaultCppTypeMappings()
std::shared_ptr<const TypeMappings> GetPglabCppTypeMappings()
{
auto tm = std::make_shared<TypeMappings>();
*tm = {
@ -28,40 +29,57 @@ std::shared_ptr<const TypeMappings> GetDefaultCppTypeMappings()
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>();
config->setTypeMappings(GetDefaultCppTypeMappings());
config->setTypeMappings(GetPglabCppTypeMappings());
config->setNameManglingRules(std::make_shared<NameManglingRules>());
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->setStructureTemplate(buildPglabStructureTemplate());
config->setIndentationConfig(std::make_shared<IndentationConfig>());
return config;
}
std::shared_ptr<const LanguageConfig> getDefaultCppLanguageConfig()
{
static auto config = buildDefaultCppLanguageConfig();
return config;
}
std::shared_ptr<const LanguageConfig> buildPgLabCppLanguageConfig()
{
auto cfg = buildDefaultCppLanguageConfig();
return cfg;
}
std::shared_ptr<const LanguageConfig> getPgLabCppLanguageConfig()
{
static auto config = buildPgLabCppLanguageConfig();
config->setResultLoopTemplate(buildPglabResultLoopTemplate());
return config;
}
std::shared_ptr<const LanguageConfig> getPglabCppLanguageConfig()
{
static auto config = buildPglabCppLanguageConfig();
return config;
}

View file

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

View file

@ -48,3 +48,13 @@ void LanguageConfig::setIndentationConfig(std::shared_ptr<const IndentationConfi
{
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 StructureTemplate;
class IndentationConfig;
class ResultLoopTemplate;
/**
*
*/
@ -25,6 +26,8 @@ public:
void setStructureTemplate(std::shared_ptr<const StructureTemplate> structure_template);
std::shared_ptr<const IndentationConfig> indentationConfig() const;
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:
/** Default template for declaring a variable of the correct type.
* exmaple: "{$type} {$varname};"
@ -34,13 +37,12 @@ private:
std::shared_ptr<const TypeMappings> m_typeMappings;
std::shared_ptr<const StructureTemplate> m_structureTemplate;
std::shared_ptr<const IndentationConfig> m_indentationConfig;
std::shared_ptr<const ResultLoopTemplate> m_resultLoopTemplate;
enum class VariableStrategy {
UseLocalVariables,
DeclareClass
};
};
#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 {
public:
QString m_startTemplate; // class /$structname/ {\npublic:\n
QString m_endTemplate; // };
// QString m_startTemplate; // class /$structname/ {\npublic:\n
// QString m_endTemplate; // };
QString m_structTemplate;
QString m_fieldTemplate; // /$typename/ /$varname/;
QString m_fieldSeparator; // use when you need something between fields but not after the last field
int m_fieldIndentation = 1;

View file

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