Adding database loading and data conversion to orm module
[toast/confclerk.git] / src / orm / ormrecord.h
1 #ifndef ORMRECORD_H
2 #define ORMRECORD_H
3
4 #include <QSqlQuery>
5 #include <QSqlRecord>
6 #include <QSqlField>
7 #include <QSqlError>
8 #include <QStringList>
9 #include <QDateTime>
10 #include <QDebug>
11
12 class OrmException
13 {
14 };
15
16 class OrmNoObjectException : OrmException
17 {
18 };
19
20 class OrmSqlException : OrmException
21 {
22 public:
23     OrmSqlException(const QString& text) : mText(text) {}
24     QString text() const { return mText; }
25
26 private:
27     QString mText;
28 };
29
30 template <typename T>
31 class OrmRecord : protected QSqlRecord
32 {
33 public:
34     OrmRecord();
35     static T hydrate(const QSqlRecord& record);
36
37 protected:
38     QVariant value(QString col) const;
39     void setValue(QString col, QVariant value);
40
41     static T loadOne(QSqlQuery query);
42     static QList<T> load(QSqlQuery query);
43
44     // auxiliary methods
45     static QString columnsForSelect(const QString& prefix = QString());
46     static QString selectQuery();
47     static QSqlRecord toRecord(const QList<QSqlField> & columnList);
48
49     static QVariant convertToC(QVariant value, QVariant::Type colType);
50     static QVariant convertToDb(QVariant value, QVariant::Type colType);
51 };
52
53 template <typename T>
54 OrmRecord<T>::OrmRecord()
55 {
56     QSqlRecord::operator=(T::sColumns);
57 }
58
59 template <typename T>
60 T OrmRecord<T>::hydrate(const QSqlRecord& record)
61 {
62     T object;
63     object.QSqlRecord::operator=(record);
64     return object;
65 }
66
67 template <typename T>
68 QVariant OrmRecord<T>::value(QString col) const
69 {
70     return convertToC(QSqlRecord::value(col), T::sColumns.field(col).type());
71 }
72
73 template <typename T>
74 void OrmRecord<T>::setValue(QString col, QVariant value)
75 {
76     QSqlRecord::setValue(col, convertToDb(value, T::sColumns.field(col).type()));
77 }
78
79 template <typename T>
80 T OrmRecord<T>::loadOne(QSqlQuery query)
81 {
82     if (!query.isActive())
83     {
84         if (!query.exec())
85         {
86             throw new OrmSqlException(query.lastError().text());
87         }
88     }
89
90     if (!query.next())
91     {
92         throw new OrmNoObjectException();
93     }
94
95     return hydrate(query.record());
96 }
97
98 template <typename T>
99 QList<T> OrmRecord<T>::load(QSqlQuery query)
100 {
101     if (!query.isActive())
102     {
103         if (!query.exec())
104         {
105             throw new OrmSqlException(query.lastError().text());
106         }
107     }
108
109     QList<T> objects;
110     while (query.next())
111     {
112         objects << hydrate(query.record());
113     }
114
115     return objects;
116 }
117
118 template <typename T>
119 QString OrmRecord<T>::columnsForSelect(const QString& prefix)
120 {
121     QStringList prefixedColumns;
122     for (int i=0; i<T::sColumns.count(); i++)
123     {
124         prefixedColumns.append(prefix.isEmpty() ?
125             T::sColumns.field(i).name() :
126             QString("%1.%2").arg(prefix, T::sColumns.field(i).name()));
127     }
128     return prefixedColumns.join(",");
129 }
130
131 template <typename T>
132 QString OrmRecord<T>::selectQuery()
133 {
134     return QString("SELECT %1 FROM %2 ").arg(columnsForSelect(), T::sTableName);
135 }
136
137 template <typename T>
138 QSqlRecord OrmRecord<T>::toRecord(const QList<QSqlField> & columnList)
139 {
140     QSqlRecord record;
141     foreach (const QSqlField & col, columnList)
142     {
143         record.append(col);
144     }
145     return record;
146 }
147
148 template <typename T>
149 QVariant OrmRecord<T>::convertToC(QVariant value, QVariant::Type colType)
150 {
151     if (colType == QVariant::DateTime &&
152         (value.type() == QVariant::UInt || value.type() == QVariant::Int))
153     {
154         QDateTime date;
155         date.setTime_t(value.toUInt());
156         return date;
157     }
158
159     return value;
160 }
161
162 template <typename T>
163 QVariant OrmRecord<T>::convertToDb(QVariant value, QVariant::Type colType)
164 {
165     if (colType == QVariant::DateTime && value.type() == QVariant::DateTime)
166     {
167         return value.toDateTime().toTime_t();
168     }
169
170     return value;
171 }
172
173 #endif // ORMRECORD_H