1432 lines
49 KiB
C++
Executable File
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);
|
|
}
|