Files
qt6-migration-pipeline/Lts/Common/CodeGen/StructBuilder.cpp
T

1432 lines
49 KiB
C++
Executable File

#include "StructBuilder.h"
#include <QDateTime>
#include <NGLLogger/NGLLoggerBootstrap.h>
using namespace CodeGen;
class DataTypeInfoIdl : public DataTypeInfo
{
protected:
DataTypeInfoIdl(const QString &name, const QString &idlType, bool isPod)
: DataTypeInfo(name, isPod)
, m_idlType(idlType)
{}
public:
QString idlType() const override final { return m_idlType; }
private:
const QString m_idlType;
};
class DataTypeInfoSimple : public DataTypeInfoIdl
{
public:
DataTypeInfoSimple(const QString &name,
const QString &idlType,
const QString &ddsType,
const QString &sqlType,
const QString &cppType,
bool isPod)
: DataTypeInfoIdl(name, idlType, isPod)
, m_ddsType(ddsType)
, m_sqlType(sqlType)
, m_cppType(cppType)
{}
QString ddsType() const override final { return m_ddsType; }
QString sqlType() const override final { return m_sqlType; }
QString cppType() const override final { return m_cppType; }
protected:
QString m_ddsType;
QString m_sqlType;
QString m_cppType;
};
class DataTypeInfoStructure final : public DataTypeInfoSimple
{
public:
DataTypeInfoStructure(const QString &name, const QString &idlType, StructBuilder *structBuilder)
: DataTypeInfoSimple(name, idlType, QString(), idlType, idlType, false)
{
const CompleteTopicTypeInformation ctti = structBuilder->topicTypeInformationByStructType(idlType);
Q_ASSERT(ctti.isValid());
m_member.reserve(ctti.members.size());
for (const IdlData &idlData : ctti.members)
m_member += DataTypeInfo::fromIdlDataType(idlData.name, idlData.type, structBuilder);
m_serviceName = ctti.serviceName;
if (ctti.name.startsWith(m_serviceName + QStringLiteral("::")))
m_ddsType = ctti.name;
else
m_ddsType = m_serviceName + QStringLiteral("::") + ctti.name;
}
bool isStructure() const override final { return true; }
virtual QVector<QSharedPointer<DataTypeInfo>> member() const override final { return m_member; }
private:
QVector<QSharedPointer<DataTypeInfo>> m_member;
QString m_serviceName;
};
class DataTypeInfoSequence final : public DataTypeInfoIdl
{
public:
DataTypeInfoSequence(const QString &name, const QString &idlType, StructBuilder *structBuilder, const QString &svcName)
: DataTypeInfoIdl(name, idlType, false)
{
const int start = idlType.indexOf(QLatin1Char('<'));
const int end = idlType.lastIndexOf(QLatin1Char('>'));
Q_ASSERT(start >= 0 && end >= 0 && end > start);
const QString inner = idlType.mid(start + 1, end - start - 1);
m_innerDataType = DataTypeInfo::fromIdlDataType(QStringLiteral("inner"), inner, structBuilder, svcName);
Q_ASSERT(m_innerDataType);
}
QString ddsType() const override final
{
return QLatin1String("std::vector<") + m_innerDataType->ddsType() + QLatin1Char('>');
}
QString sqlType() const override final
{
return QStringLiteral("jsonb");
}
QString cppType() const override final
{
return QLatin1String("std::vector<") + m_innerDataType->cppType() + QLatin1Char('>');
}
QString cppTypeConstRef() const override final
{
return QLatin1String("const std::vector<") + m_innerDataType->cppType() + QLatin1String("> &");
}
virtual bool isSequence() const override final { return true; }
QSharedPointer<DataTypeInfo> innerDataType() const override final { return m_innerDataType; }
private:
QSharedPointer<DataTypeInfo> m_innerDataType;
};
QSharedPointer<DataTypeInfo> DataTypeInfo::fromIdlDataType(const QString &name,
const QString &idlType,
StructBuilder *structBuilder,
const QString &svcName)
{
const QString fullIdlType = (svcName.isEmpty() || idlType.contains(QLatin1String("::")))
? idlType : svcName + QLatin1String("::") + idlType;
if (idlType == QLatin1String("sequence<octet>"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("std::vector<uint8_t>"),
QStringLiteral("bytea"),
QStringLiteral("QByteArray"),
false));
if (idlType == QLatin1String("boolean"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("bool"),
QStringLiteral("boolean"),
QStringLiteral("bool"),
true));
if (idlType == QLatin1String("char"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("char"),
QStringLiteral("char"),
QStringLiteral("char"),
true));
if (idlType == QLatin1String("double"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("double"),
QStringLiteral("double precision"),
QStringLiteral("double"),
true));
if (idlType == QLatin1String("long"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("int32_t"),
QStringLiteral("integer"),
QStringLiteral("qint32"),
true));
if (idlType == QLatin1String("long long"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("rti::core::int64"),
QStringLiteral("bigint"),
QStringLiteral("qint64"),
true));
if (idlType == QLatin1String("short"))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("int16_t"),
QStringLiteral("smallint"),
QStringLiteral("qint16"),
true));
if (idlType.startsWith(QLatin1String("string")))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name,
idlType,
QStringLiteral("std::string"),
QStringLiteral("text"),
QStringLiteral("std::string"),
false));
if (idlType.startsWith(QLatin1String("sequence")))
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSequence(name, idlType, structBuilder, svcName));
const EnumInformation ei = structBuilder->enumInformationByType(fullIdlType, true, false);
if (ei.isValid())
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name, idlType, ei.enumName, QStringLiteral("integer"), ei.enumName, true));
const CompleteTopicTypeInformation ctti = structBuilder->topicTypeInformationByStructType(fullIdlType, true);
if (ctti.isValid())
return QSharedPointer<DataTypeInfo>(new DataTypeInfoStructure(name, idlType, structBuilder));
return QSharedPointer<DataTypeInfo>(new DataTypeInfoSimple(name, idlType, idlType, QStringLiteral("integer"), idlType, true));
}
StructBuilder::StructBuilder(XmlReader *xmlReader)
: m_needPoint3d(false)
, m_needPgArrayInclude(false)
, m_xmlReader(xmlReader)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("CodeGen.StructBuilder"))
, m_loggerCSV(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("fileCSV"))
{}
bool StructBuilder::buildStructures()
{
m_structInfos.clear();
m_topicTypeInfos.clear();
m_enumInfos.clear();
m_sqlTableInformations.clear();
m_sqlTableInformationsAlreadyAvailable.clear();
m_sqlViewInformations.clear();
m_externalTopicTypes.clear();
m_serializeFromToJsonTopics.clear();
m_jsonStructureInformation.clear();
m_needPoint3d = false;
m_needPgArrayInclude = false;
const QMap<QString, QSharedPointer<TableInformation> > tables = m_xmlReader->getTables();
for (const QSharedPointer<TableInformation> &ti : tables)
{
CompleteTableInformation cti(*ti);
if (cti.exerciseDependency == ExerciseDependency::Undefined)
cti.exerciseDependency = m_xmlReader->defaultExerciseDependency();
m_sqlTableInformations[ti->name] = cti;
}
const QMap<QString, QSharedPointer<ViewInformation> > views = m_xmlReader->getViews();
for (const QSharedPointer<ViewInformation> &vi : views)
{
ViewInformation cti(*vi);
if (cti.exerciseDependency == ExerciseDependency::Undefined)
cti.exerciseDependency = m_xmlReader->defaultExerciseDependency();
m_sqlViewInformations[vi->name] = cti;
}
const QVector<EnumInformation> enumData = m_xmlReader->getEnumerations();
for (const EnumInformation &ei : enumData)
{
if (!handleEnum(ei))
return false;
}
const QVector<ServiceStructInformation> structsToGenerate = m_xmlReader->getStructToGenerate();
for (const ServiceStructInformation &ssi : structsToGenerate)
{
if (!handleTable(ssi))
return false;
}
const QVector<TopicTypeInformation> idlStructsToGenerate = m_xmlReader->getIdlStructToGenerate();
for (const TopicTypeInformation &tti : idlStructsToGenerate)
{
DEBUG_LOG(m_loggerCSV) << tti.name;
if (!handleIdlStructInfo(tti, m_topicTypeInfos))
return false;
}
const QVector<TopicTypeInformation> idlExternalTopicTypes = m_xmlReader->getExternalTopicTypes();
for (const TopicTypeInformation &tti : idlExternalTopicTypes)
{
const ServiceTypeStruct sts = extractServiceAndTypeFromTypename(tti.name);
if (!sts.isExternalType())
{
ERROR_LOG(m_logger) << "Invalid external topic type name: '" << tti.name << "'";
return false;
}
if (!handleIdlStructInfo(tti, m_externalTopicTypes, sts.service))
return false;
}
return true;
}
bool StructBuilder::handleEnum(const EnumInformation &ei)
{
m_enumInfos.push_back(ei);
if (ei.tableName.isEmpty())
return true;
QSharedPointer<TableInformation> ti = m_xmlReader->getTable(ei.tableName);
if (ti.isNull())
{
WARNING_LOG(m_logger) << "Could not find table information for enum: "
<< ei.enumName << ", table: " << ei.tableName;
return false;
}
CompleteTableInformation cti = m_sqlTableInformations[ei.tableName];
for (const ColumnInformation &ci : qAsConst(ti->plainColumns))
{
MemberInformation mi;
mi.db = FullQualifiedColumnInformation(ci, ei.tableName);
cti.columns.push_back(std::move(mi));
}
m_sqlTableInformations[ei.tableName] = cti;
return true;
}
CompleteStructInformation StructBuilder::structInformationByTableName(const QString &tableName) const
{
for (const CompleteStructInformation &csi : m_structInfos)
{
if (csi.primaryTable->name == tableName)
return csi;
}
return CompleteStructInformation();
}
EnumInformation StructBuilder::enumInformationByType(const QString &type, bool checkExternals, bool verbose)
{
if (type.isEmpty())
return EnumInformation();
const ServiceTypeStruct extInfo = extractServiceAndTypeFromTypename(type);
if (extInfo.isExternalType())
{
if (!checkExternals)
{
ERROR_LOG(m_logger) << "Could not find enumeration '" << type << "'";
return EnumInformation();
}
if (extInfo.type.isEmpty())
{
WARNING_LOG(m_logger) << "Could not parse external enumeration '" << type << "'";
return EnumInformation();
}
return m_xmlReader->getExternalEnumeration(extInfo.service, extInfo.type, verbose);
}
for (const EnumInformation &ei : qAsConst(m_enumInfos))
{
if (ei.enumName == type)
return ei;
}
if (verbose)
ERROR_LOG(m_logger) << "Could not find enumeration '" << type << "'";
return EnumInformation();
}
CompleteTopicTypeInformation StructBuilder::topicTypeInformationByStructType(const QString &type, bool checkExternals)
{
DEBUG_LOG(m_logger) << "topicTypeInformationByStructType(" << type << ")";
if (type.isEmpty())
return CompleteTopicTypeInformation();
const ServiceTypeStruct extInfo = extractServiceAndTypeFromTypename(type);
if (extInfo.isExternalType())
{
if (!checkExternals)
return CompleteTopicTypeInformation();
return externalTopicTypeByStructType(extInfo);
}
for (const CompleteTopicTypeInformation &csi : qAsConst(m_topicTypeInfos))
{
if (csi.name == type)
return csi;
}
DEBUG_LOG(m_logger) << "Type '" << type << "' not found in idlStructs - maybe not yet exported or an enum";
const QVector<TopicTypeInformation> idlStructsToGenerate = m_xmlReader->getIdlStructToGenerate();
for (const TopicTypeInformation &tti : idlStructsToGenerate)
{
if (tti.name == type)
{
DEBUG_LOG(m_logger) << "Found not yet exported type " << type;
if (!handleIdlStructInfo(tti, m_topicTypeInfos))
return CompleteTopicTypeInformation();
return topicTypeInformationByStructType(type);
}
}
ERROR_LOG(m_logger) << "Could not find type '" << type << "' in idlStructs";
return CompleteTopicTypeInformation();
}
CompleteTopicTypeInformation StructBuilder::externalTopicTypeByStructType(const ServiceTypeStruct &sts)
{
const QString typeToSearch = sts.fqType();
DEBUG_LOG(m_logger) << "externalTopicTypeByStructType " << typeToSearch;
for (const CompleteTopicTypeInformation &ctti : qAsConst(m_externalTopicTypes))
{
if (ctti.name == typeToSearch)
return ctti;
}
if (!loadExternalTopicType(sts))
return CompleteTopicTypeInformation();
return externalTopicTypeByStructType(sts);
}
bool StructBuilder::loadExternalTopicType(const ServiceTypeStruct &sts)
{
DEBUG_LOG(m_logger) << "loadExternalTopicType(" << sts.fqType() << ")";
const TopicTypeInformation tti = m_xmlReader->loadExternalTopicType(sts.service, sts.type);
if (!tti.isValid())
{
DEBUG_LOG(m_logger) << "Could not find external topic '" << sts.fqType() << "'";
return false;
}
if (!handleIdlStructInfo(tti, m_externalTopicTypes, sts.service))
return false;
return true;
}
bool StructBuilder::getColumnsFromTable(const QString &tableName,
QVector<ColumnInformationEx> &columns,
QVector<QString> &tableNames) const
{
if (tableName.isEmpty())
return true;
const QString parentTable = m_xmlReader->getStruct2BaseClassRelations().value(tableName);
if (!getColumnsFromTable(parentTable, columns, tableNames))
return false;
tableNames += tableName;
const QSharedPointer<TableInformation> ti = m_xmlReader->getTable(tableName);
QVector<ConstraintInformation> constraints;
constraints.reserve(ti->constraints.size());
for (const ConstraintInformation &ci : qAsConst(ti->constraints))
{
if (ci.affectedColumns.size() != 1)
continue;
if (ci.type != ConstraintInformation::Type::index)
continue;
constraints += ci;
}
columns.reserve(columns.size() + ti->plainColumns.size());
for (const auto &plainColum : qAsConst(ti->plainColumns))
{
ColumnInformationEx cie(ColumnInformationEx(plainColum, ti));
for (int j = 0; j < constraints.size(); ++j)
{
const ConstraintInformation &ci = constraints.at(j);
if (ci.affectedColumns.first() == cie.columnName)
{
cie.generateSelectRemove = true;
constraints.remove(j);
break;
}
}
columns += cie;
}
return true;
}
bool StructBuilder::handleTable(const ServiceStructInformation &ssi)
{
DEBUG_LOG(m_loggerCSV) << "StructInfo name: #" << ssi.name;
CompleteStructInformation csi;
csi.structName = ssi.name;
csi.primaryTable = m_xmlReader->getTable(ssi.primaryTable);
csi.viewName = csi.primaryTable->name + QLatin1String("_view");
csi.hasStaticContent = ssi.hasStaticContent;
csi.dbNotifications = ssi.dbNotifications;
DEBUG_LOG(m_loggerCSV) << "primaryTable: " << csi.primaryTable;
DEBUG_LOG(m_loggerCSV) << "hasStaticContent: " << csi.hasStaticContent;
QVector<ColumnInformationEx> columns;
QVector<QString> tableNames;
if (!getColumnsFromTable(ssi.primaryTable, columns, tableNames))
{
WARNING_LOG(m_logger) << "Could not retrieve columns from table "
<< ssi.primaryTable;
return false;
}
DEBUG_LOG(m_logger) << "Got " << columns.size() << " columns for table "
<< ssi.primaryTable;
QSet<QString> sqlTables;
csi.member.reserve(columns.size() + 1);
MemberInformation miPkFirstTable, miPkLastTable;
for (const ColumnInformationEx &ci : qAsConst(columns))
{
DEBUG_LOG(m_logger) << "handling column " << ci.columnName;
const QSharedPointer<TableInformation> ti = ci.table;
if (ti.isNull())
{
WARNING_LOG(m_logger) << "Could not find table for column " << ci.columnName
<< " primary table is " << ssi.primaryTable;
return false;
}
csi.tables += ti;
sqlTables += ti->name;
MemberInformation memberInfo;
memberInfo.ea.column = ci.columnName;
memberInfo.ea.table = ti->name;
memberInfo.ea.type = ci.datatype;
memberInfo.db = FullQualifiedColumnInformation(ci, memberInfo.ea.table);
if (ci.hasSequence)
{
memberInfo.db.usedForInsert = !ci.isPrimaryKey;
memberInfo.db.hasSequence = true;
}
else
memberInfo.db.usedForInsert = true;
memberInfo.db.usedForView = !ci.isPrimaryKey;
memberInfo.cpp.structName = ssi.name;
memberInfo.cpp.memberName = camelCaseString(ci.columnName);
memberInfo.cpp.type = ci.datatype;
memberInfo.cpp.usedForCppStruct = !ci.isPrimaryKey;
if (ci.isForeignKey)
{
const QSharedPointer<ForeignKeyInformation> fki = ti->fkInformationForColumn(ti->name, ci.columnName);
if (!fki.isNull())
{
for(const auto &tbl : qAsConst(csi.tables))
{
if (tbl->name == fki->destination.tableName)
{
memberInfo.cpp.isReadOnly = true;
memberInfo.fk = fki;
memberInfo.cpp.memberName = QLatin1String("priv_") + memberInfo.cpp.memberName;
break;
}
}
if (memberInfo.fk.isNull())
{
if (fki->destination.service.isEmpty())
{
for (const EnumInformation &ei : qAsConst(m_enumInfos))
{
if (ei.tableName == fki->destination.tableName)
{
memberInfo.enumeration = QSharedPointer<EnumInformation>(new EnumInformation(ei));
break;
}
}
}
else
{
QString enumType = fki->destination.service + QStringLiteral("::") +
camelCaseString(fki->destination.tableName, true);
EnumInformation ei = enumInformationByType(enumType, true, false);
DEBUG_LOG(m_logger) << "Checking if " << enumType << " is an enum: " << ei.isValid();
if (!ei.isValid() && fki->destination.tableName.contains(QLatin1Char('_')))
{
enumType = fki->destination.service + QStringLiteral("::") +
camelCaseString(fki->destination.tableName.section(QLatin1Char('_'), 1), true);
ei = enumInformationByType(enumType, true, false);
DEBUG_LOG(m_logger) << "Checking if " << enumType << " is an enum: " << ei.isValid();
}
if (ei.isValid() &&
ei.tableName == fki->destination.tableName)
memberInfo.enumeration = QSharedPointer<EnumInformation>(new EnumInformation(ei));
}
}
}
}
MemberInformation memberInfoJson = memberInfo;
memberInfoJson.cpp.usedForJson = true;
memberInfoJson.cpp.usedForCppStruct = false;
memberInfoJson.db.isForeignKey = false;
memberInfoJson.db.generateSelectRemove = false;
memberInfoJson.db.usedForView = false;
memberInfoJson.db.usedForInsert = false;
if (ci.isOptional)
{
memberInfo.cpp.isOptional = true;
memberInfoJson.cpp.isOptional = true;
memberInfo.ea.type = QStringLiteral("QVariant");
memberInfo.cpp.type = memberInfo.ea.type;
}
if (!fixupCustomDbDatatypes(memberInfo, csi.member) ||
!fixupQVariantConversions(memberInfo))
return false;
if (!fixupCustomDbDatatypes(memberInfoJson, csi.member) ||
!fixupQVariantConversions(memberInfoJson))
return false;
if (ci.isPrimaryKey && tableNames.first() == ti->name)
{
miPkFirstTable = memberInfo;
}
if (ci.isPrimaryKey && tableNames.last() == ti->name)
{
miPkLastTable = memberInfo;
}
csi.member.push_back(memberInfo);
csi.member.push_back(memberInfoJson);
addToSqlTableInformation(memberInfo);
DEBUG_LOG(m_loggerCSV) << memberInfo.toString();
}
if (!miPkFirstTable.isEmpty())
{
miPkFirstTable.db.usedForInsert = false;
miPkFirstTable.db.usedForView = true;
miPkFirstTable.cpp.usedForCppStruct = true;
csi.member.push_front(miPkFirstTable);
}
if (tableNames.size() > 1 && !miPkLastTable.isEmpty())
{
miPkLastTable.db.usedForInsert = false;
miPkLastTable.db.usedForView = true;
miPkLastTable.cpp.usedForCppStruct = true;
miPkLastTable.db.isAssignmentForPrimaryTablePk = true;
miPkLastTable.db.columnNameView =
miPkLastTable.db.table + QLatin1Char('_') + miPkLastTable.db.columnName;
QString name = miPkLastTable.db.table;
if (name.startsWith(m_xmlReader->getServiceAbbr().toLower()))
name = name.mid(m_xmlReader->getServiceAbbr().size() + 1);
miPkLastTable.cpp.memberName = camelCaseString(QLatin1String("priv_") + name + QLatin1String("_id"));
csi.member.push_back(miPkLastTable);
}
m_structInfos.push_back(csi);
m_sqlTableInformationsAlreadyAvailable += sqlTables;
return true;
}
bool StructBuilder::handleIdlStructInfo(const TopicTypeInformation &tti,
QVector<CompleteTopicTypeInformation> &destination,
const QString &svcName)
{
for (const CompleteTopicTypeInformation &c : qAsConst(destination))
{
if (c.name == tti.name)
return true;
}
CompleteTopicTypeInformation ctti(tti);
ctti.members.reserve(tti.columns.size());
for (const auto &ci : tti.columns)
{
IdlData idlData(ci);
idlData.dataTypeInfo = DataTypeInfo::fromIdlDataType(idlData.name, idlData.type, this, svcName);
ctti.members.push_back(idlData);
if (idlData.isKey && idlData.isOptional)
{
ERROR_LOG(m_logger) << "Column option isKey & isOptional are mutually exclusive!";
ERROR_LOG(m_logger) << "Change column '" << tti.name << "."
<< idlData.name << "'' to have either key or optional parameter ";
return false;
}
}
if (!svcName.isEmpty() &&
!ctti.baseValueType.isEmpty() &&
!ctti.baseValueType.contains(QLatin1String("::")))
ctti.baseValueType = svcName + QStringLiteral("::") + ctti.baseValueType;
ctti.serviceName = svcName.isEmpty() ? m_xmlReader->getServiceNamespace() : svcName;
destination.push_back(ctti);
return true;
}
bool StructBuilder::fixupCustomDbDatatypes(MemberInformation &memberInfo, QVector<MemberInformation> &members)
{
if (!fixupDatatypePoint2d(memberInfo, members))
return false;
if (!fixupDatatypePoint3d(memberInfo, members))
return false;
if (!fixupDatatypeIntegerArray(memberInfo))
return false;
return true;
}
bool StructBuilder::fixupDatatypePoint2d(MemberInformation &memberInfo,
QVector<MemberInformation> &members)
{
if (memberInfo.ea.type.toLower() != QLatin1String("point_2d"))
return true;
MemberInformation mi = memberInfo;
mi.db.datatype = QStringLiteral("double precision");
mi.cpp.type = QStringLiteral("QPointF");
mi.cpp.fromVariantPost = QStringLiteral(".toDouble()");
MemberInformation miX = mi;
MemberInformation miY = mi;
miX.db.columnName = memberInfo.db.columnName + QLatin1String("_x");
miY.db.columnName = memberInfo.db.columnName + QLatin1String("_y");
miY.cpp.usedForCppStruct = false;
miY.cpp.usedForJson = false;
miX.cpp.toVariantPost = QStringLiteral(".x()");
miY.cpp.toVariantPost = QStringLiteral(".y()");
miX.cpp.fromVariantPre1 = QStringLiteral(".rx()");
miY.cpp.fromVariantPre1 = QStringLiteral(".ry()");
miX.cpp.memberName = camelCaseString(miX.cpp.memberName);
miX.cpp.toJsonPre = QStringLiteral("toJson(");
miX.cpp.toJsonPost = QStringLiteral(")");
miX.cpp.fromJsonPre2 = QStringLiteral("fromJson<QPointF>(");
miX.cpp.fromJsonPost = QStringLiteral(")");
members.push_back(miX);
if (memberInfo.cpp.usedForCppStruct)
addToSqlTableInformation(miX);
DEBUG_LOG(m_loggerCSV) << miX.toString();
memberInfo = miY;
return true;
}
bool StructBuilder::fixupDatatypePoint3d(MemberInformation &memberInfo,
QVector<MemberInformation> &members)
{
if (memberInfo.ea.type.toLower() != QLatin1String("point_3d"))
return true;
MemberInformation mi = memberInfo;
mi.db.datatype = QStringLiteral("double precision");
mi.cpp.type = QStringLiteral("LtsUtils::QPoint3D");
mi.cpp.fromVariantPost = QStringLiteral(".toDouble()");
MemberInformation miX = mi;
MemberInformation miY = mi;
MemberInformation miZ = mi;
miX.db.columnName = memberInfo.db.columnName + QLatin1String("_x");
miY.db.columnName = memberInfo.db.columnName + QLatin1String("_y");
miZ.db.columnName = memberInfo.db.columnName + QLatin1String("_z");
miY.cpp.usedForCppStruct = false;
miZ.cpp.usedForCppStruct = false;
miY.cpp.usedForJson = false;
miZ.cpp.usedForJson = false;
miX.cpp.toVariantPost = QStringLiteral(".x()");
miY.cpp.toVariantPost = QStringLiteral(".y()");
miZ.cpp.toVariantPost = QStringLiteral(".z()");
miX.cpp.fromVariantPre1 = QStringLiteral(".rx()");
miY.cpp.fromVariantPre1 = QStringLiteral(".ry()");
miZ.cpp.fromVariantPre1 = QStringLiteral(".rz()");
miX.cpp.memberName = camelCaseString(miX.cpp.memberName);
miX.cpp.toJsonPre = QStringLiteral("toJson(");
miX.cpp.toJsonPost = QStringLiteral(")");
miX.cpp.fromJsonPre2 = QStringLiteral("fromJson<LtsUtils::QPoint3D>(");
miX.cpp.fromJsonPost = QStringLiteral(")");
members.push_back(miX);
members.push_back(miY);
if (memberInfo.cpp.usedForCppStruct)
{
addToSqlTableInformation(miX);
addToSqlTableInformation(miY);
}
DEBUG_LOG(m_loggerCSV) << miX.toString();
memberInfo = miZ;
m_needPoint3d = true;
return true;
}
bool StructBuilder::fixupDatatypeIntegerArray(MemberInformation &memberInfo)
{
if (memberInfo.ea.type.toLower() == QLatin1String("integer[]"))
{
memberInfo.db.datatype = memberInfo.ea.type.toLower();
memberInfo.cpp.type = QStringLiteral("LtsUtils::IntArray");
memberInfo.cpp.fromVariantPre2 = QStringLiteral("LtsUtils::IntArray::fromPgString(");
memberInfo.cpp.fromVariantPost = QStringLiteral(".toString())");
memberInfo.cpp.toVariantPost = QStringLiteral(".toPgString()");
m_needPgArrayInclude = true;
}
else if (memberInfo.ea.type.toLower() == QLatin1String("bigint[]"))
{
memberInfo.db.datatype = memberInfo.ea.type.toLower();
memberInfo.cpp.type = QStringLiteral("LtsUtils::BigintArray");
memberInfo.cpp.fromVariantPre2 = QStringLiteral("LtsUtils::BigintArray::fromPgString(");
memberInfo.cpp.fromVariantPost = QStringLiteral(".toString())");
memberInfo.cpp.toVariantPost = QStringLiteral(".toPgString()");
m_needPgArrayInclude = true;
}
else if (memberInfo.cpp.type.toLower() == QLatin1String("sequence<long>"))
{
memberInfo.db.datatype = QStringLiteral("integer[]");
memberInfo.cpp.type = QStringLiteral("std::vector<int32_t>");
memberInfo.cpp.fromVariantPre2 = QStringLiteral("std::vector<int32_t>(LtsUtils::IntArray::fromPgString(");
memberInfo.cpp.fromVariantPost = QStringLiteral(".toString())())");
memberInfo.cpp.toVariantPre = QStringLiteral("LtsUtils::IntArray(");
memberInfo.cpp.toVariantPost = QStringLiteral(").toPgString()");
m_needPgArrayInclude = true;
}
else if (memberInfo.ea.type.toLower() == QLatin1String("integer[][]"))
{
memberInfo.db.datatype = memberInfo.ea.type.toLower();
memberInfo.cpp.type = QStringLiteral("LtsUtils::IntArray2D");
memberInfo.cpp.fromVariantPre2 = QStringLiteral("LtsUtils::IntArray2D::fromPgString(");
memberInfo.cpp.fromVariantPost = QStringLiteral(".toString())");
memberInfo.cpp.toVariantPost = QStringLiteral(".toPgString()");
m_needPgArrayInclude = true;
}
else if (memberInfo.ea.type.toLower() == QLatin1String("bigint[][]"))
{
memberInfo.db.datatype = memberInfo.ea.type.toLower();
memberInfo.cpp.type = QStringLiteral("LtsUtils::BigintArray2D");
memberInfo.cpp.fromVariantPre2 = QStringLiteral("LtsUtils::BigintArray2D::fromPgString(");
memberInfo.cpp.fromVariantPost = QStringLiteral(".toString())");
memberInfo.cpp.toVariantPost = QStringLiteral(".toPgString()");
m_needPgArrayInclude = true;
}
return true;
}
bool StructBuilder::fixupQVariantConversions(MemberInformation &mi) const
{
if (!mi.cpp.toVariantPost.isEmpty())
return true;
mi.cpp.toVariantPre.clear();
mi.cpp.toVariantPost.clear();
mi.cpp.fromVariantPre1.clear();
mi.cpp.fromVariantPre2.clear();
mi.cpp.fromVariantPost.clear();
if (mi.enumeration)
{
QString svcName(mi.enumeration->serviceName);
if (!svcName.isEmpty())
svcName += QStringLiteral("::");
mi.cpp.type = svcName + mi.enumeration->enumName;
mi.cpp.fromVariantPre2 = QStringLiteral("static_cast<") +
svcName + mi.enumeration->enumName +
QStringLiteral("_def::type>(");
mi.cpp.fromVariantPost = QStringLiteral(".toInt())");
mi.cpp.toVariantPre = QStringLiteral("static_cast<int>(");
mi.cpp.toVariantPost = QStringLiteral(".underlying())");
if (!mi.enumeration->values.isEmpty())
{
mi.cpp.defaultValue = svcName + mi.enumeration->enumName + QStringLiteral("::") +
mi.enumeration->values.first().key;
}
return true;
}
const QString datatype = mi.cpp.type.toLower();
if (datatype == QLatin1String("bigint") ||
datatype == QLatin1String("qint64") ||
datatype == QLatin1String("long long"))
{
mi.cpp.type = QStringLiteral("qint64");
mi.cpp.fromVariantPost = QStringLiteral(".toLongLong()");
mi.cpp.fromJsonPost = QStringLiteral(".toDouble()");
mi.cpp.defaultValue = QLatin1Char('0');
}
else if (datatype == QLatin1String("boolean") ||
datatype == QLatin1String("bool"))
{
mi.cpp.type = QStringLiteral("bool");
mi.cpp.fromVariantPost = QStringLiteral(".toBool()");
mi.cpp.defaultValue = QStringLiteral("false");
}
else if (datatype == QLatin1String("bytea") ||
datatype == QLatin1String("QByteArray"))
{
mi.cpp.type = QStringLiteral("QByteArray");
mi.cpp.fromVariantPost = QStringLiteral(".toByteArray()");
mi.cpp.toJsonPre = QStringLiteral("QString::fromLatin1(");
mi.cpp.toJsonPost = QStringLiteral(".toBase64())");
mi.cpp.fromJsonPre2 = QStringLiteral("QByteArray::fromBase64(");
mi.cpp.fromJsonPost = QStringLiteral(".toString().toLatin1())");
mi.cpp.defaultValue.clear();
}
else if (datatype == QLatin1String("sequence<octet>"))
{
mi.cpp.type = QStringLiteral("QByteArray");
mi.cpp.ddsType = QStringLiteral("std::vector<uint8_t>");
mi.cpp.toVariantPre = QStringLiteral("octetSequenceToQVariant(");
mi.cpp.toVariantPost = QStringLiteral(")");
mi.cpp.fromVariantPre2 = QStringLiteral("qVariantToOctetSequence(");
mi.cpp.fromVariantPost = QStringLiteral(")");
mi.cpp.toJsonPre = QStringLiteral("toJson(");
mi.cpp.toJsonPost = QStringLiteral(")");
mi.cpp.fromJsonPre2 = QStringLiteral("fromJson<std::vector<uint8_t>>(");
mi.cpp.fromJsonPost = QStringLiteral(")");
mi.cpp.defaultValue.clear();
}
else if (datatype == QLatin1String("char"))
{
mi.cpp.type = QStringLiteral("char");
mi.cpp.fromVariantPost = QStringLiteral(".toChar().toLatin1()");
mi.cpp.fromJsonPost = QStringLiteral(".toInt()");
mi.cpp.defaultValue = QStringLiteral("\\0");
}
else if (datatype == QLatin1String("integer") ||
datatype == QLatin1String("qint32") ||
datatype == QLatin1String("long"))
{
mi.cpp.type = QStringLiteral("qint32");
mi.cpp.fromVariantPost = QStringLiteral(".toInt()");
mi.cpp.defaultValue = QLatin1Char('0');
}
else if (datatype == QLatin1String("real") ||
datatype == QLatin1String("double") ||
datatype == QLatin1String("double precision") ||
datatype == QLatin1String("float"))
{
mi.cpp.type = QStringLiteral("double");
mi.cpp.fromVariantPost = QStringLiteral(".toDouble()");
mi.cpp.defaultValue = QStringLiteral("0.0");
mi.db.datatype = QStringLiteral("double precision");
}
else if (datatype == QLatin1String("numeric") ||
datatype == QLatin1String("decimal"))
{
mi.cpp.type = QStringLiteral("double");
mi.cpp.fromVariantPost = QStringLiteral(".toDouble()");
mi.cpp.defaultValue = QStringLiteral("0.0");
mi.db.datatype = QStringLiteral("numeric");
}
else if (datatype == QLatin1String("smallint") ||
datatype == QLatin1String("qint16") ||
datatype == QLatin1String("short"))
{
mi.cpp.type = QStringLiteral("qint16");
mi.cpp.fromVariantPost = QStringLiteral(".toInt()");
mi.cpp.defaultValue = QLatin1Char('0');
}
else if (datatype == QLatin1String("text") ||
datatype == QLatin1String("QString"))
{
mi.cpp.type = QStringLiteral("QString");
mi.cpp.fromVariantPost = QStringLiteral(".toString()");
mi.cpp.defaultValue = QString();
}
else if (datatype == QLatin1String("json") ||
datatype == QLatin1String("jsonb"))
{
mi.cpp.type = QStringLiteral("QString");
mi.cpp.fromVariantPre2 = QStringLiteral("qVariantToJsonString(");
mi.cpp.fromVariantPost = QStringLiteral(")");
mi.cpp.fromJsonPre2 = QStringLiteral("jsonValueToJsonString(");
mi.cpp.fromJsonPost = QStringLiteral(")");
mi.cpp.toVariantPre = QStringLiteral("fixupEmptyJsonString(");
mi.cpp.toVariantPost = QStringLiteral(")");
mi.cpp.defaultValue = QStringLiteral("QLatin1String(\"{}\")");
}
else if (datatype.startsWith(QLatin1String("string")))
{
mi.cpp.type = QStringLiteral("std::string");
mi.cpp.toVariantPre = QStringLiteral("QString::fromStdString(");
mi.cpp.toVariantPost = QStringLiteral(")");
mi.cpp.fromVariantPost = QStringLiteral(".toString().toStdString()");
mi.cpp.fromJsonPre2 = QStringLiteral("fromJson<std::string>(");
mi.cpp.fromJsonPost = QStringLiteral(")");
}
else if (datatype == QLatin1String("timestamp") ||
datatype == QLatin1String("qdatetime"))
{
mi.db.datatype = QStringLiteral("bigint");
if (mi.db.defaultValue.toLower() == QStringLiteral("now()"))
mi.db.defaultValue = QStringLiteral("(extract(epoch from now()) * 1000)");
mi.cpp.type = QStringLiteral("QDateTime");
mi.cpp.fromVariantPre2 = QStringLiteral("NSqlQuery::qVariantToQDateTime(");
mi.cpp.fromVariantPost = QStringLiteral(")");
mi.cpp.toVariantPre = QStringLiteral("NSqlQuery::qDateTimeToQVariant(");
mi.cpp.toVariantPost = QStringLiteral(")");
mi.cpp.toJsonPre = QLatin1String("");
mi.cpp.toJsonPost = QStringLiteral(".toMSecsSinceEpoch()");
mi.cpp.fromJsonPre2 = QStringLiteral("QDateTime::fromMSecsSinceEpoch(");
mi.cpp.fromJsonPost = QStringLiteral(".toDouble())");
}
else if (datatype == QLatin1String("qvariant"))
{
}
else
{
ERROR_LOG(m_logger) << "Unknown cpp datatype: " << mi.cpp.type;
return false;
}
return true;
}
QVector<MemberInformation> StructBuilder::buildDbTableInformationFromIdlData(const CompleteTopicTypeInformation &ctti,
const QString &tableName,
const QString &columnNamePrefix,
const QString &cppStructure)
{
QVector<MemberInformation> ret;
if (!ctti.isValid())
return ret;
if (!ctti.baseValueType.isEmpty())
{
ret += buildDbTableInformationFromIdlData(topicTypeInformationByStructType(ctti.baseValueType),
tableName,
columnNamePrefix,
cppStructure);
}
for (const IdlData &member : ctti.members)
{
if (member.dataTypeInfo->isStructure() && !member.isOptional)
{
const CompleteTopicTypeInformation cttiChild = topicTypeInformationByStructType(member.type);
if (!cttiChild.isValid())
{
ERROR_LOG(m_logger) << "Can not find structure '" << member.type << "'";
continue;
}
QString pre;
if (!columnNamePrefix.isEmpty())
pre += columnNamePrefix;
pre += member.name + QLatin1Char('_');
ret += buildDbTableInformationFromIdlData(cttiChild,
tableName,
StructBuilder::camelCaseToUnderline(pre),
cppStructure + member.name + QStringLiteral("().")
);
continue;
}
if(member.dataTypeInfo->isSequence() && member.dataTypeInfo->innerDataType()->isStructure())
{
const CompleteTopicTypeInformation &cttiChild = topicTypeInformationByStructType(member.dataTypeInfo->innerDataType()->idlType());
if (!cttiChild.isValid())
{
ERROR_LOG(m_logger) << "Can not find structure '" << member.type << "'";
continue;
}
buildDbTableInformationFromIdlData(cttiChild,
tableName,
columnNamePrefix,
member.name
);
}
MemberInformation mi;
mi.isDdsKey = member.isKey;
mi.db.table = tableName;
mi.db.columnName = columnNamePrefix + StructBuilder::camelCaseToUnderline(member.name);
mi.db.datatype = member.dataTypeInfo->sqlType();
mi.db.usedForView = true;
mi.cpp.memberName = cppStructure + member.name;
mi.cpp.type = member.type;
mi.cpp.usedForCppStruct = true;
mi.cpp.isOptional = member.isOptional;
const EnumInformation ei = enumInformationByType(member.type, true, false);
if (ei.isValid())
mi.enumeration = QSharedPointer<EnumInformation>(new EnumInformation(ei));
if ((member.dataTypeInfo->isSequence() && member.dataTypeInfo->innerDataType()->idlType() != QLatin1String("octet")) ||
(member.dataTypeInfo->isStructure() && member.isOptional))
{
mi.db.datatype = QStringLiteral("jsonb");
mi.cpp.toJsonPre = QStringLiteral("toJson(");
mi.cpp.toJsonPost = QStringLiteral(")");
mi.cpp.type = member.dataTypeInfo->ddsType();
mi.cpp.fromVariantPre2 = QStringLiteral("fromJson<") + member.dataTypeInfo->ddsType() + QStringLiteral(">(");
mi.cpp.fromVariantPost = QStringLiteral(")");
if (member.dataTypeInfo->isSequence())
addToSerializeFromToJsonTopics(member.dataTypeInfo->innerDataType());
else
addToSerializeFromToJsonTopics(DataTypeInfo::fromIdlDataType(mi.cpp.memberName, member.type, this));
}
else
{
fixupCustomDbDatatypes(mi, ret);
fixupQVariantConversions(mi);
}
ret += mi;
}
return ret;
}
bool StructBuilder::buildJSonStructureInformationFromIdlData(const CompleteTopicTypeInformation &ctti)
{
if (!ctti.isValid())
return false;
if (m_jsonStructureInformation.contains(ctti.name))
return true;
if (!ctti.baseValueType.isEmpty())
{
if (!buildJSonStructureInformationFromIdlData(topicTypeInformationByStructType(ctti.baseValueType)))
return false;
}
QVector<MemberInformation> content;
content.reserve(ctti.members.size());
for (const IdlData &member : ctti.members)
{
MemberInformation mi;
mi.isDdsKey = member.isKey;
mi.db.table = ctti.name;
mi.db.columnName = StructBuilder::camelCaseToUnderline(member.name);
mi.db.datatype = member.dataTypeInfo->sqlType();
mi.db.usedForView = true;
mi.cpp.memberName = member.name;
mi.cpp.type = member.type;
mi.cpp.usedForCppStruct = true;
mi.cpp.isOptional = member.isOptional;
if (member.dataTypeInfo->isStructure())
{
const CompleteTopicTypeInformation cttiChild = topicTypeInformationByStructType(member.type);
if (!cttiChild.isValid())
{
ERROR_LOG(m_logger) << "Can not find structure '" << member.type << "'";
continue;
}
if (!buildJSonStructureInformationFromIdlData(cttiChild))
return false;
mi.cpp.toJsonPre = QStringLiteral("toJson(");
mi.cpp.toJsonPost = QStringLiteral(")");
mi.cpp.type = member.dataTypeInfo->ddsType();
mi.cpp.fromVariantPre2 = QStringLiteral("fromJson<") + member.dataTypeInfo->ddsType() + QStringLiteral(">(");
mi.cpp.fromVariantPost = QStringLiteral(")");
}
else if (member.dataTypeInfo->isSequence() &&
member.dataTypeInfo->innerDataType()->idlType() != QLatin1String("octet"))
{
auto inner = member.dataTypeInfo->innerDataType();
if (inner->isStructure())
{
const CompleteTopicTypeInformation cttiChild = topicTypeInformationByStructType(inner->idlType());
if (cttiChild.isValid())
{
if (!buildJSonStructureInformationFromIdlData(cttiChild))
return false;
}
else
WARNING_LOG(m_logger) << "Can not find structure '" << member.type << "'";
}
mi.db.datatype = QStringLiteral("jsonb");
mi.cpp.toJsonPre = QStringLiteral("toJson(");
mi.cpp.toJsonPost = QStringLiteral(")");
mi.cpp.type = member.dataTypeInfo->ddsType();
mi.cpp.fromVariantPre2 = QStringLiteral("fromJson<") + member.dataTypeInfo->ddsType() + QStringLiteral(">(");
mi.cpp.fromVariantPost = QStringLiteral(")");
}
else
{
const EnumInformation ei = enumInformationByType(member.type, true, false);
if (ei.isValid())
mi.enumeration = QSharedPointer<EnumInformation>(new EnumInformation(ei));
fixupCustomDbDatatypes(mi, content);
fixupQVariantConversions(mi);
}
content += mi;
}
m_jsonStructureInformation[ctti.name] = content;
return true;
}
CompleteTableInformation StructBuilder::completeTableInformation(const CompleteTopicTypeInformation &ctti)
{
CompleteTableInformation cti;
cti.structName = ctti.name;
cti.name = QStringLiteral("rec_") + camelCaseToUnderline(ctti.name);
cti.comment = QStringLiteral("recorded data for topic ") + ctti.name;
cti.columns = buildDbTableInformationFromIdlData(ctti, cti.name, QString(), QString());
buildJSonStructureInformationFromIdlData(ctti);
cti.exerciseDependency = ExerciseDependency::Exercise;
return cti;
}
MemberInformation StructBuilder::getRecordPrimaryKey() const
{
MemberInformation miPrimaryKey;
miPrimaryKey.db.isPrimaryKey = true;
miPrimaryKey.db.columnName = QStringLiteral("rec_id");
miPrimaryKey.db.datatype = QStringLiteral("bigint");
miPrimaryKey.db.hasSequence = true;
miPrimaryKey.db.sequenceStart = 1;
miPrimaryKey.db.sequenceIncrement = 1;
miPrimaryKey.db.usedForView = false;
miPrimaryKey.cpp.type = QStringLiteral("bigint");
miPrimaryKey.cpp.usedForCppStruct = false;
fixupQVariantConversions(miPrimaryKey);
return miPrimaryKey;
}
CompleteTableInformation StructBuilder::getRecordingTopicTable(const QString &structName)
{
const auto vec = structName.contains(QLatin1String("::")) ? m_externalTopicTypes : m_topicTypeInfos;
for (const CompleteTopicTypeInformation &ctti : qAsConst(vec))
{
if (structName != ctti.name)
continue;
MemberInformation miPrimaryKey(getRecordPrimaryKey());
miPrimaryKey.db.table = ctti.name;
return getRecordingTopicTable(ctti, getRecordPrimaryKey());
}
return CompleteTableInformation();
}
CompleteTableInformation StructBuilder::getRecordingTopicTable(const CompleteTopicTypeInformation &ctti,
const MemberInformation &miPrimaryKey)
{
CompleteTableInformation cti = completeTableInformation(ctti);
cti.columns.push_back(miPrimaryKey);
return cti;
}
QMap<QString, CompleteTableInformation> StructBuilder::getRecordingTopicTables()
{
QMap<QString, CompleteTableInformation> ret;
MemberInformation miPrimaryKey(getRecordPrimaryKey());
for (const CompleteTopicTypeInformation &ctti : qAsConst(m_topicTypeInfos))
{
if (!ctti.recordTopic)
continue;
if (!ctti.isDataObject)
{
WARNING_LOG(m_logger) << "Trying to record topic '" << ctti.name
<< "' which is not directly published - ignoring!";
continue;
}
DEBUG_LOG(m_logger) << "Rec table: " << ctti.name;
miPrimaryKey.db.table = ctti.name;
ret.insert(ctti.name, getRecordingTopicTable(ctti, miPrimaryKey));
}
return ret;
}
void StructBuilder::addToSerializeFromToJsonTopics(const QSharedPointer<DataTypeInfo> &toAdd)
{
typedef QSharedPointer<DataTypeInfo> sDTI;
for (const sDTI &dti : qAsConst(m_serializeFromToJsonTopics))
{
if (dti->cppType() == toAdd->cppType())
return;
}
m_serializeFromToJsonTopics += toAdd;
}
QVector<QSharedPointer<DataTypeInfo>> StructBuilder::getSerializeFromToJsonTopics() const
{
return m_serializeFromToJsonTopics;
}
QString StructBuilder::firstCharLowercase(const QString &txt)
{
QString ret = txt;
if (txt.isEmpty())
return ret;
ret[0] = ret[0].toLower();
return ret;
}
QString StructBuilder::camelCaseString(const QString &in, bool bFirstUppercase)
{
Q_DECL_CONSTEXPR const QChar s_underline(QLatin1Char('_'));
QString out;
out.reserve(in.size());
bool bNextIsUpperCase = bFirstUppercase;
for (const auto c : in)
{
if (c == s_underline)
bNextIsUpperCase = true;
else
{
out += (bNextIsUpperCase ? c.toUpper() : c);
bNextIsUpperCase = false;
}
}
return out;
}
QString StructBuilder::camelCaseToUnderline(const QString &in)
{
QString out;
if (in.isEmpty())
return out;
out.reserve(in.size());
out += in.at(0).toLower();
for (int i = 1; i < in.size(); ++i)
{
const QChar c = in.at(i);
if (!c.isLetter() || c.isLower())
out += c;
else
out += QLatin1Char('_') + c.toLower();
}
return out;
}
StructBuilder::ServiceTypeStruct StructBuilder::extractServiceAndTypeFromTypename(const QString &type)
{
const QVector<QStringRef> sl = type.splitRef(QStringLiteral("::"));
QStringRef extServiceRef;;
QStringRef extTypeRef;
if (sl.size() == 1)
extTypeRef = sl.at(0);
else if (sl.size() == 2)
{
extServiceRef = sl.at(0);
extTypeRef = sl.at(1);
}
else
WARNING_LOG(m_logger) << "Error parsing type: " << type;
StructBuilder::ServiceTypeStruct ret;
if (!extServiceRef.isEmpty())
{
if (extServiceRef.contains(QLatin1Char('<')))
ret.service = extServiceRef.split(QLatin1Char('<')).at(1).toString();
else
ret.service = extServiceRef.toString();
}
if (!extTypeRef.isEmpty())
{
if (extTypeRef.contains(QLatin1Char('>')))
ret.type = extTypeRef.split(QLatin1Char('>')).at(0).toString();
else
ret.type = extTypeRef.toString();
}
return ret;
}
void StructBuilder::addToSqlTableInformation(const MemberInformation &mi)
{
if (!m_sqlTableInformationsAlreadyAvailable.contains(mi.db.table))
m_sqlTableInformations[mi.db.table].columns.append(mi);
}