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