tizen 2.4 release
[framework/web/wrt-commons.git] / modules / db / include / dpl / db / orm_generator.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        orm_generator.h
18  * @author      Bartosz Janiak (b.janiak@samsung.com)
19  * @version     1.0
20  * @brief       Macro definitions for generating the DPL-ORM table definitions from database definitions.
21  */
22
23 #ifndef ORM_GENERATOR_DATABASE_NAME
24 #error You need to define database name in ORM_GENERATOR_DATABASE_NAME define before you include orm_generator.h file
25 #endif
26
27 #include <dpl/db/orm_interface.h>
28
29 #define ORM_GENERATOR_DATABASE_NAME_LOCAL <ORM_GENERATOR_DATABASE_NAME>
30
31 #ifdef DPL_ORM_GENERATOR_H
32 #warning orm_generator.h is included multiply times. Make sure it has different ORM_GENERATOR_DATABASE_NAME set.
33 #endif
34
35 #define DPL_ORM_GENERATOR_H
36
37
38 #include <boost/optional.hpp>
39 #include <dpl/string.h>
40 #include <dpl/type_list.h>
41 #include <dpl/db/sql_connection.h>
42 #include <dpl/db/orm.h>
43 #include <dpl/assert.h>
44 #include <string>
45
46 /*
47
48 This is true only when exactly one db is available.
49
50 #if (defined DECLARE_COLUMN) || (defined INT) || (defined TINYINT) ||               \
51     (defined INTEGER) || (defined BIGINT) || defined(VARCHAR) || defined(TEXT) ||   \
52     (defined SQL) || (defined TABLE_CONSTRAINTS) || (defined OPTIONAL) ||           \
53     (defined DATABASE_START) || (defined DATABASE_END) || (defined CREATE_TABLE) || \
54     (defined COLUMN) || (defined COLUMN_NOT_NULL) || (defined CREATE_TABLE_END)
55
56 #error  This file temporarily defines many macros with generic names. To avoid name clash please include \
57         this file as early as possible. If this is not possible please report this problem to DPL developers.
58
59 #endif
60 */
61
62 namespace DPL {
63 namespace DB {
64 namespace ORM {
65
66 // Global macros
67
68 #define STRINGIFY(s) _str(s)
69 #define _str(s) #s
70 #define DECLARE_COLUMN(FIELD, TYPE) \
71     struct FIELD { \
72         typedef TYPE ColumnType; \
73         static const char* GetTableName() { return GetName(); } \
74         static const char* GetColumnName() { return STRINGIFY(FIELD); } \
75         static void SetRowField(Row& row, const TYPE& _value) { row.Set_##FIELD(_value);} \
76     };
77
78 #define INT         int
79 #define TINYINT     int
80 #define INTEGER     int  //TODO: should be long long?
81 #define BIGINT      int  //TODO: should be long long?
82 #define VARCHAR(x)  DPL::String
83 #define TEXT        DPL::String
84
85 #define SQL(...)
86 #define TABLE_CONSTRAINTS(...)
87 #define OPTIONAL(type) boost::optional< type >
88 #define DATABASE_START(db_name)                                 \
89     namespace db_name                                           \
90     {                                                           \
91         class ScopedTransaction                                 \
92         {                                                       \
93             bool m_commited;                                    \
94             IOrmInterface *m_interface;                         \
95                                                                 \
96         public:                                                 \
97             ScopedTransaction(IOrmInterface *interface) :       \
98                 m_commited(false),                              \
99                 m_interface(interface)                          \
100             {                                                   \
101                 Assert(interface != NULL);                      \
102                 m_interface->TransactionBegin();                \
103             }                                                   \
104                                                                 \
105             ~ScopedTransaction()                                \
106             {                                                   \
107                 if (!m_commited)                                \
108                     m_interface->TransactionRollback();         \
109             }                                                   \
110                                                                 \
111             void Commit()                                       \
112             {                                                   \
113                 m_interface->TransactionCommit();               \
114                 m_commited = true;                              \
115             }                                                   \
116         };
117
118 #define DATABASE_END() }
119
120 // RowBase ostream operator<< declaration
121
122 #define CREATE_TABLE(name) \
123     namespace name {                                                            \
124         class RowBase;                                                          \
125         inline std::ostream& operator<<(std::ostream& ostr, const RowBase& row); \
126     }
127 #define COLUMN_NOT_NULL(name, type, ...)
128 #define COLUMN(name, type, ...)
129 #define CREATE_TABLE_END()
130
131 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
132
133 #undef CREATE_TABLE
134 #undef COLUMN_NOT_NULL
135 #undef COLUMN
136 #undef CREATE_TABLE_END
137
138 #undef DATABASE_START
139 #define DATABASE_START(db_name) namespace db_name {
140
141 // RowBase class
142
143 #define CREATE_TABLE(name) namespace name { class RowBase {                 \
144    public: friend std::ostream& operator<<(std::ostream&, const RowBase&);
145 #define COLUMN_NOT_NULL(name, type, ...)                                \
146         protected: type name; bool m_##name##_set;                          \
147         public:  void Set_##name(const type& _value) {                       \
148                      m_##name##_set = true;                                 \
149                      this->name = _value;                                     \
150         }                                                                   \
151         public:  type Get_##name() const {                                  \
152                      if ( !m_##name##_set ) {                               \
153                         ThrowMsg(Exception::RowFieldNotInitialized,         \
154                         "You tried to read a row field that hasn't been set yet."); \
155                      }                                                      \
156                      return name;                                           \
157         }
158
159 #define COLUMN(name, type, ...)                                         \
160         protected: OPTIONAL(type) name; bool m_##name##_set;                \
161         public:  void Set_##name(const OPTIONAL(type)& _value) {             \
162                      m_##name##_set = true;                                 \
163                      this->name = _value;                                     \
164         }                                                                   \
165         public:  OPTIONAL(type) Get_##name() const {                        \
166                      if ( !m_##name##_set ) {                               \
167                         ThrowMsg(Exception::RowFieldNotInitialized,         \
168                         "You tried to read a row field that hasn't been set yet."); \
169                      }                                                      \
170                      return name;                                           \
171         }
172 #define CREATE_TABLE_END() }; }
173
174 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
175
176 #undef CREATE_TABLE
177 #undef COLUMN_NOT_NULL
178 #undef COLUMN
179 #undef CREATE_TABLE_END
180
181 // RowBase ostream operator<<
182
183 #define CREATE_TABLE(name) std::ostream& name::operator<<(std::ostream& ostr, const RowBase& row) { using ::operator<< ; ostr << STRINGIFY(name) << " (";
184 #define COLUMN_NOT_NULL(name, type, ...) ostr << " '" << row.name << "'" ;
185 #define COLUMN(name, type, ...)          if (!!(row.name)) { ostr << " '" << *(row.name) << "'"; } else { ostr << " '" << "NULL" << "'"; }
186 #define CREATE_TABLE_END() ostr << " )" ; return ostr; }
187
188 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
189
190 #undef CREATE_TABLE
191 #undef COLUMN_NOT_NULL
192 #undef COLUMN
193 #undef CREATE_TABLE_END
194
195 // RowBase2 class (== RowBase + operator==)
196
197 #define CREATE_TABLE(name) namespace name { class RowBase2 : public RowBase { \
198     public: bool operator==(const RowBase2& row) const { return true
199 #define COLUMN_NOT_NULL(name, type, ...) && (this->name == row.name)
200 #define COLUMN(name, type, ...)          && (this->name == row.name)
201 #define CREATE_TABLE_END() ; } }; }
202
203 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
204
205 #undef CREATE_TABLE
206 #undef COLUMN_NOT_NULL
207 #undef COLUMN
208 #undef CREATE_TABLE_END
209
210 // RowBase3 class (== RowBase2 + operator<)
211
212 #define CREATE_TABLE(name) namespace name { class RowBase3 : public RowBase2 { \
213     public: bool operator<(const RowBase3& row) const {
214 #define COLUMN_NOT_NULL(name, type, ...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; }
215 #define COLUMN(name, type, ...)          if (this->name < row.name) { return true; } if (this->name > row.name) { return false; }
216 #define CREATE_TABLE_END() return false; } }; }
217
218 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
219
220 #undef CREATE_TABLE
221 #undef COLUMN_NOT_NULL
222 #undef COLUMN
223 #undef CREATE_TABLE_END
224
225 // RowBase4 class (== RowBase3 + IsSignatureMatching )
226
227 #define CREATE_TABLE(name) namespace name { class RowBase4 : public RowBase3 { \
228     public: bool IsSignatureMatching(const RowBase4& row) const { return true
229 #define COLUMN_NOT_NULL(name, type, ...) && (this->m_##name##_set == row.m_##name##_set)
230 #define COLUMN(name, type, ...)          && (this->m_##name##_set == row.m_##name##_set)
231 #define CREATE_TABLE_END() ; } }; }
232
233 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
234
235 #undef CREATE_TABLE
236 #undef COLUMN_NOT_NULL
237 #undef COLUMN
238 #undef CREATE_TABLE_END
239
240 // RowBase5 class (== RowBase4 + default constructor)
241
242 #define CREATE_TABLE(name) namespace name { class RowBase5 : public RowBase4 { \
243     public: RowBase5() {
244 #define COLUMN_NOT_NULL(name, type, ...) m_##name##_set = false;
245 #define COLUMN(name, type, ...)          m_##name##_set = false;
246 #define CREATE_TABLE_END() } }; }
247
248 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
249
250 #undef CREATE_TABLE
251 #undef COLUMN_NOT_NULL
252 #undef COLUMN
253 #undef CREATE_TABLE_END
254
255 // Row class (== RowBase5 + ForEachColumn )
256
257 #define CREATE_TABLE(name) namespace name { class Row : public RowBase5 { \
258     public: template<typename Visitor>                                    \
259     void VisitColumns(Visitor& visitor) const {
260 #define COLUMN_NOT_NULL(name, type, ...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set);
261 #define COLUMN(name, type, ...)          visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set);
262 #define CREATE_TABLE_END() } }; }
263
264 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
265
266 #undef CREATE_TABLE
267 #undef COLUMN_NOT_NULL
268 #undef COLUMN
269 #undef CREATE_TABLE_END
270
271 // Field structure declarations
272
273 #define CREATE_TABLE(name) namespace name { \
274     static const char* GetName() { return STRINGIFY(name); }
275 #define COLUMN_NOT_NULL(name, type, ...) DECLARE_COLUMN(name, type)
276 #define COLUMN(name, type, ...) DECLARE_COLUMN(name, OPTIONAL(type))
277 #define CREATE_TABLE_END() }
278
279 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
280
281 #undef CREATE_TABLE
282 #undef COLUMN_NOT_NULL
283 #undef COLUMN
284 #undef CREATE_TABLE_END
285
286 // ColumnList typedef
287
288 #define CREATE_TABLE(name) namespace name { typedef DPL::TypeListDecl<
289 #define COLUMN_NOT_NULL(name, type, ...) name,
290 #define COLUMN(name, type, ...) name,
291 #define CREATE_TABLE_END() DPL::TypeListGuard>::Type ColumnList; }
292
293 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
294
295 #undef CREATE_TABLE
296 #undef COLUMN_NOT_NULL
297 #undef COLUMN
298 #undef CREATE_TABLE_END
299
300 // TableDefinition struct
301
302 #define CREATE_TABLE(table_name)                                            \
303     namespace table_name {                                                  \
304         struct TableDefinition {                                            \
305             typedef table_name::ColumnList ColumnList;                      \
306             typedef table_name::Row Row;                                    \
307             static const char* GetName() { return STRINGIFY(table_name); }  \
308             static DPL::DB::SqlConnection::DataCommand *AllocTableDataCommand( \
309                 const std::string &statement,                               \
310                 IOrmInterface *interface)                                   \
311             {                                                               \
312                 Assert(interface != NULL);                                  \
313                 return interface->AllocDataCommand(statement);              \
314             }                                                               \
315             static void FreeTableDataCommand(                               \
316                 DPL::DB::SqlConnection::DataCommand *command,               \
317                 IOrmInterface *interface)                                   \
318             {                                                               \
319                 Assert(interface != NULL);                                  \
320                 interface->FreeDataCommand(command);                        \
321             }                                                               \
322             static DPL::DB::SqlConnection::RowID GetLastInsertRowID(        \
323                 IOrmInterface *interface)                                   \
324             {                                                               \
325                 Assert(interface != NULL);                                  \
326                 return interface->GetLastInsertRowID();                     \
327             }                                                               \
328         };                                                                  \
329     }
330
331 #define COLUMN_NOT_NULL(name, type, ...)
332 #define COLUMN(name, type, ...)
333 #define CREATE_TABLE_END()
334
335 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
336
337 #undef CREATE_TABLE
338 #undef COLUMN_NOT_NULL
339 #undef COLUMN
340 #undef CREATE_TABLE_END
341
342 // Query typedefs
343
344 #define CREATE_TABLE(name) \
345     namespace name { \
346         typedef Select<TableDefinition> Select; \
347         typedef Insert<TableDefinition> Insert; \
348         typedef Delete<TableDefinition> Delete; \
349         typedef Update<TableDefinition> Update; \
350     }
351 #define COLUMN_NOT_NULL(name, type, ...)
352 #define COLUMN(name, type, ...)
353 #define CREATE_TABLE_END()
354
355 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
356
357 #undef CREATE_TABLE
358 #undef COLUMN_NOT_NULL
359 #undef COLUMN
360 #undef CREATE_TABLE_END
361
362
363 // Global undefs
364 #undef INT
365 #undef TINYINT
366 #undef INTEGER
367 #undef BIGINT
368 #undef VARCHAR
369 #undef TEXT
370
371 #undef SQL
372 #undef TABLE_CONSTRAINTS
373 #undef OPTIONAL
374 #undef DATABASE_START
375 #undef DATABASE_END
376
377 } //namespace ORM
378 } //namespace DB
379 } //namespace DPL
380
381 #undef ORM_GENERATOR_DATABASE_NAME
382 #undef ORM_GENERATOR_DATABASE_NAME_LOCAL