/**************************************************************************** ** ** https://www.qxorm.com/ ** Copyright (C) 2013 XDL Team (ic-east.com) ** ** This file is part of the QxOrm library ** ** This software is provided 'as-is', without any express or implied ** warranty. In no event will the authors be held liable for any ** damages arising from the use of this software ** ** Commercial Usage ** Licensees holding valid commercial QxOrm licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and XDL Team ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file 'license.gpl3.txt' included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met : http://www.gnu.org/copyleft/gpl.html ** ** If you are unsure which license is appropriate for your use, or ** if you have questions regarding the use of this file, please contact : ** ic-east.com ** ****************************************************************************/ #ifndef _QX_DAO_POINTER_H_ #define _QX_DAO_POINTER_H_ #ifdef _MSC_VER #pragma once #endif /*! * \file QxDaoPointer.h * \author XDL Team * \ingroup QxDao * \brief qx::dao::ptr : provide a classic smart-pointer (like boost::shared_ptr or QSharedPointer) with some features associated with QxDao module of QxOrm library */ #include #include #include #include namespace qx { template QSharedPointer clone_to_qt_shared_ptr(const T &obj); } // namespace qx namespace qx { namespace dao { template class ptr; } // namespace dao } // namespace qx template QDataStream &operator<<(QDataStream &stream, const qx::dao::ptr &t); template QDataStream &operator>>(QDataStream &stream, qx::dao::ptr &t); namespace qx { namespace dao { namespace detail { template struct QxDao_IsDirty; } // namespace detail /*! * \ingroup QxDao * \brief qx::dao::ptr : provide a classic smart-pointer (like boost::shared_ptr or QSharedPointer) with some features associated with QxDao module of QxOrm library * * QxOrm can be used with smart-pointers of boost and Qt libraries. * QxOrm smart-pointer is based on QSharedPointer and provides new features with qx::dao::xxx functions of QxDao module. * qx::dao::ptr keeps automatically values from database. * So it's possible to detect if an instance has been modified using the method isDirty() : this method can return list of properties changed. * qx::dao::ptr can also be used with the function qx::dao::update_optimized() to update in database only properties changed. * qx::dao::ptr can be used with a simple object and with many containers : stl, boost, Qt and qx::QxCollection. * * Quick sample using qx::dao::ptr smart-pointer : * \code // Test 'isDirty()' method qx::dao::ptr blog_isdirty = qx::dao::ptr(new blog()); blog_isdirty->m_id = blog_1->m_id; daoError = qx::dao::fetch_by_id(blog_isdirty); qAssert(! daoError.isValid() && ! blog_isdirty.isDirty()); blog_isdirty->m_text = "blog property 'text' modified => blog is dirty !!!"; QStringList lstDiff; bool bDirty = blog_isdirty.isDirty(lstDiff); qAssert(bDirty && (lstDiff.count() == 1) && (lstDiff.at(0) == "blog_text")); if (bDirty) { qDebug("[QxOrm] test dirty 1 : blog is dirty => '%s'", qPrintable(lstDiff.join("|"))); } // Update only property 'm_text' of 'blog_isdirty' daoError = qx::dao::update_optimized(blog_isdirty); qAssert(! daoError.isValid() && ! blog_isdirty.isDirty()); qx::dump(blog_isdirty); // Test 'isDirty()' method with a container typedef qx::dao::ptr< QList > type_lst_author_test_is_dirty; type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList()); daoError = qx::dao::fetch_all(container_isdirty); qAssert(! daoError.isValid() && ! container_isdirty.isDirty() && (container_isdirty->count() == 3)); author_ptr author_ptr_dirty = container_isdirty->at(1); author_ptr_dirty->m_name = "author name modified at index 1 => container is dirty !!!"; bDirty = container_isdirty.isDirty(lstDiff); qAssert(bDirty && (lstDiff.count() == 1)); if (bDirty) { qDebug("[QxOrm] test dirty 2 : container is dirty => '%s'", qPrintable(lstDiff.join("|"))); } author_ptr_dirty = container_isdirty->at(2); author_ptr_dirty->m_birthdate = QDate(1998, 03, 06); bDirty = container_isdirty.isDirty(lstDiff); qAssert(bDirty && (lstDiff.count() == 2)); if (bDirty) { qDebug("[QxOrm] test dirty 3 : container is dirty => '%s'", qPrintable(lstDiff.join("|"))); } // Update only property 'm_name' at position 1, only property 'm_birthdate' at position 2 and nothing at position 0 daoError = qx::dao::update_optimized(container_isdirty); qAssert(! daoError.isValid() && ! container_isdirty.isDirty()); qx::dump(container_isdirty); // Fetch only property 'm_dt_creation' of blog QStringList lstColumns = QStringList() << "date_creation"; list_blog lst_blog_with_only_date_creation; daoError = qx::dao::fetch_all(lst_blog_with_only_date_creation, NULL, lstColumns); qAssert(! daoError.isValid() && (lst_blog_with_only_date_creation.size() > 0)); if ((lst_blog_with_only_date_creation.size() > 0) && (lst_blog_with_only_date_creation[0] != NULL)) { qAssert(lst_blog_with_only_date_creation[0]->m_text.isEmpty()); } qx::dump(lst_blog_with_only_date_creation); * \endcode */ template class ptr { template friend QDataStream & ::operator<<(QDataStream & stream, const qx::dao::ptr &t); template friend QDataStream & ::operator>>(QDataStream & stream, qx::dao::ptr &t); private: QSharedPointer m_pWork; //!< Default pointer => user works with this pointer QSharedPointer m_pOriginal; //!< Keep original pointer containing all values from database public: ptr() { ; } explicit ptr(T *ptr) : m_pWork(ptr) { ; } explicit ptr(T *ptr, T *original) : m_pWork(ptr), m_pOriginal(original) { ; } ptr(const qx::dao::ptr &other) : m_pWork(other.m_pWork), m_pOriginal(other.m_pOriginal) { ; } ptr(const QSharedPointer &other) : m_pWork(other) { ; } ptr(const QSharedPointer &other, const QSharedPointer &original) : m_pWork(other), m_pOriginal(original) { ; } ptr(const QWeakPointer &other) : m_pWork(other) { ; } ptr(const QWeakPointer &other, const QWeakPointer &original) : m_pWork(other), m_pOriginal(original) { ; } virtual ~ptr() { ; } template ptr(T *ptr, Deleter deleter) : m_pWork(ptr, deleter) { ; } template ptr(T *ptr, T *original, Deleter deleter) : m_pWork(ptr, deleter), m_pOriginal(original) { ; } template ptr(const qx::dao::ptr &other) : m_pWork(qSharedPointerCast(other.m_pWork)), m_pOriginal(qSharedPointerCast(other.m_pOriginal)) { ; } template ptr(const QSharedPointer &other) : m_pWork(qSharedPointerCast(other)) { ; } template ptr(const QSharedPointer &other, const QSharedPointer &original) : m_pWork(qSharedPointerCast(other)), m_pOriginal(qSharedPointerCast(original)) { ; } template ptr(const QWeakPointer &other) : m_pWork(qSharedPointerCast(other.toStrongRef())) { ; } template ptr(const QWeakPointer &other, const QWeakPointer &original) : m_pWork(qSharedPointerCast(other.toStrongRef())), m_pOriginal(qSharedPointerCast(original.toStrongRef())) { ; } qx::dao::ptr &operator=(const qx::dao::ptr &other) { m_pWork = other.m_pWork; m_pOriginal = other.m_pOriginal; return (*this); } qx::dao::ptr &operator=(const QSharedPointer &other) { m_pWork = other; m_pOriginal.clear(); return (*this); } qx::dao::ptr &operator=(const QWeakPointer &other) { m_pWork = other; m_pOriginal.clear(); return (*this); } template qx::dao::ptr &operator=(const qx::dao::ptr &other) { m_pWork = qSharedPointerCast(other.m_pWork); m_pOriginal = qSharedPointerCast(other.m_pOriginal); return (*this); } template qx::dao::ptr &operator=(const QSharedPointer &other) { m_pWork = qSharedPointerCast(other); m_pOriginal.clear(); return (*this); } template qx::dao::ptr &operator=(const QWeakPointer &other) { m_pWork = qSharedPointerCast(other.toStrongRef()); m_pOriginal.clear(); return (*this); } inline T *get() const { return m_pWork.data(); } inline T *getOriginal() const { return m_pOriginal.data(); } inline T *data() const { return m_pWork.data(); } inline T *dataOriginal() const { return m_pOriginal.data(); } inline bool isNull() const { return m_pWork.isNull(); } inline operator bool() const { return (!m_pWork.isNull()); } inline bool operator!() const { return m_pWork.isNull(); } inline T &operator*() const { return (*m_pWork.data()); } inline T *operator->() const { return m_pWork.data(); } inline void clear() { m_pWork.clear(); m_pOriginal.clear(); } inline void reset() { m_pWork.clear(); m_pOriginal.clear(); } inline void reset(const QSharedPointer &ptr) { m_pWork = ptr; m_pOriginal.clear(); } inline void resetOriginal(const QSharedPointer &ptr) { m_pOriginal = ptr; } inline bool isDirty() const { QStringList lstDiff; return isDirty(lstDiff); } inline QSharedPointer toQtSharedPointer() const { return m_pWork; } inline void saveToOriginal() { m_pOriginal.clear(); if (m_pWork) { m_pOriginal = qx::clone_to_qt_shared_ptr(*m_pWork); } } inline void restoreFromOriginal() { m_pWork.clear(); if (m_pOriginal) { m_pWork = qx::clone_to_qt_shared_ptr(*m_pOriginal); } } template qx::dao::ptr staticCast() const { return qx::dao::ptr(m_pWork.template staticCast(), m_pOriginal.template staticCast()); } template qx::dao::ptr dynamicCast() const { return qx::dao::ptr(m_pWork.template dynamicCast(), m_pOriginal.template dynamicCast()); } template qx::dao::ptr constCast() const { return qx::dao::ptr(m_pWork.template constCast(), m_pOriginal.template constCast()); } bool isDirty(QStringList &lstDiff) const { lstDiff.clear(); if (m_pWork.isNull() || m_pOriginal.isNull()) { lstDiff.append("*"); return true; } if (m_pWork == m_pOriginal) { return false; } qx::dao::detail::QxDao_IsDirty::compare((*m_pWork), (*m_pOriginal), lstDiff); return (!lstDiff.isEmpty()); } }; } // namespace dao } // namespace qx template bool operator==(const qx::dao::ptr &ptr1, const qx::dao::ptr &ptr2) { return (ptr1.toQtSharedPointer() == ptr2.toQtSharedPointer()); } template bool operator!=(const qx::dao::ptr &ptr1, const qx::dao::ptr &ptr2) { return (ptr1.toQtSharedPointer() != ptr2.toQtSharedPointer()); } template bool operator==(const qx::dao::ptr &ptr1, const X *ptr2) { return (ptr1.toQtSharedPointer() == ptr2); } template bool operator!=(const qx::dao::ptr &ptr1, const X *ptr2) { return (ptr1.toQtSharedPointer() != ptr2); } template bool operator==(const T *ptr1, const qx::dao::ptr &ptr2) { return (ptr1 == ptr2.toQtSharedPointer()); } template bool operator!=(const T *ptr1, const qx::dao::ptr &ptr2) { return (ptr1 != ptr2.toQtSharedPointer()); } template QDataStream &operator<<(QDataStream &stream, const qx::dao::ptr &t) { stream << t.m_pWork; stream << t.m_pOriginal; return stream; } template QDataStream &operator>>(QDataStream &stream, qx::dao::ptr &t) { stream >> t.m_pWork; stream >> t.m_pOriginal; return stream; } #endif // _QX_DAO_POINTER_H_