commit d27d606ded8e08d3f6f6d123516252baf5d1eb6d
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Sun Dec 6 18:44:22 2015 +0100

    created attribute resolver

diff --git a/src/attribute.cpp b/src/attribute.cpp
index 6881892..1686f64 100644
--- a/src/attribute.cpp
+++ b/src/attribute.cpp
@@ -1,15 +1,21 @@
 #include "attribute.h"
+#include "entityhelper.h"
 using namespace CuteEntityManager;
 
 Attribute::Attribute(QString name, QString columnName, QString tableName,
-                     QMetaObject *metaObj, QString relatedTable, QMetaObject *relatedClass,
-                     QString conjunctedTable) {
+                     const QMetaObject *metaObj, QString relatedTable, const QMetaObject *relatedClass,
+                     QString conjunctedTable,  QString relatedColumnName, QString baseTableName,
+                     const QMetaObject *baseMetaObj) {
     this->name = name;
+    this->columnName = columnName;
     this->tableName = tableName;
     this->metaObj = metaObj;
     this->relatedTable = relatedTable;
     this->relatedClass = relatedClass;
     this->conjunctedTable = conjunctedTable;
+    this->relatedColumnName = relatedColumnName;
+    this->baseMetaObj = baseMetaObj;
+    this->baseTableName = baseTableName;
 }
 
 QString Attribute::getName() const {
@@ -44,14 +50,6 @@ void Attribute::setRelatedTable(const QString &value) {
     relatedTable = value;
 }
 
-QMetaObject *Attribute::getRelatedClass() const {
-    return relatedClass;
-}
-
-void Attribute::setRelatedClass(QMetaObject *value) {
-    relatedClass = value;
-}
-
 QString Attribute::getConjunctedTable() const {
     return conjunctedTable;
 }
@@ -60,11 +58,61 @@ void Attribute::setConjunctedTable(const QString &value) {
     conjunctedTable = value;
 }
 
-QMetaObject *Attribute::getMetaObj() const {
+QString Attribute::getBaseTableName() const {
+    return baseTableName;
+}
+
+void Attribute::setBaseTableName(const QString &value) {
+    baseTableName = value;
+}
+
+void Attribute::setInheritance(const QString &baseTableName,
+                               const QMetaObject *baseMetaObj) {
+    this->baseTableName = baseTableName;
+    this->baseMetaObj = baseMetaObj;
+}
+
+void Attribute::setRelation(const QString &tableName, const QMetaObject *relatedMetaObj,
+                            const QString &conjunctedTable, const QString &relatedColumnName) {
+    this->relatedTable = tableName;
+    this->relatedClass = relatedMetaObj;
+    this->conjunctedTable = conjunctedTable;
+    this->relatedColumnName = relatedColumnName;
+}
+
+const QMetaProperty Attribute::getMetaProperty() {
+    return EntityHelper::getMetaProperties(this->getMetaObj()).value(this->getName());
+}
+
+const QMetaObject *Attribute::getMetaObj() const {
     return metaObj;
 }
 
-void Attribute::setMetaObj(QMetaObject *value) {
+void Attribute::setMetaObj(const QMetaObject *value) {
     metaObj = value;
 }
 
+const QMetaObject *Attribute::getBaseMetaObj() const {
+    return baseMetaObj;
+}
+
+void Attribute::setBaseMetaObj(const QMetaObject *value) {
+    baseMetaObj = value;
+}
+
+const QMetaObject *Attribute::getRelatedClass() const {
+    return relatedClass;
+}
+
+void Attribute::setRelatedClass(const QMetaObject *value) {
+    relatedClass = value;
+}
+
+QString Attribute::getRelatedColumnName() const {
+    return relatedColumnName;
+}
+
+void Attribute::setRelatedColumnName(const QString &value) {
+    relatedColumnName = value;
+}
+
diff --git a/src/attribute.h b/src/attribute.h
index c664b31..5cba1ed 100644
--- a/src/attribute.h
+++ b/src/attribute.h
@@ -1,14 +1,14 @@
 #ifndef ATTRIBUTE_H
 #define ATTRIBUTE_H
 #include <QString>
+#include <QMetaObject>
 namespace CuteEntityManager {
-
-
 class Attribute {
   public:
-    Attribute(QString name, QString columnName, QString tableName, QMetaObject *metaObj,
-              QString relatedTable = "", QMetaObject *relatedClass = nullptr,
-              QString conjunctedTable = "");
+    Attribute(QString name, QString columnName, QString tableName, const QMetaObject *metaObj,
+              QString relatedTable = "", const QMetaObject *relatedClass = nullptr,
+              QString conjunctedTable = "", QString relatedColumnName = "", QString baseTableName = "",
+              const QMetaObject *baseMetaObj = nullptr);
     QString getName() const;
     void setName(const QString &value);
 
@@ -21,22 +21,37 @@ class Attribute {
     QString getRelatedTable() const;
     void setRelatedTable(const QString &value);
 
-    QMetaObject *getRelatedClass() const;
-    void setRelatedClass(QMetaObject *value);
-
     QString getConjunctedTable() const;
     void setConjunctedTable(const QString &value);
 
-    QMetaObject *getMetaObj() const;
-    void setMetaObj(QMetaObject *value);
+    QString getBaseTableName() const;
+    void setBaseTableName(const QString &value);
+    void setInheritance(const QString &baseTableName, const QMetaObject *baseMetaObj);
+    void setRelation(const QString &tableName, const QMetaObject *relatedMetaObj,
+                     const QString &conjunctedTable = "", const QString &relatedColumnName = "");
+    const QMetaProperty getMetaProperty();
+    const QMetaObject *getMetaObj() const;
+    void setMetaObj(const QMetaObject *value);
+
+    const QMetaObject *getBaseMetaObj() const;
+    void setBaseMetaObj(const QMetaObject *value);
+
+    const QMetaObject *getRelatedClass() const;
+    void setRelatedClass(const QMetaObject *value);
+
+    QString getRelatedColumnName() const;
+    void setRelatedColumnName(const QString &value);
 
   private:
     QString name;
     QString columnName;
     QString tableName;
-    QMetaObject *metaObj;
+    const QMetaObject *metaObj;
+    QString baseTableName;
+    const QMetaObject *baseMetaObj;
     QString relatedTable;
-    QMetaObject *relatedClass;
+    const QMetaObject *relatedClass;
+    QString relatedColumnName;
     QString conjunctedTable;
 };
 }
diff --git a/src/attributeresolver.cpp b/src/attributeresolver.cpp
new file mode 100644
index 0000000..8d147ef
--- /dev/null
+++ b/src/attributeresolver.cpp
@@ -0,0 +1,146 @@
+#include "attributeresolver.h"
+#include "entityhelper.h"
+#include "querybuilder.h"
+using namespace CuteEntityManager;
+
+AttributeResolver::AttributeResolver(QSharedPointer<QueryBuilder> queryBuilder) {
+    this->qb = queryBuilder;
+}
+
+AttributeResolver::~AttributeResolver() {
+    this->qb = QSharedPointer<QueryBuilder>(nullptr);
+    if(!this->attributes.isEmpty()) {
+        QMutableHashIterator<QString, QHash<QString, Attribute*>> i(this->attributes);
+        while(i.hasNext()) {
+            i.next();
+            auto embeddedHash = i.value();
+            QMutableHashIterator<QString, Attribute*> i2(embeddedHash);
+            while(i2.hasNext()) {
+                i2.next();
+                auto attr = i2.value();
+                delete attr;
+                i2.remove();
+            }
+            i.remove();
+        }
+    }
+}
+
+QHash<QString, QHash<QString, Attribute *>> AttributeResolver::getAttributes() const {
+    return attributes;
+}
+
+void AttributeResolver::setAttributes(const QHash<QString, QHash<QString, Attribute*>>
+                                      &value) {
+    attributes = value;
+}
+
+Attribute *AttributeResolver::resolveManyToManyAttribute(const QSharedPointer<Entity> &e,
+        const QString &attr, const Relation &r, const QSharedPointer<Entity> &target) {
+    auto ptr = e;
+    QString attributeName = r.getPropertyName();
+    if (!r.getMappedBy().isEmpty()) {
+        ptr = target;
+        attributeName = r.getMappedBy();
+    }
+    auto obj = EntityHelper::getBaseClassObject(ptr, attributeName);
+    Attribute *attrObj = new Attribute(attr,
+                                       this->qb->generateColumnNameID(obj->getTablename()),
+                                       e->getTablename(), e->metaObject());
+    this->resolveInheritance(e, attrObj);
+    attrObj->setRelation(target->getTablename(), target->metaObject(),
+                         this->qb->generateManyToManyTableName(obj->getTablename(), attributeName),
+                         this->qb->generateColumnNameID(target->getTablename()));
+    delete obj;
+    return attrObj;
+}
+
+Attribute *AttributeResolver::resolveManyToOneAttribute(const QSharedPointer<Entity> &e,
+        const QString &attr, const Relation &r, const QSharedPointer<Entity> &target) {
+    Q_UNUSED(r);
+    auto obj = EntityHelper::getBaseClassObject(e, attr);
+    Attribute *attrObj = new Attribute(attr,
+                                       this->qb->generateColumnNameID(attr),
+                                       e->getTablename(), e->metaObject());
+    this->resolveInheritance(e, attrObj);
+    attrObj->setRelation(target->getTablename(), target->metaObject(), "", "id");
+    delete obj;
+    return attrObj;
+}
+
+Attribute *AttributeResolver::resolveOneToManyAttribute(const QSharedPointer<Entity> &e,
+        const QString &attr, const Relation &r, const QSharedPointer<Entity> &target) {
+    auto obj = EntityHelper::getBaseClassObject(e, attr);
+    Attribute *attrObj = new Attribute(attr, "id",
+                                       e->getTablename(), e->metaObject());
+    this->resolveInheritance(e, attrObj);
+    attrObj->setRelation(target->getTablename(), target->metaObject(), "",
+                         this->qb->generateColumnNameID(r.getMappedBy()));
+    delete obj;
+    return attrObj;
+}
+
+Attribute *AttributeResolver::resolveNonRelatedAttribute(const QSharedPointer<Entity> &e,
+        const QString &attr) {
+    Attribute *obj = new Attribute(attr, attr, e->getTablename(), e->metaObject());
+    this->resolveInheritance(e, obj);
+    return obj;
+}
+
+const QMetaObject *AttributeResolver::resolveInheritance(const QSharedPointer<Entity> &e,
+        Attribute *&attribute) {
+    auto obj = EntityHelper::getBaseClassObject(e, attribute->getName());
+    if(obj && obj->getTablename() != e->getTablename()) {
+        attribute->setInheritance(obj->getTablename(), obj->metaObject());
+    }
+    return obj->metaObject();
+}
+
+void AttributeResolver::addAttribute(const QString &className, Attribute *&attr) {
+    auto attrs = this->attributes.value(className);
+    attrs.insert(attr->getName(), attr);
+    this->attributes.insert(className, attrs);
+}
+
+Attribute *AttributeResolver::resolveExplicitAttribute(const QSharedPointer<Entity>
+        &classObj, const QString &attribute, QSharedPointer<Entity> related) {
+    Attribute* a = nullptr;
+    if(classObj->getRelations().contains(attribute)) {
+        auto relation = classObj->getRelations().value(attribute);
+        if(relation.getType() == RelationType::MANY_TO_MANY) {
+            a = this->resolveManyToManyAttribute(classObj, attribute, relation, related);
+        } else if(relation.getType() == RelationType::MANY_TO_ONE ||
+                  (relation.getType() == RelationType::ONE_TO_ONE && relation.getMappedBy().isEmpty())) {
+            a = this->resolveManyToOneAttribute(classObj, attribute, relation, related);
+        } else {
+            a = this->resolveOneToManyAttribute(classObj, attribute, relation, related);
+        }
+    } else {
+        a = this->resolveNonRelatedAttribute(classObj, attribute);
+    }
+    return a;
+}
+
+bool AttributeResolver::containsAttribute(const QString &className,
+        const QString &attribute) const {
+    bool r = false;
+    auto attributes = this->getAttributes();
+    if(!this->attributes.isEmpty() && attributes.contains(className) &&
+            !attributes.value(className).isEmpty() &&
+            attributes.value(className).contains(attribute)) {
+        r = true;
+    }
+    return r;
+}
+
+Attribute *AttributeResolver::resolveAttribute(const QSharedPointer<Entity> &classObj,
+        const QString &attribute, QSharedPointer<Entity> related) {
+    Attribute *attr = nullptr;
+    if(this->containsAttribute(classObj->getClassname(), attribute)) {
+        attr = this->attributes.value(classObj->getClassname()).value(attribute);
+    } else {
+        attr = this->resolveExplicitAttribute(classObj, attribute, related);
+        this->addAttribute(classObj->getClassname(), attr);
+    }
+    return attr;
+}
diff --git a/src/attributeresolver.h b/src/attributeresolver.h
new file mode 100644
index 0000000..73c2a07
--- /dev/null
+++ b/src/attributeresolver.h
@@ -0,0 +1,38 @@
+#ifndef ATTRIBUTERESOLVER_H
+#define ATTRIBUTERESOLVER_H
+#include <QHash>
+#include <QString>
+#include "attribute.h"
+#include "entity.h"
+namespace CuteEntityManager {
+class QueryBuilder;
+class AttributeResolver {
+  public:
+    AttributeResolver(QSharedPointer<QueryBuilder> queryBuilder);
+    virtual ~AttributeResolver();
+    bool containsAttribute(const QString &className, const QString &attribute) const;
+    Attribute* resolveAttribute(const QSharedPointer<Entity> &classObj,
+                                const QString &attribute, QSharedPointer<Entity> related = QSharedPointer<Entity>());
+    QHash<QString, QHash<QString, Attribute *>> getAttributes() const;
+    void setAttributes(const QHash<QString, QHash<QString, Attribute *>> &value);
+  protected:
+    Attribute* resolveManyToManyAttribute(const QSharedPointer<Entity> &e,
+                                          const QString &attr, const Relation &r, const QSharedPointer<Entity> &target);
+    Attribute* resolveManyToOneAttribute(const QSharedPointer<Entity> &e, const QString &attr,
+                                         const Relation &r, const QSharedPointer<Entity> &target);
+    Attribute* resolveOneToManyAttribute(const QSharedPointer<Entity> &e, const QString &attr,
+                                         const Relation &r, const QSharedPointer<Entity> &target);
+    Attribute* resolveNonRelatedAttribute(const QSharedPointer<Entity> &e,
+                                          const QString &attr);
+    const QMetaObject *resolveInheritance(const QSharedPointer<Entity> &e,Attribute *&attribute);
+    void addAttribute(const QString &className, Attribute *&attr);
+    Attribute* resolveExplicitAttribute(const QSharedPointer<Entity> &classObj,
+                                        const QString &attribute, QSharedPointer<Entity> related = QSharedPointer<Entity>());
+
+  private:
+    QSharedPointer<QueryBuilder> qb;
+    QHash<QString, QHash<QString, Attribute*>> attributes;
+};
+}
+
+#endif // ATTRIBUTERESOLVER_H
diff --git a/src/entitymanager.cpp b/src/entitymanager.cpp
index 4017784..a85429e 100644
--- a/src/entitymanager.cpp
+++ b/src/entitymanager.cpp
@@ -580,8 +580,8 @@ void EntityManager::persistMappedByRelation(const QList<QSharedPointer<Entity>>
     this->db->startTransaction();
     auto builder = this->schema->getQueryBuilder();
     q = builder->manyToManyInsert(tblName,
-                                  builder->generateManyToManyColumnName(entity,r.getPropertyName()),
-                                  builder->generateManyToManyColumnName(ptr,r.getMappedBy()));
+                                  builder->generateManyToManyColumnName(entity, r.getPropertyName()),
+                                  builder->generateManyToManyColumnName(ptr, r.getMappedBy()));
     q.bindValue(0, entity->getProperty(entity->getPrimaryKey()));
     auto prop = EntityHelper::mappedProperty(r, ptr);
     QSharedPointer<Entity> item;
@@ -733,7 +733,7 @@ void EntityManager::removeManyToManyEntityList(const QSharedPointer<Entity> &e,
             QString tblName = builder->generateManyToManyTableName(e, ptr, r);
             if (this->schema->getTables().contains(tblName)) {
                 QSqlQuery q = builder->manyToManyDelete(
-                                  tblName, builder->generateManyToManyColumnName(e,r.getPropertyName()),
+                                  tblName, builder->generateManyToManyColumnName(e, r.getPropertyName()),
                                   e->getProperty(e->getPrimaryKey()).toLongLong());
                 if (this->db->exec(q)) {
                     bool refresh = r.getCascadeType().contains(CascadeType::REFRESH)
@@ -786,7 +786,7 @@ void EntityManager::persistManyToMany(const QSharedPointer<Entity> &entity,
               * @todo diff and remove entity from relational object when association is deleted
               */
             q = builder->manyToManyDelete(
-                    tblName, builder->generateManyToManyColumnName(entity,r.getPropertyName()),
+                    tblName, builder->generateManyToManyColumnName(entity, r.getPropertyName()),
                     entity->getProperty(entity->getPrimaryKey()).toLongLong());
             ok = this->db->exec(q);
         } else {
@@ -825,13 +825,14 @@ void EntityManager::manyToMany(const QSharedPointer<Entity> &entity,
                           relation);
         if (this->schema->getTables().contains(tblName)) {
             QSqlQuery q = builder->manyToMany(tblName,
-                                              builder->generateManyToManyColumnName(entity,relation.getPropertyName()),
+                                              builder->generateManyToManyColumnName(entity, relation.getPropertyName()),
                                               entity->getProperty(entity->getPrimaryKey()).toLongLong());
             auto listMap = this->convertQueryResult(q);
             auto secClassName = EntityHelper::getClassName(secEntityPtr.data());
             QSharedPointer<Entity> e;
             for (int var = 0; var < listMap.size(); ++var) {
-                auto id = listMap.at(var).value(builder->generateManyToManyColumnName(secEntityPtr,relation.getMappedBy()));
+                auto id = listMap.at(var).value(builder->generateManyToManyColumnName(secEntityPtr,
+                                                relation.getMappedBy()));
                 if (refresh || !(this->cache.contains(id.toLongLong(), secClassName) &&
                                  (e = this->cache.get(id.toLongLong(), secClassName)))) {
                     e = this->findById(id.toLongLong(), secClassName);
diff --git a/src/entitymanager.h b/src/entitymanager.h
index ce7ac75..4b43f15 100644
--- a/src/entitymanager.h
+++ b/src/entitymanager.h
@@ -34,6 +34,7 @@
 #include "cache.h"
 #include "querybuilder.h"
 #include "validators/errormsg.h"
+#include "attribute.h"
 namespace CuteEntityManager {
 #ifdef QT_DEBUG
 #define DEFAULTMSGTYPE MsgType::DEBUG
@@ -279,7 +280,7 @@ class EntityManager : public QObject {
         return newList;
     }
 
-  protected:
+protected:
     bool saveObject(QSharedPointer<Entity> &entity, QList<Entity *> &mergedObjects,
                     const bool persistRelations = true,
                     const bool ignoreHasChanged = false, const bool validate = true,
diff --git a/src/querybuilder.cpp b/src/querybuilder.cpp
index 5fb8634..1c454d2 100644
--- a/src/querybuilder.cpp
+++ b/src/querybuilder.cpp
@@ -434,11 +434,16 @@ QString QueryBuilder::generateManyToManyTableName(const QSharedPointer<Entity>
         attributeName = r.getMappedBy();
     }
     auto obj = EntityHelper::getBaseClassObject(ptr, attributeName);
-    QString tblName = obj->getTablename() + "_" + attributeName;
+    QString tblName = this->generateManyToManyTableName(obj->getTablename(), attributeName);
     delete obj;
     return tblName;
 }
 
+QString QueryBuilder::generateManyToManyTableName(const QString &tableName,
+        const QString &attribute) const {
+    return tableName + "_" + attribute;
+}
+
 QHash<QString, QHash<QString, QString>> QueryBuilder::generateRelationTables(
 const QSharedPointer<Entity> &entity) const {
     auto relations = QHash<QString, QHash<QString, QString>>();
diff --git a/src/querybuilder.h b/src/querybuilder.h
index 9741e90..4d9ba13 100644
--- a/src/querybuilder.h
+++ b/src/querybuilder.h
@@ -44,6 +44,7 @@ class QueryBuilder {
      */
     friend class EntityManager;
     friend class QueryInterpreter;
+    friend class AttributeResolver;
   public:
     QueryBuilder(Schema *schema, QSharedPointer<Database> &database);
     virtual ~QueryBuilder();
@@ -258,7 +259,10 @@ class QueryBuilder {
             const QSharedPointer<Entity> &entity) const;
     QString generateManyToManyTableName(const QSharedPointer<Entity> &firstEntity,
                                         const QSharedPointer<Entity> &secondEntity, const Relation &r) const;
-    QString generateManyToManyColumnName(const QSharedPointer<Entity> &entity, QString attribute) const;
+    QString generateManyToManyTableName(const QString &tableName,
+                                        const QString &attribute) const;
+    QString generateManyToManyColumnName(const QSharedPointer<Entity> &entity,
+                                         QString attribute) const;
     QString buildCreateQuery(QHash<QString, QVariant>::const_iterator i,
                              QHash<QString, QVariant>::const_iterator end,
                              QString &p1, QString &p2) const;
diff --git a/src/src.pro b/src/src.pro
index 9e0d919..ade82e6 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -54,7 +54,8 @@ entity.h \
     schema/mysqlquerybuilder.h \
     entityinspector.h \
     sqlitebackupprocessor.h \
-    attribute.h
+    attribute.h \
+    attributeresolver.h
 
 SOURCES += \
 entity.cpp \
@@ -99,7 +100,8 @@ entity.cpp \
     schema/mysqlquerybuilder.cpp \
     entityinspector.cpp \
     sqlitebackupprocessor.cpp \
-    attribute.cpp
+    attribute.cpp \
+    attributeresolver.cpp
 
 win32:!system-sqlite:!contains(LIBS, .*sqlite3.*) {
     include($$[QT_INSTALL_PREFIX]/../Src/qtbase/src/3rdparty/sqlite.pri)
