- #ifndef DBMETAMODEL_H
- #define DBMETAMODEL_H
- #include <QString>
- #include <QStringList>
- #include <QStringBuilder>
- #include <QVariant>
- #include <QMetaProperty>
- #include <QSqlQuery>
- #include <QDateTime>
- #include <QDebug>
- class DbMetaModel
- {
- public:
- static bool open(const QString& databaseName);
- static void close();
- /**
- * Creates table.
- */
- template<class T>
- static bool createTable()
- {
- bool ret = true;
- QString columns;
- const QMetaObject & metaObject = T::staticMetaObject;
- for(int i = 0; i < metaObject.propertyCount(); i++) {
- if(!columns.isEmpty())
- columns.append(", ");
- const QMetaProperty & property = metaObject.property(i);
- if(QString(property.name()) == "objectName"){
- continue;
- } else if(QString(property.name()) == "id") {
- columns.append("id INTEGER PRIMARY KEY");
- } else if(property.type() == QVariant::String) {
- columns.append(property.name()).append(" TEXT");
- } else if(property.type() == QVariant::Int) {
- columns.append(property.name()).append(" INTEGER");
- } else if(property.type() == QVariant::DateTime) {
- columns.append(property.name()).append(" INTEGER");
- } else {
- qWarning() << "Found property:" << property.name() << " with type:" << property.typeName() << "which can't handle";
- ret = false;
- }
- }
- if(ret) {
- QString createTableQuery = QString("CREATE TABLE %1 (%2)").arg(DbMetaModel::tableName<T>()).arg(columns);
- qDebug() << createTableQuery;
- QSqlQuery createTable;
- ret = createTable.exec(createTableQuery);
- } else {
- qWarning() << "Not going to create tables because there were some properties which don't know how to handle";
- }
- return ret;
- }
- template<class T>
- static QString tableName(){
- return QString(T::staticMetaObject.className()).toLower().append("s");
- }
- template<class T>
- static bool dropTable() {
- QString tableName = DbMetaModel::tableName<T>();
- QString dropTableQuery("DROP TABLE " + tableName);
- qDebug() << dropTableQuery;
- QSqlQuery dropTable;
- return dropTable.exec(dropTableQuery);
- }
- template<class T>
- static QList<T *> findAll() {
- QList<T *> all;
- QStringList props = properties<T>();
- QString findAllQuery = QString("SELECT %1 FROM %2").arg(props.join(", ")).arg(tableName<T>());
- qDebug() << findAllQuery;
- QSqlQuery findAll;
- findAll.exec(findAllQuery);
- while(findAll.next()) {
- T * obj = new T;
- int index = 0;
- Q_FOREACH(QString property, props) {
- QVariant res = findAll.value(index);
- setProperty<T>(obj, property, res);
- index++;
- }
- all.append(obj);
- }
- return all;
- }
- template<class T>
- static QList<T *> findBy(const QString& property, const QVariant& value);
- template<class T>
- static bool save(T * obj) {
- bool ret = true;
- QStringList props = properties<T>();
- props.removeOne(QString("id"));
- QSqlQuery saveQuery;
- if(obj->property("id").toInt() <= 0) {
- QStringList valuesList = values<T>(obj, props);
- QString insertQuery = QString("INSERT INTO %1 (%2) VALUES (%3)").arg(tableName<T>()).arg(props.join(", ")).arg(valuesList.join(", "));
- qDebug() << insertQuery;
- ret = saveQuery.exec(insertQuery);
- obj->setProperty("id", saveQuery.lastInsertId());
- } else {
- QStringList valuesList = values<T>(obj, props, DbMetaModel::PropertyValuePair);
- QString updateQuery = QString("UPDATE %1 SET %2 WHERE id=%3").arg(tableName<T>(), valuesList.join(", ")).arg(obj->property("id").toInt());
- qDebug() << updateQuery;
- ret = saveQuery.exec(updateQuery);
- }
- return ret;
- }
- template<class T>
- static bool existBy(const QString& property, const QVariant& value)
- {
- QString selectQuery = QString("SELECT * FROM %1 WHERE %2=%3").arg(tableName<T>(), property, value.toString());
- QSqlQuery select;
- select.exec(selectQuery);
- return select.next();
- }
- private:
- /**
- * Iterates over all properties and combines them in a string list.
- * Default property: <code>objectName</code> is excluded.
- */
- template<class T>
- static QStringList properties()
- {
- const QMetaObject & metaObject = T::staticMetaObject;
- QStringList list;
- for(int i = metaObject.propertyOffset(); i < metaObject.propertyCount(); i++) {
- const QMetaProperty &property = metaObject.property(i);
- QString propertyName(property.name());
- list.append(propertyName);
- }
- return list;
- }
- enum ValuesFormat {
- SingleValue,
- PropertyValuePair
- } ;
- /**
- * Returns all values as list, strings will be wrapped with single quotes.
- */
- template<class T>
- static QStringList values(const T * obj, const QStringList& props, DbMetaModel::ValuesFormat format = DbMetaModel::SingleValue)
- {
- QStringList valuesList;
- QString valueString;
- Q_FOREACH(QString property, props) {
- QVariant value = obj->property(property.toLatin1());
- if(value.type() == QVariant::String) {
- valueString = QString("'%1'").arg(value.toString());
- } else if(value.type() == QVariant::DateTime) {
- QDateTime dateTime = value.toDateTime();
- valueString = QString("%1").arg(dateTime.toMSecsSinceEpoch());
- } else {
- valueString = value.toString();
- }
- if(format == DbMetaModel::SingleValue) {
- valuesList.append(valueString);
- } else {
- valuesList.append(QString("%1=%2").arg(property, valueString));
- }
- }
- return valuesList;
- }
- /**
- * Sets property value from a QVariant which is retrieved from database query.
- * It converts needed types.
- */
- template<class T>
- static void setProperty(T * obj, const QString& propertyName, QVariant propertyValue)
- {
- const QMetaObject &metaObject = T::staticMetaObject;
- int propertyIndex = metaObject.indexOfProperty(propertyName.toLocal8Bit());
- const QMetaProperty & metaProperty = metaObject.property(propertyIndex);
- if(metaProperty.type() == QVariant::String) {
- obj->setProperty(propertyName.toLocal8Bit(), QString::fromUtf8(propertyValue.toByteArray().data()));
- } else if(metaProperty.type() == QVariant::DateTime) {
- obj->setProperty(propertyName.toLocal8Bit(), QDateTime::fromMSecsSinceEpoch(propertyValue.toLongLong()));
- } else {
- obj->setProperty(propertyName.toLocal8Bit(), propertyValue);
- }
- }
- };
- #endif // DBMETAMODEL_H