Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 4th, 2012  |  syntax: None  |  size: 7.04 KB  |  hits: 12  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #ifndef DBMETAMODEL_H
  2. #define DBMETAMODEL_H
  3.  
  4. #include <QString>
  5. #include <QStringList>
  6. #include <QStringBuilder>
  7. #include <QVariant>
  8. #include <QMetaProperty>
  9. #include <QSqlQuery>
  10. #include <QDateTime>
  11. #include <QDebug>
  12.  
  13. class DbMetaModel
  14. {
  15. public:
  16.     static bool open(const QString& databaseName);
  17.  
  18.     static void close();
  19.  
  20.     /**
  21.       * Creates table.
  22.       */
  23.     template<class T>
  24.     static bool createTable()
  25.     {
  26.         bool ret = true;
  27.  
  28.         QString columns;
  29.         const QMetaObject & metaObject = T::staticMetaObject;
  30.         for(int i = 0; i < metaObject.propertyCount(); i++) {
  31.             if(!columns.isEmpty())
  32.                 columns.append(", ");
  33.  
  34.             const QMetaProperty & property = metaObject.property(i);
  35.  
  36.             if(QString(property.name()) == "objectName"){
  37.                 continue;
  38.             } else if(QString(property.name()) == "id") {
  39.                 columns.append("id INTEGER PRIMARY KEY");
  40.             } else if(property.type() == QVariant::String) {
  41.                 columns.append(property.name()).append(" TEXT");
  42.             } else if(property.type() == QVariant::Int) {
  43.                 columns.append(property.name()).append(" INTEGER");
  44.             } else if(property.type() == QVariant::DateTime) {
  45.                 columns.append(property.name()).append(" INTEGER");
  46.             } else {
  47.                 qWarning() << "Found property:" << property.name() << " with type:" << property.typeName() << "which can't handle";
  48.                 ret = false;
  49.             }
  50.         }
  51.  
  52.         if(ret) {
  53.             QString createTableQuery = QString("CREATE TABLE %1 (%2)").arg(DbMetaModel::tableName<T>()).arg(columns);
  54.             qDebug() << createTableQuery;
  55.             QSqlQuery createTable;
  56.             ret = createTable.exec(createTableQuery);
  57.         } else {
  58.             qWarning() << "Not going to create tables because there were some properties which don't know how to handle";
  59.         }
  60.  
  61.         return ret;
  62.     }
  63.  
  64.     template<class T>
  65.     static QString tableName(){
  66.         return QString(T::staticMetaObject.className()).toLower().append("s");
  67.     }
  68.  
  69.     template<class T>
  70.     static bool dropTable() {
  71.         QString tableName = DbMetaModel::tableName<T>();
  72.         QString dropTableQuery("DROP TABLE " + tableName);
  73.         qDebug() << dropTableQuery;
  74.         QSqlQuery dropTable;
  75.         return dropTable.exec(dropTableQuery);
  76.     }
  77.  
  78.     template<class T>
  79.     static QList<T *> findAll() {
  80.         QList<T *> all;
  81.         QStringList props = properties<T>();
  82.         QString findAllQuery = QString("SELECT %1 FROM %2").arg(props.join(", ")).arg(tableName<T>());
  83.  
  84.         qDebug() << findAllQuery;
  85.  
  86.         QSqlQuery findAll;
  87.         findAll.exec(findAllQuery);
  88.         while(findAll.next()) {
  89.             T * obj = new T;
  90.             int index = 0;
  91.             Q_FOREACH(QString property, props) {
  92.                 QVariant res = findAll.value(index);
  93.                 setProperty<T>(obj, property, res);
  94.                 index++;
  95.             }
  96.             all.append(obj);
  97.         }
  98.  
  99.         return all;
  100.     }
  101.  
  102.     template<class T>
  103.     static QList<T *> findBy(const QString& property, const QVariant& value);
  104.  
  105.     template<class T>
  106.     static bool save(T * obj) {
  107.         bool ret = true;
  108.  
  109.         QStringList props = properties<T>();
  110.         props.removeOne(QString("id"));
  111.  
  112.         QSqlQuery saveQuery;
  113.         if(obj->property("id").toInt() <= 0) {
  114.             QStringList valuesList = values<T>(obj, props);
  115.  
  116.             QString insertQuery = QString("INSERT INTO %1 (%2) VALUES (%3)").arg(tableName<T>()).arg(props.join(", ")).arg(valuesList.join(", "));
  117.             qDebug() << insertQuery;
  118.  
  119.             ret = saveQuery.exec(insertQuery);
  120.             obj->setProperty("id", saveQuery.lastInsertId());
  121.         } else {
  122.             QStringList valuesList = values<T>(obj, props, DbMetaModel::PropertyValuePair);
  123.  
  124.             QString updateQuery = QString("UPDATE %1 SET %2 WHERE id=%3").arg(tableName<T>(), valuesList.join(", ")).arg(obj->property("id").toInt());
  125.             qDebug() << updateQuery;
  126.             ret = saveQuery.exec(updateQuery);
  127.         }
  128.  
  129.         return ret;
  130.     }
  131.  
  132.     template<class T>
  133.     static bool existBy(const QString& property, const QVariant& value)
  134.     {
  135.         QString selectQuery = QString("SELECT * FROM %1 WHERE %2=%3").arg(tableName<T>(), property, value.toString());
  136.         QSqlQuery select;
  137.         select.exec(selectQuery);
  138.         return select.next();
  139.     }
  140.  
  141. private:
  142.     /**
  143.       * Iterates over all properties and combines them in a string list.
  144.       * Default property: <code>objectName</code> is excluded.
  145.       */
  146.     template<class T>
  147.     static QStringList properties()
  148.     {
  149.         const QMetaObject & metaObject = T::staticMetaObject;
  150.  
  151.         QStringList list;
  152.         for(int i = metaObject.propertyOffset(); i < metaObject.propertyCount(); i++) {
  153.             const QMetaProperty &property = metaObject.property(i);
  154.             QString propertyName(property.name());
  155.  
  156.             list.append(propertyName);
  157.         }
  158.  
  159.         return list;
  160.     }
  161.  
  162.     enum ValuesFormat {
  163.         SingleValue,
  164.         PropertyValuePair
  165.     } ;
  166.  
  167.     /**
  168.       * Returns all values as list, strings will be wrapped with single quotes.
  169.       */
  170.     template<class T>
  171.     static QStringList values(const T * obj, const QStringList& props, DbMetaModel::ValuesFormat format = DbMetaModel::SingleValue)
  172.     {
  173.         QStringList valuesList;
  174.         QString valueString;
  175.  
  176.         Q_FOREACH(QString property, props) {
  177.             QVariant value = obj->property(property.toLatin1());
  178.             if(value.type() == QVariant::String) {
  179.                 valueString = QString("'%1'").arg(value.toString());
  180.             } else if(value.type() == QVariant::DateTime) {
  181.                 QDateTime dateTime = value.toDateTime();
  182.                 valueString = QString("%1").arg(dateTime.toMSecsSinceEpoch());
  183.             } else {
  184.                 valueString = value.toString();
  185.             }
  186.  
  187.             if(format == DbMetaModel::SingleValue) {
  188.                 valuesList.append(valueString);
  189.             } else {
  190.                 valuesList.append(QString("%1=%2").arg(property, valueString));
  191.             }
  192.         }
  193.         return valuesList;
  194.     }
  195.  
  196.     /**
  197.       * Sets property value from a QVariant which is retrieved from database query.
  198.       * It converts needed types.
  199.       */
  200.     template<class T>
  201.     static void setProperty(T * obj, const QString& propertyName, QVariant propertyValue)
  202.     {
  203.         const QMetaObject &metaObject = T::staticMetaObject;
  204.         int propertyIndex = metaObject.indexOfProperty(propertyName.toLocal8Bit());
  205.         const QMetaProperty & metaProperty = metaObject.property(propertyIndex);
  206.  
  207.         if(metaProperty.type() == QVariant::String) {
  208.             obj->setProperty(propertyName.toLocal8Bit(), QString::fromUtf8(propertyValue.toByteArray().data()));
  209.         } else if(metaProperty.type() == QVariant::DateTime) {
  210.             obj->setProperty(propertyName.toLocal8Bit(), QDateTime::fromMSecsSinceEpoch(propertyValue.toLongLong()));
  211.         } else {
  212.             obj->setProperty(propertyName.toLocal8Bit(), propertyValue);
  213.         }
  214.     }
  215. };
  216.  
  217. #endif // DBMETAMODEL_H