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.
31 #include <boost/optional.hpp>
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>
48 //TODO move to type utils
49 #define DPL_CHECK_TYPE_INSTANTIABILITY(type) \
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;
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;
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
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);
82 class __attribute__ ((visibility("hidden"))) Expression {
84 virtual ~Expression() {}
85 virtual std::string GetString() const = 0;
86 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0;
89 typedef std::shared_ptr<Expression> ExpressionPtr;
91 namespace OrderingUtils {
93 template<typename CompoundType> inline std::string OrderByInternal()
95 std::string order = OrderByInternal<typename CompoundType::Tail>();
96 if(!order.empty()) return CompoundType::Head::GetString() + ", " + order;
97 else return CompoundType::Head::GetString();
100 template<> inline std::string OrderByInternal<TypeListGuard>()
102 return std::string();
107 template<typename ColumnType>
108 class __attribute__ ((visibility("hidden"))) OrderingExpression {
110 static std::string GetSchemaAndName()
112 std::string statement;
113 statement += ColumnType::GetTableName();
115 statement += ColumnType::GetColumnName();
120 virtual ~OrderingExpression() {}
123 template<const char* Operator, typename LeftExpression, typename RightExpression>
124 class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression {
126 LeftExpression m_leftExpression;
127 RightExpression m_rightExpression;
128 bool m_outerParenthesis;
130 BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
131 m_leftExpression(leftExpression),
132 m_rightExpression(rightExpression),
133 m_outerParenthesis(outerParenthesis)
136 virtual std::string GetString() const
138 return (m_outerParenthesis ? "( " : " " ) +
139 m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
140 (m_outerParenthesis ? " )" : " " ) ;
143 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
145 index = m_leftExpression.BindTo(command, index);
146 return m_rightExpression.BindTo(command, index);
149 template<typename TableDefinition>
150 struct ValidForTable {
151 typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
152 typename RightExpression::template ValidForTable<TableDefinition>::Yes >
157 template<typename LeftExpression, typename RightExpression>
158 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
159 And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
161 return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
162 (leftExpression, rightExpression);
165 template<typename LeftExpression, typename RightExpression>
166 BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
167 Or(const LeftExpression& leftExpression, const RightExpression& rightExpression)
169 return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
170 (leftExpression, rightExpression);
173 template<typename ArgumentType>
174 class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression {
176 ArgumentType argument;
179 explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
181 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
183 DataCommandUtils::BindArgument(command, index, argument);
188 template<typename ColumnData, const char* Relation>
189 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
191 explicit Compare(typename ColumnData::ColumnType column) :
192 ExpressionWithArgument<typename ColumnData::ColumnType>(column)
195 virtual std::string GetString() const
197 std::string statement;
198 statement += ColumnData::GetTableName();
200 statement += ColumnData::GetColumnName();
202 statement += Relation;
207 template<typename TableDefinition>
208 struct ValidForTable {
209 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
212 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \
213 template<typename ColumnData> \
214 class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> { \
216 name(typename ColumnData::ColumnType column) : \
217 Compare<ColumnData, RelationTypes::relationType>(column) \
221 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
222 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
224 #define ORM_DEFINE_ORDERING_EXPRESSION(name, value) \
225 template<typename ColumnType> \
226 class __attribute__ ((visibility("hidden"))) name \
227 : OrderingExpression<ColumnType> { \
229 static std::string GetString() \
231 std::string statement = OrderingExpression<ColumnType>::GetSchemaAndName(); \
232 statement += value; \
237 ORM_DEFINE_ORDERING_EXPRESSION(OrderingAscending, "ASC")
238 ORM_DEFINE_ORDERING_EXPRESSION(OrderingDescending, "DESC")
240 template<typename ColumnData1, typename ColumnData2>
241 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
243 std::string m_relation;
245 CompareBinaryColumn(const char* Relation) :
249 virtual ~CompareBinaryColumn() {}
251 virtual std::string GetString() const
253 std::string statement;
254 statement += ColumnData1::GetTableName();
256 statement += ColumnData1::GetColumnName();
258 statement += m_relation;
260 statement += ColumnData2::GetTableName();
262 statement += ColumnData2::GetColumnName();
268 template<typename ColumnData1, typename ColumnData2>
269 CompareBinaryColumn<ColumnData1, ColumnData2>
272 return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
275 template<typename ColumnData, const char* Relation>
276 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
278 std::set<typename ColumnData::ColumnType> m_argumentList;
280 NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
282 virtual std::string GetString() const
284 std::string statement;
285 statement += ColumnData::GetColumnName();
287 statement += Relation;
290 int argumentCount = m_argumentList.size();
306 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
308 ArgumentIndex argumentIndex = index;
309 FOREACH(argumentIt, m_argumentList)
311 DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
314 return argumentIndex + 1;
317 template<typename TableDefinition>
318 struct ValidForTable {
319 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
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> { \
327 name(std::set<typename ColumnData::ColumnType> column) : \
328 NumerousArguments<ColumnData, RelationTypes::relationType>(column) \
332 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
334 template<typename ColumnType>
335 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
337 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
339 CustomColumnBase() {}
340 virtual ~CustomColumnBase() {}
343 template<typename ColumnType>
344 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
346 ColumnType m_columnData;
350 CustomColumn(ColumnType data)
355 void SetColumnData(ColumnType data)
360 ColumnType GetColumnData() const
366 template<typename ColumnList>
367 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
369 static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
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);
377 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
379 CopyColumnList(srcList, dstList, 0);
382 static ColumnIndex GetColumnIndex(const std::string& columnName)
384 return GetColumnIndex(columnName, 0);
388 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
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);
396 static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
398 if (ColumnList::Head::GetColumnName() == columnName)
401 return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
404 template<typename Other>
405 friend class CustomRowUtil;
409 class __attribute__ ((visibility("hidden"))) CustomRowUtil<DPL::TypeListGuard> {
411 static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
413 static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
414 static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
416 template<typename Other>
417 friend class CustomRowUtil;
420 template<typename ColumnList>
421 class __attribute__ ((visibility("hidden"))) CustomRow {
423 std::vector<CustomColumnBase*> m_columns;
428 CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
431 CustomRow(const CustomRow& r)
433 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
435 CustomRow& operator=(const CustomRow& r)
437 if(this == &r) return *this;
438 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
444 while (!m_columns.empty())
446 CustomColumnBase* pCustomColumn = m_columns.back();
447 m_columns.pop_back();
449 delete pCustomColumn;
453 template<typename ColumnType>
454 void SetColumnData(ColumnIndex columnIndex, ColumnType data)
456 typedef CustomColumn<ColumnType> Type;
457 Assert(columnIndex < m_columns.size());
458 Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
460 pColumn->SetColumnData(data);
463 template<typename ColumnData>
464 typename ColumnData::ColumnType GetColumnData()
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));
471 return pColumn->GetColumnData();
475 template<typename CustomRow, typename ColumnType>
476 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
478 row.SetColumnData<ColumnType>(columnIndex, columnData);
481 template<typename ColumnList, typename CustomRow>
482 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
484 static void FillCustomRow(CustomRow& row, DataCommand* command)
486 FillCustomRow(row, 0, command);
490 static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
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);
498 template<typename Other, typename OtherRow>
499 friend class FillCustomRowUtil;
502 template<typename CustomRow>
503 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil<DPL::TypeListGuard, CustomRow> {
505 static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
506 { /* do nothing, we're past the last element of column list */ }
508 template<typename Other, typename OtherRow>
509 friend class FillCustomRowUtil;
512 template<typename ColumnList, typename Row>
513 class __attribute__ ((visibility("hidden"))) FillRowUtil {
515 static void FillRow(Row& row, DataCommand *command)
517 FillRow(row, 0, command);
521 static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
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);
529 template<typename Other, typename OtherRow>
530 friend class FillRowUtil;
533 template<typename Row>
534 class __attribute__ ((visibility("hidden"))) FillRowUtil<DPL::TypeListGuard, Row> {
536 static void FillRow(Row&, ColumnIndex, DataCommand *)
537 { /* do nothing, we're past the last element of column list */ }
539 template<typename Other, typename OtherRow>
540 friend class FillRowUtil;
543 template<typename ColumnList>
544 class __attribute__ ((visibility("hidden"))) JoinUtil {
546 static std::string GetColumnNames()
549 result = ColumnList::Head::GetTableName();
551 result += ColumnList::Head::GetColumnName();
552 if (ColumnList::Tail::Size > 0)
555 return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
558 static std::string GetJoinTableName(const std::string& tableName)
560 std::string joinTableName = ColumnList::Head::GetTableName();
561 if (tableName.find(joinTableName) == std::string::npos)
562 return joinTableName;
564 return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
569 class __attribute__ ((visibility("hidden"))) JoinUtil<DPL::TypeListGuard> {
571 static std::string GetColumnNames() { return ""; }
572 static std::string GetJoinTableName(std::string) { return ""; }
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)
583 template<typename TableDefinition>
584 class __attribute__ ((visibility("hidden"))) Query
587 explicit Query(IOrmInterface* interface) :
588 m_interface(interface),
595 if (m_command == NULL)
598 TableDefinition::FreeTableDataCommand(m_command, m_interface);
601 IOrmInterface* m_interface;
602 DataCommand *m_command;
603 std::string m_commandString;
604 ArgumentIndex m_bindArgumentIndex;
607 template<typename TableDefinition>
608 class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
611 ExpressionPtr m_whereExpression;
615 if ( !!m_whereExpression )
617 this->m_commandString += " WHERE ";
618 this->m_commandString += m_whereExpression->GetString();
624 if ( !!m_whereExpression )
626 this->m_bindArgumentIndex = m_whereExpression->BindTo(
627 this->m_command, this->m_bindArgumentIndex);
632 explicit QueryWithWhereClause(IOrmInterface* interface) :
633 Query<TableDefinition>(interface)
637 template<typename Expression>
638 void Where(const Expression& expression)
640 DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
641 if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
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";
648 str << this->m_commandString;
649 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
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));
658 template<typename TableDefinition>
659 class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
664 if ( !this->m_command)
666 this->m_commandString = "DELETE FROM ";
667 this->m_commandString += TableDefinition::GetName();
669 QueryWithWhereClause<TableDefinition>::Prepare();
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());
680 this->m_bindArgumentIndex = 1;
681 QueryWithWhereClause<TableDefinition>::Bind();
685 explicit Delete(IOrmInterface *interface = NULL) :
686 QueryWithWhereClause<TableDefinition>(interface)
694 this->m_command->Step();
695 this->m_command->Reset();
702 DataCommand *m_command;
704 ArgumentIndex m_bindArgumentIndex;
706 BindVisitor(DataCommand *command) :
708 m_bindArgumentIndex(1)
711 template<typename ColumnType>
712 void Visit(const char*, const ColumnType& value, bool isSet)
716 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
717 m_bindArgumentIndex++;
721 } //anonymous namespace
722 template<typename TableDefinition>
723 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
726 typedef typename TableDefinition::Row Row;
727 typedef DPL::DB::SqlConnection::RowID RowID;
730 boost::optional<std::string> m_orClause;
733 class PrepareVisitor {
735 std::string m_columnNames;
736 std::string m_values;
738 template<typename ColumnType>
739 void Visit(const char* name, const ColumnType&, bool isSet)
743 if ( !m_columnNames.empty() )
745 m_columnNames += ", ";
748 m_columnNames += name;
756 if ( !this->m_command )
758 this->m_commandString = "INSERT ";
761 this->m_commandString += " OR " + *m_orClause + " ";
763 this->m_commandString += "INTO ";
764 this->m_commandString += TableDefinition::GetName();
766 PrepareVisitor visitor;
767 m_row.VisitColumns(visitor);
769 this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
770 this->m_commandString += "VALUES ( " + visitor.m_values + " )";
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);
781 BindVisitor visitor(this->m_command);
782 m_row.VisitColumns(visitor);
787 IOrmInterface* interface = NULL,
788 const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
789 Query<TableDefinition>(interface),
794 void Values(const Row& row)
796 if ( this->m_command )
798 if ( !row.IsSignatureMatching(m_row) )
800 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
801 "Current ORM implementation doesn't allow to reuse Insert instance "
802 "with different query signature.");
812 this->m_command->Step();
814 RowID result = TableDefinition::GetLastInsertRowID(
815 Query<TableDefinition>::m_interface);
817 this->m_command->Reset();
822 template<typename TableDefinition>
823 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
826 typedef typename TableDefinition::ColumnList ColumnList;
827 typedef typename TableDefinition::Row Row;
829 typedef std::list<Row> RowList;
831 boost::optional<std::string> m_orderBy;
832 std::string m_JoinClause;
833 bool m_distinctResults;
835 void Prepare(const char* selectColumnName)
837 if ( !this->m_command )
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();
846 this->m_commandString += m_JoinClause;
848 QueryWithWhereClause<TableDefinition>::Prepare();
852 this->m_commandString += " ORDER BY " + *m_orderBy;
855 this->m_command = TableDefinition::AllocTableDataCommand(
856 this->m_commandString.c_str(),
857 Query<TableDefinition>::m_interface);
859 //WrtLogD("Prepared SQL command %s", this->m_commandString.c_str());
865 this->m_bindArgumentIndex = 1;
866 QueryWithWhereClause<TableDefinition>::Bind();
869 template<typename ColumnType>
870 ColumnType GetColumn(ColumnIndex columnIndex)
872 return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
878 FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
882 template<typename ColumnList, typename CustomRow>
883 CustomRow GetCustomRow()
886 FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
892 explicit Select(IOrmInterface *interface = NULL) :
893 QueryWithWhereClause<TableDefinition>(interface),
894 m_distinctResults(false)
900 m_distinctResults = true;
903 template<typename CompoundType>
904 void OrderBy(const CompoundType&)
906 m_orderBy = OrderingUtils::OrderByInternal<typename CompoundType::Type>();
909 void OrderBy(const std::string & orderBy) //backward compatibility
914 void OrderBy(const char * orderBy) //backward compatibility
916 m_orderBy = std::string(orderBy);
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;
925 this->m_JoinClause += " JOIN ";
926 this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
927 this->m_JoinClause += " ON ";
928 this->m_JoinClause += expression.GetString();
931 template<typename ColumnData>
932 typename ColumnData::ColumnType GetSingleValue()
934 Prepare(ColumnData::GetColumnName());
936 this->m_command->Step();
938 typename ColumnData::ColumnType result =
939 GetColumn<typename ColumnData::ColumnType>(0);
941 this->m_command->Reset();
945 //TODO return range - pair of custom iterators
946 template<typename ColumnData>
947 std::list<typename ColumnData::ColumnType> GetValueList()
949 Prepare(ColumnData::GetColumnName());
952 std::list<typename ColumnData::ColumnType> resultList;
954 while (this->m_command->Step())
955 resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
957 this->m_command->Reset();
965 this->m_command->Step();
967 Row result = GetRow();
969 this->m_command->Reset();
973 //TODO return range - pair of custom iterators
981 while (this->m_command->Step())
982 resultList.push_back(GetRow());
984 this->m_command->Reset();
988 template<typename ColumnList, typename CustomRow>
989 CustomRow GetCustomSingleRow()
991 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
993 this->m_command->Step();
995 CustomRow result = GetCustomRow<ColumnList, CustomRow>();
997 this->m_command->Reset();
1001 template<typename ColumnList, typename CustomRow>
1002 std::list<CustomRow> GetCustomRowList()
1004 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
1007 std::list<CustomRow> resultList;
1009 while (this->m_command->Step())
1010 resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
1012 this->m_command->Reset();
1017 template<typename TableDefinition>
1018 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
1020 typedef typename TableDefinition::Row Row;
1023 boost::optional<std::string> m_orClause;
1026 class PrepareVisitor {
1028 std::string m_setExpressions;
1030 template<typename ColumnType>
1031 void Visit(const char* name, const ColumnType&, bool isSet)
1035 if ( !m_setExpressions.empty() )
1037 m_setExpressions += ", ";
1039 m_setExpressions += name;
1040 m_setExpressions += " = ";
1041 m_setExpressions += "?";
1048 if ( !this->m_command )
1050 this->m_commandString = "UPDATE ";
1053 this->m_commandString += " OR " + *m_orClause + " ";
1055 this->m_commandString += TableDefinition::GetName();
1056 this->m_commandString += " SET ";
1058 // got through row columns and values
1059 PrepareVisitor visitor;
1060 m_row.VisitColumns(visitor);
1062 if(visitor.m_setExpressions.empty())
1064 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
1067 this->m_commandString += visitor.m_setExpressions;
1070 QueryWithWhereClause<TableDefinition>::Prepare();
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());
1081 BindVisitor visitor(this->m_command);
1082 m_row.VisitColumns(visitor);
1084 this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1085 QueryWithWhereClause<TableDefinition>::Bind();
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)
1097 void Values(const Row& row)
1099 if ( this->m_command )
1101 if ( !row.IsSignatureMatching(m_row) )
1103 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1104 "Current ORM implementation doesn't allow to reuse Update instance "
1105 "with different query signature.");
1115 this->m_command->Step();
1116 this->m_command->Reset();