Skip to content

Instantly share code, notes, and snippets.

@dubik
Created July 19, 2011 08:30
Show Gist options
  • Save dubik/1091727 to your computer and use it in GitHub Desktop.
Save dubik/1091727 to your computer and use it in GitHub Desktop.
simple orm
#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
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