2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @author Bartosz Janiak (b.janiak@samsung.com)
20 * @brief DPL-ORM: Object-relational mapping for sqlite database, written on top of DPL.
30 #include <boost/optional.hpp>
32 #include <dpl/db/sql_connection.h>
33 #include <dpl/db/orm_interface.h>
34 #include <dpl/string.h>
35 #include <dpl/type_list.h>
36 #include <dpl/assert.h>
37 #include <dpl/foreach.h>
46 //TODO move to type utils
47 #define DPL_CHECK_TYPE_INSTANTIABILITY(type) \
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;
57 typedef size_t ColumnIndex;
58 typedef size_t ArgumentIndex;
59 typedef boost::optional<DPL::String> OptionalString;
60 typedef boost::optional<int> OptionalInteger;
61 typedef DPL::DB::SqlConnection::DataCommand DataCommand;
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
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);
80 class __attribute__ ((visibility("hidden"))) Expression {
82 virtual ~Expression() {}
83 virtual std::string GetString() const = 0;
84 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0;
87 typedef std::shared_ptr<Expression> ExpressionPtr;
89 namespace OrderingUtils {
91 template<typename CompoundType> inline std::string OrderByInternal()
93 std::string order = OrderByInternal<typename CompoundType::Tail>();
94 if(!order.empty()) return CompoundType::Head::GetString() + ", " + order;
95 else return CompoundType::Head::GetString();
98 template<> inline std::string OrderByInternal<TypeListGuard>()
100 return std::string();
105 template<typename ColumnType>
106 class __attribute__ ((visibility("hidden"))) OrderingExpression {
108 static std::string GetSchemaAndName()
110 std::string statement;
111 statement += ColumnType::GetTableName();
113 statement += ColumnType::GetColumnName();
118 virtual ~OrderingExpression() {}
121 template<const char* Operator, typename LeftExpression, typename RightExpression>
122 class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression {
124 LeftExpression m_leftExpression;
125 RightExpression m_rightExpression;
126 bool m_outerParenthesis;
128 BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
129 m_leftExpression(leftExpression),
130 m_rightExpression(rightExpression),
131 m_outerParenthesis(outerParenthesis)
134 virtual std::string GetString() const
136 return (m_outerParenthesis ? "( " : " " ) +
137 m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
138 (m_outerParenthesis ? " )" : " " ) ;
141 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
143 index = m_leftExpression.BindTo(command, index);
144 return m_rightExpression.BindTo(command, index);
147 template<typename TableDefinition>
148 struct ValidForTable {
149 typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
150 typename RightExpression::template ValidForTable<TableDefinition>::Yes >
155 template<typename LeftExpression, typename RightExpression>
156 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
157 And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
159 return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
160 (leftExpression, rightExpression);
163 template<typename LeftExpression, typename RightExpression>
164 BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
165 Or(const LeftExpression& leftExpression, const RightExpression& rightExpression)
167 return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
168 (leftExpression, rightExpression);
171 template<typename ArgumentType>
172 class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression {
174 ArgumentType argument;
177 explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
179 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
181 DataCommandUtils::BindArgument(command, index, argument);
186 template<typename ColumnData, const char* Relation>
187 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
189 explicit Compare(typename ColumnData::ColumnType column) :
190 ExpressionWithArgument<typename ColumnData::ColumnType>(column)
193 virtual std::string GetString() const
195 std::string statement;
196 statement += ColumnData::GetTableName();
198 statement += ColumnData::GetColumnName();
200 statement += Relation;
205 template<typename TableDefinition>
206 struct ValidForTable {
207 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
210 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \
211 template<typename ColumnData> \
212 class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> { \
214 name(typename ColumnData::ColumnType column) : \
215 Compare<ColumnData, RelationTypes::relationType>(column) \
219 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
220 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
222 #define ORM_DEFINE_ORDERING_EXPRESSION(name, value) \
223 template<typename ColumnType> \
224 class __attribute__ ((visibility("hidden"))) name \
225 : OrderingExpression<ColumnType> { \
227 static std::string GetString() \
229 std::string statement = OrderingExpression<ColumnType>::GetSchemaAndName(); \
230 statement += value; \
235 ORM_DEFINE_ORDERING_EXPRESSION(OrderingAscending, "ASC")
236 ORM_DEFINE_ORDERING_EXPRESSION(OrderingDescending, "DESC")
238 template<typename ColumnData1, typename ColumnData2>
239 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
241 std::string m_relation;
243 CompareBinaryColumn(const char* Relation) :
247 virtual ~CompareBinaryColumn() {}
249 virtual std::string GetString() const
251 std::string statement;
252 statement += ColumnData1::GetTableName();
254 statement += ColumnData1::GetColumnName();
256 statement += m_relation;
258 statement += ColumnData2::GetTableName();
260 statement += ColumnData2::GetColumnName();
266 template<typename ColumnData1, typename ColumnData2>
267 CompareBinaryColumn<ColumnData1, ColumnData2>
270 return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
273 template<typename ColumnData, const char* Relation>
274 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
276 std::set<typename ColumnData::ColumnType> m_argumentList;
278 NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
280 virtual std::string GetString() const
282 std::string statement;
283 statement += ColumnData::GetColumnName();
285 statement += Relation;
288 int argumentCount = m_argumentList.size();
304 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
306 ArgumentIndex argumentIndex = index;
307 FOREACH(argumentIt, m_argumentList)
309 DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
312 return argumentIndex + 1;
315 template<typename TableDefinition>
316 struct ValidForTable {
317 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
321 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \
322 template<typename ColumnData> \
323 class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> { \
325 name(std::set<typename ColumnData::ColumnType> column) : \
326 NumerousArguments<ColumnData, RelationTypes::relationType>(column) \
330 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
332 template<typename ColumnType>
333 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
335 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
337 CustomColumnBase() {}
338 virtual ~CustomColumnBase() {}
341 template<typename ColumnType>
342 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
344 ColumnType m_columnData;
348 CustomColumn(ColumnType data)
353 void SetColumnData(ColumnType data)
358 ColumnType GetColumnData() const
364 template<typename ColumnList>
365 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
367 static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
369 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
370 Type* pColumn = new Type();
371 columnList.push_back(pColumn);
372 CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
375 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
377 CopyColumnList(srcList, dstList, 0);
380 static ColumnIndex GetColumnIndex(const std::string& columnName)
382 return GetColumnIndex(columnName, 0);
386 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
388 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
389 Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
390 dstList.push_back(pColumn);
391 CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
394 static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
396 if (ColumnList::Head::GetColumnName() == columnName)
399 return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
402 template<typename Other>
403 friend class CustomRowUtil;
407 class __attribute__ ((visibility("hidden"))) CustomRowUtil<DPL::TypeListGuard> {
409 static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
411 static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
412 static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
414 template<typename Other>
415 friend class CustomRowUtil;
418 template<typename ColumnList>
419 class __attribute__ ((visibility("hidden"))) CustomRow {
421 std::vector<CustomColumnBase*> m_columns;
426 CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
429 CustomRow(const CustomRow& r)
431 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
436 while (!m_columns.empty())
438 CustomColumnBase* pCustomColumn = m_columns.back();
439 m_columns.pop_back();
441 delete pCustomColumn;
445 template<typename ColumnType>
446 void SetColumnData(ColumnIndex columnIndex, ColumnType data)
448 typedef CustomColumn<ColumnType> Type;
449 Assert(columnIndex < m_columns.size());
450 Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
452 pColumn->SetColumnData(data);
455 template<typename ColumnData>
456 typename ColumnData::ColumnType GetColumnData()
458 typedef CustomColumn<typename ColumnData::ColumnType> Type;
459 ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
460 Assert(index < m_columns.size());
461 Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
463 return pColumn->GetColumnData();
467 template<typename CustomRow, typename ColumnType>
468 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
470 row.SetColumnData<ColumnType>(columnIndex, columnData);
473 template<typename ColumnList, typename CustomRow>
474 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
476 static void FillCustomRow(CustomRow& row, DataCommand* command)
478 FillCustomRow(row, 0, command);
482 static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
484 typename ColumnList::Head::ColumnType columnData;
485 columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
486 SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
487 FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
490 template<typename Other, typename OtherRow>
491 friend class FillCustomRowUtil;
494 template<typename CustomRow>
495 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil<DPL::TypeListGuard, CustomRow> {
497 static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
498 { /* do nothing, we're past the last element of column list */ }
500 template<typename Other, typename OtherRow>
501 friend class FillCustomRowUtil;
504 template<typename ColumnList, typename Row>
505 class __attribute__ ((visibility("hidden"))) FillRowUtil {
507 static void FillRow(Row& row, DataCommand *command)
509 FillRow(row, 0, command);
513 static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
515 typename ColumnList::Head::ColumnType rowField;
516 rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
517 ColumnList::Head::SetRowField(row, rowField);
518 FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
521 template<typename Other, typename OtherRow>
522 friend class FillRowUtil;
525 template<typename Row>
526 class __attribute__ ((visibility("hidden"))) FillRowUtil<DPL::TypeListGuard, Row> {
528 static void FillRow(Row&, ColumnIndex, DataCommand *)
529 { /* do nothing, we're past the last element of column list */ }
531 template<typename Other, typename OtherRow>
532 friend class FillRowUtil;
535 template<typename ColumnList>
536 class __attribute__ ((visibility("hidden"))) JoinUtil {
538 static std::string GetColumnNames()
541 result = ColumnList::Head::GetTableName();
543 result += ColumnList::Head::GetColumnName();
544 if (ColumnList::Tail::Size > 0)
547 return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
550 static std::string GetJoinTableName(const std::string& tableName)
552 std::string joinTableName = ColumnList::Head::GetTableName();
553 if (tableName.find(joinTableName) == std::string::npos)
554 return joinTableName;
556 return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
561 class __attribute__ ((visibility("hidden"))) JoinUtil<DPL::TypeListGuard> {
563 static std::string GetColumnNames() { return ""; }
564 static std::string GetJoinTableName(std::string) { return ""; }
569 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
570 DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
571 DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
572 DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
575 template<typename TableDefinition>
576 class __attribute__ ((visibility("hidden"))) Query
579 explicit Query(IOrmInterface* interface) :
580 m_interface(interface),
587 if (m_command == NULL)
590 TableDefinition::FreeTableDataCommand(m_command, m_interface);
593 IOrmInterface* m_interface;
594 DataCommand *m_command;
595 std::string m_commandString;
596 ArgumentIndex m_bindArgumentIndex;
599 template<typename TableDefinition>
600 class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
603 ExpressionPtr m_whereExpression;
607 if ( !!m_whereExpression )
609 this->m_commandString += " WHERE ";
610 this->m_commandString += m_whereExpression->GetString();
616 if ( !!m_whereExpression )
618 this->m_bindArgumentIndex = m_whereExpression->BindTo(
619 this->m_command, this->m_bindArgumentIndex);
624 explicit QueryWithWhereClause(IOrmInterface* interface) :
625 Query<TableDefinition>(interface)
629 template<typename Expression>
630 void Where(const Expression& expression)
632 DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
633 if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
635 std::ostringstream str;
636 str << "Current ORM implementation doesn't allow to reuse Select"
637 " instance with different query signature (particularly "
638 "WHERE on different column).\n";
640 str << this->m_commandString;
641 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
644 //TODO maybe don't make a copy here but just generate the string part of the query.
645 m_whereExpression.reset(new Expression(expression));
650 template<typename TableDefinition>
651 class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
656 if ( !this->m_command)
658 this->m_commandString = "DELETE FROM ";
659 this->m_commandString += TableDefinition::GetName();
661 QueryWithWhereClause<TableDefinition>::Prepare();
663 this->m_command = TableDefinition::AllocTableDataCommand(
664 this->m_commandString.c_str(),
665 Query<TableDefinition>::m_interface);
666 LogPedantic("Prepared SQL command " << this->m_commandString);
672 this->m_bindArgumentIndex = 1;
673 QueryWithWhereClause<TableDefinition>::Bind();
677 explicit Delete(IOrmInterface *interface = NULL) :
678 QueryWithWhereClause<TableDefinition>(interface)
686 this->m_command->Step();
687 this->m_command->Reset();
694 DataCommand *m_command;
696 ArgumentIndex m_bindArgumentIndex;
698 BindVisitor(DataCommand *command) :
700 m_bindArgumentIndex(1)
703 template<typename ColumnType>
704 void Visit(const char*, const ColumnType& value, bool isSet)
708 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
709 m_bindArgumentIndex++;
713 } //anonymous namespace
714 template<typename TableDefinition>
715 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
718 typedef typename TableDefinition::Row Row;
719 typedef DPL::DB::SqlConnection::RowID RowID;
722 boost::optional<std::string> m_orClause;
725 class PrepareVisitor {
727 std::string m_columnNames;
728 std::string m_values;
730 template<typename ColumnType>
731 void Visit(const char* name, const ColumnType&, bool isSet)
735 if ( !m_columnNames.empty() )
737 m_columnNames += ", ";
740 m_columnNames += name;
748 if ( !this->m_command )
750 this->m_commandString = "INSERT ";
753 this->m_commandString += " OR " + *m_orClause + " ";
755 this->m_commandString += "INTO ";
756 this->m_commandString += TableDefinition::GetName();
758 PrepareVisitor visitor;
759 m_row.VisitColumns(visitor);
761 this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
762 this->m_commandString += "VALUES ( " + visitor.m_values + " )";
764 LogPedantic("Prepared SQL command " << this->m_commandString);
765 this->m_command = TableDefinition::AllocTableDataCommand(
766 this->m_commandString.c_str(),
767 Query<TableDefinition>::m_interface);
773 BindVisitor visitor(this->m_command);
774 m_row.VisitColumns(visitor);
779 IOrmInterface* interface = NULL,
780 const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
781 Query<TableDefinition>(interface),
786 void Values(const Row& row)
788 if ( this->m_command )
790 if ( !row.IsSignatureMatching(m_row) )
792 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
793 "Current ORM implementation doesn't allow to reuse Insert instance "
794 "with different query signature.");
804 this->m_command->Step();
806 RowID result = TableDefinition::GetLastInsertRowID(
807 Query<TableDefinition>::m_interface);
809 this->m_command->Reset();
814 template<typename TableDefinition>
815 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
818 typedef typename TableDefinition::ColumnList ColumnList;
819 typedef typename TableDefinition::Row Row;
821 typedef std::list<Row> RowList;
823 boost::optional<std::string> m_orderBy;
824 std::string m_JoinClause;
825 bool m_distinctResults;
827 void Prepare(const char* selectColumnName)
829 if ( !this->m_command )
831 this->m_commandString = "SELECT ";
832 if (m_distinctResults)
833 this->m_commandString += "DISTINCT ";
834 this->m_commandString += selectColumnName;
835 this->m_commandString += " FROM ";
836 this->m_commandString += TableDefinition::GetName();
838 this->m_commandString += m_JoinClause;
840 QueryWithWhereClause<TableDefinition>::Prepare();
844 this->m_commandString += " ORDER BY " + *m_orderBy;
847 this->m_command = TableDefinition::AllocTableDataCommand(
848 this->m_commandString.c_str(),
849 Query<TableDefinition>::m_interface);
851 LogPedantic("Prepared SQL command " << this->m_commandString);
857 this->m_bindArgumentIndex = 1;
858 QueryWithWhereClause<TableDefinition>::Bind();
861 template<typename ColumnType>
862 ColumnType GetColumn(ColumnIndex columnIndex)
864 return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
870 FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
874 template<typename ColumnList, typename CustomRow>
875 CustomRow GetCustomRow()
878 FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
884 explicit Select(IOrmInterface *interface = NULL) :
885 QueryWithWhereClause<TableDefinition>(interface),
886 m_distinctResults(false)
892 m_distinctResults = true;
895 template<typename CompoundType>
896 void OrderBy(const CompoundType&)
898 m_orderBy = OrderingUtils::OrderByInternal<typename CompoundType::Type>();
901 void OrderBy(const std::string & orderBy) //backward compatibility
906 void OrderBy(const char * orderBy) //backward compatibility
908 m_orderBy = std::string(orderBy);
911 template<typename ColumnList, typename Expression>
912 void Join(const Expression& expression) {
913 std::string usedTableNames = TableDefinition::GetName();
914 if (!m_JoinClause.empty())
915 usedTableNames += m_JoinClause;
917 this->m_JoinClause += " JOIN ";
918 this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
919 this->m_JoinClause += " ON ";
920 this->m_JoinClause += expression.GetString();
923 template<typename ColumnData>
924 typename ColumnData::ColumnType GetSingleValue()
926 Prepare(ColumnData::GetColumnName());
928 this->m_command->Step();
930 typename ColumnData::ColumnType result =
931 GetColumn<typename ColumnData::ColumnType>(0);
933 this->m_command->Reset();
937 //TODO return range - pair of custom iterators
938 template<typename ColumnData>
939 std::list<typename ColumnData::ColumnType> GetValueList()
941 Prepare(ColumnData::GetColumnName());
944 std::list<typename ColumnData::ColumnType> resultList;
946 while (this->m_command->Step())
947 resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
949 this->m_command->Reset();
957 this->m_command->Step();
959 Row result = GetRow();
961 this->m_command->Reset();
965 //TODO return range - pair of custom iterators
973 while (this->m_command->Step())
974 resultList.push_back(GetRow());
976 this->m_command->Reset();
980 template<typename ColumnList, typename CustomRow>
981 CustomRow GetCustomSingleRow()
983 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
985 this->m_command->Step();
987 CustomRow result = GetCustomRow<ColumnList, CustomRow>();
989 this->m_command->Reset();
993 template<typename ColumnList, typename CustomRow>
994 std::list<CustomRow> GetCustomRowList()
996 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
999 std::list<CustomRow> resultList;
1001 while (this->m_command->Step())
1002 resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
1004 this->m_command->Reset();
1009 template<typename TableDefinition>
1010 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
1012 typedef typename TableDefinition::Row Row;
1015 boost::optional<std::string> m_orClause;
1018 class PrepareVisitor {
1020 std::string m_setExpressions;
1022 template<typename ColumnType>
1023 void Visit(const char* name, const ColumnType&, bool isSet)
1027 if ( !m_setExpressions.empty() )
1029 m_setExpressions += ", ";
1031 m_setExpressions += name;
1032 m_setExpressions += " = ";
1033 m_setExpressions += "?";
1040 if ( !this->m_command )
1042 this->m_commandString = "UPDATE ";
1045 this->m_commandString += " OR " + *m_orClause + " ";
1047 this->m_commandString += TableDefinition::GetName();
1048 this->m_commandString += " SET ";
1050 // got through row columns and values
1051 PrepareVisitor visitor;
1052 m_row.VisitColumns(visitor);
1054 if(visitor.m_setExpressions.empty())
1056 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
1059 this->m_commandString += visitor.m_setExpressions;
1062 QueryWithWhereClause<TableDefinition>::Prepare();
1064 this->m_command = TableDefinition::AllocTableDataCommand(
1065 this->m_commandString.c_str(),
1066 Query<TableDefinition>::m_interface);
1067 LogPedantic("Prepared SQL command " << this->m_commandString);
1073 BindVisitor visitor(this->m_command);
1074 m_row.VisitColumns(visitor);
1076 this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1077 QueryWithWhereClause<TableDefinition>::Bind();
1082 explicit Update(IOrmInterface *interface = NULL,
1083 const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
1084 QueryWithWhereClause<TableDefinition>(interface),
1085 m_orClause(orClause)
1089 void Values(const Row& row)
1091 if ( this->m_command )
1093 if ( !row.IsSignatureMatching(m_row) )
1095 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1096 "Current ORM implementation doesn't allow to reuse Update instance "
1097 "with different query signature.");
1107 this->m_command->Step();
1108 this->m_command->Reset();