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 <dpl/db/sql_connection.h>
32 #include <dpl/db/orm_interface.h>
33 #include <dpl/string.h>
34 #include <dpl/optional.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 DPL::Optional<DPL::String> OptionalString;
60 typedef DPL::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 template<const char* Operator, typename LeftExpression, typename RightExpression>
90 class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression {
92 LeftExpression m_leftExpression;
93 RightExpression m_rightExpression;
94 bool m_outerParenthesis;
96 BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) :
97 m_leftExpression(leftExpression),
98 m_rightExpression(rightExpression),
99 m_outerParenthesis(outerParenthesis)
102 virtual std::string GetString() const
104 return (m_outerParenthesis ? "( " : " " ) +
105 m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() +
106 (m_outerParenthesis ? " )" : " " ) ;
109 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
111 index = m_leftExpression.BindTo(command, index);
112 return m_rightExpression.BindTo(command, index);
115 template<typename TableDefinition>
116 struct ValidForTable {
117 typedef std::pair<typename LeftExpression ::template ValidForTable<TableDefinition>::Yes ,
118 typename RightExpression::template ValidForTable<TableDefinition>::Yes >
123 template<typename LeftExpression, typename RightExpression>
124 BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
125 And(const LeftExpression& leftExpression, const RightExpression& rightExpression)
127 return BinaryExpression<RelationTypes::And, LeftExpression, RightExpression>
128 (leftExpression, rightExpression);
131 template<typename LeftExpression, typename RightExpression>
132 BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
133 Or(const LeftExpression& leftExpression, const RightExpression& rightExpression)
135 return BinaryExpression<RelationTypes::Or, LeftExpression, RightExpression>
136 (leftExpression, rightExpression);
139 template<typename ArgumentType>
140 class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression {
142 ArgumentType argument;
145 explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {}
147 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
149 DataCommandUtils::BindArgument(command, index, argument);
154 template<typename ColumnData, const char* Relation>
155 class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument<typename ColumnData::ColumnType> {
157 explicit Compare(typename ColumnData::ColumnType column) :
158 ExpressionWithArgument<typename ColumnData::ColumnType>(column)
161 virtual std::string GetString() const
163 std::string statement;
164 statement += ColumnData::GetTableName();
166 statement += ColumnData::GetColumnName();
168 statement += Relation;
173 template<typename TableDefinition>
174 struct ValidForTable {
175 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
178 #define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \
179 template<typename ColumnData> \
180 class __attribute__ ((visibility("hidden"))) name : public Compare<ColumnData, RelationTypes::relationType> { \
182 name(typename ColumnData::ColumnType column) : \
183 Compare<ColumnData, RelationTypes::relationType>(column) \
187 ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal)
188 ORM_DEFINE_COMPARE_EXPRESSION(Is, Is)
190 template<typename ColumnData1, typename ColumnData2>
191 class __attribute__ ((visibility("hidden"))) CompareBinaryColumn {
193 std::string m_relation;
195 CompareBinaryColumn(const char* Relation) :
199 virtual ~CompareBinaryColumn() {}
201 virtual std::string GetString() const
203 std::string statement;
204 statement += ColumnData1::GetTableName();
206 statement += ColumnData1::GetColumnName();
208 statement += m_relation;
210 statement += ColumnData2::GetTableName();
212 statement += ColumnData2::GetColumnName();
218 template<typename ColumnData1, typename ColumnData2>
219 CompareBinaryColumn<ColumnData1, ColumnData2>
222 return CompareBinaryColumn<ColumnData1, ColumnData2>(RelationTypes::Equal);
225 template<typename ColumnData, const char* Relation>
226 class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression {
228 std::set<typename ColumnData::ColumnType> m_argumentList;
230 NumerousArguments(const std::set<typename ColumnData::ColumnType>& argumentList) : m_argumentList(argumentList) {}
232 virtual std::string GetString() const
234 std::string statement;
235 statement += ColumnData::GetColumnName();
237 statement += Relation;
240 int argumentCount = m_argumentList.size();
256 virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index)
258 ArgumentIndex argumentIndex = index;
259 FOREACH(argumentIt, m_argumentList)
261 DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt);
264 return argumentIndex + 1;
267 template<typename TableDefinition>
268 struct ValidForTable {
269 typedef typename TableDefinition::ColumnList::template Contains<ColumnData> Yes;
273 #define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \
274 template<typename ColumnData> \
275 class __attribute__ ((visibility("hidden"))) name : public NumerousArguments<ColumnData, RelationTypes::relationType> { \
277 name(std::set<typename ColumnData::ColumnType> column) : \
278 NumerousArguments<ColumnData, RelationTypes::relationType>(column) \
282 ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In)
284 template<typename ColumnType>
285 ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command);
287 class __attribute__ ((visibility("hidden"))) CustomColumnBase {
289 CustomColumnBase() {}
290 virtual ~CustomColumnBase() {}
293 template<typename ColumnType>
294 class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase {
296 ColumnType m_columnData;
300 CustomColumn(ColumnType data)
305 void SetColumnData(ColumnType data)
310 ColumnType GetColumnData() const
316 template<typename ColumnList>
317 class __attribute__ ((visibility("hidden"))) CustomRowUtil {
319 static void MakeColumnList(std::vector<CustomColumnBase*>& columnList)
321 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
322 Type* pColumn = new Type();
323 columnList.push_back(pColumn);
324 CustomRowUtil<typename ColumnList::Tail>::MakeColumnList(columnList);
327 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList)
329 CopyColumnList(srcList, dstList, 0);
332 static ColumnIndex GetColumnIndex(const std::string& columnName)
334 return GetColumnIndex(columnName, 0);
338 static void CopyColumnList(const std::vector<CustomColumnBase*>& srcList, std::vector<CustomColumnBase*>& dstList, ColumnIndex index)
340 typedef CustomColumn<typename ColumnList::Head::ColumnType> Type;
341 Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData());
342 dstList.push_back(pColumn);
343 CustomRowUtil<typename ColumnList::Tail>::CopyColumnList(srcList, dstList, index + 1);
346 static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index)
348 if (ColumnList::Head::GetColumnName() == columnName)
351 return CustomRowUtil<typename ColumnList::Tail>::GetColumnIndex(columnName, index + 1);
354 template<typename Other>
355 friend class CustomRowUtil;
359 class __attribute__ ((visibility("hidden"))) CustomRowUtil<DPL::TypeListGuard> {
361 static void MakeColumnList(std::vector<CustomColumnBase*>&) {}
363 static void CopyColumnList(const std::vector<CustomColumnBase*>&, std::vector<CustomColumnBase*>&, ColumnIndex) {}
364 static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; }
366 template<typename Other>
367 friend class CustomRowUtil;
370 template<typename ColumnList>
371 class __attribute__ ((visibility("hidden"))) CustomRow {
373 std::vector<CustomColumnBase*> m_columns;
378 CustomRowUtil<ColumnList>::MakeColumnList(m_columns);
381 CustomRow(const CustomRow& r)
383 CustomRowUtil<ColumnList>::CopyColumnList(r.m_columns, m_columns);
388 while (!m_columns.empty())
390 CustomColumnBase* pCustomColumn = m_columns.back();
391 m_columns.pop_back();
393 delete pCustomColumn;
397 template<typename ColumnType>
398 void SetColumnData(ColumnIndex columnIndex, ColumnType data)
400 typedef CustomColumn<ColumnType> Type;
401 Assert(columnIndex < m_columns.size());
402 Type* pColumn = dynamic_cast<Type*>(m_columns.at(columnIndex));
404 pColumn->SetColumnData(data);
407 template<typename ColumnData>
408 typename ColumnData::ColumnType GetColumnData()
410 typedef CustomColumn<typename ColumnData::ColumnType> Type;
411 ColumnIndex index = CustomRowUtil<ColumnList>::GetColumnIndex(ColumnData::GetColumnName());
412 Assert(index < m_columns.size());
413 Type* pColumn = dynamic_cast<Type*>(m_columns.at(index));
415 return pColumn->GetColumnData();
419 template<typename CustomRow, typename ColumnType>
420 void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex)
422 row.SetColumnData<ColumnType>(columnIndex, columnData);
425 template<typename ColumnList, typename CustomRow>
426 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil {
428 static void FillCustomRow(CustomRow& row, DataCommand* command)
430 FillCustomRow(row, 0, command);
434 static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command)
436 typename ColumnList::Head::ColumnType columnData;
437 columnData = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
438 SetColumnData<CustomRow, typename ColumnList::Head::ColumnType>(row, columnData, columnIndex);
439 FillCustomRowUtil<typename ColumnList::Tail, CustomRow>::FillCustomRow(row, columnIndex + 1, command);
442 template<typename Other, typename OtherRow>
443 friend class FillCustomRowUtil;
446 template<typename CustomRow>
447 class __attribute__ ((visibility("hidden"))) FillCustomRowUtil<DPL::TypeListGuard, CustomRow> {
449 static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *)
450 { /* do nothing, we're past the last element of column list */ }
452 template<typename Other, typename OtherRow>
453 friend class FillCustomRowUtil;
456 template<typename ColumnList, typename Row>
457 class __attribute__ ((visibility("hidden"))) FillRowUtil {
459 static void FillRow(Row& row, DataCommand *command)
461 FillRow(row, 0, command);
465 static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command)
467 typename ColumnList::Head::ColumnType rowField;
468 rowField = GetColumnFromCommand<typename ColumnList::Head::ColumnType>(columnIndex, command);
469 ColumnList::Head::SetRowField(row, rowField);
470 FillRowUtil<typename ColumnList::Tail, Row>::FillRow(row, columnIndex + 1, command);
473 template<typename Other, typename OtherRow>
474 friend class FillRowUtil;
477 template<typename Row>
478 class __attribute__ ((visibility("hidden"))) FillRowUtil<DPL::TypeListGuard, Row> {
480 static void FillRow(Row&, ColumnIndex, DataCommand *)
481 { /* do nothing, we're past the last element of column list */ }
483 template<typename Other, typename OtherRow>
484 friend class FillRowUtil;
487 template<typename ColumnList>
488 class __attribute__ ((visibility("hidden"))) JoinUtil {
490 static std::string GetColumnNames()
493 result = ColumnList::Head::GetTableName();
495 result += ColumnList::Head::GetColumnName();
496 if (ColumnList::Tail::Size > 0)
499 return result += JoinUtil<typename ColumnList::Tail>::GetColumnNames();
502 static std::string GetJoinTableName(const std::string& tableName)
504 std::string joinTableName = ColumnList::Head::GetTableName();
505 if (tableName.find(joinTableName) == std::string::npos)
506 return joinTableName;
508 return JoinUtil<typename ColumnList::Tail>::GetJoinTableName(tableName);
513 class __attribute__ ((visibility("hidden"))) JoinUtil<DPL::TypeListGuard> {
515 static std::string GetColumnNames() { return ""; }
516 static std::string GetJoinTableName(std::string) { return ""; }
521 DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
522 DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature)
523 DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized)
524 DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement)
527 template<typename TableDefinition>
528 class __attribute__ ((visibility("hidden"))) Query
531 explicit Query(IOrmInterface* interface) :
532 m_interface(interface),
539 if (m_command == NULL)
542 TableDefinition::FreeTableDataCommand(m_command, m_interface);
545 IOrmInterface* m_interface;
546 DataCommand *m_command;
547 std::string m_commandString;
548 ArgumentIndex m_bindArgumentIndex;
551 template<typename TableDefinition>
552 class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query<TableDefinition>
555 ExpressionPtr m_whereExpression;
559 if ( !!m_whereExpression )
561 this->m_commandString += " WHERE ";
562 this->m_commandString += m_whereExpression->GetString();
568 if ( !!m_whereExpression )
570 this->m_bindArgumentIndex = m_whereExpression->BindTo(
571 this->m_command, this->m_bindArgumentIndex);
576 explicit QueryWithWhereClause(IOrmInterface* interface) :
577 Query<TableDefinition>(interface)
581 template<typename Expression>
582 void Where(const Expression& expression)
584 DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable<TableDefinition>::Yes);
585 if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) )
587 std::ostringstream str;
588 str << "Current ORM implementation doesn't allow to reuse Select"
589 " instance with different query signature (particularly "
590 "WHERE on different column).\n";
592 str << this->m_commandString;
593 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
596 //TODO maybe don't make a copy here but just generate the string part of the query.
597 m_whereExpression.reset(new Expression(expression));
602 template<typename TableDefinition>
603 class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause<TableDefinition>
608 if ( !this->m_command)
610 this->m_commandString = "DELETE FROM ";
611 this->m_commandString += TableDefinition::GetName();
613 QueryWithWhereClause<TableDefinition>::Prepare();
615 this->m_command = TableDefinition::AllocTableDataCommand(
616 this->m_commandString.c_str(),
617 Query<TableDefinition>::m_interface);
618 LogPedantic("Prepared SQL command " << this->m_commandString);
624 this->m_bindArgumentIndex = 1;
625 QueryWithWhereClause<TableDefinition>::Bind();
629 explicit Delete(IOrmInterface *interface = NULL) :
630 QueryWithWhereClause<TableDefinition>(interface)
638 this->m_command->Step();
639 this->m_command->Reset();
646 DataCommand *m_command;
648 ArgumentIndex m_bindArgumentIndex;
650 BindVisitor(DataCommand *command) :
652 m_bindArgumentIndex(1)
655 template<typename ColumnType>
656 void Visit(const char*, const ColumnType& value, bool isSet)
660 DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value);
661 m_bindArgumentIndex++;
665 } //anonymous namespace
666 template<typename TableDefinition>
667 class __attribute__ ((visibility("hidden"))) Insert : public Query<TableDefinition>
670 typedef typename TableDefinition::Row Row;
671 typedef DPL::DB::SqlConnection::RowID RowID;
674 DPL::Optional<std::string> m_orClause;
677 class PrepareVisitor {
679 std::string m_columnNames;
680 std::string m_values;
682 template<typename ColumnType>
683 void Visit(const char* name, const ColumnType&, bool isSet)
687 if ( !m_columnNames.empty() )
689 m_columnNames += ", ";
692 m_columnNames += name;
700 if ( !this->m_command )
702 this->m_commandString = "INSERT ";
705 this->m_commandString += " OR " + *m_orClause + " ";
707 this->m_commandString += "INTO ";
708 this->m_commandString += TableDefinition::GetName();
710 PrepareVisitor visitor;
711 m_row.VisitColumns(visitor);
713 this->m_commandString += " ( " + visitor.m_columnNames + " ) ";
714 this->m_commandString += "VALUES ( " + visitor.m_values + " )";
716 LogPedantic("Prepared SQL command " << this->m_commandString);
717 this->m_command = TableDefinition::AllocTableDataCommand(
718 this->m_commandString.c_str(),
719 Query<TableDefinition>::m_interface);
725 BindVisitor visitor(this->m_command);
726 m_row.VisitColumns(visitor);
731 IOrmInterface* interface = NULL,
732 const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
733 Query<TableDefinition>(interface),
738 void Values(const Row& row)
740 if ( this->m_command )
742 if ( !row.IsSignatureMatching(m_row) )
744 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
745 "Current ORM implementation doesn't allow to reuse Insert instance "
746 "with different query signature.");
756 this->m_command->Step();
758 RowID result = TableDefinition::GetLastInsertRowID(
759 Query<TableDefinition>::m_interface);
761 this->m_command->Reset();
766 template<typename TableDefinition>
767 class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause<TableDefinition>
770 typedef typename TableDefinition::ColumnList ColumnList;
771 typedef typename TableDefinition::Row Row;
773 typedef std::list<Row> RowList;
775 DPL::Optional<std::string> m_orderBy;
776 std::string m_JoinClause;
777 bool m_distinctResults;
779 void Prepare(const char* selectColumnName)
781 if ( !this->m_command )
783 this->m_commandString = "SELECT ";
784 if (m_distinctResults)
785 this->m_commandString += "DISTINCT ";
786 this->m_commandString += selectColumnName;
787 this->m_commandString += " FROM ";
788 this->m_commandString += TableDefinition::GetName();
790 this->m_commandString += m_JoinClause;
792 QueryWithWhereClause<TableDefinition>::Prepare();
794 if ( !m_orderBy.IsNull() )
796 this->m_commandString += " ORDER BY " + *m_orderBy;
799 this->m_command = TableDefinition::AllocTableDataCommand(
800 this->m_commandString.c_str(),
801 Query<TableDefinition>::m_interface);
803 LogPedantic("Prepared SQL command " << this->m_commandString);
809 this->m_bindArgumentIndex = 1;
810 QueryWithWhereClause<TableDefinition>::Bind();
813 template<typename ColumnType>
814 ColumnType GetColumn(ColumnIndex columnIndex)
816 return GetColumnFromCommand<ColumnType>(columnIndex, this->m_command);
822 FillRowUtil<ColumnList, Row>::FillRow(row, this->m_command);
826 template<typename ColumnList, typename CustomRow>
827 CustomRow GetCustomRow()
830 FillCustomRowUtil<ColumnList, CustomRow>::FillCustomRow(row, this->m_command);
836 explicit Select(IOrmInterface *interface = NULL) :
837 QueryWithWhereClause<TableDefinition>(interface),
838 m_distinctResults(false)
844 m_distinctResults = true;
847 void OrderBy(const std::string& orderBy)
852 template<typename ColumnList, typename Expression>
853 void Join(const Expression& expression) {
854 std::string usedTableNames = TableDefinition::GetName();
855 if (!m_JoinClause.empty())
856 usedTableNames += m_JoinClause;
858 this->m_JoinClause += " JOIN ";
859 this->m_JoinClause += JoinUtil<ColumnList>::GetJoinTableName(usedTableNames);
860 this->m_JoinClause += " ON ";
861 this->m_JoinClause += expression.GetString();
864 template<typename ColumnData>
865 typename ColumnData::ColumnType GetSingleValue()
867 Prepare(ColumnData::GetColumnName());
869 this->m_command->Step();
871 typename ColumnData::ColumnType result =
872 GetColumn<typename ColumnData::ColumnType>(0);
874 this->m_command->Reset();
878 //TODO return range - pair of custom iterators
879 template<typename ColumnData>
880 std::list<typename ColumnData::ColumnType> GetValueList()
882 Prepare(ColumnData::GetColumnName());
885 std::list<typename ColumnData::ColumnType> resultList;
887 while (this->m_command->Step())
888 resultList.push_back(GetColumn<typename ColumnData::ColumnType>(0));
890 this->m_command->Reset();
898 this->m_command->Step();
900 Row result = GetRow();
902 this->m_command->Reset();
906 //TODO return range - pair of custom iterators
914 while (this->m_command->Step())
915 resultList.push_back(GetRow());
917 this->m_command->Reset();
921 template<typename ColumnList, typename CustomRow>
922 CustomRow GetCustomSingleRow()
924 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
926 this->m_command->Step();
928 CustomRow result = GetCustomRow<ColumnList, CustomRow>();
930 this->m_command->Reset();
934 template<typename ColumnList, typename CustomRow>
935 std::list<CustomRow> GetCustomRowList()
937 Prepare(JoinUtil<ColumnList>::GetColumnNames().c_str());
940 std::list<CustomRow> resultList;
942 while (this->m_command->Step())
943 resultList.push_back(GetCustomRow<ColumnList, CustomRow>());
945 this->m_command->Reset();
950 template<typename TableDefinition>
951 class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause<TableDefinition> {
953 typedef typename TableDefinition::Row Row;
956 DPL::Optional<std::string> m_orClause;
959 class PrepareVisitor {
961 std::string m_setExpressions;
963 template<typename ColumnType>
964 void Visit(const char* name, const ColumnType&, bool isSet)
968 if ( !m_setExpressions.empty() )
970 m_setExpressions += ", ";
972 m_setExpressions += name;
973 m_setExpressions += " = ";
974 m_setExpressions += "?";
981 if ( !this->m_command )
983 this->m_commandString = "UPDATE ";
986 this->m_commandString += " OR " + *m_orClause + " ";
988 this->m_commandString += TableDefinition::GetName();
989 this->m_commandString += " SET ";
991 // got through row columns and values
992 PrepareVisitor visitor;
993 m_row.VisitColumns(visitor);
995 if(visitor.m_setExpressions.empty())
997 ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement");
1000 this->m_commandString += visitor.m_setExpressions;
1003 QueryWithWhereClause<TableDefinition>::Prepare();
1005 this->m_command = TableDefinition::AllocTableDataCommand(
1006 this->m_commandString.c_str(),
1007 Query<TableDefinition>::m_interface);
1008 LogPedantic("Prepared SQL command " << this->m_commandString);
1014 BindVisitor visitor(this->m_command);
1015 m_row.VisitColumns(visitor);
1017 this->m_bindArgumentIndex = visitor.m_bindArgumentIndex;
1018 QueryWithWhereClause<TableDefinition>::Bind();
1023 explicit Update(IOrmInterface *interface = NULL,
1024 const DPL::Optional<std::string>& orClause = DPL::Optional<std::string>::Null) :
1025 QueryWithWhereClause<TableDefinition>(interface),
1026 m_orClause(orClause)
1030 void Values(const Row& row)
1032 if ( this->m_command )
1034 if ( !row.IsSignatureMatching(m_row) )
1036 ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature,
1037 "Current ORM implementation doesn't allow to reuse Update instance "
1038 "with different query signature.");
1048 this->m_command->Step();
1049 this->m_command->Reset();