Lot of code for generating code. Working on unit tests.

This commit is contained in:
eelke 2018-09-09 18:52:32 +02:00
parent da45929b12
commit 8f4845d4d2
42 changed files with 1089 additions and 267 deletions

View file

@ -1,6 +1,7 @@
#include "BaseTableModel.h" #include "BaseTableModel.h"
#include "ResultTableModelUtil.h" #include "ResultTableModelUtil.h"
#include <QBrush> #include <QBrush>
#include "Pgsql_oids.h"
using namespace Pgsql; using namespace Pgsql;
@ -10,7 +11,7 @@ QVariant BaseTableModel::data(const QModelIndex &index, int role) const
Oid oid = getType(index.column()); Oid oid = getType(index.column());
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
v = getData(index); v = getData(index);
if (oid == BOOLOID) { if (oid == bool_oid) {
v = FormatBoolForDisplay(v.toBool()); v = FormatBoolForDisplay(v.toBool());
} }
} }
@ -18,7 +19,7 @@ QVariant BaseTableModel::data(const QModelIndex &index, int role) const
v = (int)GetDefaultAlignmentForType(oid); v = (int)GetDefaultAlignmentForType(oid);
} }
else if (role == Qt::ForegroundRole) { else if (role == Qt::ForegroundRole) {
if (oid == BOOLOID) { if (oid == bool_oid) {
QVariant d = getData(index); QVariant d = getData(index);
if (d.type() == QVariant::Bool) { if (d.type() == QVariant::Bool) {
v = QBrush(GetDefaultBoolColor(d.toBool())); v = QBrush(GetDefaultBoolColor(d.toBool()));

View file

@ -1,8 +0,0 @@
#include "CodeBuilderConfiguration.h"
#include "Pgsql_Result.h"
QString CodeBuilder::GenClassDefinition(const Pgsql::Result &/*result*/) const
{
return QString();
}

View file

@ -1,120 +0,0 @@
#pragma once
#include <QString>
#include <QStringBuilder>
#include <libpq-fe.h>
namespace Pgsql { class Result; }
/*
class PgAuthId {
public:
PgAuthId();
Oid oid = InvalidOid;
QString name;
bool super;
bool inherit;
bool createRole;
bool createDB;
bool canlogin;
bool replication;
bool bypassRls;
int connLimit;
QDateTime validUntil;*/
/** Defines how a database result fieldname should be converted into a variable
* name in the target language.
*
*/
class VarNameManglingRules {
public:
enum class CollisionHandling {
Restrict, ///< An error will be reported and no code generated
Fqn, ///< Turn into fully qualified name (table_column)
Number ///< A number will be appended to fields that have the same name
};
enum class CaseConversion {
AsIs,
Upper,
Lower
};
QString replaceSpaceWith; ///< default is empty string which means remove spaces
CollisionHandling CollisionHandling = CollisionHandling::Restrict;
CaseConversion caseConversion = CaseConversion::AsIs; ///< overall case conversion rule
CaseConversion caseFirstChar = CaseConversion::AsIs; ///< case of the first char
bool underscoreToCamel = false; ///< remove underscores and make first char after underscore uppercase
};
/**
*
*/
class LanguageConfig {
public:
/** Default template for declaring a variable of the correct type.
* exmaple: "{$type} {$varname};"
*/
QString varDeclTemplate;
VarNameManglingRules varNaming;
enum class VariableStrategy {
UseLocalVariables,
DeclareClass
};
QString classStartTemplate;
QString classEndTemplate;
QString classFieldTemplate;
};
/**
*
* There are some default fallbacks in place
* - smallint > integer
* - integer > bigint
* - int2 > smallint
* - int4 > integer
* - int8 > bigint
*
* - float > double
* - text > varchar
*/
class TypeConfig {
public:
/** The following template allows you to derive the variable name from the result fieldname.
*
* {$} in the suplied value will be replaced with the name of the result field.
*
* example: {$}
*/
QString varNameTemplate;
QString typeIdent;
QString varDeclTemplate; ///< Overrules the default template in the language config
// Mapping() = default;
// Mapping(Oid oid, QString lang_type_ident)
// : db_oid(oid), lang_type(lang_type_ident)
// {}
//
// bool operator < (const Mapping &rhs) const
// {
// return db_oid < rhs.db_oid;
// }
};
class TypeMappings {
public:
private:
};
class CodeBuilderConfiguration {
public:
};
class CodeBuilder {
public:
QString GenClassDefinition(const Pgsql::Result &result) const;
};

View file

@ -140,7 +140,7 @@ int ColumnTableModel::columnCount(const QModelIndex &/*parent*/) const
Oid ColumnTableModel::getType(int /*column*/) const Oid ColumnTableModel::getType(int /*column*/) const
{ {
Oid oid = Pgsql::VARCHAROID; Oid oid = Pgsql::varchar_oid;
// switch (column) { // switch (column) {
// case TypeCol: // case TypeCol:
// case NameCol: // case NameCol:

View file

@ -79,12 +79,12 @@ QVariant ConstraintModel::headerData(int section, Qt::Orientation orientation, i
return v; return v;
} }
int ConstraintModel::rowCount(const QModelIndex &parent) const int ConstraintModel::rowCount(const QModelIndex &) const
{ {
return m_constraints.size(); return m_constraints.size();
} }
int ConstraintModel::columnCount(const QModelIndex &parent) const int ConstraintModel::columnCount(const QModelIndex &) const
{ {
return colCount; return colCount;
} }
@ -99,7 +99,7 @@ int ConstraintModel::columnCount(const QModelIndex &parent) const
// return v; // return v;
//} //}
Oid ConstraintModel::getType(int column) const Oid ConstraintModel::getType(int ) const
{ {
Oid oid = Pgsql::varchar_oid; Oid oid = Pgsql::varchar_oid;

View file

@ -84,10 +84,10 @@ Oid DatabasesTableModel::getType(int column) const
switch (column) { switch (column) {
case AllowConnCol: case AllowConnCol:
case IsTemplateCol: case IsTemplateCol:
oid = BOOLOID; oid = bool_oid;
break; break;
case ConnLimitCol: case ConnLimitCol:
oid = INT4OID; oid = int4_oid;
break; break;
case AclCol: case AclCol:
case CollateCol: case CollateCol:
@ -96,7 +96,7 @@ Oid DatabasesTableModel::getType(int column) const
case DbaCol: case DbaCol:
case NameCol: case NameCol:
case TablespaceCol: case TablespaceCol:
oid = VARCHAROID; oid = varchar_oid;
break; break;
default: default:
oid = InvalidOid; oid = InvalidOid;

View file

@ -32,8 +32,8 @@ void IconColumnDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
} }
} }
QSize IconColumnDelegate::sizeHint(const QStyleOptionViewItem &option, QSize IconColumnDelegate::sizeHint(const QStyleOptionViewItem &,
const QModelIndex &index) const const QModelIndex &) const
{ {
return QSize(16, 16); return QSize(16, 16);
} }

View file

@ -81,7 +81,7 @@ Oid RolesTableModel::getType(int column) const
Oid oid; Oid oid;
switch (column) { switch (column) {
case NameCol: case NameCol:
oid = VARCHAROID; oid = varchar_oid;
break; break;
case ReplicationCol: case ReplicationCol:
@ -91,15 +91,15 @@ Oid RolesTableModel::getType(int column) const
case CreateRoleCol: case CreateRoleCol:
case InheritCol: case InheritCol:
case SuperCol: case SuperCol:
oid = BOOLOID; oid = bool_oid;
break; break;
case ConnlimitCol: case ConnlimitCol:
oid = INT4OID; oid = int4_oid;
break; break;
case ValidUntilCol: case ValidUntilCol:
oid = TIMESTAMPOID; oid = timestamp_oid;
break; break;
default: default:
oid = InvalidOid; oid = InvalidOid;

View file

@ -142,7 +142,7 @@ Oid TablesTableModel::getType(int column) const
case OptionsCol: case OptionsCol:
// case AclCol: // case AclCol:
default: default:
oid = Pgsql::VARCHAROID; oid = Pgsql::varchar_oid;
} }
return oid; return oid;
} }

View file

@ -54,7 +54,6 @@ SOURCES += main.cpp\
ConnectionList.cpp \ ConnectionList.cpp \
ProcessStdioWidget.cpp \ ProcessStdioWidget.cpp \
GlobalIoService.cpp \ GlobalIoService.cpp \
CodeBuilderConfiguration.cpp \
ResultTableModelUtil.cpp \ ResultTableModelUtil.cpp \
BaseTableModel.cpp \ BaseTableModel.cpp \
QueryParamListController.cpp \ QueryParamListController.cpp \

View file

@ -24,6 +24,8 @@ class PgContainer: public IPgContainter {
public: public:
using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access using t_Container = std::vector<T>; ///< Do not assume it will stay a vector only expect bidirectional access
PgContainer() = default;
explicit PgContainer(std::weak_ptr<PgDatabaseCatalog> cat) explicit PgContainer(std::weak_ptr<PgDatabaseCatalog> cat)
: m_catalogue(cat) : m_catalogue(cat)
{} {}
@ -87,6 +89,13 @@ public:
std::sort(m_container.begin(), m_container.end()); std::sort(m_container.begin(), m_container.end());
} }
// Meant for mocking during testing
void add(const T &elem)
{
m_container.push_back(elem);
std::sort(m_container.begin(), m_container.end());
}
protected: protected:
std::weak_ptr<PgDatabaseCatalog> m_catalogue; std::weak_ptr<PgDatabaseCatalog> m_catalogue;
t_Container m_container; t_Container m_container;

View file

@ -0,0 +1,119 @@
#include "CodeBuilder.h"
#include "Pgsql_Result.h"
#include "IndentationConfig.h"
#include "LanguageConfig.h"
#include "StructureTemplate.h"
#include "util.h"
#include <QTextStream>
void FormatToStream(QTextStream &stream, QString format, std::function<void(QTextStream &, QString)> field_callback)
{
// Use static to optimize only once
static QRegularExpression cached_find_var_re("(?:[^\\\\]|^)(\\/%([a-zA-Z0-9_-]+)%\\/)", QRegularExpression::OptimizeOnFirstUsageOption);
int from = 0;
QRegularExpressionMatch match;
while (format.indexOf(cached_find_var_re, from, &match) >= 0) {
if (from > 0) {
// Because the regex has to check for backslash in front we have the from position
// one position before where we actually should continue for the second match and later ie when from > 0
// Therefor increase from by 1 to make the substring (midRef) calculation work
++from;
}
// copy code before the var to the stream
stream << format.midRef(from, match.capturedStart(1) - from);
field_callback(stream, match.captured(2));
from = match.capturedEnd()-1; // -1 because it wants to match one character before or start of line to make sure there is no backslash
}
if (from > 0) {
// same reason as at the start of the loop
++from;
}
stream << format.midRef(from);
}
void CodeBuilder::GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result)
{
// %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 =
"Pgsql::Result result = conn.query(/%query_literal%/);"
"for (auto row: result) {\n"
" Pgsql::Col col(row);\n"
" /%struct_type%/ v;\n"
"/%assign_fields%/"
"}";
// %field_name%
// %column_name%
// %column_index%
QString assign_result_field_template = "col >> v./%field_name%/";
QString query_string_literal = ConvertToMultiLineCString(query);
// [optional] Gen declaration of result structure
GenReturnStructDefinition(q, result);
// assume we have connection? What name???
// gen code for creating and executing statement
// - bind parameters
// Gen code for iterating through result and filling the result struct/or local variables
}
void CodeBuilder::GenReturnStructDefinition(QTextStream &q, const Pgsql::Result &result) const
{
std::shared_ptr<const StructureTemplate> templ = m_configuration->structureTemplate();
QString struct_name = "TODO";
QString field_format = templ->m_fieldTemplate;
int field_indent_levels = templ->m_fieldIndentation;
QString field_indent_string = m_configuration->indentationConfig()->getIndentString(field_indent_levels);
// Make struct start
q << QString(templ->m_startTemplate).arg(struct_name);
// 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
q << QString(templ->m_endTemplate).arg(struct_name);
}
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);
q << QString(format).arg(field_name).arg(type_name);
}

View file

@ -0,0 +1,28 @@
#ifndef CODEBUILDER_H
#define CODEBUILDER_H
#include "Pgsql_declare.h"
#include <QString>
class LanguageConfig;
class QTextStream;
class CodeBuilder {
public:
void GenCodeForExecutingQuery(QTextStream &q, const QString &query, const Pgsql::Result &result);
void GenReturnStructDefinition(QTextStream &q, const Pgsql::Result &result) const;
// Generating code for performing query and going through the result
// - Code for executing the query
// - Code for looping the result
// - Code for processing a single row
// - Declaration of struct for holding single row result
QString columnNameToVariableName(QString column_name) const;
QString getTypeName(Oid dbtype) const;
private:
std::shared_ptr<const LanguageConfig> m_configuration;
void genFieldDeclaration(QTextStream &q, const QString &format, const QString &column_name, Oid column_type) const;
};
#endif // CODEBUILDER_H

View file

@ -0,0 +1,50 @@
#include "DefaultConfigs.h"
#include "LanguageConfig.h"
#include "TypeMappings.h"
#include "Pgsql_oids.h"
using namespace Pgsql;
TypeMappings GetDefaultCppTypeMappings()
{
TypeMappings result = {
{ bool_oid, "bool" },
{ char_oid, "char" },
{ name_oid, "std::string" },
{ int8_oid, "int64_t" },
{ int2_oid, "int16_t" },
{ int4_oid, "int32_t" },
{ text_oid, "std::string" },
{ oid_oid, "Oid" },
{ float4_oid, "float" },
{ float8_oid, "double" }
};
return result;
}
std::shared_ptr<LanguageConfig> buildDefaultCppLanguageConfig()
{
return std::make_shared<LanguageConfig>();
}
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();
return config;
}

View file

@ -0,0 +1,11 @@
#ifndef DEFAULTCONFIGS_H
#define DEFAULTCONFIGS_H
#include <memory>
class LanguageConfig;
std::shared_ptr<const LanguageConfig> getDefaultCppLanguageConfig();
std::shared_ptr<const LanguageConfig> getPgLabCppLanguageConfig();
#endif // DEFAULTCONFIGS_H

View file

@ -0,0 +1,27 @@
#include "IndentationConfig.h"
IndentationConfig::IndentationConfig() = default;
IndentationConfig::IndentationConfig(int tab_size, int indentation_size, bool use_tabs)
: m_tabSize(tab_size)
, m_indentationSize(indentation_size)
, m_useTabs(use_tabs)
{}
/** Returns a string with the right amount of tabs and spaces for the
* requested indentation level.
*/
QString IndentationConfig::getIndentString(int level) const
{
int spaces = level * m_indentationSize;
int tabs = 0;
if (m_useTabs) {
tabs = spaces / m_tabSize;
spaces -= tabs * m_tabSize;
}
if (tabs > 0)
return QString(tabs, '\t') + QString(spaces, ' ');
else
return QString(spaces, ' ');
}

View file

@ -0,0 +1,23 @@
#ifndef INDENTATIONCONFIG_H
#define INDENTATIONCONFIG_H
#include <QString>
class IndentationConfig {
public:
IndentationConfig();
IndentationConfig(int tab_size, int indentation_size, bool use_tabs);
/** Returns a string with the right amount of tabs and spaces for the
* requested indentation level.
*/
QString getIndentString(int level) const;
private:
int m_tabSize = 8; ///< the size of a tab
int m_indentationSize = 4; ///< Number of positions per level to indent
bool m_useTabs = true; ///< Use tabs as much as possible instead of spaces when indenting
};
#endif // INDENTATIONCONFIG_H

View file

@ -0,0 +1,15 @@
#include "LanguageConfig.h"
#include "NameManglingRules.h"
#include "TypeMappings.h"
LanguageConfig::LanguageConfig() = default;
QString LanguageConfig::columnNameToFieldName(const QString& column_name) const
{
return m_varNaming->transform(column_name);
}
QString LanguageConfig::getTypeName(Oid dbtype) const
{
return m_typeMappings->getTypeForOid(dbtype);
}

View file

@ -0,0 +1,54 @@
#ifndef LANGUAGECONFIG_H
#define LANGUAGECONFIG_H
#include <QString>
#include "Pgsql_oids.h"
class NameManglingRules;
class TypeMappings;
class StructureTemplate;
class IndentationConfig;
/**
*
*/
class LanguageConfig {
public:
LanguageConfig();
QString columnNameToFieldName(const QString& column_name) const;
QString getTypeName(Oid dbtype) const;
std::shared_ptr<const TypeMappings> typeMappings() const { return m_typeMappings; }
void setTypeMappings(std::shared_ptr<const TypeMappings> type_mappings)
{
m_typeMappings = type_mappings;
}
std::shared_ptr<const StructureTemplate> structureTemplate() const
{
return m_structureTemplate;
}
std::shared_ptr<const IndentationConfig> indentationConfig() const
{
return m_indentationConfig;
}
private:
/** Default template for declaring a variable of the correct type.
* exmaple: "{$type} {$varname};"
*/
//QString varDeclTemplate;
std::shared_ptr<const NameManglingRules> m_varNaming;
std::shared_ptr<const TypeMappings> m_typeMappings;
std::shared_ptr<const StructureTemplate> m_structureTemplate;
std::shared_ptr<const IndentationConfig> m_indentationConfig;
enum class VariableStrategy {
UseLocalVariables,
DeclareClass
};
};
#endif // LANGUAGECONFIG_H

View file

@ -0,0 +1,32 @@
#include "NameManglingRules.h"
void NameManglingRules::apply(const ReplaceRule &rule, QString &in) const
{
int from = 0;
int pos;
QRegularExpressionMatch match;
while ((pos = in.indexOf(rule.pattern, from, &match)) >= 0) {
int len = match.capturedLength();
in.replace(pos, len, rule.replace);
from = pos + rule.replace.size();
if (rule.nextToUpper)
in[from] = in[from].toUpper();
}
}
QString NameManglingRules::transform(const QString &input) const
{
QString result;
if (caseConversion == CaseConversion::Lower)
result = input.toLower();
else if (caseConversion == CaseConversion::Upper)
result = input.toUpper();
else
result = input;
for (auto rule : replaceRules) {
apply(rule, result);
}
return result;
}

View file

@ -0,0 +1,50 @@
#ifndef NAMEMANGLINGRULES_H
#define NAMEMANGLINGRULES_H
#include <QString>
#include <QRegularExpression>
#include <vector>
/** Defines how a database result fieldname should be converted into a variable
* name in the target language.
*
*/
class NameManglingRules {
public:
enum class CollisionHandling {
Restrict, ///< An error will be reported and no code generated
Fqn, ///< Turn into fully qualified name (table_column)
Number ///< A number will be appended to fields that have the same name
};
enum class CaseConversion {
AsIs,
Upper,
Lower
};
class ReplaceRule {
public:
QRegularExpression pattern;
QString replace;
bool nextToUpper = false;
};
using ReplaceRules = std::vector<ReplaceRule>;
ReplaceRules replaceRules;
// { {"[ -_]", QRegularExpression::OptimizeOnFirstUsageOption }, "", true }
QString replaceSpaceWith; ///< default is empty string which means remove spaces
//CollisionHandling CollisionHandling = CollisionHandling::Restrict;
CaseConversion caseConversion = CaseConversion::AsIs; ///< overall case conversion rule
//CaseConversion caseFirstChar = CaseConversion::AsIs; ///< case of the first char
bool camelCase = false; ///< removes underscores and make first char after underscore uppercase
void apply(const ReplaceRule &rule, QString &in) const;
QString transform(const QString &input) const;
};
#endif // NAMEMANGLINGRULES_H

View file

@ -0,0 +1,2 @@
#include "StructureTemplate.h"

View file

@ -0,0 +1,16 @@
#ifndef STRUCTURETEMPLATE_H
#define STRUCTURETEMPLATE_H
#include <QString>
class StructureTemplate {
public:
QString m_startTemplate; // class /$structname/ {\npublic:\n
QString m_endTemplate; // };
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;
};
#endif // STRUCTURETEMPLATE_H

View file

@ -0,0 +1,133 @@
#include "TypeMappings.h"
#include "PgTypeContainer.h"
//namespace {
// using Fallbacks = std::unordered_map<Oid, Oid>;
// Fallbacks fallbacks = {
// { oid_text, oid_varchar },
// { }
// };
//}
TypeMappings::TypeMappings() = default;
TypeMappings::TypeMappings(std::initializer_list<Mapping> mappings)
{
m_typeMap.insert(mappings.begin(), mappings.end());
}
QString TypeMappings::getTypeForOid(Oid oid) const
{
// TODO use the catalog to determine if someting is an array or vector type.
// If it is lookup its element type and use the std container
auto res = m_typeMap.find(oid);
if (res != m_typeMap.end()) {
return res->second;
}
if (m_types) {
PgType type = m_types->getByKey(oid);
if (type.oid != InvalidOid && type.elem != InvalidOid) {
res = m_typeMap.find(type.elem);
QString type_string;
if (res == m_typeMap.end()) {
type_string = m_defaultStringType;
}
else {
type_string = res->second;
}
return QString(m_defaultContainerType).arg(type_string);
}
}
return m_defaultStringType;
}
void TypeMappings::setTypes(std::shared_ptr<const PgTypeContainer> types)
{
m_types = types;
}
void TypeMappings::setDefaultStringType(QString str)
{
m_defaultStringType = str;
}
void TypeMappings::setDefaultContainerType(QString str)
{
m_defaultContainerType = str;
}
void TypeMappings::set(Oid oid, QString type)
{
m_typeMap.insert_or_assign(oid, type);
}
//constexpr Oid bool_oid = 16;
//constexpr Oid bytea_oid = 17;
//constexpr Oid char_oid = 18;
//constexpr Oid name_oid = 19;
//constexpr Oid int8_oid = 20;
//constexpr Oid int2_oid = 21;
//constexpr Oid int4_oid = 23;
//constexpr Oid regproc_oid = 24;
//constexpr Oid text_oid = 25;
//constexpr Oid oid_oid = 26;
//constexpr Oid tid_oid = 27;
//constexpr Oid xid_oid = 28;
//constexpr Oid cid_oid = 29;
//constexpr Oid json_oid = 114;
//constexpr Oid xml_oid = 142;
//constexpr Oid point_oid = 600;
//constexpr Oid lseg_oid = 601;
//constexpr Oid path_oid = 602;
//constexpr Oid box_oid = 603;
//constexpr Oid polygon_oid = 604;
//constexpr Oid line_oid = 628;
//constexpr Oid cidr_oid = 650;
//constexpr Oid float4_oid = 700;
//constexpr Oid float8_oid = 701;
//constexpr Oid abstime_oid = 702;
//constexpr Oid reltime_oid = 703;
//constexpr Oid tinterval_oid = 704;
//constexpr Oid circle_oid = 718;
//constexpr Oid money_oid = 790;
//constexpr Oid macaddr_oid = 829;
//constexpr Oid inet_oid = 869;
//constexpr Oid aclitem_oid = 1033;
//constexpr Oid bpchar_oid = 1042;
//constexpr Oid varchar_oid = 1043;
//constexpr Oid date_oid = 1082;
//constexpr Oid time_oid = 1083;
//constexpr Oid timestamp_oid = 1114;
//constexpr Oid timestamptz_oid = 1184;
//constexpr Oid interval_oid = 1186;
//constexpr Oid timetz_oid = 1266;
//constexpr Oid bit_oid = 1560;
//constexpr Oid varbit_oid = 1562;
//constexpr Oid numeric_oid = 1700;
//constexpr Oid refcursor_oid = 1790;
//constexpr Oid regprocedure_oid = 2202;
//constexpr Oid regoper_oid = 2203;
//constexpr Oid regoperator_oid = 2204;
//constexpr Oid regclass_oid = 2205;
//constexpr Oid regtype_oid = 2206;
//constexpr Oid uuid_oid = 2950;
//constexpr Oid txid_snapshot_oid = 2970;
//constexpr Oid pg_lsn_oid = 3220;
//constexpr Oid tsvector_oid = 3614;
//constexpr Oid tsquery_oid = 3615;
//constexpr Oid gtsvector_oid = 3642;
//constexpr Oid regconfig_oid = 3734;
//constexpr Oid regdictionary_oid = 3769;
//constexpr Oid jsonb_oid = 3802;
//constexpr Oid int4range_oid = 3904;
//constexpr Oid numrange_oid = 3906;
//constexpr Oid tsrange_oid = 3908;
//constexpr Oid tstzrange_oid = 3910;
//constexpr Oid daterange_oid = 3912;
//constexpr Oid int8range_oid = 3926;
//constexpr Oid regnamespace_oid = 4089;
//constexpr Oid regrole_oid = 4096;

View file

@ -0,0 +1,46 @@
#ifndef TYPEMAPPINGS_H
#define TYPEMAPPINGS_H
#include <Pgsql_declare.h>
#include <QString>
#include <initializer_list>
#include <unordered_map>
class PgTypeContainer;
class TypeMappings {
public:
using TypeMap = std::unordered_map<Oid, QString>;
using Mapping = std::pair<Oid, QString>;
TypeMappings();
TypeMappings(std::initializer_list<Mapping> mappings);
QString getTypeForOid(Oid oid) const;
const TypeMap& typeMap() const { return m_typeMap; }
QString defaultStringType() const { return m_defaultStringType; }
void setTypes(std::shared_ptr<const PgTypeContainer> types);
void setDefaultStringType(QString str);
void setDefaultContainerType(QString str);
void set(Oid oid, QString type);
/** Removing a type from the mapping will reeastablish its default mapping
* which in most cases is the default string type for the language.
*/
void remove(Oid oid);
private:
TypeMap m_typeMap;
QString m_defaultStringType;
QString m_defaultContainerType; ///< This string should contain a format variable where the element type should go
std::shared_ptr<const PgTypeContainer> m_types;
};
#endif // TYPEMAPPINGS_H

View file

@ -57,7 +57,14 @@ SOURCES += \
PgAmContainer.cpp \ PgAmContainer.cpp \
PgObject.cpp \ PgObject.cpp \
PgTablespace.cpp \ PgTablespace.cpp \
PgTablespaceContainer.cpp PgTablespaceContainer.cpp \
codebuilder/LanguageConfig.cpp \
codebuilder/CodeBuilder.cpp \
codebuilder/NameManglingRules.cpp \
codebuilder/DefaultConfigs.cpp \
codebuilder/TypeMappings.cpp \
codebuilder/IndentationConfig.cpp \
codebuilder/StructureTemplate.cpp
HEADERS += \ HEADERS += \
Pglablib.h \ Pglablib.h \
@ -92,7 +99,14 @@ HEADERS += \
PgAmContainer.h \ PgAmContainer.h \
PgObject.h \ PgObject.h \
PgTablespace.h \ PgTablespace.h \
PgTablespaceContainer.h PgTablespaceContainer.h \
codebuilder/LanguageConfig.h \
codebuilder/CodeBuilder.h \
codebuilder/NameManglingRules.h \
codebuilder/DefaultConfigs.h \
codebuilder/TypeMappings.h \
codebuilder/IndentationConfig.h \
codebuilder/StructureTemplate.h
unix { unix {
target.path = /usr/lib target.path = /usr/lib

View file

@ -73,7 +73,7 @@ namespace Pgsql {
* *
* The class takes ownership of data and will try to delete[] it. * The class takes ownership of data and will try to delete[] it.
*/ */
Param addText(const char *data, Oid oid=VARCHAROID); Param addText(const char *data, Oid oid=varchar_oid);
}; };
} // end namespace Pgsql } // end namespace Pgsql

View file

@ -103,9 +103,9 @@ Value::operator double() const
bool Value::isString() const bool Value::isString() const
{ {
return m_typ == CHAROID return m_typ == char_oid
|| m_typ == VARCHAROID || m_typ == varchar_oid
|| m_typ == TEXTOID || m_typ == text_oid
; ;
} }

View file

@ -5,95 +5,95 @@
namespace Pgsql { namespace Pgsql {
const Oid BOOLOID = 16; // const Oid BOOLOID = 16;
const Oid BYTEAOID = 17; // const Oid BYTEAOID = 17;
const Oid CHAROID = 18; // const Oid CHAROID = 18;
const Oid NAMEOID = 19; // const Oid NAMEOID = 19;
const Oid INT8OID = 20; // const Oid INT8OID = 20;
const Oid INT2OID = 21; // const Oid INT2OID = 21;
const Oid INT2VECTOROID = 22; // const Oid INT2VECTOROID = 22;
const Oid INT4OID = 23; // const Oid INT4OID = 23;
const Oid REGPROCOID = 24; // const Oid REGPROCOID = 24;
const Oid TEXTOID = 25; // const Oid TEXTOID = 25;
const Oid OIDOID = 26; // const Oid OIDOID = 26;
const Oid TIDOID = 27; // const Oid TIDOID = 27;
const Oid XIDOID = 28; // const Oid XIDOID = 28;
const Oid CIDOID = 29; // const Oid CIDOID = 29;
const Oid OIDVECTOROID = 30; // const Oid OIDVECTOROID = 30;
const Oid JSONOID = 114; // const Oid JSONOID = 114;
const Oid XMLOID = 142; // const Oid XMLOID = 142;
const Oid PGNODETREEOID = 194; // const Oid PGNODETREEOID = 194;
const Oid PGDDLCOMMANDOID = 32; // const Oid PGDDLCOMMANDOID = 32;
const Oid POINTOID = 600; // const Oid POINTOID = 600;
const Oid LSEGOID = 601; // const Oid LSEGOID = 601;
const Oid PATHOID = 602; // const Oid PATHOID = 602;
const Oid BOXOID = 603; // const Oid BOXOID = 603;
const Oid POLYGONOID = 604; // const Oid POLYGONOID = 604;
const Oid LINEOID = 628; // const Oid LINEOID = 628;
const Oid FLOAT4OID = 700; // const Oid FLOAT4OID = 700;
const Oid FLOAT8OID = 701; // const Oid FLOAT8OID = 701;
const Oid ABSTIMEOID = 702; // const Oid ABSTIMEOID = 702;
const Oid RELTIMEOID = 703; // const Oid RELTIMEOID = 703;
const Oid TINTERVALOID = 704; // const Oid TINTERVALOID = 704;
const Oid UNKNOWNOID = 705; // const Oid UNKNOWNOID = 705;
const Oid CIRCLEOID = 718; // const Oid CIRCLEOID = 718;
const Oid CASHOID = 790; // const Oid CASHOID = 790;
const Oid MACADDROID = 829; // const Oid MACADDROID = 829;
const Oid INETOID = 869; // const Oid INETOID = 869;
const Oid CIDROID = 650; // const Oid CIDROID = 650;
const Oid INT2ARRAYOID = 1005; // const Oid INT2ARRAYOID = 1005;
const Oid INT4ARRAYOID = 1007; // const Oid INT4ARRAYOID = 1007;
const Oid TEXTARRAYOID = 1009; // const Oid TEXTARRAYOID = 1009;
const Oid OIDARRAYOID = 1028; // const Oid OIDARRAYOID = 1028;
const Oid FLOAT4ARRAYOID = 1021; // const Oid FLOAT4ARRAYOID = 1021;
const Oid ACLITEMOID = 1033; // const Oid ACLITEMOID = 1033;
const Oid CSTRINGARRAYOID = 1263; // const Oid CSTRINGARRAYOID = 1263;
const Oid BPCHAROID = 1042; // const Oid BPCHAROID = 1042;
const Oid VARCHAROID = 1043; // const Oid VARCHAROID = 1043;
const Oid DATEOID = 1082; // const Oid DATEOID = 1082;
const Oid TIMEOID = 1083; // const Oid TIMEOID = 1083;
const Oid TIMESTAMPOID = 1114; // const Oid TIMESTAMPOID = 1114;
const Oid TIMESTAMPTZOID = 1184; // const Oid TIMESTAMPTZOID = 1184;
const Oid INTERVALOID = 1186; // const Oid INTERVALOID = 1186;
const Oid TIMETZOID = 1266; // const Oid TIMETZOID = 1266;
const Oid BITOID = 1560; // const Oid BITOID = 1560;
const Oid VARBITOID = 1562; // const Oid VARBITOID = 1562;
const Oid NUMERICOID = 1700; // const Oid NUMERICOID = 1700;
const Oid REFCURSOROID = 1790; // const Oid REFCURSOROID = 1790;
const Oid REGPROCEDUREOID = 2202; // const Oid REGPROCEDUREOID = 2202;
const Oid REGOPEROID = 2203; // const Oid REGOPEROID = 2203;
const Oid REGOPERATOROID = 2204; // const Oid REGOPERATOROID = 2204;
const Oid REGCLASSOID = 2205; // const Oid REGCLASSOID = 2205;
const Oid REGTYPEOID = 2206; // const Oid REGTYPEOID = 2206;
const Oid REGROLEOID = 4096; // const Oid REGROLEOID = 4096;
const Oid REGNAMESPACEOID = 4089; // const Oid REGNAMESPACEOID = 4089;
const Oid REGTYPEARRAYOID = 2211; // const Oid REGTYPEARRAYOID = 2211;
const Oid UUIDOID = 2950; // const Oid UUIDOID = 2950;
const Oid LSNOID = 3220; // const Oid LSNOID = 3220;
const Oid TSVECTOROID = 3614; // const Oid TSVECTOROID = 3614;
const Oid GTSVECTOROID = 3642; // const Oid GTSVECTOROID = 3642;
const Oid TSQUERYOID = 3615; // const Oid TSQUERYOID = 3615;
const Oid REGCONFIGOID = 3734; // const Oid REGCONFIGOID = 3734;
const Oid REGDICTIONARYOID = 3769; // const Oid REGDICTIONARYOID = 3769;
const Oid JSONBOID = 3802; // const Oid JSONBOID = 3802;
const Oid INT4RANGEOID = 3904; // const Oid INT4RANGEOID = 3904;
const Oid RECORDOID = 2249; // const Oid RECORDOID = 2249;
const Oid RECORDARRAYOID = 2287; // const Oid RECORDARRAYOID = 2287;
const Oid CSTRINGOID = 2275; // const Oid CSTRINGOID = 2275;
const Oid ANYOID = 2276; // const Oid ANYOID = 2276;
const Oid ANYARRAYOID = 2277; // const Oid ANYARRAYOID = 2277;
const Oid VOIDOID = 2278; // const Oid VOIDOID = 2278;
const Oid TRIGGEROID = 2279; // const Oid TRIGGEROID = 2279;
const Oid EVTTRIGGEROID = 3838; // const Oid EVTTRIGGEROID = 3838;
const Oid LANGUAGE_HANDLEROID = 2280; // const Oid LANGUAGE_HANDLEROID = 2280;
const Oid INTERNALOID = 2281; // const Oid INTERNALOID = 2281;
const Oid OPAQUEOID = 2282; // const Oid OPAQUEOID = 2282;
const Oid ANYELEMENTOID = 2283; // const Oid ANYELEMENTOID = 2283;
const Oid ANYNONARRAYOID = 2776; // const Oid ANYNONARRAYOID = 2776;
const Oid ANYENUMOID = 3500; // const Oid ANYENUMOID = 3500;
const Oid FDW_HANDLEROID = 3115; // const Oid FDW_HANDLEROID = 3115;
const Oid TSM_HANDLEROID = 3310; // const Oid TSM_HANDLEROID = 3310;
const Oid ANYRANGEOID = 3831; // const Oid ANYRANGEOID = 3831;
class Params; class Params;

View file

@ -163,7 +163,7 @@ namespace {
} }
Oid Pgsql::ElemOidFromArrayOid(Oid oid) Oid Pgsql::ElemOidFromArrayOid(Oid oid) noexcept
{ {
auto iter = std::lower_bound(g_ArrayToElem.begin(), g_ArrayToElem.end(), auto iter = std::lower_bound(g_ArrayToElem.begin(), g_ArrayToElem.end(),
@ -173,11 +173,11 @@ Oid Pgsql::ElemOidFromArrayOid(Oid oid)
return l.array < r.array; return l.array < r.array;
}); });
if (iter == g_ArrayToElem.end()) if (iter == g_ArrayToElem.end())
throw std::runtime_error("ElemOidFromArrayOid Oid not found"); return InvalidOid;
return iter->elem; return iter->elem;
} }
Oid Pgsql::ArrayOidFromElemOid(Oid oid) Oid Pgsql::ArrayOidFromElemOid(Oid oid) noexcept
{ {
auto iter = std::lower_bound(g_ElemToArray.begin(), g_ElemToArray.end(), auto iter = std::lower_bound(g_ElemToArray.begin(), g_ElemToArray.end(),
ElemArray{oid, oid}, ElemArray{oid, oid},
@ -186,7 +186,6 @@ Oid Pgsql::ArrayOidFromElemOid(Oid oid)
return l.elem < r.elem; return l.elem < r.elem;
}); });
if (iter == g_ElemToArray.end()) if (iter == g_ElemToArray.end())
throw std::runtime_error("ElemOidFromArrayOid Oid not found"); return InvalidOid;
return iter->array; return iter->array;
} }

View file

@ -55,6 +55,7 @@ namespace Pgsql {
constexpr Oid regoperator_oid = 2204; constexpr Oid regoperator_oid = 2204;
constexpr Oid regclass_oid = 2205; constexpr Oid regclass_oid = 2205;
constexpr Oid regtype_oid = 2206; constexpr Oid regtype_oid = 2206;
constexpr Oid any_oid = 2276;
constexpr Oid uuid_oid = 2950; constexpr Oid uuid_oid = 2950;
constexpr Oid txid_snapshot_oid = 2970; constexpr Oid txid_snapshot_oid = 2970;
constexpr Oid pg_lsn_oid = 3220; constexpr Oid pg_lsn_oid = 3220;
@ -140,8 +141,19 @@ namespace Pgsql {
constexpr Oid regnamespace_array_oid = 4090; constexpr Oid regnamespace_array_oid = 4090;
constexpr Oid regrole_array_oid = 4097; constexpr Oid regrole_array_oid = 4097;
Oid ElemOidFromArrayOid(Oid oid); /** If oid is an array oid then it returns the corresponding element oid.
Oid ArrayOidFromElemOid(Oid oid); * It oid is not an array the functions returns InvalidOid.
* This function only works for the predefined postgresql types.
* If you need it to work for user defined types then use the system catalogue.
*/
Oid ElemOidFromArrayOid(Oid oid) noexcept;
/** If oid is a non array oid then it returns the corresponding array oid.
* It oid is a array oid or oid is unknown it returns InvalidOid.
* This function only works for the predefined postgresql types.
* If you need it to work for user defined types then use the system catalogue.
*
*/
Oid ArrayOidFromElemOid(Oid oid) noexcept;
template <typename T> template <typename T>
class OidFor { class OidFor {

View file

@ -11,14 +11,14 @@ using namespace Pgsql;
TEST(Pgsql_Value, test_int4) TEST(Pgsql_Value, test_int4)
{ {
Pgsql::Value v("1", INT4OID); Pgsql::Value v("1", int4_oid);
int i = (int)v; int i = (int)v;
ASSERT_EQ(i, 1); ASSERT_EQ(i, 1);
} }
TEST(Pgsql_Value, test_QDateTime) TEST(Pgsql_Value, test_QDateTime)
{ {
Pgsql::Value v("2017-10-22 12:34:56", TIMESTAMPTZOID); Pgsql::Value v("2017-10-22 12:34:56", timestamptz_oid);
QDateTime dt = (QDateTime)v; QDateTime dt = (QDateTime)v;
ASSERT_EQ(dt, QDateTime(QDate(2017, 10, 22), QTime(12, 34, 56))); ASSERT_EQ(dt, QDateTime(QDate(2017, 10, 22), QTime(12, 34, 56)));
} }
@ -26,7 +26,7 @@ TEST(Pgsql_Value, test_QDateTime)
TEST(Pgsql_Value, test_QDateTime_2) TEST(Pgsql_Value, test_QDateTime_2)
{ {
Pgsql::Value v("2017-12-01 09:38:17.339817+02", TIMESTAMPTZOID); Pgsql::Value v("2017-12-01 09:38:17.339817+02", timestamptz_oid);
QDateTime dt = (QDateTime)v; QDateTime dt = (QDateTime)v;
QDateTime exp(QDate(2017, 12, 1), QTime(9, 38, 17, 340), QDateTime exp(QDate(2017, 12, 1), QTime(9, 38, 17, 340),
Qt::OffsetFromUTC, 2*3600); Qt::OffsetFromUTC, 2*3600);
@ -35,21 +35,21 @@ TEST(Pgsql_Value, test_QDateTime_2)
TEST(Pgsql_Value, test_QDate) TEST(Pgsql_Value, test_QDate)
{ {
Pgsql::Value v("2017-10-22", DATEOID); Pgsql::Value v("2017-10-22", date_oid);
QDate d = v; QDate d = v;
ASSERT_EQ(d, QDate(2017, 10, 22)); ASSERT_EQ(d, QDate(2017, 10, 22));
} }
TEST(Pgsql_Value, test_QTime) TEST(Pgsql_Value, test_QTime)
{ {
Pgsql::Value v("12:34:56", TIMEOID); Pgsql::Value v("12:34:56", time_oid);
QTime t = v; QTime t = v;
ASSERT_EQ(t, QTime(12, 34, 56)); ASSERT_EQ(t, QTime(12, 34, 56));
} }
TEST(Pgsql_Value, test_QTimeMS) TEST(Pgsql_Value, test_QTimeMS)
{ {
Pgsql::Value v("09:38:17.339817+02", TIMETZOID); Pgsql::Value v("09:38:17.339817+02", timetz_oid);
QTime t = v; QTime t = v;
ASSERT_EQ(t, QTime(9, 38, 17, 340)); ASSERT_EQ(t, QTime(9, 38, 17, 340));
} }
@ -58,19 +58,19 @@ TEST(Pgsql_Value, test_QTimeMS)
TEST(Pgsql_Value, isString_int4) TEST(Pgsql_Value, isString_int4)
{ {
Pgsql::Value v("1", INT4OID); Pgsql::Value v("1", int4_oid);
ASSERT_EQ(v.isString(), false); ASSERT_EQ(v.isString(), false);
} }
TEST(Pgsql_Value, isString_varchar) TEST(Pgsql_Value, isString_varchar)
{ {
Pgsql::Value v("1", VARCHAROID); Pgsql::Value v("1", varchar_oid);
ASSERT_EQ(v.isString(), true); ASSERT_EQ(v.isString(), true);
} }
TEST(Pgsql_Value, getAsVector_Ints) TEST(Pgsql_Value, getAsVector_Ints)
{ {
Pgsql::Value v("1 2", ANYOID); Pgsql::Value v("1 2", any_oid);
std::vector<int> r; std::vector<int> r;
v.getAsVector<int>(std::back_inserter(r)); v.getAsVector<int>(std::back_inserter(r));
@ -83,7 +83,7 @@ TEST(Pgsql_Value, getAsVector_Ints)
TEST(Pgsql_Value, getAsArray_Ints) TEST(Pgsql_Value, getAsArray_Ints)
{ {
Pgsql::Value v("{1,2}", TEXTARRAYOID); Pgsql::Value v("{1,2}", text_array_oid);
std::vector<int> r; std::vector<int> r;
v.getAsArray<int>(std::back_inserter(r)); v.getAsArray<int>(std::back_inserter(r));
@ -94,7 +94,7 @@ TEST(Pgsql_Value, getAsArray_Ints)
TEST(Pgsql_Value, getAsArray_QDateTime) TEST(Pgsql_Value, getAsArray_QDateTime)
{ {
Pgsql::Value v("{\"2017-12-11 10:11:22\",\"2017-12-13 12:00:11\"}", TEXTARRAYOID); Pgsql::Value v("{\"2017-12-11 10:11:22\",\"2017-12-13 12:00:11\"}", text_array_oid);
std::set<QDateTime> r; std::set<QDateTime> r;
v.getAsArray<QDateTime>(std::inserter(r, r.end())); v.getAsArray<QDateTime>(std::inserter(r, r.end()));
@ -103,7 +103,7 @@ TEST(Pgsql_Value, getAsArray_QDateTime)
TEST(Pgsql_Value, getAsArray_throws_on_NULL) TEST(Pgsql_Value, getAsArray_throws_on_NULL)
{ {
Pgsql::Value v("{1,NULL,2}", TEXTARRAYOID); Pgsql::Value v("{1,NULL,2}", text_array_oid);
std::vector<int> r; std::vector<int> r;
try { try {
v.getAsArray<int>(std::back_inserter(r)); v.getAsArray<int>(std::back_inserter(r));
@ -117,7 +117,7 @@ TEST(Pgsql_Value, getAsArray_throws_on_NULL)
TEST(Pgsql_Value, getAsArray_default_on_NULL) TEST(Pgsql_Value, getAsArray_default_on_NULL)
{ {
Pgsql::Value v("{1,NULL,2}", TEXTARRAYOID); Pgsql::Value v("{1,NULL,2}", text_array_oid);
std::vector<int> r; std::vector<int> r;
try { try {
v.getAsArray<int>(std::back_inserter(r), -1); v.getAsArray<int>(std::back_inserter(r), -1);
@ -132,7 +132,7 @@ TEST(Pgsql_Value, getAsArray_default_on_NULL)
TEST(Pgsql_Value, getAsArray_ignore_NULL) TEST(Pgsql_Value, getAsArray_ignore_NULL)
{ {
Pgsql::Value v("{1,NULL,2}", TEXTARRAYOID); Pgsql::Value v("{1,NULL,2}", text_array_oid);
std::vector<int> r; std::vector<int> r;
try { try {
v.getAsArray<int>(std::back_inserter(r), NullHandling::Ignore); v.getAsArray<int>(std::back_inserter(r), NullHandling::Ignore);
@ -146,7 +146,7 @@ TEST(Pgsql_Value, getAsArray_ignore_NULL)
TEST(Pgsql_Value, getAsArrayOptional) TEST(Pgsql_Value, getAsArrayOptional)
{ {
Pgsql::Value v("{1,NULL,2}", TEXTARRAYOID); Pgsql::Value v("{1,NULL,2}", text_array_oid);
std::vector<std::optional<int>> r; std::vector<std::optional<int>> r;
try { try {
v.getAsArrayOfOptional<int>(std::back_inserter(r)); v.getAsArrayOfOptional<int>(std::back_inserter(r));

View file

@ -1,12 +1,15 @@
include(gtest_dependency.pri) include(gtest_dependency.pri)
TEMPLATE = app TEMPLATE = app
CONFIG += console c++14 CONFIG += console c++17
CONFIG -= app_bundle CONFIG -= app_bundle
CONFIG += thread CONFIG += thread
CONFIG += qt CONFIG += qt
QT += core QT += core widgets
QMAKE_CXXFLAGS += /std:c++17
LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
HEADERS += HEADERS +=
@ -17,7 +20,9 @@ SOURCES += main.cpp \
tst_scopeguard.cpp \ tst_scopeguard.cpp \
tst_CsvWriter.cpp \ tst_CsvWriter.cpp \
tst_PasswordManager.cpp \ tst_PasswordManager.cpp \
tst_ParamJson.cpp tst_ParamJson.cpp \
tst_CodeBuilder.cpp \
tst_NameManglingRules.cpp
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../core/release/ -lcore win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../core/release/ -lcore
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../core/debug/ -lcore else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../core/debug/ -lcore
@ -60,3 +65,16 @@ else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../p
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/release/pglablib.lib else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/release/pglablib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/debug/pglablib.lib else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/debug/pglablib.lib
else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/libpglablib.a else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../../pglablib/libpglablib.a
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/release/ -lmygtestutils
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../mygtestutils/debug/ -lmygtestutils
else:unix:!macx: LIBS += -L$$OUT_PWD/../mygtestutils/ -lmygtestutils
INCLUDEPATH += $$PWD/../mygtestutils
DEPENDPATH += $$PWD/../mygtestutils
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/libmygtestutils.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/libmygtestutils.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/release/mygtestutils.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/debug/mygtestutils.lib
else:unix:!macx: PRE_TARGETDEPS += $$OUT_PWD/../mygtestutils/libmygtestutils.a

View file

@ -0,0 +1,231 @@
#include <gtest/gtest.h>
#include <gmock/gmock-matchers.h>
#include <QRegularExpression>
#include "PgType.h"
#include "PgTypeContainer.h"
#include "PrintTo_Qt.h"
#include "codebuilder/IndentationConfig.h"
#include "codebuilder/TypeMappings.h"
#include "Pgsql_oids.h"
using namespace testing;
// Test to verify my understanding of the documentation
TEST(QRegularExpression, doIUnderstandItCorrectly)
{
QString text("abcdefghi");
QRegularExpression re("c(def)g");
QRegularExpressionMatch match;
int pos = text.indexOf(re, 0, &match);
ASSERT_THAT(pos, Eq(2));
ASSERT_THAT(match.capturedStart(), Eq(2));
ASSERT_THAT(match.capturedEnd(), Eq(7));
ASSERT_THAT(match.capturedStart(1), Eq(3));
ASSERT_THAT(match.capturedEnd(1), Eq(6));
}
TEST(QRegularExpression, doIUnderstandItCorrectly2)
{
QString text("abc/%def%/ghi");
QRegularExpression re("(?:[^\\\\]|^)(\\/%([a-zA-Z0-9_-]+)%\\/)");
QRegularExpressionMatch match;
int pos = text.indexOf(re, 0, &match);
ASSERT_THAT(pos, Eq(2));
ASSERT_THAT(match.capturedStart(1), Eq(3));
ASSERT_THAT(match.capturedLength(1), Eq(7));
ASSERT_THAT(match.capturedStart(2), Eq(5));
ASSERT_THAT(match.capturedLength(2), Eq(3));
}
#include <QTextStream>
void FormatToStream(QTextStream &stream, QString format, std::function<void(QTextStream &, QString)> field_callback);
TEST(FormatToStream, EmptyFormat)
{
QString result;
QTextStream stream(&result);
FormatToStream(stream, "", nullptr);
stream.flush();
ASSERT_THAT(result, Eq(QString()));
}
TEST(FormatToStream, OnlyVar)
{
QString result;
QTextStream stream(&result);
FormatToStream(stream, "/%var%/",
[](QTextStream &stream, QString varname)
{
if (varname == "var")
stream << "abc";
});
stream.flush();
ASSERT_EQ(result, QString("abc"));
}
TEST(FormatToStream, StartWithVar)
{
QString result;
QTextStream stream(&result);
FormatToStream(stream, "/%var%/def",
[](QTextStream &stream, QString varname)
{
if (varname == "var")
stream << "abc";
});
stream.flush();
ASSERT_EQ(result, QString("abcdef"));
}
TEST(FormatToStream, EndWithVar)
{
QString result;
QTextStream stream(&result);
FormatToStream(stream, "def/%var%/",
[](QTextStream &stream, QString varname)
{
if (varname == "var")
stream << "abc";
});
stream.flush();
ASSERT_EQ(result, QString("defabc"));
}
TEST(FormatToStream, TwoVarsTogether)
{
QString result;
QTextStream stream(&result);
FormatToStream(stream, "/%var1%//%var2%/",
[](QTextStream &stream, QString varname)
{
if (varname == "var1")
stream << "abc";
else if (varname == "var2")
stream << "def";
});
stream.flush();
ASSERT_EQ(result, QString("abcdef"));
}
TEST(FormatToStream, TwoVarsWithTextInBetween)
{
QString result;
QTextStream stream(&result);
FormatToStream(stream, "1/%var1%/2/%var2%/3",
[](QTextStream &stream, QString varname)
{
if (varname == "var1")
stream << "abc";
else if (varname == "var2")
stream << "def";
});
stream.flush();
ASSERT_EQ(result, QString("1abc2def3"));
}
TEST(IndentationConfig, tab8indent4true_level1)
{
IndentationConfig icfg(8, 4, true);
QString result = icfg.getIndentString(1);
ASSERT_EQ(result, " ");
}
TEST(IndentationConfig, tab8indent4true_level2)
{
IndentationConfig icfg(8, 4, true);
QString result = icfg.getIndentString(2);
ASSERT_EQ(result, "\t");
}
TEST(IndentationConfig, tab8indent4true_level3)
{
IndentationConfig icfg(8, 4, true);
QString result = icfg.getIndentString(3);
ASSERT_EQ(result, "\t ");
}
TEST(IndentationConfig, tab8indent4false_level1)
{
IndentationConfig icfg(8, 4, false);
QString result = icfg.getIndentString(1);
ASSERT_EQ(result, " ");
}
TEST(IndentationConfig, tab8indent4false_level2)
{
IndentationConfig icfg(8, 4, false);
QString result = icfg.getIndentString(2);
ASSERT_EQ(result, " ");
}
class TypeMappingsTest : public ::testing::Test {
protected:
void SetUp() override
{
def_str_type = "std::string";
int4str = "int";
int8str = "long long";
tm = TypeMappings( {
{ Pgsql::int4_oid, int4str },
{ Pgsql::int8_oid, int8str }
});
tm.setDefaultStringType(def_str_type);
tm.setDefaultContainerType("std::vector<%1>");
}
// void TearDown() override {}
QString def_str_type;
QString int4str;
QString int8str;
TypeMappings tm;
};
TEST_F(TypeMappingsTest, defStringType)
{
QString result = tm.getTypeForOid(Pgsql::float4_oid);
ASSERT_EQ(result, def_str_type);
}
TEST_F(TypeMappingsTest, int4Type)
{
QString result = tm.getTypeForOid(Pgsql::int4_oid);
ASSERT_EQ(result, int4str);
}
TEST_F(TypeMappingsTest, int4overideType)
{
tm.set(Pgsql::int4_oid, "QString");
QString result = tm.getTypeForOid(Pgsql::int4_oid);
ASSERT_EQ(result, "QString");
}
// Need catalogue for the next test
// Maybe we should mock this !?
TEST_F(TypeMappingsTest, int4arrayType)
{
auto types= std::make_shared<PgTypeContainer>();
PgType int4arr;
int4arr.oid = Pgsql::int4_array_oid;
int4arr.elem = Pgsql::int4_oid;
types->add(int4arr);
tm.setTypes(types);
QString result = tm.getTypeForOid(Pgsql::int4_array_oid);
ASSERT_EQ(result, "std::vector<int>");
}

View file

@ -3,6 +3,7 @@
#include "CsvWriter.h" #include "CsvWriter.h"
#include <QTextStream> #include <QTextStream>
#include <QByteArray> #include <QByteArray>
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;

View file

@ -2,6 +2,7 @@
#include <gmock/gmock-matchers.h> #include <gmock/gmock-matchers.h>
#include "ExplainTreeModelItem.h" #include "ExplainTreeModelItem.h"
#include "json/json.h" #include "json/json.h"
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;

View file

@ -0,0 +1,54 @@
#include <gtest/gtest.h>
#include <gmock/gmock-matchers.h>
#include "PrintTo_Qt.h"
#include "codebuilder/NameManglingRules.h"
#include "Pgsql_oids.h"
using namespace testing;
class NameManglingRulesTest : public ::testing::Test, public ::testing::WithParamInterface<
std::tuple<QString, NameManglingRules::CaseConversion, bool> > {
protected:
virtual void SetUp() override
{
NameManglingRules r;
auto p = GetParam();
//ReplaceRules replaceRules;
// { {"[ -_]", QRegularExpression::OptimizeOnFirstUsageOption }, "", true }
r.replaceRules;
//QString replaceSpaceWith; ///< default is empty string which means remove spaces
r.replaceSpaceWith = std::get<0>(p);
//CollisionHandling CollisionHandling = CollisionHandling::Restrict;
//CaseConversion caseConversion = CaseConversion::AsIs; ///< overall case conversion rule
r.caseConversion = std::get<1>(p);
//CaseConversion caseFirstChar = CaseConversion::AsIs; ///< case of the first char
r.camelCase = std::get<2>(p); ///< removes underscores and make first char after underscore uppercase
rules = r;
}
NameManglingRules rules;
};
TEST_P(NameManglingRulesTest, test1)
{
ASSERT_EQ(rules.replaceSpaceWith, std::get<0>(GetParam()));
}
TEST_P(NameManglingRulesTest, test2)
{
ASSERT_EQ(rules.camelCase, std::get<2>(GetParam()));
}
INSTANTIATE_TEST_CASE_P(InstantiationName1,
NameManglingRulesTest,
::testing::Combine(
::testing::Values("", "_", "+"),
::testing::Values(NameManglingRules::CaseConversion::AsIs,
NameManglingRules::CaseConversion::Lower,
NameManglingRules::CaseConversion::Upper),
::testing::Bool()
));

View file

@ -2,6 +2,7 @@
#include <gmock/gmock-matchers.h> #include <gmock/gmock-matchers.h>
#include "ParamListModel.h" #include "ParamListModel.h"
#include "ParamListJson.h" #include "ParamListJson.h"
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;

View file

@ -1,6 +1,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock-matchers.h> #include <gmock/gmock-matchers.h>
#include "PasswordManager.h" #include "PasswordManager.h"
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;

View file

@ -1,6 +1,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock-matchers.h> #include <gmock/gmock-matchers.h>
#include "SqlLexer.h" #include "SqlLexer.h"
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;

View file

@ -1,6 +1,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock-matchers.h> #include <gmock/gmock-matchers.h>
#include "Expected.h" #include "Expected.h"
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;

View file

@ -1,6 +1,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock-matchers.h> #include <gmock/gmock-matchers.h>
#include "ScopeGuard.h" #include "ScopeGuard.h"
#include "PrintTo_Qt.h"
using namespace testing; using namespace testing;