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