2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file orm_generator.h
18 * @author Bartosz Janiak (b.janiak@samsung.com)
20 * @brief Macro definitions for generating the DPL-ORM table definitions from database definitions.
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
27 #include <dpl/db/orm_interface.h>
29 #define ORM_GENERATOR_DATABASE_NAME_LOCAL <ORM_GENERATOR_DATABASE_NAME>
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.
35 #define DPL_ORM_GENERATOR_H
38 #include <dpl/string.h>
39 #include <dpl/optional.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>
48 This is true only when exactly one db is available.
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)
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.
68 #define STRINGIFY(s) _str(s)
70 #define DECLARE_COLUMN(FIELD, TYPE) \
72 typedef TYPE ColumnType; \
73 static const char* GetColumnName() { return STRINGIFY(FIELD); } \
74 static void SetRowField(Row& row, const TYPE& value) { row.Set_##FIELD(value);} \
79 #define INTEGER int //TODO: should be long long?
80 #define BIGINT int //TODO: should be long long?
81 #define VARCHAR(x) DPL::String
82 #define TEXT DPL::String
85 #define TABLE_CONSTRAINTS(args...)
86 #define OPTIONAL(type) DPL::Optional< type >
87 #define DATABASE_START(db_name) \
90 class ScopedTransaction \
93 IOrmInterface *m_interface; \
96 ScopedTransaction(IOrmInterface *interface) : \
98 m_interface(interface) \
100 Assert(interface != NULL); \
101 m_interface->TransactionBegin(); \
104 ~ScopedTransaction() \
107 m_interface->TransactionRollback(); \
112 m_interface->TransactionCommit(); \
117 #define DATABASE_END() }
119 // RowBase ostream operator<< declaration
121 #define CREATE_TABLE(name) \
124 inline std::ostream& operator<<(std::ostream& ostr, const RowBase& row); \
126 #define COLUMN_NOT_NULL(name, type, args...)
127 #define COLUMN(name, type, args...)
128 #define CREATE_TABLE_END()
130 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
133 #undef COLUMN_NOT_NULL
135 #undef CREATE_TABLE_END
137 #undef DATABASE_START
138 #define DATABASE_START(db_name) namespace db_name {
142 #define CREATE_TABLE(name) namespace name { class RowBase { \
143 public: friend std::ostream& operator<<(std::ostream&, const RowBase&);
144 #define COLUMN_NOT_NULL(name, type, args...) \
145 protected: type name; bool m_##name##_set; \
146 public: void Set_##name(const type& value) { \
147 m_##name##_set = true; \
148 this->name = value; \
150 public: type Get_##name() const { \
151 if ( !m_##name##_set ) { \
152 ThrowMsg(Exception::RowFieldNotInitialized, \
153 "You tried to read a row field that hasn't been set yet."); \
158 #define COLUMN(name, type, args...) \
159 protected: OPTIONAL(type) name; bool m_##name##_set; \
160 public: void Set_##name(const OPTIONAL(type)& value) { \
161 m_##name##_set = true; \
162 this->name = value; \
164 public: OPTIONAL(type) Get_##name() const { \
165 if ( !m_##name##_set ) { \
166 ThrowMsg(Exception::RowFieldNotInitialized, \
167 "You tried to read a row field that hasn't been set yet."); \
171 #define CREATE_TABLE_END() }; }
173 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
176 #undef COLUMN_NOT_NULL
178 #undef CREATE_TABLE_END
180 // RowBase ostream operator<<
182 #define CREATE_TABLE(name) std::ostream& name::operator<<(std::ostream& ostr, const RowBase& row) { using ::operator<< ; ostr << STRINGIFY(name) << " (";
183 #define COLUMN_NOT_NULL(name, type, args...) ostr << " '" << row.name << "'" ;
184 #define COLUMN(name, type, args...) ostr << " '" << row.name << "'" ;
185 #define CREATE_TABLE_END() ostr << " )" ; return ostr; }
187 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
190 #undef COLUMN_NOT_NULL
192 #undef CREATE_TABLE_END
194 // RowBase2 class (== RowBase + operator==)
196 #define CREATE_TABLE(name) namespace name { class RowBase2 : public RowBase { \
197 public: bool operator==(const RowBase2& row) const { return true
198 #define COLUMN_NOT_NULL(name, type, args...) && (this->name == row.name)
199 #define COLUMN(name, type, args...) && (this->name == row.name)
200 #define CREATE_TABLE_END() ; } }; }
202 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
205 #undef COLUMN_NOT_NULL
207 #undef CREATE_TABLE_END
209 // RowBase3 class (== RowBase2 + operator<)
211 #define CREATE_TABLE(name) namespace name { class RowBase3 : public RowBase2 { \
212 public: bool operator<(const RowBase3& row) const {
213 #define COLUMN_NOT_NULL(name, type, args...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; }
214 #define COLUMN(name, type, args...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; }
215 #define CREATE_TABLE_END() return false; } }; }
217 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
220 #undef COLUMN_NOT_NULL
222 #undef CREATE_TABLE_END
224 // RowBase4 class (== RowBase3 + IsSignatureMatching )
226 #define CREATE_TABLE(name) namespace name { class RowBase4 : public RowBase3 { \
227 public: bool IsSignatureMatching(const RowBase4& row) const { return true
228 #define COLUMN_NOT_NULL(name, type, args...) && (this->m_##name##_set == row.m_##name##_set)
229 #define COLUMN(name, type, args...) && (this->m_##name##_set == row.m_##name##_set)
230 #define CREATE_TABLE_END() ; } }; }
232 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
235 #undef COLUMN_NOT_NULL
237 #undef CREATE_TABLE_END
239 // RowBase5 class (== RowBase4 + default constructor)
241 #define CREATE_TABLE(name) namespace name { class RowBase5 : public RowBase4 { \
243 #define COLUMN_NOT_NULL(name, type, args...) m_##name##_set = false;
244 #define COLUMN(name, type, args...) m_##name##_set = false;
245 #define CREATE_TABLE_END() } }; }
247 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
250 #undef COLUMN_NOT_NULL
252 #undef CREATE_TABLE_END
254 // Row class (== RowBase5 + ForEachColumn )
256 #define CREATE_TABLE(name) namespace name { class Row : public RowBase5 { \
257 public: template<typename Visitor> \
258 void VisitColumns(Visitor& visitor) const {
259 #define COLUMN_NOT_NULL(name, type, args...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set);
260 #define COLUMN(name, type, args...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set);
261 #define CREATE_TABLE_END() } }; }
263 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
266 #undef COLUMN_NOT_NULL
268 #undef CREATE_TABLE_END
270 // Field structure declarations
272 #define CREATE_TABLE(name) namespace name {
273 #define COLUMN_NOT_NULL(name, type, args...) DECLARE_COLUMN(name, type)
274 #define COLUMN(name, type, args...) DECLARE_COLUMN(name, OPTIONAL(type))
275 #define CREATE_TABLE_END() }
277 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
280 #undef COLUMN_NOT_NULL
282 #undef CREATE_TABLE_END
284 // ColumnList typedef
286 #define CREATE_TABLE(name) namespace name { typedef DPL::TypeListDecl<
287 #define COLUMN_NOT_NULL(name, type, args...) name,
288 #define COLUMN(name, type, args...) name,
289 #define CREATE_TABLE_END() DPL::TypeListGuard>::Type ColumnList; }
291 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
294 #undef COLUMN_NOT_NULL
296 #undef CREATE_TABLE_END
298 // TableDefinition struct
300 #define CREATE_TABLE(table_name) \
301 namespace table_name { \
302 struct TableDefinition { \
303 typedef table_name::ColumnList ColumnList; \
304 typedef table_name::Row Row; \
305 static const char* GetName() { return STRINGIFY(table_name); } \
306 static DPL::DB::SqlConnection::DataCommand *AllocTableDataCommand( \
307 const std::string &statement, \
308 IOrmInterface *interface) \
310 Assert(interface != NULL); \
311 return interface->AllocDataCommand(statement); \
313 static void FreeTableDataCommand( \
314 DPL::DB::SqlConnection::DataCommand *command, \
315 IOrmInterface *interface) \
317 Assert(interface != NULL); \
318 interface->FreeDataCommand(command); \
320 static DPL::DB::SqlConnection::RowID GetLastInsertRowID( \
321 IOrmInterface *interface) \
323 Assert(interface != NULL); \
324 return interface->GetLastInsertRowID(); \
329 #define COLUMN_NOT_NULL(name, type, args...)
330 #define COLUMN(name, type, args...)
331 #define CREATE_TABLE_END()
333 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
336 #undef COLUMN_NOT_NULL
338 #undef CREATE_TABLE_END
342 #define CREATE_TABLE(name) \
344 typedef Select<TableDefinition> Select; \
345 typedef Insert<TableDefinition> Insert; \
346 typedef Delete<TableDefinition> Delete; \
347 typedef Update<TableDefinition> Update; \
349 #define COLUMN_NOT_NULL(name, type, args...)
350 #define COLUMN(name, type, args...)
351 #define CREATE_TABLE_END()
353 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
356 #undef COLUMN_NOT_NULL
358 #undef CREATE_TABLE_END
370 #undef TABLE_CONSTRAINTS
372 #undef DATABASE_START
379 #undef ORM_GENERATOR_DATABASE_NAME
380 #undef ORM_GENERATOR_DATABASE_NAME_LOCAL