Created
July 19, 2011 08:30
-
-
Save dubik/1091727 to your computer and use it in GitHub Desktop.
simple orm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DbMetaModel::open("meeReader.db.sqlite"); | |
DbMetaModel::createTable<Book>(); | |
QList<Book *> all = DbMetaModel::findAll<Book>(); | |
Book * book = new Book; | |
book->setOriginalFileName(fileInfo.fileName()); | |
DbMetaModel::save<Book>(book); | |
DbMetaModel::close(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment