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