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/db/sql_connection.h>
34 #include <dpl/db/orm_interface.h>
35 #include <dpl/string.h>
36 #include <dpl/type_list.h>
37 #include <dpl/assert.h>
38 #include <dpl/foreach.h>
47 //TODO move to type utils
48 #define DPL_CHECK_TYPE_INSTANTIABILITY(type) \
54 #define DECLARE_COLUMN_TYPE_LIST() typedef VcoreDPL::TypeListDecl<
55 #define SELECTED_COLUMN(table_name, column_name) table_name::column_name,
56 #define DECLARE_COLUMN_TYPE_LIST_END(name) VcoreDPL::TypeListGuard>::Type name;
58 typedef size_t ColumnIndex;
59 typedef size_t ArgumentIndex;
60 typedef boost::optional<VcoreDPL::String> OptionalString;
61 typedef boost::optional<int> OptionalInteger;
62 typedef VcoreDPL::DB::SqlConnection::DataCommand DataCommand;
64 namespace RelationTypes {
65 extern const char Equal[];
66 extern const char LessThan[];
67 extern const char And[];
68 extern const char Or[];
69 extern const char Is[];
70 extern const char In[];
71 //TODO define more relation types
74 namespace DataCommandUtils {
75 //TODO move to VcoreDPL::DataCommand?
76 void BindArgument(DataCommand *command, ArgumentIndex index, int argument);
77 void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalInteger& argument);
78 void BindArgument(DataCommand *command, ArgumentIndex index, const VcoreDPL::String& argument);
79 void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalString& argument);
81 class __attribute__ ((visibility("hidden"))) Expression {
83 virtual ~Expression() {}
84 virtual std::string GetString() const = 0;
85 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0;
88 typedef std::shared_ptr<Expression> ExpressionPtr;
90 namespace OrderingUtils {
92 template<typename CompoundType> inline std::string OrderByInternal()
94 std::string order = OrderByInternal<typename CompoundType::Tail>();
95 if(!order.empty()) return CompoundType::Head::GetString() + ", " + order;
96 else return CompoundType::Head::GetString();
99 template<> inline std::string OrderByInternal<TypeListGuard>()
101 return std::string();
106 template<typename ColumnType>
107 class __attribute__ ((visibility("hidden"))) OrderingExpression {
109 static std::string GetSchemaAndName()
111 std::string statement;
112 statement += ColumnType::GetTableName();
114 statement += ColumnType::GetColumnName();
119 virtual ~OrderingExpression() {}
122 template<const char* Operator, typename LeftExpression, typename RightExpression>
123 class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression {
125 LeftExpression m_leftExpression;
126 RightExpression m_rightExpression;
127 bool m_outerParenthesis;
129 BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
130 m_leftExpression(leftExpression),
131 m_rightExpression(rightExpression),
132 m_outerParenthesis(outerParenthesis)
135 virtual std::string GetString() const
137 return (m_outerParenthesis ? "( " : " " ) +
138 m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
139 (m_outerParenthesis ? " )" : " " ) ;
142 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
144 index = m_leftExpression.BindTo(command, index);
145 return m_rightExpression.BindTo(command, index);
148 template<typename TableDefinition>
149 struct ValidForTable {
150 typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
151 typename RightExpression::template ValidForTable<TableDefinition>::Yes >
156 template<typename LeftExpression, typename RightExpression>
157 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
158 And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
160 return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
161 (leftExpression, rightExpression);
164 template<typename LeftExpression, typename RightExpression>
165 BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
166 Or(const LeftExpression& leftExpression, const RightExpression& rightExpression)
168 return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
169 (leftExpression, rightExpression);
172 template<typename ArgumentType>
173 class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression {
175 ArgumentType argument;
178 explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
180 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
182 DataCommandUtils::BindArgument(command, index, argument);
187 template<typename ColumnData, const char* Relation>
188 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
190 explicit Compare(typename ColumnData::ColumnType column) :
191 ExpressionWithArgument<typename ColumnData::ColumnType>(column)
194 virtual std::string GetString() const
196 std::string statement;
197 statement += ColumnData::GetTableName();
199 statement += ColumnData::GetColumnName();
201 statement += Relation;
206 template<typename TableDefinition>
207 struct ValidForTable {
208 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
211 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \
212 template<typename ColumnData> \
213 class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> { \
215 name(typename ColumnData::ColumnType column) : \
216 Compare<ColumnData, RelationTypes::relationType>(column) \
220 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
221 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
223 #define ORM_DEFINE_ORDERING_EXPRESSION(name, value) \
224 template<typename ColumnType> \
225 class __attribute__ ((visibility("hidden"))) name \
226 : OrderingExpression<ColumnType> { \
228 static std::string GetString() \
230 std::string statement = OrderingExpression<ColumnType>::GetSchemaAndName(); \
231 statement += value; \
236 ORM_DEFINE_ORDERING_EXPRESSION(OrderingAscending, "ASC")
237 ORM_DEFINE_ORDERING_EXPRESSION(OrderingDescending, "DESC")
239 template<typename ColumnData1, typename ColumnData2>
240 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
242 std::string m_relation;
244 CompareBinaryColumn(const char* Relation) :
248 virtual ~CompareBinaryColumn() {}
250 virtual std::string GetString() const
252 std::string statement;
253 statement += ColumnData1::GetTableName();
255 statement += ColumnData1::GetColumnName();
257 statement += m_relation;
259 statement += ColumnData2::GetTableName();
261 statement += ColumnData2::GetColumnName();
267 template<typename ColumnData1, typename ColumnData2>
268 CompareBinaryColumn<ColumnData1, ColumnData2>
271 return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
274 template<typename ColumnData, const char* Relation>
275 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
277 std::set<typename ColumnData::ColumnType> m_argumentList;
279 NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
281 virtual std::string GetString() const
283 std::string statement;
284 statement += ColumnData::GetColumnName();
286 statement += Relation;
289 int argumentCount = m_argumentList.size();
305 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
307 ArgumentIndex argumentIndex = index;
308 FOREACH(argumentIt, m_argumentList)
310 DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
313 return argumentIndex + 1;
316 template<typename TableDefinition>
317 struct ValidForTable {
318 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
322 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \
323 template<typename ColumnData> \
324 class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> { \
326 name(std::set<typename ColumnData::ColumnType> column) : \
327 NumerousArguments<ColumnData, RelationTypes::relationType>(column) \
331 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
333 template<typename ColumnType>
334 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
336 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
338 CustomColumnBase() {}
339 virtual ~CustomColumnBase() {}
342 template<typename ColumnType>
343 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
345 ColumnType m_columnData;
349 CustomColumn(ColumnType data)
354 void SetColumnData(ColumnType data)
359 ColumnType GetColumnData() const
365 template<typename ColumnList>
366 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
368 static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
370 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
371 Type* pColumn = new Type();
372 columnList.push_back(pColumn);
373 CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
376 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
378 CopyColumnList(srcList, dstList, 0);
381 static ColumnIndex GetColumnIndex(const std::string& columnName)
383 return GetColumnIndex(columnName, 0);
387 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
389 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
390 Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
391 dstList.push_back(pColumn);
392 CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
395 static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
397 if (ColumnList::Head::GetColumnName() == columnName)
400 return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
403 template<typename Other>
404 friend class CustomRowUtil;
408 class __attribute__ ((visibility("hidden"))) CustomRowUtil<VcoreDPL::TypeListGuard> {
410 static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
412 static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
413 static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
415 template<typename Other>
416 friend class CustomRowUtil;
419 template<typename ColumnList>
420 class __attribute__ ((visibility("hidden"))) CustomRow {
422 std::vector<CustomColumnBase*> m_columns;
427 CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
430 CustomRow(const CustomRow& r)
432 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
437 while (!m_columns.empty())
439 CustomColumnBase* pCustomColumn = m_columns.back();
440 m_columns.pop_back();
442 delete pCustomColumn;
446 template<typename ColumnType>
447 void SetColumnData(ColumnIndex columnIndex, ColumnType data)
449 typedef CustomColumn<ColumnType> Type;
450 Assert(columnIndex < m_columns.size());
451 Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
453 pColumn->SetColumnData(data);
456 template<typename ColumnData>
457 typename ColumnData::ColumnType GetColumnData()
459 typedef CustomColumn<typename ColumnData::ColumnType> Type;
460 ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
461 Assert(index < m_columns.size());
462 Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
464 return pColumn->GetColumnData();
468 template<typename CustomRow, typename ColumnType>
469 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
471 row.SetColumnData<ColumnType>(columnIndex, columnData);
474 template<typename ColumnList, typename CustomRow>
475 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
477 static void FillCustomRow(CustomRow& row, DataCommand* command)
479 FillCustomRow(row, 0, command);
483 static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
485 typename ColumnList::Head::ColumnType columnData;
486 columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
487 SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
488 FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
491 template<typename Other, typename OtherRow>
492 friend class FillCustomRowUtil;
495 template<typename CustomRow>
496 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil<VcoreDPL::TypeListGuard, CustomRow> {
498 static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
499 { /* do nothing, we're past the last element of column list */ }
501 template<typename Other, typename OtherRow>
502 friend class FillCustomRowUtil;
505 template<typename ColumnList, typename Row>
506 class __attribute__ ((visibility("hidden"))) FillRowUtil {
508 static void FillRow(Row& row, DataCommand *command)
510 FillRow(row, 0, command);
514 static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
516 typename ColumnList::Head::ColumnType rowField;
517 rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
518 ColumnList::Head::SetRowField(row, rowField);
519 FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
522 template<typename Other, typename OtherRow>
523 friend class FillRowUtil;
526 template<typename Row>
527 class __attribute__ ((visibility("hidden"))) FillRowUtil<VcoreDPL::TypeListGuard, Row> {
529 static void FillRow(Row&, ColumnIndex, DataCommand *)
530 { /* do nothing, we're past the last element of column list */ }
532 template<typename Other, typename OtherRow>
533 friend class FillRowUtil;
536 template<typename ColumnList>
537 class __attribute__ ((visibility("hidden"))) JoinUtil {
539 static std::string GetColumnNames()
542 result = ColumnList::Head::GetTableName();
544 result += ColumnList::Head::GetColumnName();
545 if (ColumnList::Tail::Size > 0)
548 return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
551 static std::string GetJoinTableName(const std::string& tableName)
553 std::string joinTableName = ColumnList::Head::GetTableName();
554 if (tableName.find(joinTableName) == std::string::npos)
555 return joinTableName;
557 return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
562 class __attribute__ ((visibility("hidden"))) JoinUtil<VcoreDPL::TypeListGuard> {
564 static std::string GetColumnNames() { return ""; }
565 static std::string GetJoinTableName(std::string) { return ""; }
570 DECLARE_EXCEPTION_TYPE(VcoreDPL::Exception, Base)
571 DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
572 DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
573 DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
576 template<typename TableDefinition>
577 class __attribute__ ((visibility("hidden"))) Query
580 explicit Query(IOrmInterface* interface) :
581 m_interface(interface),
588 if (m_command == NULL)
591 TableDefinition::FreeTableDataCommand(m_command, m_interface);
594 IOrmInterface* m_interface;
595 DataCommand *m_command;
596 std::string m_commandString;
597 ArgumentIndex m_bindArgumentIndex;
600 template<typename TableDefinition>
601 class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
604 ExpressionPtr m_whereExpression;
608 if ( !!m_whereExpression )
610 this->m_commandString += " WHERE ";
611 this->m_commandString += m_whereExpression->GetString();
617 if ( !!m_whereExpression )
619 this->m_bindArgumentIndex = m_whereExpression->BindTo(
620 this->m_command, this->m_bindArgumentIndex);
625 explicit QueryWithWhereClause(IOrmInterface* interface) :
626 Query<TableDefinition>(interface)
630 template<typename Expression>
631 void Where(const Expression& expression)
633 DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
634 if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
636 std::ostringstream str;
637 str << "Current ORM implementation doesn't allow to reuse Select"
638 " instance with different query signature (particularly "
639 "WHERE on different column).\n";
641 str << this->m_commandString;
642 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
645 //TODO maybe don't make a copy here but just generate the string part of the query.
646 m_whereExpression.reset(new Expression(expression));
651 template<typename TableDefinition>
652 class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
657 if ( !this->m_command)
659 this->m_commandString = "DELETE FROM ";
660 this->m_commandString += TableDefinition::GetName();
662 QueryWithWhereClause<TableDefinition>::Prepare();
664 this->m_command = TableDefinition::AllocTableDataCommand(
665 this->m_commandString.c_str(),
666 Query<TableDefinition>::m_interface);
667 LogDebug("Prepared SQL command " << this->m_commandString);
673 this->m_bindArgumentIndex = 1;
674 QueryWithWhereClause<TableDefinition>::Bind();
678 explicit Delete(IOrmInterface *interface = NULL) :
679 QueryWithWhereClause<TableDefinition>(interface)
687 this->m_command->Step();
688 this->m_command->Reset();
695 DataCommand *m_command;
697 ArgumentIndex m_bindArgumentIndex;
699 BindVisitor(DataCommand *command) :
701 m_bindArgumentIndex(1)
704 template<typename ColumnType>
705 void Visit(const char*, const ColumnType& value, bool isSet)
709 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
710 m_bindArgumentIndex++;
714 } //anonymous namespace
715 template<typename TableDefinition>
716 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
719 typedef typename TableDefinition::Row Row;
720 typedef VcoreDPL::DB::SqlConnection::RowID RowID;
723 boost::optional<std::string> m_orClause;
726 class PrepareVisitor {
728 std::string m_columnNames;
729 std::string m_values;
731 template<typename ColumnType>
732 void Visit(const char* name, const ColumnType&, bool isSet)
736 if ( !m_columnNames.empty() )
738 m_columnNames += ", ";
741 m_columnNames += name;
749 if ( !this->m_command )
751 this->m_commandString = "INSERT ";
754 this->m_commandString += " OR " + *m_orClause + " ";
756 this->m_commandString += "INTO ";
757 this->m_commandString += TableDefinition::GetName();
759 PrepareVisitor visitor;
760 m_row.VisitColumns(visitor);
762 this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
763 this->m_commandString += "VALUES ( " + visitor.m_values + " )";
765 LogDebug("Prepared SQL command " << this->m_commandString);
766 this->m_command = TableDefinition::AllocTableDataCommand(
767 this->m_commandString.c_str(),
768 Query<TableDefinition>::m_interface);
774 BindVisitor visitor(this->m_command);
775 m_row.VisitColumns(visitor);
780 IOrmInterface* interface = NULL,
781 const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
782 Query<TableDefinition>(interface),
787 void Values(const Row& row)
789 if ( this->m_command )
791 if ( !row.IsSignatureMatching(m_row) )
793 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
794 "Current ORM implementation doesn't allow to reuse Insert instance "
795 "with different query signature.");
805 this->m_command->Step();
807 RowID result = TableDefinition::GetLastInsertRowID(
808 Query<TableDefinition>::m_interface);
810 this->m_command->Reset();
815 template<typename TableDefinition>
816 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
819 typedef typename TableDefinition::ColumnList ColumnList;
820 typedef typename TableDefinition::Row Row;
822 typedef std::list<Row> RowList;
824 boost::optional<std::string> m_orderBy;
825 std::string m_JoinClause;
826 bool m_distinctResults;
828 void Prepare(const char* selectColumnName)
830 if ( !this->m_command )
832 this->m_commandString = "SELECT ";
833 if (m_distinctResults)
834 this->m_commandString += "DISTINCT ";
835 this->m_commandString += selectColumnName;
836 this->m_commandString += " FROM ";
837 this->m_commandString += TableDefinition::GetName();
839 this->m_commandString += m_JoinClause;
841 QueryWithWhereClause<TableDefinition>::Prepare();
845 this->m_commandString += " ORDER BY " + *m_orderBy;
848 this->m_command = TableDefinition::AllocTableDataCommand(
849 this->m_commandString.c_str(),
850 Query<TableDefinition>::m_interface);
852 LogDebug("Prepared SQL command " << this->m_commandString);
858 this->m_bindArgumentIndex = 1;
859 QueryWithWhereClause<TableDefinition>::Bind();
862 template<typename ColumnType>
863 ColumnType GetColumn(ColumnIndex columnIndex)
865 return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
871 FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
875 template<typename ColumnList, typename CustomRow>
876 CustomRow GetCustomRow()
879 FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
885 explicit Select(IOrmInterface *interface = NULL) :
886 QueryWithWhereClause<TableDefinition>(interface),
887 m_distinctResults(false)
893 m_distinctResults = true;
896 template<typename CompoundType>
897 void OrderBy(const CompoundType&)
899 m_orderBy = OrderingUtils::OrderByInternal<typename CompoundType::Type>();
902 void OrderBy(const std::string & orderBy) //backward compatibility
907 void OrderBy(const char * orderBy) //backward compatibility
909 m_orderBy = std::string(orderBy);
912 template<typename ColumnList, typename Expression>
913 void Join(const Expression& expression) {
914 std::string usedTableNames = TableDefinition::GetName();
915 if (!m_JoinClause.empty())
916 usedTableNames += m_JoinClause;
918 this->m_JoinClause += " JOIN ";
919 this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
920 this->m_JoinClause += " ON ";
921 this->m_JoinClause += expression.GetString();
924 template<typename ColumnData>
925 typename ColumnData::ColumnType GetSingleValue()
927 Prepare(ColumnData::GetColumnName());
929 this->m_command->Step();
931 typename ColumnData::ColumnType result =
932 GetColumn<typename ColumnData::ColumnType>(0);
934 this->m_command->Reset();
938 //TODO return range - pair of custom iterators
939 template<typename ColumnData>
940 std::list<typename ColumnData::ColumnType> GetValueList()
942 Prepare(ColumnData::GetColumnName());
945 std::list<typename ColumnData::ColumnType> resultList;
947 while (this->m_command->Step())
948 resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
950 this->m_command->Reset();
958 this->m_command->Step();
960 Row result = GetRow();
962 this->m_command->Reset();
966 //TODO return range - pair of custom iterators
974 while (this->m_command->Step())
975 resultList.push_back(GetRow());
977 this->m_command->Reset();
981 template<typename ColumnList, typename CustomRow>
982 CustomRow GetCustomSingleRow()
984 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
986 this->m_command->Step();
988 CustomRow result = GetCustomRow<ColumnList, CustomRow>();
990 this->m_command->Reset();
994 template<typename ColumnList, typename CustomRow>
995 std::list<CustomRow> GetCustomRowList()
997 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
1000 std::list<CustomRow> resultList;
1002 while (this->m_command->Step())
1003 resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
1005 this->m_command->Reset();
1010 template<typename TableDefinition>
1011 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
1013 typedef typename TableDefinition::Row Row;
1016 boost::optional<std::string> m_orClause;
1019 class PrepareVisitor {
1021 std::string m_setExpressions;
1023 template<typename ColumnType>
1024 void Visit(const char* name, const ColumnType&, bool isSet)
1028 if ( !m_setExpressions.empty() )
1030 m_setExpressions += ", ";
1032 m_setExpressions += name;
1033 m_setExpressions += " = ";
1034 m_setExpressions += "?";
1041 if ( !this->m_command )
1043 this->m_commandString = "UPDATE ";
1046 this->m_commandString += " OR " + *m_orClause + " ";
1048 this->m_commandString += TableDefinition::GetName();
1049 this->m_commandString += " SET ";
1051 // got through row columns and values
1052 PrepareVisitor visitor;
1053 m_row.VisitColumns(visitor);
1055 if(visitor.m_setExpressions.empty())
1057 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
1060 this->m_commandString += visitor.m_setExpressions;
1063 QueryWithWhereClause<TableDefinition>::Prepare();
1065 this->m_command = TableDefinition::AllocTableDataCommand(
1066 this->m_commandString.c_str(),
1067 Query<TableDefinition>::m_interface);
1068 LogDebug("Prepared SQL command " << this->m_commandString);
1074 BindVisitor visitor(this->m_command);
1075 m_row.VisitColumns(visitor);
1077 this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1078 QueryWithWhereClause<TableDefinition>::Bind();
1083 explicit Update(IOrmInterface *interface = NULL,
1084 const boost::optional<std::string>& orClause = boost::optional<std::string>()) :
1085 QueryWithWhereClause<TableDefinition>(interface),
1086 m_orClause(orClause)
1090 void Values(const Row& row)
1092 if ( this->m_command )
1094 if ( !row.IsSignatureMatching(m_row) )
1096 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1097 "Current ORM implementation doesn't allow to reuse Update instance "
1098 "with different query signature.");
1108 this->m_command->Step();
1109 this->m_command->Reset();
1115 } //namespace VcoreDPL