commit ba800d6dc2d5c0b94f95e45291d664ecdca0e244
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Sun Apr 26 00:04:19 2015 +0200

    wip

diff --git a/src/entity.cpp b/src/entity.cpp
index 08c9f1c..f7f3b4b 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -27,6 +27,7 @@ QString Entity::toString() {
 }
 
 Entity::~Entity() {
+
 }
 
 QString Entity::getTablename() {
@@ -57,7 +58,7 @@ QHash<QString, QMetaProperty> Entity::getMetaProperties() {
     QHash<QString, QMetaProperty> h = QHash<QString, QMetaProperty>();
     for (int var = 0; var < this->metaObject()->propertyCount(); ++var) {
         QMetaProperty m = this->metaObject()->property(var);
-        if (m.name() != QString("objectName")) {
+        if (m.name() != QString("objectName") && m.isValid()) {
             h.insert(m.name(), m);
         }
     }
diff --git a/src/entity.h b/src/entity.h
index a682c98..8618d89 100644
--- a/src/entity.h
+++ b/src/entity.h
@@ -27,7 +27,7 @@
 namespace CuteEntityManager {
 
 /**
- * You should name any persisted property objectName, because its pre used by Qt and will be ignored by Entity Manager
+ * You mustn't name any persisted property objectName, because its pre used by Qt and will be ignored by Entity Manager
  * @brief The Entity class
  */
 class Entity : public QObject {
@@ -51,7 +51,7 @@ class Entity : public QObject {
     /**
      * The hashmap keys must be equal to the ones which are defined in the hashmap of getRelations()
      * The EntityManager will only introspect Entity Objects, non-Entity inherited relations will be processed in a other way
-     * You must use this method, if you have a n-n Relation with Entity Objects.
+     * You must use this method, if you have a n-m Relation with Entity Objects.
      * @brief getRelationObjects
      * @return
      */
diff --git a/src/querybuilder.cpp b/src/querybuilder.cpp
index f952fc6..c248d4e 100644
--- a/src/querybuilder.cpp
+++ b/src/querybuilder.cpp
@@ -151,7 +151,7 @@ QHash<QString, QString> QueryBuilder::generateTableDefinition(const QSharedPoint
                 map.insert(m.name(), this->schema.data()->getTypeMap().data()->value(this->schema.data()->TYPE_INTEGER));
             } else if (relations.contains(m.name())) {
                 Relation r = relations.value(m.name());
-                if (r.getType() == RelationType::BELONGS_TO) {
+                if (r.getType() == RelationType::MANY_TO_ONE) {
                     map.insert(QString(m.name()) + "_id", this->schema.data()->TYPE_BIGINT);
                 }
             } else if (entity.data()->getBLOBColumns().contains(m.name())) {
@@ -170,19 +170,31 @@ QHash<QString, QString> QueryBuilder::generateTableDefinition(const QSharedPoint
     return map;
 }
 
-QList<QHash<QString, QString>> QueryBuilder::generateRelationTables(const QSharedPointer<Entity> &entity) const {
-    QList<QHash<QString, QString>> relations = QList<QHash<QString, QString>>();
+QString QueryBuilder::generateManyToManyTableName(const QSharedPointer<Entity> &firstEntity,
+        const QSharedPointer<Entity> &secondEntity) const {
+    return QString(firstEntity.data()->metaObject()->className()).toLower() + "_" + QString(
+               secondEntity.data()->metaObject()->className()).toLower();
+}
+
+QHash<QString, QHash<QString, QString>> QueryBuilder::generateRelationTables(const QSharedPointer<Entity> &entity)
+const {
+    auto relations = QHash<QString, QHash<QString, QString>>();
     QHash<QString, Relation> m = entity.data()->getRelations();
     QHash<QString, QSharedPointer<Entity>> os = entity.data()->getRelationObjects();
-    for(auto i = m.begin(); i != m.end(); ++i) {
+    for (auto i = m.begin(); i != m.end(); ++i) {
         Relation r = i.value();
-        if(r.getType() == HAS_MANY) {
+        if (r.getType() == MANY_TO_MANY && r.getMappedBy().isEmpty()) {
             QHash<QString, QString> h = QHash<QString, QString>();
-            h.insert("id",this->schema.data()->TYPE_BIGPK);
-            h.insert(QString(entity.data()->metaObject()->className())+ QString("_id"), this->schema.data()->TYPE_BIGINT);
-            if(os.contains(i.key())) {
-            h.insert(QString(os.value(i.key()).data()->metaObject()->className())+ QString("_id"),this->schema.data()->TYPE_BIGINT);
-            relations.append(h);
+            h.insert("id", this->schema.data()->TYPE_BIGPK);
+            h.insert(QString(entity.data()->metaObject()->className()) + QString("_id"), this->schema.data()->TYPE_BIGINT);
+            if (os.contains(i.key())) {
+                h.insert(QString(os.value(i.key()).data()->metaObject()->className()) + QString("_id"),
+                         this->schema.data()->TYPE_BIGINT);
+                if (r.getTableName().isEmpty()) {
+                    relations.insert(this->generateManyToManyTableName(entity, os.value(i.key())), h);
+                } else {
+                    relations.insert(r.getTableName(), h);
+                }
             }
         }
     }
@@ -241,41 +253,46 @@ QString QueryBuilder::getColumnType(const QString &type) const {
     return type;
 }
 
-QHash<QString, QVariant> QueryBuilder::getEntityAttributes(const QSharedPointer<Entity> &entity) {
+QHash<QString, QVariant> QueryBuilder::getEntityAttributes(const QHash<QString, QMetaProperty> &props,
+        const QSharedPointer<Entity> &entity) {
     Entity *e = entity.data();
     auto map = QHash<QString, QVariant>();
-    auto metaObject = e->metaObject();
     auto transientAttrs = e->getTransientAttributes();
-    for (int var = 0; var < metaObject->propertyCount(); ++var) {
-        auto p = metaObject->property(var);
-        QString name = QString(p.name());
-        if (p.isValid() && !transientAttrs.contains(name) && name != QString("objectName")) {
-            QVariant v = p.read(e);
-            //Relation
+    auto relations = e->getRelations();
+    auto i = props.constBegin();
+    while (i != props.constEnd()) {
+        if (!transientAttrs.contains(i.key()) && !relations.contains(i.key())) {
+            map.insert(i.key(), i.value().read(e));
+        }
+        ++i;
+    }
+    return map;
+}
+
+QHash<QString, QVariant> QueryBuilder::getManyToOneAttributes(const QHash<QString, QMetaProperty> &props,
+        const QSharedPointer<Entity> &entity) {
+    Entity *e = entity.data();
+    auto map = QHash<QString, QVariant>();
+    auto relations = e->getRelations();
+    auto i = relations.constBegin();
+    while (i != relations.constEnd()) {
+        Relation r = i.value();
+        if (r.getType() == MANY_TO_ONE && props.contains(i.key())) {
+            auto v = props.value(i.key()).read(e);
             if (v.canConvert<Entity *>()) {
-                this->insertRelationId(qvariant_cast<Entity *>(v), map, name);
+                this->insertRelationId(qvariant_cast<Entity *>(v), map, i.key());
             } else if (v.canConvert<QSharedPointer<Entity>>()) {
-                this->insertRelationId(qvariant_cast<QSharedPointer<Entity>>(v).data(), map, name);
+                this->insertRelationId(qvariant_cast<QSharedPointer<Entity>>(v).data(), map, i.key());
             } else if (v.canConvert<QPointer<Entity>>()) {
-                this->insertRelationId(qvariant_cast<QPointer<Entity>>(v).data(), map, name);
-            } else if (QString(p.typeName()).contains("QList")) {
-                /**
-                  @TODO
-                  //List and/or ManyToManyRelation
-                  */
-                auto n = static_cast<QList<CuteEntityManager::Entity *>*>(v.data());
-                for (int var = 0; var < n->size(); ++var) {
-                    CuteEntityManager::Entity *entity = n->at(var);
-                    qDebug() << entity->toString();
-                }
-            } else {
-                map.insert(name, v);
+                this->insertRelationId(qvariant_cast<QPointer<Entity>>(v).data(), map, i.key());
             }
+            ++i;
         }
     }
     return map;
 }
 
+
 void QueryBuilder::insertRelationId(const Entity *e, QHash<QString, QVariant> &map, QString relName) {
     if (e && e->getId() > -1) {
         map.insert(relName + "_id", e->getId());
@@ -296,6 +313,8 @@ QString QueryBuilder::buildColumns(const QStringList &columns) const {
     return r;
 }
 
+
+
 QSharedPointer<Schema> QueryBuilder::getSchema() const {
     return schema;
 }
@@ -303,4 +322,3 @@ QSharedPointer<Schema> QueryBuilder::getSchema() const {
 void QueryBuilder::setSchema(const QSharedPointer<Schema> &value) {
     schema = value;
 }
-
diff --git a/src/querybuilder.h b/src/querybuilder.h
index 801f1f1..f81ae05 100644
--- a/src/querybuilder.h
+++ b/src/querybuilder.h
@@ -29,14 +29,18 @@ class QueryBuilder {
     virtual QString dropForeignKey(QString name, QString tableName) const;
     virtual QString createIndex(QString name, QString tableName, QStringList columns, bool unique)const;
     virtual QString dropIndex(QString name, QString tableName)const;
-    QHash<QString, QVariant> getEntityAttributes(const QSharedPointer<Entity> &entity);
+    QHash<QString, QVariant> getEntityAttributes(const QHash<QString, QMetaProperty> &props,
+            const QSharedPointer<Entity> &entity);
+
     QSharedPointer<Schema> getSchema() const;
     void setSchema(const QSharedPointer<Schema> &value);
 
     QSharedPointer<Database> getDatabase() const;
     void setDatabase(const QSharedPointer<Database> &value);
-    QList<QHash<QString, QString>> generateRelationTables(const QSharedPointer<Entity> &entity) const;
+    QHash<QString, QHash<QString, QString>> generateRelationTables(const QSharedPointer<Entity> &entity) const;
     QHash<QString, QString> generateTableDefinition(const QSharedPointer<Entity> &entity) const;
+    QString generateManyToManyTableName(const QSharedPointer<Entity> &firstEntity,
+                                        const QSharedPointer<Entity> &secondEntity) const;
 
     QString transformTypeToAbstractDbType(QString typeName) const;
     QString transformAbstractTypeToRealDbType(QString typeName) const;
@@ -46,6 +50,8 @@ class QueryBuilder {
   protected:
     void insertRelationId(const Entity *e, QHash<QString, QVariant> &map, QString relName);
     QString buildColumns(const QStringList &columns) const;
+    QHash<QString, QVariant> getManyToOneAttributes(const QHash<QString, QMetaProperty> &props,
+            const QSharedPointer<Entity> &entity);
 
     QSharedPointer<Schema> schema;
     QSharedPointer<Database> database;
diff --git a/src/relation.cpp b/src/relation.cpp
index d140cfb..c796213 100644
--- a/src/relation.cpp
+++ b/src/relation.cpp
@@ -8,6 +8,19 @@ Relation::Relation(QString propertyName, RelationType type, bool optional) {
     this->propertyName = propertyName;
     this->type = type;
     this->optional = optional;
+    this->tableName = "";
+    this->cascadeType = ALL;
+}
+
+Relation::Relation(QString propertyName, RelationType type, QString mappedBy, QString tableName,
+                   CascadeType cascadeType) {
+    this->propertyName = propertyName;
+    this->type = type;
+    this->mappedBy = mappedBy;
+    this->optional = true;
+    this->tableName = tableName;
+    this->cascadeType = cascadeType;
+
 }
 
 Relation::~Relation() {
@@ -35,3 +48,27 @@ bool Relation::getOptional() const {
 void Relation::setOptional(bool value) {
     optional = value;
 }
+QString Relation::getMappedBy() const {
+    return mappedBy;
+}
+
+void Relation::setMappedBy(const QString &value) {
+    mappedBy = value;
+}
+QString Relation::getTableName() const {
+    return tableName;
+}
+
+void Relation::setTableName(const QString &value) {
+    tableName = value;
+}
+CascadeType Relation::getCascadeType() const {
+    return cascadeType;
+}
+
+void Relation::setCascadeType(const CascadeType &value) {
+    cascadeType = value;
+}
+
+
+
diff --git a/src/relation.h b/src/relation.h
index c598b8b..786d90f 100644
--- a/src/relation.h
+++ b/src/relation.h
@@ -3,16 +3,32 @@
 #include <QString>
 namespace CuteEntityManager {
 enum RelationType {
-    BELONGS_TO,
-    HAS_MANY,
-    HAS_ONE,
-    MANY_MANY,
+    ONE_TO_ONE, //e.g. specialization
+    ONE_TO_MANY, //@OneToMany(cascade=ALL, mappedBy="customer")
+    MANY_TO_ONE, //1-n  Entity foreign key in same table
+    MANY_TO_MANY,
+};
+
+enum CascadeType {
+    ALL,
+    MERGE,
+    PERSIST,
+    REFRESH,
+    REMOVE,
 };
 
 class Relation {
   public:
     Relation();
     Relation(QString propertyName, RelationType type, bool optional = true);
+    /**
+     * @brief Relation
+     * @param propertyName
+     * @param type
+     * @param mappedBy Q_PROPERTY in foreign Entity
+     */
+    Relation(QString propertyName, RelationType type, QString mappedBy, QString tableName = "",
+             CascadeType cascadeType = ALL);
     ~Relation();
     RelationType getType() const;
     void setType(const RelationType &value);
@@ -23,9 +39,21 @@ class Relation {
     bool getOptional() const;
     void setOptional(bool value);
 
+    QString getMappedBy() const;
+    void setMappedBy(const QString &value);
+
+    QString getTableName() const;
+    void setTableName(const QString &value);
+
+    CascadeType getCascadeType() const;
+    void setCascadeType(const CascadeType &value);
+
   protected:
     QString propertyName;
+    QString mappedBy;
+    QString tableName;
     RelationType type;
+    CascadeType cascadeType;
     bool optional;
 
 };
diff --git a/src/schema.h b/src/schema.h
index 2da04d7..7950f2b 100644
--- a/src/schema.h
+++ b/src/schema.h
@@ -56,7 +56,7 @@ class Schema {
     QSharedPointer<QHash<QString, QString> > getAbstractTypeMap() const;
     void setAbstractTypeMap(const QSharedPointer<QHash<QString, QString> > &value);
 
-protected:
+  protected:
     virtual QStringList findTableNames(QString schema = "") = 0;
     virtual QHash<QString, QStringList> findUniqueIndexes(const QSharedPointer<TableSchema> &table) = 0;
     virtual void findConstraints(const QSharedPointer<TableSchema> &ts) = 0;
