diff --git a/pglab/CodeGenerator.cpp b/pglab/CodeGenerator.cpp index 92c4c2f..0cf97aa 100644 --- a/pglab/CodeGenerator.cpp +++ b/pglab/CodeGenerator.cpp @@ -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); diff --git a/pglablib/codebuilder/CodeBuilder.cpp b/pglablib/codebuilder/CodeBuilder.cpp index dd782c0..763c567 100644 --- a/pglablib/codebuilder/CodeBuilder.cpp +++ b/pglablib/codebuilder/CodeBuilder.cpp @@ -3,45 +3,30 @@ #include "Pgsql_Result.h" #include "IndentationConfig.h" #include "LanguageConfig.h" +#include "ResultLoopTemplate.h" #include "StructureTemplate.h" #include "util.h" #include 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 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 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(result.cols())); diff --git a/pglablib/codebuilder/CodeBuilder.h b/pglablib/codebuilder/CodeBuilder.h index aad070d..01694e7 100644 --- a/pglablib/codebuilder/CodeBuilder.h +++ b/pglablib/codebuilder/CodeBuilder.h @@ -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; + + ColumnDataList createColumnDataList(const Pgsql::Result &result) const; + void setLanguageConfig(std::shared_ptr 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; std::shared_ptr 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 diff --git a/pglablib/codebuilder/DefaultConfigs.cpp b/pglablib/codebuilder/DefaultConfigs.cpp index d9f31c3..da1eba2 100644 --- a/pglablib/codebuilder/DefaultConfigs.cpp +++ b/pglablib/codebuilder/DefaultConfigs.cpp @@ -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 GetDefaultCppTypeMappings() +std::shared_ptr GetPglabCppTypeMappings() { auto tm = std::make_shared(); *tm = { @@ -28,40 +29,57 @@ std::shared_ptr GetDefaultCppTypeMappings() return tm; } +std::shared_ptr buildPglabStructureTemplate() +{ + auto t = std::make_shared(); + t->m_structTemplate = +R"__(class /%structname%/ { +public: +/%structfields%/ +}; +using /%structname%/Lst = std::vector; +)__"; -std::shared_ptr buildDefaultCppLanguageConfig() + t->m_fieldTemplate = "/%typename%/ /%varname%/;"; + //st_templ->m_fieldSeparator; + + return t; +} + +std::shared_ptr buildPglabResultLoopTemplate() +{ + auto t = std::make_shared(); + 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 buildPglabCppLanguageConfig() { auto config = std::make_shared(); - config->setTypeMappings(GetDefaultCppTypeMappings()); + config->setTypeMappings(GetPglabCppTypeMappings()); config->setNameManglingRules(std::make_shared()); - - auto st_templ = std::make_shared(); - 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()); - - return config; -} - -std::shared_ptr getDefaultCppLanguageConfig() -{ - static auto config = buildDefaultCppLanguageConfig(); - return config; -} - -std::shared_ptr buildPgLabCppLanguageConfig() -{ - auto cfg = buildDefaultCppLanguageConfig(); - - return cfg; -} - -std::shared_ptr getPgLabCppLanguageConfig() -{ - static auto config = buildPgLabCppLanguageConfig(); + config->setResultLoopTemplate(buildPglabResultLoopTemplate()); + return config; +} + + +std::shared_ptr getPglabCppLanguageConfig() +{ + static auto config = buildPglabCppLanguageConfig(); return config; } diff --git a/pglablib/codebuilder/DefaultConfigs.h b/pglablib/codebuilder/DefaultConfigs.h index d446d22..bb04da9 100644 --- a/pglablib/codebuilder/DefaultConfigs.h +++ b/pglablib/codebuilder/DefaultConfigs.h @@ -5,7 +5,7 @@ class LanguageConfig; -std::shared_ptr getDefaultCppLanguageConfig(); -std::shared_ptr getPgLabCppLanguageConfig(); +//std::shared_ptr getDefaultCppLanguageConfig(); +std::shared_ptr getPglabCppLanguageConfig(); #endif // DEFAULTCONFIGS_H diff --git a/pglablib/codebuilder/LanguageConfig.cpp b/pglablib/codebuilder/LanguageConfig.cpp index 33100f8..2fa4b74 100644 --- a/pglablib/codebuilder/LanguageConfig.cpp +++ b/pglablib/codebuilder/LanguageConfig.cpp @@ -48,3 +48,13 @@ void LanguageConfig::setIndentationConfig(std::shared_ptr LanguageConfig::resultLoopTemplate() const +{ + return m_resultLoopTemplate; +} + +void LanguageConfig::setResultLoopTemplate(std::shared_ptr result_loop_template) +{ + m_resultLoopTemplate = result_loop_template; +} diff --git a/pglablib/codebuilder/LanguageConfig.h b/pglablib/codebuilder/LanguageConfig.h index 3f9ac46..8631a99 100644 --- a/pglablib/codebuilder/LanguageConfig.h +++ b/pglablib/codebuilder/LanguageConfig.h @@ -8,6 +8,7 @@ class NameManglingRules; class TypeMappings; class StructureTemplate; class IndentationConfig; +class ResultLoopTemplate; /** * */ @@ -25,6 +26,8 @@ public: void setStructureTemplate(std::shared_ptr structure_template); std::shared_ptr indentationConfig() const; void setIndentationConfig(std::shared_ptr indentation_config); + std::shared_ptr resultLoopTemplate() const; + void setResultLoopTemplate(std::shared_ptr 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 m_typeMappings; std::shared_ptr m_structureTemplate; std::shared_ptr m_indentationConfig; + std::shared_ptr m_resultLoopTemplate; enum class VariableStrategy { UseLocalVariables, DeclareClass }; - - }; #endif // LANGUAGECONFIG_H diff --git a/pglablib/codebuilder/ResultLoopTemplate.h b/pglablib/codebuilder/ResultLoopTemplate.h new file mode 100644 index 0000000..660d437 --- /dev/null +++ b/pglablib/codebuilder/ResultLoopTemplate.h @@ -0,0 +1,26 @@ +#ifndef RESULTLOOPTEMPLATE_H +#define RESULTLOOPTEMPLATE_H + +#include + +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 diff --git a/pglablib/codebuilder/StructureTemplate.h b/pglablib/codebuilder/StructureTemplate.h index 716031a..f93a1ef 100644 --- a/pglablib/codebuilder/StructureTemplate.h +++ b/pglablib/codebuilder/StructureTemplate.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; diff --git a/pglablib/pglablib.pro b/pglablib/pglablib.pro index 1d0acf9..b355769 100644 --- a/pglablib/pglablib.pro +++ b/pglablib/pglablib.pro @@ -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