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* GetTableName() { return GetName(); } \
74 static const char* GetColumnName() { return STRINGIFY(FIELD); } \
75 static void SetRowField(Row& row, const TYPE& _value) { row.Set_##FIELD(_value);} \
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
86 #define TABLE_CONSTRAINTS(...)
87 #define OPTIONAL(type) DPL::Optional< type >
88 #define DATABASE_START(db_name) \
91 class ScopedTransaction \
94 IOrmInterface *m_interface; \
97 ScopedTransaction(IOrmInterface *interface) : \
99 m_interface(interface) \
101 Assert(interface != NULL); \
102 m_interface->TransactionBegin(); \
105 ~ScopedTransaction() \
108 m_interface->TransactionRollback(); \
113 m_interface->TransactionCommit(); \
118 #define DATABASE_END() }
120 // RowBase ostream operator<< declaration
122 #define CREATE_TABLE(name) \
125 inline std::ostream& operator<<(std::ostream& ostr, const RowBase& row); \
127 #define COLUMN_NOT_NULL(name, type, ...)
128 #define COLUMN(name, type, ...)
129 #define CREATE_TABLE_END()
131 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
134 #undef COLUMN_NOT_NULL
136 #undef CREATE_TABLE_END
138 #undef DATABASE_START
139 #define DATABASE_START(db_name) namespace db_name {
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; \
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."); \
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; \
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."); \
172 #define CREATE_TABLE_END() }; }
174 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
177 #undef COLUMN_NOT_NULL
179 #undef CREATE_TABLE_END
181 // RowBase ostream operator<<
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, ...) ostr << " '" << row.name << "'" ;
186 #define CREATE_TABLE_END() ostr << " )" ; return ostr; }
188 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
191 #undef COLUMN_NOT_NULL
193 #undef CREATE_TABLE_END
195 // RowBase2 class (== RowBase + operator==)
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() ; } }; }
203 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
206 #undef COLUMN_NOT_NULL
208 #undef CREATE_TABLE_END
210 // RowBase3 class (== RowBase2 + operator<)
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; } }; }
218 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
221 #undef COLUMN_NOT_NULL
223 #undef CREATE_TABLE_END
225 // RowBase4 class (== RowBase3 + IsSignatureMatching )
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() ; } }; }
233 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
236 #undef COLUMN_NOT_NULL
238 #undef CREATE_TABLE_END
240 // RowBase5 class (== RowBase4 + default constructor)
242 #define CREATE_TABLE(name) namespace name { class RowBase5 : public RowBase4 { \
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() } }; }
248 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
251 #undef COLUMN_NOT_NULL
253 #undef CREATE_TABLE_END
255 // Row class (== RowBase5 + ForEachColumn )
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() } }; }
264 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
267 #undef COLUMN_NOT_NULL
269 #undef CREATE_TABLE_END
271 // Field structure declarations
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() }
279 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
282 #undef COLUMN_NOT_NULL
284 #undef CREATE_TABLE_END
286 // ColumnList typedef
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; }
293 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
296 #undef COLUMN_NOT_NULL
298 #undef CREATE_TABLE_END
300 // TableDefinition struct
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) \
312 Assert(interface != NULL); \
313 return interface->AllocDataCommand(statement); \
315 static void FreeTableDataCommand( \
316 DPL::DB::SqlConnection::DataCommand *command, \
317 IOrmInterface *interface) \
319 Assert(interface != NULL); \
320 interface->FreeDataCommand(command); \
322 static DPL::DB::SqlConnection::RowID GetLastInsertRowID( \
323 IOrmInterface *interface) \
325 Assert(interface != NULL); \
326 return interface->GetLastInsertRowID(); \
331 #define COLUMN_NOT_NULL(name, type, ...)
332 #define COLUMN(name, type, ...)
333 #define CREATE_TABLE_END()
335 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
338 #undef COLUMN_NOT_NULL
340 #undef CREATE_TABLE_END
344 #define CREATE_TABLE(name) \
346 typedef Select<TableDefinition> Select; \
347 typedef Insert<TableDefinition> Insert; \
348 typedef Delete<TableDefinition> Delete; \
349 typedef Update<TableDefinition> Update; \
351 #define COLUMN_NOT_NULL(name, type, ...)
352 #define COLUMN(name, type, ...)
353 #define CREATE_TABLE_END()
355 #include ORM_GENERATOR_DATABASE_NAME_LOCAL
358 #undef COLUMN_NOT_NULL
360 #undef CREATE_TABLE_END
372 #undef TABLE_CONSTRAINTS
374 #undef DATABASE_START
381 #undef ORM_GENERATOR_DATABASE_NAME
382 #undef ORM_GENERATOR_DATABASE_NAME_LOCAL