Gen code for query #78
10 changed files with 143 additions and 91 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
26
pglablib/codebuilder/ResultLoopTemplate.h
Normal file
26
pglablib/codebuilder/ResultLoopTemplate.h
Normal 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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue