Adding database loading and data conversion to orm module
authorkomarma <komarma@localhost>
Wed, 30 Dec 2009 13:50:23 +0000 (13:50 +0000)
committerkomarma <komarma@localhost>
Wed, 30 Dec 2009 13:50:23 +0000 (13:50 +0000)
src/model/event.cpp
src/model/event.h
src/orm/ormrecord.h
src/orm/sqlcondition.cpp [deleted file]
src/orm/sqlcondition.h [deleted file]
src/test/model/eventtest.cpp
src/test/model/eventtest.h

index 58b6730..ff7f1d2 100644 (file)
@@ -1,6 +1,23 @@
 #include "event.h"
 
-QStringList const Event::sColNames = QStringList()
-    << "id" << "xid_conference" << "start" << "duration" << "xid_activity" << "type" << "language";
+QSqlRecord const Event::sColumns = Event::toRecord(QList<QSqlField>()
+    << QSqlField("id", QVariant::Int)
+    << QSqlField("xid_conference", QVariant::Int)
+    << QSqlField("start", QVariant::DateTime)
+    << QSqlField("duration", QVariant::Int)
+    << QSqlField("xid_activity", QVariant::Int)
+    << QSqlField("type", QVariant::String)
+    << QSqlField("language", QVariant::String));
 
 QString const Event::sTableName = QString("event");
+
+Event Event::getById(int id, int conferenceId)
+{
+    QString query = selectQuery() + "WHERE id = :id AND xid_conference = :conf";
+
+    QSqlQuery q;
+    q.prepare(query);
+    q.bindValue(":id", id);
+    q.bindValue(":conf", conferenceId);
+    return loadOne(q);
+}
index 50890ef..14aa5f3 100644 (file)
@@ -15,44 +15,33 @@ class NoSuchEventException
 {
 };
 
-class Event : public OrmRecord <Event>
+class Event : public OrmRecord<Event>
 {
 public:
-    // column definition
-    enum Column
-    {
-        Id = 0,
-        Conference,
-        Start,
-        Duration,
-        Activity,
-        Type,
-        Language
-    };
-
-    static QStringList const sColNames;
-
+    static QSqlRecord const sColumns;
     static QString const sTableName;
 
 public:
-    static Event getById(int id, int conferenceId) { return Event(); } //EventTable::selectOne("id=1"); }
+    static Event getById(int id, int conferenceId);
 
 public:
-    int id() const { return value(Id).toInt(); }
-    int conferenceId() const { return value(Conference).toInt(); }
-    QDateTime start() const { return value(Start).toDateTime(); }
-    int duration() const { return value(Duration).toInt(); }
-    int activityId() const { return value(Activity).toInt(); }
-    int typeId() const { return value(Type).toInt(); }
-    int languageId() const { return value(Language).toInt(); }
-
-    void setId(int id) { setValue(Id, id); }
-    void setConferenceId(int conferenceId) { setValue(Conference, conferenceId); }
-    void setStart(const QDateTime& start) { setValue(Start, start); }
-    void setDuration(int duration) { setValue(Duration, duration); }
-    void setActivityId(int activityId) { setValue(Activity, activityId); }
-    void setTypeId(int typeId) { setValue(Type, typeId); }
-    void setLanguageId(int languageId) { setValue(Language, languageId); }
+    int id() const { return value("id").toInt(); }
+    int conferenceId() const { return value("xid_conference").toInt(); }
+    QDateTime start() const { return value("start").toDateTime(); }
+    int duration() const { return value("duration").toInt(); }
+    int activityId() const { return value("xid_activity").toInt(); }
+    int typeId() const { return value("type").toInt(); }
+    int languageId() const { return value("language").toInt(); }
+
+    void setId(int id) { setValue("id", id); }
+    void setConferenceId(int conferenceId) { setValue("xid_conference", conferenceId); }
+    void setStart(const QDateTime& start) { setValue("start", start); }
+    void setDuration(int duration) { setValue("duration", duration); }
+    void setActivityId(int activityId) { setValue("xid_activity", activityId); }
+    void setTypeId(int typeId) { setValue("type", typeId); }
+    void setLanguageId(int languageId) { setValue("language", languageId); }
+
+friend class EventTest;
 };
 
 
index 754bc4f..22e19f4 100644 (file)
+#ifndef ORMRECORD_H
+#define ORMRECORD_H
+
+#include <QSqlQuery>
 #include <QSqlRecord>
 #include <QSqlField>
+#include <QSqlError>
+#include <QStringList>
+#include <QDateTime>
+#include <QDebug>
+
+class OrmException
+{
+};
+
+class OrmNoObjectException : OrmException
+{
+};
+
+class OrmSqlException : OrmException
+{
+public:
+    OrmSqlException(const QString& text) : mText(text) {}
+    QString text() const { return mText; }
+
+private:
+    QString mText;
+};
 
 template <typename T>
 class OrmRecord : protected QSqlRecord
 {
 public:
-    static QString colName(int col);
+    OrmRecord();
+    static T hydrate(const QSqlRecord& record);
 
 protected:
-    QVariant value(int col) const;
-    void setValue(int col, QVariant value);
+    QVariant value(QString col) const;
+    void setValue(QString col, QVariant value);
+
+    static T loadOne(QSqlQuery query);
+    static QList<T> load(QSqlQuery query);
+
+    // auxiliary methods
+    static QString columnsForSelect(const QString& prefix = QString());
+    static QString selectQuery();
+    static QSqlRecord toRecord(const QList<QSqlField> & columnList);
+
+    static QVariant convertToC(QVariant value, QVariant::Type colType);
+    static QVariant convertToDb(QVariant value, QVariant::Type colType);
 };
 
 template <typename T>
-QString OrmRecord<T>::colName(int col)
+OrmRecord<T>::OrmRecord()
+{
+    QSqlRecord::operator=(T::sColumns);
+}
+
+template <typename T>
+T OrmRecord<T>::hydrate(const QSqlRecord& record)
+{
+    T object;
+    object.QSqlRecord::operator=(record);
+    return object;
+}
+
+template <typename T>
+QVariant OrmRecord<T>::value(QString col) const
+{
+    return convertToC(QSqlRecord::value(col), T::sColumns.field(col).type());
+}
+
+template <typename T>
+void OrmRecord<T>::setValue(QString col, QVariant value)
+{
+    QSqlRecord::setValue(col, convertToDb(value, T::sColumns.field(col).type()));
+}
+
+template <typename T>
+T OrmRecord<T>::loadOne(QSqlQuery query)
+{
+    if (!query.isActive())
+    {
+        if (!query.exec())
+        {
+            throw new OrmSqlException(query.lastError().text());
+        }
+    }
+
+    if (!query.next())
+    {
+        throw new OrmNoObjectException();
+    }
+
+    return hydrate(query.record());
+}
+
+template <typename T>
+QList<T> OrmRecord<T>::load(QSqlQuery query)
+{
+    if (!query.isActive())
+    {
+        if (!query.exec())
+        {
+            throw new OrmSqlException(query.lastError().text());
+        }
+    }
+
+    QList<T> objects;
+    while (query.next())
+    {
+        objects << hydrate(query.record());
+    }
+
+    return objects;
+}
+
+template <typename T>
+QString OrmRecord<T>::columnsForSelect(const QString& prefix)
 {
-    return T::sColNames.at(col);
+    QStringList prefixedColumns;
+    for (int i=0; i<T::sColumns.count(); i++)
+    {
+        prefixedColumns.append(prefix.isEmpty() ?
+            T::sColumns.field(i).name() :
+            QString("%1.%2").arg(prefix, T::sColumns.field(i).name()));
+    }
+    return prefixedColumns.join(",");
 }
 
 template <typename T>
-QVariant OrmRecord<T>::value(int col) const
+QString OrmRecord<T>::selectQuery()
 {
-    Q_ASSERT(col >= 0 && col < T::sColNames.count());
+    return QString("SELECT %1 FROM %2 ").arg(columnsForSelect(), T::sTableName);
+}
 
-    return QSqlRecord::value(T::sColNames.at(col));
+template <typename T>
+QSqlRecord OrmRecord<T>::toRecord(const QList<QSqlField> & columnList)
+{
+    QSqlRecord record;
+    foreach (const QSqlField & col, columnList)
+    {
+        record.append(col);
+    }
+    return record;
 }
 
 template <typename T>
-void OrmRecord<T>::setValue(int col, QVariant value)
+QVariant OrmRecord<T>::convertToC(QVariant value, QVariant::Type colType)
 {
-    Q_ASSERT(col >= 0 && col < T::sColNames.count());
+    if (colType == QVariant::DateTime &&
+        (value.type() == QVariant::UInt || value.type() == QVariant::Int))
+    {
+        QDateTime date;
+        date.setTime_t(value.toUInt());
+        return date;
+    }
 
-    QString fieldName = T::sColNames.at(col);
+    return value;
+}
 
-    if (!contains(fieldName))
+template <typename T>
+QVariant OrmRecord<T>::convertToDb(QVariant value, QVariant::Type colType)
+{
+    if (colType == QVariant::DateTime && value.type() == QVariant::DateTime)
     {
-        append(QSqlField(fieldName, value.type()));
+        return value.toDateTime().toTime_t();
     }
 
-    QSqlRecord::setValue(fieldName, value);
+    return value;
 }
+
+#endif // ORMRECORD_H
diff --git a/src/orm/sqlcondition.cpp b/src/orm/sqlcondition.cpp
deleted file mode 100644 (file)
index 6aece67..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "sqlcondition.h"
-
-//static char* SqlTerm::sOperatorNames[] = {"=", "<>", ">", ">=", "<", "<="};
-//
-//QString SqlTerm::toString() const
-//{
-//    return QString("%1 %2 %3").arg(mColumn, sOperatorNames[mOperator], mValue);
-//}
-//
-//QString SqlAndCondition::toString() const
-//{
-//    return QString("(%1) AND (%2)").arg(mLeft.toString(), mRight.toString());
-//}
-//
-//QString SqlOrCondition::toString() const
-//{
-//    return QString("(%1) OR (%2)").arg(mLeft.toString(), mRight.toString());
-//}
-//
-//QString SqlNotCondition::toString() const
-//{
-//    return QString("!(%1)").arg(mCond.toString());
-//}
diff --git a/src/orm/sqlcondition.h b/src/orm/sqlcondition.h
deleted file mode 100644 (file)
index 6b1a455..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef SQLCONDITION_H
-#define SQLCONDITION_H
-
-//#include <QVariant>
-
-//class SqlCondition
-//{
-//public:
-//    enum Operator { eq = 0, ne, gt, ge, lt, le };
-//
-//public:
-//    SqlCondition(const QLatin1String& column, Operator op, const QVariant& value) :
-//            mColumn(column), mValue(value), mOperator(op) {}
-//
-//    virtual QString toString() const;
-//private:
-//    QLatin1String mColumn;
-//    QVariant mValue;
-//    Operator mOperator;
-//
-//private:
-//    static char* sOperatorNames[];
-//};
-//
-//class SqlAndCondition : public SqlCondition
-//{
-//    SqlCondition mLeft;
-//    SqlCondition mRight;
-//
-//public:
-//    SqlAndCondition(const SqlCondition& left, const SqlCondition& right):
-//            mLeft(left), mRight(right) {}
-//
-//    QString toString() const;
-//};
-//
-//class SqlOrCondition : public SqlCondition
-//{
-//    SqlCondition mLeft;
-//    SqlCondition mRight;
-//
-//public:
-//    SqlOrCondition(const SqlCondition& left, const SqlCondition& right):
-//            mLeft(left), mRight(right) {}
-//
-//    QString toString() const;
-//};
-//
-//class SqlNotCondition : public SqlCondition
-//{
-//    SqlCondition mCond;
-//public:
-//    SqlNotCondition(const SqlCondition& cond): mCond(new SqlCondition(cond)) {}
-//
-//    QString toString() const;
-//};
-//
-//class SqlColumn
-//{
-//public:
-//    SqlColumn(const QLatin1String& column) : mColumn(column) {}
-//
-//    SqlCondition const operator==(const QVariant& value) { return SqlCondition(mColumn, SqlCondition::eq, value); }
-//    SqlCondition const operator!=(const QVariant& value) { return SqlCondition(mColumn, SqlCondition::ne, value); }
-//    SqlCondition const operator>=(const QVariant& value) { return SqlCondition(mColumn, SqlCondition::ge, value); }
-//    SqlCondition const operator> (const QVariant& value) { return SqlCondition(mColumn, SqlCondition::gt, value); }
-//    SqlCondition const operator<=(const QVariant& value) { return SqlCondition(mColumn, SqlCondition::le, value); }
-//    SqlCondition const operator< (const QVariant& value) { return SqlCondition(mColumn, SqlCondition::lt, value); }
-//private:
-//    QLatin1String mColumn;
-//};
-
-
-#endif // SQLCONDITION_H
index 2219f62..83f1996 100644 (file)
@@ -11,7 +11,7 @@ void EventTest::initTestCase()
 {
     // Connect to the test database. Ask Mr. Pavelka to generate one for you :)
     QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
-    db.setDatabaseName("fostem-test.sqlite");
+    db.setDatabaseName("fosdem-test.sqlite");
     QVERIFY(db.open());
 }
 
@@ -27,40 +27,49 @@ void EventTest::getById()
     QCOMPARE(event.languageId(), 0);
 }
 
-void EventTest::colNames()
-{
-    QCOMPARE(Event::colName(Event::Id), QString("id"));
-    QCOMPARE(Event::colName(Event::Conference), QString("xid_conference"));
-    QCOMPARE(Event::colName(Event::Start), QString("start"));
-    QCOMPARE(Event::colName(Event::Duration), QString("duration"));
-    QCOMPARE(Event::colName(Event::Activity), QString("xid_activity"));
-    QCOMPARE(Event::colName(Event::Type), QString("type"));
-    QCOMPARE(Event::colName(Event::Language), QString("language"));
-}
-
 void EventTest::storingValues()
 {
     Event event;
-    QCOMPARE(event.id(), 0);
 
     event.setId(10);
-    QCOMPARE(event.id(), 10);
-
     event.setConferenceId(20);
-    QCOMPARE(event.conferenceId(), 20);
-
     event.setStart(QDateTime::fromString("Sat Feb 7 11:30:00 2009"));
-    QCOMPARE(event.start(), QDateTime::fromString("Sat Feb 7 11:30:00 2009"));
-
     event.setDuration(30);
-    QCOMPARE(event.duration(), 30);
-
     event.setActivityId(40);
-    QCOMPARE(event.activityId(), 40);
-
     event.setTypeId(50);
-    QCOMPARE(event.typeId(), 50);
-
     event.setLanguageId(60);
+
+    QCOMPARE(event.id(), 10);
+    QCOMPARE(event.conferenceId(), 20);
+    QCOMPARE(event.start(), QDateTime::fromString("Sat Feb 7 11:30:00 2009"));
+    QCOMPARE(event.duration(), 30);
+    QCOMPARE(event.activityId(), 40);
+    QCOMPARE(event.typeId(), 50);
     QCOMPARE(event.languageId(), 60);
 }
+
+
+void EventTest::hydrate()
+{
+    QSqlRecord record;
+    record.append(QSqlField("duration", QVariant::Int));
+    record.append(QSqlField("id", QVariant::Int));
+    record.setValue(0, 10);
+    record.setValue(1, 20);
+
+    Event event = Event::hydrate(record);
+    QCOMPARE(event.id(), 20);
+    QCOMPARE(event.duration(), 10);
+}
+
+void EventTest::columnsForSelect()
+{
+    QCOMPARE(Event::columnsForSelect(), QString("id,xid_conference,start,duration,xid_activity,type,language"));
+    QCOMPARE(Event::columnsForSelect("t0"),
+             QString("t0.id,t0.xid_conference,t0.start,t0.duration,t0.xid_activity,t0.type,t0.language"));
+}
+
+void EventTest::selectQuery()
+{
+    QCOMPARE(Event::selectQuery(), QString("SELECT id,xid_conference,start,duration,xid_activity,type,language FROM event "));
+}
index 4e479b0..9a734a8 100644 (file)
@@ -11,8 +11,10 @@ private slots:
     void initTestCase();
 
     void getById();
-    void colNames();
     void storingValues();
+    void hydrate();
+    void columnsForSelect();
+    void selectQuery();
 };