00179212ac74fc3b9eab0e8b4cbb3adcb82c326e
[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             //TODO Palo: exception handling !
106                 QString start = "START\n";
107                 QString end = "\nEND\n";
108                 QString message = start + query.lastError().text() + end;
109                 const char *data = message.toLatin1().data();
110                 qDebug(data);
111             throw new OrmSqlException(query.lastError().text());
112         }
113     }
114
115     QList<T> objects;
116     while (query.next())
117     {
118         objects << hydrate(query.record());
119     }
120
121     return objects;
122 }
123
124 template <typename T>
125 QString OrmRecord<T>::columnsForSelect(const QString& prefix)
126 {
127     QStringList prefixedColumns;
128     for (int i=0; i<T::sColumns.count(); i++)
129     {
130         prefixedColumns.append(prefix.isEmpty() ?
131             T::sColumns.field(i).name() :
132             QString("%1.%2").arg(prefix, T::sColumns.field(i).name()));
133     }
134     return prefixedColumns.join(",");
135 }
136
137 template <typename T>
138 QString OrmRecord<T>::selectQuery()
139 {
140     return QString("SELECT %1 FROM %2 ").arg(columnsForSelect(), T::sTableName);
141 }
142
143 template <typename T>
144 QSqlRecord OrmRecord<T>::toRecord(const QList<QSqlField> & columnList)
145 {
146     QSqlRecord record;
147     foreach (const QSqlField & col, columnList)
148     {
149         record.append(col);
150     }
151     return record;
152 }
153
154 template <typename T>
155 QVariant OrmRecord<T>::convertToC(QVariant value, QVariant::Type colType)
156 {
157     if (colType == QVariant::DateTime && value.canConvert<uint>())
158     {
159         QDateTime date;
160         date.setTimeSpec(Qt::UTC);
161         date.setTime_t(value.toUInt());
162         return date;
163     }
164
165     return value;
166 }
167
168 template <typename T>
169 QVariant OrmRecord<T>::convertToDb(QVariant value, QVariant::Type colType)
170 {
171     if (colType == QVariant::DateTime && value.canConvert<QDateTime>())
172     {
173         return value.toDateTime().toTime_t();
174     }
175
176     return value;
177 }
178
179 #endif // ORMRECORD_H