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