Tizen 2.0 Release
[framework/web/wrt-commons.git] / modules / db / include / dpl / db / orm.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.h
18  * @author      Bartosz Janiak (b.janiak@samsung.com)
19  * @version     1.0
20  * @brief       DPL-ORM: Object-relational mapping for sqlite database, written on top of DPL.
21  */
22
23 #include <cstdlib>
24 #include <cstdio>
25 #include <string>
26 #include <typeinfo>
27 #include <utility>
28 #include <set>
29 #include <memory>
30
31 #include <dpl/db/sql_connection.h>
32 #include <dpl/db/orm_interface.h>
33 #include <dpl/string.h>
34 #include <dpl/optional.h>
35 #include <dpl/type_list.h>
36 #include <dpl/assert.h>
37 #include <dpl/foreach.h>
38
39 #ifndef DPL_ORM_H
40 #define DPL_ORM_H
41
42 namespace DPL {
43 namespace DB {
44 namespace ORM {
45
46 //TODO move to type utils
47 #define DPL_CHECK_TYPE_INSTANTIABILITY(type) \
48     { \
49         type _ignored_; \
50         (void)_ignored_; \
51     }
52
53 #define DECLARE_COLUMN_TYPE_LIST() typedef DPL::TypeListDecl<
54 #define SELECTED_COLUMN(table_name, column_name) table_name::column_name,
55 #define DECLARE_COLUMN_TYPE_LIST_END(name) DPL::TypeListGuard>::Type name;
56
57 typedef size_t ColumnIndex;
58 typedef size_t ArgumentIndex;
59 typedef DPL::Optional<DPL::String> OptionalString;
60 typedef DPL::Optional<int> OptionalInteger;
61 typedef DPL::DB::SqlConnection::DataCommand DataCommand;
62
63 namespace RelationTypes {
64     extern const char Equal[];
65     extern const char LessThan[];
66     extern const char And[];
67     extern const char Or[];
68     extern const char Is[];
69     extern const char In[];
70     //TODO define more relation types
71 }
72
73 namespace DataCommandUtils {
74     //TODO move to DPL::DataCommand?
75     void BindArgument(DataCommand *command, ArgumentIndex index, int argument);
76     void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalInteger& argument);
77     void BindArgument(DataCommand *command, ArgumentIndex index, const DPL::String& argument);
78     void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalString& argument);
79 }
80 class __attribute__ ((visibility("hidden"))) Expression {
81 public:
82     virtual ~Expression() {}
83     virtual std::string GetString() const = 0;
84     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0;
85 };
86
87 typedef std::shared_ptr<Expression> ExpressionPtr;
88
89 template<const char* Operator, typename LeftExpression, typename RightExpression>
90 class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression {
91 protected:
92     LeftExpression  m_leftExpression;
93     RightExpression m_rightExpression;
94     bool            m_outerParenthesis;
95 public:
96     BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
97         m_leftExpression(leftExpression),
98         m_rightExpression(rightExpression),
99         m_outerParenthesis(outerParenthesis)
100     {}
101
102     virtual std::string GetString() const
103     {
104         return  (m_outerParenthesis ? "( " : " " ) +
105                  m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
106                 (m_outerParenthesis ? " )" : " " ) ;
107     }
108
109     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
110     {
111         index = m_leftExpression.BindTo(command, index);
112         return  m_rightExpression.BindTo(command, index);
113     }
114
115     template<typename TableDefinition>
116     struct ValidForTable {
117         typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
118                           typename RightExpression::template ValidForTable<TableDefinition>::Yes >
119                 Yes;
120     };
121 };
122
123 template<typename LeftExpression, typename RightExpression>
124 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
125     And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
126 {
127     return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
128             (leftExpression, rightExpression);
129 }
130
131 template<typename LeftExpression, typename RightExpression>
132 BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
133     Or(const LeftExpression& leftExpression, const RightExpression& rightExpression)
134 {
135     return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
136             (leftExpression, rightExpression);
137 }
138
139 template<typename ArgumentType>
140 class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression {
141 protected:
142     ArgumentType argument;
143
144 public:
145     explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
146
147     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
148     {
149         DataCommandUtils::BindArgument(command, index, argument);
150         return index + 1;
151     }
152 };
153
154 template<typename ColumnData, const char* Relation>
155 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
156 public:
157     explicit Compare(typename ColumnData::ColumnType column) :
158         ExpressionWithArgument<typename ColumnData::ColumnType>(column)
159     {}
160
161     virtual std::string GetString() const
162     {
163         std::string statement;
164         statement += ColumnData::GetTableName();
165         statement += ".";
166         statement += ColumnData::GetColumnName();
167         statement += " ";
168         statement += Relation;
169         statement += " ?";
170         return statement;
171     }
172
173     template<typename TableDefinition>
174     struct ValidForTable {
175         typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
176     };
177 };
178 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType)                      \
179     template<typename ColumnData>                                              \
180     class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> {     \
181     public:                                                                    \
182         name(typename ColumnData::ColumnType column) :                         \
183             Compare<ColumnData, RelationTypes::relationType>(column)           \
184         {}                                                                     \
185     };
186
187 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
188 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
189
190 template<typename ColumnData1, typename ColumnData2>
191 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
192 private:
193     std::string m_relation;
194 public:
195     CompareBinaryColumn(const char* Relation) :
196       m_relation(Relation)
197     {}
198
199     virtual ~CompareBinaryColumn() {}
200
201     virtual std::string GetString() const
202     {
203         std::string statement;
204         statement += ColumnData1::GetTableName();
205         statement += ".";
206         statement += ColumnData1::GetColumnName();
207         statement += " ";
208         statement += m_relation;
209         statement += " ";
210         statement += ColumnData2::GetTableName();
211         statement += ".";
212         statement += ColumnData2::GetColumnName();
213
214         return statement;
215     }
216 };
217
218 template<typename ColumnData1, typename ColumnData2>
219 CompareBinaryColumn<ColumnData1, ColumnData2>
220     Equal()
221 {
222     return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
223 }
224
225 template<typename ColumnData, const char* Relation>
226 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
227 protected:
228     std::set<typename ColumnData::ColumnType> m_argumentList;
229 public:
230     NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
231
232     virtual std::string GetString() const
233     {
234         std::string statement;
235         statement += ColumnData::GetColumnName();
236         statement += " ";
237         statement += Relation;
238         statement += " ( ";
239
240         int argumentCount = m_argumentList.size();
241         while(argumentCount)
242         {
243             statement += "?";
244             argumentCount--;
245             if (argumentCount)
246             {
247                 statement += ", ";
248             }
249         }
250
251         statement += " )";
252
253         return statement;
254     }
255
256     virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
257     {
258         ArgumentIndex argumentIndex = index;
259         FOREACH(argumentIt, m_argumentList)
260         {
261             DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
262             argumentIndex++;
263         }
264         return  argumentIndex + 1;
265     }
266
267     template<typename TableDefinition>
268     struct ValidForTable {
269         typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
270     };
271 };
272
273 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType)                      \
274     template<typename ColumnData>                                              \
275     class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> {     \
276     public:                                                                    \
277         name(std::set<typename ColumnData::ColumnType> column) :                         \
278             NumerousArguments<ColumnData, RelationTypes::relationType>(column)           \
279         {}                                                                     \
280     };
281
282 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
283
284 template<typename ColumnType>
285 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
286
287 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
288 public:
289     CustomColumnBase() {}
290     virtual ~CustomColumnBase() {}
291 };
292
293 template<typename ColumnType>
294 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
295 private:
296     ColumnType m_columnData;
297
298 public:
299     CustomColumn() {}
300     CustomColumn(ColumnType data)
301     {
302         m_columnData = data;
303     }
304
305     void SetColumnData(ColumnType data)
306     {
307         m_columnData = data;
308     }
309
310     ColumnType GetColumnData() const
311     {
312         return m_columnData;
313     }
314 };
315
316 template<typename ColumnList>
317 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
318 public:
319     static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
320     {
321         typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
322         Type* pColumn = new Type();
323         columnList.push_back(pColumn);
324         CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
325     }
326
327     static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
328     {
329         CopyColumnList(srcList, dstList, 0);
330     }
331
332     static ColumnIndex GetColumnIndex(const std::string& columnName)
333     {
334         return GetColumnIndex(columnName, 0);
335     }
336
337 private:
338     static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
339     {
340         typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
341         Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
342         dstList.push_back(pColumn);
343         CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
344     }
345
346     static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
347     {
348         if (ColumnList::Head::GetColumnName() == columnName)
349             return index;
350
351         return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
352     }
353
354 template<typename Other>
355 friend class CustomRowUtil;
356 };
357
358 template<>
359 class __attribute__ ((visibility("hidden"))) CustomRowUtil<DPL::TypeListGuard> {
360 public:
361     static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
362 private:
363     static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
364     static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
365
366 template<typename Other>
367 friend class CustomRowUtil;
368 };
369
370 template<typename ColumnList>
371 class __attribute__ ((visibility("hidden"))) CustomRow {
372 private:
373     std::vector<CustomColumnBase*> m_columns;
374
375 public:
376     CustomRow()
377     {
378         CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
379     }
380
381     CustomRow(const CustomRow& r)
382     {
383         CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
384     }
385
386     virtual ~CustomRow()
387     {
388         while (!m_columns.empty())
389         {
390             CustomColumnBase* pCustomColumn = m_columns.back();
391             m_columns.pop_back();
392             if (pCustomColumn)
393                 delete pCustomColumn;
394         }
395     }
396
397     template<typename ColumnType>
398     void SetColumnData(ColumnIndex columnIndex, ColumnType data)
399     {
400         typedef CustomColumn<ColumnType> Type;
401         Assert(columnIndex < m_columns.size());
402         Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
403         Assert(pColumn);
404         pColumn->SetColumnData(data);
405     }
406
407     template<typename ColumnData>
408     typename ColumnData::ColumnType GetColumnData()
409     {
410         typedef CustomColumn<typename ColumnData::ColumnType> Type;
411         ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
412         Assert(index < m_columns.size());
413         Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
414         Assert(pColumn);
415         return pColumn->GetColumnData();
416     }
417 };
418
419 template<typename CustomRow, typename ColumnType>
420 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
421 {
422     row.SetColumnData<ColumnType>(columnIndex, columnData);
423 }
424
425 template<typename ColumnList, typename CustomRow>
426 class  __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
427 public:
428     static void FillCustomRow(CustomRow& row, DataCommand* command)
429     {
430         FillCustomRow(row, 0, command);
431     }
432
433 private:
434     static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
435     {
436         typename ColumnList::Head::ColumnType columnData;
437         columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
438         SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
439         FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
440     }
441
442 template<typename Other, typename OtherRow>
443 friend class FillCustomRowUtil;
444 };
445
446 template<typename CustomRow>
447 class  __attribute__ ((visibility("hidden"))) FillCustomRowUtil<DPL::TypeListGuard, CustomRow> {
448 private:
449     static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
450     { /* do nothing, we're past the last element of column list */ }
451
452 template<typename Other, typename OtherRow>
453 friend class FillCustomRowUtil;
454 };
455
456 template<typename ColumnList, typename Row>
457 class  __attribute__ ((visibility("hidden"))) FillRowUtil {
458 public:
459     static void FillRow(Row& row, DataCommand *command)
460     {
461         FillRow(row, 0, command);
462     }
463
464 private:
465     static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
466     {
467         typename ColumnList::Head::ColumnType rowField;
468         rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
469         ColumnList::Head::SetRowField(row, rowField);
470         FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
471     }
472
473 template<typename Other, typename OtherRow>
474 friend class FillRowUtil;
475 };
476
477 template<typename Row>
478 class  __attribute__ ((visibility("hidden"))) FillRowUtil<DPL::TypeListGuard, Row> {
479 private:
480     static void FillRow(Row&, ColumnIndex, DataCommand *)
481     { /* do nothing, we're past the last element of column list */ }
482
483 template<typename Other, typename OtherRow>
484 friend class FillRowUtil;
485 };
486
487 template<typename ColumnList>
488 class  __attribute__ ((visibility("hidden"))) JoinUtil {
489 public:
490     static std::string GetColumnNames()
491     {
492         std::string result;
493         result = ColumnList::Head::GetTableName();
494         result += ".";
495         result += ColumnList::Head::GetColumnName();
496         if (ColumnList::Tail::Size > 0)
497             result += ", ";
498
499         return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
500     }
501
502     static std::string GetJoinTableName(const std::string& tableName)
503     {
504         std::string joinTableName = ColumnList::Head::GetTableName();
505         if (tableName.find(joinTableName) == std::string::npos)
506             return joinTableName;
507
508         return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
509     }
510 };
511
512 template<>
513 class  __attribute__ ((visibility("hidden"))) JoinUtil<DPL::TypeListGuard> {
514 public:
515     static std::string GetColumnNames() { return ""; }
516     static std::string GetJoinTableName(std::string) { return ""; }
517 };
518
519 class Exception {
520 public:
521     DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
522     DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
523     DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
524     DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
525 };
526
527 template<typename TableDefinition>
528 class  __attribute__ ((visibility("hidden"))) Query
529 {
530 protected:
531     explicit Query(IOrmInterface* interface) :
532         m_interface(interface),
533         m_command(NULL)
534     {
535     }
536
537     virtual ~Query()
538     {
539         if (m_command == NULL)
540             return;
541
542         TableDefinition::FreeTableDataCommand(m_command, m_interface);
543     }
544
545     IOrmInterface* m_interface;
546     DataCommand *m_command;
547     std::string m_commandString;
548     ArgumentIndex m_bindArgumentIndex;
549 };
550
551 template<typename TableDefinition>
552 class  __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
553 {
554 protected:
555     ExpressionPtr m_whereExpression;
556
557     void Prepare()
558     {
559         if ( !!m_whereExpression )
560         {
561             this->m_commandString += " WHERE ";
562             this->m_commandString += m_whereExpression->GetString();
563         }
564     }
565
566     void Bind()
567     {
568         if ( !!m_whereExpression )
569         {
570             this->m_bindArgumentIndex = m_whereExpression->BindTo(
571                 this->m_command, this->m_bindArgumentIndex);
572         }
573     }
574
575 public:
576     explicit QueryWithWhereClause(IOrmInterface* interface) :
577         Query<TableDefinition>(interface)
578     {
579     }
580
581     template<typename Expression>
582     void Where(const Expression& expression)
583     {
584         DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
585         if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
586         {
587             std::ostringstream str;
588             str << "Current ORM implementation doesn't allow to reuse Select"
589                     " instance with different query signature (particularly "
590                     "WHERE on different column).\n";
591             str << "Query: ";
592             str << this->m_commandString;
593             ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
594                 str.str());
595         }
596         //TODO maybe don't make a copy here but just generate the string part of the query.
597         m_whereExpression.reset(new Expression(expression));
598     }
599
600 };
601
602 template<typename TableDefinition>
603 class  __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
604 {
605 protected:
606     void Prepare()
607     {
608         if ( !this->m_command)
609         {
610             this->m_commandString  = "DELETE FROM ";
611             this->m_commandString += TableDefinition::GetName();
612
613             QueryWithWhereClause<TableDefinition>::Prepare();
614
615             this->m_command = TableDefinition::AllocTableDataCommand(
616                     this->m_commandString.c_str(),
617                     Query<TableDefinition>::m_interface);
618             LogPedantic("Prepared SQL command " << this->m_commandString);
619         }
620     }
621
622     void Bind()
623     {
624         this->m_bindArgumentIndex = 1;
625         QueryWithWhereClause<TableDefinition>::Bind();
626     }
627
628 public:
629     explicit Delete(IOrmInterface *interface = NULL) :
630         QueryWithWhereClause<TableDefinition>(interface)
631     {
632     }
633
634     void Execute()
635     {
636         Prepare();
637         Bind();
638         this->m_command->Step();
639         this->m_command->Reset();
640     }
641 };
642
643 namespace {
644 class BindVisitor {
645 private:
646     DataCommand *m_command;
647 public:
648     ArgumentIndex m_bindArgumentIndex;
649
650     BindVisitor(DataCommand *command) :
651         m_command(command),
652         m_bindArgumentIndex(1)
653     {}
654
655     template<typename ColumnType>
656     void Visit(const char*, const ColumnType& value, bool isSet)
657     {
658         if ( isSet )
659         {
660             DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
661             m_bindArgumentIndex++;
662         }
663     }
664 };
665 } //anonymous namespace
666 template<typename TableDefinition>
667 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
668 {
669 public:
670     typedef typename TableDefinition::Row Row;
671     typedef DPL::DB::SqlConnection::RowID RowID;
672
673 protected:
674     DPL::Optional<std::string> m_orClause;
675     Row m_row;
676
677     class PrepareVisitor {
678     public:
679         std::string m_columnNames;
680         std::string m_values;
681
682         template<typename ColumnType>
683         void Visit(const char* name, const ColumnType&, bool isSet)
684         {
685             if ( isSet )
686             {
687                 if ( !m_columnNames.empty() )
688                 {
689                     m_columnNames += ", ";
690                     m_values += ", ";
691                 }
692                 m_columnNames += name;
693                 m_values += "?";
694             }
695         }
696     };
697
698     void Prepare()
699     {
700         if ( !this->m_command )
701         {
702             this->m_commandString = "INSERT ";
703             if ( !!m_orClause )
704             {
705                 this->m_commandString += " OR " + *m_orClause + " ";
706             }
707             this->m_commandString += "INTO ";
708             this->m_commandString += TableDefinition::GetName();
709
710             PrepareVisitor visitor;
711             m_row.VisitColumns(visitor);
712
713             this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
714             this->m_commandString += "VALUES ( " + visitor.m_values + " )";
715
716             LogPedantic("Prepared SQL command " << this->m_commandString);
717             this->m_command = TableDefinition::AllocTableDataCommand(
718                 this->m_commandString.c_str(),
719                 Query<TableDefinition>::m_interface);
720         }
721     }
722
723     void Bind()
724     {
725         BindVisitor visitor(this->m_command);
726         m_row.VisitColumns(visitor);
727     }
728
729 public:
730     explicit Insert(
731             IOrmInterface* interface = NULL,
732             const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
733         Query<TableDefinition>(interface),
734         m_orClause(orClause)
735     {
736     }
737
738     void Values(const Row& row)
739     {
740         if ( this->m_command )
741         {
742             if ( !row.IsSignatureMatching(m_row) )
743             {
744                 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
745                     "Current ORM implementation doesn't allow to reuse Insert instance "
746                     "with different query signature.");
747             }
748         }
749         m_row = row;
750     }
751
752     RowID Execute()
753     {
754         Prepare();
755         Bind();
756         this->m_command->Step();
757
758         RowID result = TableDefinition::GetLastInsertRowID(
759             Query<TableDefinition>::m_interface);
760
761         this->m_command->Reset();
762         return result;
763     }
764 };
765
766 template<typename TableDefinition>
767 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
768 {
769 public:
770     typedef typename TableDefinition::ColumnList       ColumnList;
771     typedef typename TableDefinition::Row              Row;
772
773     typedef std::list<Row>                             RowList;
774 protected:
775     DPL::Optional<std::string> m_orderBy;
776     std::string m_JoinClause;
777     bool                       m_distinctResults;
778
779     void Prepare(const char* selectColumnName)
780     {
781         if ( !this->m_command )
782         {
783             this->m_commandString  = "SELECT ";
784             if (m_distinctResults)
785                 this->m_commandString += "DISTINCT ";
786             this->m_commandString += selectColumnName;
787             this->m_commandString += " FROM ";
788             this->m_commandString += TableDefinition::GetName();
789
790             this->m_commandString += m_JoinClause;
791
792             QueryWithWhereClause<TableDefinition>::Prepare();
793
794             if ( !m_orderBy.IsNull() )
795             {
796                 this->m_commandString += " ORDER BY " + *m_orderBy;
797             }
798
799             this->m_command = TableDefinition::AllocTableDataCommand(
800                 this->m_commandString.c_str(),
801                 Query<TableDefinition>::m_interface);
802
803             LogPedantic("Prepared SQL command " << this->m_commandString);
804         }
805     }
806
807     void Bind()
808     {
809         this->m_bindArgumentIndex = 1;
810         QueryWithWhereClause<TableDefinition>::Bind();
811     }
812
813     template<typename ColumnType>
814     ColumnType GetColumn(ColumnIndex columnIndex)
815     {
816         return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
817     }
818
819     Row GetRow()
820     {
821         Row row;
822         FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
823         return row;
824     }
825
826     template<typename ColumnList, typename CustomRow>
827     CustomRow GetCustomRow()
828     {
829         CustomRow row;
830         FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
831         return row;
832     }
833
834 public:
835
836     explicit Select(IOrmInterface *interface = NULL) :
837         QueryWithWhereClause<TableDefinition>(interface),
838         m_distinctResults(false)
839     {
840     }
841
842     void Distinct()
843     {
844         m_distinctResults = true;
845     }
846
847     void OrderBy(const std::string& orderBy)
848     {
849         m_orderBy = orderBy;
850     }
851
852     template<typename ColumnList, typename Expression>
853     void Join(const Expression& expression) {
854         std::string usedTableNames = TableDefinition::GetName();
855         if (!m_JoinClause.empty())
856             usedTableNames += m_JoinClause;
857
858         this->m_JoinClause += " JOIN ";
859         this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
860         this->m_JoinClause += " ON ";
861         this->m_JoinClause += expression.GetString();
862     }
863
864     template<typename ColumnData>
865     typename ColumnData::ColumnType GetSingleValue()
866     {
867         Prepare(ColumnData::GetColumnName());
868         Bind();
869         this->m_command->Step();
870
871         typename ColumnData::ColumnType result =
872             GetColumn<typename ColumnData::ColumnType>(0);
873
874         this->m_command->Reset();
875         return result;
876     }
877
878     //TODO return range - pair of custom iterators
879     template<typename ColumnData>
880     std::list<typename ColumnData::ColumnType> GetValueList()
881     {
882         Prepare(ColumnData::GetColumnName());
883         Bind();
884
885         std::list<typename ColumnData::ColumnType> resultList;
886
887         while (this->m_command->Step())
888             resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
889
890         this->m_command->Reset();
891         return resultList;
892     }
893
894     Row GetSingleRow()
895     {
896         Prepare("*");
897         Bind();
898         this->m_command->Step();
899
900         Row result = GetRow();
901
902         this->m_command->Reset();
903         return result;
904     }
905
906     //TODO return range - pair of custom iterators
907     RowList GetRowList()
908     {
909         Prepare("*");
910         Bind();
911
912         RowList resultList;
913
914         while (this->m_command->Step())
915             resultList.push_back(GetRow());
916
917         this->m_command->Reset();
918         return resultList;
919     }
920
921     template<typename ColumnList, typename CustomRow>
922     CustomRow GetCustomSingleRow()
923     {
924         Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
925         Bind();
926         this->m_command->Step();
927
928         CustomRow result = GetCustomRow<ColumnList, CustomRow>();
929
930         this->m_command->Reset();
931         return result;
932     }
933
934     template<typename ColumnList, typename CustomRow>
935     std::list<CustomRow> GetCustomRowList()
936     {
937         Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
938         Bind();
939
940         std::list<CustomRow> resultList;
941
942         while (this->m_command->Step())
943             resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
944
945         this->m_command->Reset();
946         return resultList;
947     }
948 };
949
950 template<typename TableDefinition>
951 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
952 public:
953     typedef typename TableDefinition::Row Row;
954
955 protected:
956     DPL::Optional<std::string> m_orClause;
957     Row m_row;
958
959     class PrepareVisitor {
960     public:
961         std::string m_setExpressions;
962
963         template<typename ColumnType>
964         void Visit(const char* name, const ColumnType&, bool isSet)
965         {
966             if ( isSet )
967             {
968                 if ( !m_setExpressions.empty() )
969                 {
970                     m_setExpressions += ", ";
971                 }
972                 m_setExpressions += name;
973                 m_setExpressions += " = ";
974                 m_setExpressions += "?";
975             }
976         }
977     };
978
979     void Prepare()
980     {
981         if ( !this->m_command )
982         {
983             this->m_commandString = "UPDATE ";
984             if ( !!m_orClause )
985             {
986                 this->m_commandString += " OR " + *m_orClause + " ";
987             }
988             this->m_commandString += TableDefinition::GetName();
989             this->m_commandString += " SET ";
990
991             // got through row columns and values
992             PrepareVisitor visitor;
993             m_row.VisitColumns(visitor);
994
995             if(visitor.m_setExpressions.empty())
996             {
997                 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
998             }
999
1000             this->m_commandString += visitor.m_setExpressions;
1001
1002             // where
1003             QueryWithWhereClause<TableDefinition>::Prepare();
1004
1005             this->m_command = TableDefinition::AllocTableDataCommand(
1006                     this->m_commandString.c_str(),
1007                     Query<TableDefinition>::m_interface);
1008             LogPedantic("Prepared SQL command " << this->m_commandString);
1009         }
1010     }
1011
1012     void Bind()
1013     {
1014         BindVisitor visitor(this->m_command);
1015         m_row.VisitColumns(visitor);
1016
1017         this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1018         QueryWithWhereClause<TableDefinition>::Bind();
1019     }
1020
1021
1022 public:
1023     explicit Update(IOrmInterface *interface = NULL,
1024                     const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
1025         QueryWithWhereClause<TableDefinition>(interface),
1026         m_orClause(orClause)
1027     {
1028     }
1029
1030     void Values(const Row& row)
1031     {
1032         if ( this->m_command )
1033         {
1034             if ( !row.IsSignatureMatching(m_row) )
1035             {
1036                 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1037                     "Current ORM implementation doesn't allow to reuse Update instance "
1038                     "with different query signature.");
1039             }
1040         }
1041         m_row = row;
1042     }
1043
1044     void Execute()
1045     {
1046         Prepare();
1047         Bind();
1048         this->m_command->Step();
1049         this->m_command->Reset();
1050     }
1051 };
1052
1053 } //namespace ORM
1054 } //namespace DB
1055 } //namespace DPL
1056
1057 #endif // DPL_ORM_H